考虑一个简单的项目,该项目包含两个不同的目录:src
用于手写代码,gen
用于生成代码。
生成文件:
foo: foo.o main.o gcc $^ -o $@ COMPILE = gcc -MD -MP -MF $(@:.o=.d) -Isrc -Igen -c $< -o $@ %.o: src/%.c $(COMPILE) %.o: gen/%.c $(COMPILE) -include $(wildcard *.d)
的src / main.c中
#include "foo.h" #include <stdio.h> int main() { printf("%d\n", foo()); return 0; }
的src / foo.h中
int foo(void);
的src / foo.c的
#include "foo.h" int foo() { return 42; }
这很有效,包括依赖性跟踪:
$ make gcc -MD -MP -MF foo.d -Isrc -Igen -c src/foo.c -o foo.o gcc -MD -MP -MF main.d -Isrc -Igen -c src/main.c -o main.o gcc foo.o main.o -o foo $ touch src/foo.h $ make gcc -MD -MP -MF foo.d -Isrc -Igen -c src/foo.c -o foo.o gcc -MD -MP -MF main.d -Isrc -Igen -c src/main.c -o main.o gcc foo.o main.o -o foo
-MP
甚至允许我将标题移动到gen/
而不会破坏构建:
$ mv src/foo.h gen/ $ make gcc -MD -MP -MF foo.d -Isrc -Igen -c src/foo.c -o foo.o gcc -MD -MP -MF main.d -Isrc -Igen -c src/main.c -o main.o gcc foo.o main.o -o foo
但不幸的是,如果没有破坏,我无法移动非标题:
$ mv src/foo.c gen/ $ make make: *** No rule to make target 'src/foo.c', needed by 'foo.o'. Stop.
那是因为GCC生成的依赖规则如下所示:
$ cat foo.d foo.o: src/foo.c /usr/include/stdc-predef.h gen/foo.h /usr/include/stdc-predef.h: gen/foo.h:
foo.o: src/foo.c
依赖关系会阻止make
在移动gen/foo.c
之后使用$ sed -i 's|src/foo.c ||' foo.d
$ make
make: 'foo' is up to date.
。如果不存在,一切都会奏效:
git rebase-like [same arguments as rebase]
有没有办法让它自动运行,使用不同的GCC标志或以某种方式更改Makefile?
答案 0 :(得分:0)
您以不寻常的方式使用依赖项(我不想说错误;))。第一次通过编译仅使用模式规则,因为依赖文件尚不存在。之后,当您移动文件时,您将被取消同步,然后调用带有旧的依赖项文件的构建,该文件带有错误的路径信息。如果没有适当和严格的目标信息,那么设计是没有设计的,因为这会导致完全不受控制的构建 - 为什么不编译文件anotherproject / notyourbusiness / foo.c如果名称适合某种程度? (*)
所以,如果你想这样做,你就被迫明确地对它进行编程,因为任何隐式功能都会使渲染变得毫无用处。您可以使用VPATH(将其设置为您的源可能出现的目录并从依赖项文件中的先决条件中删除路径信息)来查找您的源,但请注意,即使是这个也没有为了捕获难以捉摸的目的而添加项目范围。
总而言之,我敢说,如果你的源文件的位置在整个项目期间造成如此大的麻烦,你就会陷入困境 - 这并不是说允许这种配置更改的灵活makefile会是一件坏事,只是不要安装这样的行为,因为&#34;正常&#34;建立步骤。
(*)当然,允许依赖关系生成滞后一个周期,但这与以不受控制的方式移动目标不同。