C 从Makefile内部调用另一个Makefile的规则
我有一个C 从Makefile内部调用另一个Makefile的规则,c,makefile,compilation,C,Makefile,Compilation,我有一个Makefile,如果某些对象文件不存在,我可以从中运行另一个Makefile的命令 规则如下: $(OBJDIRCOMMON)/%.o: $(COMMONDIR)/%.c $(COMMONDIR)/Makefile | $(OBJDIRCOMMON) +$(MAKE) -C $(COMMONDIR) 其中变量在相同的Makefile中定义如下: COMMONDIR := ../common SOURCESCOMMON := $(wildcard $(COMMONDIR
Makefile
,如果某些对象文件不存在,我可以从中运行另一个Makefile
的命令
规则如下:
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/%.c $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
其中变量在相同的Makefile
中定义如下:
COMMONDIR := ../common
SOURCESCOMMON := $(wildcard $(COMMONDIR)/*.c)
OBJDIRCOMMON := $(COMMONDIR)/obj
OBJECTSCOMMON := $(patsubst $(COMMONDIR)/%.c,$(OBJDIRCOMMON)/%.o, $(SOURCESCOMMON))
DEPENDSCOMMON := $(patsubst $(COMMONDIR)/%.c,$(OBJDIRCOMMON)/%.d, $(SOURCESCOMMON))
这个规则很好用,但在一天结束时,该规则唯一需要的真正输入是另一个Makefile
,因此我尝试了:
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
但这不起作用,为什么
为了完整起见,这里是完整的Makefile
CC = gcc
INC_PATH = -I../common/
SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR :=./obj
OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))
COMMONDIR := ../common
SOURCESCOMMON := $(wildcard $(COMMONDIR)/*.c)
OBJDIRCOMMON := $(COMMONDIR)/obj
OBJECTSCOMMON := $(patsubst $(COMMONDIR)/%.c,$(OBJDIRCOMMON)/%.o, $(SOURCESCOMMON))
DEPENDSCOMMON := $(patsubst $(COMMONDIR)/%.c,$(OBJDIRCOMMON)/%.d, $(SOURCESCOMMON))
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
# OBJS_LOC is in current working directory,
EXECUTABLE := ../server
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: $(EXECUTABLE)
clean:
$(RM) $(OBJECTS) $(DEPENDS) $(EXECUTABLE)
# Linking the executable from the object files
# $^ # "src.c src.h" (all prerequisites)
$(EXECUTABLE): $(OBJECTS) $(OBJECTSCOMMON)
$(CC) $(WARNING) $^ -o $@
-include $(DEPENDS) $(DEPENDSCOMMON)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
$(CC) $(WARNING) -MMD -MP -c $(INC_PATH) $< -o $@
$(OBJDIRCOMMON):
mkdir -p $(OBJDIRCOMMON)
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/%.c $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
从中我了解到另一个
Makefile
的执行是成功的。然而,在那之后,它试图执行这个命令,gcc../common/obj/error.d.o-o../common/obj/error.d
,这是错误的,但我不知道是哪个规则以及它为什么生成它。应该有&而不是管道吗
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/Makefile | (OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR
你为什么做错了 配方A:
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/%.c $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
和配方B:
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/%.c $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
具有本质上不同的含义,肯定不会产生相同的行为
食谱A上写着:
$(OBJDIRCOMMON)/file.o
如果不存在,则必须是最新的
或者早于$(COMMONDIR)/file.c
或$(COMMONDIR)/Makefile
$(OBJDIRCOMMON)/file.o
必须是最新的,则$(OBJDIRCOMMON)
必须首先更新$(OBJDIRCOMMON)/file.o更新,请在shell中运行$(make)-C$(COMMONDIR)
的扩展
$(OBJDIRCOMMON)/file.o
如果不存在,则必须是最新的
或者早于$(COMMONDIR)/Makefile
$(OBJDIRCOMMON)/file.o
必须是最新的,则$(OBJDIRCOMMON)
必须首先更新$(OBJDIRCOMMON)/file.o更新,请在shell中执行$(make)-C$(COMMONDIR)
的扩展
$(OBJDIRCOMMON)/file.o
早于$(OBJDIRCOMMON)/file.c
。配方B将不起作用。
配方B放弃目标文件对相应源文件的依赖关系,
并告诉Make只有在满足以下条件时才能重新生成$(OBJDIRCOMMON)/file.o
早于$(COMMONDIR)/Makefile
在一天结束时,规则所需的唯一真正输入是另一个Makefile
这里您所说的“规则”实际上是命令行(扩展自)$(MAKE)-C$(COMMONDIR)
。
这个命令的输入是一件事;执行它的标准是另一个
您所做的是如何导致您看到的错误的
这更棘手。让我们复制一下
这是一个玩具笔:
$ ls -R
.:
app common
./app:
foo.c main.c Makefile
./common:
bar.c Makefile
这里,/app/Makefile
正是您的配方A的Makefile<代码>/common/Makefile,
您没有发布的内容只是:
obj/bar.o: bar.c
gcc -MMD -MP -c -I. $< -o $@
这很好
现在,我将/app/Makefile
更改为使用recipeB,然后重新构建
$ make
gcc -Wall -Wextra -MMD -MP -c -I../common/ foo.c -o obj/foo.o
gcc -Wall -Wextra -MMD -MP -c -I../common/ main.c -o obj/main.o
gcc -Wall -Wextra obj/foo.o obj/main.o ../common/obj/bar.o -o ../server
还是很好。。。但是等一下!那一个没有调用/common
make
毕竟,这是变化可能会影响的因素。更好的清洁:
$ make clean
rm -f ./obj/foo.o ./obj/main.o ./obj/foo.d ./obj/main.d ../server
然后重试:
$ make
gcc -Wall -Wextra -MMD -MP -c -I../common/ foo.c -o obj/foo.o
gcc -Wall -Wextra -MMD -MP -c -I../common/ main.c -o obj/main.o
gcc -Wall -Wextra obj/foo.o obj/main.o ../common/obj/bar.o -o ../server
没有区别?啊,那是因为这个Makefile的clean
无法删除所有
生成的文件
生成:它省略了。/common/obj/bar.o
。所以我只想:
$ rm ../common/obj/*
再来一次:
$ make
make -C ../common
make[1]: Entering directory '/home/imk/develop/so/make_prob/common'
gcc -MMD -MP -c -I. bar.c -o obj/bar.o
make[1]: Leaving directory '/home/imk/develop/so/make_prob/common'
gcc ../common/obj/bar.d.o -o ../common/obj/bar.d
gcc: error: ../common/obj/bar.d.o: No such file or directory
gcc: fatal error: no input files
compilation terminated.
这是你的秘密
当我清除。/common/obj
文件时,我不仅删除了其中的所有对象文件
还有依赖项文件。/common/obj/bar.d
。现在Make正试图通过运行以下命令来重新制作:
gcc ../common/obj/bar.d.o -o ../common/obj/bar.d
$(MAKE) -C $(COMMONDIR)
为什么?为了回答这个问题,我们首先将/app/Makefile
更改回使用recipeA
-考虑它完成-然后做:< /P>
$ make --print-data-base > out.txt
它将所有从阅读中收集到的信息转储到out.txt
中
makefiles(Makefile
及其递归包含的所有makefiles
-s,
在这种情况下,只需自动生成.d
文件)
让我们看看数据库对。/common/obj/bar.d
的看法。它说:
# Not a target:
../common/obj/bar.d:
# Implicit rule search has been done.
# Last modified 2019-01-11 16:01:33.199263608
# File has been updated.
# Successfully updated.
当然,我们不希望。/common/obj/bar.d
成为目标,它也不是目标
因为读取了所有makefile并考虑了其所有内置规则,
而且它能找到的所有文件,Make都看不到。/common/obj/bar.d
必须对这些文件中的任何文件进行更新。好
现在让我们回到< <强> > b>强> <代码> ./APP/MaMeCuff再次-考虑它完成了
再次强调:
$ make --print-data-base > out.txt
再次查看out.txt
中有关。/common/obj/bar.d
。这次我们发现:
../common/obj/bar.d: ../common/obj/bar.d.o
# Implicit rule search has been done.
# Implicit/static pattern stem: '../common/obj/bar.d'
# Last modified 2019-01-11 16:01:33.199263608
# File has been updated.
# Successfully updated.
# recipe to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
所以这次。/common/obj/bar.d
是一个目标!它取决于。/common/obj/bar.d.o
!
制作它的配方是:
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
当然,这将扩展到:
gcc ../common/obj/bar.d.o -o ../common/obj/bar.d
多亏了配方B,我们是如何做到这一点的
首先,它考虑的是makefile中的任何规则还是
内置规则使它可以直接从任何现有文件中生成。/common/obj/bar.d
,
然后画了一张空白
接下来,它考虑了这些规则中是否有任何一条给了它一条解决问题的途径
将。/common/obj/bar.d
从。中间文件是一个不存在但自身可以生成的文件
从现有文件中,通过它已读取的任何规则或其内置规则。这
它终于找到了出路
Make的内置模式规则之一是:
%: %.o
# recipe to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
你可以在out中找到它
make -C ../common
make[1]: Entering directory '/home/imk/develop/so/make_prob/common'
gcc -MMD -MP -c -I. bar.c -o obj/bar.o
make[1]: Leaving directory '/home/imk/develop/so/make_prob/common'
../common/obj/bar.d: ../common/obj/bar.d.o
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
gcc ../common/obj/bar.d.o -o ../common/obj/bar.d
make -C ../common
gcc: error: ../common/obj/bar.d.o: No such file or directory
$(OBJDIRCOMMON)/bar.d.o: $(OBJDIRCOMMON)/bar.d.c $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)