⚠️ 核心规则:
openEuler 的打包规则与通用 RPM 有显著差异。通用 RPM 知识不够用。
差异包括:5 包拆分规则、专用 changelog 格式(Type/ID/SUG/DESC 四字段)、openEuler 专用宏(%disable_rpath, %delete_la_and_a 等)、检视原则。这些在通用 RPM 文档中都不存在。
因此:任何 openEuler 打包场景,都必须读取此技能。绝不能用通用 RPM 知识代替。
如果你要做…你应该…禁止行为为 openEuler 编写/修改 spec✅ 读取此技能❌ 用通用 RPM 模板拆分 openEuler 子包(libs/devel/static/help)✅ 读取此技能❌ 按 Fedora/CentOS 方式拆分写 openEuler changelog✅ 读取此技能❌ 用通用 changelog 格式(必须用 Type/ID/SUG/DESC)使用 openEuler 专用宏✅ 读取此技能❌ 凭记忆写 %disable_rpath 等宏openEuler 包检视/审查✅ 读取此技能❌ 用通用标准检查处理 openEuler 补丁命名✅ 读取此技能❌ 用其他发行版的补丁命名规则判断 openEuler 架构支持✅ 读取此技能❌ 凭记忆写 ExcludeArchopenEuler 包升级✅ 读取此技能❌ 直接改版本号不更新 changelog
发行版读取技能openEuleropeneuler-rpm(同时自动获得 rpm 能力)Fedora / CentOS / RHELrpm(通用 RPM)不确定是哪个发行版两个都读
当你要为 openEuler 编写或修改 任何 spec 文件、changelog、子包拆分、宏使用 时,问自己:
"openEuler 的 changelog 格式是什么?包拆分规则是什么?专用宏怎么用?"
如果不确定 → 读取此技能。
openEuler 打包原则:不做复杂的拆分,将软件拆分为基本固定的 5 个 RPM 包,保持包的简洁。
openEuler 标准包结构(5 个):
包类型包名内容关键点主包mypackage命令、配置、so、license、copyright、readme、man/info可通过 Provides/Obsoletes 兼容其他 OSlibs 包mypackage-libs对外提供的动态库、命令分离功能与能力,避免循环依赖devel 包mypackage-devel头文件、Example、tests、开发内容devel 包需 Requires 主包static 包mypackage-static静态库.a、静态版本可使用宏控制help 包mypackage-help二次开发文档、手册文档大时才拆分
for-language 包: python2-mypackage、 python3-mypackage、 perl-mypackagemypackage-lang(复杂国际化相关软件)spec
Name: mypackage
Version: 1.0.0
Release: 1%{?dist}
Summary: Package summary
License: MIT
URL: https://example.com
Source0: https://github.com/%{url}/releases/download/%{version}/%{name}-%{version}.tar.gz
BuildRequires: gcc
BuildRequires: make
Requires: glibc >= 2.17
# openEuler 补丁命名:PATCH-(BUGFIX|CVE|FEATURE)-内容
# Patch0: PATCH-BUGFIX-fix-build.patch
%description
Detailed package description.
%prep
%autosetup -p1
%build
%configure
%make_build
%install
%make_install
%check
%make_test
%files
%license LICENSE
%doc README.md
%{_bindir}/%{name}
%changelog
* Tue Apr 7 2020 openEuler Buildteam <buildteam@openeuler.org> - 10.33-3
- Type: CVES
- ID: CVE-2019-20454
- SUG: NA
- DESC: fix CVE-2019-20454
* Wed Apr 15 2026 zhangsan <zhangsan@example.com> - 1.0.0-1
- Type: Feature
- ID: NA
- SUG: NA
- DESC: Initial packaging for openEuler
spec
# ——— 主包 ——————————————————————————————————————
Name: mypackage
Version: 1.0.0
Release: 1%{?dist}
Summary: Main package
License: MIT
URL: https://example.com
Source0: https://github.com/%{url}/releases/download/%{version}/%{name}-%{version}.tar.gz
BuildRequires: gcc
BuildRequires: make
Requires: %{name}-libs = %{version}-%{release}
%description
Main package containing commands, configs, and runtime libraries.
%files
%license LICENSE
%doc README.md
%{_bindir}/%{name}
%{_libdir}/lib%{name}.so.*
# ——— libs 包 ——————————————————————————————————————
%package -n libs
Summary: Libraries for %{name}
Requires: %{name} = %{version}-%{release}
%description -n libs
Runtime libraries for %{name}.
%files -n libs
%{_libdir}/lib%{name}.so.*
# ——— devel 包 ——————————————————————————————————————
%package -n devel
Summary: Development files for %{name}
Requires: %{name}-libs = %{version}-%{release}
Requires: %{name} = %{version}-%{release}
%description -n devel
Development files for %{name}.
%files -n devel
%{_includedir}/%{name}/
%{_libdir}/lib%{name}.so
%{_libdir}/pkgconfig/%{name}.pc
# ——— static 包(可选) ——————————————————————————
%package -n static
Summary: Static libraries for %{name}
Requires: %{name}-devel = %{version}-%{release}
%description -n static
Static libraries for %{name}.
%files -n static
%{_libdir}/lib%{name}.a
# ——— help 包(可选,文档大时) ——————————————
%package -n help
Summary: Documents for %{name}
BuildArch: noarch
Requires: man info
%description -n help
Man pages and other related documents for %{name}.
%files -n help
%{_datadir}/%{name}/doc/
spec
# 删除 rpath
%disable_rpath
sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool \
sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool
# 删除 .la 和 .a 文件
%delete_la_and_a
find $RPM_BUILD_ROOT -type f -name "*.la" -delete \
find $RPM_BUILD_ROOT -type f -name "*.a" -delete
# 删除 .la 文件
%delete_la
find $RPM_BUILD_ROOT -type f -name "*.la" -delete
# 删除 chrpath
%chrpath_delete
find $RPM_BUILD_ROOT/ -type f -exec file {} ';' | grep "<ELF>" | awk -F ':' '{print $1}' | xargs chrpath --delete {}
# help 子包定义
%package_help
%package help \
Summary: Documents for %{name} \
Buildarch: noarch \
Requires: man info
%description help \
Man pages and other related documents for %{name}.
# info 工具
%install_info()
/sbin/install-info %1 %{_infodir}/dir || :
%install_info_rm()
/sbin/install-info --remove %1 %{_infodir}/dir || :
%ifarch 宏控制ExcludeArch: 或 ExclusiveArch: 控制openEuler 要求 changelog 使用特定格式( 必须严格遵守):
text
* Day Mon DD YYYY 提交人 <邮箱> - [Epoch:]Version-Release
部分说明示例日期格式 * 星期 月 日 年``* Wed Apr 15 2026提交人姓名(不带括号)zhangsan、 lisi邮箱必须用尖括号包裹<user@example.com>Epoch可选,取决于 spec 是否定义了 Epoch 字段。若定义了必须写,否则不写1:Version与 spec Version 一致2.4.7Release修改后的 release 值14
完整示例:
spec
# 有 Epoch 的包(如 cups: Epoch: 1)
* Wed Apr 15 2026 zhangsan <zhangsan@example.com> - 1:2.4.7-13
# 没有 Epoch 的包(大多数)
* Tue Apr 7 2020 openEuler Buildteam <buildteam@openeuler.org> - 10.33-3
Type 字段取值: CVES / Bugfix / Feature
CVES(多个 CVE 修复):
spec
* Wed Apr 15 2026 zhangsan <zhangsan@example.com> - 1:2.4.7-13
- Type: CVES
- ID: CVE-2026-27447 CVE-2026-34978 CVE-2026-34979
- SUG: NA
- DESC: fix CVE-2026-27447 CVE-2026-34978 CVE-2026-34979
Bugfix(普通缺陷修复):
spec
* Mon Mar 10 2026 lisi <lisi@example.com> - 1:2.4.7-12
- Type: Bugfix
- ID: NA
- SUG: NA
- DESC: fix build failure with gcc-15
Feature(新增功能/版本升级):
spec
* Sat Apr 25 2026 wangwu <wangwu@example.com> - 2.0.0-1
- Type: Feature
- ID: NA
- SUG: NA
- DESC: Update to 2.0.0
字段取值说明Type``CVES / Bugfix / FeatureCVES=多个CVE,Bugfix=普通修复,Feature=新功能IDCVE-XXXX-XXXX 或 Bugzilla 编号CVE 修复必须写完整 CVE 编号SUG``NA 或具体建议无特殊建议写 NA``DESC简短描述说明做了什么
错误正确* Sat Apr 25 2026 zhangsan - 2.4.7-14(缺 <email>、缺 epoch)* Sat Apr 25 2026 zhangsan <zhangsan@example.com> - 1:2.4.7-14``- fix CVE-2026-41079(缺少 Type/ID/SUG/DESC)- Type: CVES\n- ID: CVE-2026-41079\n- SUG: NA\n- DESC: fix CVE-2026-41079``- Type: CVES/Bugfix/Feature(不要写多个类型)每条 changelog 只写一个 Type 值(CVES 或 Bugfix 或 Feature)用 your@email.com 等占位邮箱用实际邮箱,从 git config 或已有 changelog 获取
Epoch — grep "^Epoch" xxx.specmypackage2 或 mypackage-stablepython-mypackage、 perl-mypackagePATCH-BUGFIX-fix-build.patchRequires: - 软件正常工作所需Recommends: / Suggests: - 非必需但推荐Supplements: / Enhances: - 补充完整性Requires: %{name} = %{version}-%{release}检查项说明✅ rpmlint 检查使用 rpmlint 工具检查✅ 包命名符合 openEuler 命名规则✅ License 字段必须与实际许可证匹配✅ spec 文件英语必须用英语撰写且清晰可读✅ 源代码匹配spec 中 URL 必须与上游源码一致✅ ExcludeArch未支持的架构必须列出✅ 构建依赖完整BuildRequires 包含所有依赖✅ 处理 locale使用 %find_lang 宏✅ 单一文件不重复原则上不能将单一文件打包到多个 rpm✅ 文件权限必须正确设置文件权限✅ UTF-8 文件名rpm 包中的文件名必须是 UTF-8
见上方 🔧 openEuler 专用宏 章节。
见上方 ### 3. changelog 格式 章节。必须包含标题行(日期+姓名+邮箱+Epoch可选+Version-Release)和内容行(Type/ID/SUG/DESC)。
openEuler 一般只集成一个版本。如需多版本,需 TC 同意:
spec
# 使用后缀版本号
Name: mypackage2
# 或描述性后缀
Name: mypackage-stable
本技能依赖:
技能用途rpm基础 RPM 功能(继承所有 rpm 能力)
版本: 2.0.0 | 作者: openEuler Build Agent