Autotools 基础

在使用 ebuild 时,了解 GNU autotools(automakeautoconf 等)会很有帮助。

主要的 Autotools 组件

Autotools 是一个相关软件包的集合,当一起使用时,可以消除创建可移植软件过程中的大部分困难。这些工具连同一些相对简单的上游提供的输入文件一起,用于创建软件包的构建系统。

How autotools fits together

主要 Autotools 组件如何协同工作的一个基本概述。

在简单的设置中

  • autoconf 程序从 configure.inconfigure.ac(参见下面的注释)生成 configure 脚本。
  • automake 程序从 Makefile.am 生成 Makefile.in
  • configure 脚本运行以从 Makefile.in 文件生成一个或多个 Makefile 文件。
  • make 程序使用 Makefile 编译程序。

您可能会看到 Autotools 在各种阶段函数中使用。 src_prepare 函数是在配置和编译之前操作源代码的最合适的地方。特别是,在 src_configure 之前调用 src_prepare,后者通常期望 configure 脚本存在。

autoreconf 工具据说根据需要运行 autoconf(以及 automakeautoheaderaclocalautopointlibtoolize)。有时它能正常工作。一些软件包附带一个名为 autogen.sh 的 shell 脚本,它执行相同的功能(这与 autogen 无关)。autotools.eclass 包含用于独立工具的帮助器函数,以及它们对应的名称,例如 eautoconfeautomake

简单的 Autotools 打补丁示例

以下代码片段说明了在修补 Makefile.amconfigure.ac 后继续进行的正确方法。

EAPI=8

WANT_AUTOCONF=2.5
WANT_AUTOMAKE=1.9
inherit autotools

IUSE="nls"

BDEPEND="nls? ( sys-devel/gettext )"

src_prepare() {
	default

	# Remove problematic LDFLAGS declaration
	sed -i -e '/^LDFLAGS/d' src/Makefile.am || die

	# Rerun autotools
	eautoreconf
}

src_configure() {
	econf $(use_enable nls)
}

configure.ac 文件

configure.ac 文件用于创建 ./configure 脚本。它由一系列宏组成,这些宏由 autoconf 处理和扩展。这些宏可以检查软件包和库,处理 --enable--with 开关,并生成各种文件。

configure.ac 的基本格式

configure.ac 文件是一个基本的文本文件。缩进和空格在很大程度上无关紧要。注释由字符串 dnl 表示(dnl 实际上是一个丢弃输入其余部分的宏——它代表“丢弃新行”)。

如果上一句话让你感到不安,你可能应该停止阅读此页面。情况会变得更糟。

一个典型的文件可能以类似以下内容开头

dnl Process this file with autoconf
AC_INIT(appname, 0.1)
AC_PREREQ(2.5)
AC_CONFIG_SRCDIR(src/main.c)
AC_CONFIG_AUX_DIR(config)
AM_INIT_AUTOMAKE(1.8)

如果存在,AC_PREREQ 行会告诉您需要哪个 autoconf 版本。这很有用,因为不同版本的 autoconf 之间不兼容。在上面的示例中,我们需要 =autoconf-2.5*,并且在调用 autoconf 时,我们应该 export WANT_AUTOCONF="2.5"(或使用 autoconf-2.59 脚本)。

AM_INIT_AUTOMAKE 行告诉我们我们需要哪个 automake 版本。同样,automake-1.7 脚本几乎不可能与 automake-1.8 正常工作。在环境中设置 WANT_AUTOMAKE="1.8" 可以使未版本化的 automake 调用运行正确的版本。

通常,一些标准检查将紧随其后

dnl Check for toolchain and install components
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_RANLIB

对于非标准应用程序,您也可能会看到手动检查

dnl Check for sed
AC_CHECK_PROGS(regex_cmd, sed)
if test x$regex_cmd = "x" ; then
    AC_MSG_ERROR([sed is required to build the data files.])
fi

您也可能会看到编译器特性的检查

dnl Check that our compiler can do const and inline
AC_C_CONST
AC_C_INLINE

库和头文件检查

dnl Check for standard headers:
AC_HEADER_STDC
AC_HEADER_DIRENT
AC_CHECK_HEADERS([stdlib.h stdio.h libintl.h locale.h])

dnl Check for libraries:
AC_CHECK_LIB(ssl, SSL_free)

以及函数检查

dnl Check for functions:
AC_CHECK_FUNCS([setlocale strtol])

通常这些都会混在一起,没有任何有用的注释。在某些情况下,许多进行的检查对于相关的应用程序甚至不是必需的——大多数 Autotools 代码都是复制/粘贴而不是从头编写的,并且 autoscan(一个帮助编写 configure.ac 的工具)有时会过于急切地添加检查。

文件将以一些输出函数结束

AM_CONFIG_HEADER(config.h)
AC_OUTPUT(Makefile src/Makefile nls/Makefile man/Makefile tests/Makefile)

这些用于使 ./configure 脚本生成相关文件。

启用和禁用检查

到目前为止,我们只看到了“硬”依赖关系。许多软件包对各种额外功能(图形工具包、添加功能的库、解释器、特性等)提供可选支持。如果我们幸运的话,这可以通过 --enable-foo--disable-foo 开关传递给 ./configure 来处理,这些开关是从 autoconf 规则生成的。

一个简单的 --enable / --disable 函数可能看起来像下面这样

AC_MSG_CHECKING(--enable-cscope argument)
AC_ARG_ENABLE(cscope,
    [  --enable-cscope         Include cscope interface.],
    [enable_cscope=$enableval],
    [enable_cscope="no"])
AC_MSG_RESULT($enable_cscope)
if test "$enable_cscope" = "yes"; then
  AC_DEFINE(FEAT_CSCOPE)
fi

有时会根据某个选项是否启用包含更复杂的检查。还有一些预定义的宏,包括 AC_ARG_ENABLE。因此,使用 AC_ARG_ENABLEconfigure.ac 进行 grep 可能不会给出完整的列表。更好的方法是使用 ./configure --help 并检查输出。

检查软件包是否正确使用此宏的一种简单方法是安装可选依赖项,然后尝试所有 ./configure./configure --enable-foo./configure --disable-foo。如果第二次和第三次运行给出相同的结果,则说明某些地方出了问题。如果第一次运行的结果与第二次和第三次不同,则很有可能误解了 AC_ARG_ENABLE 参数。

带和不带检查

一个简单的 --with / --without 检查可能如下所示

AC_MSG_CHECKING([whether to enable foo])
AC_ARG_WITH(foo,
    [  --with-foo           enable foo support],
    with_foo=$withval,
    with_foo=yes)
AC_MSG_RESULT($with_foo)

同样,第三个参数用于“指定”,第四个参数用于“未指定”,并且有一些标准宏包含 with 选项。

自动检查

可以编写绕过手动启用/禁用约定的 autoconf 规则(或者只是忽略用户请求的内容)。如果您的软件包执行此操作,则必须对其进行修复以避免依赖项问题。

最常见的形式是软件包简单地使用 AC_CHECK_LIB 来决定是否启用某个功能。如果您发现某个软件包执行此操作,则必须更改其行为。

configure.ac 的引用规则

在后台,autoconf 大量使用 m4 宏处理器来完成工作。 m4 的引号字符由 autoconf 设置为 [],分别表示开始和结束引号。使用 "' 可能会产生意外的结果。

要包含一个文字左方括号,最简单的方法是使用特殊字符串 @<:@。对于右方括号,使用 @:>@

例如

AC_MSG_RESULT(the first)
AC_MSG_RESULT([the second])
AC_MSG_RESULT("the third")
AC_MSG_RESULT(@<:@the fourth@:>@)
AC_MSG_RESULT([@<:@the fifth@:>@])

给出

    the first
    the second
    "the third"
    [the fourth]
    [the fifth]

如有疑问,通常最安全的方法是使用 [ ] 引用宏参数,而不是不加引用。

Makefile.am 文件

Makefile.am 文件由 automake 处理以创建 Makefile.inMakefile.in 又由 configure 处理以创建 MakefileMakefile 又由 make 用于构建软件。

基本格式类似于 Makefile。但是,您会看到设置了各种“特殊”变量,而不是手动编写每个规则。

一个非常简单的例子

bin_PROGRAMS = myapp
myapp_SOURCES = myapp_commandline.c myapp.c

所有标准的 GNU 规则都将生成,因此 makemake cleanmake distcleanmake dist 等等都将在这里工作。

您也可能会看到一些标准的 Makefile 结构出现在没有标准的 automake 方法来处理某些任务时。例如

CLEANFILES = glep31check.1
man_MANS = glep31check.1
EXTRA_DIST = glep31check.in

%.1 : %.in
    @regex_cmd@ -e "s,\@VERSION\@,$(VERSION),g" $? > $@

这里, @regex_cmd@ 变量将被替换为 configure 在创建 Makefile 时检测到的任何内容(在本例中为 sed)。这通过 configure.ac 中的宏 AC_SUBST(VARNAME) 处理。

Makefile 变量

有时,行为不良的 Makefile.am 文件会覆盖用户变量,例如 CFLAGS。不允许这样做——请参阅不筛选变量。在这些情况下,应该使用单独的特殊变量——例如,为了设置 CFLAGSMakefile.am 应该使用 AM_CFLAGS,以便不会忽略用户首选项。

因此,如果 Makefile.am 包含,比如说

CFLAGS="-Wall"

您应该使用 sedpatch 将其修改为

AM_CFLAGS="-Wall"

如果您这样做,请记住手动运行 autoconf 然后 automake

config.h.in 文件

config.h.in 文件由 autoheader 生成。通常您不必担心这个问题,但偶尔您可能需要在构建过程中手动运行 autoheader,如果上游没有提供预生成的版本。

aclocalm4 文件

configure.acconfigure.in 文件中,您不仅可以调用 autoconfautomake 定义的默认宏,还可以调用由特定软件包(如库和程序)定义的其他函数,以正确的方式检查其功能。

这些函数(通常)在 m4 文件中定义,这些文件由软件包放置在 /usr/share/aclocal 目录中。当您需要重新生成 autotools 文件时,可能会出现问题,因为 configure.ac 文件使用的函数可以在用户系统上未安装的 m4 宏文件中定义。例如,对于某些需要库并由 USE 标志禁用的可选功能就是这种情况。如果 m4 文件未安装在用户系统上,则 autoconf 步骤将失败。

为了解决这个问题,大多数软件包只是将其 configure.ac 所需的 m4 宏文件放在源软件包中的 m4 子目录中。不幸的是,即使存在,并非所有 m4 目录都是完整的。

在这些情况下,您需要找出 m4 文件,通常由依赖项安装在 /usr/share/aclocal 中,并确保 src_unpack 阶段使 autotools 可以使用这些文件并调用 aclocal 来重新创建 aclocal.m4 文件,该文件在创建配置脚本时由 autoconf 使用。

通常缺少的不仅仅是一个 m4 文件,因此您可能希望将它们打包成一个 tarball,并将其添加到 SRC_URI 中。在确保 tarball 提取到 ${WORKDIR} 中的某个位置(例如,在 gentoo-m4 目录中)后,通常有两种处理这些宏文件的一般方法,一种用于带有不完整 m4 目录的软件包,另一种用于不带 m4 目录的软件包。

在第一种情况下,您通常希望执行以下操作

WANT_AUTOCONF="2.5"
inherit autotools

src_prepare() {
	default

	einfo "Regenerating autotools files..."
	cp "${WORKDIR}/gentoo-m4" "${S}/m4" || die "m4 copy failed"
	eaclocal -I "${S}/m4"
	eautoconf
}

等等。在第二种情况下,您可以通过这种方式简化它

WANT_AUTOCONF="2.5"
inherit autotools

src_prepare() {
	default

	einfo "Regenerating autotools files..."
	eaclocal -I "${WORKDIR}/gentoo-m4"
	eautoconf
}

无需复制文件。

当分发版中缺少所需的 m4 文件时,最好始终通知上游,要求他们在源 tarball 中添加所有所需的文件,以避免如果宏发生更改则版本冲突。

Libtool

更多 autotools 阅读资料

有关 autotools 的更多详细信息