Linux中程序包管理及程序的源码编译
程序的源码编译
在此之前我们思考一个问题,利用高级语言编(比如c/c++)写出来的程序是如何让计算机识别并运行的呢?我们都知道计算机只能识别二进制格式的文件,对于高级语言编写出来的程序,我们必须要有一个“翻译官”作为与计算机交流的一个中间者,将高级语言编写出来的程序“翻译”成二进制文件以便让计算机识别,这个“翻译官”称之为编译器,把“翻译”的过程称为编译。
一个程序的开发,可能要编写好多的功能,几个程序之间有时候某些需求功能是相同的,这时在编写程序的时候不可能每次都将这些功能都实现,这样只会增加代码的冗余量,而且在计算机当中我们有一句话,别人已经实现的东西,我们拿来直接用就行,没有必要事事都亲历为之。所以就出了一些库函数开发的人员,他们将一些通用的功能编写成为函数库并编译成二进制文件,为上层程序提供调用的接口,在编写程序的时候有些功能的实现就可以通过调用函数库来实现。总而言之,函数库是将底层的一些功能实现之后为上层程序提供调用接口的特殊程序。
c源码编译过程
Linux上最标准的程序语言为C,利用C语言进程程序源码的编写,然后利用编译程序gcc来编译,就可以实现一个可以执行的binary program,其流程如下:
事实上,使用类似gcc这样的编译程序进行编译的过程并不简单,对于大型的软件程序而言,并不会仅有一支程序组成,而是有一堆程序代码文件,这些文件之间存在着某种联系,可能一个子程序的执行要依赖另一个子程序的执行,也就是存在程序如何编译的问题,即编译指令,make命令的相关功能可以简化编译过程的指令。
通常每个源程序都会提供configure程序,该程序是用来侦测用户的工作环境,以及该工作环境中是否有该软件所需的其它功能,通过该程序我们可以定制软件的功能,定义其文件安装的路径,库文件的路径。当这个程序执行完成后,会生成一个Makefile文件,里面记录了源码如何编译的详细信息,make命令通过Makefile文件描述源程序之间的相互关系并自动维护编译工作。
configure侦测程序所侦测的内容:
- 是否有合适的编译程序可以编译软件的程序代码;
- 是否已经存在本软件所需的库函数,或其他依赖的软件;
- 操作系统平台是否适合本软件,包括Linux的核心版本;
- 头文件和驱动程序是否存在;
make、configure工作流程
Linux中c源码编译安装
第一步:开源程序源码的获取
-
官方自建站点上获取
-
代码托管机构获取:
SoureceForge
Github.com
code.google.com
第二步:开发工具及开发环境的准备
-
开发工具:make, gcc等
-
开发环境:开发库,头文件,glibc
通过“包组”提供开发组件:CentOS6上通过安装以下两个开发组件:
Development Tools
Server Platform Development
第三步:执行congfigure程序
该程序通过选项传递参数,指定启用特性、安装路径等。执行时会参考用户的指定以及Makefile.in文件生成makefile。最后检查依赖的外部环境。
常用选项
Options | Function |
---|---|
- -help | 获取其支持使用的选项 |
- -prefix=/PATH/TO/SOMEWHERE | 指定默认安装位置,默认为/usr.local/ |
- -sysconfdir=/PATH/TO/SOMEWHERE | 配置文件安装位置 |
第四步:make
- 根据makefile文件,构建应用程序
第五步:make install
安装后的配置
当我们指定程序的安装路径以及配置文件的安装路径后,我们要添加程序的环境变量、库文件的路径、程序的帮助手册:
- 导出二进制程序目录至PATH环境变量中:
编辑文件/etc/profile.d/NAME.sh
export PATH=/PATH/TO/BIN:$PATH
- 导出库文件路径
a. 编辑/etc/ld.so.conf.d/NAME.conf
添加新的库文件所在目录至此文件中
b. 让系统重新生成缓存
# ldconfig [-v]
- 导出头文件
头文件一般在系统上/usr/include目录下,基于链接的方式实现(将程序安装目录下的include文件链接至/usr/include)
# ln -sv
- 导出帮助手册
编辑/etc/man.config文件,添加安装的程序的man手册路径
rpm程序包管理器
rpm(RedHat Package Manager),是以一种数据库记录的方式来将你所需的软件安装到Linux系统上的一套管理机制。RPM将软件先编译,然后打包成RPM机制的包文件,通过包装好的软件里默认的数据库记录,记录了该软件安装时所依赖的其他属性软件。其功能是将编译好的应用程序的各组成文件打包成一个或几个程序包文件,从而更方便地实现程序包的安装、升级、卸载、查询校验等管理操作。不同的Linux发行版本的软件管理机制不同:
Distribution代表 | 软件管理体制 | 使用命令 | 在线升级机制(指令) |
---|---|---|---|
Red Hat/Fedora | RPM | rpm, rpmbuild | YUM(yum)/dnf |
Debian/Ubuntu | DPKG | dpkg | APT(apt-get) |
rpm包命名格式
rpm包是在源代码的基础上进行命名的。那么源代码的命名格式是什么呢?
源代码:name-VERSION.tar.gz
VERSION包含major.minor.release
major:主版本号,代表一个重大的版本分支
minor: 次版本号,在重大分支中进行一小部分的功能修改
release: 发行号,修整了BUG,或者对一小部分的代码进行修改
rpm包命名格式:
name-VERSION-release.arch.rpm
VERSION: major.minor.release
release.arch: rpm包的发行号
其中arch表示该rpm包适用的系统框架,一般rpm包命名格式的系统框架平台有:
Archetecture | Introduction |
---|---|
i386 | 32位的系统,pentum、Inter Core 2与K8系列的CUP,其中i指的是Inter兼容的CUP |
i586 | 针对586等级的计算机框架平台,包括pentum第一代MMX CPU名,AMD的K5,K6系列CPU |
i686 | 在pentum II以后的Intel系列CUP,以及K7以后等级的CUP |
x86_64 | 64位的系统,包括Intel的Core 2以上等级CPU,以及AMD的Athlon64以后的CUP |
noarch | 没有系统框架的限制,适用于任何系统框架,这类的RPM包里面应该没有binary program存在,较常出现的就是属于shell script相关的软件 |
RPM包一般分为主包和支包,主包一般是个软件的基本功能的软件包,而支包是整个软件中实现其他一些功能的包,这种方式我们称其为拆包。主包和支包的格式如下:
主包:name-VERSION-release.arch.rpm
支包:name-function-VERSION-release.arch.rpm
其中function一般有:devel, utils, libs...
rpm包内包含的内容
对于一个rpm包中每个程序包中都单独包含以下内容:
- 文件清单
- 安装或卸载时运行的脚本
RPM包是通过数据库实现一些列的管理功能,该数据库所在的路径为/var/lib/rpm/目录下,其数据库中包含了以下内容:
- 程序包的名称和版本
- 程序包的依赖关系
- 程序的功能说明
- 安装生成的各文件的文件路径及校验码信息
- 等等等
rpm包获取的途径
- 系统大型版的光盘或官方的文件服务器(或镜像站点)
http://mirrors.aliyun.com
http://mirrors.163.com
http://mirrors.sohu.com
- 项目的官方站点
- 第三方组织
EPEL
搜索引擎
http://pkgs.org
http://rpmfind.net
htto://rpm.pbone.net
- 自己动手制作rpm包
rpm命令管理程序包
前面说过rpm程序包管理器主要实现程序的安装、升级、卸载、查询和校验以及数据库维护。
rpm命令格式
rpm [OPTIONS] [PACKAGE_FILE]
常用选项
Options | Function |
---|---|
-i, - -install | 安装软件包 |
-u, - -update, -F, --freshen | 升级软件包 |
-e, - -erase | 卸载程序 |
-q, - -query | 查询软件相关的信息 |
-V, - -verify | 校验 |
- - builddb, - -initdb | 数据库维护 |
-v | verbose,详细信息 |
-vv | 更详细的输出 |
安装
安装命名格式
# rpm {-i | --install} [install-options] PACKAGE_FILE...
# rpm -ivh PACKAGE_FILE... 安装软件包常用的命令
[install-option]
Options | Function |
---|---|
-h, - -hash | hash marks输出进度条,每个#号表示2%的进度 |
- -test | 测试安装,检查并报告依赖关系及冲突消息等 |
- -nodeps | 忽略依赖关系,不建议 |
- -replacepkgs | 重新安装 |
- -noscripts | rpm包可以自带脚本,该安装选项是禁止脚本的执行。rpm包自带的脚本分为四类,以下一一详述 |
%per, - -nopre | preinstall安装过程开始之前运行的脚本 |
%post, - -nopost | postinstall安装过程完成之后运行的脚本 |
%preun, - -nopreun | preuninstall卸载过程真正开始执行之前运行的脚本 |
%psotun, - -nopostun | postuninstall卸载过程完成之后运行的脚本 |
- -nosignature | 不检查包签名信息,不检查来源合法性 |
- - nodigest | 不检查包完整性信息 |
升级
升级命名格式
# rpm {-U|--upgrade} [install-options] PACKAGE_FILE ... 对以安装的软件进行升级,如果该软件没有安装,则安装之
# rpm {-F|--freshen} [install-options] PACKAGE_FILE ... 只能对以安装的软件进行升级
常用的升级命令:
# rpm -Uvh PACKAGE_FILE...
# rpm -Fvh PACKAGE_FILE...
[install-options]
Options | Function |
---|---|
- -oldpackage | 降级 |
- -force | 强制升级 |
注意:
- 不要对内核进行升级操作,Linux支持多内核版本并存,因此直接安装新版本内核
- 如果某原程序包的配置文件安装后曾被修改过,升级时,新版本的程序提供的同一配置文件不会覆盖原有版本的配置文件,而是把新版本的配置文件重命名(FILENAME.rpmnew)后提供
卸载
软件卸载的命令格式
rpm {-e|--erase} [--allmatches] [--justdb] [--nodeps] [--noscripts] [--notriggers] [--test] PACKAGE_NAME ...
常用选项
Options | Function |
---|---|
- -allmatches | 卸载所有匹配指定名称的程序包的各版本 |
- -nodeps | 忽略依赖关系 |
- -test | 测试卸载,dry run模式 |
查询
rpm包的查询的所有操作都是基于/var/lib/rpm/目录下的数据库进行的。
软件查询的命令格式
rpm {-q|--query} [select-options] [query-options]
[select-options]
Select-options | Function |
---|---|
PACKAGE_NAME | 查询指定的程序包是否已经安装,及其版本 |
-a, - -all | 查询所有已经安装过的包 |
-f FILE | 查询指定的文件由哪个程序包安装生成 |
-p, - -package PACKAGE_NAME | 用于实现对未安装的程序包执行查询操作 |
- -whatprovides CAPABILITY | 查询指定的CAPABILITY由哪个程序包提供 |
- -whatrequires CAPABILITY | 查询指定的CAPABILITY被哪个包所依赖 |
[query-options]
Query-options | Function |
---|---|
- -changelog | 查询rpm包的chagelog |
-l, - -list | 程序安装生成的所有文件列表 |
-i, - -info | 程序包相关的信息、版本号、大小、所属的包组等 |
-c, - -configures | 查询指定的程序包提供的配置文件 |
-d, - -docfiles | 列出指定的程序包提供的文档 |
- -provides | 列出指定的程序包提供的所有的CAPABILITY |
-R, - -require | 查询指定的程序包的依赖关系 |
- -scripts | 查询程序包自带的脚本片段 |
校验
软件校验的命令格式
# rpm {-V|--verify} [select-options] [verify-options]
在软件包校验之前到获取并导入信任的包制作者的密钥。对于CentOS发行版来说导入密钥的密令如下:
# rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
验证软件包时,安装此组织签名的程序时,会自动执行验证,或者手动验证,命令如下:
# rpm -K PACKAGE_FILE
数据库重建
rpm管理器数据库重建路径:/var/lib/rpm/,通过man命令可以获取rpm数据库的信息:
CentOS 6: man rpm
CentOS 7: man rpmdb
数据库重建的命令格式
# rpm {--initdb|--rebuilddb} [-v] [--dbpath DIRECTORY] [--root DIRECTORY]
常用选项
Options | Function |
---|---|
- -initdb | 初始化数据库,当前无任何数据库可初始化创建一个新的,当前有时不执行任何操作 |
- -rebuilddb | 重新构建,通过读取当前系统上所有已经安装过的程序包进行重新创建 |
总结
由于RPM是利用预先编译并打包成为RPM文件格式后,再进行安装的一种方式,并且还能够进行数据库的记载,所有RPM有以下的优点:
- RPM内含已经编译过的程序与配置文件等数据,可以让用户免除重新编译的困扰
- RPM在被安装之前,会先检查系统的相关信息,比如操作系统的版本,可以避免文件被错误安装
- RPM文件本身提供软件版本信息、相依赖软件的名称、软件用途说明、软件所含文件等信息,便于了解软件
- RPM管理的方式视同数据库记录RPM文件的相关参数,便于升级、卸载、查询与验证
yum使用详解
上面提到过rpm包的拆包的现象,其是为了重复利用既有的软件的功能,很多软件都会以函数库的方式被抽出部分功能,以便其他软件的调用。因为这个现象,RPM包管理器就会出现所谓的软件包依赖的问题产生,所以YUM(yellow dog, Yellow Update Modifier)在线升级工具来解决软件包的依赖关系。
yum的工作原理
yum是基于C/S架构实现的,YUM服务器端存储了众多RPM包,通过分析这些软件的依赖关系,将软件内的记录信息记录下来。然后将这些信息分析后记录成软件相关性的列表,即就是包的相关的元数据文件(放置于特定的目录下:repodata)这些列表数据与软件所在的本机或网络位置称为软件仓库。当客户端有软件安装的需求时,客户端主机会主动向yum服务器的软件库网址下载清单列表,然后通过列表的数据与本机RPM数据库已存在的软件数据相比较,就能安装所需的具有相依赖的软件。整个流程如下图所示:
yum客户端的配置
yum服务器为Linux客户端提供软件仓库,那么Linux客户端怎么连接软件仓库?通过对本地和yum相关的配置文件进行配置就可以连接yum服务器了。yum客户端的配置文件:
/etc/yum.conf: 为所有仓库提供公共配置
/etc/yum.repos.d/*.repo: 为仓库的指向提供配置
仓库指向的定义:
[repositoryID]
name=Some name for this repository
baseurl=url://path/to/repository/
enable={1|0}
gpgcheck={1|0}
gpgkey=UR:
enablegroup={1|0}
failovermethod={roundrobin|priority}
默认为:roundrobin,意为随机挑选;
cost=
默认为1000
yum的repo配置文件中可用的变量:
$releasever: 当前OS的发行版的主版本号;
$arch: 平台;
$basearch: 基础平台;
$YUM0-$YUM9
yum命令的用法
yum命令的格式
# yum [options] [command] [package ...]
常用选项
Options | Function |
---|---|
- -nogpgcheck | 禁止进行gpg check |
-y | 自动回答为“yes” |
-q | 静默模式 |
- -disablerepo=repoidglob | 临时禁用此处指定的repo |
- -enbalerepo=repoidglob | 临时启用此处指定的repo |
- -noplugins | 禁用所有插件 |
command
- 显示仓库列表
repolist [all|enabled|disabled]
- 显示程序包
list
# yum list [all | glob_exp1] [glob_exp2] [...]
# yum list {available|installed|updates} [glob_exp1] [...]
- 安装程序包
install package1 [package2] [...]
reinstall package1 [package2] [...] (重新安装)
- 升级程序包
update [package1] [package2] [...]
downgrade package1 [package2] [...] (降级)
- 检查可用升级
check-update
- 卸载程序包
remove | erase package1 [package2] [...]
- 查看程序包information
info [...]
- 查看指定的特性(可以是某文件)是由哪个程序包所提供
provides | whatprovides feature1 [feature2] [...]
- 清理本地缓存
clean [ packages | metadata | expire-cache | rpmdb | plugins | all ]
- 构建缓存
makecache
- 搜索
search string1 [string2] [...]
以指定的关键字搜索程序包名及summary信息
- 查看指定包所依赖的CAPABILITY
deplist package1 [package2] [...]
- 查看yum事务历史
history [info|list|packages-list|packages-info|summary|addon-info|redo|undo|rollback|new|sync|stats]
- 安装升级本地程序包
下载到本地的rpm包也可以用yum进行安装,可以解决安装过程中的依赖关系。
localinstall rpmfile1 [rpmfile2] [...]
(maintained for legacy reasons only - use install)
localupdate rpmfile1 [rpmfile2] [...]
(maintained for legacy reasons only - use update)
- 包组管理的相关命令
* groupinstall group1 [group2] [...]
* groupupdate group1 [group2] [...]
* grouplist [hidden] [groupwildcard] [...]
* groupremove group1 [group2] [...]
* groupinfo group1 [...]
创建yum仓库
createrepo [options] <directory>