软件安装:源码与Tarball
1、开放源码的软件安装与升级简介
Linux 上面的软件几乎都是经过 GPL 的授权,所以每个软件几乎均提供源码,并且你可以自行修改该程序代码,以符合个人的需求!这就是开放源码的优点。
1.1、什么是开放源码、编译程序与可执行文件
之前说过,在 Linux 上面一个文件能不能被执行看的是有没有可执行权限。不过,Linux 系统上面真正认识的可执行文件其实是二进制文件,即二进制程序代码。
[root@li ~]# 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]=85e3da5a087950e7aaeb7893c056218a8874d2e5, stripped
#如果是 binary 而且是可以执行的话,它就会显示执行文件类型(ELF 64-bit LSB executable),同时会说明是否使用动态函数库(shared libs)
[root@li ~]# file /etc/init.d/network
/etc/init.d/network: Bourne-Again shell script, ASCII text executable
#如果是一般的 scripts,那他就会显示 text executable 之类的字样
那制作一支可以被执行的二进制文件,整体流程如下:
1.2、什么是函数库
函数库又分为静态和动态函数库。下面以一个简单的流程图来说明呼叫外部函数库的程序的执行情况:
Linux 的内核提供了很多的内核相关函数库与外部参数,这些内核功能在设计硬件驱动程序的时候是相当有用的信息,这些内核相关信息大多放置在 /usr/include,/usr/lib,/usr/lib64 目录。
1.3、什么是 make 与 configure
make 指令可以进行大型软件的编译简化。当执行 make 时,make 会在当前的目录下搜寻 Makefile(或 makefile)这个文件,而 Makefile 里面则记录了源码如何编译的具体信息!make 会自动的判别源码是否经过变动了。
make 是一支程序,会去找 Makefile,那 Makefile 怎么写?通常软件开发商都会写一支侦测程序来侦测用户的作业环境,以及该作业是否有软件开发商需要的其他功能,该侦测程序侦测完毕后,就会主动地建立这个 Makefile 的规则文件!通常这支侦测程序的文件名为 configure 或 config。
那为什么要侦测作业环境呢?不是每个 Linux distribution 都使用同样的内核吗?但你要注意的是,不同版本的内核所使用的系统呼叫可能不相同,而且每个软件所需要的相依赖的函数库也不相同,同时,软件开发商不会针对 Linux 开发,而是针对整个 Unix-Like 做开发!所以他也必须要侦测该操作系统平台有没有提供合适的编译程序才行!一般来说,侦测程序会侦测的数据大约有底下这些:
- 是否有合适的编译程序可以编译本软件的程序代码;
- 是否已经存在了本软件所需要的函数库,或其他需要的相依赖软件;
- 操作系统平台是否适合本软件,包括 Linux 的内核版本;
- 内核的表头定义文件(header include)是否存在(驱动程序必须要的侦测)。
至于 make 与 configure 运行的流程的相关性,我们可以用底下的图来示意:
上图中你要进行的任务其实只有两个,一个是执行 configure 来建立 Makefile,这个步骤一定要成功!成功之后再以 make 来呼叫所需要的数据来编译即可。
1.4、什么是 Tarball 的软件
我们知道所谓的源码,就是纯文本文件,之前我们也说过,纯文本文件在网络上其实是一种很浪费带宽的一种文件格式!所以,如果能够将这些源码通过文件的打包与压缩技术将文件的数量与容量减少,不但让用户容易下载,软件开发商的网站带宽也能够节省很多!这就是 Tarball 文件的由来。
所谓的 Tarball 文件,其实就是将软件的所有源码文件先以 tar 打包,然后再以压缩技术来压缩,通常最常见的就是以 gzip 来压缩了。**因为利用了 tar 与 gzip 的功能,所以 tarball 文件一般的扩展名就会被写成 .tar.gz 或者是简写成 .tgz!Tarball 是一个软件包,你将它解压缩之后,里面的文件通常包含:
- 源代码文件;
- 侦测程序文件(可能是 configure 或 cinfig 等文件名);
- 本软件的简易说明与安装说明(INSTALL 或 README)。
1.5、如何安装与升级
基本上更新的办法可分为两大类,分别是:
- 直接以源码通过编译安装与升级;
- 直接以编译好的 binary program 来安装与升级。
那么一个软件的 Tarball 是如何安装的呢?基本流程如下:
- 将 Tarball 由厂商的网页下载下来;
- 将 Tarball 解开,产生很多的源码文件;
- 开始以 gcc 进行源码的编译(会产生目标文件 object files);
- 然后以 gcc 进行函数库、主、子程序的链接,以形成主要的 binary file;
- 将上述的 binary file 以及相关的配置文件安装至自己的主机上。
上述的第 3、4 步骤可以用 make 进行简化。
2、使用传统程序语言进行编译的简单示范
2.1、单一程序:打印出 Hello World
#预设安装编译工具
[root@li ~]# yum groupinstall "Development Tools"
2.1.1、编辑程序代码,即源代码
[root@li ~]# vim hello.c
#include <stdio.h>
int main(void){
printf("Hello World\n");
}
2.1.2、开始编译与测试运行
[root@li ~]# gcc hello.c
[root@li ~]# ll hello.c a.out
-rwxr-xr-x. 1 root root 8360 8月 25 15:17 a.out #此时会产生这个文件
-rw-r--r--. 1 root root 63 8月 25 15:16 hello.c
[root@li ~]# ./a.out
Hello World
在预设的状态下,如果我们直接以 gcc 编译源码,并且没有加上任何参数,则执行文件的文件名会被自动设定为 a.out 这文件名!所以你就能直接执行 ./a.out 这个文件了!那个 hello.c 就是源码,而 gcc 就是编译程序,至于 a.out 就是编译成功后的可执行 binary program!那如果我想要产生目标文件来进行其他的动作,而且执行文件的文件名也不要用预设的 a.out 呢,该如何操作?
[root@li ~]# gcc -c hello.c
[root@li ~]# ll hello*
-rw-r--r--. 1 root root 63 8月 25 15:16 hello.c
-rw-r--r--. 1 root root 1496 8月 25 15:22 hello.o #就是产生的目标文件
[root@li ~]# gcc -o hello hello.o
[root@li ~]# ll hello*
-rwxr-xr-x. 1 root root 8360 8月 25 15:23 hello #这就是可执行文件! -o 的结果
-rw-r--r--. 1 root root 63 8月 25 15:16 hello.c
-rw-r--r--. 1 root root 1496 8月 25 15:22 hello.o
[root@li ~]# ./hello
Hello World
或许你会觉得,只要一个动作就可以制作出 a.out 就好了,为什么还要先制作出目标文件再制作可执行文件呢?
2.2、主、子程序链接:子程序的编译
如果我们在一个主程序里面又呼叫另一个子程序呢?这是很常见的一个程序写法,因为可以简化整个程序的易读性!
2.2.1、撰写所需要的主、子程序
#1、编辑主程序
[root@li ~]# vim thanks.c
#include <stdio.h>
int main(void){
printf("Hello World\n");
thanks_2();
}
[root@li ~]# vim thanks_2.c
#include <stdio.h>
void thanks_2(void){
printf("Thank you!\n");
}
2.2.2、进行编译与链接
#2、开始将源码编译成可执行文件 binary file
[root@li ~]# gcc -c thanks.c thanks_2.c
[root@li ~]# ll thank*
-rw-r--r--. 1 root root 63 8月 25 15:28 thanks_2.c
-rw-r--r--. 1 root root 1496 8月 25 15:29 thanks_2.o
-rw-r--r--. 1 root root 76 8月 25 15:27 thanks.c
-rw-r--r--. 1 root root 1560 8月 25 15:29 thanks.o
[root@li ~]# gcc -o thanks thanks.o thanks_2.o
[root@li ~]# ll thanks*
-rwxr-xr-x. 1 root root 8424 8月 25 15:32 thanks #最终会产生这个文件
[root@li ~]# ./thanks
Hello World
Thank you!
现在知道为什么要制作出目标文件了吧?由于我们的源码文件有时并非只有一个文件,所以我们无法进行直接编译。这个时候就需要先产生目标文件,然后再以链接制成 binary 可执行文件。另外,如果有一天,你更新了 thanks_2.c 的内容,则你只要重新编译 thanks_2.c 来产生目标文件,然后再链接制作出新的 binary 可执行文件即可。
2.3、呼叫外部函数库:加入链接的函数库
我们想要计算出三角函数里面的 sin(90度角):
[root@li ~]# vim sin.c
#include <stdio.h>
#include <math.h>
int main(void){
float value;
value = sin(3.14/2);
printf("%f\n",value);
}
那如何编译这个程序呢?
[root@li ~]# gcc sin.c
#新的 gcc 会主动将函数抓进来给你用,所以只要加上 include <math.h> 即可
数学函数库使用的是 libm.so 这个函数库,你最好在编译的时候将这个函数库纳进来。另外要注意,这个函数库放置的地方是系统默认会去找的 /lib,/lib64,所以你无须使用底下的 -L 去加入搜寻的目录!而 linm.so 在编译的写法上,使用的是 -lm:
[root@li ~]# gcc sin.c -lm -L/lib -L/lib64
[root@li ~]# ./a.out
1.000000
至于 #include <stdio.h>,头文件,这个文件放置在 /usr/include/ 目录下。可使用 -I/path 进行搜索。
3、用 make 进行宏编译
3.1、为什么使用 make
先来想象一个案例,假设我们的执行文件里面包含了四个源码文件,分别是 main.c,haha.c,sin_value.c,cos_value.c 这四个文件,这四个文件的目的是:
- main.c:主要目的是让用户输入角度数据与呼叫其他三支子程序;
- haha.c:输出一堆有的没的信息而已;
- sin_value:计算使用者输入的角度(360)sin 数值;
- cos_value:计算使用者输入的角度(360)cos 数值。
#1、先进行目标文件的编译,最终会有四个 *.o 的文件名出现
[root@li ~]# gcc -c main.c
[root@li ~]# gcc -c haha.c
[root@li ~]# gcc -c sin_value.c
[root@li ~]# gcc -c cos_value.c
#2、再进行链接成为执行文件,并加入 libm 的数学函数库,以产生 main 执行文件
[root@li main]# gcc -o main main.o haha.o sin_value.o cos_value.o -lm
#3、本程序的执行结果,必须输入姓名、360角度的角度值来计算
[root@li main]# ./main
Please input your name: Li
Please enter the degree angle (ex> 90): 30
Hi, Dear Li, nice to meet you.
The Sin is: 0.50
The Cos is: 0.87
编译的过程需要进行好多动作!而且如果要重新编译,则上述的流程得要重新来一遍,光是找出这些指令就够烦人了!如果可以的话,能不能一个步骤给它完成上面的所有动作呢?那就利用 make 这个工具吧!先试看看这个目录下建立一个名为 makefile 的文件:
#1、先编辑 makefile 这个规则文件,内容只要做出 main 这个执行文件
[root@li main]# 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 #这一行是 [Tab] 产生的空格
#2、尝试使用 makefile 指定的规则进行编译
[root@li main]# rm -f main*.o
[root@li main]# 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@li main]# make
make: “main”是最新的。 #只会进行更新的动作而已
make 的好处有这些:
- 简化编译时所需下达的命令;
- 若在编译完成后,修改了某个源码文件,则 make 仅会针对被修改的文件进行编译,其他的 object file 不会被更改;
- 最后可以依照想依赖性来更新执行文件。
3.2、makefile 的基本语法与变量
基本的 makefile 规则是这样的:
目标(target):目标文件1 目标文件2
<tab> gcc -o 预建立的执行文件 目标文件1 目标文件2
- 在 makefile 当中的 # 代表批注;
- <tab> 必须是命令所在行的第一个字符;
- 目标文件与相依赖文件之间需要以 “:” 隔开。
那么,如果我想有两个以上的执行动作时,例如下达一个指令就直接清除掉所有的目标文件与执行文件:
#1、先编辑 makefile 来建立新的规则,此规则的目标名称为 clean
[root@li main]# 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
clean:
rm -f main main.o haha.o sin_value.o cos_value.o
#2、以新的目标测试看看执行 make 的结果
[root@li main]# make clean
rm -f main main.o haha.o sin_value.o cos_value.o
如此一来,我们的 makefile 里面就具有至少两个目标,分别是 main 和 clean,如果我们想要建立 main 的话,输入 make main;如果想要清除文件,输入 make clean 即可。而如果想要先清除目标文件再编译 main 的话,就可以这样输入:make clean main,如下:
[root@li main]# make clean main
rm -f main main.o haha.o sin_value.o cos_value.o
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
但是还有一个问题,那就是 makefile 里面的重复数据为什么那么多!那么我们可以用 shell script 那时候学到的变量来简化:
[root@li main]# vim makefile
LIBS = -lm
OBJS = main.o haha.o sin_value.o cos_value.o
main: ${
OBJS}
gcc -o main ${
OBJS} ${
LIBS}
clean:
rm -f main ${
OBJS}
与 bash script 的语法有点不同,变量的基本语法如下:
- 变量与变量内容以 “=” 隔开,同时两边可以具有空格;
- 变量左边不可以有 <tab>;
- 变量与变量内容在 “=” 两边不能具有 “:”;
- 在习惯上,变量是大写;
- 运用变量时,以 ${变量名} 或 $(变量名) 使用;
- 在该 shell 的环境变量是可以被套用的,例如 CFLAGS;
- 在指令模式也可以给予变量。
[root@li main]# CFLAGS="-Wall" make clean main
也可以这样做:
[root@li main]# vim makefile
LIBS = -lm
OBJS = main.o haha.o sin_value.o cos_value.o
CFLAGS = -Wall
main: ${
OBJS}
gcc -o main ${
OBJS} ${
LIBS}
clean:
rm -f main ${
OBJS}
环境变量取用的规则:
- make 指令后面加上的环境变量优先;
- makefile 里面指定的环境变量第二;
- shell 原本具有的环境变量第三。
此外,还有一些特殊的变量需要了解:
- $@:代表目前的目标
所以,我们可以将 makefile 改写为:
[root@li main]# vim makefile
LIBS = -lm
OBJS = main.o haha.o sin_value.o cos_value.o
CFLAGS = -Wall
main: ${
OBJS}
gcc -o $@ ${
OBJS} ${
LIBS}
clean:
rm -f main ${
OBJS}
4、Tarball 的管理与建议
4.1、使用原始管理软件所需要的基础软件
要制作一个二进制的可执行文件,需要底下这几个基础的软件:
- gcc 或 cc 等 C 语言编译程序;
- make 及 autoconfig 等软件;
- 需要内核提供的 Library 以及相关的 Include 文件;
4.2、Tarball 安装的基本步骤
整个的安装步骤大多是这样的:
- 取得原始文件:将 tarball 文件在 /usr/local/src 目录下解压缩;
- 取得步骤流程:进入新建立的目录底下,去查阅 INSTALL 与 README 等相关文件内容(很重要的步骤!);
- 相依赖性软件安装:根据 INSTALL/README 的内容查看并安装好一些相依赖性的软件(非必要);
- 建立 makefile:以自动侦测程序(configure 或 config)侦测作业环境,并建立 Makefile 这个文件;
- 编译:以 make 这个程序并使用该目录下的 Makefile 作为他的参数配置文件,来进行 make(编译或其他)的动作;
- 安装:以 make 这个程序,并以 Makefile 这个参数配置文件,依据 install 这个目标的指定来安装到正确的路径!
我们提一下大部分的 tarball 软件安装的指令下达方式:
-
./configure
这个步骤就是建立 Makefile 这个文件。通常程序开发者都会写一支 scripts 来检查你的 Linux 环境、相关软件属性等等。
-
make clean
make 获取读取 Makefile 中关于 clean 的工作。这个步骤不一定会有,但是希望执行一下,因为它会去除目标文件!
-
make
make 会依据 Makefile 当中的预设工作进行编译。编译的工作主要是进行 gcc 来将源码编译成可以被执行的目标文件,但是这些目标文件通常还需要一些函数库之类的链接后,才能产生一个完整的可执行文件!使用 make 就是要将源码编译成可以被执行的可执行文件,而这个可执行文件会被放置在目前所在的目录下,尚未被安装到预定安装的目录。
-
make install
通常这都是最后的安装步骤了!make 会依据 Makefile 这个文件里面关于 install 的项目,将上一个步骤所编译的数据给它安装到预定的目录中。
4.3、一般 Tarball 软件安装的建议事项(如何移除?升级?)
基本上,在预设的情况下,原本的 Linux Distribution 安装的软件大多是在 /usr 里面的,而用户自行安装的软件则建议放置在 /usr/local/ 里面。为什么呢?我们晓得几乎每个软件都会提供联机帮助的服务,那就是 info 和 man 的功能。在预设的情况下,man 会搜寻 /usr/local/man 里面的说明文件,因此,如果我们将软件安装在 /usr/local 底下的话,那么自然安装完成后,该软件的说明文件就可以被找到了。所以,通常建议将自己安装的软件放置在 /usr/local 底下,至于源码建议放置在 /usr/local/src 底下。
再来,让我们先来看看 Linux distribution 默认的安装软件的路径会用到哪些?我们以 apache 这个软件来说明:
- /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/lcoal/apache/bin
- /usr/local/apache/lib
- /usr/local/apache/man
单一软件的文件都在同一目录下,那么要移除该软件就简单的多了!只要将该目录移除即可视为该软件已经被移除了!我想要移除 apache 只要下达 rm -rf /usr/local/apache 就算是移除了这个软件了。当然,实际安装的时候还是得要查看该软件的 Makefile 里面 install 的信息才能知道到底它的安装情况如何。
这个方式虽然有利于软件的移除,但不晓得你发现了没有,我们在执行某些指令的时候,与该指令是否在 PATH 这个环境变量所记录的路径有关,以上面的为例,我的 /usr/lcoal/apache/bin 肯定不在 PATH 里面的,所以执行 apache 的指令就要利用绝对路径了,否则就把它加入 PATH。另外,那个 /usr/local/apache/man 也需要加入 man page 搜寻的路径当中。
由于 Tarball 在升级与安装上面具有特色,即 tarball 在反安装上面具有比较高的难度,所以,为了方便 tarball 的管理,通常建议:
-
最好将 tarball 的原始文件解压缩到 /usr/local/src 这个目录下;
-
安装时,最好安装到 /usr/local 这个默认目录下;
-
考虑到将来的反安装,最好将每个软件单独地安装在 /usr/local 底下;
-
为了安装到单独目录的软件之 man page 加入 man path 搜寻:
如果你安装的软件放置到 /usr/local/software/,那么 man page 搜寻的设定中,可能就得要在 /etc/man_db.conf 内的写下:MANPATH_MAP /usr/local/software/bin /usr/local/software/man;这样才能使用 man 来查询该软件的在线文件。
4.4、一个简单的范例、利用 ntp 来示范
我们对这个软件的要求是这样的:
- 假设 ntp-4...tar.gz 这个文件放置在 /root 这个目录下;
- 源码请解压缩到 /usr/local/src 底下;
- 安装到 /usr/local/ntp 这个目录下。
4.4.1、解压缩下载的 tarball,并阅读 README/INSTALL 文件
[root@li local]# cd /usr/local/src
[root@li src]# tar -zxvf /root/ntp-4.2.8p3.tar.gz
ntp-4.2.8p3/ #会建立此目录
ntp-4.2.8p3/CommitLog
...
[root@li ntp-4.2.8p3]# vim INSTALL
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
...
4.4.2、检查 configure 支持参数,并实际建立 makefile 文件
[root@li ntp-4.2.8p3]# ./configure --help | less
--prefix=PREFIX install architecture-independent files in PREFIX
[/usr/local]
--enable-all-clocks + include all suitable non-PARSE clocks:
--enable-parse-clocks - include all suitable PARSE clocks:
[root@li ntp-4.2.8p3]# ./configure --prefix=/usr/local/ntp \
> --enable-all-clocks --enable-parse-clocks #开始建立 Makefile
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for gcc... gcc #也有找到 gcc 编译程序
...
config.status: creating Makefile #生成 Makefile
...
一般来说,configure 设定参数比较重要的就是那个 --prefix=/path 了,–prefix 后面接的是路径就是要安装的路径。如果没有指定 --prefix=/path 的话,通常就是预设的 /usr/local ,至于其他的参数就要参考 ./configure --help 了。整个侦测检查过程会显示在屏幕上,特别留意的是关于 gcc 的检查,还有最重要的最后需要成功建立起 Makefile 文件才行!
4.4.3、最后开始编译与安装
[root@li ntp-4.2.8p3]# make clean;make
[root@li ntp-4.2.8p3]# make check
[root@li ntp-4.2.8p3]# make install
[root@li ntp-4.2.8p3]# cd /usr/local/ntp
[root@li ntp]# ls
bin libexec sbin share
4.5、利用 patch 更新源码
所谓的 “更新源码” 常常是只有更改部分文件的小部分而已。既然如此的话,那么我们是否可以就那些被更改的文件来进行修改就可以了。也就是说,旧版本到新版本之间没有更动的文件就不要理他,仅将有修订的文件部分来处理即可。这有什么好处呢?首先,没有更动过的文件的目标文件根本就不需要重新编译,而且有更动过的文件又可以利用 make 来自动 update,如此一来,我们原先的设定(makefile 文件里面的规则)将不需要重新改写或侦测。
我们在《文件格式化处理》中提到了一个比对文件的指令,那就是 diff,这个指令可以将 “两个文件之间的差异性列出来”。那我们可以通过 diff 比对出新旧版本之间的文字差异,然后再以相关指令来将旧版本的文件更新吗?当然可以,那就是 patch 指令。
假设我们刚刚计算三角函数的程序经历了多次改版,0.1 版仅会简单输出,0.2 版的输出就会含有角度值,因此这两个版本的内容就不同:
4.5.1、测试旧版程序的功能
[root@li ~]# tar -zxvf main-0.1.tgz
main-0.1/
main-0.1/haha.c
main-0.1/Makefile
main-0.1/sin_value.c
main-0.1/main.c
main-0.1/cos_value.c
[root@li ~]# cd main-0.1
[root@li main-0.1]# make clean main
rm -f main main.o haha.o sin_value.o cos_value.o
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
[root@li main-0.1]# ./main
version 0.1
Please input your name: Li
Please enter the degree angle (ex> 90): 45
Hi, Dear Li, nice to meet you.
The Sin is: 0.71
The Cos is: 0.71
4.5.2、查阅 patch file 内容
[root@li 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
...
4.5.3、更新源码,并且重新编译
[root@li 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
[root@li main-0.1]# make clean main
rm -f main main.o haha.o sin_value.o cos_value.o
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
[root@li main-0.1]# ./main
version 0.2
Please input your name: Li
Please enter the degree angle (ex> 90): 45
Hi, Dear Li, nice to meet you.
The sin(45.000000) is: 0.71
The cos(45.000000) is: 0.71
[root@li main-0.1]# make install #直接安装
cp -a main /usr/local/bin
[root@li main-0.1]# main
version 0.2
Please input your name:
...
[root@li main-0.1]# make uninstall #卸载
rm -f /usr/local/bin/main
5、函数库管理
5.1、动态与静态函数库
这些函数库文件大多存放在 /lib,/lib64 的目录下。此外,Linux 系统里面很多的函数库其实内核就提供了,那么内核的函数库放在哪呢?就是 /lib/modules 里面。
5.1.1、静态函数库的特点
-
拓展名:(拓展名为 .a)
-
编译行为:
这类函数库在编译的时候会直接整合到执行程序当中,所以利用静态函数库编译成的文件一般会比较大。
-
独立执行的状态:
这类函数库最大的优点,就是编译成功的可执行文件可以独立运行,而不需要再向外部要求读取函数库的内容。
-
升级难易度:
在升级方面,只要函数库升级了,所有将此函数库纳入的程序都需要重新编译。
5.1.2、动态函数库的特点
-
拓展名:(拓展名为 .so)
-
编译行为:
动态函数库与静态函数库的编译行为差异挺大的。与静态函数库被整个捉到程序中不同,动态函数库在编译的时候,在程序里面只有一个 “指向” 的位置而已。也就是说,动态函数库的内容并没有被整个到执行文件中,而是当执行文件要使用到函数库的机制时,程序才会去读取函数库来使用。由于执行文件当中仅有指向动态函数库的指针,并不包含函数库的内容,所以文件会小一点。
-
独立执行的状态:
这类型的函数库所编译的程序不能独立被执行,因为当我们使用到函数库的机制时,程序才去读取函数库,所以函数库文件 “必须要存在” 才行,而且,函数库的 “所在目录也不能被改变”,因为我们的可执行文件里面仅有 “指针” 而已。
-
升级难易度:
当函数库升级时,执行文件根本不需要重新编译。
5.1.3、ldconfig 与 /etc/ld.so.conf
我们知道内存的访问速度是硬盘的好几倍,所以,如果我们将常用到的动态函数库先加载到内存当中,如此一来,当软件要取用动态函数库时,就不需要从头由硬盘读取了。那如何将动态函数库加载到高速缓存当中呢?
- 首先,我们必须要在 /etc/ld.so.conf 里面写下 “想要读入高速缓存当中的动态函数库所在的目录”;
- 接下来则是利用 ldconfig 这个执行文件将 /etc/ld.so.conf 的资料读入快存当中;
- 同时也将数据记录一份在 /etc/ld.so.cache 这个文件当中。
假设想要将 mariadb 函数库加入到快存当中,可以这样做:
[root@li ~]# ldconfig [-f conf] [-C cache]
[root@li ~]# ldconfig [-p]
选项与参数:
-f conf:那个 conf 指的是某个文件名,也就是说,使用 conf 作为 libarary 函数库的取得路径,而不以 /etc/ld.so.conf 为默认值
-C cache:那个 cache 指的是某个文件名,也就是说,使用 cache 作为快存暂存的函数库资料,而不以 /etc/ld.so.cache 资料
-p:列出目前有的函数库资料内容
[root@li main-0.1]# vim /etc/ld.so.conf.d/li.conf
/usr/lib64/mysql
[root@li main-0.1]# ldconfig #暂时不会显示任何信息
[root@li main-0.1]# ldconfig -p
在缓冲区“/etc/ld.so.cache”中找到 426 个库
p11-kit-trust.so (libc6,x86-64) => /lib64/p11-kit-trust.so
libz.so.1 (libc6,x86-64) => /lib64/libz.so.1
#函数库名 => 该函数库的实际路径
在某些时候,你可能会自行加入某些 Tarball 安装的动态函数库,而你想要让这些动态函数库的相关链接可以被读入到快存中,这个时候你可以将动态函数库所在的目录名称写入 /etc/ld.so.conf.d/文件名.conf 当中,然后执行 ldconfig 就可以了。
5.1.4、程序的动态函数库解析:ldd
如何判断某个可执行文件含有什么动态函数库呢?利用 ldd 就知道了:
[root@li ~]# ldd [-vdr] [文件名]
选项与参数:
-v:列出所有内容信息
-d:重新将资料有遗失的 link 点列出来
-r:将 ELF 有关的错误信息列出来
#1、找出 /usr/bin/passwd 这个文件的函数库信息
[root@li main-0.1]# ldd /usr/bin/passwd
linux-vdso.so.1 => (0x00007fff811c9000)
libuser.so.1 => /lib64/libuser.so.1 (0x00007f1a490a7000)
libgobject-2.0.so.0 => /lib64/libgobject-2.0.so.0 (0x00007f1a48e56000)
libglib-2.0.so.0 => /lib64/libglib-2.0.so.0 (0x00007f1a48b40000)
...
#2、找出 /lib64/libc.so.6 这个函数库的相关其他函数库
[root@li main-0.1]# ldd -v /lib64/libc.so.6
/lib64/ld-linux-x86-64.so.2 (0x00007fe83050f000)
linux-vdso.so.1 => (0x00007ffeb738b000)
Version information:
/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