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

C Make:在同一目标中编译对象文件两次,c,makefile,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 我需要执行rm*.o操作,因为我希望每次都编译对象文件(在我真正的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
我需要执行
rm*.o
操作,因为我希望每次都编译对象文件(在我真正的Makefile中,我有一个更复杂的用例,我使用不同的标志进行编译)

我如何解决这个问题?似乎
make
只编译一次对象文件


我用
.PHONY
代替了
rm
,但它只编译了一次。

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

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


因此,如果你想构建两个不同的东西,不要用同一个名字来称呼它们!如果需要两个不同的
test.o
文件,请以不同的方式调用它们。这个问题将在您不需要尝试和说服
make
它应该像命令式编程语言一样的情况下解决,而它是专门设计的。如果您想要一个命令式的构建规范,请使用shell脚本。

您的makefile有点违反了
make
逻辑,这就是为什么结果不是您所期望的:

  • 在这里,您定义了两个目标(
    lib1.a
    lib2.a
    ),它们具有共同的依赖关系:
    test.o
  • 然后定义依赖于
    lib1.a
    lib2.a
    的规则
    all
    (顺便说一句,应该是
    .PHONY
    ,但这不是问题)
因此,为了“完成”
all
make
必须构建
lib1.a
lib2.a
。它们都依赖于
test.o
,因此
make
builds
test.o
一次,然后构建
lib1.a
lib2.a
,期望您定义的配方只构建这些文件,而不是别的

问题是您删除了
lib1.a
lib2.a
配方中的
test.o
,虽然构建它们不需要此操作,但这是在清理而不是构建时要执行的操作

有两种解决方案:

  • 将删除操作移动到要执行此操作的规则中(例如,名为
    clean
    .PHONY
    规则)
  • 当不再需要它们时,它们的使用将被删除。事实上,如果您使用中间目标简单地删除makefile的第一条规则(
    %.o::%.c
    one),您甚至不需要考虑中间目标就可以实现这一点

  • 一次创建
    .o
    文件符合Make的工作方式,应该不会有问题(事实上,从时间消耗的角度来看,它不重复该步骤是件好事)。奇怪的是在运行
    ar
    后立即将其删除。为什么要这样做?尝试为每个对象文件使用不同的名称。更好的是,将每组.o文件编译成单独的目录。为什么
    lib1.a
    lib2.a
    包含相同的对象文件?你应该有一个
    libmy.a
    !您应该在
    Makefile
    中使用更多变量,就像这是我实际Makefile的简化版本一样。我尝试用一个公共对象文件和一些其他不同的文件创建不同的库。但是,对于某些库,我使用不同的标志编译公共对象文件。我想我确实可以按照@iharob的建议创建不同的对象文件。
    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