Linux笔记:13-软件安装:原始码与Tarball
@
软件安装:原始码与 Tarball
在这一章当中,我们将藉由 Linux 操作系统里面的执行文件,来理解什么是可执行的程序,以及了解什么是编译程序。可以了解如何将开放源码的程序设计、加入函式库的原理、透过编译而成为可以执行 的 binary program,最后该执行档可被我们所使用的一连串过程。
开放源码的软件安装与升级简介
因为 Linux 上面的软件几乎都是经过 GPL 的授权,所以每个软件几乎均提供源代码, 并且你可以自行修改该程序代码,以符合你个人的需求
什么是开放源码、编译程序与可执行文件
我们说过,在 Linux 系统上面,一个文件能不能被执行看的是有没有可执行的那个权限 (具有 x permission),不过, Linux 系统上真正认识的可执行文件其实是二进制文件 ( binary program),例如 /usr/bin/passwd, /bin/touch 这些个文件即为二进制程序代码。
或许你会说 shell scripts 不是也可以执行吗?其实 shell scripts 只是利用 shell (例如 bash) 这支程序的功能进行一些判断式,而最终执行的除了 bash 提供的功能外,仍是呼叫一些已经编译好的二进制程序来执行的。
bash 本身也是一支二进制程序;
那么我怎么知道一个文件是否为binary 呢?还记得我们在 Linux文件与目录管理 里面提到的 file 这个指令的功能
# 先以系统的文件测试看看:
[root@study ~]# file /bin/bash
/bin/bash: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked
(uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0x7e60e35005254...stripped
# 如果是系统提供的 /etc/init.d/network 呢?
[root@study ~]# file /etc/init.d/network
/etc/init.d/network: Bourne-Again shell script, ASCII text executable
如果是 binary 而且是可以执行的时候,他就会显示执行文件类别 (ELF 64-bit LSBexecutable), 同时会说明是否使用动态函式库 (shared libs),而如果是一般的 script ,那他就会显示出 text executables 之类的字样。
既然 Linux 操作系统真正认识的其实是 binary program,那么我们是如何做出这样的一支 binary 的程序呢?
首先,我们必须要写程序,用什么东西写程序?就是一般的字处理器。 这个程序代码文件其实就是一般的纯文本档。 在完成这个原始码文件的编写之后,再来就是要将这个文件『编译』成为操作系统看的懂得 binary program 。
而要编译自然就需要『编译程序』来动作, 经过编译程序的编译与连结之后,就会产生一支可以执行的 binary program 。

事实上,在编译的过程当中还会产生所谓的目标文件 (Object file),这些文件是以 *.o 的扩展名样式存在的。
至于 C 语言的原始码文件通常以 *.c 作为扩展名。此外,有的时候,我们会在程序当中『引用、呼叫』 其他的外部子程序,或者是利用其他软件提供的『函数功能』,这个时候,我们就必须要在编译的过程当中, 将该函式库给他加进去,如此一来,编译程序就可以将所有的程序代码与函式库作一个连结 (Link) 以产生正确的执行档。
各名词解释如下:
- 开放源码:就是程序代码,写给人类看的程序语言,但机器并不认识,所以无法执行;
- 编译程序:将程序代码转译成为机器看的懂得语言,就类似翻译者的角色;
- 可执行文件:经过编译程序变成二进制程序后,机器看的懂所以可以执行的文件。
什么是函式库
在编译的过程里面有提到函式库这东西。 什么是函式库呢?
先举个例子来说:我们的 Linux 系统上通常已经提供一个可以进行身份验证的模块, 就是在 Linux账号管理与ACL权限设定 提到的 PAM 模块。这个 PAM 提供的功能可以让很多的程序在被执行的时候,除了可以验证用户登入的信息外, 还可以将身份确认的数据记录在登录档里面,以方便系统管理员的追踪。
如果我要编写具有身份认证功能的程序时,直接引用该 PAM 的功能就好了,如此一来,我就不需要重新设计认证机制!也就是说,只要在我写的程序代码里面,设定去呼叫 PAM 的函式功能,我的程序就可以利用 Linux 原本就有的身份认证的程序!除此之外,其实我们的 Linux 核心也提供了相当多的函式库来给硬件开发者利用。
函式库又分为动态与静态函式库
这里我们以一个简单的流程图,来示意一支有呼叫外部函式库的程序的执行情况。

事实上, Linux 的核心提供很多的核心相关函式库与外部参数, 这些核心功能在设计硬件的驱动程序的时候是相当有用的信息,这些核心相关信息大多放置在/usr/include, /usr/lib, /usr/lib64 里面
反正我们可以简单的这么理解:
- 函式库:就类似子程序的角色,可以被呼叫来执行的一段功能函数。
什么是 make 与 configure
事实上,使用类似 gcc 的编译程序来进行编译的过程并不简单,因为一套软件并不会仅有一支程序,而是有一堆程序代码文件。所以除了每个主程序与子程序均需要写上一笔编译过程的指令外,还需要写上最终的链接程序。 程序代码小的时候还好,如果是类似 WWW 服务器软件 (例如 Apache) ,或者是类似核心的原始码,动则数百 MBytes 的数据量,编译指令会写到疯掉~这个时候,我们就可以使用 make 这个指令的相关功能来进行编译过程的指令简化了。
当执行 make 时, make 会在当时的目录下搜寻 Makefile (or makefile) 这个文本文件,而 Makefile 里面则记录了原始码如何编译的详细信息!
make 会自动的判别原始码是否经过变动了,而自动更新执行档
make 是一支程序,会去找 Makefile ,那 Makefile 怎么写?
通常软件开发商都会写一支侦测程序来侦测用户的作业环境, 以及该作业环境是否有软件开发商所需要的其他功能,该侦测程序侦测完毕后,就会主动的建立这个 Makefile 的规则文件。
通常这支侦测程序的文件名为 configure 或者是 config 。
那为什么要侦测作业环境呢?
我们曾经提过其实每个 Linux distribution 都使用同样的核心,但妳得要注意, 不同版本的核心所使用的系统呼叫可能不相同,而且每个软件所需要的相依的函式库也不相同, 同时,软件开发商不会仅针对 Linux 开发,而是会针对整个 Unix-Like做开发。 所以他也必须要侦测该操作系统平台有没有提供合适的编译程序才行。
所以当然要侦测环境, 一般来说,侦测程序会侦测的数据大约有底下这些:
- 是否有适合的编译程序可以编译本软件的程序代码;
- 是否已经存在本软件所需要的函式库,或其他需要的相依软件;
- 操作系统平台是否适合本软件,包括 Linux 的核心版本;
- 核心的表头定义档 (header include) 是否存在 (驱动程序必须要的侦测)。
至于 make 与 configure 运作流程的相关性,我们可以使用底下的图示来示意一下;
下图中,妳要进行的任务其实只有两个,一个是执行 configure 来建立 Makefile , 这个步骤一定要成功!
成功之后再以 make 来呼叫所需要的数据来编译即可

由于不同的 Linux distribution 的函式库文件所放置的路径,或者是函式库的档名, 或者是预设安装的编译程序,以及核心的版本都不相同,因此理论上,你无法在 CentOS 7.x 上面编译出 binaryprogram 后,还将他拿到 SuSE 上面执行,这个动作通常是不可能成功的! 因为呼叫的目标函式库位置可能不同 , 核心版本更不可能相同!所以能够执行的情况是微乎其微!所以同一套软件要在不同的平台上面执行时, 必须要重复编译!所以才需要原始码。
什么是 Tarball 的软件
我们知道所谓的源代码,其实就是一些写满了程序代码的纯文本文件。
我们在 文件与文件系统的压缩,打包与备份 的压缩指令的介绍当中, 也了解了纯文本文件在网络上其实是很浪费带宽的一种文件格式! 如果能够将这些原始码透过文件的打包与压缩技术来将文件的数量与容量减小, 不但让用户容易下载,软件开发商的网站带宽也能够节省很多。这就是 Tarball 文件的由来。
所谓的 Tarball 文件,其实就是将软件的所有原始码文件先以 tar 打包,然后再以压缩技术来压缩,通常最常见的就是以 gzip 来压缩。
**因为利用了 tar 与 gzip 的功能,所以 tarball 文件一般的扩展名就会写成 .tar.gz 或者是简写为 .tgz 。
不过,近来由于 bzip2 与 xz 的压缩率较佳,所以 Tarball渐渐的以 bzip2 及 xz 的压缩技术来取代 gzip 。因此档名也会变成 *.tar.bz2, *.tar.xz 之类的。所以说, Tarball 是一个软件包, 妳将他解压缩之后,里面的文件通常就会有:
- 源代码文件;
- 侦测程序文件 (可能是 configure 或 config 等檔名);
- 本软件的简易说明与安装说明 (INSTALL 或 README)。
其中最重要的是那个 INSTALL 或者是 README 这两个文件,通常你只要能够参考这两个文件,Tarball 软件的安装是很简单的。
如何安装与升级软件
基本上更新的方法可以分为两大类,分别是:
- 直接以原始码透过编译来安装与升级;
- 直接以编译好的 binary program 来安装与升级。
上面第一点很简单,就是直接以 Tarball 在自己的机器上面进行侦测、编译、 安装与设定等等动作来升级就了。
不过,这样的动作虽然让使用者在安装过程当中具有很高的弹性, 但毕竟是比较麻烦一点,如果 Linux distribution 厂商能够针对自己的作业平台先进行编译等过程,再将编译好的binary program 释出的话,那由于我的系统与该 Linux distribution 的环境是相同的,所以他所释出的binary program 就可以在我的机器上面直接安装。省略了侦测与编译等等繁杂的过程。
这个预先编译好程序的机制存在于很多 distribution ,包括有 Red Hat 系统 (含 Fedora/CentOS 系列) 发展的 RPM 软件管理机制与 yum 在线更新模式; Debian 使用的 dpkg 软件管理机制与 APT在线更新模式等等。
由于 CentOS 系统是依循标准的 Linux distribution,所以可以使用 Tarball 直接进行编译的安装与升级, 当然也可以使用 RPM 相关的机制来进行安装与升级。
本章节主要针对 Tarball ,至于 RPM则留待下个章节再来介绍。
好了,那么一个软件的 Tarball 是如何安装的呢?基本流程是这样的:
- 将 Tarball 由厂商的网页下载下来;
- 将 Tarball 解开,产生很多的原始码文件;
- 开始以 gcc 进行原始码的编译 (会产生目标文件 object files);
- 然后以 gcc 进行函式库、主、子程序的链接,以形成主要的 binary file;
- 将上述的 binary file 以及相关的配置文件安装至自己的主机上面。
上面第 3, 4 步骤当中,我们可以透过 make 这个指令的功能来简化他, 所以整个步骤其实是很简单的。
只不过你就得需要至少有 gcc 以及 make 这两个软件在你的 Linux 系统里面才行。
用 make 进行宏编译
看看使用 make 简化下达编译指令的流程
为什么要用 make
假设我的执行档里面包含了四个原始码文件,分别是 main.c haha.c sin_value.ccos_value.c 这四个文件,这四个文件的目的是:
- main.c :主要的目的是让用户输入角度数据与呼叫其他三支子程序;
- haha.c :输出一堆有的没有的讯息而已;
- sin_value.c :计算使用者输入的角度(360) sin 数值;
- cos_value.c :计算使用者输入的角度(360) cos 数值。
由于这四个文件里面包含了相关性,并且还用到数学函式在里面,所以如果你想要让这个程序可以跑, 那么就需要这样编译:
# 1\. 先进行目标文件的编译,最终会有四个 *.o 的文件名出现:
[root@study ~]# gcc -c main.c
[root@study ~]# gcc -c haha.c
[root@study ~]# gcc -c sin_value.c
[root@study ~]# gcc -c cos_value.c
# 2\. 再进行链接成为可执行文件,并加入 libm 的数学函数,以产生 main 可执行文件:
[root@study ~]# gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 3\. 本程序的执行结果,必须输入姓名、360 度角的角度值来计算:
[root@study ~]# ./main
Please input your name: VBird <==这里先输入名字
Please enter the degree angle (ex> 90): 30 <==输入以 360 度角为主的角度
Hi, Dear VBird, nice to meet you. <==这三行为输出的结果喔!
The Sin is: 0.50
The Cos is: 0.87
编译的过程需要进行好多动作。而且如果要重新编译,则上述的流程得要重新来一遍,光是找出这
些指令就够烦人的了。如果可以的话,能不能一个步骤就给他完成上面所有的动作呢?那就利用make 这个工具吧! 先试看看在这个目录下建立一个名为 makefile 的文件,内容如下:
# 1\. 先编辑 makefile 这个规则档,内容只要作出 main 这个可执行文件
[root@study ~]# vim makefile
main: main.o haha.o sin_value.o cos_value.o
gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 注意:第二行的 gcc 之前是 <tab> 按键产生的空格喔!
# 2\. 尝试使用 makefile 制订的规则进行编译的行为:
[root@study ~]# rm -f main *.o <==先将之前的目标文件去除
[root@study ~]# make
cc -c -o main.o main.c
cc -c -o haha.o haha.c
cc -c -o sin_value.o sin_value.c
cc -c -o cos_value.o cos_value.c
gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 此时 make 会去读取 makefile 的内容,并根据内容直接去给他编译相关的文件啰!
# 3\. 在不删除任何文件的情况下,重新执行一次编译的动作:
[root@study ~]# make
make: `main' is up to date.
# 看到了吧!是否很方便呢!只会进行更新 (update) 的动作而已。
或许你会说:『如果我建立一个 shell script 来将上面的所有动作都集结在一起,不是具有同样的效果吗?』。
效果当然不一样,以上面的测试为例,我们仅写出 main 需要的目标文件,结果 make会主动的去判断每个目标文件相关的原始码文件,并直接予以编译,最后再直接进行连结的动作! 真的是很方便。
此外,如果我们更动过某些原始码文件,则 make 也可以主动的判断哪一个原始码与相关的目标文件文件有更新过, 并仅更新该文件,如此一来,将可大大的节省很多编译的时间。要知道,某些程序在进行编译的行为时,会消耗很多的 CPU 资源。
所以说, make 有这些好处:
- 简化编译时所需要下达的指令;
- 若在编译完成之后,修改了某个原始码文件,则 make 仅会针对被修改了的文件进行编译,其他的 object file
不会被更动;- 最后可以依照相依性来更新 (update) 执行档。
makefile 的基本语法与变量
make 的语法可是相当的多而复杂的,有兴趣的话可以到 GNU (注 1) 去查阅相关的说明;
这里仅列出一些基本的规则,重点在于让读者们未来在接触原始码时,不会太紧张。基本的makefile 规则是这样的:
目标(target): 目标文件1 目标文件2
<tab> gcc -o 欲创建的可执行文件 目标文件1 目标文件2
那个目标 (target) 就是我们想要建立的信息,而目标文件就是具有相关性的 object files ,那建立执行文件的语法就是以 <tab> 按键开头的那一行。
特别注意:『命令行必须要以 tab 按键作为开头』才行。他的规则基本上是这样的:
- 在 makefile 当中的 # 代表批注;
- <tab> 需要在命令行 (例如 gcc 这个编译程序指令) 的第一个字符;
- 目标 (target) 与相依文件(就是目标文件)之间需以『:』隔开。
Tarball 的管理与建议
从前面几个小节的说明当中,我们晓得其实 Tarball 的安装是可以跨平台的,因为 C 语言的程序代码在各个平台上面是可以共通的, 只是需要的编译程序可能并不相同而已。
例如 Linux 上面用 gcc 而 Windows 上面也有相关的 C 编译程序~所以呢,同样的一组原始码,既可以在 CentOS Linux 上面编译,也可以在 SuSE Linux 上面编译,当然,也可以在大部分的 Unix平台上面编译成功的。
如果万一没有编译成功怎么办?很简单啊,透过修改小部分的程序代码 (通常是因为很小部分的异动而已) 就可以进行跨平台的移植了!也就是说,刚刚我们在 Linux 底下写的程序『理论上,是可以在 Windows 上面编译的!』这就是原始码的好处。
所以说,如果朋友们想要学习程序语言的话,鸟哥个人是比较建议学习『具有跨平台能力的程序语言』,例如 C 就是很不错的一个!
使用原始码管理软件所需要的基础软件
从原始码的说明我们晓得要制作一个 binary program 需要很多东西。这包括底下这些基础的软件:
gcc 或 cc 等 C 语言编译程序 (compiler):
没有编译程序怎么进行编译的动作?所以 C compiler 是一定要有的。不过 Linux 上面有众多的编译程序,其中当然以 GNU 的 gcc 是首选的自由软件编译程序。
事实上很多在 Linux 平台上面发展的软件的原始码,原本就是以 gcc 为底来设计的。
make 及 autoconfig 等软件:
一般来说,以 Tarball 方式释出的软件当中,为了简化编译的流程,通常都是配合前几个小节提到的 make 这个指令来依据目标文件的相依性而进行编译。
但是我们也知道说 make 需要makefile 这个文件的规则,那由于不同的系统里面可能具有的基础软件环境并不相同, 所以就需要侦测用户的作业环境,好自行建立一个 makefile 文件。
这个自行侦测的小程序也必须要藉由autoconfig 这个相关的软件来辅助才行。
需要 Kernel 提供的 Library 以及相关的 Include 文件:
从前面的原始码编译过程,我们晓得函式库 (library) 的重要性,同时也晓得有 include 文件的存在。
很多的软件在发展的时候都是直接取用系统核心提供的函式库与 include 文件的,这样才可以与这个操作系统兼容。尤其是在『驱动程序方面的模块 』,例如网络卡、声卡、 USB 等驱动程序在安装的时候,常常是需要核心提供的相关信息的。
在 Red Hat 的系统当中 (包含Fedora/CentOS 等系列) ,这个核心相关的功能通常都是被包含在 kernel-source 或 kernel-header 这些软件名称当中,所以记得要安装这些软件。
因为目前的 Linux distribution 大多已经偏向于桌面计算机的使用 (非服务器端),他们希望使用者能够按照厂商自己的希望来安装相关的软件即可, 所以通常『预设』是没有安装 gcc 或者是 make 等软件的。
所以啦, 如果你希望未来可以自行安装一些以Tarball 方式释出的软件时,记得请自行挑选想要安装的软件名称。例如在 CentOS 或者是 Red Hat当中记得选择 Development Tools 以及 Kernel Source Development 等相关字眼的软件群集。
那万一我已经安装好一部 Linux 主机,但是使用的是默认值所安装的软件,所以没有 make, gcc 等咚咚,该如何是好?
问题其实不大啦,目前使用最广泛的 CentOS/Fedora 或者是 Red Hat 大多是以 RPM (下一章会介绍) 来安装软件的,所以,你只要拿出当初安装 Linux 时的原版光盘,然后以下一章介绍的 RPM 来一个一个的加入到你的 Linux 主机里面就好。
尤其现在又有 yum 这玩意儿,更方便。
在 CentOS 当中,如果你已经有网络可以连上 Internet 的话,那么就可以使用下一章会谈到的 yum。
透过 yum 的软件群组安装功能,你可以这样做:
- 如果是要安装 gcc 等软件开发工具,请使用『 yum groupinstall "Development Tools" 』
- 若待安装的软件需要图形接口支持,一般还需要『 yum groupinstall "X Software Development" 』
- 若安装的软件较旧,可能需要『 yum groupinstall "Legacy Software Development" 』
Tarball 安装的基本步骤
以 Tarball 方式释出的软件是需要重新编译可执行的 binary program 的。
而 Tarball 是以tar 这个指令来打包与压缩的文件,所以,当然就需要先将 Tarball 解压缩,然后到原始码所在的目录下进行 makefile 的建立,再以 make 来进行编译与安装的动作。
所以整个安装的基础动作大多是这样的:
- 取得原始档:将 tarball 文件在 /usr/local/src 目录下解压缩;
- 取得步骤流程:进入新建立的目录底下,去查阅 INSTALL 与 README 等相关文件内容 (很重要的步骤! );
- 相依属性软件安装:根据 INSTALL/README 的内容察看并安装好一些相依的软件 (非必要);
- 建立 makefile:以自动侦测程序 (configure 或 config) 侦测作业环境,并建立 Makefile 这个文件;
- 编译:以 make 这个程序并使用该目录下的 Makefile 做为他的参数配置文件,来进行 make (编译或其他)
的动作;- 安装:以 make 这个程序,并以 Makefile 这个参数配置文件,依据 install 这个目标 (target) 的指定来安
装到正确的路径。
注意到上面的第二个步骤,通常在每个软件在释出的时候,都会附上 INSTALL 或者是 README 这种档名的说明档,这些说明档请『确实详细的』 阅读过一遍,通常这些文件会记录这个软件的安装要求、软件的工作项目、 与软件的安装参数设定及技巧等,只要仔细的读完这些文件,基本上,要安装好 tarball 的文件,都不会有什么大问题。
至于 makefile 在制作出来之后,里头会有相当多的目标 (target),最常见的就是 install 与 clean 。
通常『make clean』代表着将目标文件 (object file) 清除掉,『make』则是将原始码进行编译而已。
注意:编译完成的可执行文件与相关的配置文件还在原始码所在的目录当中。
因此,最后要进行『make install』来将编译完成的所有东西都给他安装到正确的路径去,这样就可以使用该软件。
我们下面概要的提一下大部分的 tarball 软件之安装的指令下达方式:
./configure
这个步骤就是在建立 Makefile 这个文件。通常程序开发者会写一支 scripts 来检查你的 Linux 系统、相关的软件属性等等,这个步骤相当的重要, 因为未来你的安装信息都是这一步骤内完成的!另外,这个步骤的相关信息应该要参考一下该目录下的 README 或 INSTALL 相关的文件。make clean
make 会读取 Makefile 中关于 clean 的工作。这个步骤不一定会有,但是希望执行一下,因为他可以去除
目标文件!因为谁也不确定原始码里面到底有没有包含上次编译过的目标文件 (*.o) 存在,所以当然还是
清除一下比较妥当的。 至少等一下新编译出来的执行档我们可以确定是使用自己的机器所编译完成的。make
make 会依据 Makefile 当中的预设工作进行编译的行为!编译的工作主要是进行 gcc 来将原始码编译成为
可以被执行的 object files ,但是这些 object files 通常还需要一些函式库之类的 link 后,才能产生一个完
整的执行档!使用 make 就是要将原始码编译成为可以被执行的可执行文件,而这个可执行文件会放置在
目前所在的目录之下, 尚未被安装到预定安装的目录中;make install
通常这就是最后的安装步骤了, make 会依据 Makefile 这个文件里面关于 install 的项目,将上一个步骤所
编译完成的数据给他安装到预定的目录中,就完成安装。
请注意,上面的步骤是一步一步来进行的,而其中只要一个步骤无法成功,那么后续的步骤就完全没有办法进行的。
另外,如果在 make 无法成功的话,那就表示源文件无法被编译成可执行文件,那么 make install 主要是将编译完成的文件给他放置到文件系统中的,既然都没有可用的执行档了,怎么进行安装? 所以,要每一个步骤都正确无误才能往下继续做。此外,如果安装成功, 并且是安装在独立的一个目录中,例如 /usr/local/packages 这个目录中好了,那么你就必需手动的将这个软件的 man page 给他写入 /etc/man_db.conf 里面去。
一般 Tarball 软件安装的建议事项 (如何移除?升级? )
或许你已经发现了也说不定,那就是为什么前一个小节里面, Tarball 要在 /usr/local/src 里面解压缩呢?
基本上,在预设的情况下,原本的 Linux distribution 释出安装的软件大多是在 /usr 里面的,而用户自行安装的软件则建议放置在 /usr/local 里面。
这是考虑到管理用户所安装软件的便利性。
我们知道几乎每个软件都会提供联机帮助的服务,那就是 info 与 man 的功能。
在预设的情况下, man 会去搜寻 /usr/local/man 里面的说明文件, 因此,如果我们将软件安装在 /usr/local底下的话,那么自然安装完成之后, 该软件的说明文件就可以被找到了。
此外,如果你所管理的主机其实是由多人共同管理的, 或者是如同学校里面,一部主机是由学生管理的,但是学生总会毕业吧? 所以需要进行交接,如果大家都将软件安装在 /usr/local 底下,那么管理上不就显的特别的容易吗!
所以,通常我们会建议大家将自己安装的软件放置在 /usr/local 下,至于原始码 (Tarball)则建议放置在/usr/local/src (src 为 source 的缩写)底下。
我们先来看一看 Linux distribution 默认的安装软件的路径会用到哪些?
我们以 apache 这个软件来说明的话 (apache 是 WWW 服务器软件):
- /etc/httpd
- /usr/lib
- /usr/bin
- /usr/share/man
我们会发现软件的内容大致上是摆在 etc, lib, bin, man 等目录当中,分别代表『配置文件、函式库、执行档、联机帮助档』。
那么你是以 tarball 来安装时,如果是放在预设的 /usr/local 里面,由于 /usr/local 原本就默认这几个目录了,所以你的数据就会被放在:
- /usr/local/etc
- /usr/local/bin
- /usr/local/lib
- /usr/local/man
但是如果你每个软件都选择在这个默认的路径下安装的话, 那么所有的软件的文件都将放置在这四个目录当中,因此,如果你都安装在这个目录下的话, 那么未来再想要升级或移除的时候,就会比较难以追查文件的来源。 而如果你在安装的时候选择的是单独的目录,例如我将 apache 安装在/usr/local/apache 当中,那么你的文件目录就会变成:
- /usr/local/apache/etc
- /usr/local/apache/bin
- /usr/local/apache/lib
- /usr/local/apache/man
单一软件的文件都在同一个目录之下,那么要移除该软件就简单的多了!
只要将该目录移除即可视为该软件已经被移除。
以上面为例,我想要移除 apache 只要下达『rm -rf /usr/local/apache』就算移除这个软件。当然,实际安装的时候还是得视该软件的 Makefile 里头的 install 信息才能知道到底他的安装情况为何的。
这个方式虽然有利于软件的移除,但不晓得你有没有发现,我们在执行某些指令的时候,与该指令是否在 PATH 这个环境变量所记录的路径有关,以上面为例,我的 /usr/local/apache/bin 肯定是不在PATH 里面的,所以执行 apache 的指令就得要利用绝对路径了,否则就得将这个/usr/local/apache/bin 加入 PATH 里面。
另外,那个 /usr/local/apache/man 也需要加入 man page 搜寻的路径当中。
除此之外, Tarball 在升级的时候也是挺困扰的。
我们还是以 apache 来说明好了。 WWW服务器为了考虑互动性,所以通常会将 PHP+MySQL+Apache 一起安装起来 ,果真如此的话,那么每个软件在安装的时候『都有一定的顺序与程序!』 因为他们三者之间具有相关性,所以安装时必需要三者同时考虑到他们的函式库与相关的编译参数。
假设今天我只要升级 PHP 呢?有的时候因为只有涉及动态函式库的升级,那么我只要升级 PHP 即可!其他的部分或许影响不大。但是如果今天 PHP 需要重新编译的模块比较多,那么可能会连带的,连 Apache 这个程序也需要重新编译过才行!真是有点给他头痛的!没办法!使用 tarball 确实有他的优点啦,但是在这方面,确实也有他一定的伤脑筋程度。
由于 Tarball 在升级与安装上面具有这些特色,亦即 Tarball 在反安装上面具有比较高的难度 (如果你没有好好规划的话~),所以,为了方便 Tarball 的管理,通常鸟哥会这样建议使用者:
- 最好将 tarball 的原始数据解压缩到 /usr/local/src 当中;
- 安装时,最好安装到 /usr/local 这个默认路径下;
- 考虑未来的反安装步骤,最好可以将每个软件单独的安装在 /usr/local 底下;
- 为安装到单独目录的软件之 man page 加入 man path 搜寻:
总结:
时至今日,老实说,真的不太需要有 tarball 的安装了。 CentOS/Fedora 有个 RPM 补遗计划,就是俗称的 EPEL 计划,一般学界会用到的软件都在里头~ 除非你要用的软件是专属软件 (要钱的) 或者是比较冷门的软件,否则都有好心的网友帮我们打包好了。
利用 patch 更新原始码
所谓的『更新原始码』常常是只有更改部分文件的小部分内容而已。
既然如此的话, 那么我们是否可以就那些被更动的文件来进行修改就可以?也就是说, 旧版本到新版本间没有更动过的文件就不要理他,仅将有修订过的文件部分来处理即可。
这样有很多好处;首先,没有更动过的文件的目标文件 (object file) 根本就不需要重新编译,而且有更动过的文件又可以利用 make 来自动 update (更新),如此一来,我们原先的设定 (makefile 文件里面的规则) 将不需要重新改写或侦测!可以节省很多宝贵的时间 (例如后续章节会提到的核心的编译! )
因此我们可以发现,如果可以将旧版的原始码数据改写成新版的版本, 那么就能直接编译了,而不需要将全部的新版 Tarball 重新下载一次。
之前有提到一个比对文件的指令,那就是 diff,这个指令可以将『两个文件之间的差异性列出来』。那我们也知道新旧版本的文件之间, 其实只有修改一些程序代码而已,那么我们可以透过 diff 比对出新旧版本之间的文字差异,然后再以相关的指令来将旧版的文件更新吗?
当然可以啦!那就是 patch 这个指令。很多的软件开发商在更新了原始码之后,几乎都会释出所谓的 patch file,也就是直接将原始码 update 而已的一个方式。
假设我们刚刚计算三角函数的程序 (main) 历经多次改版, 0.1 版仅会简单的输出, 0.2 版的输出就会含有角度值,因此这两个版本的内容不相同。如下所示,两个文件的意义为:
- http://linux.vbird.org/linux_basic/0520source/main-0.1.tgz : main 的 0.1 版;
- http://linux.vbird.org/linux_basic/0520source/main_0.1_to_0.2.patch : main 由 0.1 升级到 0.2 的 patch file;
请您先下载这两个文件,并且解压缩到你的 /root 底下。
你发现系统产生一个名为 main-0.1 的目录。 该目录内含有五个文件,就是刚刚的程序加上一个 Makefile 的规则文件。你可以到该目录下去看看 Makefile 的内容, 在这一版当中含有 main 与 clean 两个目标功能而已。至于 0.2 版则加入了 install 与 uninstall 的规则设定。
测试旧版程序的功能
[root@study ~]# tar -zxvf main-0.1.tgz
[root@study ~]# cd main-0.1
[root@study main-0.1]# make clean main
[root@study main-0.1]# ./main
version 0.1
Please input your name: VBird
Please enter the degree angle (ex> 90): 45
Hi, Dear VBird, nice to meet you.
The Sin is: 0.71
The Cos is: 0.71
与之前的结果非常类似,只是鸟哥将 Makefile 直接给您了!但如果你下达 make install 时,系统会告知没有 install 的 target 啊!而且版本是 0.1 也告知了。那么如何更新到 0.2 版呢?透过这个patch 文件吧!这个文件的内容有点像这样:
查阅 patch file 内容
[root@study main-0.1]# vim ~/main_0.1_to_0.2.patch
diff -Naur main-0.1/cos_value.c main-0.2/cos_value.c
--- main-0.1/cos_value.c 2015-09-04 14:46:59.200444001 +0800
+++ main-0.2/cos_value.c 2015-09-04 14:47:10.215444000 +0800
@@ -7,5 +7,5 @@
{
float value;
....(下面省略)....
上面表格内有个底线的部分,那代表使用 diff 去比较时,被比较的两个文件所在路径,这个路径非常的重要!因为 patch 的基本语法如下:
patch -p 数字 < patch_file
特别留意那个『 -p 数字』,那是与 patch_file 里面列出的文件名有关的信息。
假如在 patch_file 第一行写的是这样:
*** /home/guest/example/expatch.old
那么当我下达『 patch -p0 < patch_file 』时,则更新的文件是『 /home/guest/example/expatch.old 』,如果『 patch -p1 < patch_file』,则更新的文件为『home/guest/example/expatch.old』,如果『patch -p4< patch_file』则更新『expatch.old』。
也就是说, -pxx 那个 xx 代表『拿掉几个斜线(/)』的意思。
根据刚刚上头的资料,我们可以发现比较的文件是在 main-0.1/xxx 与main-0.2/xxx , 所以说,如果你是在 main-0.1 底下,并且想要处理更新时,就得要拿掉一个目录 (因为并没有 main-0.2 的目录存在, 我们是在当前的目录进行更新的! ),因此使用的是 -p1 才对。所以:
更新原始码,并且重新编译程序!
[root@study main-0.1]# patch -p1 < ../main_0.1_to_0.2.patch
patching file cos_value.c
patching file main.c
patching file Makefile
patching file sin_value.c
# 请注意,鸟哥目前所在目录是在 main-0.1 下面喔!注意与 patch 文件的相对路径!
# 虽然有五个文件,但其实只有四个文件有修改过喔!上面显示有改过的文件!
[root@study main-0.1]# make clean main
[root@study main-0.1]# ./main
version 0.2
Please input your name: VBird
Please enter the degree angle (ex> 90): 45
Hi, Dear VBird, nice to meet you.
The sin(45.000000) is: 0.71
The cos(45.000000) is: 0.71
# 你可以发现,输出的结果中版本变了,输出信息多了括号 () 喔!
[root@study main-0.1]# make install <==将他安装到 /usr/local/bin 给大家用
cp -a main /usr/local/bin
[root@study main-0.1]# main <==直接输入指令可执行!
[root@study main-0.1]# make uninstall <==移除此软件!
rm -f /usr/local/bin/main
所以你只要下载 patch file 就能够对你的软件原始码更新了。只不过更新了原始码并非软件就更新。你还是得要将该软件进行编译后,才会是最终正确的软件。 因为 patch 的功能主要仅只是更新原始码文件而已。切记切记!
此外,如果你 patch 错误呢?没关系的!我们的 patch是可以还原,透过『 patch -R <../main_0.1_to_0.2.patch 』就可以还原。
函式库管理
在我们的 Linux 操作系统当中,函式库是很重要的一个项目。 因为很多的软件之间都会互相取用彼此提供的函式库来进行特殊功能的运作,函式库又依照是否被编译到程序内部而分为动态与静态函式库。
动态与静态函式库
依据函式库被使用的类型而分为两大类,分别是静态(Static) 与动态 (Dynamic) 函式库两类。
·静态函式库的特色 ·
扩展名:
(扩展名为 .a) 这类的函式库通常扩展名为 libxxx.a 的类型;
编译行为:
这类函式库在编译的时候会直接整合到执行程序当中,所以利用静态函式库编译成的文件会比较大一些;
独立执行的状态:
这类函式库最大的优点,就是编译成功的可执行文件可以独立执行,而不需要再向外部要求读取函式库的内容 (请参照动态函式库的说明)。
升级难易度:
虽然执行档可以独立执行,但因为函式库是直接整合到执行档中, 因此若函式库升级时,整个执行档必须要重新编译才能将新版的函式库整合到程序当中。 也就是说,在升级方面,只要函式库升级了,所有将此函式库纳入的程序都需要重新编译!
动态函式库的特色
扩展名:
(扩展名为 .so) 这类函式库通常扩展名为 libxxx.so 的类型;
编译行为:
动态函式库与静态函式库的编译行为差异挺大的。 与静态函式库被整个捉到程序中不同的,动态函式库在
编译的时候,在程序里面只有一个『指向 (Pointer)』的位置而已。也就是说,动态函式库的内容并没有被
整合到执行档当中,而是当执行档要使用到函式库的机制时, 程序才会去读取函式库来使用。由于执行文
件当中仅具有指向动态函式库所在的指标而已, 并不包含函式库的内容,所以他的文件会比较小一点。独立执行的状态:
这类型的函式库所编译出来的程序不能被独立执行, 因为当我们使用到函式库的机制时,程序才会去读取
函式库,所以函式库文件『必须要存在』才行,而且,函式库的『所在目录也不能改变』,因为我们的可执
行文件里面仅有『指标』亦即当要取用该动态函式库时, 程序会主动去某个路径下读取,所以动态函式库可不能随意移动或删除,会影响很多相依的程序软件!升级难易度:
虽然这类型的执行档无法独立运作,然而由于是具有指向的功能, 所以,当函式库升级后,执行档根本不
需要进行重新编译的行为,因为执行档会直接指向新的函式库文件 (前提是函式库新旧版本的档名相同喔!)。
目前的 Linux distribution 比较倾向于使用动态函式库,因为如同上面提到的最重要的一点, 就是函式库的升级方便 。
由于 Linux 系统里面的软件相依性太复杂了,如果使用太多的静态函式库,那么升级某一个函式库时, 都会对整个系统造成很大的冲击!因为其他相依的执行档也要同时重新编译啊! 这个时候动态函式库可就有用多了,因为只要动态函式库升级就好,其他的软件根本无须变动。
绝大多数的函式库都放置在: /lib64, /lib 目录下。
此外, Linux 系统里面很多的函式库其实 kernel 就提供了,那么 kernel 的函式库放在哪里?就是在/lib/modules 里面。
不过要注意的是, 不同版本的核心提供的函式库差异性是挺大的,所以 kernel 2.4.xx 版本的系统不要想将核心换成 2.6.xx 。 很容易由于函式库的不同而导致很多原本可以执行的软件无法顺利运作。
ldconfig 与 /etc/ld.so.conf
我们目前的 Linux 大多是将函式库做成动态函式库,那有没有办法增加函式库的读取效能?
我们知道内存的访问速度是硬盘的好几倍,所以, 如果我们将常用到的动态函式库先加载内存当中 (快取, cache),如此一来,当软件要取用动态函式库时,就不需要从头由硬盘里面读出!
这样不就可以增进动态函式库的读取速度?这个时候就需要 ldconfig 与 /etc/ld.so.conf 的协助了。
如何将动态函式库加载高速缓存当中
- 首先,我们必须要在 /etc/ld.so.conf 里面写下『 想要读入高速缓存当中的动态函式库所在的目录』,注意
, 是目录而不是文件;- 接下来则是利用 ldconfig 这个执行档将 /etc/ld.so.conf 的资料读入快取当中;
- 同时也将数据记录一份在 /etc/ld.so.cache 这个文件当中。

ldconfig 还可以用来判断动态函式库的链接信息 。
假设妳想要将目前你系统下的 mariadb 函式库加入到快取当中时,可以这样做:
[root@study ~]# ldconfig [-f conf] [ -C cache]
[root@study ~]# ldconfig [-p]
选项与参数:
-f conf :那个 conf 指的是某个文件名称,也就是说,使用 conf 作为 libarary
函数库的取得路径,而不以 /etc/ld.so.conf 为默认值
-C cache:那个 cache 指的是某个文件名称,也就是说,使用 cache 作为高速缓存暂存
的函数库数据,而不以 /etc/ld.so.cache 为默认值
-p :列出目前有的所有函数库数据内容 (在 /etc/ld.so.cache 内的数据!)
范例一:假设我的 Mariadb 数据库函数库在 /usr/lib64/mysql 当中,如何读进 cache ?
[root@study ~]# vim /etc/ld.so.conf.d/vbird.conf
/usr/lib64/mysql <==这一行新增的啦!
[root@study ~]# ldconfig <==画面上不会显示任何的信息,不要太紧张!正常的!
[root@study ~]# ldconfig -p
924 libs found in cache `/etc/ld.so.cache'
p11-kit-trust.so (libc6,x86-64) => /lib64/p11-kit-trust.so
libzapojit-0.0.so.0 (libc6,x86-64) => /lib64/libzapojit-0.0.so.0
....(下面省略)....
# 函数库名称 => 该函数库实际路径
透过上面的动作,我们可以将 Mariadb 的相关函式库给他读入快取当中,这样可以加快函式库读取的效率。
在某些时候,你可能会自行加入某些 Tarball 安装的动态函式库,而你想要让这些动态函式库的相关连结可以被读入到快取当中, 这个时候你可以将动态函式库所在的目录名称写入/etc/ld.so.conf.d/yourfile.conf 当中,然后执行 ldconfig 就可以。
程序的动态函式库解析: ldd
如何判断某个可执行的 binary 文件含有什么动态函式库呢?
[root@study ~]# ldd [-vdr] [filename]
选项与参数:
-v :列出所有内容信息;
-d :重新将数据有遗失的 link 点秀出来!
-r :将 ELF 有关的错误内容秀出来!
范例一:找出 /usr/bin/passwd 这个文件的函数库数据
[root@study ~]# ldd /usr/bin/passwd
....(前面省略)....
libpam.so.0 => /lib64/libpam.so.0 (0x00007f5e683dd000) <==PAM 模块
libpam_misc.so.0 => /lib64/libpam_misc.so.0 (0x00007f5e681d8000)
libaudit.so.1 => /lib64/libaudit.so.1 (0x00007f5e67fb1000) <==SELinux
libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f5e67d8c000) <==SELinux
....(下面省略)....
# 我们前言的部分不是一直提到 passwd 有使用到 pam 的模块吗!怎么知道?
# 利用 ldd 察看一下这个文件,看到 libpam.so 了吧?这就是 pam 提供的函数库
范例二:找出 /lib64/libc.so.6 这个函数的相关其他函数库!
[root@study ~]# ldd -v /lib64/libc.so.6
/lib64/ld-linux-x86-64.so.2 (0x00007f7acc68f000)
linux-vdso.so.1 => (0x00007fffa975b000)
Version information: <==使用 -v 选项,增加显示其他版本信息!
/lib64/libc.so.6:
ld-linux-x86-64.so.2 (GLIBC_2.3) => /lib64/ld-linux-x86-64.so.2
ld-linux-x86-64.so.2 (GLIBC_PRIVATE) => /lib64/ld-linux-x86-64.so.2
未来如果你常常升级安装 RPM 的软件时 (下一章节会介绍),应该常常会发现那个『 相依属性』的问题。
我们可以先以 ldd 来视察『相依函式库』之间的相关性,以先取得了解。
例如上面的例子中,我们检查了 libc.so.6 这个在 /lib64 当中的函式库,结果发现他其实还跟ld-linux-x86-64.so.2 有关。
所以我们就需要来了解一下,那个文件到底是什么软件的函式库呀?使用-v 这个参数还可以得知该函式库来自于哪一个软件!像上面的数据中,就可以得到该 libc.so.6 其实可以支持 GLIBC_2.3 等的版本。

浙公网安备 33010602011771号