-
Notifications
You must be signed in to change notification settings - Fork 13
/
21补2、configure,make,make install 背后的魔法
276 lines (140 loc) · 9.07 KB
/
21补2、configure,make,make install 背后的魔法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
翻译自:
https://robots.thoughtbot.com/the-magic-behind-configure-make-make-install
若你使用过任何种类的 Unix 系统用于开发,那么你可能已经用下面的魔咒来从源码安装软件
./configure
make
make install
我知道我已经把它们输入过好多遍了,但在我使用 Linux 的早些时候,我并不真的理解它们意味着什么,
我仅知道若我想安装软件,那就按照这个来就好了
最近我开始构建我自己的 Unix 工具,而且我也想利用这个标准安装流程;
这不仅仅是因为很多 Unix 用户对它很熟悉,同时,也是为 Homebrew 和各种 Linux 以及 BSD 包管理器构建包的良好起点
是时候一头扎入 Unix 的魔法书来寻找这些咒语到底是什么意思了
所有这些到底都在干什么?
该过程有三个完全不同的步骤:
1、配置软件
configure 脚本用于在你特定的系统上准备好构建软件
它保证了其后的构建和安装过程中需要的依赖都是可用的,
也找出使用这些依赖所需要知道的任何内容
Unix 软件通常用 C 写成,所以我们通常需要一个 C 编译器来编译它们
在这些情况下 configure 脚本将确认的你同种的确具有一个 C 编译器,并找到它叫什么,以及何处能找到它
2、构建软件
一旦 configure 完成了它的工作,我们可以调用 make 来构建软件
它运行一系列在 Makefile 中定义的操作从源码构建出最终的程序
你下载的 tarball 中通常并不包含最终的 Makefile 文件
相反,它通常包含一个被称为 Makefile.in 的模板,以及用于生成你系统特定的 Makefile 的 configure 脚本
3、安装软件
现在软件就构建完成,且已经可以运行了,文件就可以被拷贝至最终的目标了
make install 冰灵将拷贝构建好的程序,以及它的库和文档,至正确的地方
这通常意味着程序的二进制文件将被拷贝至你 PATH 定义的目录中,
程序的用户手册将被拷贝至的你 MANPATH 定义的目录中,
其它任何被它依赖的文件都将被安全地存储在正确的位置
由于安装步骤也同样被定义在 Makefile 中,而软件安装的位置可以基于传入 configure 脚本的参数来修改,
或者 configure 脚本从你系统中发现的东西
基于软件被安装的位置,你可能需要为这个步骤提权,这样你可以拷贝文件至系统目录中
使用 sudo 通常就可以了
这些脚本来自哪里
所有这些工作都是由于 configure 脚本价差了你的系统,并用它找的信息将 Makefile.in 模板转换为 Makefile,
但 configure 脚本和 Makefile.in 模板又来自哪里呢?
若你打开过一个 configure 脚本,或关联的 Makefile.in,你应该已经见过了它们包含上千行密密麻麻的 shell 脚本
有些时候这些支持脚本比它们所安装的程序的源码还要长
即便是从一个现有的 configure 脚本开始,手动构建一个也是非常让人却步的
别担心,这些脚本都不是手动编辑的
用这种方法编译的程序通常使用一些列被统称为 autotools 的工具打包
这套工具包含 autoconf automake 以及很多其他工具,所有这些工具共同工作让软件维护者的生活简单了很多
终端用户不会看到这些工具,但它们免去了在各类不同的 Unix 上配置和安装过程的痛苦
Hello world
让我们选用一个简单的 “Hello world” C 程序,然后看一看用 autotools 如何将其打包
这里是程序的源码,放在一个被称为 main.c 的文件中:
#include <stdio.h>
int
main(int argc, char* argv[])
{
printf("Hello world\n");
return 0;
}
创建 configure 脚本
不用手动创建 configure 脚本,我们需要创建一个 m4sh 格式——结合了 m4 宏以及 POSIX shell 脚本——的 configure.ac 文件,
来描述 configure 文件将要做什么
我们需要的第一个 m4 宏称为 AC_INIT,它将初始化 autoconf 并为我们打包的程序设置一些基础的信息
本程序叫做 helloworld,版本号是 0.1,维护者是 george@thoughtbot.com:
AC_INIT([helloworld], [0.1], [george@thoughtbot.com])
我们将在该项目中使用 automake,所以我们需要使用 AM_INIT_AUTOMAKE 宏来初始化它:
AM_INIT_AUTOMAKE
接着,我们需要告诉 autoconf 有关于我们的 configure 脚本需要寻找的依赖
在这个案例中, configure 脚本仅需要寻找 C 编译器
我们可以用 AC_PROG_CC 宏来设置:
AC_PROG_CC
若有其它的依赖,我们需要用其他的 m4 宏来发现它们;
举例来说,AC_PATH_PROG 宏用于从用户定义的 PATH 中寻找给定的程序
现在我们已经罗列了我们的依赖,我们可以使用它们了
我们前面看到一个典型的 configure 脚本将使用它从用户系统上找到的信息,从 Makefile.in 模板中构建 Makefile
下一行使用 AC_CONFIG_FILES 宏来告诉 autoconf configure 脚本应该这样做:它应该找到一个被称为 Makefile.in 的文件,
用类似于 0.1 这样的值,替换类似于 @PACKAGE_VERSIOIN@ 这样占位符,并将结果写入 Makefile 中
AC_CONFIG_FILES([Makefile])
最终,当我们告诉了 autoconf 所有我们的 configure 脚本应该做的事情之后,我们可以调用 AC_OUTPUT 宏来输出这个脚本:
AC_OUTPUT
这就是所有的东西了
与将要生成的 4737 行的 configure 脚本来说,一切还不错
AC_INIT([helloworld], [0.1], [george@thoughtbot.com])
AM_INIT_AUTOMAKE
AC_PROG_CC
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
我们几乎就要完成打包,并分发我们的程序了,但是我们依旧缺少一些东西
我们的 configure 脚本希望一个 Makefile.in 文件,让它可以替换所有那些系统特定的变量进去,但到目前为止,我们还没有创建那个文件
创建 Makefile
与 configure 脚本一样, Makefile.in 模板也是非常的长而复杂的
所以我们不会手写它,我们写一个更短的 Makefile.am 文件,而 automake 将使用它为我们生成 Makefile.in
首先,我们需要设置一些选项来告诉 automake 关于工程的布局
由于我们并没有遵循 GNU 项目的标准布局,我们警告 automake 这是一个 foreign 项目:
AUTOMAKE_OPTIONS = foreign
下一步,我们告诉 automake 我么希望 Makefile 构建一个名为 helloworld 的程序:
bin_PROGRAMS = helloworld
这行涵盖了很多的信息,感谢 automake 的 uniform naming scheme
PROGRAMS 后缀被称为一个 primary
它告诉 automake helloworld 这个文件的属性
举例来说,PROGRAMS 需要被构建,而 SCRIPTS 和 DATA 则不需要被构建
bin 前缀告诉 automake 这里罗列的文件应该被安装至由变量 bindir 所定义的目录下
autotools 为我们定义了很多目录——包含 bindir, libdir, pkglibdir——但我们也可以定义我们自己的
若我们想安装一些 Ruby 脚本作为我们程序的一部分,我们可以定义个 rubydir 变量,
并告诉 automake 将我们的 Ruby 文件安装到那里
rubydir = $(datadir)/ruby
ruby_DATA = myscript.rb my_other_script.rb
附加的前缀可以在安装目录前被添加,用于更加细调 automake 的行为
由于我们已经定义了一个 PROGRAM,我们需要告诉 automake 从那里寻找源文件
在当前的案例中,前缀是这些源码构建出来的程序名,而不是它们应该被安装的地方:
helloworld_SOURCES = main.c
这里是我们的 helloworld 程序的完整的 Makefile.am 文件
与 configure.ac 与 configure 脚本的关系一样,它也比它生成的 Makefile.in 短太多了:
AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = helloworld
helloworld_SOURCES = main.c
将它们组合起来
现在我们写好了我们的配置文件,我们可以运行 autotools,并生成完整的 configure 脚本和 Makefile.in 模板了
首先,我们需要生成一个 m4 环境以供 autotools 使用:
aclocal
现在我们可以运行 autoconf 来将我们的 configure.ac 转化为 configure 脚本,
并用 automake 将 Makefile.am 转化为 Makefile.in:
autoconf
automake --add-missing
分发程序
终端用户不需要看见我们的 autotools 设置,所以我们可以仅分发 configure 脚本和 Makefile.in,
而不用包含我们用来生成它们的文件
幸运的是,autotools 也能帮注我们分发
Makefile 包含了各种有趣的 target,其中包含了一个用于构建包含了分发所需要的所有工程文件的 tarball 的 target:
./configure
make dist
你甚至可以测试你分发的包是否可以在各种条件下安装:
make distcheck
总览
现在我们知道这些咒语的来源,以及它们是如何运行的了!
在维护者的系统上:
aclocal # 设置 m4 环境
autoconf # 从 configure.ac 生成 configure
automake --add-missing # 从 Makefile.am 生成 Makefile.in
./configure # 从 Makefile.in 生成 Makefile
make distcheck # 使用 Makefile 构建并测试一个用于分发的 tarball
在终端用户系统上:
./configure # 从 Makefile.in 生成 Makefile
make # 使用 Makefile 构建程序
make install # 使用 Makefile 安装程序