构建RPM包

    RPM打包的时候需要编译源码,需要把编译好的配置文件、二进制命令文件等放到合适的位置,还要根据需要对RPM的包进行测试,这些都需要先有一个“工作空间”。rpmbuild命令使用一套标准化的“工作空间”:

    rpmdev-setuptree这个命令就是安装 rpmdevtools 带来的。可以看到运行了这个命令之后,在“/root“目录(非root用户为“/home/用户名“目录)下多了一个 rpmbuild 的文件夹,目录结构如下:

    1. rpmbuild
    2. ├── BUILD
    3. ├── RPMS
    4. ├── SOURCES
    5. ├── SPECS
    6. └── SRPMS

    内容相关的说明如下:

    SPECS 下是RPM包的配置文件,是RPM打包的“图纸”,这个文件会告诉rpmbuild命令如何去打包。“宏代码”这一列就可以在SPEC文件中用来代指所对应的目录,类似于编程语言中的宏或全局变量。

    打包流程

    打包的过程主要分为如下步骤:

    1. 把源代码放到%_sourcedir中。
    2. 进行编译,编译的过程是在%_builddir中完成的,一般情况下,源代码是压缩包格式,需要先进行解压。
    3. 进行“安装”,类似于预先组装软件包,把软件包应该包含的内容(比如二进制文件、配置文件、man文档等)复制到%_buildrootdir中,并按照实际安装后的目录结构组装,比如二进制命令可能会放在/usr/bin下,那么就在%_buildrootdir下也按照同样的目录结构放置。
    4. 做一些必要的配置,比如在实际安装前的准备,安装后的清理等等。这些都是通过配置在SPEC文件中来告诉rpmbuild命令。
    5. 检查软件是否正常运行。
    6. 生成的RPM包放置到%_rpmdir,源码包放置到%_srpmdir下。

    在SPEC文件中的,各个阶段说明如下:

    通过rpmbuild命令构建软件包。rpmbuild构建软件包一般可以通过构建SPEC文件、tar文件、source文件实现。

    rpmbuild命令格式为:rpmbuild [option…]

    常用的rpmbuild打包选项如所示。

    表 1 rpmbuild打包选项

    本章通过一个简单的示例介绍如何在本地构建RPM软件包的方法。

    搭建开发环境

    前提条件

    需要root权限,已设置openEuler的repo软件源。

    操作步骤

    用户可以直接使用DNF工具安装 rpmdevtools,其中包含 rpm-build 等命令以及相关依赖(例如make、gdb)。使用如下命令:

    1. # dnf install rpmdevtools*

    这里以GNU “Hello World” 项目的打包过程作为示例,包含了典型的FOSS(Free and Open Source Software) 软件项目相关的最常用的外围组件,其中包括配置/编译/安装环境、文档、国际化等等。

    下载源码

    我们直接下载官方例子的源码,使用如下命令:

    1. $ cd ~/rpmbuild/SOURCES
    2. $ wget http://ftp.gnu.org/gnu/hello/hello-2.10.tar.gz

    编辑SPEC文件

    1. $ cd ~/rpmbuild/SPECS
    2. $ vi hello.spec

    在文件中写入对应内容后保存文件。文件内容示例如下,请根据实际情况修改相应字段。

    1. Name: hello
    2. Version: 2.10
    3. Release: 1%{?dist}
    4. Summary: The "Hello World" program from GNU
    5. Summary(zh_CN): GNU "Hello World" 程序
    6. License: GPLv3+
    7. URL: http://ftp.gnu.org/gnu/hello
    8. Source0: http://ftp.gnu.org/gnu/hello/%{name}-%{version}.tar.gz
    9. BuildRequires: gettext
    10. Requires(post): info
    11. Requires(preun): info
    12. %description
    13. The "Hello World" program, done with all bells and whistles of a proper FOSS
    14. project, including configuration, build, internationalization, help files, etc.
    15. %description -l zh_CN
    16. "Hello World" 程序, 包含 FOSS 项目所需的所有部分, 包括配置, 构建, 国际化, 帮助文件等.
    17. %prep
    18. %setup -q
    19. %build
    20. %configure
    21. make %{?_smp_mflags}
    22. %install
    23. make install DESTDIR=%{buildroot}
    24. rm -f %{buildroot}/%{_infodir}/dir
    25. %post
    26. /sbin/install-info %{_infodir}/%{name}.info %{_infodir}/dir || :
    27. %preun
    28. if [ $1 = 0 ] ; then
    29. /sbin/install-info --delete %{_infodir}/%{name}.info %{_infodir}/dir || :
    30. fi
    31. %files -f %{name}.lang
    32. %doc AUTHORS ChangeLog NEWS README THANKS TODO
    33. %license COPYING
    34. %{_mandir}/man1/hello.1.*
    35. %{_infodir}/hello.info.*
    36. %{_bindir}/hello
    37. %changelog
    38. * Thu Dec 26 2019 Your Name <youremail@xxx.xxx> - 2.10-1
    39. - Update to 2.10
    40. * Sat Dec 3 2016 Your Name <youremail@xxx.xxx> - 2.9-1
    41. - 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文件所在目录执行如下命令:

    1. $ rpmbuild -ba hello.spec

    执行成功后,查看结果,使用如下命令:

    1. $ tree ~/rpmbuild/*RPMS
    2. /home/testUser/rpmbuild/RPMS
    3. └── aarch64
    4. ├── hello-2.10-1.aarch64.rpm
    5. ├── hello-debuginfo-2.10-1.aarch64.rpm
    6. └── hello-debugsource-2.10-1.aarch64.rpm
    7. /home/testUser/rpmbuild/SRPMS
    8. └── hello-2.10-1.src.rpm

    本章介绍通过网页和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网页端,修改已有软件的源代码,并将修改后的源文件构建为RPM软件包的操作方法如下:

    1. 登录OBS界面,地址为:。
    2. 单击“All Projects”进入所有工程页面。
    3. 单击需要修改的对应工程,进入该工程的详情页面,例如单击“openEuler:Mainline”。
    4. 在工程详情页面的搜索框查找需要修改的软件包,然后单击该软件包包名,进入该软件包详请页面。
    5. 单击“Branch package”,在弹出的确认页面单击“Accept”确认创建子工程,如图1所示。

      图 1 Branch Confirmation页面

    6. 单击“_service”文件进入编辑页面,修改_service内容后点击“Save”保存该文件。_service内容示例如下,其中 userCodeURLuserCommitID 分别为用户代码托管路径、用户代码提交版本号或分支。

      1. <services>
      2. <service name="tar_scm_kernel">
      3. <param name="scm">git</param>
      4. <param name="url">userCodeURL</param>
      5. <param name="revision">userCommitID</param>
      6. </service>
      7. <service name="recompress">
      8. <param name="compression">bz2</param>
      9. </service>
      10. </services>

      构建RPM包 - 图3 说明:
      单击“Save”保存_service文件后,OBS服务会根据_service文件描述,从指定的url下载源码到OBS对应工程的软件目录下并替换原有文件,例如上述例子中 “openEuler:Mainline”工程的kernel目录。

    7. 文件拷贝并替换完成后,OBS会自动开始构建RPM软件包。等待构建完成,并查看右侧状态栏的构建状态。

      • succeeded:构建成功。用户可以单击“succeeded”查看构建日志,如图2所示。

        图 2 succeeded的页面

      • failed:构建失败。请单击“failed”查看错误日志进行问题定位后重新构建。

      • unresolvable:未进行构建,可能由于缺失依赖。
      • disabled:构建被手动关闭或正在排队构建。
      • excluded:构建被禁止,可能由于缺少spec文件或者spec文件中禁止了目标架构的编译。

    新增软件包

    使用OBS网页端,新增一个全新软件包的操作方法如下:

    1. 登录OBS界面。
    2. 根据新增软件包的依赖情况,选择合适的工程,即单击“All Projects”选择对应工程,例如“openEuler:Mainline”。
    3. 单击工程下任一软件包,进入该软件包的详情页面。
    4. 单击“Branch package”,在弹出的确认页面单击“Accept”确认创建子工程。
    5. 单击“Delete package”,删除新创建子工程中的软件包,如所示。

      图 3 删除子工程中软件包
      构建RPM包 - 图5

    6. 单击“Create Package”,在弹出的页面输入软件包名称、标题和软件包描述,然后单击“Create”创建软件包,分别如、图5所示。

      图 4 Create Package页面

      图 5 创建软件包信息填写页面
      构建RPM包 - 图8

    7. 文件上传成功后,OBS会自动开始构建RPM软件包。等待构建完成,并查看右侧状态栏的构建状态。

      • succeed:构建成功。用户可以单击“succeeded”查看构建日志。
      • failed:构建失败。请单击“failed”查看错误日志进行问题定位后重新构建。
      • unresolvable:未进行构建,可能由于缺失依赖。
      • disabled:构建被手动关闭或正在排队构建。
      • excluded:构建被禁止,可能由于缺少spec文件或者spec文件中禁止了目标架构的编译。

    获取软件包

    RPM软件包构建完成后,通过网页端获取对应RPM软件包的方法如下:

    1. 登录OBS界面。
    2. 单击“All Projects”找到所需软件包的对应工程,例如“openEuler:Mainline”。
    3. 在工程下单击所需软件包的包名,进入该软件包详请页面。例如上述例子中的kernel页面。

    4. 选择Repositories页签进入软件包的软件仓库管理页面,在Publish Flag中通过单击选择“Enable”开启(状态由变为构建RPM包 - 图11)对应的RPM软件包下载功能,如图7所示。

      图 7 Repositories页面

    5. 单击Repository列的构建工程名称,进入RPM软件包下载页面,单击RPM软件包右侧的“Download”即可下载对应RPM软件包,如图8所示。

      图 8 RPM软件包下载页面
      构建RPM包 - 图13

    使用osc构建软件包

    本章介绍使用OBS的命令行工具osc创建工程并构建RPM软件包的方法。

    安装并配置osc

    前提条件

    需要root权限,已设置openEuler的repo软件源。

    操作步骤
    1. 使用root用户安装osc命令行工具及依赖。

      1. # dnf install osc build

      说明:
      编译RPM软件包的过程中会依赖build。

    2. 配置osc。

      1. 打开~/.oscrc,命令如下:

      2. 在~/.oscrc中添加user和pass字段,如下所示,它们的取值 userNamepassWord 分别是用户在OBS网页(https://build.openeuler.org/)上已经注册的账号和密码。

        1. [general]
        2. apiurl = https://build.openeuler.org/
        3. [https://build.openeuler.org/]
        4. user=userName
        5. pass=passWord

    构建已有软件包

    创建工程

    1. 通过拷贝已有工程,创建属于用户自己的子工程。例如将openEuler:Mainline工程下的zlib软件包到新分支,参考命令如下:

      1. $ osc branch openEuler:Mainline zlib

      回显如下所示,说明在用户testUser下创建了新的分支工程home:testUser:branches:openEuler:Mainline。

      1. A working copy of the branched package can be checked out with:
      2. osc co home:testUser:branches:openEuler:Mainline/zlib
    2. 将需要修改软件包的相关配置文件(例如_service)下载到本地当前路径。其中 testUser 为~/.oscrc配置文件中配置的账户名称,请根据实际情况修改。

      1. $ osc co home:testUser:branches:openEuler:Mainline/zlib

      回显如下所示:

      1. A home:testUser:branches:openEuler:Mainline
      2. A home:testUser:branches:openEuler:Mainline/zlib
      3. A home:testUser:branches:openEuler:Mainline/zlib/_service
    3. 进入本地子工程目录,并将软件包远程代码同步到本地。

      1. $ cd home:testUser:branches:openEuler:Mainline/zlib
      2. $ osc up -S

      回显如下所示:

      1. A _service:tar_scm_kernel_repo:0001-Neon-Optimized-hash-chain-rebase.patch
      2. A _service:tar_scm_kernel_repo:0002-Porting-optimized-longest_match.patch
      3. A _service:tar_scm_kernel_repo:0003-arm64-specific-build-patch.patch
      4. A _service:tar_scm_kernel_repo:zlib-1.2.11-optimized-s390.patch
      5. A _service:tar_scm_kernel_repo:zlib-1.2.11.tar.xz
      6. A _service:tar_scm_kernel_repo:zlib-1.2.5-minizip-fixuncrypt.patch
      7. A _service:tar_scm_kernel_repo:zlib.spec

    构建RPM包

    1. 重命名源文件,然后将重命名后的源文件添加到OBS暂存中。

      1. $ rm -f _service;for file in `ls | grep -v .osc`;do new_file=${file##*:};mv $file $new_file;done
      2. $ osc addremove *
    2. 修改源代码和spec文件,并执行如下命令更新文件。

      1. $ osc up
    3. 将对应软件包的所有修改同步到OBS服务器。参考命令如下,-m参数后的信息为提交记录。

    4. 获取当前工程的仓库名称和架构,参考命令如下:

      1. $ osc repos home:testUser:branches:openEuler:Mainline
    5. 修改提交成功后,OBS会自动开始编译软件包。可以通过如下命令,查看对应仓库的编译日志,其中 standard_aarch64aarch64 分别为查询所得仓库名称和架构。

      1. $ osc buildlog standard_aarch64 aarch64

    新增软件包

    使用OBS的osc工具新增一个全新软件包的操作方法如下:

    创建工程

    1. 根据新增软件包的依赖情况,基于合适的工程,创建属于用户自己的个人工程。例如基于 openEuler:Mainline 工程的 zlib 创建工程的参考命令如下,zlib 为工程下的任一软件包。

      1. $ osc branch openEuler:Mainline zlib
    2. 删除创建工程时新增的无用软件包。例如删除zlib软件包的参考命令如下:

      1. $ cd home:testUser:branches:openEuler:Mainline
      2. $ osc rm zlib
      3. $ osc commit -m "commit log"
    3. 在个人工程下创建新增的软件包。例如新增软件包 my-first-obs-package命令如下:

      1. $ mkdir my-first-obs-package
      2. $ cd my-first-obs-package

    构建RPM包

    1. 添加准备的源文件和spec文件到软件包目录。
    2. 修改源代码和spec文件,并将对应软件包的所有文件上传到OBS服务器。参考命令如下,-m 参数后的信息为提交记录。

      1. $ cd home:testUser:branches:openEuler:Mainline
      2. $ osc add my-first-obs-package
      3. $ osc ci -m "commit log"
    3. 获取当前工程的仓库名称和架构,参考命令如下:

      1. $ osc repos home:testUser:branches:openEuler:Mainline
    4. 修改提交成功后,OBS会自动开始编译软件包。可以通过如下命令,查看对应仓库的编译日志,其中 standard_aarch64aarch64 分别为查询所得仓库名称和架构。

      1. $ cd home:testUser:branches:openEuler:Mainline/my-first-obs-package

      构建RPM包 - 图16 说明:
      用户也可以通过网页端打开自己创建的对应工程,查看构建日志。

    获取软件包

    RPM软件包构建完成后,使用osc获取对应RPM软件包的命令如下:

    1. $ osc getbinaries home:testUser:branches:openEuler:Mainline my-first-obs-package standard_aarch64 aarch64

    命令中的各参数含义如下,请用户根据实际情况修改:

    • home:testUser:branches:openEuler:Mainline :软件包所在工程名称
    • my-first-obs-package :软件包名称
    • aarch64 :仓库架构名称