如何在 Automake/Makefile.am 中执行 shell 命令?

How to execute shell commands in Automake/Makefile.am?

使用 Automake 编译我的可执行文件后,我希望可执行文件输出编译日期、使用的编译器和 git 存储库 version/date。但是,我似乎无法从 Makefile.am 获得对 运行 的 shell 命令。当我尝试时,我收到这些警告:

sample/C++/Makefile.am:1: warning: date +%D: non-POSIX variable name

sample/C++/Makefile.am:1: (probably a GNU make extension)

sample/C++/Makefile.am:2: warning: git --no-pager show --date=short --format="%ad" --name-only | { read first _ ; echo $first ; }: non-POSIX variable name

sample/C++/Makefile.am:2: (probably a GNU make extension)

sample/C++/Makefile.am:3: warning: git --no-pager describe --tags --always --dirty: non-POSIX variable name

sample/C++/Makefile.am:3: (probably a GNU make extension)

如果除了运行宁configure.ac中的命令(因为这违背了编译时间的目的)之外还有更好的方法来做到这一点,请告诉我。

POSIX make 和许多特定的 make 实现不提供 运行ning shell 命令之外的机制。 GNU make 或许其他人确实将其作为扩展提供,但 Autotools 的 objectives 之一是支持尽可能广泛的构建环境,因此依赖特定实现提供的扩展是相反的到 Autotools 惯用语。

解决问题而不依赖扩展的一种方法是使您的源 #include 成为在构建时动态生成的 header。例如,Makefile.am 部分可能如下所示:

bin_PROGRAMS = hello

hello_SOURCES = \
  hello.cpp \
  build_details.h

BUILT_SOURCES = \
  build_details.h

CLEANFILES = \
  build_details.h

build_details.h:
    echo "#define BUILDDATE \"`date +%D`\"" >$@
    echo "#define COMPILER \"$(CXX)\"" >>$@

因为它列在 BUILT_SOURCES 中,目标 build_details.h 将提前构建。因为构建它的规则没有先决条件,它总是被认为是过时的,所以它会被重建,从而得到新鲜的细节。当然,这也意味着每次您 运行 make 时,所有依赖它的源都将被重建,但如果您正在跟踪此类构建信息,也许这就是您真正想要的。

另一方面,如果您愿意依赖 GNU make 扩展,那么它们提供了一种将变量设置为 shell 命令输出的方法。在那种情况下,您可能会做更多类似的事情:

bin_PROGRAMS = hello

builddate := $(shell date +%D)
CXXFLAGS = -DBUILDDATE='"$(builddate)"' -DCOMPILER='"$(CXX)"'

hello_SOURCES = \
  hello.cpp

注意双引号:内部双引号需要成为正在定义的宏的替换文本的一部分,因此需要保护它们不受 shell 的影响,因为它们出现在编译器命令行上。

这样的好处是比较短,如果hello.cpp没变,不会导致hello重新构建。但它只适用于支持所用 GNU 扩展的 make。此外,这不会导致任何 objects 过时,因此它可能会保留过时的构建信息被记录在二进制文件中的可能性,因为 object 不保存它在那些根据给定 make 执行重建的那些中。

当然,虽然我已经解决了提出的问题,但值得注意的是,其中一些是 C 和 C++ 语言中直接存在的功能的重复。具体来说,__DATE____TIME__ 宏被自动定义为扩展到编译日期和时间。它们不会让您控制格式,但这可能是一个值得的权衡。