Make:在同一目标中两次编译目标文件

时间:2014-12-01 14:41:18

标签: c makefile

我在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.amake 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,但同样,它只编译一次。

2 个答案:

答案 0 :(得分:1)

你的makefile与make逻辑有点对比,这就是为什么结果不符合你的期望:

  • 在此定义两个具有共同依赖关系的目标(lib1.alib2.a):test.o
  • 然后您定义规则all(顺便说一句,.PHONY但这不是问题)取决于lib1.alib2.a

因此,为了“做”allmake必须构建lib1.alib2.a。它们都依赖于test.o,因此make构建test.o一次,然后构建lib1.alib2.a,期望您定义的食谱只会构建这些文件,仅此而已。

问题是您删除test.olib1.a 的配方中的lib2.a ,虽然不需要此操作来构建它们,但这是你想在清洁时做,而不是建筑。

有两种解决方案:

  1. 将删除操作移到要执行此操作的规则中(例如,.PHONY一个名为clean的规则。)
  2. intermediate targets的使用,将在不再需要时删除。实际上,如果您只是删除makefile的第一条规则(%.o:: %.c),because make already has an implicit rule that does that使用中间目标,那么即使不考虑中间目标,也可以实现这一目标。

答案 1 :(得分:0)

Make是一个基于规则的系统。规则是声明性的:你从什么声明你想要构建的内容,你没有指定发生这种情况的顺序(除非你无法避免)。所以一个好的Makefile是声明性的:所有结果都是声明的,就像在声明性编程语言中一样。它们就像Java中的final变量:您将它们绑定到一个值,之后不会将它们重新分配给不同的值。

Make也是基于文件的:它的“变量”,目标和先决条件是文件。

因此,如果您想构建两个不同的东西,请不要使用相同的名称来调用它们!如果您需要两个不同的test.o文件,请以不同方式调用它们。问题将消失,你不必试图说服make它应该像命令式编程语言,它是专门设计的不是。如果您需要命令式构建规范,请使用shell脚本。