Linux下GNU Autotools工具基础教程

对于我们平时写的小的测试Demo程序,可能自己手动编写一个Makefile文件就可以编译整个项目了,但是对于一些大型的工程,包含多个源码文件夹、头文件文件夹、库文件文件夹,如果我们每个源码文件的Makefile文件都自己去编写会非常繁琐,所以这时候需要一些自动化工具来帮助我们简化项目的构建,这里比较主流的有两种工具一个是GNU下的Autotools工具,一个是CMake工具。

Autotools工具是一些版本比较老的工具了,遗留了很多问题,包括他的语法复杂(m4宏语言),涉及的工具种类太多,生成的configure脚本非常庞大等问题,在2000年后出现的新一代构建系统包括CMake、Meson、Ninja等能够有效解决Autotools的历史疑难杂症,并且语法更加现代化、生成速度更快。那我们为什么还要学习了解Autotools呢?因为历史原因,早年很多的开源软件都是使用的Autotools来构建的,并且Autotools目前在GNU体系中还是大量使用,并且在嵌入式Linux中非常常见,而且在一些老牌的C项目中也非常常见,所以还是非常有必要了解Autotools。

这里给出官方的Autotools的文档连接 https://www.gnu.org/software/autoconf/

一、Autotools工具详细介绍

1.1 Autotools工具组成

GNU Autotools并不是一个工具,而是由一系列的工具合集组成,在现如今的Linux发行版中,大概率是自带这些工具的,如果没有可以自行下载

  • autoscan:这个工具主要是用来扫描查找源代码目录下的源文件用来生成configure.scan文件。configure.scan文件是自动生成的模板,里面包含了一些系统配置的基本选项都是一些宏定义,这些宏通过autoconf工具处理后会变成检查系统特性、环境变量的shell脚本,我们可以根据这个模板修改,最后将configure.scan重新命名为configure.ac文件
  • aclocal:这个工具是一个perl脚本程序,他主要用来根据上一步的configure.ac文件的内容,自动生成aclocal.m4文件
  • autoconf:这个工具会使用configure.ac文件来生成名称为configure的shell脚本文件用来检查系统特性与环境变量,运行这个脚本文件之后,就会生成Makefile文件,之后我们就可以执行makemake install命令了
  • autoheader:这个工具主要是用来自动生成config.h.in文件的,当我们执行了./configure之后,会生成一个config.h文件,在调用autoheader工具之后,就会生成config.h.in文件
  • automake:使用automake来产生Makefile.in文件,需要注意的是Makefile.in是由Makefile.am生成的这个需要我们手动来编写

这里可以注意到,最后工具用到的文件都是以.in结尾的文件,这些文件相当于我们最后需要的目标文件的输入文件

1.2 configure脚本制作流程

这块内容可以参考 https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.72/autoconf.html 文档的第三章内容,详细阐述了configure脚本的制作流程,下面简单介绍一下,以下图流程图中,带*的是执行的命令,带[]的表示可选项

首先根据文档中的这个流程图,可以看见用我们的源文件,通过autoscan命令生成configure.scan文件,然后我们再修改这个模板,生成我们的configure.ac文件,在通过autoconf命令生成configure脚本的时候,aclocal.m4acsite.m4这两个文件为可选项,如果我们后续需要使用automake工具,那么还需要在执行autoconf前使用aclocal工具生成aclocal.m4文件

在执行autoconf命令的同时,我们可以选择使用autoheader来生成config.h.in文件。这个文件的作用是为 configure 提供一个模板,告诉它哪些宏需要根据系统环境进行检测,从而生成最终的config.h文件,供代码在条件编译中使用,后需会详细讲解这部分内容。

如果我们还需要使用automake工具来生成Makefile.in文件,那么需要在autoscan生成了configure.ac文件之后追加以下的流程

第一步,我们需要使用aclocal命令来生成aclocal.m4文件,有了这个文件之后,我们在生成configure的时候会使用到这个文件,然后第二步我们需要自己编写一个Makefile.am文件,然后执行automake命令来生成Makefile.in

做完上述两个流程之后,我们就可以得到两个关键文件了一个是configure脚本文件,一个是Makefile.in模板文件,在通过以下流程,生成最后的Makefile文件

直接执行configure脚本文件,脚本会去找config.h.inMakefile.in文件进行文件生成,最后生成config.hMakefile文件,之后我们就可以执行make命令来编译工程了

可能这里三个图的关系比较混乱,后面会通过一个工程上的实例,来具体演示Autotools的使用以及流程

1.3 autoheader工具与config.h.in文件

前面我们提到了使用autoconf生成configure的同时,可以使用autoheader来生成config.h.in文件,这个文件到底是用来干什么的呢?这一小节详细讲解一下。

例如,现在有一个场景:我们的应用代码需要跨平台,在 Linux 环境下,会使用到 <unistd.h> 头文件。不同系统可能是否存在这个头文件不同,因此我们希望通过自动化的方式进行检测和适配。我们需要先在configure.ac文件中添加配置项

复制代码
AC_INIT([example], [1.0])
AC_CONFIG_HEADERS([config.h])
AC_CHECK_HEADERS([unistd.h])
AC_OUTPUT
  • AC_CONFIG_HEADERS([config.h]):告诉 Autotools 最终需要生成 config.h 文件
  • AC_CHECK_HEADERS([unistd.h]):告知 Autotools 需要检测系统是否有 <unistd.h>,并生成相应宏 HAVE_UNISTD_H

当我们在configure.ac中添加了这些选项之后,可以运行autoheader命令来生成config.h.in,这时的模板文件中会有以下这样的记录

复制代码
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
  • 注意:#undef HAVE_UNISTD_H 只是占位宏,值还没有确定
  • 这个宏的名字是由 AC_CHECK_HEADERS 自动生成的

有了config.h.in文件之后,如果我们运行了./configure后,工具会检测系统中是否有<unistd.h>根据最终结果来生成config.h头文件,如果包含有那么在config.h文件中,就会多出

c 复制代码
#define HAVE_UNISTD_H 1

//如果没有该头文件的话
/* #undef HAVE_UNISTD_H */

后续我们就可以通过包含config.h文件来进行条件编译了,这样代码可以在不同平台上自动适配,而不需要手动修改

c 复制代码
#include "config.h"

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

int main() {
#ifdef HAVE_UNISTD_H
    write(1, "unistd.h exists\n", 16);
#else
    printf("unistd.h not found\n");
#endif
    return 0;
}

总结:

  • config.h.in = 模板文件,列出待检测的宏
  • ./configure = 系统检测器,把模板宏填上实际值
  • config.h = 最终宏定义文件,代码条件编译使用
  • 条件编译语句 (#ifdef) 永远需要开发者在代码里自己写

二、Autotools实例分析

这一章节主要是对autotools的具体使用举例。

第一步 :创建demo工程项目,新建了一个源码文件夹,创建一个c文件,编写了一个简单的代码。

第二步 :生成configure.ac文件。在源码路径下执行了autoscan命令之后,可以看见configure.scan文件已经生成出来了

可以打开这个文件查看,就是一些功能宏定义

宏解释:

  • AC_PREREQ()宏声明本文件要求的autoconf版本,本例使用的版本为2.71
  • AC_INIT()中分别的是: 软件包的名字,版本,作者的联系方式(一般是Email)
  • AC_CONFIG_SRCDIR宏用来侦测所指定的源码文件是否存在,来确定源码目录的有效性。此处为当前目录下的test.c,如果有多个源文件的话选择一个主要的文件,通常是 main.c 或其他代表源代码位置的文件。
  • AC_CONFIG_HEADER宏用于生成config.h文件,以便autoheader使用
  • AC_PROG_CC用来指定编译器,如果不指定,选用默认gcc。 比如: AC_PROG_CC(gcc)
  • AC_OUTPUT用来设定 configure 所要产生的文件,如果是makefile,configure会把它检查出来的结果带入makefile.in文件产生合适的makefile。使用Automake时,还需要一些其他的参数,这些额外的宏用aclocal工具产生

这些宏可以直接到 https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.72/autoconf.html#Making-configure-Scripts 官方文档中去查询

最后修改这个模板文件,填入自己的软件信息,并将configure.scan重命名为configure.ac文件

这里有几点需要注意,第一就是注意填写好自己软件的信息,第二就是如果我们后续要使用automake工具的话,需要添加一行AM_INIT_AUTOMAKE,并且需要指定构建行为常用的选项为[foreign]如果不指定的话,就是[gnu]严格模式,会检查AUTHORS、NEWS、README、ChangeLog、COPYING、INSTALL等文件,如果缺失的话,后续使用automake就会报错,这是我踩的一个坑,对于现代的项目,大多数使用git代码管理,对于这些文件有一些是不必要的,所以这里可以关闭GNU strict模式,如果你需要使用GNU的严格模式的话,创建这些所需文件就可以解决报错。第三点就是记得添加输出文件列表的宏AC_CONFIG_FILES([文件名])这三点编辑好之后,一个基础的configure.ac就编辑好了

第三步 :生成aclocal.m4文件,因为我们后续要使用到automake工具,需要依赖aclocal.m4文件,所以这一步通过aclocal来生成aclocal.m4文件

可以看见执行了aclocal之后,aclocal.m4文件成功输出了

第四步 :生成config.h.in文件,因为我们在configure中使用了宏检查,需要输出config.h,所以我们需要先生成config.h.in

执行autoheader命令之后,config.h.in也成功生成了

第五步 :生成configure文件,使用autoconf命令得到configure脚本文件

如果这时候我们直接运行这个脚本,可以发现,缺少install-sh脚本,这个脚本就是通过automake来生成的

第六步 :编写Makefile.am文件,执行automake命令。这里只写了一个比较简单的Makefile.am进行测试

Makefile.am文件编写规范非常重要,这里指出我踩到的另外一个坑,Makefile.am文件中的这两个宏定义,必须得规范否则也会爆出错误或者警告。

bin_PROGRAMS的含义是生成一个可执行文件 test,并在 make install 时安装到$(bindir),一般情况下$(bindir) = /usr/local/bin
test_SOURCES的结构为<目标名>_SOURCES目标名必须和bin_PROGRAMS的程序名完全一致,否则 Automake 会报错

除了bin_PROGRAMS还有其他Automake内部已经定义好的安装目录变量

变量 安装目录
bin_PROGRAMS $(bindir) → /usr/local/bin
sbin_PROGRAMS $(sbindir)
libexec_PROGRAMS $(libexecdir)
noinst_PROGRAMS 不安装,只编译
check_PROGRAMS 测试程序
具体其他宏的功能,大家可以查看官方的文档,这篇文章主要是autotools工具的使用,这里就不深入剖析底层了

还有一个需要注意的点是,如果我们这时候直接使用automake命令,会提示报错,工具也对我们继续了提示需要加上--add-missing选项,添加选项--add-missing 可以让automake工具自动添加必要的脚本文件,这里也可以看见如果AM_INIT_AUTOMAKE没有关闭GNU的严格模式,会报出缺失必要文件的错误。这里是因为这张图是没有修改的时候截取的,修改之后我没有重新automake

加上该选项,并修改了AM_INIT_AUTOMAKE之后,再次执行automake命令执行成功,并成功生成Makefile.in文件和install-sh文件

第七步 :执行configure脚本,更具Makfile.inconfig.h.in生成最后的文件。

可以看见成功生成了config.status以及Makefile文件,打开该Makefile文件,可以看见生成了700多行

我们非常简单的一个代码,autotools工具给我们生成了700多行的Makefile文件,其中大量的代码都是用来检测环境和编译器相关的内容。有了Makefile之后,我们就可以直接使用make命令来编译了

并且生成了对应的可执行文件,同时我们可以执行make install进行系统安装,默认安装到/user/local/bin下,需要注意的是使用make install时需要权限。

我们可以使用make dist用来生成一个源码压缩包,拿到这个包之后,我们就可以将工程发布给别人或者发布成release版本了

至此整个Autotools最基本的流程与用法就结束了,当然在实际开发当中,我们不可能只有一个源文件,之后的博客会对实际工程项目情况举例与分析。

相关推荐
ttkwzyttk2 天前
嵌入式Linux手动交叉编译开源软件需要注意的问题
c·linux应用
REDcker2 天前
FFmpeg完整文档
linux·服务器·c++·ffmpeg·音视频·c·后端开发
REDcker3 天前
curl开发者快速入门
linux·服务器·c++·c·curl·后端开发
REDcker3 天前
curl完整文档
c++·c·curl·服务端·后端开发
小牛历险记4 天前
BES平台系统基础知识
c·学习方法·系统
雪域迷影4 天前
sdl3-sample-简明教程,指导如何在包括移动和 Web 在内的各种平台上构建和使用 SDL3
github·c·开源软件·sdl3
春栀怡铃声13 天前
认识二叉树~
c语言·数据结构·经验分享·c·编译
季明洵17 天前
C语言实现顺序表
数据结构·算法·c·顺序表
日更嵌入式的打工仔22 天前
C 语言 restrict 关键字
c