如何在 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__
宏被自动定义为扩展到编译日期和时间。它们不会让您控制格式,但这可能是一个值得的权衡。
使用 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__
宏被自动定义为扩展到编译日期和时间。它们不会让您控制格式,但这可能是一个值得的权衡。