我在Makefile中遇到以下简单问题:
%.o:: %.c
gcc -o $@ -c $<
lib1.a: test.o
ar -r $@ test.o
rm *.o
lib2.a: test.o
ar -r $@ test.o
rm *.o
all: lib1.a lib2.a
make lib1.a
或make lib2.a
正常工作。但是,make all
给出了:
gcc -o test.o -c test.c
ar -r lib1.a test.o
rm *.o
ar -r lib2.a test.o
ar: test.o: No such file or directory
make: *** [lib2.a] Error 1
我需要执行rm *.o
因为我希望每次都能编译目标文件(在我的真实Makefile中,我有一个更复杂的用例,我用不同的标志编译)。
如何解决此问题?似乎make
只编译一次目标文件。
我尝试使用.PHONY
而不是rm
,但同样,它只编译一次。
答案 0 :(得分:1)
你的makefile与make
逻辑有点对比,这就是为什么结果不符合你的期望:
lib1.a
和lib2.a
):test.o
。all
(顺便说一句,.PHONY
但这不是问题)取决于lib1.a
和lib2.a
因此,为了“做”all
,make
必须构建lib1.a
和lib2.a
。它们都依赖于test.o
,因此make
构建test.o
一次,然后构建lib1.a
和lib2.a
,期望您定义的食谱只会构建这些文件,仅此而已。
问题是您删除test.o
和lib1.a
的配方中的lib2.a
,虽然不需要此操作来构建它们,但这是你想在清洁时做,而不是建筑。
有两种解决方案:
.PHONY
一个名为clean
的规则。)%.o:: %.c
),because make
already has an implicit rule that does that使用中间目标,那么即使不考虑中间目标,也可以实现这一目标。答案 1 :(得分:0)
Make是一个基于规则的系统。规则是声明性的:你从什么声明你想要构建的内容,你没有指定发生这种情况的顺序(除非你无法避免)。所以一个好的Makefile是声明性的:所有结果都是声明的,就像在声明性编程语言中一样。它们就像Java中的final
变量:您将它们绑定到一个值,之后不会将它们重新分配给不同的值。
Make也是基于文件的:它的“变量”,目标和先决条件是文件。
因此,如果您想构建两个不同的东西,请不要使用相同的名称来调用它们!如果您需要两个不同的test.o
文件,请以不同方式调用它们。问题将消失,你不必试图说服make
它应该像命令式编程语言,它是专门设计的不是。如果您需要命令式构建规范,请使用shell脚本。