大家好,又见面了,我是你们的朋友全栈君。
前言
来源:AUTOTOOLS – John Calcote or AUTOTOOLS – 亚马逊
这里简单整理下这本书的第三章:configure your project with autoconf
书中介绍,循序渐进。
第一步:介绍了autoconf和M4宏,并整体运行了一遍,介绍了相关脚本的调用顺序和文件作用。
第二步:通过autoconf将Makefile中定义为@VARIABLE@的变量替换,并通过VPATH进行远程构建。
第三步:借助autoscan生成configure.ac,并说明文件中的宏含义。
代码的初始结构
代码仓库,下面的代码在这基础上,不断修改补充。
代码语言:javascript复制➜ jupiter-makefile-ch2 tree
.
├── Makefile
└── src
├── main.c
└── Makefile
了解autoconf的第一步
本节的代码仓库
这里,我们在初始代码的基础上,添加configure.ac文件。
代码语言:javascript复制➜ jupiter-autoconf-ch3-01 git:(master) ✗ tree
.
├── configure.ac
├── Makefile
└── src
├── main.c
└── Makefile
代码语言:javascript复制# configure.ac文件
AC_INIT([Jupiter],[1.0])
AC_OUTPUT
autoconf
对于autoconf而言,输入是通过宏调用的shell脚本(上面那些宏展开来是shell脚本)。autoconf中使用的宏语言为M4。[configure.ac是autoconf的输入]
宏在与autoconf软件包一起分发的文件中定义。 例如,您可以在Autoconf安装目录(通常为/usr/(local/)share /autoconf)中的autoconf/general.m4文件中找到AC_INIT的定义。AC_OUTPUT在autoconf/status.m4中定义。
Autoconf – wiki autoconf是一个古老和成熟的产品,如果使用得当,可以使用一个非常简单的接口进行复杂的交叉编译。但是有一些批评指出autoconf使用了过时的技术,因而遗留了很多限制。autoconf无法为Xcode与Visual Studio制作项目文件,其脚本通常大且复杂,因此增加了Debug的难度。Autoconf所使用的M4对于一些开发者来说是陌生的,因此他们需要专门学习[6]。一些开发者并不遵循配置脚本的一些习惯约定[7]。因此一些自由软件开发者开始使用其他软件代替autoconf,KDE于KDE 4起开始使用CMake[8],Scribus同样开始使用CMake[8]。
调用M4宏,需要满足一些规则
- 以方括号确保参数扩展
- 以逗号分隔的参数列表
- 左括号都必须紧跟其定义中的宏名称,并且中间没有空格
- 如果未传递任何参数,则也可以省略括号
- 多余参数将被忽略
通常,阅读那些宏定义的代码,令人极度不愉快。M4的广泛使用对那些试图理解Autoconf的人造成了相当大的挫败感。幸运的是,能够有效使用Autoconf通常不需要深入了解宏的内部工作原理。
执行
运行autoconf很简单:只需在configure.ac文件所在的目录中执行它即可。 虽然我可以在本章的每个示例中做到这一点,但我将使用autoreconf程序代替autoconf程序,因为运行autoreconf与运行autoconf具有完全相同的效果,只是当您使用autoreconf也会做正确的事情 开始向您的构建系统添加Automake和Libtool功能。 也就是说,它将根据configure.ac文件的内容以正确的顺序执行所有Autotools。
代码语言:javascript复制✗ autoreconf
✗ autoreconf
✗ ls -1p
autom4te.cache/
configure
configure.ac
Makefile
src/
我们注意到,autoconf创建一个名为autom4te.cache的目录。 这是autom4te缓存目录。 在连续执行Autotools工具链中的实用程序期间,此缓存可加快对configure.ac的访问。
configure和configure.ac实质上是相同的文件,只是将configure.ac中所有宏都已完全展开。 欢迎您看一下configure,不要感到惊讶^_^。 通过M4宏扩展,configure.ac文件已转换为包含数千行复杂的Bourne Shell脚本的文本文件。
接下来,我们执行configure文件。
代码语言:javascript复制✗ ./configure
configure: creating ./config.status
✗ tree -L 1
.
├── autom4te.cache
├── config.log
├── config.status
├── configure
├── configure.ac
├── Makefile
└── src
configre脚本有三个功能:
- 执行请求的检查。 [检查结果以某种方式写入config.status中]
- 生成然后调用config.status。[config.status从模板(Makefile.in,config.h.in等)生成文件]
- 还会创建一个名为config.log的日志文件:
[上面功能可以看到,configure生成了config.status,然后调用config.status,省去config.status可以好?]
为什么不configure仅执行它写入config.status的代码,而不是麻烦立即生成第二个脚本,而只是立即调用它呢? 有几个很好的理由。 首先,执行检查和生成文件的操作在概念上是不同的,并且在概念上不同的操作与单独的make目标相关联时,make的效果最佳。 第二个原因是,您可以分别执行config.status以从其相应的模板文件重新生成输出文件,从而节省了执行那些冗长的检查所需的时间。 最后,编写config.status来记住最初在configure命令行上使用的参数。 因此,当make检测到需要更新构建系统时,它可以使用最初指定的命令行选项调用config.status重新执行配置。
了解autoconf的第二步
本节的仓库代码
现在我们给configure.ac中,添加一些实质内容。
代码语言:javascript复制# configure.ac
AC_INIT([Jupiter],[1.0])
AC_CONFIG_FILES([Makefile src/Makefile])
AC_OUTPUT
没错,相较于上一节的代码,多了一行。
此行代码假定存在用于Makefile和src/Makefile的模板,分别称为Makefile.in和src/Makefile.in
这些模板文件看起来与它们的Makefile副本完全相同,但有一个例外:使用@VARIABLE@语法。
autoconf替换文本中所有都使用@VARIABLE@语法标记的变量。
像下面这样修改Makefile为Makefile.in,详细见代码仓库。
代码语言:javascript复制# @configure_input@
# package-specific substitution variables
package = @PACKAGE_NAME@
version = @PACKAGE_VERSION@
tarname = @PACKAGE_TARNAME@
distdir = $(tarname)-$(version)
# prefix-specific substitution variables
prefix ?= @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
# VPATH-specific substitution variables
srcdir = @srcdir@
VPATH = @srcdir@
现在可以执行autoreconf,然后执行configure和make,以构建项目。
这个简单的三行configure.ac文件会生成功能完整的configure script。 (autoreconf)、
生成的configure script将运行各种系统检查,并生成config.status脚本,该脚本可以替换此构建系统中[*.in]一组指定模板。
其中,VPATH构建是一种使用Makefile结构(VPATH)在源目录以外的目录中配置和构建项目的方法,详细介绍见:Makefile目标文件搜索(VPATH和vpath)
VPATH构建,思考下,很容易明白。在其他目录执行configure。根据模板生成的makefile文件在当前目录。 make 刚生成的makefile文件,由于其中已经定义了VPATH变量。所以很自然的根据VPATH,找到依赖的源码位置,编译出来的内容在当前目录。从而实现,在非源码目录编译project。
了解autoconf的第三步
本节的仓库代码
此时的代码结构如下
代码语言:javascript复制.
├── autogen.sh
├── autoscan.log
├── configure.ac
├── configure.ac.bak
├── Makefile.in
└── src
├── main.c
└── Makefile.in
我们通过autoscan自动生成configure.scan。configure.scan备份一份为configure.ac.bak。然后,修改configure.scan并为configure.ac。避免完全人工实现configure.ac。
代码语言:javascript复制# configure.ac内容
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([Jupiter], [1.0], [jupiter-bugs@example.org])
AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
# Checks for libraries.
# Checks for header files.
AC_CHECK_HEADERS([stdlib.h])
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES([Makefile
src/Makefile])
AC_OUTPUT
autogen.sh
代码语言:javascript复制# autogen.sh
#!/bin/sh
autoreconf --install
automake --add-missing --copy >/dev/null 2>&1
configure检查到有install的时候,需要install-sh的shell脚本,原因如下。
Autoconf就是关于可移植性的,不幸的是,Unix安装实用程序并不像它可能的那样可移植。 从一个平台到另一个平台,安装功能的关键部分都足以引起问题,因此Autotools提供了一个名为install-sh的shell脚本(不建议使用的名称:install.sh)。 该脚本充当系统自身安装实用程序的包装,掩盖了不同版本的安装之间的重要差异。
但是我们目前没有在autoconf中使用automake。而install是automake的工作,需要它提供install-sh。 Autoconf不会生成任何makefile构造-只会将变量代入您的Makefile.in模板中。 因此,Autoconf实际上没有理由抱怨缺少installsh脚本。
所以需要上面的autogen.sh。第五章使用automake的时候,直接autoreconf –install就好。
configure.ac
总结
总体来说:
- 将Makefile中,需要替换的部分,通过@VARIABLE@表示
- 使用autoscan扫描自动生成configure.scan
- 根据需要修改configure.scan内容,并重命名为configure.ac
- 之后运行autoreconfig、configure、make、[make install]
这里面比较重要的是理解configure.ac里面宏的含义。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/135920.html原文链接:https://javaforall.cn