autoconf命令

autoconf 命令 #

autoconf是 GNU 构建系统的一部分,用于生成自动配置脚本(通常命名为configure),这些脚本可以自动检测系统特性并适应不同的平台环境,从而使软件包能够在各种 Unix 类系统上编译。

语法 #

autoconf [选项]... [模板文件]

如果没有指定模板文件,默认使用configure.ac或旧式的configure.in

常用选项 #

选项 描述
-h, --help 显示帮助信息
-V, --version 显示版本信息
-v, --verbose 启用详细输出
-f, --force 强制更新所有生成的文件
-W 类别 报告指定类别的警告
-B 目录 将目录添加到搜索路径的开头
-I 目录 将目录添加到搜索路径
-o 文件 将输出保存到指定文件而不是configure
-t 文件 更新文件的时间戳
--include=目录 将目录添加到搜索路径(同-I)
--prepend-include=目录 将目录添加到搜索路径的开头(同-B)
--warnings=类别 报告指定类别的警告(同-W)
--trace=宏 报告宏的使用情况
--initialization 跟踪 autoconf 的初始化过程

基本用法 #

1. 生成配置脚本 #

autoconf

这将读取configure.ac(或configure.in)文件,并生成configure脚本。

2. 使用详细输出 #

autoconf -v

3. 强制重新生成 #

autoconf -f

4. 指定输出文件 #

autoconf -o my-configure

5. 指定模板文件 #

autoconf my-configure.ac

configure.ac 基本结构 #

configure.ac是 autoconf 的主要输入文件,包含了一系列宏调用,用于生成configure脚本。以下是一个基本的configure.ac文件结构:

# 初始化autoconf,指定包名称和版本
AC_INIT([mypackage], [1.0], [[email protected]])

# 检查基本程序
AC_PROG_CC
AC_PROG_INSTALL

# 检查头文件
AC_CHECK_HEADERS([stdlib.h string.h unistd.h])

# 检查库函数
AC_CHECK_FUNCS([malloc strdup])

# 检查类型定义
AC_TYPE_SIZE_T

# 配置输出文件
AC_CONFIG_FILES([Makefile src/Makefile])

# 生成配置头文件
AC_CONFIG_HEADERS([config.h])

# 完成配置
AC_OUTPUT

常用宏 #

1. 初始化和设置 #

描述
AC_INIT(包名, 版本, 错误报告地址) 初始化 autoconf
AC_CONFIG_SRCDIR(唯一文件) 指定源目录中的唯一文件,用于 sanity 检查
AC_CONFIG_HEADERS(文件) 指定要生成的配置头文件
AC_CONFIG_FILES(文件...) 指定要生成的文件列表
AC_CONFIG_AUX_DIR(目录) 指定辅助构建工具的目录
AC_CONFIG_MACRO_DIR(目录) 指定宏文件的目录
AC_PREREQ(版本) 指定所需的 autoconf 最低版本
AC_CANONICAL_HOST 确定主机系统类型
AC_CANONICAL_TARGET 确定目标系统类型
AC_PREFIX_DEFAULT(前缀) 设置默认安装前缀
AC_OUTPUT 生成配置文件并结束配置脚本

2. 程序和工具检查 #

描述
AC_PROG_CC 检查 C 编译器
AC_PROG_CXX 检查 C++编译器
AC_PROG_F77 检查 Fortran 77 编译器
AC_PROG_FC 检查 Fortran 编译器
AC_PROG_INSTALL 检查 install 程序
AC_PROG_MAKE_SET 检查 make 程序
AC_PROG_RANLIB 检查 ranlib 程序
AC_PROG_AWK 检查 awk 程序
AC_PROG_SED 检查 sed 程序
AC_PROG_YACC 检查 yacc 程序
AC_PROG_LEX 检查 lex 程序
AC_CHECK_PROG(变量, 程序, 值-如果找到, 值-如果未找到, [路径]) 检查特定程序
AC_PATH_PROG(变量, 程序, 值-如果未找到, [路径]) 检查程序并返回完整路径

3. 库和函数检查 #

描述
AC_CHECK_LIB(库, 函数, [动作-如果找到], [动作-如果未找到]) 检查库中的函数
AC_CHECK_FUNCS(函数列表, [动作-如果找到], [动作-如果未找到]) 检查函数是否存在
AC_REPLACE_FUNCS(函数列表) 检查函数,如果不存在则使用替代实现
AC_LIBOBJ(文件) 添加文件到要编译的对象文件列表
AC_SEARCH_LIBS(函数, 库列表, [动作-如果找到], [动作-如果未找到]) 在库列表中搜索函数

4. 头文件和结构检查 #

描述
AC_CHECK_HEADERS(头文件列表, [动作-如果找到], [动作-如果未找到]) 检查头文件是否存在
AC_CHECK_HEADER(头文件, [动作-如果找到], [动作-如果未找到]) 检查单个头文件
AC_HEADER_STDC 检查 ANSI C 头文件
AC_STRUCT_TIMEZONE 检查时区结构
AC_CHECK_MEMBERS([结构.成员], [动作-如果找到], [动作-如果未找到]) 检查结构成员

5. 类型检查 #

描述
AC_TYPE_SIZE_T 检查 size_t 类型
AC_TYPE_PID_T 检查 pid_t 类型
AC_TYPE_OFF_T 检查 off_t 类型
AC_TYPE_SIGNAL 检查信号处理程序返回类型
AC_CHECK_TYPES(类型列表, [动作-如果找到], [动作-如果未找到]) 检查类型是否存在
AC_CHECK_SIZEOF(类型, [默认]) 检查类型的大小

6. 系统特性检查 #

描述
AC_SYS_LARGEFILE 检查大文件支持
AC_FUNC_ALLOCA 检查 alloca 函数
AC_FUNC_MALLOC 检查 malloc 函数
AC_FUNC_REALLOC 检查 realloc 函数
AC_FUNC_MMAP 检查 mmap 函数
AC_CHECK_DECLS(符号列表, [动作-如果声明], [动作-如果未声明]) 检查符号是否已声明

7. 输出和消息 #

描述
AC_MSG_CHECKING(特性描述) 打印正在检查特性的消息
AC_MSG_RESULT(结果) 打印检查结果
AC_MSG_NOTICE(消息) 打印通知消息
AC_MSG_ERROR(错误消息, [退出状态=1]) 打印错误消息并退出
AC_MSG_WARN(警告消息) 打印警告消息
AC_MSG_FAILURE(错误消息, [退出状态=1]) 打印错误消息并退出

8. 变量和条件 #

描述
AC_DEFINE(变量, 值, [描述]) 定义 C 预处理器宏
AC_DEFINE_UNQUOTED(变量, 值, [描述]) 定义 C 预处理器宏,展开 shell 变量
AC_SUBST(变量, [值]) 替换输出文件中的变量
AC_ARG_ENABLE(特性, 帮助字符串, [动作-如果给定], [动作-如果未给定]) 添加–enable-特性选项
AC_ARG_WITH(包, 帮助字符串, [动作-如果给定], [动作-如果未给定]) 添加–with-包选项
AS_IF(测试1, [动作1], [测试2], [动作2], ..., [否则动作]) 条件执行
AS_CASE(字符串, [模式1], [动作1], ..., [默认动作]) 基于模式匹配执行动作

高级用法 #

1. 自定义宏 #

可以在aclocal.m4文件或m4目录中定义自定义宏:

# 定义检查特定库版本的宏
AC_DEFUN([MY_CHECK_LIB_VERSION],
[
  AC_MSG_CHECKING([for $1 version >= $2])
  AC_COMPILE_IFELSE(
    [AC_LANG_PROGRAM(
      [[#include <$1.h>]],
      [[#if $1_VERSION < $2
        #error Version too old
        #endif
      ]])],
    [
      AC_MSG_RESULT([yes])
      $3
    ],
    [
      AC_MSG_RESULT([no])
      $4
    ])
])

2. 条件配置 #

# 添加--enable-debug选项
AC_ARG_ENABLE([debug],
  [AS_HELP_STRING([--enable-debug], [enable debug mode])],
  [], [enable_debug=no])

# 根据选项设置编译标志
AS_IF([test "x$enable_debug" = xyes],
  [CFLAGS="$CFLAGS -g -O0 -DDEBUG"],
  [CFLAGS="$CFLAGS -O2"])

3. 检查外部包 #

# 添加--with-zlib选项
AC_ARG_WITH([zlib],
  [AS_HELP_STRING([--with-zlib=DIR], [use zlib in DIR])],
  [], [with_zlib=yes])

# 检查zlib
AS_IF([test "x$with_zlib" != xno],
  [
    AS_IF([test "x$with_zlib" != xyes],
      [
        CPPFLAGS="$CPPFLAGS -I$with_zlib/include"
        LDFLAGS="$LDFLAGS -L$with_zlib/lib"
      ])
    AC_CHECK_HEADERS([zlib.h], [], [AC_MSG_ERROR([zlib.h not found])])
    AC_CHECK_LIB([z], [inflate], [], [AC_MSG_ERROR([zlib not found])])
  ])

4. 生成多个输出文件 #

# 配置多个输出文件
AC_CONFIG_FILES([
  Makefile
  src/Makefile
  doc/Makefile
  tests/Makefile
])

5. 使用 autoheader 生成配置头文件 #

# 在configure.ac中
AC_CONFIG_HEADERS([config.h])

# 定义配置选项
AC_DEFINE([HAVE_FEATURE], [1], [Define if feature is available])

然后运行:

autoheader
autoconf

6. 使用 autoscan 生成 configure.ac 模板 #

autoscan

这将生成configure.scan文件,可以将其重命名为configure.ac并进行编辑。

完整构建系统示例 #

1. 目录结构 #

project/
├── configure.ac
├── Makefile.am
├── src/
│   ├── Makefile.am
│   ├── main.c
│   └── utils.c
└── include/
    └── utils.h

2. configure.ac #

# 初始化autoconf
AC_INIT([myproject], [1.0], [[email protected]])
AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])

# 初始化automake
AM_INIT_AUTOMAKE([-Wall -Werror foreign])

# 检查程序
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_MAKE_SET

# 检查库和头文件
AC_CHECK_HEADERS([stdlib.h string.h unistd.h])
AC_CHECK_FUNCS([malloc strdup])
AC_CHECK_LIB([m], [sqrt])

# 添加选项
AC_ARG_ENABLE([debug],
  [AS_HELP_STRING([--enable-debug], [enable debug mode])],
  [], [enable_debug=no])

AS_IF([test "x$enable_debug" = xyes],
  [CFLAGS="$CFLAGS -g -O0 -DDEBUG"],
  [CFLAGS="$CFLAGS -O2"])

# 配置输出文件
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([
  Makefile
  src/Makefile
])

# 完成配置
AC_OUTPUT

3. Makefile.am(顶层) #

SUBDIRS = src
dist_doc_DATA = README.md

4. src/Makefile.am #

bin_PROGRAMS = myprogram
myprogram_SOURCES = main.c utils.c
myprogram_CPPFLAGS = -I$(top_srcdir)/include

5. 构建步骤 #

# 生成aclocal.m4
aclocal

# 生成config.h.in
autoheader

# 生成configure脚本
autoconf

# 生成Makefile.in文件
automake --add-missing

# 配置项目
./configure

# 构建项目
make

# 安装项目
make install

实用示例 #

1. 检查特定版本的编译器 #

AC_PREREQ([2.69])
AC_INIT([myproject], [1.0])

# 检查C编译器
AC_PROG_CC
AC_LANG([C])

# 检查GCC版本
AS_IF([test "x$GCC" = xyes],
  [
    AC_MSG_CHECKING([if GCC version is >= 4.8])
    AC_COMPILE_IFELSE(
      [AC_LANG_PROGRAM(
        [[
          #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)
          #error GCC version is too old
          #endif
        ]],
        [[]])],
      [
        AC_MSG_RESULT([yes])
      ],
      [
        AC_MSG_RESULT([no])
        AC_MSG_ERROR([GCC version must be at least 4.8])
      ])
  ])

AC_OUTPUT

2. 检查系统特性并适配代码 #

AC_INIT([myproject], [1.0])
AC_CONFIG_HEADERS([config.h])

# 检查大小端
AC_C_BIGENDIAN(
  [AC_DEFINE([IS_BIG_ENDIAN], [1], [Define if system is big endian])],
  [AC_DEFINE([IS_LITTLE_ENDIAN], [1], [Define if system is little endian])])

# 检查类型大小
AC_CHECK_SIZEOF([int])
AC_CHECK_SIZEOF([long])
AC_CHECK_SIZEOF([void *])

# 检查特定函数
AC_CHECK_FUNCS([mmap posix_memalign])

AC_OUTPUT

3. 配置可选功能 #

AC_INIT([myproject], [1.0])
AC_CONFIG_HEADERS([config.h])

# 添加可选功能
AC_ARG_ENABLE([feature1],
  [AS_HELP_STRING([--enable-feature1], [enable feature1 support])],
  [], [enable_feature1=no])

AC_ARG_ENABLE([feature2],
  [AS_HELP_STRING([--enable-feature2], [enable feature2 support])],
  [], [enable_feature2=no])

# 根据选项配置
AS_IF([test "x$enable_feature1" = xyes],
  [AC_DEFINE([HAVE_FEATURE1], [1], [Define if feature1 is enabled])])

AS_IF([test "x$enable_feature2" = xyes],
  [
    # 检查feature2所需的库
    AC_CHECK_LIB([feature2], [feature2_func], [],
      [AC_MSG_ERROR([feature2 requested but library not found])])
    AC_DEFINE([HAVE_FEATURE2], [1], [Define if feature2 is enabled])
  ])

AC_OUTPUT

4. 跨平台配置 #

AC_INIT([myproject], [1.0])
AC_CONFIG_HEADERS([config.h])

# 检查系统类型
AC_CANONICAL_HOST

# 根据系统类型配置
case $host_os in
  linux*)
    AC_DEFINE([OS_LINUX], [1], [Define if on Linux])
    ;;
  darwin*)
    AC_DEFINE([OS_MACOS], [1], [Define if on macOS])
    ;;
  mingw*|cygwin*|msys*)
    AC_DEFINE([OS_WINDOWS], [1], [Define if on Windows])
    ;;
  *)
    AC_MSG_WARN([Unsupported operating system: $host_os])
    ;;
esac

AC_OUTPUT

5. 检查外部依赖 #

AC_INIT([myproject], [1.0])
AC_CONFIG_HEADERS([config.h])

# 检查pkg-config
PKG_PROG_PKG_CONFIG

# 检查libpng
PKG_CHECK_MODULES([PNG], [libpng >= 1.6.0],
  [
    AC_DEFINE([HAVE_LIBPNG], [1], [Define if libpng is available])
  ],
  [
    AC_MSG_WARN([libpng not found, PNG support will be disabled])
  ])

# 将标志添加到Makefile
AC_SUBST([PNG_CFLAGS])
AC_SUBST([PNG_LIBS])

AC_OUTPUT

常见问题排查 #

1. 找不到宏 #

错误:

configure.ac:10: error: possibly undefined macro: AM_INIT_AUTOMAKE

解决方案:

# 添加automake宏
AC_CONFIG_MACRO_DIR([m4])
# 确保运行aclocal时包含正确的目录

2. 缺少文件 #

错误:

configure: error: cannot find install-sh, install.sh, or shtool in build-aux "."/build-aux

解决方案:

# 指定辅助目录
AC_CONFIG_AUX_DIR([build-aux])
# 运行automake --add-missing来创建缺少的文件

3. 版本不兼容 #

错误:

warning: The macro `AC_HELP_STRING' is obsolete.

解决方案:

# 使用新的宏
# 旧: AC_HELP_STRING([--enable-feature], [description])
# 新: AS_HELP_STRING([--enable-feature], [description])

4. 缺少 m4 目录 #

错误:

configure.ac:8: warning: cannot find macro directory 'm4'

解决方案:

# 创建m4目录
mkdir -p m4

与其他自动化构建工具的比较 #

工具 优点 缺点 适用场景
autoconf 广泛支持、成熟、强大的系统检测 语法复杂、学习曲线陡峭 需要广泛兼容性的 Unix/Linux 项目
CMake 跨平台、现代语法、IDE 支持 不如 autoconf 在 Unix 系统上灵活 跨平台项目、需要 IDE 集成
Meson 快速、简单、现代 相对较新、不如 autoconf 成熟 新项目、注重构建速度
SCons Python 语法、灵活 构建速度较慢 Python 项目、需要高度定制的构建系统

提示和技巧 #

1. 使用 autoreconf 简化流程 #

# 一步完成所有autotools步骤
autoreconf -i

2. 使用宏包 #

# 在configure.ac中
# 使用gettext宏
AM_GNU_GETTEXT([external])
AM_GNU_GETTEXT_VERSION([0.19])

# 使用libtool宏
LT_INIT

3. 调试 configure 脚本 #

# 运行configure时启用shell调试
sh -x ./configure

4. 使用 config.site 文件 #

创建~/.config.site文件来设置默认选项:

# 默认启用调试
enable_debug=yes

# 默认安装前缀
prefix=/opt/local

5. 使用 AC_CONFIG_COMMANDS 执行自定义命令 #

AC_CONFIG_COMMANDS([stamp-h], [date > stamp-h])

扩展阅读 #