gpt4 book ai didi

c++ - 请解释这个 Makefile - 似乎缺少可执行规则

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:08:31 25 4
gpt4 key购买 nike

我有这个我不明白的生成文件。

build_sources:=$(wildcard *.cpp)
depends:=$(build_sources:.cpp=.d)
build_targets:=$(build_sources:.cpp=)

.PHONY: all
all: $(build_targets)

.PHONY: clean
clean:
rm -f $(build_targets) *.{a,o,d}

#build the list of header file dependencies automatically
%.d: %.cpp
@echo building include dependencies for $(*F)
@$(CXX) -MM $(CPPFLAGS) $< | { sed 's#\($*\)\.o[ :]*#\1.o $@ : #g' ; echo "%.h:;" ; } > $@

-include $(depends)

我知道创建的可执行文件是 build_target。因此,如果我有 Foo.cppBar.cpp,创建的可执行文件将是 FooBar

但是它是如何做到的呢?我只看到 1 条规则,它是 %.d: %.cpp。所以它说 Foo.d 文件依赖于 Foo.cpp。但是实际编译 Foo 的规则呢?

这个 makefile 有效,所以它实际上并没有遗漏任何东西。但是我怎么没看到规则呢?是否有一些隐含的规则?

编辑 - 我确实进行了调试,并看到了以下内容

No need to remake target `foo.d'.
Considering target file `foo'.
File `foo' does not exist.
Looking for an implicit rule for `foo'.
Trying pattern rule with stem `foo'.
Trying implicit prerequisite `foo.o'.
Found an implicit rule for `foo'. ## WHAT EXACTLY IS THIS?
Considering target file `foo.o'.
File `foo.o' does not exist.
Looking for an implicit rule for `foo.o'.
Trying pattern rule with stem `foo'.
Trying implicit prerequisite `foo.c'.
Trying pattern rule with stem `foo'.
Trying implicit prerequisite `foo.cc'.
Trying pattern rule with stem `foo'.
Trying implicit prerequisite `foo.C'.
Trying pattern rule with stem `foo'.
Trying implicit prerequisite `foo.cpp'.
Found an implicit rule for `foo.o'.
Pruning file `foo.cpp'.
Pruning file `foo.cpp'.
Finished prerequisites of target file `foo.o'.
Must remake target `foo.o'.
g++ -I../../include -Wall -std=c++11 -O3 -Wsign-compare -Wno-strict-aliasing -s -c -o foo.o foo.cpp

太好了。这必须是被调用的规则。但是这个规则是从哪里来的呢?我如何知道存在哪些默认规则?

最佳答案

在理解这个 Makefile 时,您可能错过的是 pattern rule 的概念。和 automatic variables .

这部分查找 .cpp 文件:

build_sources:=$(wildcard *.cpp)

这部分创建具有相同名称的目标(使用上面定义的变量 build_sources),除了扩展名被替换为 .d:

depends:=$(build_sources:.cpp=.d)

相同类型的构造定义了构建目标(删除扩展名的相同文件名):

build_targets:=$(build_sources:.cpp=)

然后默认目标被定义为需要build_targets,即对应.cpp`的可执行文件

all: $(build_targets)

此规则定义如何从 .cpp 构建 .d:

#build the list of header file dependencies automatically
%.d: %.cpp
@echo building include dependencies for $(*F)
@$(CXX) -MM $(CPPFLAGS) $< | { sed 's#\($*\)\.o[ :]*#\1.o $@ : #g' ; echo "%.h:;" ; } > $@

gcc -MM 生成规则以了解 .c.cpp 文件所依赖的 header 。通常,如果 test.cpp 包含 test1.htest2.h,输出将是:

test.o: test.cpp test1.h test2.h

.d 将包含每个 cpp 文件的依赖项,并将创建一个规则来构建 .o 文件和每个 cpp 的可执行文件。 $@ 是规则的目标(.d 文件),除非我记错了,否则它将包含一个看起来像这样的规则(由 sed 表达式编写) :

filename.o filename.d : filename.cpp <list of headers>
%.h:;

第一条规则给出了.o 文件的依赖关系。它没有配方,这意味着它只是将依赖项添加到任何现有规则。将使用隐式规则来构建它们。第二个在这里,以防您抑制标题。在这种情况下,make 将使用此规则,表示无事可做(它有一个空配方)。

然后所有的 .d 文件都包含在 makefile 中:

-include $(depends)

最后,implicit rule链接单个 .o 文件开始:

Linking a single object file

n is made automatically from n.o by running the linker (usually called ld) via the C compiler. The precise recipe used is ‘$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)’.

编辑:要在子目录 obj 中构建对象,您必须修改每个文件名:

depends:=$(foreach file,$(build_sources:.cpp=.d),"obj/$(file)")

要在单独的子目录 bin 中构建二进制文件,您需要对 build_targets 执行相同的操作:

build_targets:=$(foreach file,$(build_sources:.cpp=), "bin/$(file)")

然后您需要编写规则来构建它,因为默认规则将不再起作用(.o 不在同一目录中)。你想要的是添加这样的规则:

bin/foo: obj/foo.o
$(CC) $(LDFLAGS) obj/foo.o $(LOADLIBES) $(LDLIBS) -o bin/foo

这可以通过正确修改长 shell 命令来完成:

    @$(CXX) -MM $(CPPFLAGS) $< | { sed 's#\($*\)\.o[ :]*#\1.o $@ : #g' ; echo "%.h:;" ; obj=`echo $< | sed 's/.cpp/.o/'` ; bin=`echo $< | sed 's/.cpp//'` ; echo "$bin: $obj" ; echo -e "\t\$(CC) \$(LDFLAGS) $obj \$(LOADLIBES) \$(LDLIBS) -o $bin" ; } > $@

关于c++ - 请解释这个 Makefile - 似乎缺少可执行规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35780580/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com