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

如何在Automake/Makefile.am中执行shell命令?,makefile,gnu,autotools,autoconf,automake,Makefile,Gnu,Autotools,Autoconf,Automake,使用Automake编译可执行文件后,我希望可执行文件输出编译日期、使用的编译器以及git repo版本/日期。但是,我似乎无法从Makefile.am运行shell命令。当我尝试时,会收到以下警告: sample/C++/Makefile.am:1:警告:日期+%D:非POSIX变量名 sample/C++/Makefile.am:1:(可能是GNUmake扩展名) sample/C++/Makefile.am:2:警告:git--无寻呼机显示--date=short--format=“%ad

使用Automake编译可执行文件后,我希望可执行文件输出编译日期、使用的编译器以及git repo版本/日期。但是,我似乎无法从Makefile.am运行shell命令。当我尝试时,会收到以下警告:

sample/C++/Makefile.am:1:警告:日期+%D:非POSIX变量名

sample/C++/Makefile.am:1:(可能是GNUmake扩展名)

sample/C++/Makefile.am:2:警告:git--无寻呼机显示--date=short--format=“%ad”--仅名称|{read first};echo$first;}:非POSIX变量名

sample/C++/Makefile.am:2:(可能是GNUmake扩展名)

sample/C++/Makefile.am:3:警告:git--无寻呼机描述--标记--始终--脏:非POSIX变量名

sample/C++/Makefile.am:3:(可能是GNUmake扩展名)


如果除了在configure.ac中运行命令之外还有更好的方法(因为这会破坏编译时间的目的),请告诉我。

POSIX
make
和许多特定的
make
实现都没有在配方之外运行shell命令的机制。GNU
make
也许其他人确实提供了扩展,但自动工具的目标之一是支持尽可能广泛的构建环境,因此依赖特定实现提供的扩展与自动工具的习惯用法相反

在不依赖扩展的情况下解决问题的一种方法是使源
#包含在构建时动态生成的头。例如,下面是
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)\"" >>$@
因为它列在
build_SOURCES
中,所以目标
build_details.h
将提前生成。因为构建它的规则没有先决条件,所以它总是被认为是过时的,所以它将被重建,从而获得新的细节。当然,这也意味着每次运行
make
,依赖它的所有源代码都将重新生成,但如果您正在跟踪此类生成信息,这可能就是您想要的

另一方面,如果您愿意依赖GNU
make
extensions,那么它们提供了一种为shell命令的输出设置变量的方法。在这种情况下,您可以执行以下操作:

bin_PROGRAMS = hello

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

hello_SOURCES = \
  hello.cpp
注意双引号:内部双引号需要是所定义宏的替换文本的一部分,因此它们需要在编译器命令行上显示时受到保护,不受shell的影响

这样做的优点是它较短,并且如果
hello.cpp
没有更改,则不会导致重建
hello
。但它只能与支持所用GNU扩展的
make
一起使用。此外,这不会导致任何对象过期,因此可能会留下将过时的生成信息记录在二进制文件中的可能性,因为保存该信息的对象不在某些给定的
make
执行中重建的对象中


当然,尽管我已经把这个问题作为一个问题来解决,但值得注意的是,其中一些是直接存在于C语言和C++语言中的重复特征。具体地说,
\uuuuuuu日期
\uuuuu时间
宏将自动定义为扩展到编译日期和时间。它们不会让您控制格式,但这可能是一个值得权衡的问题。

还可以将
build\u details.c
文件生成为
build\u SOURCES
,这将避免在仅更改生成信息时编译其他代码的开销。此外,您还可以向
BUILD\u SOURCES
添加一个伪戳文件,并让配方生成一个新文件
BUILD\u details.c.new
,如果后者实际不同或不存在,则只将该
*.new
复制到
BUILD\u details.c
。这样可以避免在git信息未更改等情况下进行不必要的重新编译。