软件包的构建,对于操作系统来说,是一件基础且非常重要的事情。当前的 Linux 操作系统生态中,不同的发行版打包方式也有不同的体现。本文整理自龙蜥大讲堂技术直播第二期,以龙蜥社区发行的龙蜥操作系统为例,来展开讲述关于 rpm 包构建的一些内容。
Linux 操作系统常见的软件包管理方式
操作系统实际上就是一个大的软件集合,成百上千个软件之间有相互调用、相互依赖等各种复杂的关联关系。所以统一的软件包格式,能够更友好地管理、定义这些复杂关系。
在 Linux 操作系统中常见的软件包格式有: 以 redhat 为代表的 rpm 系列、和以 debian 为代表的 deb 系列(如图 1)。
图1 常见两种软件包格式示例
通过图 1 可以直观的看到,以 .rpm 为扩展名的 rpm 系包,与以 .deb 为扩展名的 deb 系列包,同一套源码包使用不同的打包工具,在各自的环境中,是可以打包出这两种格式的软件包的。
- .rpm 使用 rpmbuild 系列命令,配合 spec文件打包。
- .deb 使用 dpkg 系列命令,配合 control 文件打包。
大部分开发者在 Linux 中习惯使用 tarball 来分发软件,不是也可以编译安装吗?当然可以,但是 tarball 编译安装的方式相比使用打包编译好的 rpm,或者 deb 来说,管理上就没有那么方便,操作也更复杂。所以我们希望,更多的开发者,将自己的源码 tarball 能够打包发布到操作系统软件源中,或者将源码贡献到龙蜥社区。
不管是 rpm 还是 deb。在不同 Linux 发行版里都是为了更好的管理、分发软件。
龙蜥操作系统的软件包组织形式
龙蜥操作系统基于 redhat 开发,也使用 rpm 来管理。
图2 rpm包信息示例
如图 2 左,rpm -ql 命令,可以直观的看到 systemd-libs 这个包的文件目录结构、安装路径。
如图 2 右,rpm -qi –provide 能够看到包名称、release 号、版本号等基础信息,加了—provide 参数将他自己所提供的符号、库等信息打印出来,非常详细、一目了然,命令也不复杂,所以,显然比 tarball 编译安装更方便一些。
操作系统之软件资源管理
图3 软件资源管理
对操作系统这样的基础性系统软件来说,它的功能总体分为硬件管理和软件管理。我们说软件包格式定义了软件资源管理方式,那软件资源管理是什么?软件资源又包含哪些?
如图 3,软件资源包括各种系统程序、各种应用程序、各种用户程序,也包括大量的文档材料、库函数等。每一种软件资源本身都是具有一定逻辑意义的相关信息的集合,在操作系统中它们以文件形式存储。
通俗的说就是 :这些软件对应的静态文件放在哪里,安装在哪个目录,库函数调用的路径等等?例如一些 man 手册、.so 文件等、可执行文件如何存储,这些就是软件资源管理所定义的内容 。
在某种意义上来说,在操作系统中,软件资源管理就依托于软件包来实现。我们从软件包打包的角度来体现操作系统软件资源管理。
图4 文件系统层次简图
龙蜥操作系统的文件系统层次就是一个很好的例子,图 4 中的目录分配,依据 FHS(文件系统层次)标准。已经定义好了那就按照规则开发,当然,针对 FHS 标准,各个发行版也有些差异,
FHS 仅定义了最上层 根目录及根目录下一层 的目录内容应该要放置的文件或目录数据,因此,在其他子目录层级内,就可以根据开发者诉求来配置。举个列子,centos 网络配置放在 /etc/sysconfig/network-scripts/ 目录,但suse将网络配置放在 /etc/sysconfig/network/ 下,所以有不同的目录名称,但是只要遵循 FHS 标准,差异性其实有限。
关于FHS
FHS(Filesystem Hierarchy Standard ):是 Linux 爱好者自发的组成的一个团体,主要是是对 Linux 做一些基本的要求。
FHS(http://www.pathname.com/fhs/) 的官方文件指出, 他们的主要目的是希望让使用者可以了解到已安装软件通常放置于那个目录下, 所以他们希望独立的软件开发商、操作系统制作者、以及想要维护系统的用户,都能够遵循 FHS 的标准。 也就是说,FHS 的重点在于规范每个特定的目录下应该要放置什么样子的数据而已。 这样做好处非常多,因为 Linux 操作系统就能够在既有的面貌下(目录架构不变)发展出开发者想要的独特风格。
事实上,FHS 是根据过去的经验一直在持续的改版,FHS 依据文件系统使用的频繁与否与是否允许使用者随意更动, 而将目录定义成为四种交互作用的形态,如表 1:
表1 FHS交互作用定义表
图5 系统目录功能分配简图
目录层级定义好了,该看看目录功能的分配,包括每个区域的用途、所需要的最小构成文件和目录,图 5 就包括了这些目录的功能性。
随着操作系统的不断发展,我们发现基础的 rpm,还会有些功能上的不方便,我们的发行版一般提供的软件版本只会有一个主要版本,但是这个版本有时候不能满足开发者需要,他们根据自己的实际情况可能需要更高、或更低的版本来支撑他们的开发,这就需要开发者自己再做构建,或者使用第三方的、非官方提供的软件仓库。这点让开发者浪费了很多时间。所以,新的特性,——module 来了,就是为了解决这个问题。
Module 是一个模块化包,但它不像非模块化包那样只是一个 rpm 文件,它代表一个或多个 rpm 包和元数据文件的集合,这些文件是模块构建过程的产物。一个模块的元数据可以定义多个 rpm 文件和模块,它们被捆绑并安装在主机系统上。作为 rhel8 系列发布的 rpm 包管理新方式,Anolis 同样支持和应用在了目前已经正式发布的所有Anolis8 系列操作系统中。
Module 其实是对 rpm 的再次管理,通过对主要包的不同版本的依赖关系进行细分,以module为单位,所以,module 其实是个集合,我个人通常把它理解为组。一个module组。但是官方的命名称之为“流”(stream)。
Anolis 每个版本仅提供一个受支持的主要软件版本。这意味着如果您需要自己使用不受支持的版本,则必须自己构建它或依赖某个非官方存储库。下面的例子可以更好地说明这种情况:
- 场景 1(图6)
一些用户安装来自不同 Anolis 版本的软件包,以便使用与其应用程序兼容的特定版本的数据库。但多亏了模块化,他们可能不再需要这样做了,因为在每个 Anolis 版本中都可以使用多个版本的数据库。他们所需要做的就是直接从 Anolis 存储库为他们的系统使用该数据库的特定流。
图6 postgresql module
- 场景 2(图7)
在某些情况下,用户无法将系统升级到新的 Anolis 版本,因为他们的应用程序无法在升级后的语言运行时的新版本中运行。模块化可以通过在两个 Anoils 版本中提供相同的语言版本来解决这个问题。这样,用户可以使用特定的语言流并在升级系统时保留它。当应用程序准备好使用新语言版本时,它可以在以后独立于操作系统进行升级,通过切换到不同的流(stream)。
图7 python 多版本module
总的来说,龙蜥操作系统中使用 rpm 来管理软件包,同时提供了 module 这样的特性来更友好的支撑对软件版本有不同需求的开发者和用户。
剖析rpm包构建
图8 rpm构建工具集关系图
构建工具集
- Spec文件
Spec 文件是构建 rpm 包的核心定义,使用 spec 文件配合其他构建工具即可打包rpm。
- Rpmbuild
rpmbuild是最基础的构建工具,它对 spec 文件进行解析和执行。
- Mock
根据软件依赖创建纯净构建环境构建 rpm 包的工具。
- Koji
Rpm 包编译构建系统。
咱们在前面讲到的软件资源管理,里面涉及到的文件存放位置的定义,存哪些文件内容,这些就直接在 spec 文件中体现。之前的规则就是用来帮助我们编写 spec 文件的,也就是编译规则。我们把软件编译方法、编译命令、安装路径、各种文件应该被放在哪里,一字不落的在 spec 文件中定义出来,让源码根据我们所指定的方式来构建出可执行安装文件。所以, spec 文件是 rpm 包构建的标准约束。
我们在本地构建一般直接使用 rpmbuild。通常我们为了构建出不受系统环境影响的 rpm 包,使用 mock 工具来构建,它与 rpmbuild 不同的点仅仅在于,它可以创建一个专门用于编译的纯净环境,它仅安装用于编译的那部分依赖包及必要的编译器和编译工具,所以 mock 可以用不同的软件仓库构建软件包,也就是说可以指定模拟不同的编译环境。
在龙蜥社区,我们使用 koji 来完成大量的构建,koji 是一个开源的 rpm 编译系统,源自 fedora,它使用 mock 来模拟构建环境,并能够将创建的编译任务自动调度分配到不同架构的机器,从而实现同源异构,koji 作为一个能够实现同源异构的编译构建系统,在使用rpm作为软件资源管理的操作系统研发领域,被大家广泛使用,可靠性和稳定性也非常高。
这三个工具之间是层层包含的关系,如图 8,他们最终都是对 spec 文件进行解析和执行。
Spec文件解析
图9 spec文件示例图
图 9 示例的spec文件就是 Rpm 包的灵魂 ,若要构建一个标准的 RPM 包,需要创建 .spec 文件,其中包含软件打包的全部信息。在 spec 文件中定义了很多重要的步骤、阶段,图 10 简要列出了 6 个关键阶段、及具体动作。
图10 spec文件中定义的主要阶段图示
图11 rpmbuild 工具宏定义目录图示
我们在编写spec文件时会有大量的宏定义,这些宏定义在在rpm构建过程中也非常重要,我们建议优先使用系统定义好的、或者rpm工具所定义好的一些宏定义来编写spec文件,尤其是一些构建目录,图11就是常用的一些目录所对应的宏定义示例。
以上就是龙蜥操作系统中软件包管理方式及构建方法的部分关键点。希望能帮助到对龙蜥社区感兴趣、并有志于加入国产开源操作系统开发工作的各位。当然,如果您是设计师、翻译、运营,龙蜥社区也可以成为大家施展拳脚的平台。
以下是关于龙蜥社区产品发布 SIG 组的目标及简单介绍:
- 制定、发布和维护龙蜥社区的打包规范、打包原则和依赖规范;
- 执行技术委员会的包引入和退出机制,预审软件包进入社区发布版本的申请,和运营/QA 团队共同规划支撑社区版本的发布过程;
- 维护和管理 Anolis OS 发布中的软件包基线列表;
- 维护和管理 Anolis OS SIG 组软件包;
- 协调各 SIG 组的软件包划分、依赖冲突等;
- Anolis OS 问题单处理和子各领域owner协调分配。
加入产品发布 SIG 组
欢迎更多开发者加入产品发布SIG:
网址:https://openanolis.cn/sig/SIG-Distr
邮件列表:os@lists.openanolis.cn
敲重点啦
本次直播视频回放已上线至龙蜥社区官网(首页-支持-视频),直播 PPT 获取方式:关注龙蜥社区公众号【OpenAnolis龙蜥】,后台回复【龙蜥课件】或【龙蜥视频回放】即可。
图12 龙蜥社区官网截图
—— 完 ——
加入龙蜥社群
加入微信群:添加社区助理-龙蜥社区小龙(微信:openanolis_assis),备注【龙蜥】拉你入群;加入钉钉群:扫描下方钉钉群二维码。欢迎开发者/用户加入龙蜥社区(OpenAnolis)交流,共同推进龙蜥社区的发展,一起打造一个活跃的、健康的开源操作系统生态!
关于龙蜥社区
龙蜥社区(OpenAnolis)是由企事业单位、高等院校、科研单位、非营利性组织、个人等按照自愿、平等、开源、协作的基础上组成的非盈利性开源社区。龙蜥社区成立于 2020 年 9 月,旨在构建一个开源、中立、开放的Linux上游发行版社区及创新平台。
短期目标是开发龙蜥操作系统(Anolis OS)作为 CentOS 替代版,重新构建一个兼容国际 Linux 主流厂商发行版。中长期目标是探索打造一个面向未来的操作系统,建立统一的开源操作系统生态,孵化创新开源项目,繁荣开源生态。
龙蜥OS 8.4已发布,支持 x86_64 、ARM64、LoongArch 架构,完善适配 Intel、飞腾、海光、兆芯、鲲鹏、龙芯等芯片,并提供全栈国密支持。
欢迎下载:https://openanolis.cn/download
加入我们,一起打造面向未来的开源操作系统!