生成的 C 文件和 autotools

A generated C file and autotools

在基于 autoools 的构建中,我想用生成的 C 文件替换版本控制的 C 文件。

这个虚拟的,你好世界示例的作品:

#!/bin/sh -ex
cat > configure.ac <<EOF
AC_INIT([hello], [0.01])
AC_PREREQ([2.68]) 
AC_CONFIG_SRCDIR([hello.c])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([1.11])
AC_CONFIG_FILES([Makefile])
AC_PROG_CC
AC_OUTPUT
EOF

cat > autogen.sh <<EOF
touch NEWS README AUTHORS ChangeLog COPYING
autoreconf -i
EOF
chmod +x autogen.sh

printf "
bin_PROGRAMS = hello
hello_SOURCES = hello.c 

hello.c: generate
\t./generate
" > Makefile.am

cat > hello.c <<EOF
#include <stdio.h>
int main()
{
    puts("hello world");
    return 0;
}
EOF

cat > generate <<EOF0
#!/bin/sh
cat > hello.c <<EOF
#include <stdio.h>
int main()
{
    puts("HELLO WORLD");
    return 0;
}
EOF
EOF0
chmod +x generate


./autogen.sh
./configure 
make -j$(nproc)

除非它阻止我进行树外构建,例如:

mkdir B
cd B
../configure
make

我通常可以在基于 autotools 的包中执行此操作。 我怎样才能生成 C 文件,以便树外构建继续工作?

重要的是要记住 make 对目录了解不多;在大多数情况下,一切都是一个字符串。这并不总是那么明显,但是当您尝试编写可以处理源外构建的构建系统时,它往往会真正困扰您。

您提供了一个构建规则,其中 hello.c 取决于您的 generate 脚本,这在原则上是可以的。 Make 甚至可以在源代码外构建中正确处理依赖项处理,在源目录中找到 generate 脚本。但是构建规则 explicitly 运行s ./generate 中的配方在执行外源构建时不存在。此外,依赖关系和构建规则之间存在脱节:'generate' 与 './generate' 不同。

主要有两种选择:

  1. 在您的构建规则中,仅依靠自动 make 变量(例如 $<)来引用依赖项。当 make 执行源外构建时,它会使用可行的路径初始化自动变量。

  2. 通过显式路径引用源目录中的文件。

要单独使用选项 (1),您需要解决在(可能)不在路径中时如何 运行 generate 脚本的问题。您可以通过 shell 间接地 运行 来做到这一点。在这种情况下你想要的 make 规则是

hello.c: generate
    $(SHELL) $<

这应该适用于源内或源外构建。 $(SHELL) make 变量应由 Autotools 提供。

另一方面,要使用选项 (2),您可能会依赖 $(srcdir)$(top_srcdir):

# Note that the dependency name will always contain a '/':
hello.c: $(srcdir)/generate
    $<

(您也可以在构建配方中使用路径命名生成脚本,但通常最好避免重复。)$(srcdir)$(top_srcdir) 变量也由自动工具。前者指的是源码树中与我们当前构建的build-tree目录对应的目录;后者指的是包含 configure 脚本的源代码树目录。

在这两者中,本着外源构建的精神,我给 (1) 的评分更高一些,但实际上并没有太大区别。