指令
ldconfig [-f conf] [ -C cache]
ldconfig [-p] :增进动态函式库的读取速度 / 判断动态函式库的链接信息
-f conf :那个 conf 指的是某个文件名,也就是说,使用 conf 作为 libarary 函式库的取得路径,而不以 /etc/ld.so.conf 为默认值
-C cache:那个 cache 指的是某个文件名,也就是说,使用 cache 作为快取暂存的函式库资料,而不以 /etc/ld.so.cache 为默认值
-p :列出目前有的所有函式库资料内容 (在 /etc/ld.so.cache 内的资料!)
ldd [-vdr] [filename] :程序的动态函式库解析
-v :列出所有内容信息;
-d :重新将资料有遗失的 link 点秀出来!
-r :将 ELF 有关的错误内容秀出来!
md5sum / sha1sum / sha256sum : 检验软件正确性
什么是开放源码、编译程序与可执行文件
在讨论程序代码是什么之前,我们先来谈论一下什么是可执行文件?我们说过,在 Linux 系统上面,一个文件能不能被执行看的是有没有可执行的那个权限 (具有 x permission),不过,Linux 系统上真正认识的可执行文件其实是二进制文件 ( binary program),例如 /usr/bin/passwd, /bin/touch 这些个文件即为二进制程序代码。
或许你会说 shell scripts 不是也可以执行吗?其实 shell scripts 只是利用 shell (例如 bash) 这支程序的功能进行一些判断式,而最终执行的除了 bash 提供的功能外,仍是呼叫一些已经编译好的二进制程序来执行的!当然, bash 本身也是一支二进制程序!那么我怎么知道一个文件是否为binary 呢?还记得我们在第六章里面提到的 file 这个指令的功能吗?我们现在来测试一下:
看到了吧!如果是 binary 而且是可以执行的时候,他就会显示执行文件类别 (ELF 64-bit LSB executable), 同时会说明是否使用动态函式库 (shared libs),而如果是一般的 script ,那他就会显示出 text executables 之类的字样!
既然 Linux 操作系统真正认识的其实是 binary program,那么我们是如何做出这样的一支 binary 的程序呢?首先,我们必须要写程序,用什么东西写程序?就是一般的字处理器!如使用 vim 来进行程序的撰写,写完的程序就是所谓的源代码! 这个程序代码文件其实就是一般的纯文本档。 在完成这个原始码文件的编写之后,再来就是要将这个文件『编译』成为操作系统看的懂得 binary program!而要编译自然就需要『编译程序』来动作, 经过编译程序的编译与连结之后,就会产生一支可以执行的 binary program。整个的流程有点像这样:
总之,我们可以这么说:
- 开放源码:就是程序代码,写给人类看的程序语言,但机器并不认识,所以无法执行;
- 编译程序:将程序代码转译成为机器看的懂得语言,就类似翻译者的角色;
- 可执行文件:经过编译程序变成二进制程序后,机器看的懂所以可以执行的文件。
什么是 make 与 configure
因为一套软件并不会仅有一支程序,而是有一堆程序代码文件。所以除了每个主程序与子程序均需要写上一笔编译过程的指令外,还需要写上最终的链接程序。 程序代码小的时候还好,如果是类似 WWW 服务器软件 (例如 Apache) ,或者是类似核心的原始码,动则数百 MBytes 的数据量,编译指令会写到疯掉~这个时候,我们就可以使用 make 这个指令的相关功能来进行编译过程的指令简化
当执行 make 时,make 会在当时的目录下搜寻 Makefile (or makefile) 这个文本文件,而 Makefile 里面则记录了原始码如何编译
的详细信息! make 会自动的判别原始码是否经过变动了,而自动更新执行档,是软件工程师相当好用的一个辅助工具
make 是一支程序,会去找 Makefile ,那 Makefile 怎么写? 通常软件开发商都会写一支侦测程序来侦测用户的作业环境, 以及该作业环境是否有软件开发商所需要的其他功能,该侦测程序侦测完毕后,就会主动的建立这个 Makefile 的规则文件!通常这支侦测程序的文件名为 configure 或者是 config
一般来说,侦测程序会侦测的数据大约有底下这些:
- 是否有适合的编译程序可以编译本软件的程序代码;
- 是否已经存在本软件所需要的函式库,或其他需要的相依软件;
- 操作系统平台是否适合本软件,包括 Linux 的核心版本;
- 核心的表头定义档 (header include) 是否存在 (驱动程序必须要的侦测)。
至于 make 与 configure 运作流程的相关性,我们可以使用底下的图示来示意一下! 下图中,妳要进行的任务其实只有两个,一个是执行 configure 来建立 Makefile , 这个步骤一定要成功!成功之后再以 make 来呼叫所需要的数据来编译即可!非常简单!
什么是 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 这两个文件,通常你只要能够参考这两个文件。
用 make 进行宏编译
我们仅写出 main 需要的目标文件,结果 make 会主动的去判断每个目标文件相关的原始码文件,并直接予以编译,最后再直接进行连结的动作! 此外,如果我们更动过某些原始码文件,则 make 也可以主动的判断哪一个原始码与相关的目标文件文件有更新过, 并仅更新该文件,如此一来,将可大大的节省很多编译的时间!要知道,某些程序在进行编译的行为时,会消耗很多的 CPU 资源!所以说, make 有这些好处:
- 简化编译时所需要下达的指令;
- 若在编译完成之后,修改了某个原始码文件,则 make 仅会针对被修改了的文件进行编译,其他的 object file 不会被更动;
- 最后可以依照相依性来更新 (update) 执行档。
makefile 的基本语法与变量
目标 (target) 就是我们想要建立的信息,而目标文件就是具有相关性的 object files ,那建立执行文件的语法就是以
- 在 makefile 当中的 # 代表批注;
需要在命令行 (例如 gcc 这个编译程序指令) 的第一个字符; - 目标 (target) 与相依文件(就是目标文件)之间需以『:』隔开
如此一来,我们的 makefile 里面就具有至少两个目标,分别是 main 与 clean ,如果我们想要建立 main 的话,输入『make main』,如果想要清除目标文件,输入『make clean』即可!而如果想要先清除目标文件再编译 main 这个程序的话,就可以这样输入:『make clean main』
makefile 里面重复的数据这么多!所以我们可以再藉由 shell script 那时学到的『变数』来更简化 makefile :
与 bash shell script 的语法有点不太相同,变量的基本语法为:
- 变量与变量内容以『=』隔开,同时两边可以具有空格;
- 变量左边不可以有
,例如上面范例的第一行 LIBS 左边不可以是 ; - 变量与变量内容在『=』两边不能具有『:』;
- 在习惯上,变数最好是以『大写字母』为主;
- 运用变量时,以 ${变量} 或 $(变量) 使用;
- 在该 shell 的环境变量是可以被套用的,例如提到的 CFLAGS 这个变数!
- 在指令列模式也可以给予变量。
由于 gcc 在进行编译的行为时,会主动的去读取 CFLAGS 这个环境变量,所以,你可以直接在 shell 定义出这个环境变量,也可以在 makefile 文件里面去定义,例如:
可以利用指令列进行环境变量的输入,也可以在文件内直接指定环境变量,那万一这个 CFLAGS 的内容在指令列与 makefile 里面并不相同时,以那个方式输入的为主?环境变量取用的规则是这样的:
- make 指令列后面加上的环境变量为优先;
- makefile 里面指定的环境变量第二;
- shell 原本具有的环境变量第三。
此外,还有一些特殊的变量需要了解的:
$@:代表目前的目标(target)
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) 的指定来安装到正确的路径!
底下约略提一下大部分的 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 的项目,将上一个步骤所编译完成的数据给他安装到预定的目录中,就完成安装了!
请注意,上面的步骤是一步一步来进行的,而其中只要一个步骤无法成功,那么后续的步骤就完全没有办法进行的!因此,要确定每一的步骤都是成功的才可以!
一般 Tarball 软件安装的建议事项 (如何移除?升级?)
或许你已经发现了也说不定,那就是为什么前一个小节里面,Tarball 要在 /usr/local/src 里面解压缩呢?基本上,在预设的情况下,原本的 Linux distribution 释出安装的软件大多是在 /usr 里面的,而用户自行安装的软件则建议放置在 /usr/local 里面。这是考虑到管理用户所安装软件的便利性。
我们晓得几乎每个软件都会提供联机帮助的服务,那就是 info 与 man 的功能。在预设的情况下, man 会去搜寻 /usr/local/man 里面的说明文件, 因此,如果我们将软件安装在 /usr/local 底下的话,那么自然安装完成之后, 该软件的说明文件就可以被找到了。此外,如果你所管理的主机其实是由多人共同管理的, 或者是如同学校里面,一部主机是由学生管理的,但是学生总会毕业吧? 所以需要进行交接,如果大家都将软件安装在 /usr/local 底下,那么管理就显的特别的容易!
为了方便 Tarball 的管理,通常会这样建议使用者:
- 最好将 tarball 的原始数据解压缩到 /usr/local/src 当中;
- 安装时,最好安装到 /usr/local 这个默认路径下;
- 考虑未来的反安装步骤,最好可以将每个软件单独的安装在 /usr/local 底下;
- 为安装到单独目录的软件之 man page 加入 man path 搜寻:
如果你安装的软件放置到 /usr/local/software/ ,那么 man page 搜寻的设定中,可能就得要在 /etc/man_db.conf 内的 40~50 行左右处,写入如下的一行:
MANPATH_MAP /usr/local/software/bin /usr/local/software/man
利用 patch 更新原始码
如果可以将旧版的原始码数据改写成新版的版本, 那么就能直接编译了,而不需要将全部的新版 Tarball 重新下载一次呢!可以节省带宽与时间说!那么如何改写原始码? 难道要我们一个文件一个文件去参考然后修订吗?当然没有这么没人性!
diff,这个指令可以将『两个文件之间的差异性列出来』!那我们也知道新旧版本的文件之间, 其实只有修改一些程序代码而已,那么我们可以透过 diff 比对出新旧版本之间的文字差异,然后再以相关的指令来将旧版的文件更新吗?当然可以!那就是 patch 这个指令!很多的软件开发商在更新了原始码之后,几乎都会释出所谓的patch file
,也就是直接将原始码 update 而已的一个方式
查阅 patch file 内容
上面表格内有个底线的部分,那代表使用 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 才对!
更新原始码,并且重新编译程序!
只不过更新了原始码并非软件就更新!你还是得要将该软件进行编译后,才会是最终正确的软件! 因为 patch 的功能主要仅只是更新原始码文件而已!切记切记
!此外,如果你 patch 错误 patch是可以还原的!透过『 patch -R < ../main_0.1_to_0.2.patch 』就可以还原
动态与静态函式库
ldconfig 与 /etc/ld.so.con
Linux 大多是将函式库做成动态函式库之后,再来要知道的就是,那有没有办法增加函式库的读取效能? 我们知道内存的访问速度是硬盘的好几倍,所以,如果我们将常用到的动态函式库先加载内存当中 (快取, cache),如此一来,当软件要取用动态函式库时,就不需要从头由硬盘里面读出!这个时候就需要 ldconfig 与 /etc/ld.so.conf 的协助了。
如何将动态函式库加载高速缓存当中呢?
- 首先,我们必须要在 /etc/ld.so.conf 里面写下『 想要读入高速缓存当中的动态函式库所在的目录』,注意, 是目录而不是文件;
- 接下来则是利用 ldconfig 这个执行档将 /etc/ld.so.conf 的资料读入快取当中;
- 同时也将数据记录一份在 /etc/ld.so.cache 这个文件当中!
总结
原始码其实大多是纯文本档,需要透过编译程序的编译动作后,才能够制作出 Linux 系统能够认识的可执行的 binary file ;
开放原始码可以加速软件的更新速度,让软件效能更快、漏洞修补更实时;
在 Linux 系统当中,最标准的 C 语言编译程序为 gcc ;
在编译的过程当中,可以藉由其他软件提供的函式库来使用该软件的相关机制与功能;
5 为了简化编译过程当中的复杂的指令输入,可以藉由 make 与 makefile 规则定义,来简化程序的更新、编译与连结等动作;Tarball 为使用 tar 与 gzip/bzip2/xz 压缩功能所打包与压缩的,具有原始码的文件;
一般而言,要使用 Tarball 管理 Linux 系统上的软件,最好需要 gcc, make, autoconfig, kernel source, kernel header 等前驱软件才行,所以在安装 Linux 之初,最好就能够选择 Software development 以及 kernel development 之类的群组;
函式库有动态函式库与静态函式库,动态函式库在升级上具有较佳的优势。动态函式库的扩展名为 *.so 而静态则是 *.a ;
patch 的主要功能在更新原始码,所以更新原始码之后,还需要进行重新编译的动作才行;
可以利用 ldconfig 与 /etc/ld.so.conf /etc/ld.so.conf.d/*.conf 来制作动态函式库的链接与快取!
透过 MD5/SHA1/SHA256 的编码可以判断下载的文件是否为原本厂商所释出的文件。