[software development] GNU构建系统简介
Tofloor
poster avatar
enforcee
deepin
2023-07-22 09:35
Author

构建(build)是程序从源代码创建独立程序产品的过程。对于一些解释型的语言来说,通常源代码就是最终产品,所以不涉及到构建过程。因此这个词语通常是针对C、C++等编译型语言的。而对于一些特定的语言来说也有专门设计的构建工具。在一次构建过程中,可能需要调用多次编译器和连接器以及其他命令,因此对一个有相当多源文件的大项目来说,手动操作来控制这个过程相当费事,因此需要一套「自动构建软件」来帮助管理。虽然对于使用IDE的开发者来说,构建只是点一个按钮的事,但是了解其背后的原理对精益求精的你来说更有帮助。

现存的各种构建软件很多,而设计也不尽相同。一些构建系统使用一步到位的模式,一个命令即可完成构建;而一些构建系统需要分步操作:一个命令用于检查系统环境、修改编译行为和生成构建控制文件;另一个命令根据构建控制文件进行实际的编译、连接。我们通常使用的构建组合有:configure+make、cmake+make、qmake+make、meson+ninja等。而configure+make通常来说就是GNU构建系统的成果。

GNU构建系统分为两个部分:GNU make和GNU autotools。make是posix标准的构建工具,在各种系统中有不同的实现(我们在GNU系统中使用的make自然是GNU make),因此很多构建系统都使用make作为后端。而GNU autotools,他包括多个组件,其主要部分是GNU autoconf和GNU automake,这些工具的目标便是创造configure脚本。由于configure脚本使用posix标准的shell解释器执行,因此创建configure脚本后进行构建的操作系统就不需要安装GNU autotools,在任何符合posix标准的操作系统都能完成构建。

make

make是posix标准的构建工具,他的控制文件是Makefile。Makefile是配方(recipe)式的语法,每一条配方需要「目标」「原料」「制作方法」这些部分组成。因此make可以自动识别源文件是否改变,而之后的构建中就不需要重复制作没有改变的目标了。Makefile的目标同时也是make的命令,只需要输入「make 某个目标」即可单独制作对应的文件。一些make的目标可以被设置为「假目标(phony target)」,比如常见的install、clean等,这些目标并没有实际制作出文件,而是专门作为命令或者中间过程,这种目标需要特别标注出来,以免存在一个同名文件后,make以为他不需要更新,就不执行相应的命令。

configure

由于不同的操作系统平台存在差异,一些时候Makefile不能兼容,因此最原始的做法是为每个平台单独编写一个Makefile。1991年,David J. MacKenzie为了把他的程序适配到20个平台,因此他手写了一个小shell脚本来检测每个平台的特性来动态生成Makefile,这个小脚本被命名为configure,在后来逐渐被推广到了其他项目中。MacKenzie后来把他在各种项目的configure中经常复制粘贴的各种段落组合并包装起来,就是autoconf(见下文)。现在我们能见到的configure通常都是autoconf生成的,不知道还有没有开发者自己动手做。

configure是一个shell脚本,他检测操作系统环境是否满足编译需求,然后通过模板文件Makefile.in和config.h.in,生成Makefile和config.h。Makefile用于make,而config.h包括一些构建选项,用于C编译器的预处理(在C源代码中引入config.h,在configure完成后,make时,这些选项就可以被编译器使用)。另外这个脚本也能接受运行参数,通过生成不同的输出文件来修改一些编译行为。

autoconf

autoconf用于生成configure脚本。他是由各种shell代码片段组成的,因此选用了专门处理宏(macro)的编程语言m4。所谓「宏」,就把一个(通常是比较复杂)的原文本,用一个缩写(宏)来表示,这样遇到一个宏的时候,m4就会自动把他转化成原文本(这个过程叫扩展(expand))。

autoconf使用configure.ac文件作为输入,在这个文件中添加autoconf提供的宏,然后执行autoconf命令,configure.ac就会扩展成为真正的configure脚本。事实上autoconf使用了一个m4的增强版autom4te作为解释器,与原版m4比是提供了缓存的功能,可以防止多次执行的时候反复执行相同的段落。

autoheader

通过configure.ac自动生成config.h.in模板文件。autoheader包括在autoconf软件包内。

automake

通过编写Makefile.am来自动生成Makefile.in文件模板文件,这样会让最终生成的Makefile符合GNU标准。automake所做的和单独的make没有什么太大的区别,都是表达源文件和目标文件的转换关系,但是automake更加严格,需要表示目标文件和源文件的类型,并且由于automake需要和autoconf联动,因此不会像单独的make一样不受编程语言和平台的限制。

automake也需要读取configure.ac,获取项目的相关信息,并且automake的相关功能也需要在configure.ac里使用,为了给autoconf提供automake的相关功能,需要再给autoconf提供一个文件aclocal.m4,其中定义了automake的相关宏。aclocal.m4需要用aclocal命令生成(这个命令是包括在automake软件包内的)。如果在项目中使用automake,需要先执行aclocal,autoconf、automake可以按需要随时执行。(其他命令的执行顺序请查阅手册。)

autoreconf

如果上面的一串让人感到很混乱,那么救星来了。autoreconf用来自动执行所需的所有命令直到生成configure脚本,只需要提供给他configure.ac和Makefile.am。而且这两个文件一个是用于configure的,一个是用于make的,听起来是不是非常完美。其实autoreconf除了执行autoconf和automake之外,还支持很多命令。根据手册,autoreconf运行autoconf、autoheader、aclocal、automake、libtoolize、intltoolize、gtkdocize和autopoint(在需要的时候)。只需要软件对应的宏放到configure.ac里面,然后autoreconf就可以了。

一些软件使用一个名为bootstrap或者autogen.sh的脚本来组合命令的顺序,其实做的事情和autoreconf差不多。既然有了autoreconf,就没必要自己再做别的了。

尽管autoreconf能自动帮你执行命令,但是不代表写配置文件时就能偷工减料了,所以了解autoconf和automake还是很重要的。autoreconf包括在autoconf软件包内。

autoscan

autoscan自动检查源代码,然后自动生成configure.ac(输出文件会被命名为configure.scan),必须手动检查并修改configure.scan,然后才能重命名成configure.ac提供给autoconf。工具的智能程度毕竟是有限的。autoscan包括在autoconf软件包内。

autoupdate

世界之大,无奇不有,不仅软件包能升级,configure.ac也能升级。使用autoupdate能自动检查configure.ac里面过时的宏并调整成新版本。autoupdate包括在autoconf软件包内。

ifnames

辅助工具,列出源代码中所有编译器预处理使用过的判断命令#if、#elif、#ifdef、#ifndef,为你检查autoscan生成的configure.ac有没有遗留的地方提供参考。ifnames包括在autoconf软件包内。


以下工具和构建本身关系不大,但是也能作为GNU构建系统的一个环节。他们都提供了一个命令和一些m4宏用于和autoconf对接。

libtool

由于各种操作系统的库格式不同(甚至有的系统不支持动态库),其命名标准和编译器参数也有所差异,因此libtool发明了一个新的库格式libtool archive(后缀.la),并且用脚本封装了编译和连接的命令。

gettext

翻译界面文本的工具,在源代码中用gettext函数提换掉原来的字符串(通常用编译器预处理定义成一个单独的下划线_("原字符串")),这样可以导出一个po文件,给译者翻译后,再编译成mo文件,这样程序会从mo文件中读取界面文本。

intltool

和gettext其实是同一个系统,但是把翻译能力进一步扩展非源代码储存的消息上(xml文件、desktop文件、界面定义文件等)。把这些字符串混合到po文件里,翻译后再融合回原来的地方。

gtk-doc

从源代码的注释中自动生成API文档。


附注:autoconf宏前缀的意义

在autoconf中使用的宏的来源有很多,他们用不同的前缀来区别。这相当于其他语言中的命名空间(namespace,autoconf文档中就是这么说的)。

m4_:原本的m4宏,和m4suger(一些为了方便使用而增加的)宏。m4原来的宏都被改成了带m4_前缀的名字,除了__file____line__dnl和autom4te增加的一个宏__oline__

AS_:m4sh宏。为了能在各种差异的shell上运行命令,把shell命令也包装成了宏。

AC_:autoconf宏。

AH_:autoheader宏。

AT_:autotest宏,编写测试套件(testsuite)使用。

AU_:过时的宏,不要再用了。

以上属于autoconf自带的宏。

AM_:automake宏。

AX_:有一个autoconf的扩展包,名为autoconf-archive,命名空间是这个。


各种资源:

autoconf教程:作者只写了三篇就弃坑了,但是还是值得看看,从最简单的开始。
http://www.idryman.org/blog/2016/03/10/autoconf-tutorial-1/

autotools教程:一个幻灯片的pdf,还有各种电子书的链接。
https://www.lrde.epita.fr/~adl/autotools.html

GNU软件页面:各种GNU软件的主页都能找到,每个里面都有详细文档。应该是对软件有一定了解了之后再去看文档,否则会迷糊的。
https://www.gnu.org/software/

--help:什么程序都可以帮帮我,快去shell里面试试吧。
用法:命令 --help(如果是shell内置命令的话,就要反过来help 命令

man:人类还是要看手册(manual)啊。
用法:man 命令(不过如果没装相应的手册页面的话也是不能显示的)

texinfo:GNU系统的用户手册。
用法:info [章节](可能只有骨灰级的GNU用户才会看这种东西)


作者的话:有些文章上来就给读者看一张流程图,然后就是这个生成那个,看到最后也没太明白到底那些部分都是干什么用的。想要运用自如的话,就一定要先清楚他的作用和原理。单纯模仿别人的操作是不能学会的。

另:网上的流程图,漏洞百出哇,大家可以自己练习画一画。

Reply Favorite View the author
All Replies
微光寒慕
deepin
2023-07-22 12:07
#1

厉害

Reply View the author
foxbcd
deepin
2023-07-22 12:35
#2

applaud

Reply View the author
阿尼樱奈奈
Moderator
2023-07-22 15:09
#3

like

Reply View the author
Tonny
deepin
2023-07-22 16:04
#4
It has been deleted!
donaldsebleung
deepin
2023-07-22 16:53
#5

学习了,感谢分享kissing_heart

Reply View the author
W2J
deepin
2023-07-22 18:02
#6

好指南,有用!

收了收了,感谢大佬深播松土。

Reply View the author
fuuko
deepin
2023-07-22 20:10
#7

全是最基础的组件了,现在一般是直接怼cmake或者xmake,然后生成配置好的makefile

Reply View the author
秋胜春朝
deepin
2023-07-22 20:18
#8

like

Reply View the author