构建RPM包
本章介绍通过本地或OBS构建RPM软件包的方法。详见打包规则。
打包说明
原理介绍
RPM打包的时候需要编译源码,需要把编写好的配置文件、二进制命令文件等放到合适的位置,还要根据需要对RPM的包进行测试,这些都需要先有一个“工作空间”。rpmbuild命令使用一套标准化的“工作空间”:
$ rpmdev-setuptree
rpmdev-setuptree这个命令就是安装 rpmdevtools 带来的。可以看到运行了这个命令之后,在"/root"目录(非root用户为"/home/用户名"目录)下多了一个 rpmbuild 的文件夹,目录结构如下:
$ tree rpmbuild
rpmbuild
├── BUILD
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS
内容相关的说明如下:
目录 | 宏代码 | 名称 | 功能 |
---|---|---|---|
~/rpmbuild/BUILD | %_builddir | 构建目录 | 源码包被解压至此,并在该目录的子目录完成编译 |
~/rpmbuild/RPMS | %_rpmdir | 标准 RPM 包目录 | 生成/保存二进制 RPM 包 |
~/rpmbuild/SOURCES | %_sourcedir | 源代码目录 | 保存源码包(如 .tar 包)和所有 patch 补丁 |
~/rpmbuild/SPECS | %_specdir | Spec 文件目录 | 保存 RPM 包配置(.spec)文件 |
~/rpmbuild/SRPMS | %_srcrpmdir | 源代码 RPM 包目录 | 生成/保存源码 RPM 包(SRPM) |
~/rpmbuild/BUILDROOT | %_buildrootdir | 最终安装目录 | 保存%install阶段安装的文件 |
SPECS 下是RPM包的配置文件,是RPM打包的“图纸”,这个文件会告诉rpmbuild命令如何去打包。“宏代码”这一列就可以在SPEC文件中用来代指所对应的目录,类似于编程语言中的宏或全局变量。
打包流程
打包的过程主要分为如下步骤:
- 把源代码放到%_sourcedir中。
- 进行编译,编译的过程是在%_builddir中完成的,一般情况下,源代码是压缩包格式,需要先进行解压。
- 进行“安装”,类似于预先组装软件包,把软件包应该包含的内容(比如二进制文件、配置文件、man文档等)复制到%_buildrootdir中,并按照实际安装后的目录结构组装,比如二进制命令可能会放在/usr/bin下,那么就在%_buildrootdir下也按照同样的目录结构放置。
- 做一些必要的配置,比如在实际安装前的准备,安装后的清理等等。这些都是通过配置在SPEC文件中来告诉rpmbuild命令。
- 检查软件是否正常运行。
- 生成的RPM包放置到%_rpmdir,源码包放置到%_srcrpmdir下。
在SPEC文件中,各个阶段说明如下:
打包选项
通过rpmbuild命令构建软件包。rpmbuild构建软件包一般可以通过构建SPEC文件、tar文件、source文件实现。
rpmbuild命令格式为:rpmbuild [option...]
常用的rpmbuild打包选项如表1所示。
表 1 rpmbuild打包选项
在--recompile 的基础上额外构建一个新的二进制包。在构建结束时,构建目录、源代码和 spec 文件都将被删除(就好像用了 --clean)。 | |
本地构建
本章通过一个简单的示例介绍如何在本地构建RPM软件包的方法。
搭建开发环境
前提条件
需要root权限,已设置openEuler的repo软件源。
操作步骤
用户可以直接使用DNF工具安装 rpmdevtools,其中包含 rpm-build 等命令以及相关依赖(例如make、gdb)。使用如下命令:
# dnf install rpmdevtools*
创建Hello World RPM包
这里以GNU “Hello World” 项目的打包过程作为示例,包含了典型的FOSS(Free and Open Source Software) 软件项目相关的最常用的外围组件,其中包括配置/编译/安装环境、文档、国际化等等。
下载源码
我们直接下载官方示例的源码,使用如下命令:
$ cd ~/rpmbuild/SOURCES
$ wget http://ftp.gnu.org/gnu/hello/hello-2.10.tar.gz
编辑SPEC文件
在**~/rpmbuild/SPECS**目录下新建spec文件,参考命令如下:
$ cd ~/rpmbuild/SPECS
$ vi hello.spec
在文件中写入对应内容后保存文件。文件内容示例如下,请根据实际情况修改相应字段。
Name: hello
Version: 2.10
Release: 1%{?dist}
Summary: The "Hello World" program from GNU
Summary(zh_CN): GNU "Hello World" 程序
License: GPLv3+
URL: http://ftp.gnu.org/gnu/hello
Source0: http://ftp.gnu.org/gnu/hello/%{name}-%{version}.tar.gz
BuildRequires: gettext
Requires(post): info
Requires(preun): info
%description
The "Hello World" program, done with all bells and whistles of a proper FOSS
project, including configuration, build, internationalization, help files, etc.
%description -l zh_CN
"Hello World" 程序, 包含 FOSS 项目所需的所有部分, 包括配置, 构建, 国际化, 帮助文件等.
%prep
%setup -q
%build
%configure
make %{?_smp_mflags}
%install
make install DESTDIR=%{buildroot}
%find_lang %{name}
rm -f %{buildroot}/%{_infodir}/dir
%post
/sbin/install-info %{_infodir}/%{name}.info %{_infodir}/dir || :
%preun
if [ $1 = 0 ] ; then
/sbin/install-info --delete %{_infodir}/%{name}.info %{_infodir}/dir || :
fi
%files -f %{name}.lang
%doc AUTHORS ChangeLog NEWS README THANKS TODO
%license COPYING
%{_mandir}/man1/hello.1.*
%{_infodir}/hello.info.*
%{_bindir}/hello
%changelog
* Thu Dec 26 2019 Your Name <youremail@xxx.xxx> - 2.10-1
- Update to 2.10
* Sat Dec 3 2016 Your Name <youremail@xxx.xxx> - 2.9-1
- Update to 2.9
- Name 标签是软件名,Version 标签是版本号,而 Release 标签是发布编号。
- Summary 标签是简要说明,英文的话第一个字母应大写,以避免 rpmlint 工具(打包检查工具)警告。
- License 标签说明软件包的协议版本,审查软件的 License 状态是打包者的职责,这可以通过检查源码或 LICENSE 文件,或与作者沟通来完成。
- Group 标签过去用于按照 /usr/share/doc/rpm-/GROUPS 分类软件包。目前该标记已丢弃,vim的模板还有这一条,删掉即可,不过添加该标记也不会有任何影响。%changelog 标签应包含每个 Release 所做的更改日志,尤其应包含上游的安全/漏洞补丁的说明。%changelog 条目应包含版本字符串,以避免 rpmlint 工具警告。
- 多行的部分,如 %changelog 或 %description 由指令下一行开始,空行结束。
- 一些不需要的行 (如 BuildRequires 和 Requires) 可在行首使用 ‘#’ 注释。
- %prep、%build、%install、%file暂时用默认的,未做任何修改。
构建RPM包
构建源码、二进制和包含调试信息的软件包,在spec文件所在目录执行如下命令:
$ rpmbuild -ba hello.spec
执行成功后,查看结果,使用如下命令:
$ tree ~/rpmbuild/*RPMS
/home/testUser/rpmbuild/RPMS
└── aarch64
├── hello-2.10-1.aarch64.rpm
├── hello-debuginfo-2.10-1.aarch64.rpm
└── hello-debugsource-2.10-1.aarch64.rpm
/home/testUser/rpmbuild/SRPMS
└── hello-2.10-1.src.rpm
使用OBS构建
本章介绍通过网页和osc构建RPM软件包的方法。主要包括如下两类:
- 修改已有软件包:修改已有软件包源代码,然后将修改后的源代码构建成一个RPM软件包。
- 新增软件包:从无到有全新开发一个新的软件源文件,并将新开发的源文件构建成一个RPM软件包。
OBS简介
OBS是基于openSUSE发行版的通用编译框架,用于将源码包构建为RPM软件包或Linux镜像。OBS采用自动化的分布式编译方式,支持多种Linux操作系统发行版(openEuler、SUSE、Debian等)镜像和安装包的编译,且支持在多种架构平台(x86、ARM64等)上编译。
OBS由后端和前端组成,后端实现所有核心功能,前端提供了网页应用和API,用于与后端进行交互。此外,OBS还有一个API命令行客户端osc,osc是在一个单独的存储库中开发的。
OBS使用工程组织软件包。基础的权限控制、相关的存仓库和构建目标(操作系统和架构)都可以在工程中定义。一个工程可以包含多个子工程,各个子工程可以独立配置,共同完成任务。
在线构建软件包
本章介绍通过OBS网页端在线构建RPM软件包的方法。
构建已有软件包
说明:
- 若为首次使用,请首先在OBS网页注册个人账号。
- 该方法需要拷贝修改后的代码,因此,请在执行下述操作前完成代码修改并提交到正确的代码路径。代码路径会在_service文件中指定。
使用OBS网页端,修改已有软件的源代码,并将修改后的源文件构建为RPM软件包的操作方法如下:
登录OBS界面,地址为:https://build.openeuler.org/。
单击“All Projects”进入所有工程页面。
单击需要修改的对应工程,进入该工程的详情页面,例如单击“openEuler:Mainline”。
在工程详情页面的搜索框查找需要修改的软件包,然后单击该软件包包名,进入该软件包详情页面。
单击“Branch package”,在弹出的确认页面单击“Accept”确认创建子工程,如图1所示。
单击“_service”文件进入编辑页面,修改_service内容后点击“Save”保存该文件。_service内容示例如下,其中 userCodeURL、 userCommitID 分别为用户代码托管路径、用户代码提交版本号或分支。
<services> <service name="tar_scm_kernel"> <param name="scm">git</param> <param name="url">userCodeURL</param> <param name="revision">userCommitID</param> </service> <service name="recompress"> <param name="compression">bz2</param> <param name="file">*.tar</param> </service> </services>
说明:
单击“Save”保存_service文件后,OBS服务会根据_service文件描述,从指定的url下载源码到OBS对应工程的软件目录下并替换原有文件,例如上述示例中 “openEuler:Mainline”工程的kernel目录。文件拷贝并替换完成后,OBS会自动开始构建RPM软件包。等待构建完成,并查看右侧状态栏的构建状态。
succeeded:构建成功。用户可以单击“succeeded”查看构建日志,如图2所示。
failed:构建失败。请单击“failed”查看错误日志进行问题定位后重新构建。
unresolvable:未进行构建,可能由于缺失依赖。
disabled:构建被手动关闭或正在排队构建。
excluded:构建被禁止,可能由于缺少spec文件或者spec文件中禁止了目标架构的编译。
新增软件包
使用OBS网页端,新增一个全新软件包的操作方法如下:
登录OBS界面。
根据新增软件包的依赖情况,选择合适的工程,即单击“All Projects”选择对应工程,例如“openEuler:Mainline”。
单击工程下任一软件包,进入该软件包的详情页面。
单击“Branch package”,在弹出的确认页面单击“Accept”确认创建子工程。
单击“Delete package”,删除新创建子工程中的软件包,如图3所示。
说明:
通过已有软件创建新工程是为了继承环境等依赖,而不需要实际的文件,所以这里需要把这些文件删除。单击“Create Package”,在弹出的页面输入软件包名称、标题和软件包描述,然后单击“Create”创建软件包,分别如图4、图5所示。
在页面中单击“Add file”上传spec文件和需要编译的文件(在spec文件中指定),如图6所示。
文件上传成功后,OBS会自动开始构建RPM软件包。等待构建完成,并查看右侧状态栏的构建状态。
- succeeded:构建成功。用户可以单击“succeeded”查看构建日志。
- failed:构建失败。请单击“failed”查看错误日志进行问题定位后重新构建。
- unresolvable:未进行构建,可能由于缺失依赖。
- disabled:构建被手动关闭或正在排队构建。
- excluded:构建被禁止,可能由于缺少spec文件或者spec文件中禁止了目标架构的编译。
获取软件包
RPM软件包构建完成后,通过网页端获取对应RPM软件包的方法如下:
登录OBS界面。
单击“All Projects”找到所需软件包的对应工程,例如“openEuler:Mainline”。
在工程下单击所需软件包的包名,进入该软件包详情页面。例如上述例子中的kernel页面。
选择Repositories页签进入软件包的软件仓库管理页面,在Publish Flag中通过单击选择“Enable”开启(状态由变为)对应的RPM软件包下载功能,如图7所示。
单击Repository列的构建工程名称,进入RPM软件包下载页面,单击RPM软件包右侧的“Download”即可下载对应RPM软件包,如图8所示。
使用osc构建软件包
本章介绍使用OBS的命令行工具osc创建工程并构建RPM软件包的方法。
安装并配置osc
前提条件
需要root权限,已设置openEuler的repo软件源。
操作步骤
使用root用户安装osc命令行工具及依赖。
# dnf install osc build
说明:
编译RPM软件包的过程中会依赖build。配置osc。
打开~/.oscrc,命令如下:
$ vi ~/.oscrc
在~/.oscrc中添加user和pass字段,如下所示,它们的取值 userName 和 passWord 分别是用户在OBS网页(https://build.openeuler.org/)上已经注册的账号和密码。
[general] apiurl = https://build.openeuler.org/ [https://build.openeuler.org/] user=userName pass=passWord
构建已有软件包
创建工程
通过拷贝已有工程,创建属于用户自己的子工程。例如将openEuler:Mainline工程下的zlib软件包到新分支,参考命令如下:
$ osc branch openEuler:Mainline zlib
回显如下所示,说明在用户testUser下创建了新的分支工程home:testUser:branches:openEuler:Mainline。
A working copy of the branched package can be checked out with: osc co home:testUser:branches:openEuler:Mainline/zlib
将需要修改软件包的相关配置文件(例如_service)下载到本地当前路径。其中 testUser 为~/.oscrc配置文件中配置的账户名称,请根据实际情况修改。
$ osc co home:testUser:branches:openEuler:Mainline/zlib
回显如下所示:
A home:testUser:branches:openEuler:Mainline A home:testUser:branches:openEuler:Mainline/zlib A home:testUser:branches:openEuler:Mainline/zlib/_service
进入本地子工程目录,并将软件包远程代码同步到本地。
$ cd home:testUser:branches:openEuler:Mainline/zlib $ osc up -S
回显如下所示:
A _service:tar_scm_kernel_repo:0001-Neon-Optimized-hash-chain-rebase.patch A _service:tar_scm_kernel_repo:0002-Porting-optimized-longest_match.patch A _service:tar_scm_kernel_repo:0003-arm64-specific-build-patch.patch A _service:tar_scm_kernel_repo:zlib-1.2.11-optimized-s390.patch A _service:tar_scm_kernel_repo:zlib-1.2.11.tar.xz A _service:tar_scm_kernel_repo:zlib-1.2.5-minizip-fixuncrypt.patch A _service:tar_scm_kernel_repo:zlib.spec
构建RPM包
重命名源文件,然后将重命名后的源文件添加到OBS暂存中。
$ rm -f _service;for file in `ls | grep -v .osc`;do new_file=${file##*:};mv $file $new_file;done $ osc addremove *
修改源代码和spec文件,并执行如下命令更新文件。
$ osc up
将对应软件包的所有修改同步到OBS服务器。参考命令如下,-m参数后的信息为提交记录。
$ osc ci -m "commit log"
获取当前工程的仓库名称和架构,参考命令如下:
$ osc repos home:testUser:branches:openEuler:Mainline
修改提交成功后,OBS会自动开始编译软件包。可以通过如下命令,查看对应仓库的编译日志,其中 standard_aarch64 、 aarch64 分别为查询所得仓库名称和架构。
$ osc buildlog standard_aarch64 aarch64
说明:
用户也可以通过网页端打开自己创建的对应工程,查看构建日志。
新增软件包
使用OBS的osc工具新增一个全新软件包的操作方法如下:
创建工程
根据新增软件包的依赖情况,基于合适的工程,创建属于用户自己的个人工程。例如基于 openEuler:Mainline 工程的 zlib 创建工程的参考命令如下,zlib 为工程下的任一软件包。
$ osc branch openEuler:Mainline zlib
删除创建工程时新增的无用软件包。例如删除zlib软件包的参考命令如下:
$ cd home:testUser:branches:openEuler:Mainline $ osc rm zlib $ osc commit -m "commit log"
在个人工程下创建新增的软件包。例如新增软件包 my-first-obs-package命令如下:
$ mkdir my-first-obs-package $ cd my-first-obs-package
构建RPM包
添加准备的源文件和spec文件到软件包目录。
修改源代码和spec文件,并将对应软件包的所有文件上传到OBS服务器。参考命令如下,-m 参数后的信息为提交记录。
$ cd home:testUser:branches:openEuler:Mainline $ osc add my-first-obs-package $ osc ci -m "commit log"
获取当前工程的仓库名称和架构,参考命令如下:
$ osc repos home:testUser:branches:openEuler:Mainline
修改提交成功后,OBS会自动开始编译软件包。可以通过如下命令,查看对应仓库的编译日志,其中 standard_aarch64 、 aarch64 分别为查询所得仓库名称和架构。
$ cd home:testUser:branches:openEuler:Mainline/my-first-obs-package $ osc buildlog standard_aarch64 aarch64
说明:
用户也可以通过网页端打开自己创建的对应工程,查看构建日志。
获取软件包
RPM软件包构建完成后,使用osc获取对应RPM软件包的命令如下:
$ osc getbinaries home:testUser:branches:openEuler:Mainline my-first-obs-package standard_aarch64 aarch64
命令中的各参数含义如下,请用户根据实际情况修改:
- home:testUser:branches:openEuler:Mainline :软件包所在工程名称
- my-first-obs-package :软件包名称
- standard_aarch64 :仓库名称
- aarch64 :仓库架构名称
说明:
使用osc构建的软件包也可以在网页端获取,获取方式请参见获取软件包。