接触过Linux开发的人都知道从源代码安装需要执行类似以下的步骤:
1 2 3
|
./configure make make install
|
目前为止我执行上述命令已经很多次了,但是并不知道它背后的逻辑。在跟进一个还在开发中的项目的时候,上要述步骤并不能完美执行,需要针对作一些修改,是时候挖掘这些咒语背后的操作了。
configure
脚本负责在特定的系统上执行build的准备工作。这确认后续的build和install的依赖关系已经满足,找出使用这些依赖需要知道的所有信息。
Linux程序通常是用C编写的,所以我们需要C编译器,configure脚本通常会检查系统有合适的C编译器,它在哪里以及如何调用。
Build
一旦configure完成,我们就可以执行
make
命令来build软件。它执行一系列在Makefile中定义的操作来编译写好的源代码。
通常下载的源文件tarball中不包含Makefile,取而代之的是一个模板文件
Makefile.in
,configure脚本产生一个针对你的系统定制的Makefile文件。
make install
现在软件已经build成可执行文件了,它们可以被复制到最终的目录。
make install
命令会将build成型的
程序
文件和
库
文件以及
文档
复制到合适的目录。
通常二进制文件会被COPY到
PATH
的某个目录,manual文件会被复制到
MANPATH
,其它依赖文件会被保存到合适的地方。
make install
的操作也会定义在
Makefile
中,所以软件的安装目录可以通过configure的参数来修改,或者由configure脚本自动从你的系统中发现。
取决于软件安装的目录,你可能需要高级的权限来完成操作,这种情况下一般加上
sudo
就可以了。
脚本从何而来
所有的操作都定义在configure脚本中,它检查你的系统,从模板文件
Makefile.in
生成
Makefile
,那么这个脚本从何而来呢?
如果你打开过任何一个configure文件,或者与之关联的Makefile.in,你会发现它包含成百上千的shell命令,有时甚至比程序源代码还长。
即使从一个现成的configure脚本开始修改,手动编写的难度也是很大的,但是不用担心,它们不用手动编写。
使用这种方式安装的程序通常使用叫做
autotools
的工具包来管理,工具包包括
autoconf
,
automake
和很多其它工具,它们一起使得软件维护大为简化。最终用户见不到这些工具,但是它们消除了在不同系统上频繁配置安装过程的麻烦。
Hello World
下面以一个简单的hello world程序为例来演示如何使用
autotools
.
程序源代码如下:
1 2 3 4 5 6 7 8
|
#include <stdio.h> int main(int argc, char* argv[]) { printf("Hello world\n"); return 0; }
|
我们不手工编写configure脚本,而是使用m4sh来编写configure.ac文件来定义configure中的操作。m4sh是m4 macro和shell的结合。
第一个调用的m4 marco是
AC_INIT
,它会初始化
autoconf
并设置一些关于 我们要打包的程序的基本信息。程序名为hellworld,版本为0.1, 维护者为[email protected]:
我们将使用
automake
工具,所以调用AM_INIT_AUTOMAKE macro:
接下来定义依赖关系,程序依赖C编译器,所以
如果还有其它的依赖,我们可以使用其它marco来发现,例如
AC_PATH_PROG
可以在用户PATH下查找程序。
依赖关系完成以后,接下就要使用这些信息生成Makefile了。
使用
AC_CONFIG_FILES
告诉autoconf脚本需要找到Makefile.in,替换变量(如@PACKAGE_VERSION@)为某值(如0.1),将结果写入Makefile。
1
|
AC_CONFIG_FILES([Makefile])
|
当一切定义完之后,使用
AC_OUTPUT
来输出脚本。
以下是全部的内容:
1 2 3 4 5
|
AM_INIT_AUTOMAKE AC_PROG_CC AC_CONFIG_FILES([Makefile]) AC_OUTPUT
|
至此已经接近完成了,马上就可以发现软件包了,但是我们还没有创建Makefile.in文件。
创建Makefile
类似Makefile,Makefile.in也会很长,所以我们写一个
Makefile.am
文件给automake来创建模板文件。
首先设置一些选项来告诉automake关于项目的结构信息。由于我们没有遵照GNU规范,所以它是一个
foreign
类型的工程
1
|
AUTOMAKE_OPTIONS = foreign
|
工程名为helloworld
1
|
bin_PROGRAMS = helloworld
|
这一行中包含了许多信息,多亏了automake的
uniform naming scheme
PROGRAMS的前缀称为
primary
,告诉automake工程有哪些properties。例如PROGRAMS需要build,但数据和脚本不需要。
bin
前缀告诉automake此处列出的文件应该安装到变量
bindir
指定的目录,autotools定义了一系列的目录,包括
bindir
,
libdir
和
pkglibdir
,还可以定义自己的目录。
如果想安装一些RUBY脚本作为程序的一部分,可以定义
rubydir
并告诉automake安装ruby脚本到此。
1 2
|
rubydir = $(datadir)/ruby ruby_DATA = my_script.rb my_other_script.rb
|
额外的前缀可以加在安装目录前来定义automake的具体行为。
因为我们定义了一个
PROGRAM
,需要告诉automake源文件位置,前缀为程序名。
1
|
helloworld_SOURCES = main.c
|
以下是Makefile.am的全文,它比Makefile或者Makefile.in要短很多。
1 2 3
|
AUTOMAKE_OPTIONS = foreign bin_PROGRAMS = helloworld helloworld_SOURCES = main.c
|
汇总
现在可以生成自己的configure和makefile.in了。首先需要生成autotools使用的m4环境变量。
现在可以运行autoconf来将configure.ac转换为configure文件,automake则生成Makefile.in
1 2
|
autoconf automake --add-missing
|
发布程序
最终用户只需configure和Makefile.in而不需要autotools生成以上文件的相关文件,所幸autotools也包含发布功能。Makefile包含所有有趣的目标,例如build一个包含发布工程所需的所有文件的tarball。
甚至可以测试该tarball在不同条件下的可安装性
总结
现在我们知道那些咒语的奥秘了
在维护者这里
1 2 3 4 5
|
aclocal # Set up an m4 environment autoconf # Generate configure from configure.ac automake --add-missing # Generate Makefile.in from Makefile.am ./configure # Generate Makefile from Makefile.in make distcheck # Use Makefile to build and test a tarball to distribute
|
在使用者那里
1 2 3
|
./configure # Generate Makefile from Makefile.in make # Use Makefile to build the program make install # Use Makefile to install the program
|