言成言成啊 | Kit Chen's Blog

大白编译——autotools与cmake

发布于2025-07-20 01:58:56,更新于2025-07-20 23:49:39,标签:devops  文章会持续修订,转载请注明来源地址:https://meethigher.top/blog

之前记录了通过autotools编译rpm包与deb包的步骤。参考小白编译——rpm包与deb包 - 言成言成啊

一、跨平台编译

1.1 背景

本节参考

1.1.1 跨平台困扰

在C中,头文件(.h)只负责“声明”,具体的实现放到“库文件”里。不同系统“库文件”示例如下

  • 静态库
    • Linux: libc.a
    • Windows: format.lib
  • 动态库
    • Linux: libc.so
    • Windows: msvcrt.dll

C语言跨平台时不兼容的主要来源

  • 函数不存在
    • strtod(),为C标准库函数,但是老版libc根本没有对应实现
  • 函数有不同的名字
    • strchr() vs index()strchr()为C标准库函数,但是在老版libc只有index(),两者作用相同。
  • 原型差异
    • 老系统只有int setpgrp(void) ,新系统只有 int setpgrp(int,int)
  • 行为差异
    • malloc(0) 返回值不确定。
  • 所在库不同
    • pow()的实现可能在 libm.solibc.so
  • 头文件差异
    • 历史原因,有些系统会针对头文件进行补充,导致其他平台没有。

1.1.2 解决办法

如何实现一个可移植的软件包?让同一份源代码能在不同系统上无修改地编译、运行。

三种应对办法

  • 大量 #if/#else → 代码凌乱,不推荐。
  • 替换宏(#define fseeko ...)→ 推荐。
  • 替换函数(提供缺失函数的兼容实现)→ 推荐。

替换宏示例,来自 coreutils-5.2.1system.h

1
2
3
4
#if !HAVE_FSEEKO && !defined fseeko
# define fseeko(s,o,w) \
((o) == (long)(o) ? fseek(s,o,w) : (errno = EOVERFLOW, -1))
#endif

开发者不关心系统是否提供,放心使用fseeko

替换函数示例,来自GNU C library,即libc.so

1
2
3
4
5
char *strdup(const char *s) {
size_t len = strlen(s) + 1;
void *new = malloc(len);
return new ? memcpy(new, s, len) : NULL;
}

此处多插一嘴。Golang标准库如何实现零运行时依赖的可执行程序的?

答:每个可执行文件都包含了完整的运行时库和标准库

1.1.3 autotools由来

1991 年起,人们开始写 shell 脚本自动探测系统特征。这就是 autotools中的configure 脚本的由来。它主要负责

  1. 检测系统是否具备所需的库、函数、工具
  2. 根据开发者写的检测指令,生成config.h。比如开发者要检测AC_CHECK_FUNCS([strdup]),那么config.h检测到存在,会写入#define HAVE_STRDUP 1
  3. 生成适合本系统的 Makefile

configureAutotools的一部分,Autotools还涉及到两个工具AutoconfAutomake

  • Autoconf
    • 用于从开发者编写的configure.ac 文件生成 configure 脚本。
  • Automake
    • 用于从开发者编写的Makefile.am 文件生成 Makefile.in 文件。Makefile.in 文件是 configure 脚本的输入,用于生成最终的 Makefile

不过在实际使用中,一行autoreconf -fi即包含了AutoconfAutomake的两个操作。Autotools整体流程如下图

对于用户来说,只需记住三板斧:./configure && make && make install

1.2 autotools与cmake对比

autotools(经典老兵)与cmake(新一代工具链)的优劣对比

  • autotools
    • 优点:轻量,在Linux上零依赖运行,只要/bin/sh+make
    • 缺点:跨平台编译体验不好。比如在Windows上编译。
  • cmake:使用c++重新实现了整套逻辑,不依赖shell
    • 优点:跨平台体验更佳。用户在多个平台,使用一套命令即可完成编译。
    • 缺点:需要安装CMake

二、编译实战

下面以两个示例,记录使用autotoolscmake进行编译的过程。

我有一个源码文件main.c,需要将其编译成Linux可执行程序。

1
2
3
4
5
6
7
// src/main.c
#include <stdio.h>
int main(void)
{
printf("Hello, world!\n");
return 0;
}

autotools与cmake的源码(meethigher/autotools-vs-cmake: 以一个入门级程序,简单比较autotools与cmake两者的编译区别)结构如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
├─hello-autotools
│ │ autogen.sh
│ │ configure.ac
│ │ Makefile.am
│ │ README.md
│ │
│ └─src
│ main.c
│ Makefile.am

└─hello-cmake
│ CMakeLists.txt
│ README.md

└─src
main.c

分别使用两种工具在Debian12上面进行编译。

参考

2.1 autotools

安装预置的编译环境

1
apt -y install autoconf make gcc

进入到项目中进行编译

1
2
3
4
5
6
7
8
# 生成 configure
chmod +x autogen.sh && ./autogen.sh
# prefix指定编译后的安装目录。默认是/usr/local
./configure --prefix=$PWD/install
make && make install

# 验证
./install/bin/hello

2.2 cmake

安装预置的编译环境

1
apt -y install cmake gcc

进入到项目中进行编译

1
2
3
4
5
6
7
8
9
10
# 将编译的内容全部放置到gaga目录。
# DCMAKE_INSTALL_PREFIX与autotools中的prefix一致,默认为/usr/local
cmake -B gaga -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$PWD/install
# 编译gaga目录
cmake --build gaga
# 将gaga目录的内容,移植到CMAKE_INSTALL_PREFIX
cmake --install gaga

# 验证
./install/bin/hello
发布:2025-07-20 01:58:56
修改:2025-07-20 23:49:39
链接:https://meethigher.top/blog/2025/autotools-vs-cmake/
标签:devops 
付款码 打赏 分享
Shift+Ctrl+1 可控制工具栏