configure.ac 介绍

configure.ac 是 Autotools 的配置入口文件。
它的作用是:在不同机器上探测编译环境,并生成可用的 configure 脚本与 Makefile

可以把它理解成“构建前的环境协商脚本”。

参考:

1. configure.ac 到底负责什么

核心职责有 4 个:

  1. 定义项目元信息(名字、版本、最低工具版本)。
  2. 检测工具链、头文件、库、函数是否可用。
  3. 定义条件编译和可替换变量。
  4. 生成目标文件(config.h、各目录 Makefile、其他 .in 模板)。

2. 常见宏分组(按用途记忆)

2.1. 项目初始化

1
2
3
4
AC_PREREQ([2.69])
AC_INIT([myapp], [1.0.0], [you@example.com])
AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_AUX_DIR([build-aux])

说明:

  1. AC_PREREQ:要求最低 autoconf 版本。
  2. AC_CONFIG_SRCDIR:确保在正确源码目录运行 configure
  3. AC_CONFIG_AUX_DIR:指定辅助脚本目录(install-shdepcomp 等)。

2.2. Automake 初始化

1
AM_INIT_AUTOMAKE([foreign subdir-objects -Wall])

常见选项:

  1. foreign:放宽 GNU 严格打包规范要求。
  2. subdir-objects:对象文件按子目录组织。
  3. -Wall / -Werror:启用警告或将警告视为错误。

2.3. 编译器与工具检测

1
2
3
4
5
AC_PROG_CC
AC_PROG_CXX
AC_PROG_YACC
AC_PROG_LEX
AM_PROG_AR

另外可用:

1
AC_CHECK_PROGS([PYTHON3], [python3 python], [:])

2.4. 头文件与库检查

1
2
AC_CHECK_HEADERS([stdio.h stdlib.h unistd.h])
AC_CHECK_LIB([m], [sqrt], [], [AC_MSG_ERROR([libm not found])])

2.5. 定义变量与宏

1
2
AC_DEFINE([ENABLE_TRACE], [1], [Enable trace logs])
AC_SUBST([EXTRA_CPPFLAGS], ['-I$(top_srcdir)/include'])

说明:

  1. AC_DEFINE:写入 config.h
  2. AC_SUBST:导出到 Makefile(用于 @VAR@ 替换)。

2.6. 输出目标

1
2
3
4
5
6
7
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([
Makefile
src/Makefile
tests/Makefile
])
AC_OUTPUT

3. 一个可直接使用的 configure.ac 模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
AC_PREREQ([2.69])
AC_INIT([myapp], [1.0.0], [you@example.com])
AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_AUX_DIR([build-aux])

AM_INIT_AUTOMAKE([foreign subdir-objects -Wall])

AC_PROG_CC
AC_PROG_CXX
AM_PROG_AR

AC_CHECK_HEADERS([stdio.h stdlib.h string.h])
AC_CHECK_LIB([pthread], [pthread_create], [], [AC_MSG_ERROR([pthread not found])])

AC_ARG_ENABLE([tests],
AS_HELP_STRING([--enable-tests], [Build unit tests]),
[enable_tests="$enableval"],
[enable_tests="no"])
AM_CONDITIONAL([BUILD_TESTS], [test "x$enable_tests" = "xyes"])

AC_SUBST([EXTRA_CPPFLAGS], ['-I$(top_srcdir)/include'])

AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([
Makefile
src/Makefile
tests/Makefile
])
AC_OUTPUT

4. 参数开关(AC_ARG_ENABLE / AC_ARG_WITH)

4.1. --enable-xxx

用于布尔开关:

1
2
3
4
AC_ARG_ENABLE([debug],
AS_HELP_STRING([--enable-debug], [Enable debug build]),
[enable_debug="$enableval"],
[enable_debug="no"])

4.2. --with-xxx=PATH

用于路径或外部组件位置:

1
2
3
4
5
AC_ARG_WITH([sdk-dir],
AS_HELP_STRING([--with-sdk-dir=PATH], [Path to external SDK]),
[SDK_DIR="$withval"],
[SDK_DIR="/usr"])
AC_SUBST([SDK_DIR])

5. 与 Makefile.am 如何联动

  1. configure.acAC_CONFIG_FILES([src/Makefile])
  2. src/Makefile.am 写编译/安装规则。
  3. 执行后由 src/Makefile.in 生成 src/Makefile

流程命令:

1
2
3
4
autoreconf -fi
./configure --prefix=/usr --enable-tests
make -j
make install DESTDIR=/tmp/pkgroot

6. .in 模板机制

任何 .in 文件都可以被 configure 替换占位符:

1
2
3
#!/bin/sh
CC='@CC@'
PREFIX='@prefix@'

前提是变量来自:

  1. autoconf 内置变量(如 @prefix@)。
  2. 你通过 AC_SUBST 导出的变量。

7. 常见坑

  1. AC_CONFIG_SRCDIR 指向了错误文件,导致在子目录运行时报错。
  2. 只写了 AC_SUBST,忘了在 Makefile.am/模板里使用。
  3. AC_CHECK_LIB 检查通过,但漏加实际链接参数(如 *_LDADD)。
  4. 加了 AC_DEFINE 却忘记 AC_CONFIG_HEADERS([config.h])
  5. 条件编译只写了 AC_ARG_ENABLE,忘了 AM_CONDITIONAL

8. 我的建议

  1. configure.ac 聚焦“环境检测与开关定义”,不要塞业务脚本逻辑。
  2. 检测失败就尽早 AC_MSG_ERROR,不要把错误拖到编译阶段。
  3. 每加一个新依赖,都补一条“检测 + 错误提示 + 链接使用”的闭环。

把这三点做扎实,configure.ac 会非常稳定,也更容易被团队维护。