目录

305 SPEC 模版和 checklist

1 背景

本文档规定龙蜥社区 RPM Tree 组织规范和 SPEC File 写作规范。 适用范围:

  1. Anolis OS 自研的软件包;
  2. Anolis 23 及以后的发行版所有的软件包;

总体原则:

  1. 简洁、可阅读、易维护
  2. 统一龙蜥标签

修订记录

时间 版本 作者 备注
2022.2.10 v1.0 @林生 初始版本
2022.3.31 v1.1 @伊和 添加规范
2022.4.20 v1.2 @伊和 添加 epoch 版本号说明
2022.8.3 v1.3 @橘悦 新增模版和 checklist
2022.11.03 v1.4 @橘悦 增加 abi 和 api 的能力
2022.11.30 v1.5 @橘悦 修改 python 类软件的规范
2023.2.7 v1.4 @橘悦 增加 Requires 的介绍并修改 doc 包的依赖关系

2 SPEC File 写作规范

2.1 spec 基础模版

spec 基础模版,可以使用 rpmdev-newspec 命令生成。

%define anolis_release 1
#Global macro/variable 定义

Name:	     package                    
Version:     1.0.0                      
Release:     %{anolis_release}%{?dist}   
Summary:     Library providing xxx     
License:     LBPLv2+ and MIT          
URL:         https://github.com/package 
Source0:     https://github.com/package/archive/%{name}-%{version}.tar.gz
Source1:     temple.conf

Patch0:      bugfix-xxx-yyy.patch

BuildRequires:  cmake
BuildRequires:  gcc
BuildRequires:  gcc-c++

Requires:       glibc

%description
Library providing xxx and xxx.

%package devel
Summary:        Development files for %{name}
Requires:       %{name} = %{version}-%{release}

%description devel
The %{name}-devel package contains development files for %{name}.

%package -n python3-%{name}
%{?python_provide:%python_provide python3-%{name}}
Summary:        Python 3 bindings for the %{name} library.
BuildRequires:  python3-devel python3-setuptools
Requires:       %{name} = %{version}-%{release}

%description -n python3-%{name}
python 3 bindings for the %{name} library.

%package doc
Summary:        Documentation files for %{name}
Requires:       %{name} = %{EVR}
BuildArch:      noarch

%description    doc
The %{name}-doc package contains documentation files for %{name}.


%prep
%autosetup -n %{name}-%{version} -p1


%build
%configure
%make_build


%install
%make_install
# 下面两行按需添加,当前仅为样例
mkdir -p %{buildroot}/%{prefix}/%{name}
install -m 0644 -p %{SOURCE1} %{buildroot}/%{prefix}/%{name}

%check
%make test 

%files
%license COPYTRING
%{_bindir}/%{name}
%{_libdir}/%{name}.so.*

%files devel
%doc example
%{_libdir}/%{name}.so
%{_libdir}/pkgconfig/%{name}.pc
%{_includedir}/%{name}/

%files -n  python3-%{name}
%{python3_sitearch}/%{name}/

%files doc
%doc README.md AUTHORS ChangLog NEWS TODO


%changelog
- Wed Aug 03 2022 happy_orange <songnannan@linux.alibaba.com> - 1.0.0-1
- Init package from upstream

2.2 纯 python 类 spec 模版

由于 python 类软件比较多,额外对外提供 python 类软件的 spec 模版。

%define anolis_release 1
%global pypi_name package_real_name
%global debug_package %{nil}

Name:           python-%{pypi_name}
Version:        0.1.0
Release:        %{anolis_release}%{?dist}
Summary:        xxxx package for Python

License:        MIT
URL:            https://sourceforge.net/projects/%{pypi_name}
Source0:        https://sourceforge.net/%{pypi_name}/code/%{pypi_name}-%{version}.tar.gz

# python package only need to build in noarch.
BuildArch:      noarch

%description
xxxx package for Python

%package -n     python3-%{pypi_name}
Summary:        YAML 1.2 loader/dumper package for Python
BuildRequires:  python3-devel
BuildRequires:  python3-setuptools
# For tests
BuildRequires:  python3-pytest
Requires:       python3-setuptools
%{?python_provide:%python_provide python3-%{pypi_name}}

%description -n python3-%{pypi_name}
xxxx package for Python

%package -n     python3-%{pypi_name}-doc
Summary:        doc files for python3-%{pypi_name}
Requires:       python3-%{pypi_name} = %{EVR}

%description -n python3-%{pypi_name}-doc
doc files for python3-%{pypi_name}


%prep
%autosetup -n %{pypi_name}-%{version} -p1
rm -rf %{pypi_name}.egg-info


%build
%py3_build


%install
%py3_install


%check
%pytest


%files -n python3-%{pypi_name}
%license LICENSE
%{python3_sitelib}/%{pypi_name}
%{python3_sitelib}/%{pypi_name}-%{version}-*.pth
%{python3_sitelib}/%{pypi_name}-%{version}-*.egg-info

%files -n python3-%{pypi_name}-doc
%doc README.rst

%changelog
* Mon Jul 25 2022 happy_orange <songnannan@linux.alibaba.com> - 0.1.0-1
- Init pacakge from upstream

2.3 rpm 增加 abi 和 api 信息

在 anolis 23 版本中额外支持在 rpm 中分别对 so 文件和 bin 文件增加 abi 和 api 信息,下面描述如何进行使用。

3 字段介绍和标准

spec header 增加 anolis_release 的定义,从 1 开始递增  
字段 定义 是否可选
Name 包的基本名称,应与 SPEC 文件名匹配。 必选
Epoch 超级版本号。
1. 用于修正版本号,比如:0.20.0 版本 更改成 21.1
2. 初始化时, epoch 为 1,每次修正版本可以递增
3. 不可过度使用
4. 其他引用 %{version}-%{relase} 需要修改成:%{epoch}:%{version}-%{relase}
可选
Version 软件的上游版本号。正式发布的 release/tag 版本号。 必选
Release 此版本软件的发布次数。
1. 初始值为: %{anolis_release}%{?dist}
2. 每次构建递增 anolis_release
3. 构建软件新version 时 anolis_release 需要重置为 1
必选
Summary 一个简短的、单行的软件包摘要。 必选
License 被打包的软件的许可证,所有许可证的并集。 必选
URL 该软件的上游项目网站。 必选
Source0 上游源代码压缩存档的路径。这应该指向存档的可访问且可靠的存储,例如,上游页面而不是打包程序的本地存储。
如果需要,可以添加更多 SourceX 指令,每次递增编号,例如:Source1、Source2、Source3 等。
必选
Patch0 对源码进行的修改以补丁的形式。
可以添加更多 PatchX 指令,每次递增编号,例如:Patch1、Patch2、Patch3 等。
可选
BuildArch 声明该软件的构建体系结构。
1. koji 构建时默认为:x86_64 和 aarch64
2. 本地构建时会自动继承构建它的机器的体系结构
3. 如果不依赖体系结构,可以声明:BuildArch: noarch
4. 如果仅涉及一个架构,则需要将对应的架构声明:BuildArch:x86_64 或 BuildArch:aarch64
可选
ExcludeArch 声明该软件不需要的架构体系。
1. 默认不需要
2. 指定不进行编译的架构,举例:ExcludeArch: x86_64
可选
ExclusiveArch 声明该软件需要的架构体系。
1. 默认不需要
2. 指定进行编译的架构,举例:ExclusiveArch: x86_64
可选
BuildRequires 声明该软件构建所需要的全部软件包列表。
1. 有多个条目 BuildRequires 每个条目在 SPEC 文件中各占一行
2. 每个条目内不同软件使用空格隔开
3. 直接声明依赖软件的 package name,不要包含: %{_isa}、/usr/bin/xx、pkg-config(xx)、/usr/lib64/xx.so 等
必选
Requires 声明该软件运行所需要的全部软件包列表。
1. 有多个条目 Requires 每个条目在 SPEC 文件中各占一行
2. 每个条目内不同软件使用空格隔开
3. 直接声明依赖软件的 package name,不要包含: %{_isa}、/usr/bin/xx、pkg-config(xx)、/usr/lib64/xx.so 等
4. 需要声明依赖软件的版本限制时,如果是其他软件,则尽量使用 version,特殊情况增加 release;如果是本软件,则精确到 release;如果是 doc 包则使用 %{ERV} ,可以省略 epoch 的检查。
必选
spec body    
字段 定义 是否可选
%description RPM 中打包的软件的完整描述。该描述可以跨越多行并且可以分成段落。 必选
%prep 用于准备软件包构建所需要的源码。
1. 路径信息:将 tar.gz 从 ~/rpmbuild/SOURCES/ 目录下解压到 ~/rpmbuild/BUILD/ 下
2. 建议使用 %autosetup -n %{name}-%{version} -p1,可以自动按照补丁定义顺序将补丁以 -p1 形式打入
3. 允许在此处拷贝 source 文件,例如:cp %{SOURCE1} ./
4. 也允许去执行一些 shell 脚本
必选
%build 将软件包的源码进行编译阶段。
1. 路径信息:在 ~/rpmbuild/BUILD/%{name}-%{version}/ 下
2. 执行构建可以根据源码语言去选择构建方式
3. 在构建过程中是个 chroot 环境,不允许联网 download 等动作
4. 不允许随意修改 flags 等
必选
%install 将软件包编译生成的文件复制到安装目录,进行预安装动作,即模拟所有 package 安装后的环境。
1. 路径信息: ~/rpmbuild/BUILDROOT/%{name}-%{version}/
2. 复制时,文件从 ~/rpmbuild/BUILD/%{name}-%{version}/ 拷贝到 ~/rpmbuild/BUILDROOT/%{name}-%{version}/
3. 复制文件时,需要保留文件的时间戳,采用 cp -p 或 install -p
4. 操作允许直接将 SourceX 文件拷贝到安装目录允许再该阶段直接生成新文件
必选
%check 用于测试软件的命令或一系列命令。
这通常包括诸如单元测试之类的东西,阶段能开则开,如果不能开启,声明不能开启的原因。
可选
%files 定义每个 package 的文件列表,并生成对应的 .rpm。
1. 文件布局必须布局遵循 FHS ,个别情况额外声明
2. 正确设置文件权限:目录 0755,文件 0644 root root,除非出于安全考虑需要使用特定的用户或组
3. 所有安装在 ~/rpmbuild/BUILDROOT/%{name}-%{version}/ 下的文件必须全部有唯一归属
4. 不允许包含具有攻击性、歧义性、宗教性、色情性、受限制使用的文件等
5. %doc 后面可以直接跟 ~/rpmbuild/BUILD/%{name}-%{version}/ 下的说明类文档:README、ChangeLog等
6. %license 后面可以跟~/rpmbuild/BUILD/%{name}-%{version}/ 下的版权文件:copying、license 等
必选
%changelog Version不同或Release构建之间的包发生的更改的记录。
1. changlog 的格式正确,包括:日期、提交者个人信息、版本信息、描述信息等
2. Message 简洁易懂,清晰明确
必选

4 check list

下面给出 spec 的 check list,可以自行检查。

分类 要求程度 详细内容 自检结果  
宏定义 must 使用宏变量代替硬编码的目录名称    
  must 不要出现其他 OS 发行版的宏,比如:fedora、rhel、openEuler、opensuse等    
  should spec 中的宏统一使用同一种格式    
  should 可以采用 %bcond_with 和 %bcond_without 来作为开关控制特性状态    
  should 宏定义时,%global 优先于 %define    
  should 不使用 %if 0 作为判断条件    
  should 关于 python/perl/rust/golang/ruby/meson 等宏的使用,遵循各个 rpm-macros 包中的定义。    
基本信息 must spec 的第一行增加 anolis_release 的定义:%define anolis_release 1    
  must Name 和 package 命名匹配    
  must Epoch 用来修正版本号,但不得过度使用    
  must Version 为正式发布的 release/tag 版本,如果采用 rc 版本,则 version 需要定义为 xx~rc1,post 版本需要定义为:xx-post1    
  must Release 使用 %{anolis_release}%{?dist}    
  must License 与实际的许可证相匹配,不存在缺失或者扩大    
  should 如果存在多个 license,建议给多个 license 加以注释    
  must Url 真实可用,属于上游源真实地址    
  must Source0 地址支持 curl 或者 wget 方式进行直接下载    
  must Source0 对应的源码包的 md5 值与开源社区的 md5 值相同    
依赖阶段 must Buildrequires 中声明所有的第一层构建依赖,且全部使用 package name 进行声明,并要求构建依赖以 rpm 形式存在相同 OS 版本构建源里,不允许其他方式引入    
  must Requires 中声明所有的第一层运行依赖,且全部使用 package name 进行声明,并要求运行依赖以 rpm 形式存在相同 OS 版本的 yum 源里,不允许其他方式引入 (禁止安装后执行 pip install 等动作)    
  must 声明 devel 或其他子包对于主包或者 libs 的依赖时,需要增加版本限制: Requires: %{name} = %{epoch}:%{verison}-%{release}    
  should 如果对依赖软件的版本有限制,则限制到软件包的 %{version} 即可,不需限制到 %{release} ,例:BuildRequires: glibc >= 2.32    
  should 声明 buildrequires 和 requires 时,不要添加 %{?_isa}    
  should 使用 provides 对外提供功能时,和以前版本保持一致,以前有加版本号,则需要一直加下去,如果以前没有加版本号,则不要增加    
  should 使用 obsoletes 时,需要增加对应版本号    
补丁文件 must 1. Patch 和 Souce 采用序号区分自研和开源三方
2. 自研补丁序号从100、1000、10000等编号开始
   
  should Patch 序号连续,并保持一种规范    
  should 每个 patch 或 source 内有详细的修改原因和原链接地址    
架构阶段 must 至少在一种架构上构建成功,如果存在仅在部分架构上构建,可以使用 BuildArch(白名单)或者 ExcludeArch(黑名单)    
  must Anolis OS 23 不支持 32 位,不支持multilib,请去除对其他架构的支持    
  should 合理使用 ifarch 和 ifnarch 的区别    
子包划分 must 有定义 doc 子包,且定义正确(依赖、架构)    
  must python 类软件仅生成 python3 子包,不再支持 python2    
准备阶段 should 在 %prep 阶段采用 %autospec 进行自动解压并打补丁,保持 spec 简洁,如果存在与架构相关的补丁时,可以不采用 %autospec    
构建阶段 must 在 %build 阶段不允许随意修改 flags,如果要修改,需要在 spec 中备注原因    
  must 在 %build 阶段不允许随意禁用 PIE    
  should 在 %build 阶段尽量采用多线程进行编译,提高构建速度    
  should 在 %build 和 %install 阶段使用宏变量要保持一致,比如:%{buildroot} 或者 $RPM_BUILD_ROOT    
安装阶段 must 在 %install 阶段复制文件时,需要保留文件的时间戳,比如 cp -p 或者 install -p    
脚本阶段 must 如果存在动态库,则必须在 %post 和 %postun 阶段调用 %ldconfig    
  must 如果存在 service 文件时,需要在 %post、%postun 和 %preun 中对服务作出对应动作(比如:%post %systemd_post xxx.service)    
打包阶段 must %files 阶段文件系统布局遵循 FHS,个别特殊情况可以加以说明    
  must %files 阶段正确设置文件权限:目录 0755,文件 0644 root root,除非出于安全考虑需要使用特定的用户或组    
  must %files 里不允许有重复文件,一个文件仅能有一个归属    
  must %files 里不允许包含具有攻击性、歧义性、宗教性、色情性、受限制使用的文件等    
  must %doc 存放 readme、changelog、authors 等文件    
  must %license 存放 copying、license 等许可证文件    
  must 可以使用 %find_lang 宏来处理 locale 文件,进行自动打包相关文件。例:%find_lang %{name}    
  must 如果存在需要保存配置的 conf 文件,需要声明 %config(noreplace) xxx.conf    
  must 如果存在头文件,则需要放置在 devel 包内    
  must 如果有动态库,则包含后缀的库文件放在主包或者 libs 包,不包含后缀的库文件要放在 devel 中    
  must 如果有静态库,则静态库需要放置在 static 包内    
  must 公共的目录名称不可以通过 %dir 被重复定义,比如:%{_libdir}、%{_bindir}    
changlog 阶段 must changlog 的格式正确,包括:日期、提交者个人信息、版本信息、描述信息等    
  should changlog 的描述信息简洁易懂