diff --git a/TECHNOLOGY_DOCS/GITEE/302-join-os-package-build.md b/TECHNOLOGY_DOCS/GITEE/302-join-os-package-build.md
new file mode 100644
index 0000000000000000000000000000000000000000..4cd28a3c66a71ef5565a568f6d0abe93aba331d5
--- /dev/null
+++ b/TECHNOLOGY_DOCS/GITEE/302-join-os-package-build.md
@@ -0,0 +1 @@
+# 参与发行版核心软件包的构建
diff --git a/TECHNOLOGY_DOCS/GITEE/303-join-kernel-developing.md b/TECHNOLOGY_DOCS/GITEE/303-join-kernel-developing.md
new file mode 100644
index 0000000000000000000000000000000000000000..d155e9b40cfcaed96d4cc4c96fae02d47ff2ac14
--- /dev/null
+++ b/TECHNOLOGY_DOCS/GITEE/303-join-kernel-developing.md
@@ -0,0 +1 @@
+# 参与龙蜥内核的开发工作
diff --git a/TECHNOLOGY_DOCS/GITEE/304-package-introduction-and-management-principles.md b/TECHNOLOGY_DOCS/GITEE/304-package-introduction-and-management-principles.md
new file mode 100644
index 0000000000000000000000000000000000000000..5c6d46a4071a5fcb2918a75cc9d6379e6cbba014
--- /dev/null
+++ b/TECHNOLOGY_DOCS/GITEE/304-package-introduction-and-management-principles.md
@@ -0,0 +1,275 @@
+# 304 龙蜥社区软件包引入和管理原则
+
+
+## 1. 综述
+### 1.1 文档范围
+本文档涵盖:
+
+- 龙蜥社区产品发布 SIG 成员在引入或维护 RPM 软件包时需遵循的准入原则及操作流程;
+- 龙蜥社区开发者及各 SIG 成员将 RPM 引入 Anolis OS 发行版时需遵循的准入原则及操作流程。
+
+本文档不涵盖:
+
+- 源码引入原则及操作流程。源码引入到龙蜥社区是另外的话题,需要单独向龙蜥社区技术委员会申请;
+- 软件包引入规则的原理解析;
+- 软件包引入时 RPM SPEC 的编写细节。
+
+本文档的维护主体为**龙蜥社区技术委员会**,文档定稿或重大修改均需报请技术委员会审议,通过后施行。
+
+
+### 1.2 术语定义
+
+在本文描述中,软件包代码在仓库中的组织形式分为两种,分别为「source tree」和「rpm tree」。
+
+- 「**source tree**」 是指项目源码本身,在 Gitee 中以源码协作开发的方式维护,并按照软件自身研发节奏发布对应的 release,供其他社区或者爱好者进行下载使用,本文档不涉及 source tree 的组织与管理;
+- 「**rpm tree**」 是用于龙蜥社区构建发行版和 SIG 组构建产品对应的软件包的代码树,通常包含 rpm spec 文件 + 包含源码的 tarball,可用于后续构建和发布。这部分软件按照软件的成熟度分别放在对应不同的 Gitee 仓库。
+
+
+### 1.3 修订记录
+
+| **时间** | **作者** | **版本** | **描述信息** |
+| --- | --- | --- | --- |
+| 2022/08/31 | happy_orange, caspar | v1.0 | 初始版本 |
+| 2022/11/03 | happy_orange | v1.1 | 修正软件选型的原则 |
+| 2023/06/13 | happy_orange | v1.2 | 在软件包引入的基本原则中增加依赖软件的要求 |
+| 2023/08/13 | happy_orange | v1.3 | 增加软件维护责任说明、闭源软件引入规范和流程 |
+
+
+## 2. 软件包管理基础设施介绍
+
+龙蜥社区使用 Gitee 管理 Anolis OS 发行版及所有 SIG 组的软件包代码,统一放在 [https://gitee.com/openanolis]() 组织下。
+
+
+
+### 2.1 软件包在代码仓库的位置
+
+此处展示使用较为频繁的几个软件包仓库的信息:
+
+| **类别** | **仓库名称** | **仓库地址** | **仓库介绍** |
+| --- | --- | --- | --- |
+| source tree | anolis | [https://gitee.com/anolis](https://gitee.com/anolis) | 存放龙蜥社区所有项目的 source tree,本文不涉及。 |
+| rpm tree | src-anolis-os | [https://gitee.com/src-anolis-os](https://gitee.com/src-anolis-os) | 存放 Anolis OS 发行版默认 RPM 打包代码 |
+| | src-anolis-sig | [https://gitee.com/src-anolis-sig](https://gitee.com/src-anolis-sig) | 存放龙蜥社区各 SIG RPM 打包代码 |
+| | src-anolis-xxx | | 其他特殊 SIG 的 RPM 打包代码 |
+
+
+### 2.2 代码分支管理
+对于 rpm tree,每个软件仓库会通过特定分支进行进一步统一管理,确保不同的 OS 版本都有对应分支可映射;在初始化仓库时,应该建立对应版本的分支,后续将代码提交 PR 通过 review 后合入到对应分支上。
+
+| **分支名称** | **介绍** |
+| --- | --- |
+| **master**, **main** | 默认都为空,用于初始化其他发行版对应的分支,禁止使用该分支管理代码。 |
+| **aX** (X 为不带任何后缀的大版本数字),如 a7, a8, a23, a25 等 | Anolis OS X 版本的主线分支。 |
+| **aX.Y** (X 为大版本数字,Y 为对应小版本数字),如 a8.2, a8.6 等 | Anolis OS X 以前发布过的 Y 小版本对应的分支,最新的主线分支开出后,之前的主线分支则重命名为形如 aX.Y 的形式。 |
+| **aX-{module名}-stream-{版本名称}** 或
**aX.Y-{module名}-stream-{版本名称}** | Anolis OS X 或者 X.Y 版本对应的 module 的模块化版本分支。 |
+
+
+
+## 3. 软件包引入
+软件包引入由申请人发起,申请人可以是产品发布 SIG 组成员,也可以是其他 SIG 组对应软件包的 owner(以下统一称为「软件包负责人」)。
+
+### 3.1 软件包引入基本原则
+软件包负责人需明确软件包引入原则,不符合软件包引入原则的组件,不允许引入。软件包引入的原则包含三大原则:
+
+- 背景和用途:能给出引入背景和软件用途,并阐述带来的业务场景和价值
+- 软件维护责任:软件引入时,需要同时声明软件包的负责人,并承担起维护的责任,包括:修复 bugfix、修复 CVE、更新等动作
+- 引入责任规范:必须满足下面所有的引入要求,达到合规状态的软件才允许引入
+
+**程度** | **要求项** | **补充说明**
+--|--|--
+must | 软件包的内容必须遵守国家法律法规、遵守社会公序良俗 |
+must | 软件包不允许存在合规、安全问题 | 例如:无 license 或 license 尚存在争议的软件
+must | 软件包能给出明确的 License,并且属于开源软件的白名单范围内 | [license 白名单](https://gitee.com/anolis/anolis-ci-test/blob/master/utils/license_check/white_black.xlsx)
+must | 软件包在龙蜥社区的 rpm tree 中从未引入过,且软件命名规范,遵循上游社区命名方式 | 同一款软件只能存在 rpm tree 的其中一个仓,如有,后加的仓库应当合并到先有的仓库。例如:src-anolis-os 和 src-anolis-sig 不可以包含同名软件包
+must | 软件包对应的上游开源社区仍在运营,并在持续发布 release | 运营是指有代码提交、代码和入、issue解决等,代表上游社区的代码仓并没有被废弃
+must | 新引入软件需要遵循 follow upstream 模式,即 source.tag.gz 是来自上游开源社区的正式版本 | md5 值和上游相同,且选取版本为正式 release 版本
+must | 原则不允许引入其他二进制,需要从源码构建,生成对应的 rpm,如果需要引入二进制软件请参考闭源软件引入规范 | 如果对构建依赖版本多要求的(比如:依赖多个 kernel-devel 版本),则需要构建多次
+ must | 软件包所需要的全部构建依赖和运行依赖必须已经存在,如果不存在,则必须按照同等规则先引入;如果已经存在,但是需要更新版本,则需要有完整评估,不能影响其他组件。 | 核心包和成熟包必须将构建依赖和安装依赖全部引入;
对于孵化期软件引入时,要求可以酌情降低,允许通过其他方式引入构建依赖和安装依赖;
Anolis OS 8 中允许使用 epel 仓库作为孵化期软件的构建依赖和所有软件的安装依赖,Anolis OS 23 没有 epel 仓库,不允许使用
Anolis OS 8 中如果有 epel 包转自维护,需要和自维护软件同等策略维护
在引入软件如果需要引入较多软件,并且有责任人进行长期维护,可以支持新增 group 或者 repo 的方式统一处理
+ must | Anolis OS 8 中允许使用 epel 仓库 | 发行版团队的同学会定期巡逻 epel ,将 epel 的包列表与 Anolis OS 8 里面自维护软件的基线列表进行对比,如果发现 epel 高于基线列表,会发起告警并需要对应软件包的负责人进行处理。
+ must | 软件维护策略:谁引入谁负责,同时需要负责引入该软件过程中的构建依赖和安装依赖软件。 | 当前构建依赖和安装依赖的构建由发行版团队进行看护,待 abs 功能完善后,支持由 sig 的主要 maintainer 自行决定构建和发布策略,但需要同时对发行版负责
+must | 同一个背景下引入的软件应该全部放到一个仓库中,不允许跨仓库存放。 |
+must | 新引入的软件不允许对原有软件产生影响。 |比如:不能提供相同的能力,导致 repo 出现错误
+must | 软件包 owner 需要评估软件的运行平台,缺省默认全部支持,如果存在不支持的架构则需要额外声明 | 目前龙蜥社区支持列表为:x86_64、aarch64 和 loongarch64
+must | 软件引入时,优先引入 Anolis OS 23 版本,其次同步引入 Anolis OS 8 版本。 | 如果仅引入 Anolis 8,需要上 TC 会议说明背景和原因。
+
+
+
+### 3.2 闭源软件引入规范
+闭源组件主要针对不想公开源码、仅公开二进制的场景,龙蜥社区允许这部分特殊软件通过闭源方式引入,并提供 epao-nonfree 仓库作为闭源组件的 repo 源公开使用。
+闭源组件除了需要满足上述 「[3.1 软件包引入原则](#31-软件包引入基本原则)」的基本原则外,还需要满足如下规范:
+
+**程度** | **要求项** | **详细说明**
+--|--|--
+must | 确定来源方式,保证合法合规 | 来源分为两种:全自研闭源和二次开发闭源
1. 全部代码自研闭源。
全部代码自研闭源方式需要走二进制披露程序,公司内部组件请自行联系法务,如果由其他合作伙伴提供,则需要合作伙伴提供对应的许可证书和对应公司的闭源二进制发布许可证明,并向发行版同学提供许可证书;
2. 基于开源组件的二次开发闭源
基于开源组件的二次开发闭源方式,需要走公司内部二进制披露程序和开源代码扫描,查看原组件的 License 类型,并确定该 License 允许在二次开发后仅通过二进制的形式对外公开 |
+must | 不能和现有开源组件发生冲突 | 1. 软件命名不能和现有组件相同,如果相同则需要重新定义。
2. 软件版本尽量要和现有版本保持一致,如遇到特殊情况需要额外说明选择不同软件版本的原因,并保证软件维护者快速响应 CVE 和功能问题。
+must | 保证安全可靠,经过充分的测试保障 | 1. 闭源软件引入过程中需要走假构建流程,即需要经历 CI 的测试,包括:安装、卸载、abi 检测、repo 的依赖关系检测等。
2. 闭源组件的运行依赖需要参照开源组件的运行依赖要求,运行依赖建议参照开源组件方式进行引入,同为闭源组件则应该先引入依赖部分的闭源组件。
3. 闭源组件需要有明确的维护周期,并在更新的过程中持续保持兼容和安全,即在其发展路线中需要给出 bugfix 、CVE、版本更新的预期节奏和更新频率。
4. 如果是基于开源组件二次开发,在开源组件的 cve 修复之后,该闭源组件的维护者也需要快速响应,修复对应的 cve。
+
+
+
+
+### 3.3 版本选型原则
+
+龙蜥社区的软件选型主要围绕「分层分类」理论展开,根据软件包对操作系统发行版的重要程度,以及整体应用场景模块化程度,设立不同的选型原则。
+
+- 优先级上参照「分层分类」理论中的分层思想,从层级优先级高的软件包开始重点制定和维护策略;
+- 场景上参照「分层分类」理论中的分类思想,按应用场景维度分割,模块化地分批引入软件包;
+
+| **layer 序号** | **layer 名称** | **详细描述** | **选型规则** |
+| --- | --- | --- | --- |
+| layer-0 | 内核层 | 操作系统服务(内核) |
1. 跟随上游内核社区,选取社区成熟期 LTS 版本;
2. 选型需兼顾龙蜥社区 IHV 生态支持最完整的内核版本,降低硬件补丁回合成本;
3.选型需兼顾龙蜥理事成员单位向上游贡献重大特性较多的内核版本,降低特性回合成本;
4. 在一个 OS 版本内不发生大版本变更,仅采取 release 更新形式,以补丁形式合入。
|
+| layer-1 | 核心层 | 核心工具、核心库、核心服务 |
1. 跟随上游社区,选取社区稳定版本或 LTS 版本;
2. 和硬件相关的组件选型时需兼顾龙蜥社区 IHV 生态支持最完整的版本,降低硬件补丁回合成本;
3. 在一个 OS 版本内主要版本不发生大版本变更,仅采取 release 更新形式,以补丁形式合入;
4. 原则上不允许同时引入多个版本(例如 libssh, libssh2 需要选择一个版本)。
|
+| layer-2 | 系统层 | 系统工具、系统库、系统服务 |
1. 跟随上游社区,选取社区稳定版本或 LTS 版本;
2. 和硬件相关的组件选型时需兼顾龙蜥社区 IHV 生态支持最完整的版本,降低硬件补丁回合成本;
3. 在一个 OS 版本内主要版本不发生大版本变更,仅采取 release 更新形式,以补丁形式合入;
4. 原则上不允许同时引入多个版本(例如 libssh, libssh2 需要选择一个版本)。
|
+| layer-3 | 应用层 | 应用工具、应用库、应用服务 |
1. 尽量选取正式发布的最新版本;
2. 允许在一个 OS 版本内发生 version 变更,但要对影响范围整体评估清楚,必须通过**兼容性验证**;
3. 原则上不允许同时引入多个版本。
4. 自研 module 包可以采用 module 模式进行管理,保障单一大版本演进过程的应用软件兼容性 |
+| layer-4 | 应用场景 | 数据库、云原生、大数据、桌面等应用场景 |
1. 优先选择最新的,其次如果最新的版本带来不兼容(对其他软件产生影响)的问题,则可以选取次新版本;
2. 允许支持某款软件存在多个版本,但需要由需求驱动,比如:tomcat 7、tomcat 8、tomcat 9等。
3. 具体业务涉及的软件版本可以由对应负责人决策,不做过多要求。
|
+
+
+### 3.4 SPEC 规范
+详细规范请参阅 [Anolis OS 23 spec 规范](/articles/305-module-and-checklist-of-spec.md)。
下列情形需严格遵守该规范编写 SPEC 文件:
+
+- Anolis OS 23 及以后的发行版引入的所有软件包;
+- Anolis OS 7, Anolis OS 8 中新引入的软件包。
+
+下列情形可参考本规范,并不强制执行:
+- Anolis OS 7 和 Anolis OS 8 中现存的软件包。
+
+
+
+### 3.5 开源软件引入流程
+1. **引入条件审查**:软件包负责人需根据 「[3.1 软件包引入原则](#31-软件包引入基本原则)」 和 「[3.2 版本选型原则](#32-闭源软件引入规范)」所载明的规范要求,明确软件包的代码符合要求、版本选型符合规范,同时明确软件包的演进和维护路线。
+1. **提交软件包引入申请**:软件包引入涉及发行版基线变更,基线数据是通过社区的软件包集成项目 ([ospkg-list](https://gitee.com/anolis/ospkg-list)) 管理的。每一个软件包都需要通过 Pull Request 提交引入意向申请。该申请将由产品发布 SIG maintainer 负责审阅,必要时报请技术委员会成员审阅,如通过后则完成软件包基线数据的变更。
+ 1. 如果软件包在 ospkg-list 里不存在,则需要参照「[附录1.1 软件包引入申请模板](#附录-11-软件包引入申请模板)」填写一个新的 `{package}.yaml`文件。申请通过后由产品发布 SIG maintainer 创建新的仓库和对应分支;
+ 1. 如果软件包在 ospkg-list 里已经存在,则无需提交新的 `{package}.yaml`,在现有软件包数据中添加新的字段即可。申请通过后由产品发布 SIG maintainer在现有仓库创建新的分支。
+1. **本地验证**:在本地进行软件包的构建和安装验证,保证基本功能正常。
+1. **提交软件包代码**:根据 「[305 SPEC 规范](../articles/305-module-and-checklist-of-spec.md)」制作符合要求的 rpm tree 代码,并提交 PR 到对应的软件包分支中。
+1. **完成引入:** 产品发布 SIG maintainer,必要时社区技术委员会指派成员,根据 review 规范审核对应的 PR,如通过后则完成软件包整体引入。其他 review 结果包括:打回修改,拒绝等。如拒绝则需给出明确的理由。
+
+
+
+### 3.6 闭源软件引入流程
+1. **引入条件审查**:软件负责人根据「[3.2 闭源软件引入规范](#31-软件包引入基本原则)」所声明的规范要求,明确软件包的代码形式、License 符合规范,同时明确软件包的演进和维护路线。
+2. **联系法务人员,保证二进制开源合规**:软件维护者需要联系软件提供厂家的法务人员,一般要申请两个纰漏流程,包括二进制披露和开源代码合规扫描,完成流程审批。
+3. **提交软件包引入申请**:同 「[3.5 开源软件引入流程](#35-开源软件引入流程)」中的提交申请步骤相同,在 ([ospkg-list](https://gitee.com/anolis/ospkg-list)) 发起申请,按照模版填写清楚背景(包括闭源原因)、收益、维护者、维护方式、License 类型等基本信息。
+4. **建立代码仓库和分支**:发行版同学在接收 ospkg-list 申请之后,进行评估,评估通过之后,会进行建立代码仓库、建立分支操作。
+5. **提交代码**:软件维护 owner 按照 [308 闭源软件集成样例](../articles/308-example-of-epao-nonfree-package.md) 将二进制提交,并发起 pr,等待门禁 CI 的运行结果
+6. **合并代码和正式构建**: 待 maintainer 审核通过后,由发行版同学负责正式构建和发布。
+7. **用户安装使用**:待软件发布到 epao-nonfree 源之后,需要先安装 anolis-epao-nonfree-release 包,再通过 yum install 方式安装闭源组件。
+
+## 4. 软件包构建
+软件包构建从构建目的角度可以划分为两种:自验证构建和正式构建。
+
+
+
+### 4.1 自验证构建
+该过程为开发者自行在本地或模拟环境中对软件进行构建,以验证软件包本身的构建能力或产出测试包供后续测试。目前推荐的方式有两种:
+
+- 本地通过 mock 机制构建,参考《[Anolis OS 8 软件包本地构建 · 语雀](https://www.yuque.com/anolis-docs/kbase/cvy9g3?view=doc_embed)》一文;
+- 通过 Anolis Build System (ABS) 提供的个人工作空间机制进行自定义构建,可以参考[《使用ABS平台轻松胜任Anolis OS开发工作》](../articles/208-how-to-build-package-via-ABS.md) 一文的内容,进行构建。
+- 构建过程中遇到的问题参考 「[306 rpmbuild 构建指导手册](../articles/306-instruction-manual-of-rpmbuild.md)」
+
+
+### 4.2 正式构建
+正式构建的产物将会发布到对应的 Anolis OS 发行版本中,因此需要慎重操作。正式构建操作需要通过命令行操作,并且需要提前获得相关 token,请联系龙蜥社区发
+布小组 maintainer 获取相关 token。
+
+
+
+## 5. 软件包发布与变更
+
+
+### 5.1 软件包发布原则
+软件包发布指的是将通过正式构建流程生成的二进制推送到镜像 YUM repo 中。发布时会根据 ospkg-list 工具中的软件包基线数据信息,推送到对应的 YUM repo 中。
软件包经过正式构建得到 RPM 产物后,并不能直接发布,需要经过 abs 系统集成的 CI 流程后,由产品发布 SIG maintainer 执行软件包签名,之后推送 YUM repo 并生成发布单(Errata)。
+
+### 5.2 软件成熟度划分和变更流程
+
+OpenAnolis 龙蜥社区中将所有的软件划分成三个阶段:系统包、成熟包、孵化包。
+
+| 阶段名称 | 阶段介绍 | 维护主体 | 变更流程 | 补充 |
+| -------- | ------------------------------------------------------------ | ------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
+| 系统包 | Anolis OS 中 Lay0 - Lay2 对应的核心软件范围,不允许随意更改。 | 发行版团队和内核团队 | 需要 TC 会议进行评审,评审通过后,即可引入。 | |
+| 成熟包 | Anolis OS 中 Lay3 - Lay4 对应的稳定应用软件范围,由维护主体决定更新策略,支持按需更新。 | 发行版团队和龙蜥社区 sig | ospkg-list 发起转正请求,并提供转正材料,通过转正评审即可引入。 | 转正材料:软件的维护责任心和维护计划、软件的特性列表、引入软件的必要性、软件的真实使用场景和客户、软件依赖范围是否变更、 CI 检测的结果、稳定性或 CVE 相关信息等。 |
+| 孵化包 | 龙蜥社区 SIG 和 社区开发爱好者新引入的软件,由维护主体决定更新策略,支持快速迭代。 | 龙蜥社区 sig 和开发爱好者 | ospkg-list 发起软件引入申请并通过 | |
+
+### 5.3 Anolis OS 软件包仓库结构
+
+根据 「[3.1 软件包引入原则](#31-软件包引入基本原则)」 和 「[5.2 软件成熟度划分和变更流程](#52-软件成熟度划分和变更流程)」中的分层机制,OpenAnolis 龙蜥社区将所有软件按照如下 [YUM 仓库](https://mirrors.openanolis.cn/anolis/) 进行管理,分为三大类:系统包、成熟包、孵化包。
+
+| 仓库名称 | 阶段 | 仓库介绍 | 仓库分层信息 | 仓库维护 owner | ISO 包含 | 仓库默认状态 | Anolis OS 8 仓库范围 | Anolis OS 23 仓库范围 |
+| ---------------- | ------ | ----------------------------------------- | -------------------------------------------- | -------------------------- | --------- | ----------------- | -------------------- | --------------------- |
+| BaseOS | 核心包 | Anolis OS 8 中的核心软件 | Lay 0 - Lay2 的全量软件部分 Lay 3 软件 | 发行版团队 | 是 | ✅ 预装
✅ 使能 | 有 | |
+| AppStream | 成熟包 | Anolis OS 8 中的稳定的开源应用库和应用软件 | Lay 3 软件 | 发行版团队 | 是 | ✅ 预装
✅ 使能 | 有 | |
+| os | 成熟包 | Anolis OS 23 中的 iso 中的全部组件,包括核心组件和应用组件等 | Lay 0 - Lay 3 软件 | 发行版团队 | 是 | ✅ 预装
✅ 使能 | 有 |
+| PowerTools | 成熟包 | 使用广泛的应用类软件 | Lay 3 软件 | 发行版团队 | 否 | ✅ 预装
✅ 使能 | 有 | |
+| Extras | 成熟包 | Anolis OS release 组件 | Lay 3 软件 | 发行版团队 | 否 | ✅ 预装
✅ 使能 | 有 | |
+| kernel-x | 成熟包 | 存放 x 版本的 kernel 包和该内核相关的组件 | Lay 3 软件 | kernel sig + 发行版团队 | 是 | ❌ 预装
❌ 使能 | 有 | 有 |
+| Plus | 成熟包 | 通过社区 sig 运行较为成熟的软件 | Lay 3 软件 | 社区 sig | 是 | ❌ 预装
❌ 使能 | 有 | |
+| DDE | 成熟包 | DDE sig 包含的桌面相关的软件 | Lay 4 软件 | 社区 sig | 否 | ❌ 预装
❌ 使能 | 有 | |
+| HighAvailability | 成熟包 | 高性能 sig 包含的软件 | Lay 4 软件 | 社区 sig | 否 | ❌ 预装
❌ 使能 | 有 | |
+| Epao | 孵化包 | 孵化阶段的所有开源软件 | | 社区 sig 和 社区开发爱好者 | 否 | ❌ 预装
❌ 使能 | 有 | 有 |
+| Epao-nonfree | 孵化包 | 所有闭源组件 | | 社区 sig 和 社区开发爱好者 | 否 | ❌ 预装
❌ 使能 | 有 | 有 |
+
+
+
+### 5.4 软件包发布流程
+
+1. 经过正式构建得到候选发布(release candidate)包,abs 自动执行集成的 CI 流程,如未自动执行,则可在 abs 系统手工触发;
+1. 通过所有 CI 测试项,或手工确认失败项无影响后,则达到发布条件。在 [Bugzilla 平台](https://bugzilla.openanolis.cn/enter_bug.cgi?classification=Anolis%20OS) 提交软件包发布需求,模板参考「[附录 1.3 软件包发布需求模板](#附录-13-软件包发布需求模板)」;同时需填写发布单(Errata),如有多个软件包,则只需填写一个发布单即可,模板参考「附录 1.4 发布单模板」。
+1. 产品发布 SIG maintainer 确认通过发布需求,分别执行软件包签名、推送 YUM repo、生成发布单操作,如软件包达到系统包级别,则还需额外更新镜像 comps 文件。
+
+
+## 6. 软件包删除
+当某些开源软件不再符合 OpenAnolis 的规范时,需要将其从社区中删除。目前已知条件如下,持续更新:
+
+| **序号** | **分类** | **条件** |
+| --- | --- | --- |
+| 1 | 版权 | 软件的版权信息发生变更,如:license 存在争议、转商用等 |
+| 2 | 代码风险 | 源码中存在恶意代码或者安全隐患,且无法修复或上游社区反馈不修复 |
+| 3 | | 源码中存在争议风险,如:地区命名、民族习俗等 |
+| 4 | 软件演进 | 开源社区不再进行维护,持续长时间无任何提交和 bug 讨论,考虑退出 |
+| 5 | | 软件落后,存在其他同类软件替代 |
+| 6 | | 功能不再被需要,可以无影响删除 |
+
+
+## 附录1
+
+### 附录 1.1 软件包引入申请模板
+```yaml
+name: my_packages
+repository: https://gitee.com/src-anolis-sig/my_package
+summary: a short description
+rpm_owner: anolis-bot
+branches:
+- name: a8
+ repo: epao
+ maturity: rawhide
+- name: a23
+ repo: epao
+ maturity: rawhide
+```
+
+### 附录 1.2 社区重点生态应用场景
+
+- 数据库
+- 云原生
+- Web Server
+
+
+### 附录 1.3 软件包发布需求模板
+
+> 申请发布
+> 1. 背景
+> 必填: 简单描述需求背景, 有必要可以提供相关公共链接
+> 2. 用户故事
+>必填: 说明用户, 业务/应用场景, 获得结果/收益, 价值/竞争力/优势等
+> 3. 重要性/优先级
+>选填: 说明该需求的重要程度, 优先级, 紧迫性等
+> 4. 目标/计划
+>选填: 说明该需求目标版本或预期日期等
+> 5. 依赖/影响
+>选填: 说明该需求开发, 测试相关依赖信息及工作量估计
+> 6. 验收标准
+>选填: 说明交付物, 预期效果等
+
+
+### 附录 1.4 发布单模板
+>
+
diff --git a/TECHNOLOGY_DOCS/GITEE/305-module-and-checklist-of-spec.md b/TECHNOLOGY_DOCS/GITEE/305-module-and-checklist-of-spec.md
new file mode 100644
index 0000000000000000000000000000000000000000..d2a9f3106d5fdd7c1634a918b611a49d3f4c9d45
--- /dev/null
+++ b/TECHNOLOGY_DOCS/GITEE/305-module-and-checklist-of-spec.md
@@ -0,0 +1,335 @@
+# 305 SPEC 模版和 checklist
+
+## 1 背景
+本文档规定龙蜥社区 RPM Tree 组织规范和 SPEC File 写作规范。
+适用范围:
+
+1. Anolis OS 自研的软件包;
+1. Anolis 23 及以后的发行版所有的软件包;
+
+总体原则:
+
+1. 简洁、可阅读、易维护
+1. 统一龙蜥标签
+
+**修订记录**
+
+| **时间** | **版本** | **作者** | **备注** |
+| --- | --- | --- | --- |
+| 2022.2.10 | v1.0 | [@林生](https://gitee.com/forrest_ly) | 初始版本 |
+| 2022.3.31 | v1.1 | [@伊和](https://gitee.com/yueeranna) | 添加规范 |
+| 2022.4.20 | v1.2 | [@伊和](https://gitee.com/yueeranna) | 添加 epoch 版本号说明 |
+| 2022.8.3 | v1.3 | [@橘悦](https://gitee.com/happy_orange)| 新增模版和 checklist |
+| 2022.11.03 | v1.4 | [@橘悦](https://gitee.com/happy_orange)| 增加 abi 和 api 的能力 |
+| 2022.11.30 | v1.5 | [@橘悦](https://gitee.com/happy_orange)| 修改 python 类软件的规范 |
+| 2023.2.7 | v1.4 | [@橘悦](https://gitee.com/happy_orange) | 增加 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 - 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 - 0.1.0-1
+- Init pacakge from upstream
+```
+
+### 2.3 rpm 增加 abi 和 api 信息
+
+在 anolis 23 版本中额外支持在 rpm 中分别对 so 文件和 bin 文件增加 abi 和 api 信息,下面描述如何进行使用。
+
+- 使用规则:
+ - 在 %install 阶段使用 `%generate_compatibility_deps` 生成 abi/api 文件
+ - abi/api 文件默认都存在放在 `%{abidir}` 中
+ - abi 文件需要和 so 文件一起打包
+ - api 文件需要和 bin 文件一起打包
+ - 需要通过`%dir %{abidir}`的方式增加路径定义,否则会造成卸载残留
+ - 需要根据文件列表和依赖关系共同决定`%dir %{abidir}` 的定义位置,放置在依赖树中最底层的包内,常见情况如下:
+ - 如果只有单个 rpm ,则将路径定义增加到此 rpm 中;
+ - 如果有多个 rpm,但是 abi/api 文件仅存在一个 rpm 内,则将路径定义增加到此 rpm 内;
+ - 如果多个子包中都包含 abi/api 文件,并且这些子包之间是独立的,没有依赖关系,如果有主包,且都依赖主包,则将路径定义增加到主包内;
+ - 如果多个子包中都包含 abi/api 文件,并且这些子包之间是独立的,没有依赖关系,如果没有主包,则新定一个主包,并将路径定义增加到主包内;
+ - 如果多个子包中都包含 abi/api 文件,并且这些子包不是独立的,则需要找出这条依赖线中最底层的 rpm,比如 common 或者 libs,然后将路径定义增加到这个底层 rpm 中;
+- 使用样例
+ - 在 `%install` 阶段生成 abi/api 文件,注意需要将脚本调用放在最后
+ ```
+ %install
+ %make_install docdir=%{_pkgdocdir}
+ # remove unpackaged files from the buildroot
+ rm -f $RPM_BUILD_ROOT%{_libdir}/*.la
+ %generate_compatibility_deps
+ ```
+ - 打包 abi/api 文件
+ ```
+ %files
+ %dir %{abidir}
+ %{_libdir}/libasound.so.*
+ %{abidir}/libasound.so.dump
+ %{_bindir}/aserver
+ %{abidir}/aserver-option.list
+ ```
+ - 验证 abi/api 的有效性
+ ```
+ # rpm -qpl alsa-lib-1.2.7.2-2.an23.x86_64.rpm | grep dump
+ /usr/lib/compatibility/alsa-lib/libasound.so.dump
+ /usr/lib/compatibility/alsa-lib/aserver-option.list
+ ```
+ - 验证 abi/api 的 provides
+ ```
+ # rpm -qp alsa-lib-1.2.7.2-2.an23.x86_64.rpm --provides | grep abi
+ abi(alsa-lib) = 1.2.7.2
+
+ # rpm -qp alsa-lib-1.2.7.2-2.an23.x86_64.rpm --provides | grep api
+ api(alsa-lib) = 1.2.7.2
+ ```
+
+
+
+## 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**](https://yuque.antfin-inc.com/bobac/pm1qpi/xz4m02) ,个别情况额外声明
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 的描述信息简洁易懂 | |
+
diff --git a/TECHNOLOGY_DOCS/GITEE/306-instruction-manual-of-rpmbuild.md b/TECHNOLOGY_DOCS/GITEE/306-instruction-manual-of-rpmbuild.md
new file mode 100644
index 0000000000000000000000000000000000000000..4fd365691f4f0ddecd22d4f0de774c2aaa084781
--- /dev/null
+++ b/TECHNOLOGY_DOCS/GITEE/306-instruction-manual-of-rpmbuild.md
@@ -0,0 +1,1235 @@
+# 306 rpmbuild 构建指导手册
+该文章介绍了 spec 编写和构建过程中的细节和技术原理,相当于指导手册。
+## 1 宏介绍
+在软件包构建的过程中,为了防止过多使用硬编码路径和常用路径引用问题,增加了“宏”的概念。将一些常用路径或者变量值通过宏变量定义出来,并可以在整个 Anolis OS 发行版中使用。
+spec 宏目前来源于三种:系统宏、各种编程语言的宏和自定义宏
+### 1.1 系统宏
+当前社区里已经提供了一些系统宏文件,用于在软件包编译过程中使用,包括:系统路径、系统文件、编译选项、编译方式等,下面以 Anolis OS 23 的环境举例。
+目前由 rpm 软件对外提供了 spec 定义和编译过程中的宏 :`/usr/lib/rpm/macros`:
+
+```
+// 宏文件路径
+[root@localhost ~]$ ls -l /usr/lib/rpm/macros
+-rw-r--r--. 1 root root 42715 3月 23 11:05 /usr/lib/rpm/macros
+
+// 查询宏文件所属的 rpm
+[root@localhost ~]$ rpm -qf /usr/lib/rpm/macros
+rpm-4.17.0-4.an23.x86_64
+
+// 查看宏文件里定义的宏
+[root@localhost ~]$ cat /usr/lib/rpm/macros
+%_sourcedir %{_topdir}/SOURCES
+%buildroot %{_buildrootdir}/%{NAME}-%{VERSION}-%{RELEASE}.%{_arch}
+%_prefix /usr
+%_exec_prefix %{_prefix}
+%_bindir %{_exec_prefix}/bin
+%_sbindir %{_exec_prefix}/sbin
+%_libexecdir %{_exec_prefix}/libexec
+%_datadir %{_prefix}/share
+%_sysconfdir /etc
+%_sharedstatedir %{_prefix}/com
+%_localstatedir %{_prefix}/var
+%_lib lib
+%_libdir %{_exec_prefix}/%{_lib}
+%_includedir %{_prefix}/include
+%_infodir %{_datadir}/info
+%_mandir %{_datadir}/man
+.......
+```
+
+编译选项相关的基础宏:
+```
+// 宏文件路径
+[root@localhost ~]$ ls -l /usr/lib/rpm/anolis/macros
+-rw-r--r-- 1 root root 16707 Mar 16 05:14 /usr/lib/rpm/anolis/macros
+
+// 查询宏文件所属的 rpm
+[root@localhost ~]$ rpm -qf /usr/lib/rpm/anolis/macros
+system-rpm-config-23-4.an23.noarch
+
+// 查看宏文件里定义的宏
+[root@localhost ~]$ cat /usr/lib/rpm/anolis/macros
+ GCC toolchain
+%__cc_gcc gcc
+%__cxx_gcc g++
+%__cpp_gcc gcc -E
+
+# Clang toolchain
+%__cc_clang clang
+%__cxx_clang clang++
+%__cpp_clang clang-cpp
+.......
+```
+
+### 1.2 各种编程语言宏
+社区里除了系统软件,对外还提供了很多编程语言的软件,包括不限于:python、perl、go、rust、java 等。
+```
+// 查询 yum 源里提供的 macros rpm
+[root@localhost root]$ yum list | grep macros | grep an23
+cmake-rpm-macros.noarch 3.22.3-1.an23 @BaseOS
+efi-srpm-macros.noarch 5-1.an23 @BaseOS
+go-srpm-macros.noarch 3.0.15-1.an23 @BaseOS
+perl-srpm-macros.noarch 23-1.an23 @BaseOS
+pyproject-rpm-macros.noarch 1.0.0-1.an23 @BaseOS
+python-rpm-macros.noarch 3.10-23.1.an23 @BaseOS
+python-srpm-macros.noarch 3.10-23.1.an23 @BaseOS
+python3-rpm-macros.noarch 3.10-23.1.an23 @BaseOS
+rust-srpm-macros.noarch 23-1.an23 @BaseOS
+systemd-rpm-macros.noarch 250.4-1.an23 @BaseOS
+fonts-rpm-macros.noarch 1:4.0.2-1.an23 BaseOS
+fonts-rpm-macros.noarch 1:4.0.2-1.an23 koji
+fonts-srpm-macros.noarch 1:4.0.2-1.an23 BaseOS
+fonts-srpm-macros.noarch 1:4.0.2-1.an23 koji
+go-rpm-macros.x86_64 3.0.15-1.an23 AppStream
+go-rpm-macros.x86_64 3.0.15-1.an23 koji
+perl-macros.noarch 4:5.34.0-6.an23 BaseOS
+perl-macros.noarch 4:5.34.0-6.an23 koji
+python-qt5-rpm-macros.noarch 5.15.6-1.an23 koji
+qt5-rpm-macros.noarch 5.15.5-1.an23 koji
+qt5-srpm-macros.noarch 5.15.5-1.an23 koji
+texlive-bbm-macros.noarch 9:svn17224.0-1.an23 koji
+texlive-bbm-macros-doc.noarch 9:svn17224.0-1.an23 koji
+texlive-chemmacros.noarch 9:svn56983-1.an23 koji
+texlive-chemmacros-doc.noarch 9:svn56983-1.an23 koji
+texlive-circuit-macros.noarch 9:svn57308-1.an23 koji
+texlive-ling-macros.noarch 9:svn42268-1.an23 koji
+texlive-macros2e-doc.noarch 9:svn46026-1.an23 koji
+texlive-macroswap.noarch 9:svn31498.1.1-1.an23 koji
+texlive-macroswap-doc.noarch 9:svn31498.1.1-1.an23 koji
+```
+
+### 1.3 自定义宏
+允许在 spec 的头部自定义宏变量,通过 `**%global 宏变量名称 宏变量值** `格式定义宏,在下文通过 `**%{宏变量名称}**`引用,样例:
+
+```
+// % %global 宏变量名称 宏变量值
+%global pname ruamel-yaml
+
+// 使用宏变量
+Name: python-%{pname}
+
+// 拓展:
+spec 中允许对基本信息字段进行宏拓展使用,比如上述第 5 行的 Name 字段,可以采用 %{name} 进行引用
+```
+
+### 1.4 查询已有宏
+
+- 通过 `rpm -E %{xxx}`来查询 xxx 宏的实际内容
+ ```
+ # 查询 %{_bindir} 的值
+ [root@localhost ~]$ rpm -E %{_bindir}
+ /usr/bin
+ ```
+
+- %bcond_with 和 %bcond_without 介绍
+
+ 通常在开启或者关闭某个特性时,可以使用这两个变量。使用方式为:
+ ```
+ // 定义
+ %bcond_without testsuite
+
+ // 使用
+ %check
+ %if %{with testsuite}
+ .....
+ %endif
+ ```
+
+ - %bcond_without xx :是指不需要去除 xx 特性,即等价于开启 xx 特性,在定义该宏之后,会在内部自动生成一个全局变量 with_xx ,并对 with_xx 进行赋值 1,即 with_xx =1。这样在使用该变量时,通过with 方法读取 with_xx 变量的值,从而生成判断结果。
+ - %bcond_with xx:即关闭 xx 特性,其生成的全局变量 with_xx = 0,从而 with 的判断为假。
+
+## 2 rpmbuild 详解
+### 2.1 代码准备
+在准备将某款软件进行构建时,需要准备的文件至少为:spec + source.tar.gz,spec文件用于指导生成rpm,source.tar.gz 为源码,有时额外还会存在一些其他 source 文件或者 patch 文件。
+下面以 lld 软件作为样例讲解:
+```
+[root@localhost ~]$ ll ~/rpmbuild/SOURCES/
+total 1492
+-rw-r--r-- 1 root root 1900 Aug 4 02:10 0001-PATCH-lld-CMake-Check-for-gtest-headers-even-if-lit..patch
+-rw-r--r-- 1 root root 20288 Aug 4 02:10 0002-PATCH-lld-Import-compact_unwind_encoding.h-from-libu.patch
+-rw-r--r-- 1 root root 699 Aug 4 02:10 lit.lld-test.cfg.py
+-rw-r--r-- 1 root root 1473868 Aug 4 02:10 lld-13.0.1.src.tar.xz
+-rw-r--r-- 1 root root 566 Aug 4 02:10 lld-13.0.1.src.tar.xz.sig
+-rw-r--r-- 1 root root 6129 Aug 4 02:10 lld.spec
+-rw-r--r-- 1 root root 488 Aug 4 02:10 README.md
+-rw-r--r-- 1 root root 1362 Aug 4 02:10 run-lit-tests
+-rw-r--r-- 1 root root 2222 Aug 4 02:10 tstellar-gpg-key.asc
+```
+### 2.2 %prep 解压
+#### 2.2.1 文件准备
+%prep 阶段的作用就是准备构建所需要的文件,这里一般包括:
+ - 解压 source.tag.gz
+ - 打补丁动作
+ - 拷贝 source 文件、或者脚本等
+#### 2.2.2 解压方式
+解压是针对 Souce0 定义的 source.tar.gz 进行解压,解压有两种方式:%setup 和 %autosetup,这两种方式的详细介绍如下,可以根据自己软件需要进行选择使用:
+
+ - `%setup -q -n %{name}-%{version}`
+ - -q :代表采用安静模式进行解压
+ - -n :声明解压之后的源码目录名称,一般为 %{name}-%{version},但是可以手动对 source.tag.gz 进行解压后查看具体目录名称
+ - 当存在补丁时,需要将每个补丁进行声明打入,并可以针对不同的补丁指定不同的忽略目录,且可以自己指定补丁打入的顺序
+ - 在存在与架构相关的补丁时,比较方便,指定对应的架构才将补丁打入用
+
+ ```
+ ......
+ Patch0: xxxxxx.patch // 一层路径
+ Patch1: xxxxxx.patch // 两层路径
+ Patch2: xxxxxx.patch // 一层路径
+ Patch3: xxxxxx.patch // 零层路径
+ Patch4: x86_64-xxx.patch // 仅 x86_64 架构打入,一层路径
+ ......
+
+ %prep
+ %setup -q -n %{name}-%{version}
+ %patch0 -p1
+ %patch1 -p2
+ %patch3 -p0
+ %patch2 -p1
+ %ifarch x86_64
+ %patch4 -p1
+ %endif
+ ```
+
+ - `%autosetup -n %{name}-%{version} -p1`
+ - -n : 同上
+ - -p1:按照 spec 内 Patch 的定义顺序全部打入,并且全部采用 -p1 忽略一层目录的结构打入补丁。
+ - 当存在与架构相关的补丁时,不再使用
+ - 代码举例:
+
+ ```
+ .....
+ Patch0: xxxxxx.patch // 一层路径
+ Patch1: xxxxxx.patch // 一层路径
+ ......
+
+ %prep
+ %autosetup -q -n %{name}-%{version} -p1
+ ```
+
+ - 此处也可以执行其他动作,比如解压其他 source.tar.gz 、拷贝其他 source 文件等
+
+ ```
+ %prep
+ %autosetup -q -n %{name}-%{version} -p1
+ tar -xvf %{SOURCE1} ./
+ ```
+
+#### 2.2.3 路径信息
+
+- 本地编译时,源码一般存放在 `~/rpmbuild/SOURCES/`下, spec 文件在 `~/rpmbuild/SOURCES/` 或者 `~/rpmbuild/SPECS/`下都可,但是 koji 编译时,spec 文件在`~/rpmbuild/SPECS/`下
+- 在执行完 %prep 后,源码将被解压到 `~/rpmbuild/BUILD` 下
+- 通常可以使用 `rpmbuild -bp ~/rpmbuild/SOURCES/xxx.spec --nodeps`来查看解压结果,并且可以在日志中看到 patch 是有被打入的。
+
+ ```
+ [root@localhost ~]$ rpmbuild -bp ~/rpmbuild/SOURCES/lld.spec --nodeps
+ Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.cJtqDn
+ + umask 022
+ + cd /root/rpmbuild/BUILD
+ + /usr/lib/rpm/redhat/gpgverify --keyring=/root/rpmbuild/SOURCES/tstellar-gpg-key.asc --signature=/root/rpmbuild/SOURCES/lld-13.0.1.src.tar.xz.sig --data=/root/rpmbuild/SOURCES/lld-13.0.1.src.tar.xz
+ gpgv: Signature made Wed Feb 2 09:58:19 2022 EST
+ gpgv: using RSA key 474E22316ABF4785A88C6E8EA2C794A986419D8A
+ gpgv: Good signature from "Tom Stellard "
+ + cd /root/rpmbuild/BUILD
+ + rm -rf lld-13.0.1.src
+ + /usr/bin/xz -dc /root/rpmbuild/SOURCES/lld-13.0.1.src.tar.xz
+ + /usr/bin/tar -xof -
+ + STATUS=0
+ + '[' 0 -ne 0 ']'
+ + cd lld-13.0.1.src
+ + /usr/bin/chmod -Rf a+rX,u+w,g-w,o-w .
+ + /usr/bin/cat /root/rpmbuild/SOURCES/0001-PATCH-lld-CMake-Check-for-gtest-headers-even-if-lit..patch
+ + /usr/bin/patch -p2 -s --fuzz=0 --no-backup-if-mismatch
+ + /usr/bin/cat /root/rpmbuild/SOURCES/0002-PATCH-lld-Import-compact_unwind_encoding.h-from-libu.patch
+ + /usr/bin/patch -p2 -s --fuzz=0 --no-backup-if-mismatch
+ + exit 0
+ [root@localhost SOURCES]$ ll ~/rpmbuild/BUILD/
+ total 8
+ drwxr-xr-x 16 root root 4096 Aug 4 02:44 lld-13.0.1.src
+ ```
+
+### 2.3 %build 构建
+#### 2.3.1 编译器
+软件包使用的编译器由软件源码的语言来决定,现在比较流行的编译器种类比较多:gcc、clang 等。但是,软件包应该默认使用 gcc 作为编译器(对于 gcc 支持的所有语言),如果上游不支持使用 gcc 构建,则应该使用clang。
+但是,如果有很好的技术原因,打包者可以选择不使用默认编译器。不使用默认编译器的有效技术原因示例包括但不限于:
+
+- 默认编译器无法正确构建包。
+- 打包者需要禁用编译器功能(例如 LTO),以便默认编译器正确编译他们的包。
+- 默认编译器需要更长的时间来构建包。
+- 默认编译器缺少一个对包有利于的特性。
+- 选择使用非默认编译器的打包人员应在spec文件的注释中记录做出这一决定的原因。
+
+#### 2.3.2 编译 Flags
+
+用于构建包的编译器必须遵守系统 rpm 默认配置中设置的编译器 Flags。
+对于 C、C++ 和 Fortran 代码, %optflags 宏包含这些 flags。不鼓励为了性能优化而覆盖这些 flags(例如,-O3 代替 -O2)。如果可以提供 benchmark 结果,显示这段代码有明显的性能优化,那可以根据具体情况重新审视。如果有充分的理由,可以添加、重写或过滤这些flags;这样做的理由必须记录在 spec 文件中。
+通常允许使用某些与安全相关的flags,这些flags可能会略微降低性能,但是相对某些程序增加的安全性收益来说是值得的。
+默认情况下,启用PIE,如果要在spec中禁用,可以通过:
+```
+%undefine _hardened_build
+```
+但是以下场景不允许禁用PIE:
+
+- 软件包长期运行,意味着它很可能会启动并继续运行,直到机器重新启动,而不是按需启动,并在空闲时退出。
+- 软件包具有 suid 二进制文件或具有功能的二进制文件。
+- 软件包以 root 身份运行。
+
+#### 2.3.3 并行构建
+
+在编译过程中,可以指定多线程来加快构建速度。一般是在 make 后增加 -jxx,来表示用 xx 线程编译,同时可以直接使用 `%make_build` 进行编译,默认增加多线程。
+```
+[root@localhost SOURCES]$ rpm -E %{make_build}
+/usr/bin/make -j96
+```
+其他语言也都有对应的编译方式,比如 %cmake_build,%meson_build、%cargo_build 等,这些宏都自带了多线程。
+
+```
+[root@localhost ~]$ rpm -E %{cmake_build}
+/usr/bin/cmake --build "anolis-linux-build" -j96 --verbose
+
+[root@localhost ~]$ rpm -E %{cargo_build}
+/usr/bin/env CARGO_HOME=.cargo RUSTC_BOOTSTRAP=1 RUSTFLAGS='-Copt-level=3 -Cdebuginfo=2 -Ccodegen-units=1 -Clink-arg=-Wl,-z,relro -Clink-arg=-Wl,-z,now --cap-lints=warn' /usr/bin/cargo build -j96 -Z avoid-dev-deps --release
+```
+
+#### 2.3.4 构建目录
+在构建阶段,所有的构建动作都在路径:`~/rpmbuild/BUILD/%{name}-%{version}/`下,并且编译生成的文件也只允许生成在当前目录下,不允许对构建环境的系统目录进行操作,比如:`/tmp`、` /home`。
+
+#### 2.3.5 网络访问
+构建系统中的软件包是在一个模拟的 chroot 中构建的,无法访问互联网。包不能依赖或使用不是它们自己创建的任何网络资源。
+
+### 2.4 %install 预安装
+在完成构建后,需要对构建结果进行一个安装,这里准备了一个预安装的环境,用于模拟安装环境。
+
+#### 2.4.1 安装路径
+预安装的绝对路径为:`~/rpmbuild/BUILDROOT/%{name}-%{version}/`,一般可以使用 `%{buildroot} `进行引用。
+
+#### 2.4.2 怎么安装
+一般该阶段执行的动作都是将文件从**构建目录**拷贝到**安装目录**,举例:
+```
+install:
+ @echo "BEGIN INSTALL xxx"
+ mkdir -p $(BINDIR)
+
+install -m 0755 $(PKGPATH)/xxx $(BINDIR)
+```
+#### 2.4.3 其他动作汇总
+```
+%install
+%make_install
+
+// 创建路径
+mkdir -p %{buildroot}/%{_datadir}/%{name}
+
+// 复制 source 文件到安装目录
+install -p -m 0644 %{SOURCE1} %{buildroot}/%{_datadir}/%{name}/
+
+// 新生成文件到安装目录
+pushd %{buildroot}/%{_datadir}/%{name}/
+touch xxx
+popd
+
+// 删除多余文件
+rm -f %{buildroot}/%{_libdir}/%{name}/*.{a,la,so}
+```
+
+### 2.5 %files 打包
+
+spec 中通过 %files 来规定 package 包含哪些文件,对于 %install 里的文件要求如下:
+
+ - 每个文件只能有一个归属,不可以同时属于两个 package
+ - 所有在 %install 阶段安装到 %{buildroot} 下的文件,必须全部都有归属
+ - 当然如果想忽略某个 %{buildroot} 下的文件,可以使用 %exclude 进行去除,但不推荐这种方式,建议直接在 %install 阶段里删除对应文件
+ - 不允许声明不在 %{buildroot} 下的文件
+
+#### 2.5.1 文件系统布局
+文件系统层次结构标准(FHS),定义了 Linux 操作系统中的主要目录及目录内容。[FHS](https://refspecs.linuxfoundation.org/fhs.shtml ) 由 Linux 基金会维护。主要介绍了每个结构的含义和应该存放的文件。
+
+| / | 第一层次结构的根,整个文件系统层次结构的根目录 |
+| --- | --- |
+| /bin | 需要在单用户模式可用的必要命令(可执行文件);面向所有用户,例如:cat、ls、cp |
+| /sbin | 必要的系统二进制文件,面向管理员用户。例如:init、ip、mount |
+| /boot | 引导程序文件,系统引导文件,如内核 vmlinuz、ramfs 文件,initrd,以及 grub(bootloader);通常划分单独的分区 |
+| /dev | 必要设备, 例如:/dev/null,/dev/sda |
+| /etc | 系统范围内的配置文件 |
+| /home | 用户的家目录,包含保存的文件、个人设置等
每一个用户的家目录通常默认为 /home/$USER |
+| /lib | /bin/ 和 /sbin/中二进制文件必要的库文件。 |
+| /lib64 | /bin/ 和 /sbin/中二进制文件必要的库文件(64位)。 |
+| /lost+found | 系统断电时候临时保存的,默认为空 |
+| /media | 可移除媒体(如CD-ROM)的挂载点 |
+| /mnt | 临时挂载的文件系统 |
+| /opt | 备用目录,第三方程序的安装目录,默认为空 |
+| /proc | 虚拟文件系统,将内核与进程状态归档为文本文件。例如:uptime、 network。在 Linux 中,对应 Procfs 格式挂载。
/proc/meminfo:查看内存信息
/proc/cpuinfo:cpu信息
/proc/mounts:挂载信息
/proc/loadavg:负载信息
/proc/partitions:磁盘信息 |
+| /root | 超级用户的家目录 |
+| /selinux | selinux 相关的安全策略等信息存储的位置,默认为空 |
+| /srv | 为服务提供数据存放位置,默认为空 |
+| /sys | 虚拟文件系统,用于输出当前系统上硬件设备相关信息的虚拟文件系统 |
+| /tmp | 临时文件(参见 /var/tmp),在系统重启时目录中文件不会被保留。 |
+| /usr | 用于存储只读用户数据的第二层次; 包含绝大多数的(多)用户工具和应用程序。 |
+| /var | 频繁发生变化的文件——在正常运行的系统中其内容不断变化的文件,如日志,脱机文件和临时电子邮件文件。
/var/cache:应用程序缓存数据目录
/var/lib:应用程序状态信息数据
/var/local:专用于/usr/local下的应用程序存储可变数据
/var/log:日志目录文件
/var/log/messages系统日志
/var/log/secure 安全日志 SSH连接日志
/var/lock:锁文件
/var/run:与运行中进程相关的数据;通常存放进程的PID文件
/var/spool:应用程序数据池
/var/tmp:保存系统两次重启之间产生的临时数据 |
+
+但是也存在一些例外:
+
+- 不允许在/或者/usr下创建目录
+- FHS 没有定义 libexecdir,rpm 的宏中包含了 %{_libexecdir} 的定义,Libexecdir(也就是系统上的 /usr/libexec)只应该用作可执行程序的目录,这些可执行程序是由其他程序运行的而不是由用户运行的。
+- /run 目录是 tmpfs,系统服务应该存放在该目录,/var/run 是 /run 的软链接。
+- /srv、/usr/local、/home/$USER 目录下禁止存放文件或目录
+- 有限使用 /opt,/etc/opt,/var/opt,如果想要安装文件到上述目录,最好是创建子目录,比如 /opt/anolis/。
+- Anolis OS 23 系统中将 / 下的几个目录与 /usr 下的几个目录合并
+
+ ```
+ /bin
+ /usr/bin %{_bindir}
+ /sbin
+ /usr/sbin %{_sbindir}
+ /lib64 or /lib
+ /usr/lib64 or /usr/lib %{_libdir}
+ /lib
+ /usr/lib %{_prefix}/lib
+ ```
+
+- 举例:用户发现 /bin/sh 与 /usr/bin/sh 是同一个文件,如果一个rpm指定
+
+ ```
+ %files
+ /bin/sh
+ ```
+ 可以满足 /bin/sh 的文件依赖,但是无法满足 /usr/bin/sh 的文件依赖。所以 %files 中需要列出历史记录中放置在 /bin,/sbin,/lib 或者 /lib64 的内容;历史记录中放在 /usr/bin,/usr/sbin 目录下的内容以 %{_bindir}、%{_sbindir} 在 %files 中列出。如果对于程序放在哪个目录不清楚,可以通过虚拟的 provides 来列出备用路径,如:
+ ```
+ .......
+ Provides: %{_sbindir}/ifconfig
+ .......
+
+ %files
+ /sbin/ifconfig
+ ```
+
+#### 2.5.2 rpath注意事项
+
+- 不允许使用 rpath。
+
+ rpath 是在链接二进制文件时使用硬编码指定特定的库路径(使用 -rpath 或 -R 标志)。动态链接器和加载器 (ld.so) 会解析可执行文件对共享库的依赖关系并加载所需的内容。但是,当使用 -rpath 或 -R 时,位置信息会被硬编码到二进制文件中,并在执行开始时由 ld.so 检查。由于 Linux 动态链接器通常比硬编码路径更智能,因此我们通常不允许使用 rpath。
+ rpmdevtools 软件包中包含一个名为 check-rpaths 的工具,并且在 ~/.rpmmacros 中配置 `%__arch_install_post` 宏:
+
+ ```
+ %__arch_install_post \
+ /usr/lib/rpm/check-rpaths \
+ /usr/lib/rpm/check-buildroot
+ ```
+
+ 运行 check-rpaths 后,可以得到错误提示:
+
+ ```
+ ERROR 0001: file '/usr/bin/xapian-tcpsrv' contains a standard rpath '/usr/lib64' in [/usr/lib64]
+ ```
+
+ 必须删除由 check-rpaths 标记的任何 rpath。
+
+- 允许内部库文件使用 rpath
+
+ 有些程序在安装内部库时,通常不会安装在系目录,这些内部库仅被包内程序使用,并不会给外部程序使用,这种情况戏下,可以使用 rpath 来查找这些库。
+ ```
+ # Internal libraries for myapp are present in:
+ %{_libdir}/myapp/
+ %{_libdir}/myapp/libmyapp.so.0.3.4
+ %{_libdir}/myapp/libmyapp.so
+
+ # myapp has an rpath to %{_libdir}/myapp/
+ readelf -d /usr/bin/myapp | grep RPATH
+ 0x0000000f (RPATH) Library rpath: [/usr/lib/myapp]
+ ```
+
+- rpath 替代方案
+
+ 通常,使用 rpath 是因为二进制文件在非标准位置(标准位置是/lib、/usr/lib、/lib64、/usr/lib64)寻找库。如果需要将库存储在非标准位置(例如 /usr/lib/foo/),则应该在 /etc/ld.so.conf.d/ 中包含一个自定义配置文件。
+ 例如,如果我将 libfoo 库放在 /usr/lib/foo 中,我就需要在 /etc/ld.so.conf.d/ 中创建一个名为“foo.conf”的文件,文件内容为 '/usr/lib/foo' 。
+ ```
+ %install
+ ......
+ mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/ld.so.conf.d
+ echo "%{_libdir}/foo" > %{buildroot}%{_sysconfdir}/ld.so.conf.d/%{name}.conf
+ ......
+ ```
+
+ - 删除 rpath:
+ - 如果应用程序包含 configure,configure添加--disable-rpath
+ - 如果应用程序使用 libtool,请将以下几行添加到 %configure 之后的spec中
+
+ ```
+ %configure
+ 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
+ ```
+
+ - 直接修改代码或者Makefile来删除 -rpath 或者-R
+ - 作为最后的手段,有一个名为 chrpath 的包。安装此软件包后,对包含 rpath 的文件运行 chrpath --delete。需要在 spec 中增加 `BuildRequires: chrpath` 后,运行:
+
+ ```
+ chrpath --delete $RPM_BUILD_ROOT%{_bindir}/xapian-tcpsrv
+ ```
+
+#### 2.5.3 权限和属主
+所有的目录和文件必须设置正确的权限。
+
+- 每个文件都应该归 root:root 所有,除非出于安全考虑需要更具体的用户或组。
+- 目录默认权限为 0755 ,文件默认权限为 0644 ,除非有特定需求
+- 所有文件必须可读
+- 文件权限方式有几种方式:
+ - 在 %install 阶段,通过 chmod 和 chown 等命令修改权限
+ - **在 %install 阶段执行拷贝命令时进行赋权限:**`install -m 0644 xxxx`, 建议使用该方式。
+ - 在 %files 阶段统一增加 `%defattr(-,root,root)`,统一赋权限,但该项仅对没有默认值的文件生效
+ - 在 %files 阶段对单个路径或者配置文件增加权限操作:`%dir %attr(0700, root, root) xxxx`
+
+#### 2.5.4 文件详情
+##### 2.5.4.1 license 许可证
+因为每款开源软件都是来源于上游社区,并且都含有自己的许可证。所以需要将许可证信息打入 rpm 包中。
+一般存在的形式为:COPYING 、License 等,解压开源码包即可查找到。
+```
+[root@localhost lld-13.0.1.src]$ ll
+total 88
+drwxr-xr-x 3 root root 4096 Jan 20 2022 cmake
+-rw-r--r-- 1 root root 7232 Aug 4 02:44 CMakeLists.txt
+-rw-r--r-- 1 root root 879 Jan 20 2022 CODE_OWNERS.TXT
+drwxr-xr-x 2 root root 4096 Jan 20 2022 COFF
+drwxr-xr-x 2 root root 4096 Jan 20 2022 Common
+drwxr-xr-x 6 root root 4096 Jan 20 2022 docs -> 这里也别忘记查看一下
+drwxr-xr-x 3 root root 4096 Jan 20 2022 ELF
+drwxr-xr-x 4 root root 4096 Aug 4 02:44 include
+drwxr-xr-x 5 root root 4096 Jan 20 2022 lib
+-rw-r--r-- 1 root root 15138 Jan 20 2022 LICENSE.TXT -> 看这里
+drwxr-xr-x 3 root root 4096 Jan 20 2022 MachO
+drwxr-xr-x 2 root root 4096 Jan 20 2022 MinGW
+-rw-r--r-- 1 root root 678 Jan 20 2022 README.md
+drwxr-xr-x 10 root root 4096 Jan 20 2022 test
+drwxr-xr-x 3 root root 4096 Jan 20 2022 tools
+drwxr-xr-x 4 root root 4096 Jan 20 2022 unittests
+drwxr-xr-x 2 root root 4096 Jan 20 2022 utils
+drwxr-xr-x 2 root root 4096 Jan 20 2022 wasm
+```
+
+在找到这个文件之后,可以直接使用 %license 的宏将文件从**源码包**目录直接打包至**rpm**包内,不需要再单独执行从编译目录拷贝到安装目录的动作。
+
+```
+// 使用样例:
+%files
+%license LICENSE.TXT
+```
+
+##### 2.5.4.2 配置文件
+
+- %config 标志
+
+ 配置文件在打包时,可以使用 %config 对配置文件进行标记,%config 额外还提供 %config(noreplace) 的形式,这样可以在软件包升级时不覆盖本地修改。当然是否选择 noreplace,还要根据具体软件包特点来定,推荐使用 %config(noreplace) 。
+ 但 %config 仅能标记配置文件,其他文件不允许。
+
+ ```
+ %files
+ %config /etc/%{package_name}/%{package_name}.conf
+ %config(noreplace) /etc/%{package_name}/%{package_name}-noreplace.conf
+ ```
+
+- 配置文件的目录
+
+ 配置文件建议放到 /etc 下,不允许放在 /usr 下。
+
+##### 2.5.4.3 systemd units
+
+systemd units文件的软件包必须将它们放入 %{_unitdir} 或 %{_userunitdir}。
+大多数 systemd 服务应该使用 %{_unitdir},但是如果服务作为用户运行的话可以使用 %{_userunitdir}。如果想要使用这两个宏,则必须增加其对应的 rpm。
+
+```
+[root@localhost ~]$ rpm -E %{_unitdir}
+/usr/lib/systemd/system
+
+[root@localhost ~]$ rpm -E %{_userunitdir}
+/usr/lib/systemd/user
+
+// 查询哪个 rpm 对外提供系统服务路径
+[root@localhost ~]$ cd /usr/lib/rpm
+[root@localhost rpm]$ grep -nr '_unitdir'
+macros.d/macros.systemd:9:%_unitdir /usr/lib/systemd/system
+[root@localhost rpm]$ rpm -qf macros.d/macros.systemd
+systemd-rpm-macros-250.4-1.an23.noarch
+```
+
+每个 service 文件都会有 scripts 伴随,一般用于设定服务启动时间、执行服务准备脚本等。主要分布在 %post
+、%preun、%postun 阶段。
+
+- 系统服务相关脚本
+
+ ```
+ BuildRequires: systemd-rpm-macros
+
+ [...]
+ %post
+ %systemd_post apache-httpd.service
+
+ %preun
+ %systemd_preun apache-httpd.service
+
+ %postun
+ %systemd_postun_with_restart apache-httpd.service
+ ```
+
+ 某些服务不支持重启(例如 D-Bus 和各种存储守护进程)。 如果升级时不应重新启动您的服务,请使用以下 %postun 脚本代替上述脚本:
+
+ ```
+ %postun
+ %systemd_postun apache-httpd.service
+ ```
+
+- 用户服务相关脚本
+
+ 安装在 %_userunitdir 下的服务也是需要有对应的脚本设置启动或禁用。
+
+ ```
+ BuildRequires: systemd-rpm-macros
+
+ [...]
+ %post
+ %systemd_user_post %{name}.service
+
+ %preun
+ %systemd_user_preun %{name}.service
+ ```
+
+##### 2.5.4.4 命令行
+
+命令行一般都被包含在主包内,存放路径为:%_bindir 或 %_sbindir,存在部分命令行直接放在 /bin 和 /sbin 下下,/bin 和 /sbin 是作为超链接存在。命令行对外是个可执行的二进制文件,用户根据自己的需求,设置对应的 option,并获取执行结果。
+```
+[root@localhost rpm]$ rpm -E %{_bindir}
+/usr/bin
+
+[root@localhost rpm]$ rpm -E %{_sbindir}
+/usr/sbin
+
+[root@localhost rpm]$ ll /bin
+lrwxrwxrwx. 1 root root 7 Jun 16 2021 /bin -> usr/bin
+
+[root@localhost rpm]$ ll /sbin
+lrwxrwxrwx. 1 root root 8 Jun 16 2021 /sbin -> usr/sbin
+```
+
+##### 2.5.4.5 动态库
+
+动态库又叫共享库,一般存放在 %{_libdir} 下。如果为 64 位系统,%_libdir 为 /usr/lib64,如果为 32 位系统,_libdir 为 /usr/lib。但是也存在一些 so 文件,直接放在 /usr/lib 下,没有64 位 和 32 位的区分。
+注意:%files 声明 %{_libdir} 下的动态库时,尽量不要使用 * 的统配方式隐藏文件名,比如:libxx.so*。
+一般动态库有三种形态,需要严格按照划分方式规定每个 so 的归属。
+
+```
+libxxx.so // 放在 devel 包,开发包,作为超链接直接对外提供,链接到 libxxx.so.1.1
+libxxx.so.1 // 放在主包或者 libs 包,作为超链接直接对外提供,链接到 libxxx.so.1.1
+libxxx.so.1.1 // 放在主包或者 libs 包,实际掉用的 so,当发生版本变更时,不影响对外提供
+```
+
+举例:
+
+```
+[root@localhost rpm]$ ll /usr/lib64 | grep libffi
+lrwxrwxrwx. 1 root root 15 3月 14 11:19 libffi.so -> libffi.so.8.1.0
+lrwxrwxrwx. 1 root root 15 3月 14 11:19 libffi.so.8 -> libffi.so.8.1.0
+-rwxr-xr-x. 1 root root 45280 3月 14 11:19 libffi.so.8.1.0
+
+[root@localhost rpm]$ rpm -qf /usr/lib64/libffi.so.8
+libffi-3.4.2-1.an23.x86_64
+[root@localhost rpm]$ rpm -qf /usr/lib64/libffi.so.8.1.0
+libffi-3.4.2-1.an23.x86_64
+[root@localhost rpm]$ rpm -qf /usr/lib64/libffi.so
+libffi-devel-3.4.2-1.an23.x86_64
+```
+
+##### 2.5.4.6 静态库
+
+静态库是指 .a 或者 .la 的文件,存放路径也在 %{_libdir} 下。但是,我们的软件应该尽可能排除掉静态库,即静态库默认不对外提供。
+如果想要对外提供静态库,则可以生成 package-static 包,其他依赖静态库的可以在 spec 中增加对 package-static 的构建依赖。
+```
+[root@localhost ~]$ rpm -ql zlib-static
+/usr/lib64/libz.a
+/usr/share/licenses/zlib-static
+/usr/share/licenses/zlib-static/README
+
+[root@localhost ~]$ ll /usr/lib64/libz.a
+-rw-r--r--. 1 root root 383514 3月 15 19:47 /usr/lib64/libz.a
+```
+
+##### 2.5.4.7 网络应用程序
+
+一般 Web 应用程序应该将它们的内容放入 `%{_datadir}/%{name}`(即: /usr/share/%{name} )中,而不是放在 /var/www/ 下,原因如下:
+
+- /var 应该包含可变数据文件和日志。 /usr/share 更适合这种情况。
+- 许多用户有可能已经在 /var/www 中拥有内容,我们不希望任何软件包覆盖用户信息。
+- FHS没有定义 /var/www
+
+##### 2.5.4.8 Tmpfiles.d
+
+tmpfiles.d 是用于管理守护进程的临时文件和运行时目录的服务,一般对应的路径为:/run 和 /run/lock。由于 /run 是一个 tmpfs 文件系统,因此每次重新启动时都必须重新创建它及其内容。 通常需要提前创建目录,最好使用 tmpfiles.d 机制来完成。
+
+- tmpfiles.d 机制,对应路径为: %{_tmpfilesdir}
+- 在 %{_tmpfilesdir} 下生成 %{name}.conf 文件
+- 配置文件的内容为一行或多行相同类型的配置:
+ ```
+ // d 规定如果目录不存在则创建路径,可以有多种类型
+ // /run/NAME 需要创建的文件系统路径
+ // PERM 创建目录时的目录权限
+ // USER 目录的所有者
+ // GROUP 目录所在组的名称
+ // - 自动清理在指定时间内未使用的文件
+ d /run/NAME PERM USER GROUP -
+ ```
+
+- 举例:
+ ```
+ // 查询 %{_tmpfilesdir} 对应的实际路径
+ [root@localhost ~]$ rpm -E %{_tmpfilesdir}
+ /usr/lib/tmpfiles.d
+
+ // 查看 /usr/lib/tmpfiles.d 下存在哪些文件
+ [root@localhost ~]$ ll /usr/lib/tmpfiles.d/x11.conf
+ -rw-r--r--. 1 root root 617 3月 11 15:33 /usr/lib/tmpfiles.d/x11.conf
+
+ // 案例1:
+ [root@localhost ~]$ cat /usr/lib/tmpfiles.d/cryptsetup.conf
+ d /run/cryptsetup 0700 root root -
+
+ // 案例2:
+ [root@localhost ~]$ cat /usr/lib/tmpfiles.d/dnf.conf
+ // Unlink the dnf lock files during boot
+ R /var/tmp/dnf*/locks/*
+ r /var/cache/dnf/download_lock.pid
+ r /var/cache/dnf/metadata_lock.pid
+ r /var/lib/dnf/rpmdb_lock.pid
+ r /var/log/log_lock.pid
+ ```
+
+##### 2.5.4.9 locale 文件
+
+rpm 提供了 %find_lang 宏用于处理 locale 文件,%find_lang 能够按名称扫描软件包中所有的 locale 文件,并将列表放入文件中,然后可以通过该文件来打包所有的locale文件。
+使用方式: 在 %install 阶段将所有的文件都安装到 %buildroot 后,运行 %find_lang ,并在 %files 阶段将文件打入 rpm。
+```
+%install
+.......
+%find_lang %{name}
+
+%files -f %{name}.lang
+......
+```
+ 如果 lang 文件与 %{name} 不同,则需要单独调用 %find_lang 脚本
+```
+%install
+.......
+%find_lang %{name}
+%find_lang test --with-man
+
+%files -f %{name}.lang -f test.lang
+......
+```
+
+##### 2.5.4.10 cron 文件
+
+cron 文件的存放目录取决于运行时的间隔,可能的目录有:
+```
+[root@localhost ~]$ ll /etc/ | grep cron
+-rw-r--r--. 1 root root 541 Jan 26 2021 anacrontab
+drwxr-xr-x. 2 root root 4096 Jun 27 2021 cron.d
+drwxr-xr-x. 2 root root 4096 Jun 27 2021 cron.daily
+-rw-r--r--. 1 root root 0 Jan 26 2021 cron.deny
+drwxr-xr-x. 2 root root 4096 Jun 27 2021 cron.hourly
+drwxr-xr-x. 2 root root 4096 Jun 16 2021 cron.monthly
+-rw-r--r--. 1 root root 451 Jun 16 2021 crontab
+drwxr-xr-x. 2 root root 4096 Jun 16 2021 cron.weekly
+```
+例外情况:如果某个 cron 的任务的运行频率或者时间间隔不满足上述规定的间隔,则需要自定义 crontab 文件添加到 /etc/cron.d(具有 0640 权限)), cron 任务文件(脚本)必须放在适当的系统位置(例如 %{_sbindir}、%{_libexecdir}),而不是 /etc/cron.d。
+
+##### 2.5.4.11 头文件
+当我们使用某款软件做开发时,会依赖其对外提供的头文件,这些头文件在系统中的位置一般都是 %{_includedir}( /usr/include ),并且会被封装到 devel 包中,同时 devel 包对于主包是存在运行依赖关系的。
+```
+[root@localhost ~]$ rpm -ql zlib-devel
+/usr/include/zconf.h
+/usr/include/zlib.h
+.....
+```
+
+##### 2.5.4.12 pkgconfig 文件
+
+一般伴随头文件的还有一个 pkgconfig 文件,在系统中的位置为 /usr/lib64/pkgconfig,一般以 %{name}.pc 文件存在,对外提供 pkgconfig(%{name}) 功能。
+```
+[root@localhost ~]$ rpm -ql zlib-devel
+......
+/usr/lib64/pkgconfig/zlib.pc
+......
+
+// 查询对外提供的 pkgconfig 能力
+[root@localhost ~]$ rpm -qP zlib-devel
+pkgconfig(zlib) = 1.2.11
+zlib-devel = 1.2.11-1.an23
+zlib-devel(x86-64) = 1.2.11-1.an23
+```
+
+##### 2.5.4.13 example 文件
+
+一般软件的源码中会包含一些测试文档和样本文件,我们也需要将这些 example 文件打入 devel 包中,存在系统的位置为:/usr/share/doc/%{package}-devel/example*,一般源码中会包含 examples 目录,我们也可以将 examples 目录都打入。
+```
+[root@localhost ~]$ rpm -ql zlib-devel
+......
+/usr/share/doc/zlib-devel/example.c
+......
+
+[root@localhost zlib-1.2.11]$ ll
+......
+drwxr-xr-x 2 501 games 4096 Aug 8 22:48 examples
+......
+```
+
+##### 2.5.4.14 doc 文件
+
+一般软件源码中也会包含一些说明性质的文档,来讲述软件的基本功能、修改记录、软件计划节奏等。
+包括不限制:readme、changelog、news、todo 等。
+
+
+### 2.6 脚本执行
+
+在 spec 中除了定义上述中的编译、安装、打包外,还有额外的脚本操作,这些脚本是按照 rpm 安装或者卸载的顺序来执行,一方面是为了准备安装或者卸载所需要的环境条件,另一方面是为了满足软件的运行需求。
+一般将脚本定义在 %install 和 %files 中间的位置。
+
+#### 2.6.1 %pre
+
+%pre 是代表 rpm 安装之前所执行的脚本。
+格式如下:在 pre 之后可以定义在具体 rpm 所执行的内容,如果 rpm 为重命名的,需要同样采用 -n 选项
+```
+%pre rpm_name
+xxxx
+
+%pre -n rpm_name
+xxxx
+```
+样例:dbus 生成的 dbus-daemon.rpm 需要设置 dbus 的用户群组
+```
+%install
+......
+
+%pre daemon
+// Add the "dbus" user and group
+getent group dbus >/dev/null || groupadd -f -g %{dbus_user_uid} -r dbus
+if ! getent passwd dbus >/dev/null ; then
+ if ! getent passwd %{dbus_user_uid} >/dev/null ; then
+ useradd -r -u %{dbus_user_uid} -g %{dbus_user_uid} -d '/' -s /sbin/nologin -c "System message bus" dbus
+ else
+ useradd -r -g %{dbus_user_uid} -d '/' -s /sbin/nologin -c "System message bus" dbus
+ fi
+fi
+exit 0
+
+
+......
+%files
+```
+
+#### 2.6.2 %post
+
+%post 用来声明 rpm 安装后执行的脚本。
+样例:在 dbus 的 spec 内,对dbus-comon 安装后需要将对应的服务启动。
+```
+%post common
+%systemd_post dbus.socket
+%systemd_user_post dbus.socket
+```
+
+#### 2.6.3 %preun
+
+%preun 用来声明 rpm 卸载之前执行的脚本。
+样例:在 dbus 的 spec 内,对dbus-comon 安装后需要将对应的服务关闭。
+```
+%preun common
+%systemd_preun dbus.socket
+%systemd_user_preun dbus.socket
+```
+
+#### 2.6.4 %postun
+
+%postun 用来声明 rpm 卸载之后执行的脚本。
+样例:
+```
+%postun common
+%systemd_postun dbus.socket
+%systemd_user_postun dbus.socket
+```
+
+#### 2.6.5 脚本执行顺序
+
+- 单个 rpm 的脚本执行顺序:
+
+ ```
+ // 安装动作
+ %pre 脚本 -》 安装文件 -》执行 %post 脚本
+
+ // 卸载动作
+ %preun 脚本 -》 删除文件 -》执行 %postun 脚本
+ ```
+
+- rpm 升级时的脚本执行顺序:
+
+ 
+
+
+#### 2.6.6 执行状态判断
+
+因为在首次安装或升级时,都要去执行 pre 或 post 操作,为了区分不同的前提状态,脚本里默认增加了变量 "$1" ,在脚本对应阶段通过 "$1" 的判断在安装和升级阶段执行不同的脚本
+
+| 软件包动作 | %pre | %post | %preun | %postun |
+| --- | --- | --- | --- | --- |
+| 首次安装 | "$1" = 1 | 不适用 | "$1" = 1 | 不适用 |
+| 升级 | "$1" = 2 | "$1" = 1 | "$1" = 2 | "$1" = 1 |
+| 卸载 | 不适用 | "$1" = 0 | 不适用 | "$1" = 0 |
+
+
+
+## 3 常见问题汇总
+
+### 3.1 rpmbuild 基础知识
+
+#### 3.1.1 为什么需要了解 rpmbuild ?
+
+rpmbuild 提供了本地生成 rpm 的功能,可以实现从 spec + source.tar.gz 生成对应的 rpm 文件。
+
+#### 3.1.2 环境初始化
+
+准备 rpmbuild 的运行所需要的目录结构,通常 SOURCES 是必须的目录,其他路径在运行过程中会自动生成。
+
+- 方案1 - 手动创建目录结构
+ ```
+ [root@localhost ~]$ mkdir rpmbuild
+ [root@localhost ~]$ mkdir rpmbuild/SOURCES
+ ```
+
+- 方案2 - 通过 rpmdevtools 中的 rpmdev-setuptree 命令生成
+ ```
+ [root@localhost ~]$ yum install rpmdevtools
+ [root@localhost ~]$ rpmdev-setuptree
+ [root@localhost ~]$ ll rpmbuild/
+ total 20
+ drwxr-xr-x 2 root root 4096 Aug 15 02:12 BUILD
+ drwxr-xr-x 2 root root 4096 Aug 15 02:12 RPMS
+ drwxr-xr-x 2 root root 4096 Aug 15 02:12 SOURCES
+ drwxr-xr-x 2 root root 4096 Aug 15 02:12 SPECS
+ drwxr-xr-x 2 root root 4096 Aug 15 02:12 SRPMS
+ ```
+
+#### 3.1.3 目录结构介绍
+
+实际使用目录介绍:
+```
+[root@localhost ~]$ ll /root/rpmbuild/
+总用量 0
+drwxr-xr-x. 3 root root 28 8月 9 14:54 BUILD ## 源码编译目录
+drwxr-xr-x. 2 root root 6 8月 8 14:51 BUILDROOT ## 源码预安装目录
+drwxr-xr-x. 2 root root 6 7月 28 17:48 RPMS ## rpm 产物目录
+drwxr-xr-x. 4 root root 174 8月 9 19:38 SOURCES ## 源码文件目录
+drwxr-xr-x. 2 root root 6 7月 28 17:48 SPECS ## spec 目录
+drwxr-xr-x. 2 root root 47 8月 8 14:51 SRPMS ## srpm 目录
+```
+
+#### 3.1.4 安装 rpmbuild
+
+初始环境中不会默认安装 `/usr/bin/rpmbuild`,需要开发者自行安装 `rpm-build`软件。
+```
+[root@localhost ~]$ yum install rpm-build
+```
+
+#### 3.1.5 使用介绍
+
+rpmbuild 针对 spec 里的每一个阶段都提供了对应的 option,可以方便的按需执行到对应阶段。
+
+- 准备阶段
+
+将 source.tar.gz 和 spec 拷贝至 SOURCES 目录后,执行 rpmbuild 命令会生成其他目录结构。
+
+- 构建相关的基本命令
+ ```
+ rpmbuild -bp xxx.spec // 执行完 %prep,解压和打补丁
+ rpmbuild -bb xxx.spec // 执行完 %build,执行到编译动作结束
+ rpmbuild -bi xxx.spec // 执行完 %install,执行到安装动作结束
+ # srpm 是将所有 source 文件打成一个压缩包
+ rpmbuild -ba xxx.spec // 全部执行,生成 srpm 和 rpm
+ rpmbuild -bs xxx.spec // 只生成 srpm
+ rpmbuild -bl xxx.spec // 检验文件是否齐全
+ ```
+
+- 拓展功能,以下为比较常用的选项介绍
+ ```
+ -buildroot=DIRECTORY // 自定义 build root 的目录
+ -clean // 完成打包后清除BUILD下的文件目录
+ -nobuild // 不执行 build 阶段
+ -nodeps // 忽略掉构建依赖
+ ```
+
+### 3.2 补丁
+
+#### 3.2.1 什么是补丁?
+
+在源码中经常能看到后缀为 .patch 的文件,这些文件即是补丁文件。样例如下:
+```
+[root@localhost tbb]$ ll
+total 5360
+-rw-r--r-- 1 root root 488 Jul 27 07:14 README.md
+-rw-r--r-- 1 root root 2677 Jul 27 07:14 tbb-2019-dont-snip-Wall.patch
+-rw-r--r-- 1 root root 670 Jul 27 07:14 tbb-2019-test-task-scheduler-init.patch
+-rw-r--r-- 1 root root 1864 Jul 27 07:14 tbb-2019-test-thread-monitor.patch
+-rw-r--r-- 1 root root 2639737 Jul 27 07:14 tbb-2020.3.tar.gz
+-rw-r--r-- 1 root root 2883 Jul 27 07:14 tbb-2020-attributes.patch
+-rw-r--r-- 1 root root 2883 Jul 27 07:14 tbb-mark-empty_task-execute-with-gnu-used.patch
+```
+
+补丁格式详解:
+总包含两大块:补丁头 + 实际修改内容。
+其中补丁头用于描述补丁的基本信息,查看这里就能清楚的获取补丁的制作人、制作时间和实现的功能。
+实际修改内容中包括:修改的文件路径 + 内容
+修改文件这里是默认采用源码包解压后的第一层目录作为相对目录进行,通常在打入补丁时采用 -px 来指定忽略 x 层路径。
+```
+From git log 信息
+From: patch 制作者
+Date: patch 的生成日期
+Subject: 修改的简要描述
+
+---
+ git diff 生成的文件差异信息
+
+diff --git 修改前文件路径 修改后文件路径
+--- 修改前文件路径
++++ 修改后文件路径
+@@ index @@ index 对应的代码行
+实际代码
+```
+样例:
+
+```
+[root@localhost tbb]$ cat tbb-mark-empty_task-execute-with-gnu-used.patch
+From db2f2116adfb545bb76c92205f91e3e3f0f9e44a Mon Sep 17 00:00:00 2001
+From: Thomas Rodgers
+Date: Wed, 2 Jun 2021 15:18:30 -0700
+Subject: [PATCH] Mark tbb::empty_task::execute with [[gnu::used]]
+
+---
+ include/tbb/task.h | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/include/tbb/task.h b/include/tbb/task.h
+index 5e137c6..5b60163 100644
+--- a/include/tbb/task.h
++++ b/include/tbb/task.h
+@@ -1040,6 +1040,9 @@ inline void task::resume(suspend_point tag) {
+ //! task that does nothing. Useful for synchronization.
+ /** @ingroup task_scheduling */
+ class __TBB_DEPRECATED_IN_VERBOSE_MODE empty_task: public task {
++#if __has_cpp_attribute(gnu::used)
++ [[gnu::used]]
++#endif
+ task* execute() __TBB_override {
+ return NULL;
+ }
+--
+2.31.1
+```
+
+#### 3.2.2 为什么要有补丁文件?
+
+因为 OS 体系是由众多第三方开源软件组成的,这些第三方开源软件都是有自己的维护者的。
+那么 Anolis OS 作为发行者的角色,只能从开源社区取到完整的 source.tar.gz,这些 source.tar.gz 是不允许直接解压开直接修改的,所以针对 source.tar.gz 所有的修改都要通过 patch 的途径进行。
+
+#### 3.2.3 如何制作补丁?
+
+- 首先,将源码包解压开,如果有前缀补丁,需要将其先打入。
+
+ ```
+ // 先将源代码拷贝到 ~/rpmbuild/SOURCES/
+ [root@localhost tbb]$ cp * /root/rpmbuild/SOURCES/
+
+ // 执行解压动作
+ [root@localhost tbb]$ rpmbuild -bp tbb.spec --nodeps
+ Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.W4Pc3T
+ + umask 022
+ + cd /root/rpmbuild/BUILD
+ + cd /root/rpmbuild/BUILD
+ + rm -rf oneTBB-2021.5.0
+ + /usr/bin/gzip -dc /root/rpmbuild/SOURCES/v2021.5.0.tar.gz
+ + /usr/bin/tar -xof -
+ + STATUS=0
+ + '[' 0 -ne 0 ']'
+ + cd oneTBB-2021.5.0
+ + /usr/bin/chmod -Rf a+rX,u+w,g-w,o-w .
+ + sed -i 's/version\s*="0.2"/version = "2021.5"/' python/setup.py
+ + sed -i '1{/^#!.*env python/ d}' python/TBB.py python/tbb/__init__.py python/tbb/__main__.py python/tbb/pool.py python/tbb/test.py
+ + exit 0
+ ```
+
+- 进入解压后的目录下,进行 git 初始化
+
+ ```
+ // 这里 v2021.5.0.tar.gz 解压完后的目录名称为 oneTBB-2021.5.0
+ [root@localhost tbb]$ cd /root/rpmbuild/BUILD/oneTBB-2021.5.0/
+
+ // 执行 git 初始化
+ [root@localhost oneTBB-2021.5.0]$ git init
+ Initialized empty Git repository in /root/rpmbuild/BUILD/oneTBB-2021.5.0/.git/
+ [root@localhost oneTBB-2021.5.0]$ git add .
+ [root@localhost oneTBB-2021.5.0]$ git commit -m "init"
+ ```
+
+- 此时可以按照自己需要修改源码,修改之后通过 `git status` 或 `git diff`查看修改内容,如果想把多处修改合并到一个 patch 里,此处可以将要修改的文件都改了。
+
+ ```
+ // 这里样例就随意修改了~
+ [root@localhost oneTBB-2021.5.0]$ git status
+ On branch master
+ Changes not staged for commit:
+ (use "git add ..." to update what will be committed)
+ (use "git restore ..." to discard changes in working directory)
+ modified: README.md
+
+ no changes added to commit (use "git add" and/or "git commit -a")
+ ```
+
+- 提交本地修改
+
+ ```
+ [root@localhost oneTBB-2021.5.0]$ git add .
+ [root@localhost oneTBB-2021.5.0]$ git commit -m "modify the README.md"
+ [master 171249b] modify the README.md
+ 1 file changed, 5 insertions(+)
+ ```
+
+- 生成补丁,HEAD^ 代表将最近的 一次生成补丁,-o 后面为补丁输出路径。
+
+ ```
+ [root@localhost oneTBB-2021.5.0]$ git format-patch -n HEAD^ -o /root/rpmbuild/SOURCES/
+ /root/rpmbuild/SOURCES/0001-modify-the-README.md.patch
+ ```
+
+- 查看补丁内容
+
+ ```
+ root@localhost oneTBB-2021.5.0]$ cat /root/rpmbuild/SOURCES/0001-modify-the-README.md.patch
+ From 171249bd0bf1641b52697710d399d832d1b85914 Mon Sep 17 00:00:00 2001
+ From: "xxx.test"
+ Date: Wed, 10 Aug 2022 05:22:25 -0400
+ Subject: [PATCH 1/1] modify the README.md
+ README.md | 5 +++++
+ 1 file changed, 5 insertions(+)
+ diff --git a/README.md b/README.md
+ index dd5156f..b024027 100644
+ --- a/README.md
+ +++ b/README.md
+ @@ -4,6 +4,11 @@
+ oneAPI Threading Building Blocks (oneTBB) lets you easily write parallel C++ programs that take xxxxxxxx
+ full advantage of multicore performance, that are portable, composable and have future-proof scalability.
+
+ +##############
+ +this is test
+ +##############
+ +
+ +
+ #### Release Information
+ Here are [Release Notes]( https://software.intel.com/en-us/articles/intel-oneapi-threading-building-blocks-release-notes) and
+ [System Requirements](https://software.intel.com/en-us/articles/intel-oneapi-threading-building-blocks-system-requirements).
+ --
+ 2.27.0
+ ```
+
+
+
+#### 3.2.4 如何打补丁?
+
+- 源码方式打入补丁
+
+ 可以通过 `git apply`命令在源码中将补丁打入
+
+ ```
+ // 解压源码,并将以前补丁打入
+ [root@localhost SOURCES]$ rpmbuild -bp tbb.spec --nodeps
+
+ // 进入解压后的目录
+ [root@localhost SOURCES]$ cd /root/rpmbuild/BUILD/oneTBB-2021.5.0/
+
+ // 检查补丁
+ [root@localhost oneTBB-2021.5.0]$ git apply --check /root/rpmbuild/SOURCES/0001-modify-the-README.md.patch
+
+ // 打入补丁
+ [root@localhost oneTBB-2021.5.0]$ git apply /root/rpmbuild/SOURCES/0001-modify-the-README.md.patch
+ ```
+
+- 通过 spec 方式打入补丁
+
+ 参见 2.2 章节中的 %prep 介绍。
+
+### 3.3 构建问题
+
+#### 3.3.1 构建环境是什么?
+
+构建环境是一个相对“干净”的环境,因为是从 chroot 生成的,该环境仅仅用于源码构建,不用于其他用途。
+
+#### 3.3.2 构建环境里安装的软件是在哪里指定的?
+
+构建环境是来源于两处:**默认安装** + **spec 中 BuildRequires 指定**。默认安装是我们针对所有软件包构建的一个基础编译环境,只包含编译工具链的软件;每个软件可以将自己构建需要引入的软件包都写到 BuildRequires 中,则构建环境会去安装这些软件,从而共同组成了构建环境。
+
+#### 3.3.3 我如果想在构建环境中增加软件,该如何做?
+
+在编译的过程中,经常会遇到缺少某个头文件或者某个动态库,再或者某个二进制的情况,这是我们需要将缺少的文件所属的 rpmpackage 添加到 BuildRequires 中,然后重新发起构建即可。
+举例: 假设当前缺少 /usr/include/ncursesw/etip.h,可以通过 `dnf`查询改文件的所属,并将该软件写到 BuildRequires 中。
+```
+$ dnf repoquery --whatprovides '/usr/include/ncursesw/etip.h'
+上次元数据过期检查:1:26:21 前,执行于 2022年08月10日 星期三 12时45分43秒。
+ncurses-devel-0:6.3-2.an23.x86_64
+```
+
+#### 3.3.4 在构建环境里的软件版本不满足我的需求怎么办?
+
+软件(A)包在构建的过程中,可能需要指定某个构建依赖包(B)的版本的版本号,这时发现构建环境里安装的这款软件和预期版本不满足,此时,需要我们先把依赖包准备出对应的 rpm 后,再来编译原本的软件。
+
+- B 大于 A
+
+这种场景下优先建议 A 软件进行适配 B 软件。因为高版本的 B 软件已经发布,整个 OS 内的其他软件已经依赖了高版本的 B,降级和多版本共存的场景都不满足 OS 发行版的要求,而且从软件的长远发展路线来看,去适配最新版本也是最好的选择。
+
+- B 小于 A
+
+这种场景下建议先将软件包 B 进行基线升级,升级到满足 A 的要求的版本,但是进行基线升级时,需要进行全面的影响评估,请勿对其他软件产生影响。
+
+#### 3.3.5 我需要在构建环境中执行外网操作怎么办?
+
+结论:不允许出现访问外网操作。
+因为构建环境是一个模拟的chroot中构建的,无法访问互联网,同时也不允许从外网直接下载依赖的操作,这里的外网操作包括但不限制如下:配置境外、国内的任何一个远端源(pip、nodejs、rust、maven 等),wget 下载、curl 下载等等。
+
+#### 3.3.6 如果我必须下载很多外部源怎么办?
+
+对于还在孵化期的软件,我们允许将所有构建依赖下载到本地,然后通过 offline 模式指定本地的路径进行编译。但该动作需要得到 OS 产品接口人的许可,方可执行。
+当前以 go 语言举例,其他语言参照
+
+- 先在联网环境下,进入到源代码目录下,下载对应的依赖,并放到本地的 vendor 目录下
+```
+go mod vendor
+```
+
+- 关闭互联网,然后执行离线构建(这里需要根据不同语言,选择不同的离线方式)
+```
+go build -mod=vendor
+```
+
+- 在上述两步执行成功之后,将 vendor 目录生成压缩包,作为 spec 的第二个source,并将离线构建方式写入
+
+ ```
+ ......
+ Source0: package.tar.gz
+ Source1: package_vendor.tar.gz
+ .......
+
+
+ %prep
+ %autosetup -n %{name}-%{release}
+ tar -xvf %{SOURCE1} ./
+
+ %build
+ go build -mod=vendor
+ ```
+
+- rpmbuild 构建或者 koji 构建测试,待成功后提交代码
+
+#### 3.3.7 构建过程中提示没有权限怎么办?
+
+当构建过程中提示权限不足时,第一想法都是怎么去提高构建权限,这种想法是不对的。因为,所有发行版的正式构建都是以 build 用户执行的,是不允许操作系统环境的,只允许在构建目录下操作。
+所以,应该去排查是哪里操作了系统目录,然后将该动作的修改到构建目录下。
diff --git a/TECHNOLOGY_DOCS/GITEE/307-build-a-new-project.md b/TECHNOLOGY_DOCS/GITEE/307-build-a-new-project.md
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/TECHNOLOGY_DOCS/GITEE/308-example-of-epao-nonfree-package.md b/TECHNOLOGY_DOCS/GITEE/308-example-of-epao-nonfree-package.md
new file mode 100644
index 0000000000000000000000000000000000000000..72c9ce82d021b1f210f197d358609fa727d579e7
--- /dev/null
+++ b/TECHNOLOGY_DOCS/GITEE/308-example-of-epao-nonfree-package.md
@@ -0,0 +1,327 @@
+# 闭源软件集成样例
+
+### 1. 联系法务,走开源流程
+
+acc 的软件维护者 程斌 同学,在准备好公开策略(公开的频率和方式)之后,联系法务同学,申请了二进制披露序和开源软件合规扫描。这里要注意一点,如果涉及版本更新,则该流程需要重新走一遍。
+
+### 2. 获取法律允许
+
+流程申请之后,获取法务许可,增加一个 Alibaba-Cloud-Compiler-End-User-Agreement.docx 文件,该文件表示用户安装此软件的同意许可。该文件和软件本身的 License 文件必须包含在 rpm 的 filelist 内。
+
+### 3. 本地准备编译环境,制作可用 rpm,并进行本地测试。
+
+1. 需要定义软件的基本信息。
+
+
+2. 包括:name、version、summary、url、descriotion。
+
+3. 注意:version 代表软件版本,release 仅代表构建次数。如果同一个版本,不做源码变更(此处叫二进制变更),仅仅是 spec 的修改,需要保证 version 不变、递增 release;如果在正式发布之后版本发生变更,比如二进制更新了,此处应该变更 version,release 重新从 1 开始。
+
+
+4. 软件维护者准备编译环境。
+
+
+5. 发布的版本尽量和本地的构建环境保持一致,因为构建依赖的版本不同可能会导致 so 运行不起来。即:发布到 Anolis OS 23 的 rpm 尽量使用 Anolis OS 23 的环境编译,发布到 Anolis OS 8 的 rpm 尽量使用 Anolis OS 8 的环境进行编译。
+
+6. acc 这个包比较特殊,特殊在仅对 glibc 的 so 有依赖,且 an8 提供的 glibc.so 在 Anolis OS 23 上也能通用,所以仅构建一次,采用 Anolis OS 8 上构建出来的结果同步发布到 Anolis OS 23 版本。
+
+
+7. 新建 spec([参考 spec 模版](https://gitee.com/anolis/docs/blob/main/articles/305-module-and-checklist-of-spec.md)),并在本地编译出闭源软件的 rpm。
+
+8. rpmbuild 过程出现问题,可以查看 [构建指导手册](../articles/306-instruction-manual-of-rpmbuild.md)
+
+9. 此处直接给出 rpm 样例:
+
+```
+ [root@localhost acc]# ls
+ alibaba-cloud-compiler-13.0.1-2.fix.an8.aarch64.rpm
+ alibaba-cloud-compiler-13.0.1-2.fix.an8.src.rpm
+ alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64.rpm
+```
+
+### 4. 制作 rpm tree 需要的 source 文件。
+
+* 需要先创建一个目录(rpmname-version),并且在该目录下创建两个架构目录(x86\_64,aarch64),如果是 noarch 的包,可以建立 noarch 目录或者选择不建立架构目录。
+
+```
+ [root@localhost acc]# mkdir alibaba-cloud-compiler-13.0.1
+ [root@localhost acc]# cd alibaba-cloud-compiler-13.0.1
+ [root@localhost alibaba-cloud-compiler-13.0.1]# mkdir x86_64
+ [root@localhost alibaba-cloud-compiler-13.0.1]# mkdir aarch64
+ [root@localhost alibaba-cloud-compiler-13.0.1]# ls
+ aarch64 x86_64
+ [root@localhost acc]# tree alibaba-cloud-compiler-13.0.1
+ alibaba-cloud-compiler-13.0.1
+ ├── aarch64
+ └── x86_64
+
+ 3 directories, 0 files
+```
+
+* 使用 rpm2cpio 命令将 rpm 解压到刚才创建的带架构的目录下。(注意:路径全部保留)-D 选项可以指定解压的目标目录。
+
+```
+ [root@localhost acc]# rpm2cpio alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64.rpm | cpio -divm -D alibaba-cloud-compiler-13.0.1/x86_64
+ [root@localhost acc]# ls alibaba-cloud-compiler-13.0.1
+ aarch64 x86_64
+ [root@localhost acc]# ls alibaba-cloud-compiler-13.0.1/x86_64/
+ opt
+ [root@localhost acc]# ls alibaba-cloud-compiler-13.0.1/x86_64/opt/
+ alibaba-cloud-compiler
+ [root@localhost acc]# ls alibaba-cloud-compiler-13.0.1/x86_64/opt/alibaba-cloud-compiler/
+ bin FLANG-LICENSE.TXT include JEMALLOC.COPYING lib64 libexec LICENSE.TXT README share
+```
+
+* 将另一个架构的 rpm 按照同样方式解压拷贝进去。
+
+```
+ [root@localhost acc]# tar -xvf 20221117-161007-543-#75-anolis8.6.aarch64.release.rpm-13-rpm.tar.gz
+ alibaba-cloud-compiler-13.0.1-2.fix.an8.aarch64.rpm
+ alibaba-cloud-compiler-13.0.1-2.fix.an8.src.rpm
+ summary_message.txt
+ [root@localhost acc]# rpm2cpio alibaba-cloud-compiler-13.0.1-2.fix.an8.aarch64.rpm | cpio -divm -D alibaba-cloud-compiler-13.0.1/aarch64/
+ [root@localhost acc]# ls alibaba-cloud-compiler-13.0.1/aarch64/opt/alibaba-cloud-compiler/
+ bin FLANG-LICENSE.TXT include JEMALLOC.COPYING lib64 libexec LICENSE.TXT README share
+```
+
+* 对整个目录进行压缩,压缩成一个 tar.gz
+
+```
+ [root@localhost acc]# tar -cvf alibaba-cloud-compiler-13.0.1.tar.gz alibaba-cloud-compiler-13.0.1
+ [root@localhost acc]# ls | grep tar.gz
+ 20221117-161007-047-#75-anolis8.6.x86_64.release.rpm-13-rpm.tar.gz
+ 20221117-161007-543-#75-anolis8.6.aarch64.release.rpm-13-rpm.tar.gz
+ alibaba-cloud-compiler-13.0.1.tar.gz
+```
+
+### 5. 走软件引入流程,ospkg-list 进行申请
+
+* 软件维护者创建 issue,按照模版填写需求背景、收益、维护者和目标。写清楚闭源软件的引入背景和原因、闭源的 License 信息等。
+
+* 由橘悦审核 issue 并通过之后,进行建立仓库。仓库地址:https://gitee.com/src-anolis-nonfree/ , a8 分支对应 Anolis OS 8,a23 分支对应 Anolis OS 23。
+
+* 软件维护者在 ospkg-list 仓库中提交代码,参照指导,提交软件信息
+
+
+### 6. 将制作好的 source.tar.gz 和 spec 提交到已经建立的仓库
+
+* 打开 gitee 的仓库地址:https://gitee.com/src-anolis-nonfree/
+
+* 将软件仓库 fork 到个人仓库
+
+* 将准备好的 source.tar.gz 和 spec 文件提交到个人仓库的版本分支(a8或a23)
+
+* 发起 pr,等待门禁通过,如果门禁失败,则需要查看错误原因,并进行解决,重新提交代码后,门禁会重新触发
+
+* 提交者下载门禁构建的 rpm 包,并自行进行功能测试
+
+* 等待 maintainer 或者发行版同学审核通过,合入代码,由发行版同学触发正式构建
+
+* 发行版同学将 rpm 发布到 epao-nonfree 仓库,维护者安装 anolis-epao-nonfree-release 包之后,即可通过 yum install 的方式进行安装对应闭源组件。
+
+
+### 7. 软件和代码样例
+
+#### 软件样例:
+
+alibaba-cloud-compiler
+
+#### 代码样例:
+
+* spec 样例:[https://gitee.com/src-anolis-sig/alibaba-cloud-compiler/blob/a23/alibaba-cloud-compiler.spec](https://gitee.com/src-anolis-sig/alibaba-cloud-compiler/blob/a23/alibaba-cloud-compiler.spec)
+
+* source 样例:[http://build.openanolis.cn/kojifiles/upstream-source/alibaba-cloud-compiler-13.0.1.3.tar.gz.c2df8c535fc55ac9604cc2f3b16cbc60](http://8.131.87.1//kojifiles/upstream-source/alibaba-cloud-compiler-13.0.1.3.tar.gz.c2df8c535fc55ac9604cc2f3b16cbc60)
+
+
+#### 门禁 CI 的检测内容样例:
+
+##### 1. 将 rpm 解压到本地
+
+ [root@localhost acc]# ls
+ 20221117-161007-047-#75-anolis8.6.x86_64.release.rpm-13-rpm.tar.gz summary_message.txt
+ 20221117-161007-543-#75-anolis8.6.aarch64.release.rpm-13-rpm.tar.gz
+ [root@localhost acc]# tar -xvf 20221117-161007-047-#75-anolis8.6.x86_64.release.rpm-13-rpm.tar.gz
+ alibaba-cloud-compiler-13.0.1-2.fix.an8.src.rpm
+ alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64.rpm
+
+##### 2. 测试基本安装和卸载
+
+* 安装测试:如果采用 rpm 安装显示缺少运行依赖时,可以采用 yum localinstall 方式进行验证。
+
+```
+ [root@localhost acc]# ls
+ 20221117-161007-047-#75-anolis8.6.x86_64.release.rpm-13-rpm.tar.gz alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64.rpm
+ 20221117-161007-543-#75-anolis8.6.aarch64.release.rpm-13-rpm.tar.gz summary_message.txt
+ alibaba-cloud-compiler-13.0.1-2.fix.an8.src.rpm
+ [root@localhost acc]# rpm -ivh alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64.rpm
+ error: Failed dependencies:
+ perl(File::Copy) is needed by alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64
+ perl(FindBin) is needed by alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64
+ perl(Hash::Util) is needed by alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64
+ perl(Sys::Hostname) is needed by alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64
+ [root@localhost acc]# yum localinstall alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64.rpm
+ Last metadata expiration check: 0:42:27 ago on Thu 03 Aug 2023 01:18:16 PM CST.
+ Dependencies resolved.
+ =====================================================================================================================================
+ Package Architecture Version Repository Size
+ =====================================================================================================================================
+ Upgrading:
+ perl-Errno x86_64 1.36-11.an23 os 14 k
+ perl-interpreter x86_64 4:5.36.1-11.an23 os 70 k
+ perl-libs x86_64 4:5.36.1-11.an23 os 2.1 M
+ Installing dependencies:
+ perl-File-Copy noarch 2.39-11.an23 os 19 k
+ perl-FindBin noarch 1.53-11.an23 os 13 k
+ perl-Hash-Util x86_64 0.28-11.an23 os 33 k
+ perl-Hash-Util-FieldHash x86_64 1.26-11.an23 os 37 k
+ perl-Sys-Hostname x86_64 1.24-11.an23 os 16 k
+ Downgrading:
+ alibaba-cloud-compiler x86_64 13.0.1-2.fix.an8 @commandline 651 M
+
+ Transaction Summary
+ =====================================================================================================================================
+ Install 5 Packages
+ Upgrade 3 Packages
+ Downgrade 1 Package
+
+ Total size: 653 M
+ Total download size: 2.3 M
+ Is this ok [y/N]: y
+ Downloading Packages:
+ (1/8): perl-FindBin-1.53-11.an23.noarch.rpm 60 kB/s | 13 kB 00:00
+ (2/8): perl-Hash-Util-0.28-11.an23.x86_64.rpm 127 kB/s | 33 kB 00:00
+ (3/8): perl-File-Copy-2.39-11.an23.noarch.rpm 69 kB/s | 19 kB 00:00
+ (4/8): perl-Hash-Util-FieldHash-1.26-11.an23.x86_64.rpm 260 kB/s | 37 kB 00:00
+ (5/8): perl-Sys-Hostname-1.24-11.an23.x86_64.rpm 105 kB/s | 16 kB 00:00
+ (6/8): perl-Errno-1.36-11.an23.x86_64.rpm 82 kB/s | 14 kB 00:00
+ (7/8): perl-interpreter-5.36.1-11.an23.x86_64.rpm 551 kB/s | 70 kB 00:00
+ (8/8): perl-libs-5.36.1-11.an23.x86_64.rpm 4.3 MB/s | 2.1 MB 00:00
+ -------------------------------------------------------------------------------------------------------------------------------------
+ Total 2.6 MB/s | 2.3 MB 00:00
+ Running transaction check
+ Transaction check succeeded.
+ Running transaction test
+ Transaction test succeeded.
+ Running
+ Preparing : 1/1
+ Upgrading : perl-libs-4:5.36.1-11.an23.x86_64 1/13
+ Installing : perl-File-Copy-2.39-11.an23.noarch 2/13
+ Installing : perl-FindBin-1.53-11.an23.noarch 3/13
+ Installing : perl-Hash-Util-FieldHash-1.26-11.an23.x86_64 4/13
+ Installing : perl-Hash-Util-0.28-11.an23.x86_64 5/13
+ Installing : perl-Sys-Hostname-1.24-11.an23.x86_64 6/13
+ Upgrading : perl-interpreter-4:5.36.1-11.an23.x86_64 7/13
+ Downgrading : alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64 8/13
+ Upgrading : perl-Errno-1.36-11.an23.x86_64 9/13
+ Cleanup : perl-Errno-1.36-10.an23.x86_64 10/13
+ Cleanup : perl-interpreter-4:5.36.0-10.an23.x86_64 11/13
+ Cleanup : perl-libs-4:5.36.0-10.an23.x86_64 12/13
+ Cleanup : alibaba-cloud-compiler-13.0.1.3-1.an23.x86_64 13/13
+ Running scriptlet: alibaba-cloud-compiler-13.0.1.3-1.an23.x86_64 13/13
+ Verifying : alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64 1/13
+ Verifying : alibaba-cloud-compiler-13.0.1.3-1.an23.x86_64 2/13
+ Verifying : perl-File-Copy-2.39-11.an23.noarch 3/13
+ Verifying : perl-FindBin-1.53-11.an23.noarch 4/13
+ Verifying : perl-Hash-Util-0.28-11.an23.x86_64 5/13
+ Verifying : perl-Hash-Util-FieldHash-1.26-11.an23.x86_64 6/13
+ Verifying : perl-Sys-Hostname-1.24-11.an23.x86_64 7/13
+ Verifying : perl-Errno-1.36-11.an23.x86_64 8/13
+ Verifying : perl-Errno-1.36-10.an23.x86_64 9/13
+ Verifying : perl-interpreter-4:5.36.1-11.an23.x86_64 10/13
+ Verifying : perl-interpreter-4:5.36.0-10.an23.x86_64 11/13
+ Verifying : perl-libs-4:5.36.1-11.an23.x86_64 12/13
+ Verifying : perl-libs-4:5.36.0-10.an23.x86_64 13/13
+
+ Upgraded:
+ perl-Errno-1.36-11.an23.x86_64 perl-interpreter-4:5.36.1-11.an23.x86_64 perl-libs-4:5.36.1-11.an23.x86_64
+ Downgraded:
+ alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64
+ Installed:
+ perl-File-Copy-2.39-11.an23.noarch perl-FindBin-1.53-11.an23.noarch perl-Hash-Util-0.28-11.an23.x86_64
+ perl-Hash-Util-FieldHash-1.26-11.an23.x86_64 perl-Sys-Hostname-1.24-11.an23.x86_64
+
+ Complete!
+```
+
+* 卸载测试:
+
+ * 卸载时不仅要测试包有没有卸载掉,更需要确认安装的文件或者路径是否被清除。
+
+ * 这个版本的 acc 在卸载时文件虽然被清除干净,但是路径没清除,该问题需要解决。解决方案:在 %files 中增加对路径的定义:
+
+```
+%files
+
+%dir /opt
+
+%dir /opt/alibaba-cloud-compiler
+```
+```
+ #
+ [root@localhost acc]# rpm -ql alibaba-cloud-compiler | grep txt
+ /opt/alibaba-cloud-compiler/lib64/clang/13.0.1/share/asan_ignorelist.txt
+ /opt/alibaba-cloud-compiler/lib64/clang/13.0.1/share/cfi_ignorelist.txt
+ /opt/alibaba-cloud-compiler/lib64/clang/13.0.1/share/dfsan_abilist.txt
+ /opt/alibaba-cloud-compiler/lib64/clang/13.0.1/share/hwasan_ignorelist.txt
+ /opt/alibaba-cloud-compiler/lib64/clang/13.0.1/share/msan_ignorelist.txt
+ [root@localhost acc]# rpm -qa alibaba-cloud-compiler
+ alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64
+ [root@localhost acc]# rpm -e alibaba-cloud-compiler
+ [root@localhost acc]# rpm -qa alibaba-cloud-compiler
+ [root@localhost acc]# ls ///opt/alibaba-cloud-compiler/lib64/
+ #### 注意 !!!!这里有问题!!!!
+ [root@localhost acc]# ls /opt/alibaba-cloud-compiler
+ bin include lib64 libexec share
+```
+
+##### 3. 测试该软件对外提供的能力是否产生冲突
+
+* 通过 rpm -qP 查看对外提供的能力,需要对每一个 Provides 的能力进行检测现有源上会不会存在同等功能,尤其是 so,一旦查出来存在相同能力即为有问题的 rpm,需要去除对应能力提供。这里可以用 libflang.so()(64bit) 举例。
+
+```
+ [root@localhost acc]# ls alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64.rpm
+ alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64.rpm
+ [root@localhost acc]# rpm -qP alibaba-cloud-compiler-13.0.1-2.fix.an8.x86_64.rpm
+ alibaba-cloud-compiler = 13.0.1-2.fix.an8
+ alibaba-cloud-compiler(x86-64) = 13.0.1-2.fix.an8
+ lib64/LLVMgold.so(LLVM_13)(64bit)
+ libRemarks.so.13()(64bit)
+ libRemarks.so.13(LLVM_13)(64bit)
+ libclang_rt.asan-x86_64.so()(64bit)
+ libclang_rt.dyndd-x86_64.so()(64bit)
+ libclang_rt.hwasan-x86_64.so()(64bit)
+ libclang_rt.hwasan_aliases-x86_64.so()(64bit)
+ libclang_rt.memprof-x86_64.so()(64bit)
+ libclang_rt.scudo-x86_64.so()(64bit)
+ libclang_rt.scudo_minimal-x86_64.so()(64bit)
+ libclang_rt.scudo_standalone-x86_64.so()(64bit)
+ libclang_rt.ubsan_minimal-x86_64.so()(64bit)
+ libclang_rt.ubsan_standalone-x86_64.so()(64bit)
+ libflang.so()(64bit)
+ libflangrti.so()(64bit)
+ libpgmath.so()(64bit)
+ pkgconfig(jemalloc) = 5.3.0_0
+
+ # 应该对每个能力进行检测,这里使用 libflang.so()(64bit) 给个样例.这里没有查到,结果正确。
+ [root@localhost acc]# yum repoquery --whatprovides 'libflang.so()(64bit)'
+ Last metadata expiration check: 1:46:37 ago on Thu 03 Aug 2023 01:18:16 PM CST.
+ [root@localhost acc]#
+```
+* 发现上述存在问题,去除相同能力提供方式。
+
+
+* 如果存在包名相同,该问题需要重新定义软件名称
+
+* 如果存在提供相同的 bin ,则需要在构建时,重新创建绝对路径,将二进制存放对应目录,或者在源码中更改生成的 bin 名称,避免产生相同的 bin
+
+* 如果存在相同的 so,不仅需要生成到不同目录,也需要去除 so 的对外提供。
+
+
+spec 中添加如下代码,将其去除:
+```
+ %global _privatelibs (libclang.*|libflang.*|libLTO|libomp.*|libc++.*|libRemarks.*|libpgmath)[.]so.*|(.*jemalloc.*)
+ %global __provides_exclude ^(%{_privatelibs})$
+```
+##### 4. 准备测试文档,将上述测试都输出到测试文档中。
+
+该测试文档可以添加到 pr 的评论中同步提交。
\ No newline at end of file
diff --git a/TECHNOLOGY_DOCS/menu.yaml b/TECHNOLOGY_DOCS/menu.yaml
index f93c731aaa78619152cdf7284d32258073fcbba2..e071e053f0d001a1a9e5bc6e77c5d206cf86c889 100644
--- a/TECHNOLOGY_DOCS/menu.yaml
+++ b/TECHNOLOGY_DOCS/menu.yaml
@@ -4,3 +4,17 @@ TECHNOLOGY_DOCS:
安全管理系统:
用户说明文档: ../安全管理系统/ANA用户API说明文档.md
安全数据文档: ../安全管理系统/OpenAnolis安全数据API文档.md
+ GITEE:
+ 302-join-os-package-build: ../GITEE/302-join-os-package-build.md
+ 303: ../GITEE/303-join-kernel-developing.md
+ 304: ../GITEE/304-package-introduction-and-management-principles.md
+ 305: ../GITEE/305-module-and-checklist-of-spec.md
+ 306: ../GITEE/306-instruction-manual-of-rpmbuild.md
+ 307: ../GITEE/307-build-a-new-project.md
+ 308: ../GITEE/308-example-of-epao-nonfree-package.md
+ CSDN:
+ 博客园:
+ GITHUB:
+ GITLAB:
+ 霍格沃斯:
+ API开发: