自动化构建工具中的头文件依赖性

6
我想创建一个Makefile.am文件,该文件可以生成xxx.c中提到的一个头文件。
假设xxx.c包含以下内容:
#include <version.h>
...

而且我有一个规则来在Makefile.am的结尾创建它:

version.h:
       echo '#define VERSION "'`hg id`'"' > version.h.tmp
       cmp version.h.tmp version.h || mv version.h.tmp version.h

我需要做哪些改变才能使得xxx.c的编译依赖于version.h?我尝试使用nodist_progname_SOURCES=version.h,但貌似不起作用。
1个回答

11
BUILT_SOURCES = version.h

所有被提及为BUILT_SOURCES的文件将在任何正常编译规则运行之前被构建。
然而,这会带来一个小问题:由于version.h需要在每次make调用时重新构建,每个包含version.hfoo.c文件的重新编译都将在每次make运行时再次触发。我们希望只有当实际上有改变时才进行重新编译。
为了解决这个问题,在一个时间戳文件的BUILT_SOURCES依赖项上使用,该文件在每次“创建”时(实际上从未创建,因此构建规则每次都会运行)。该时间戳文件的构建规则创建一个名为version.h.tmp的新version.h文件,并仅在version.h.tmp实际上与version.h不同的情况下将version.h.tmp复制到version.h中(就像您的version.h规则一样)。因此,如果version.h没有发生变化,它的时间戳(mtime)保持不变,不会触发依赖于version.h的对象的构建:
BUILT_SOURCES = version.stamp

version.stamp:
        echo '#define VERSION "'`hg id`'"' > version.h.tmp
        cmp version.h.tmp version.h || mv version.h.tmp version.h

这个解决方案将会实现你所要求的功能。

但是,当你从一个dist tarball进行构建时,会有一个小问题:然后hg id将会给你虚假的信息,并且在你的tarball中可能没有version.h,因此构建将会失败或包含虚假的版本信息。

我已经为使用gitxf86-video-radeonhd项目解决了这个问题。在这个解决方案中生成的git-version.h文件包含了一些比单个版本号更多的版本信息。如果你感兴趣,你可以在git_version.sh的末尾看到我的这个仅在不同情况下更新的解决方案,以及RadeonHD.amBUILT_SOURCES的连接(包括处理所有out-of-source-treefrom-dist-tarball构建情况)。


这个方案非常好,但有一个限制。根据 automake 手册的描述:“需要强调的是,BUILT_SOURCES 只会被‘make all’、‘make check’和‘make install’所识别。这意味着如果某个特定目标(例如‘make foo’)依赖于已构建的源文件,则无法在干净的树中构建它。”尽管如此,这仍然是我所知道的最佳解决方案。 - phs
我猜如果有人知道如何运行make foo,你可以合理地假设他们知道他们正在构建什么,因此需要手动确保重新构建BUILT_SOURCES。 - ndim
你必须通过“&&”运算符将它们放入单行中,否则make将很乐意并行化你的version.h构建。 - Jan Kundrát
@JanKundrát 不是的。make 只会并行地运行完整的目标 配方。单个目标配方中的 shell 命令顺序 运行的。 - ndim

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