如何确保目标在makefile中的所有其他构建规则之前运行?

11
我有一个C++项目,其中包含一个生成的文件,所有其他C++文件都依赖于它。我试图强制在任何其他编译之前生成和编译该文件。通常情况下,只需将该文件放在all:目标中的第一位即可解决问题,但问题在于我的Makefile也是由构建系统生成的,我只能向其附加片段,而不能对其进行一般性编辑。
那么,是否有一种方法可以通过依赖关系或其他方式强制运行生成的文件目标?我考虑使用类似以下内容的东西:
cpp_files := $(wildcard src/*.cpp)
$(cpp_files): generated_file.cpp
generated_file.cpp:
    # generate the file here

但是它似乎没有起作用。为了参考,我的源目录结构如下,因此我需要递归收集cpp文件:

src/
|---file1.cpp
|---file2.cpp
|---subdir1/
    |---file3.cpp

gen/
|---generated_file.cpp
2个回答

26

如果你确信这就是你想要的,下面是一种方法:为一个虚拟文件编写规则,并在makefile中使用 include

.PHONY: dummy
dummy:
    # generate the file here

-include dummy
无论你指定什么目标,Make都会首先运行dummy规则,然后重新启动自己。

太棒了!这真是拯救生命的好东西! - hesham_EE
2
注意:如果您有其他包含依赖于生成的文件,则虚拟包含必须跟随这些包含,而不是像您可能认为的那样在其之前。 - Oleksandr
@stunpix 最后的评论真的对我帮助很大。它在Cygwin make方面产生了巨大的影响,谢谢! - hesham_EE
@Vroomfondel:GNUMake文档并没有做出如此广泛的承诺。 - Beta
@Vroomfondel:它非常明确地防止了.PHONY将要避免的冲突,即豁免您引用的承诺。但是文件和规则之间仍然可能存在联系,例如:1)如果makefile包含该文件,则Make将执行该规则。2)如果makefile包含该文件,并且该文件存在,则其内容可能会在执行规则之前中止Make进程,3)配方中命令的行为可能取决于文件的内容(或文件是否存在)。这个技巧相当可靠,但不是不可破解的。 - Beta
显示剩余2条评论

5

实际上,其他cpp文件不依赖于生成的文件(在Make规则方面)。依赖图仍然如下:

program
 |
 ^- file1.o
 |   ^- file1.c
 |
 ^- file2.o
 |   ^- file2.c
 |
 ^- generated_file.o
     ^- generated_file.c
         ^- <generator prerequisites>

如果您的源文件需要依赖某种生成的头文件(在这些源文件被#include时),则只能如此。

如果您只需要生成一个cpp文件,则以下makefile应该足够:

srcs := $(wildcard src/*.cpp src/*/*.cpp)

gen_file := gen/generated_file.cpp
srcs += $(gen_file)

objs := $(srcs:.cpp=.o)

.PHONY : all
all : program

program : $(objs)
    @$(LD) ...

%.o : %.c
    @$(CC) ...

$(gen_file) :
    # generate the file here

更新。

基于Beta的答案做了一点改进。

-include generator-task
.PHONY : generator-task

generator-task : $(gen_files)

$(gen_files) : $(gen_prerequisites)
    # generate the file here

与每次调用Make时运行生成器不同,这将仅在其先决条件更改时重新生成文件。


实际上,我也有一个生成的头文件和cpp文件。你提供的代码会有很大不同吗? - andrei
@andrei,宁可选择肯定也不要否定......在这种情况下,我建议您将代码生成和编译阶段分开。 实际上,Beta的解决方案实现了同样的目标。 - Eldar Abusalimov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接