7.4. rpmbuild - Build RPM Package(s)

安装rpmbuild,我们将使用它来制作rpm包

yum search rpm-build
yum install -y rpm-build
		

Debian: sudo apt-get install rpm

rpm 工作空间,默认是/usr/src/redhat/

		
mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}

echo "%_topdir /home/neo/rpmbuild" >> ~/.rpmmacros
echo "%packager Test User <test@example.com>" >> ~/.rpmmacros
cat ~/.rpmmacros

touch ~/rpmbuild/SPECS/package-1.0.spec
		
		

准备好你的文件包

tar zcvf %{name}-%{version}.tar.gz your_dir
		

编辑spec文件

		
vim ~/rpmbuild/SPECS/package-1.0.spec

Summary: My Test Package
Name: test
Version: 1.0
Release: 1.0
License: BSD
# group you want your package in, mostly for GUI package browsers
# some example groups used by vendors:
# http://www.rpmfind.net/linux/RPM/Groups.html
Group: Networking/Daemons
# your name for example
Packager: Neo Chen <openunix@163.com>
#
#Source: http://full.url.to.the/package/%{name}-%{version}.tar.gz
Source: %{name}-%{version}.tar.gz
# list all your patches here:
#Patch:
# list all packages required to build this package
#BuildRequires:
#Provides:
# list all packages that conflict with this one:
#BuildRoot: %{_tmppath}/%{name}-%{version}-build
BuildRoot: %{_tmppath}/%{name}-%{version}

####
# full length description
%description

description

#####
# this prepares a fresh build directory in ~/build/BUILD, useful macros here
# are:
# %setup - cleans any previous builds and untargzips the source
# %patch - applies patches
# any other commands here are executed as standard sh commands
%prep

%setup
#%patch


#####
# this tells rpmbuild how to build your package, rpmbuild runs it as a sh
# script
%build
#make

#####
# all the steps necessary to install your package into $RPM_BUILD_ROOT
# first step is to clear $RPM_BUILD_ROOT
%install
[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
cp -r ../* %{_tmppath}
#install all files under RPM_BUILD_ROOT
#make install DESTDIR=$RPM_BUILD_ROOT
# now you can remove uneeded stuff
#rm -f $RPM_BUILD_ROOT{_prefix}

#####
# NOTE: this section is optional
# commands run just before the package is installed
%pre
#/usr/sbin/useradd -c "test user" -r -s /bin/false -u 666 -d / neo 2> /dev/null

#####
# NOTE: this section is optional
# commands run before uninstalling the software
%preun
#/sbin/service test stop > /dev/null 2>&1
#/sbin/chkconfig --del test

#####
# NOTE: this section is optional
# commands run after installing the package
%post
#/sbin/chkconfig -add test
#touch /var/log/test

#####
# NOTE: this section is optional
# commands run after unistalling the package
%postun
#/sbin/service test stop
#/usr/sbin/userdel test

#####
# list all the files that are part of the package. If a file is not in the
# list rpmbuild won't put it in the package
# see below on how to automate the process of creating this list.
# some useful macros here:
# %doc /path/to/filename - installs filename into /path/to/filename and marks
# it as being documentation
# %config /etc/config_file - similar for configuration files
# %attr(mode, user, group) file - lets you specify file attributes applied
# during installation, use - if you want to use defaults
%files
#/usr/bin/test
#/usr/sbin/test
# this will package the dir and all directories inside it
#/example/of/a/dir
/srv/neo
# this will package only the 'dir' directory
#%dir /example/of/a/dir


#####
# document changes between package releases
%changelog

		
		

开始制作rpm文件

rpmbuild -ba ~/rpmbuild/SPECS/package-1.0.spec
		

查看你的rpm文件包含文件列表

rpm -qpl /usr/src/redhat/RPMS/x86_64/test-1.0-1.0.x86_64.rpm
/srv
/srv/bin
/srv/bin/console
/srv/bin/nodekeeper
/srv/etc
/srv/etc/commands.cfg
/srv/etc/nodekeeper.cfg
/srv/etc/protocol.cfg
/srv/logs
/srv/logs/nodekeeper.log
/srv/run
/srv/run/nodekeeper.pid
		

安装RPM

# rpm -Uvh --nodeps /tmp/test-1.0-1.0.x86_64.rpm
Preparing...                ########################################### [100%]
   1:test                   ########################################### [100%]
		

也可以使用 yum 安装

yum localinstall /tmp/test-1.0-1.0.x86_64.rpm
		

查看安装信息

		
# rpm -qi test
Name        : test                         Relocations: (not relocatable)
Version     : 1.0                               Vendor: (none)
Release     : 1.0                           Build Date: Wed 21 Sep 2011 05:50:54 PM CST
Install Date: Wed 21 Sep 2011 05:46:50 PM CST      Build Host: dev3.example.com
Group       : Networking/Daemons            Source RPM: test-1.0-1.0.src.rpm
Size        : 20373                            License: BSD
Signature   : (none)
Packager    : Neo Chen <openunix@163.com>
Summary     : My Test Package
Description :

description
		
		

是使用yum info 查看信息

# yum info test
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirrors.163.com
 * extras: mirrors.163.com
 * updates: mirrors.163.com
Installed Packages
Name       : test
Arch       : x86_64
Version    : 1.0
Release    : 1.0
Size       : 20 k
Repo       : installed
Summary    : My Test Package
License    : BSD
Description:
           : description
		

7.4.1. RPM_directory_macros

http://fedoraproject.org/wiki/Packaging/RPMMacros#RPM_directory_macros

			
%{_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

%{_initddir}          %{_sysconfdir}/rc.d/init.d

Note: On releases older than Fedora 10 (and EPEL), %{_initddir} does not exist. Instead, you should use the deprecated%{_initrddir} macro.
RPM directory macros
%{_topdir}            %{getenv:HOME}/rpmbuild

%{_builddir}          %{_topdir}/BUILD

%{_rpmdir}            %{_topdir}/RPMS

%{_sourcedir}         %{_topdir}/SOURCES

%{_specdir}           %{_topdir}/SPECS

%{_srcrpmdir}         %{_topdir}/SRPMS

%{_buildrootdir}      %{_topdir}/BUILDROOT

Note: On releases older than Fedora 10 (and EPEL), %{_buildrootdir} does not exist.
Build flags macros
%{_global_cflags}     -O2 -g -pipe

%{_optflags}          %{__global_cflags} -m32 -march=i386 -mtune=pentium4 # if redhat-rpm-config is installed

Other macros
%{_var}               /var

%{_tmppath}           %{_var}/tmp

%{_usr}               /usr

%{_usrsrc}            %{_usr}/src

%{_docdir}            %{_datadir}/doc
			
			

7.4.2. --define 专递模板变量

spec 文件中定义宏默认值

			
%define <variable> <value>
			
			

另一种是在外部传递变量值

rpmbuild -ba SPECS/bacula.spec --define "build_su110 1" --define "build_mysql4 1"
			

注意:当两种同时使用时,外部--define无法替代%define 的定义。

7.4.3. defattr

			
%defattr(-,root,root,-)		
			
			

7.4.4. GPG 签名

查看GPG证书

			
$ gpg --list-keys
/home/neo/.gnupg/pubring.gpg
----------------------------
pub   1024R/63268A35 2013-09-11
uid                  Neo Chen (netkiller) <netkiller@msn.com>
sub   1024R/F4F946F9 2013-09-11
			
			

设置 _gpg_name 宏,与上面查看结果需一致

			
cat << EOF >> ~/.rpmmacros
%_signature gpg
%_gpg_name Neo Chen (netkiller) <netkiller@msn.com>
%_gpgpath ~/.gnupg
%_gpgbin /usr/bin/gpg
EOF
			
			

建立RPM

rpmbuild --define "_topdir /path/to/macrodir" -bb --sign spec
			

如果你的证书有Passphrase,会提示你输入了密码。

Enter pass phrase:
Pass phrase is good.
			

7.4.5. 使用 CMake3 编译并创建RPM包

			
root@VM_7_221_centos ~/mysql-outfile-plugin % cat Outfile.spec 
Name: mysql-outfile-plugin		
Version: 1.0
Release:	1%{?dist}
Summary: MySQL outfile plugin	

Group: MySQL Database server
License: CC 3.0
URL: http://www.netkiller.cn	
Source0: https://github.com/netkiller/mysql-outfile-plugin/archive/v1.0.tar.gz

BuildRequires: cmake3 mysql-community-devel	
Requires: gcc	

%description


%prep
%setup -q


%build
cmake3 .
make %{?_smp_mflags}


%install
make install DESTDIR=%{buildroot}


%files
/usr/lib64/mysql/plugin/liboutfile.so
%doc



%changelog
			
			
			

7.4.6. FAQ

error: File /home/neo/rpmbuild/SOURCES/netkiller-docbook-1.0.1.tar.gz: No such file or directory

Source 定义的文件不存在,如果你需要忽略Source可以使用 %setup -T





原文出处:Netkiller 系列 手札
本文作者:陈景峯
转载请与作者联系,同时请务必标明文章原始出处和作者信息及本声明。

<think>我们遇到了一个在构建RPM时的错误。错误信息如下: ``` error: parse error in expression: 0%{rhel} >= 7 error: ^ error: /root/xq/did-vpp/build-root/rpmbuild/SPECS/vpp.spec:50: bad %if condition: 0%{rhel} >= 7 ``` 这个错误发生在`rpmbuild`过程中,具体是在解析spec文件(vpp.spec)的第50行时,条件判断`%if`后面的表达式`0%{rhel} >= 7`有语法错误。 ### 错误分析 在RPM的spec文件中,条件判断`%if`后面需要跟一个有效的表达式。这里的表达式是`0%{rhel} >= 7`。问题可能出在`%{rhel}`这个宏变量上。 1. **`%{rhel}`宏变量**:这个宏通常用于获取RHEL(Red Hat Enterprise Linux)的主版本号。但是,如果这个宏没有被定义,那么`%{rhel}`会被替换为空字符串,导致表达式变成`0 >= 7`,这在语法上是正确的(尽管逻辑上可能不是我们想要的)。然而,错误信息提示的是“parse error in expression”,说明在解析表达式时遇到了问题。 2. **表达式语法**:注意表达式中的空格。在错误信息中,表达式被写为`0%{rhel} >= 7`,其中`0%{rhel}`之间没有空格,这可能导致解析器将其视为一个整体(例如,如果`%{rhel}`被替换为数字,那么`0`和这个数字连在一起会形成一个新数字,比如如果`%{rhel}`是6,那么就是06,即6)。但是,如果`%{rhel}`未定义,那么表达式就变成了`0 >= 7`,这是合法的。 3. **错误位置**:错误信息指向了表达式中的空格位置(在`0`和`%{rhel}`之间),但实际上错误信息中的`^`指向了空格后面的位置。这可能是由于宏展开后造成的。 4. **可能的原因**:在构建环境中,`%{rhel}`宏可能没有被定义。当宏未定义时,在表达式中使用它会导致错误吗?实际上,在条件表达式中,如果宏未定义,它会被视为空字符串,然后整个表达式`0 >= 7`是合法的,但这里却出现了语法错误。 5. **另一种可能**:在spec文件中,条件判断的写法可能有误。正确的写法应该是: ``` %if 0%{?rhel} >= 7 ``` 这里使用了`%{?rhel}`,其中`?`表示如果宏`rhel`存在则展开,否则忽略(展开为空)。这样,如果`rhel`不存在,表达式就变成`0 >= 7`;如果存在,比如`rhel`为7,则变成`07 >= 7`(注意,这里07是八进制数,等于7,所以表达式成立)。但是,如果`rhel`不存在,那么表达式就是`0>=7`,这个表达式是false,但语法正确。 然而,在原始错误中,表达式写的是`0%{rhel} >= 7`,没有使用`?`。如果`rhel`未定义,那么`%{rhel}`会被替换为空字符串,表达式变成`0 >= 7`,这是合法的。但错误信息提示解析错误,所以可能是另一种情况:`%{rhel}`被替换成了非数字的字符串?比如,如果`rhel`被定义为字符串(而不是数字),那么表达式就会变成类似`0string >= 7`,这显然会导致语法错误。 ### 解决方案 我们需要检查spec文件第50行附近的条件判断。通常,为了安全地使用可能未定义的宏,我们应该使用条件宏展开(即加上`?`)。修改建议: 将原来的: ``` %if 0%{rhel} >= 7 ``` 修改为: ``` %if 0%{?rhel} >= 7 ``` 这样,如果`rhel`宏未定义,那么`%{?rhel}`会被替换为空,整个表达式变成`0>=7`(值为0),不会导致语法错误。 ### 操作步骤 1. 打开spec文件:`/root/xq/did-vpp/build-root/rpmbuild/SPECS/vpp.spec` 2. 找到第50行(或附近)的`%if 0%{rhel} >= 7`。 3. 将其修改为`%if 0%{?rhel} >= 7`。 4. 保存文件,然后重新运行rpmbuild命令。 ### 修改示例 假设原spec文件第50行是: ``` %if 0%{rhel} >= 7 ``` 修改为: ``` %if 0%{?rhel} >= 7 ``` ### 重新运行构建 重新运行之前失败的rpmbuild命令: ```bash rpmbuild -bb \ --define "_topdir /root/xq/did-vpp/build-root/rpmbuild" \ --define "_version 24.06.0" \ --define "_release 31~g52887ab33" \ /root/xq/did-vpp/build-root/rpmbuild/SPECS/vpp.spec ``` ### 注意事项 如果修改后仍然出现错误,可能需要检查构建环境中`%{rhel}`宏是否被正确定义。可以通过以下命令查看当前rpm宏变量: ```bash rpm --eval %{rhel} ``` 如果输出为空,说明未定义。此时,如果spec文件中还有其他地方依赖`%{rhel}`,可能需要设置它。在构建命令中,我们可以通过`--define`选项来定义宏,例如: ```bash rpmbuild -bb \ --define "_topdir /root/xq/did-vpp/build-root/rpmbuild" \ --define "_version 24.06.0" \ --define "_release 31~g52887ab33" \ --define "rhel 7" \ # 添加这一行,假设我们构建的目标是RHEL7 /root/xq/did-vpp/build-root/rpmbuild/SPECS/vpp.spec ``` 但是,请注意,我们不应该随意设置`rhel`宏的值,因为它应该由构建环境(比如在RHEL系统上构建)自动提供。如果构建环境不是RHEL或其衍生版(如CentOS),那么可能没有`rhel`宏。在这种情况下,我们可能需要根据实际情况调整spec文件中的条件判断。 ### 总结 我们通过修改spec文件中的条件判断表达式,使用`%{?rhel}`来避免宏未定义时的语法错误。如果问题依旧,可能需要进一步检查环境或spec文件的其他部分。 ### 相关问题 根据上述问题和解决方案,我们可以提出以下相关问题: §§相关问题§§: 1. RPM spec文件中条件判断`%if`的正确用法是什么? 2. 如何在RPM spec文件中安全地使用可能未定义的宏? 3. 在构建RPM时,如何查看和定义rpm宏变量? 4. 除了修改spec文件,还有哪些方法可以解决宏未定义导致的构建错误?</think>### 问题分析与解决方案 您遇到的错误是由于 RPM spec 文件中的条件判断语法问题导致的。具体错误信息: ``` error: parse error in expression: 0%{rhel} >= 7 error: /root/xq/did-vpp/build-root/rpmbuild/SPECS/vpp.spec:50: bad %if condition: 0%{rhel} >= 7 ``` #### 原因分析: 1. **宏变量未定义**:`%{rhel}` 宏变量在构建环境中未定义,导致表达式 `0%{rhel}` 被解析为空或无效值 2. **语法问题**:RPM spec 文件的条件判断 (`%if`) 要求严格语法,未定义的宏会引发解析错误 3. **平台兼容性**:该条件判断尝试检查 RHEL 版本,但在非 RHEL 系统上构建时 `%{rhel}` 宏不存在 #### 解决方案: 修改 spec 文件,使用更健壮的条件判断语法。以下是修复步骤: 1. 打开 spec 文件: ```bash nano /root/xq/did-vpp/build-root/rpmbuild/SPECS/vpp.spec ``` 2. 找到第 50 行附近的 `%if 0%{rhel} >= 7` 语句 3. 修改为以下更安全的语法: ```diff - %if 0%{rhel} >= 7 + %if 0%{?rhel} >= 7 ``` #### 完整修复方案: ```bash # 1. 备份原spec文件 cp /root/xq/did-vpp/build-root/rpmbuild/SPECS/vpp.spec{,.bak} # 2. 使用sed修复条件判断 sed -i 's/%if 0%{rhel} >= 7/%if 0%{?rhel} >= 7/' \ /root/xq/did-vpp/build-root/rpmbuild/SPECS/vpp.spec # 3. 重新运行构建命令 cd /root/xq/did-vpp make pkg-rpm ``` #### 关键修改说明: - `%{?rhel}` 中的 `?` 表示: - 如果 `rhel` 宏存在则展开其值 - 如果不存在则展开为空字符串 - `0%{?rhel}` 的处理结果: - RHEL 系统:`07` (RHEL7) 或 `08` (RHEL8) → 有效数字 - 非 RHEL 系统:`0` → 仍为有效数字表达式 - 避免宏未定义导致的语法错误 #### 替代方案(如果问题依旧): 如果上述修改仍不生效,可以完全绕过版本检查: ```diff - %if 0%{rhel} >= 7 + %if 1 ``` 这将无条件启用该代码块,适用于非生产环境构建。 ### 完整构建命令示例 ```bash # 清理之前的构建 rm -rf /root/xq/did-vpp/build-root/rpmbuild # 重新设置目录结构 mkdir -p /root/xq/did-vpp/build-root/rpmbuild/{RPMS,SRPMS,BUILD,SOURCES,SPECS} # 复制源文件和spec文件 cp /root/xq/did-vpp/build-root/vpp-24.06.0-31~g52887ab33.tar.xz \ /root/xq/did-vpp/build-root/rpmbuild/SOURCES/ cp /root/xq/did-vpp/extras/rpm/vpp.spec \ /root/xq/did-vpp/build-root/rpmbuild/SPECS/ # 应用修复(确保已修改spec文件) sed -i 's/%if 0%{rhel} >= 7/%if 0%{?rhel} >= 7/' \ /root/xq/did-vpp/build-root/rpmbuild/SPECS/vpp.spec # 执行构建 rpmbuild -bb \ --define "_topdir /root/xq/did-vpp/build-root/rpmbuild" \ --define "_version 24.06.0" \ --define "_release 31~g52887ab33" \ /root/xq/did-vpp/build-root/rpmbuild/SPECS/vpp.spec ``` ### 预防性建议: 1. 在 spec 文件中始终使用 `%{?macro_name}` 语法引用可能未定义的宏 2. 添加宏存在性检查: ```rpm %if ! %{defined rhel} %define rhel 0 %endif %if 0%{?rhel} >= 7 ``` 3. 使用 `rpm --eval` 调试宏值: ```bash rpm --eval %{rhel} # 检查当前环境的RHEL版本宏 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值