介绍
我们在 linux
上安装软件时,经常会使用如下命令
|
|
这些命令是怎么工作的呢?
这些命令有什么作用?
linux
上使用源码编译安装软件通常有如下三步
- 配置软件(Configure the software)
configure
脚本负责完成在指定系统上构建软件的准备工作,它确保后续的构建和安装过程中所有需要的依赖可以使用,并且找出使用这些依赖所需的任何信息。
Unix/Linux
程序经常使用 C
语言编写,所以我们经常需要 C
编译器来构建这些程序。在这个场景下, configure
脚本会确保你的系统中确实存在一个 C
编译器,并且找到这个 C
编译器的名字和位置。
- 构建软件(Build the software)
一旦 configure
命令执行完成,我们可以调用 make
命令来构建软件。这个步骤会执行定义在 Makefile
文件中的一系列任务来将软件从源码构建为最终可执行程序。
你下载的软件源码 tar
包通常不包含最终的 Makefile
文件,而是包含名为 Makefile.in
的模板文件。然后利用 configure
脚本针对当前的系统利用 Makefile.in
文件生成的定制化的 Makefile
文件。
- 安装软件(Install the software)
现在软件已经构建完成,可以运行了,相关文件可以被拷贝到它们的最终目录。 make install
命令会将构建出的可执行文件和它的依赖库、文档拷贝到正确的位置。
这通常意味着软件的二进制文件会被拷贝到你的 PATH
路径下,软件的操作手册会被拷贝到你的 MANPATH
路径下,同时软件依赖的其他文件也会被安全地保存到相应的位置。
因为安装步骤也是定义在 Makefile
文件中,所以软件的安装位置可以通过某个参数传递给 configure
脚本,或者由 configure
脚本利用某个系统变量来实现指定安装位置。
根据软件的安装位置,您可能需要升级此步骤的权限,以便可以将文件复制到系统目录。 使用 sudo
通常可以达到目的。
这些脚本是怎么产生的?
上述步骤之所以能成功工作,是因为 configure
脚本会检查你的系统,并使用它找到的信息将 Makefile.in
模板转换为 Makefile
文件,但是 configure
脚本和 Makefile.in
模板是怎么产生的呢?
如果你曾经打开过 configure
脚本,或者相关的 Makefile.in 文件,你会发现这些文件里包含几千行的脚本语句。有时候这些支持配置的脚本语句比要安装的程序的源代码还要长。
即使利用已有的 configure
脚本文件开始编写,手动编写完成一个 configure
脚本也是非常艰巨的。不过不用担心:这些脚本不是手工构建的。
以这种方式构建的软件通常使用一个叫做 autotools
的工具集进行打包。这个工具集包含 autoconf
、automake
等工具,所有的这些工具使得维护软件生命周期变得很容易。最终用户不需要了解这些工具,同时让软件在不同的 Unix/Linux
系统的安装步骤变得简单。
Hello World 案例
我们以一个简单的 Hello World
C 语言
程序为例,来看看如何使用 autotools
工具集打包。
下面是程序源代码,在一个名为 main.c
的文件中
|
|
创建 configure 脚本
不需要手动编写 configure
脚本,我们需要创建一个使用 m4sh
语言(m4
宏命令和 POSIX shell
脚本的组合)编写的 configure.ac
文件来描述 configure
脚本需要做的事情。
我们需要第一个调用的 m4
宏为 AC_INIT
,它会初始化 autoconf
并且设置一些关于打包软件的基本信息。我们的软件名为 helloworld
,版本为 0.1
,维护者为 george@thoughtbot.com
:
|
|
这个项目中我们会使用 automake
,所以我们需要使用 AM_INIT_AUTOMAKE
宏命令来初始化 automake
|
|
下面,我们需要告诉 autoconf
让 configure
脚本需要寻找的相关依赖,在本例中, configure
脚本仅需要使用 C
编译器,我们可以使用 AC_PROG_CC
宏命令设置。
|
|
如果有其他的依赖项,那我们可以使用其他的 m4
宏命令来设置,如使用 AC_PATH_PROG
宏表示在用户的 PATH
路径中搜索一个特定的程序。
此时我们已经列出了使用的依赖,前面有提到,configure
脚本会根据用户系统的系统信息和 Makefile.in
模板文件生成 Makefile
文件。
下面一行使用 AC_CONFIG_FILES
宏命令告诉 autoconf
工具 configure
脚本文件需要做这些工作:configure
脚本文件需要找到一个名为 Makefile.in
的文件,将文件内的站位符使用对应的值替换,例如将 @PACKAGE_VERSION@
替换为 0.1
,然后将结果写入到 Makefile
文件。
|
|
最后,当我们告诉 autoconf
工具所有 configure
脚本需要做的工作后,可以调用 AC_OUTPUT
宏命令输出脚本内容
|
|
下面是 configure.ac
中的所有代码,相比 4737 行的 configure
脚本文件,这些代码好多了。
|
|
还差一点我们就可以发布软件了,configure
脚本需要一个 Makefile.in
文件,将系统相关信息填充进去后,生成最终的 Makefile
文件。
创建 Makefile 文件
与 configure
脚本文件相比,Makefile.in
模板文件非常长且复杂。因此,我们不是手工编写,而是编写一个较短的 Makefile.am
文件,然后利用automake
使用该文件为我们生成 Makefile.in
文件。
首先,我们需要设置一些参数来告诉 automake
工具本项目的结构,因为这里的例子不是标准的 GNU
项目的结构,所以结构声明为 foreign
。
|
|
接下来告诉 automake
我们希望 Makefile
编译的软件名为 helloworld
:
|
|
这行包含了很多打包信息,感谢 automake
的统一命名规则
PROGRAMS
后缀成为 primary
主要信息,它告诉 automake
工具 helloworld
文件具有哪些属性。例如 PROGRAMS
需要被编译,相比 SCRIPTS
和 DATA
文件不需要被编译。
bin
前缀告诉 automake
工具,这里列出的文件应该被安装到 bindir
变量指定的路径下。 autotools
工具还为我们定义了其他目录,包括 bindir
, libdir
, pkglibdir
,我们也可以自定义自己需要的目录。
如果我们的程序有一部分是 Ruby
脚本,我们可以定义 rubydir
变量并且告诉 automake
安装我们的 ruby
文件到该路径。
|
|
可以在安装目录之前添加其他前缀,以进一步区分 automake
的行为。
因为我们已经定义了 RPOGRAM
,我们需要告诉 automake
在哪里可以找到它的源文件。 在这种情况下,前缀是这些源文件构建的程序的名称,而不是它们将安装的位置:
|
|
这是我们的 helloworld
程序的整个 Makefile.am
文件。 与 configure.ac
和 configure
脚本一样,它比它生成的 Makefile.in
要短得多:
|
|
把它们放在一起
现在我们已经编写了配置文件,我们可以运行 autotools
并生成完成的 configure
脚本和 Makefile.in
模板。
首先,我们需要生成一个 m4
环境供 autotools
使用:
|
|
现在我们可以运行 autoconf 将
configure.ac转换为
configure脚本,并运行
automake将
Makefile.am转换为
Makefile.in`:
|
|
分发程序
最终用户不需要查看我们的 autotools
工具的设置,因此我们可以分发 configure
脚本和 Makefile.in
,而无需分发用于生成它们的所有文件。
幸运的是,autotools
工具也将帮助我们进行分发。 Makefile
包含各种有趣的目标,包括构建项目 tarball
的目标,其中包含我们需要分发的所有文件:
|
|
您甚至可以测试分发 tarball
是否可以在各种条件下安装:
|
|
总览
现在我们知道编译安装命令从何而来以及它是如何运作的!
在维护者的系统上:
|
|
在最终用户的系统上:
|
|
参考:
https://zhuanlan.zhihu.com/p/77813702
https://thoughtbot.com/blog/the-magic-behind-configure-make-make-install