如何构建一个RPM包
构建一个RPM包
1. rpmdevtools工具及SPEC文件
一些基础点 可以直接从下一章节看
网上找了好多相关的教程,RedHat的教程应该是最官方的。
目前没找到如何生成压缩包的,本文使用setuptools生成
还有说使用pyinstaller生成可执行文件然后获取其依赖并压缩的,没有测试这个
rpmdevtools工具
构建主要用的就是SPEC文件和源文件,将其放到对应的文件夹下执行构建命令
首先创建RPM的工作环境,便捷的就是安装rpmdevtools工具
执行rpmdev-setuptree命令后结果如下1
2
3
4
5
6
7
8rpmdev-setuptree
tree ~/rpmbuild/
/root/rpmbuild/
├── BUILD
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS工作环境目录用途如下
目录 用途 BUILD 构建时生成的各种信息都在这里 RPMS 构建出的二进制包 SOURCES 构建用的源文件放这里,如压缩包、补丁文件等 SPECS 构建用的.spec文件放这里 SRPMS 构建出的源码包 BUILDROOT 构建过程中创建,保存%install阶段安装的文件 SPEC文件
SPEC文件可以分为Preamble和Body两部分
Preamble:
SPEC指令 用途 Name package name Version version number Release NA Summary NA License NA URL 该包的上游网址 Source0 源文件 Patch0 数量可变 BuildArch 构建依赖的环境 BuildRequires 构建所需的依赖包 Requires 运行所需的依赖包 Body:
SPEC指令 用途 %description NA %prep 构建前的一些命令 %build 构建时执行的命令 %install 最终安装目录 %check 测试软件命令 %files 最终会安装在系统的文件 %changelog NA
2.构建一个简单的hello world rpm包
编写py文件
还是最通用的hello world
1
2
3
4
5
6
7
8!/usr/bin/python
-*- coding: utf-8 -*-
def my_print():
print('hello world')
if __name__ == '__main__':
my_print()编写setup.py文件
前面是license 命令是setuptools.setup
setup中哪些可以不需要还没有完全搞清楚,当前这样没有问题1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
# Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
See the License for the specific language governing permissions and
limitations under the License.
THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
import setuptools
setuptools.setup(
name='myrpm',
version='0.1.1',
license='Apache License 2.0',
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Software Development :: Libraries :: Python Modules',
],
packages=['myrpm'],
include_package_data=True,
zip_safe=False,
platforms='any',
)目录结构
1
2
3
4
5python-myrpm/
├── myrpm
│ ├── __init__.py
│ └── myrpm.py
└── setup.py生成压缩包
在python-myrpm/目录下执行
1
python setup.py sdist
执行后目录如下 生成了myrpm-0.1.1.tar.gz压缩文件
感兴趣可以解压看看 我们就使用这个压缩文件作为源码构建RPM包1
2
3
4
5
6
7
8
9
10
11
12
13python-myrpm/
├── dist
│ └── myrpm-0.1.1.tar.gz
├── myrpm
│ ├── __init__.py
│ └── myrpm.py
├── myrpm.egg-info
│ ├── dependency_links.txt
│ ├── not-zip-safe
│ ├── PKG-INFO
│ ├── SOURCES.txt
│ └── top_level.txt
└── setup.py对应的还有一些其他命令,install是使用源码安装、build是构建、
clean是清理build和bdist生产的临时目录、bdist是生成二进制压缩包、
sdist是源码压缩包,–formats可以指定压缩包格式1
2
3
4python setup.py build
python setup.py install
python setup.py clean
python setup.py bdist制作SPEC文件
优先使用工具创建 在SPECS目录下执行如下命令 生成myrpm.spec文件
1
rpmdev-newspec myrpm.spec
修改SPEC文件如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37global debug_package %{nil}
Name: myrpm
Version: 0.1.1
Release: 1
Summary: simple python rpm
License: Apache-2.0
URL: https://docs.openstack.org/tooz/latest/
Source0: myrpm-0.1.1.tar.gz
BuildArch: noarch
BuildRequires: python3-setuptools
description
A simple python rpm
prep
autosetup -n %{name}-%{version}
build
py3_build
install
py3_install
pushd %{buildroot}
if [ -d usr/lib ]; then
find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst
fi
popd
mv %{buildroot}/filelist.lst .
files -n %{name} -f filelist.lst
dir %{python3_sitelib}/*
changelog
* Thu Sep 21 2023 XXX <XXX@gmail.com>
- init其中
%global debug_package %{nil} 是缺少debug相关文件 当前不关注使用该命令忽略其报错
Source0填充包名
%prep 填充%autosetup -n %{name}-%{version}
%build 填充%py3_build
%install 填充%py3_install
pushd 这里是把最终会安装在系统的文件写入到filelist.lst中
%file 是指明哪些文件会安装在系统,如果有遗漏,构建是会提示
‘error: Installed (but unpackaged) file(s) found’的报错
%license 和 %doc 当前不关注忽略对SPEC文件中更高级的修改需要进一步探索
构建RPM包
把第4步和第5步中的源码压缩包、SPEC文件分别放到SOURCE和SPECS目录下
1
2
3
4
5
6
7
8~/rpmbuild
├── BUILD
├── RPMS
├── SOURCES
│ └── myrpm-0.1.1.tar.gz
├── SPECS
│ └── myrpm.spec
└── SRPMS在SPECS目录下执行rpmbuild命令
1
rpmbuild -ba myrpm.spec
构建成功后使用如下命令查询结果
1
2
3
4
5
6tree /root/rpmbuild/*RPMS
/root/rpmbuild/RPMS
└── noarch
└── myrpm-0.1.1-1.noarch.rpm
/root/rpmbuild/SRPMS
└── myrpm-0.1.1-1.src.rpmRPM包使用
使用rpm -ivh
安装rpm包,安装后就可以import了
使用rpm -qa | grep查询安装的包
使用rpm -e卸载安装的包
当前发现卸载是会在/usr/lib/python3.9/site-packages/中残留__pycache__文件夹
暂时无法解决,试了下别的包也有这个问题
3.增量构建RPM包
增量构建可能描述的不准确,实际上是以git.patch的形式添加自己对已有RPM包的修改,然后构建
这种构建要使用源码包
RPM包一般分为二进制和源码包(后缀为.src.rpm)
包名中noarch字段表示无环境依赖
源码包可以通过rpm2cpio命令解压.src.rpm的包得到
也可以找到相关的SPEC文件,通过URL获取对应的压缩包
以上一章节中构建的RPM包为例,更改my_print的打印内容
解压rpm包获取源码压缩包
1
2
3
4
5
6rpm2cpio myrpm-0.1.1-1.src.rpm | cpio -div -D srcrpm
tree
.
└── srcrpm
├── myrpm-0.1.1.tar.gz
└── myrpm.spec其中 -D 参数为指定解压的目录
解压源码
解压后进入到myrpm目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18tar -vxf myrpm-0.1.1.tar.gz
tree
srcrpm/
├── myrpm-0.1.1
│ ├── myrpm
│ │ ├── __init__.py
│ │ └── myrpm.py
│ ├── myrpm.egg-info
│ │ ├── dependency_links.txt
│ │ ├── not-zip-safe
│ │ ├── PKG-INFO
│ │ ├── SOURCES.txt
│ │ └── top_level.txt
│ ├── PKG-INFO
│ ├── setup.cfg
│ └── setup.py
├── myrpm-0.1.1.tar.gz
└── myrpm.spec生成git patch文件
当前在srcrpm/myrpm-0.1.1/myrpm目录,示例如下
- 选择要修改的文件初始化git仓
- 完成你的修改,且不要add
- git diff生成补丁文件
1
2
3
4
5
6
7
8
9
10git init
git add myrpm.py
git commit -m "init"
vi myrpm.py
git diff myrpm.py > myrpm.patch
tree
.
├── __init__.py
├── myrpm.patch
└── myrpm.py
修改SPEC文件
需要修改或者添加的字段如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34index 5869db2..cb7fcb8 100644
--- a/myrpm.spec
+++ b/myrpm.spec
@@ -1,12 +1,13 @@
Name: myrpm
Version: 0.1.1
-Release: 1
+Release: 2
Summary: simple python rpm
License: Apache-2.0
URL: https://docs.openstack.org/tooz/latest/
Source0: myrpm-0.1.1.tar.gz
+Patch01: myrpm.patch
BuildArch: noarch
BuildRequires: python3-setuptools
@@ -15,7 +16,7 @@ BuildRequires: python3-setuptools
A simple python rpm
prep
autosetup -n %{name}-%{version}
+%autosetup -n %{name}-%{version} -p1
build
@@ -38,5 +39,8 @@ mv %{buildroot}/filelist.lst .
changelog
+* Fri Sep 22 2023 xxx <xxx@gmail.com> - 0.1.1-2
+- change print content
+
* Thu Sep 21 2023 xxx <xxx@gmail.com> - 0.1.1-1构建
构建时将patch文件补充到SOURCES目录中,其他与上一章节相同
如果遇到’No file to patch. Skipping patch.’的报错
大概率是patch文件中的目录有问题
如当前示例中,patch文件中的目录为a/myrpm.py和b/myrpm.py
并且构建是会报错,将目录改为a/myrpm/myrpm.py和b/myrpm/myrpm.py即可
4.部分宏的对应值
宏 | 值 |
---|---|
%{_sysconfdir} | /etc |
%{_prefix} | /usr |
%{_exec_prefix} | %{_prefix} |
%{_bindir} | %{_exec_prefix}/bin |
%{_lib} | lib (lib64 on 64bit systems) |
%{_libdir} | %{_exec_prefix}/%{_lib} |
%{_libexecdir} | %{_exec_prefix}/libexec |
%{_sbindir} | %{_exec_prefix}/sbin |
%{_sharedstatedir} | /var/lib |
%{_datadir} | %{_prefix}/share |
%{_includedir} | %{_prefix}/include |
%{_oldincludedir} | /usr/include |
%{_infodir} | /usr/share/info |
%{_mandir} | /usr/share/man |
%{_localstatedir} | /var |
%{_topdir} | %{getenv:HOME}/rpmbuild |
%{_builddir} | %{_topdir}/BUILD |
%{_rpmdir} | %{_topdir}/RPMS |
%{_sourcedir} | %{_topdir}/SOURCES |
%{_specdir} | %{_topdir}/SPECS |
%{_srcrpmdir} | %{_topdir}/SRPMS |
%{_buildrootdir} | %{_topdir}/BUILDROOT |
%{_var} | /var |
%{_tmppath} | %{_var}/tmp |
%{_usr} | /usr |
%{_usrsrc} | %{_usr}/src |
%{_docdir} | %{_datadir}/doc |