资讯动态

autoconf/automake原理与实战:GNU构建系统详解

发布时间:2026/10/15 9:52:18 来源:尧图企业网站定制
1. 为什么今天还要啃透 autoconf/automake 这套“老古董”你打开一个 GitHub 上星标过万的 C 语言开源项目比如某个嵌入式通信协议栈、某个跨平台图像处理库或者某款老牌命令行工具——十有八九你会在根目录下看到这四个文件configure.ac、Makefile.am、configure、Makefile.in。接着执行./configure make sudo make install一切丝滑如初。但如果你试着删掉configure直接make大概率会得到一串红色报错“No rule to make target all”或者更绝望的“error: config.h.in not found”。这不是玄学是 GNU 构建系统GNU Build System在工作。它不是为炫技而生而是为解决一个真实到骨子里的工程问题如何让同一份 C 源码在 x86_64 的 Ubuntu 24.04、ARM64 的 Debian 12、甚至老旧的 CentOS 7 上都能自动适配编译器版本、头文件路径、库函数是否存在、系统调用差异最终生成可运行的二进制这个问题gcc main.c一行命令解决不了CMakeLists.txt在某些嵌入式交叉编译场景里也未必能兜底而autoconf和automake就是为此打磨了三十年的“工程级胶水”。我第一次被这套工具“教育”是在给某高校实验室维护一个基于 POSIX 的实时日志分析模块时。原作者只在自己的 Fedora 工作站上测试过代码里硬编码了/usr/include/bsd/路径用了strlcpy这个非标准函数。当把它部署到目标服务器CentOS 7 glibc 2.17时make直接失败。当时我花了整整两天手动改头文件包含路径、写条件编译宏、替换字符串函数……最后发现只要把AC_CHECK_FUNCS([strlcpy])加进configure.ac再在源码里用#ifdef HAVE_STRLCPY包裹整个适配过程就变成了./configure时的一次自动探测。那一刻我才明白autoconf不是写配置是在给代码装上“环境感知神经”。这套工具链的核心价值从来不是“多了一层抽象”而是把“人脑判断环境差异”的过程固化成可复现、可审计、可协作的机器逻辑。它不替代 Makefile而是生成 Makefile它不替代 C 编译器而是告诉编译器“该用什么参数、链接什么库”。关键词不是“自动化”而是“可移植性”与“确定性”。当你需要交付一个能被下游用户git clone ./configure --prefix/opt/myapp make install一键部署的 C 项目时这套工具就是你工程信誉的基石。2. autoconf 与 automake分工明确的“探路者”与“施工队”很多人把autoconf和automake当成一个整体甚至误以为automake是autoconf的子命令。这是个危险的误解。它们是两个独立工具职责清晰协作紧密就像建筑工地上的地质勘探队和施工队——前者负责摸清地底岩层、地下水位、断层走向即系统环境后者根据勘探报告绘制施工图纸、调度钢筋水泥、安排浇筑顺序即生成符合 GNU 标准的 Makefile。2.1 autoconf环境探测的“地质雷达”autoconf的核心输入是configure.ac旧称configure.in这是一个用 M4 宏语言写的脚本。M4 看似古怪但它本质是一种“元编程”工具它不直接生成 C 代码而是生成能生成 C 代码的 shell 脚本即configure。configure.ac中每一行AC_*宏都是一个探测指令AC_INIT([myproject], [1.0.0], [bugexample.com])这不是简单的项目声明。它会自动生成config.h头文件中的PACKAGE_NAME、PACKAGE_VERSION宏并在configure脚本中初始化错误处理逻辑。更重要的是它隐含了对autotools版本兼容性的检查——如果用户用太老的autoconf运行它会直接报错避免后续探测失真。AC_PROG_CC表面看只是找gcc或clang实则触发一整套探测链先尝试gcc失败则试cc再失败则试clang找到后还会运行gcc -v提取版本号用gcc -dumpmachine确认目标架构并设置CC变量为最终选定的编译器路径。这个过程比你在Makefile里写CC gcc严谨一万倍。AC_CHECK_HEADERS([sys/epoll.h, poll.h])这里不是简单检查头文件存不存在。autoconf会实际调用gcc -E对一个最小测试程序进行预处理捕获#include sys/epoll.h是否成功。如果失败它不会报错退出而是定义HAVE_SYS_EPOLL_H0并在生成的config.h中写入/* #undef HAVE_SYS_EPOLL_H */。你的 C 代码就可以安全地写#ifdef HAVE_SYS_EPOLL_H #include sys/epoll.h // 使用 epoll #else #include poll.h // 使用 poll #endif这种“探测即定义”的机制彻底消除了手动#ifdef __linux__的脆弱性——因为__linux__宏只告诉你操作系统却无法告诉你内核是否真的支持epoll系统调用。提示AC_CHECK_FUNCS([strlcpy])的探测原理更精妙。它会生成一个临时 C 文件里面调用strlcpy然后用gcc -c尝试编译。如果链接失败undefined reference说明函数不存在如果编译通过则定义HAVE_STRLCPY。这种“编译时验证”比单纯查头文件可靠得多因为它验证了函数的可用性而非仅仅是声明存在。2.2 automakeMakefile 的“标准化生成器”如果说autoconf解决了“能不能编译”的问题automake解决的就是“怎么高效、规范、可维护地编译”的问题。它的输入是Makefile.am输出是Makefile.in再经configure处理成最终的Makefile。Makefile.am看似像简化版 Makefile但它是声明式的。你不用写gcc -o main.o -c main.c这样的具体命令而是写bin_PROGRAMS myapp myapp_SOURCES main.c utils.c myapp_CFLAGS $(AM_CFLAGS) -Wall -Wextra这段代码背后automake做了三件关键事自动推导依赖关系它会扫描main.c和utils.c中的#include自动生成.d依赖文件规则确保头文件修改后相关.o文件能被自动重新编译。你再也不用手动维护main.o: main.c utils.h这类易出错的规则。强制 GNU 标准化automake会注入install,uninstall,dist,distcheck,clean等所有 GNU 标准目标。其中distcheck是灵魂——它会自动打包源码、解压到临时目录、运行完整./configure make make check make install流程验证你的发布包是否真正可构建。这是CMake的cpack都难以完全替代的“发布前终极压力测试”。变量层级管理myapp_CFLAGS中的$(AM_CFLAGS)是automake预设的“项目级 CFLAGS”而AM_CFLAGS又可能来自configure.ac中的AC_SUBST([AM_CFLAGS], [-O2])。这种变量继承链让编译选项的管理变得层次分明用户可通过./configure CFLAGS-g -O0覆盖默认值而项目维护者只需在Makefile.am中声明myapp_CFLAGS无需关心底层细节。注意automake从不直接调用gcc。它生成的Makefile.in里所有编译命令都形如$(CC) $(CFLAGS) $(myapp_CFLAGS) -c $ -o $。真正的CC和CFLAGS值由configure脚本在运行时根据探测结果填入。这种“配置与构建分离”的设计是 GNU 构建系统健壮性的根基。3. 从零搭建一个可发布的 C 项目手把手走通全流程理论讲完现在我们动手搭一个最小但完整的可发布 C 项目。目标一个名为hello-world的命令行工具打印带时间戳的问候语并能被用户在任意 Linux 发行版上./configure make install。整个过程不依赖任何 IDE只用终端和基础工具。3.1 初始化项目骨架与基础文件首先创建项目目录并初始化 Git虽然autotools不依赖 Git但现代协作离不开它mkdir hello-world cd hello-world git init接着创建最核心的三个文件。注意它们的文件名是约定俗成的不能随意更改configure.acautoconf的输入脚本Makefile.amautomake的输入脚本src/main.c我们的主程序先放一个极简版本configure.ac内容如下请严格按此格式空格和换行都重要# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.71]) AC_INIT([hello-world], [0.1.0], [supportexample.com]) AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_HEADERS([config.h]) # 初始化 automake必须放在 AC_PROG_CC 之前 AM_INIT_AUTOMAKE([-Wall -Werror foreign]) # 检查编译器 AC_PROG_CC # 检查时间函数为后续扩展留接口 AC_CHECK_FUNCS([clock_gettime]) # 输出最终的 Makefile AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT这里的关键点解析AC_PREREQ([2.71])声明最低autoconf版本。2.71是当前广泛兼容的稳定版低于此版本会报错。AC_CONFIG_SRCDIR([src/main.c])这是autoconf的“锚点”。它确保configure脚本只能在项目根目录运行防止用户误入子目录执行导致路径混乱。AM_INIT_AUTOMAKE([...])启用automakeforeign模式表示不强制要求NEWS、README等 GNU 标准文件适合小项目-Wall -Werror让automake在生成Makefile.in时开启所有警告并视为错误提前暴露配置问题。AC_CONFIG_FILES([...])声明要生成哪些Makefile.in。因为我们把源码放在src/子目录所以必须显式列出src/Makefile。Makefile.am内容放在项目根目录# 顶层 Makefile.am定义子目录 SUBDIRS src # 定义 dist发布包包含的文件 EXTRA_DIST README.md # 顶层安装规则可选 install-exec-hook: echo Installation completed successfully!src/Makefile.am需手动创建src/目录# 定义要安装的可执行程序 bin_PROGRAMS hello-world # 定义该程序的源文件 hello-world_SOURCES main.c # 定义编译时需要的头文件此处引用 config.h hello-world_CPPFLAGS -I$(top_builddir) -I$(top_srcdir) # 定义链接时需要的库此处无额外库 hello-world_LDADD # 安装后程序的权限默认 0755可省略src/main.c极简版仅验证流程#include stdio.h #include time.h int main(int argc, char *argv[]) { time_t now time(NULL); printf(Hello, World! Built at %s, ctime(now)); return 0; }3.2 运行 autoreconf一次调用全链路生成现在项目骨架已备。下一步不是手动运行autoconf和automake而是使用autoreconf—— 这是 GNU 官方推荐的“一站式”工具它会智能判断缺失哪些中间文件并按正确顺序调用所有必要工具。# 确保已安装必要工具Ubuntu/Debian sudo apt-get install autoconf automake libtool pkg-config # 在项目根目录运行 autoreconf --install --verbose--install参数至关重要它会自动将automake所需的辅助文件如install-sh,missing,depcomp复制到项目中。这些文件是 GNU 构建系统的“基础设施”没有它们make会报各种奇怪的错误比如make: *** No rule to make target install-sh。执行后你会看到类似输出autoreconf: export WARNINGS autoreconf: Entering directory . autoreconf: configure.ac: not using Gettext autoreconf: running: aclocal --force -I m4 autoreconf: configure.ac: tracing autoreconf: configure.ac: creating directory build-aux autoreconf: running: libtoolize --copy --force autoreconf: running: /usr/bin/autoconf --force autoreconf: running: /usr/bin/autoheader --force autoreconf: running: automake --add-missing --copy --force-missing autoreconf: Leaving directory .此时项目根目录下会多出这些关键文件configure由autoconf生成的 shell 脚本用户唯一需要运行的入口。Makefile.in和src/Makefile.in由automake生成的模板文件。config.h.in由autoheader生成的头文件模板其中包含#undef HAVE_CLOCK_GETTIME等占位符。build-aux/目录存放install-sh,missing等辅助脚本。m4/目录存放libtool等宏定义如果用了libtoolize。实操心得autoreconf --install是“神圣不可侵犯”的第一步。我曾见过团队成员为了“省事”手动运行autoconf后发现make报错折腾半天才发现漏了automake --add-missing。记住永远用autoreconf --install它是经过三十年验证的、最可靠的启动方式。3.3 构建、安装与验证从源码到可执行现在项目已具备“开箱即用”的能力。让我们走一遍标准用户流程# 1. 运行 configure探测环境生成最终 Makefile ./configure --prefix/tmp/hello-test # 2. 编译 make # 3. 运行测试可选我们没写 test跳过 # make check # 4. 安装到指定前缀 sudo make install # 5. 验证安装结果 /tmp/hello-test/bin/hello-world # 输出应为Hello, World! Built at Thu Jun 20 10:30:45 2024./configure的执行过程值得深究。它会读取configure.ac中的AC_PROG_CC找到gcc并测试其功能读取AC_CHECK_FUNCS([clock_gettime])编译一个测试程序确认clock_gettime是否可用将探测结果填入config.h例如如果clock_gettime存在则写#define HAVE_CLOCK_GETTIME 1将$(prefix)值/tmp/hello-test填入Makefile中所有$(prefix)占位符最终生成Makefile和config.h。此时make命令之所以能工作是因为Makefile中已经包含了所有gcc调用的具体命令、依赖规则、以及-I/tmp/hello-test/include这样的路径。整个过程用户无需知道gcc在哪、config.h怎么生成、src/目录如何参与构建——configure和Makefile已将所有复杂性封装完毕。4. 常见陷阱与排错指南那些让你抓狂的“红字”从何而来即使严格按照上述步骤操作autotools项目在构建时仍可能抛出令人困惑的错误。这些错误往往源于对工具链工作流的细微误解。下面是我踩过的、也是社区高频提问的几类典型问题附带完整的排查链路。4.1 错误configure: error: cannot find install-sh, install.sh, or shtool in . ./.. ./../..现象运行./configure时第一行就报错提示找不到install-sh。根因定位install-sh是automake生成的辅助脚本位于build-aux/目录。这个错误意味着autoreconf --install没有成功执行或者执行后build-aux/目录被意外删除。完整排查链路检查build-aux/目录是否存在ls -la build-aux/。如果不存在说明autoreconf --install未运行或失败。如果build-aux/存在检查install-sh是否在其中ls build-aux/install-sh。如果不存在可能是automake版本太低或autoreconf被中断。强制重新生成rm -rf build-aux/ autoreconf --install。注意--install是关键缺了它automake不会复制辅助文件。验证configure脚本头部用head -n 10 configure | grep build-aux应能看到类似# Generated by GNU Autoconf 2.71.和# Report bugs to bug-autoconfgnu.org.的注释证明它是autoconf正确生成的。提示很多开发者习惯用git clean -fdx清理工作区但这会删除build-aux/。正确做法是git clean -fdX大写 X它会忽略.gitignore中的文件而build-aux/通常在.gitignore里。4.2 错误Makefile:xxx: *** missing separator. Stop.现象运行make时报错说某行缺少分隔符通常是 Tab 字符。根因定位这是Makefile语法的铁律所有命令行即target: dependencies下面的gcc ...这些行必须以 Tab 字符开头不能是空格。而Makefile.in是由automake生成的理论上不应有此问题。所以这个错误几乎 100% 意味着你手动编辑了Makefile.in或Makefile并且在命令行前误用了空格。完整排查链路确认错误行号Makefile:123打开Makefile跳转到第 123 行。用cat -A Makefile | sed -n 123p查看该行的“可视字符”。^I表示 Tab 空格就是空格。如果看到的是空格就是问题所在。修复方法绝对不要手动修改Makefile.in或Makefile。回到源头检查Makefile.am。常见错误是# 错误在 .am 文件里写了命令这是 automake 禁止的 all: echo building... # 这行前面如果是空格生成的 Makefile.in 也会是空格正确做法是Makefile.am只写声明bin_PROGRAMS,SOURCES所有命令逻辑交给configure.ac的AC_CONFIG_COMMANDS或自定义Makefile规则需用%.o: %.c这种模式规则。4.3 错误src/main.c:10:10: error: clock_gettime was not declared in this scope现象make编译时报错说clock_gettime函数未声明尽管configure显示探测成功。根因定位AC_CHECK_FUNCS([clock_gettime])只探测函数是否可链接但clock_gettime需要#include time.h和链接-lrt库。automake默认不链接rt库且config.h的#define只影响#ifdef不影响头文件包含。完整排查链路检查config.hgrep HAVE_CLOCK_GETTIME config.h。如果输出#define HAVE_CLOCK_GETTIME 1说明探测成功。检查src/main.c确认是否#include time.h。是没问题。检查链接库clock_gettime在librt中必须显式链接。在src/Makefile.am中添加hello-world_LDADD -lrt重新运行make。如果还报错检查configure日志cat config.log | grep -A5 -B5 clock_gettime确认探测时是否真的链接成功。经验技巧对于需要额外库的函数autoconf提供了更安全的宏AC_SEARCH_LIBS([clock_gettime], [rt], [], [AC_MSG_ERROR([clock_gettime not found])])。它会先尝试不加-l链接失败后再试-lrt并将结果存入LIBS变量automake会自动将其注入链接命令。5. 与 CMake 的对比何时该坚持 autotools何时该果断切换CMake如今已是 C/C 项目的事实标准那么autoconf/automake是否已成历史答案是否定的。二者不是简单的“新 vs 旧”而是“通用 vs 专用”的互补关系。选择哪个取决于你的项目基因和交付场景。5.1 autotools 的不可替代优势场景场景一需要极致的 POSIX 兼容性与“零依赖”构建假设你要为一个资源极度受限的嵌入式设备如只有 BusyBox 的 ARM 路由器开发一个守护进程。目标系统上没有cmake甚至没有python但一定有sh和gcc。此时autotools生成的configure脚本就是一个纯 shell 脚本它只依赖 POSIX shell 和gcc用户只需./configure make即可。而CMake生成的Makefile本身不依赖cmake但CMakeLists.txt的编写和调试离不开cmake工具链这对下游集成者是额外负担。场景二深度融入 GNU 生态与发行版打包Linux 发行版如 Debian、Fedora的打包系统dpkg-buildpackage,rpmbuild对autotools有原生支持。一个./configure --prefix/usr生成的包能被debuild或rpmbuild -ba直接识别自动处理install、strip、debuginfo等所有环节。而CMake项目需要额外编写debian/rules或%build宏增加了维护成本。场景三已有大型遗留项目迁移成本 收益某公司维护着一个 20 年历史的网络协议栈其configure.ac已有 500 行集成了对 Solaris、AIX、HP-UX 的专有探测逻辑。强行迁移到CMake不仅需要重写所有探测逻辑还要重构整个构建流程风险极高。此时autotools的稳定性和可预测性就是最大的生产力。5.2 CMake 的显著优势场景场景一跨语言混合项目C/CUDA/Python bindingsCMake对多语言支持是声明式的。一个CMakeLists.txt可以同时定义add_executable()、cuda_add_library()、pybind11_add_module()并自动处理 CUDA 编译器、Python 解释器路径等。autotools虽然也能通过AC_PROG_CXX、AC_PROG_F77等宏支持但对 CUDA、Rust FFI 等新兴语言生态支持滞后需要大量手工AC_SUBST和Makefile.amhack。场景二IDE 集成与可视化调试CLion、VS Code 的 CMake 插件能直接解析CMakeLists.txt提供智能补全、跳转定义、图形化构建目标选择。而autotools项目在这些 IDE 中通常只能作为“Generic Makefile Project”失去了大部分高级功能。场景三Windows 原生支持CMake的Visual Studio Generator能直接生成.sln和.vcxproj文件让 Windows 开发者无缝接入。autotools在 Windows 上依赖 MSYS2 或 WSL本质上仍是类 Unix 环境对纯 Windows 原生开发如调用 Win32 API支持薄弱。我的实践建议新项目如果目标用户主要是开发者GitHub 开源且不强求发行版打包优先CMake如果目标是系统级工具、嵌入式固件、或需要被 Debian/Fedora 官方仓库收录则autotools仍是首选。两者并非互斥一个成熟的项目可以同时提供CMakeLists.txt和configure.ac用CMake做日常开发用autotools做最终发布。6. 进阶技巧让 autoconf/automake 更强大、更可控掌握了基础流程下一步是让这套工具链为你所用而不是被它牵着鼻子走。以下是我多年实践中提炼出的几个高价值技巧能显著提升项目的健壮性和可维护性。6.1 自定义 configure 选项让用户拥有更多控制权./configure --help列出的选项是有限的。你可以轻松添加自己的开关比如--enable-debug来开启调试符号或--with-openssl来指定 OpenSSL 路径。在configure.ac中添加# 添加 --enable-debug 选项 AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug], [Compile with debug symbols and assertions])], [enable_debug$enableval], [enable_debugno] ) if test x$enable_debug xyes; then AM_CFLAGS$AM_CFLAGS -g -O0 -DDEBUG AC_DEFINE([DEBUG], [1], [Define to 1 if debugging is enabled]) else AM_CFLAGS$AM_CFLAGS -O2 fi # 添加 --with-opensslPATH 选项 AC_ARG_WITH([openssl], [AS_HELP_STRING([--with-opensslPATH], [Path to OpenSSL installation])], [openssl_path$withval], [openssl_pathauto] ) if test x$openssl_path ! xauto; then PKG_CHECK_MODULES([OPENSSL], [openssl 1.1.1], [], [AC_MSG_ERROR([OpenSSL not found at $openssl_path])]) # 设置 OPENSSL_CFLAGS 和 OPENSSL_LIBS else PKG_CHECK_MODULES([OPENSSL], [openssl 1.1.1]) fi然后在src/Makefile.am中使用hello-world_CPPFLAGS $(AM_CPPFLAGS) $(OPENSSL_CFLAGS) hello-world_LDADD $(OPENSSL_LIBS)这样用户就可以./configure --enable-debug获得-g -O0编译方便 GDB 调试./configure --with-openssl/opt/openssl链接自定义 OpenSSL。关键点AC_ARG_ENABLE和AC_ARG_WITH是autoconf提供的“选项解析宏”它们将命令行参数转化为 shell 变量enable_debug,openssl_path后续逻辑即可自由使用这些变量做条件判断。6.2 条件编译与平台特化一份代码多端运行autotools的强大之处在于它能让 C 代码“感知”自身所处的环境。比如Linux 用epollFreeBSD 用kqueueWindows 用IOCP。我们可以用autoconf探测再用automake生成对应的源文件列表。在configure.ac中# 探测 I/O 多路复用机制 AC_CHECK_FUNCS([epoll_create1 kqueue]) AC_CHECK_HEADERS([sys/epoll.h sys/event.h])在src/Makefile.am中利用automake的条件语法# 根据 configure 探测结果定义不同的源文件 if HAVE_EPOLL_CREATE1 IO_SOURCES io_epoll.c IO_CFLAGS -DUSE_EPOLL endif if HAVE_KQUEUE IO_SOURCES io_kqueue.c IO_CFLAGS -DUSE_KQUEUE endif # 主程序源文件 hello-world_SOURCES main.c utils.c $(IO_SOURCES) hello-world_CPPFLAGS $(AM_CPPFLAGS) $(IO_CFLAGS)这样make会根据configure的结果自动编译io_epoll.c或io_kqueue.c而main.c中只需#ifdef USE_EPOLL #include io_epoll.h #elif defined(USE_KQUEUE) #include io_kqueue.h #endif6.3 distcheck发布前的“终极审判”make distcheck是automake提供的、最严格的测试目标。它会模拟一个全新用户的视角执行完整发布流程make dist打包源码为hello-world-0.1.0.tar.gz解压到临时目录hello-world-0.1.0/_build进入_build目录运行../configure --prefix/tmp/test运行make运行make check如果有测试运行make install运行make installcheck验证安装后的程序是否正常清理所有临时文件。如果其中任何一步失败distcheck就会报错并保留_build目录供你检查。这是保证你的tarball能被任何人下载、构建、安装的黄金标准。实操心得我坚持在 CI如 GitHub Actions中加入make distcheck步骤。它曾帮我揪出过一个致命 bugMakefile.am中漏写了EXTRA_DIST config.h.in导致make dist打包的 tarball 里没有config.h.in新用户./configure时直接失败。distcheck在本地就能发现远胜于用户提 issue。7. 结语工具的价值在于它如何塑造你的工程思维写完这篇长文我回看自己第一次接触autotools时的困惑——那时觉得它繁琐、晦涩、反直觉。直到亲手用它解决了一个又一个“在客户服务器上编译失败”的线上问题才真正理解它的设计哲学不是为了让构建更快而是为了让构建更确定不是为了减少代码而是为了消除歧义不是为了取悦开发者而是为了服务最终用户。autoconf和automake不是过时的 relics它们是 Unix 哲学在构建领域的具象化小工具、管道化、文本化、可组合。configure.ac是用 M4 写的“环境需求说明书”Makefile.am是用声明式语法写的“构建蓝图”而configure和Makefile则是这份说明书和蓝图在特定机器上的“执行快照”。每一次./configure都是对目标环境的一次严谨审计每一次make都是对这份审计报告的忠实执行。所以当你下次看到一个开源项目的configure.ac别再把它当成一堆神秘的宏。试着读懂它它在探测什么它在假设什么它为哪些边界情况做了准备这种阅读代码的能力比写出一个能跑的Makefile更重要。因为真正的工程能力不在于你会用多少工具而在于你能否看懂工具背后的约束并在约束中优雅地解决问题。我在实际维护一个跨平台日志库时曾把AC_CHECK_DECLS([getrandom])和AC_CHECK_FUNCS([getrandom])同时加入configure.ac只为确保在不同内核版本下既能编译通过又能安全降级。那一刻

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑