學習 RPM 打包

說明如何在 Fedora 21 或更新的系統上對最簡單的 project - hello (無外部相依) 進行打包.

安裝 rpm 開發相關工具

$ sudo dnf install fedora-packager @development-tools

將自己加到 mock 群中

$ sudo usermod -a -G mock derekdai

產生工作目錄

$ rpmdev-setuptree

上面的指令會在 ~/ 下產生一個叫 rpmbuild 的目錄

$ ls rpmbuild/
BUILD  BUILDROOT  RPMS  SOURCES  SPECS  SRPMS

接下來, 準備我們的 source code, 建立 SOURCES/hello-1.0/

$ cd rpmbuild/SOURCES
$ mkdir hello-1.0

hello-1.0/ 下保存以下檔案

/* hello.c */
#include <stdio.h>

int main()
{
        printf("hello\n");

        return 0;
}
# Makefile
all: hello

hello: hello.o

hello.o: hello.c

.PHONY: clean
clean:
rm -rf hello hello.o

接著產生 tar 包

$ tar zcvpf hello-1.0.tar.gz hello-1.0

有了 hello-1.0.tar.gz, 就可以產生 .spec 檔的模板了

$ cd ../SPECS
$ rpmdev-newspec hello
$ cat hello.spec
Name:           hello
Version:        
Release:        1%{?dist}
Summary:        

License:        
URL:            
Source0:        

BuildRequires:  
Requires:       

%description


%prep
%setup -q


%build
%configure
make %{?_smp_mflags}


%install
rm -rf $RPM_BUILD_ROOT
%make_install


%files
%doc



%changelog
* Thu Sep 24 2015 Derek Dai
- 

試 build 看能否通過

$ rpmbuild -ba hello.spec 
error: line 2: Empty tag: Version:

看起來有幾個資訊必給, 修改 hello.spec

...
Version:        1.0
Release:        1%{?dist}
Summary:        Say hello to world

License:        GPLv3
URL:            http://no.upstream.im
Source0:        http://no.upstream.im/hello-1.0.tar.gz

#BuildRequires:
#Requires:

Version 指的是 upstream 的版本, Release 是指 rpm 打包的版本. Sammary 的第一個字母一定要大小, 不然會有 warning. Source0 的最後如果跟 tar 包名字相同 (hello-1.0.tar.gz) 則不用另外指定 archive 檔名.

再試 build 看看

$ rpmbuild -ba hello.spec 
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.9d19xj
+ umask 022
+ cd /home/derekdai/rpmbuild/BUILD
+ cd /home/derekdai/rpmbuild/BUILD
+ rm -rf hello-1.0
+ /usr/bin/gzip -dc /home/derekdai/rpmbuild/SOURCES/hello-1.0.tar.gz
+ /usr/bin/tar -xf -
+ STATUS=0
+ '[' 0 -ne 0 ']'
+ cd hello-1.0
+ /usr/bin/chmod -Rf a+rX,u+w,g-w,o-w .
+ exit 0
Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.4XUqDb
+ umask 022
+ cd /home/derekdai/rpmbuild/BUILD
+ cd hello-1.0
+ CFLAGS='-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches  -m64 -mtune=generic'
+ export CFLAGS
+ CXXFLAGS='-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches  -m64 -mtune=generic'
+ export CXXFLAGS
+ FFLAGS='-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches  -m64 -mtune=generic -I/usr/lib64/gfortran/modules'
+ export FFLAGS
+ FCFLAGS='-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches  -m64 -mtune=generic -I/usr/lib64/gfortran/modules'
+ export FCFLAGS
+ LDFLAGS='-Wl,-z,relro '
+ export LDFLAGS
+ '[' 1 = 1 ']'
++ find . -name config.guess -o -name config.sub
+ '[' 1 = 1 ']'
+ '[' x '!=' x ']'
+ ./configure --build=x86_64-redhat-linux-gnu --host=x86_64-redhat-linux-gnu --program-prefix= --disable-dependency-tracking --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --sysconfdir=/etc --datadir=/usr/share --includedir=/usr/include --libdir=/usr/lib64 --libexecdir=/usr/libexec --localstatedir=/var --sharedstatedir=/var/lib --mandir=/usr/share/man --infodir=/usr/share/info
/var/tmp/rpm-tmp.4XUqDb: line 44: ./configure: No such file or directory
error: Bad exit status from /var/tmp/rpm-tmp.4XUqDb (%build)


RPM build errors:
    Bad exit status from /var/tmp/rpm-tmp.4XUqDb (%build)

在執行 configure 時失敗了, 嗯~ 本來我們就只有簡單的 Makefile, 去掉這行試試

...
%configure
...

再試 build

...
+ /usr/bin/make install DESTDIR=/home/derekdai/rpmbuild/BUILDROOT/hello-1.0-1.fc21.x86_64
make: *** No rule to make target 'install'.  Stop.
error: Bad exit status from /var/tmp/rpm-tmp.hn1Er4 (%install)


RPM build errors:
    Bad exit status from /var/tmp/rpm-tmp.hn1Er4 (%install)

執行到 make install 時失敗, 因為我們的 Makefile 只有 build & clean 的部份, 修改後的內容如下

# Makefile
all: hello

hello: hello.o

hello.o: hello.c

install:
        /usr/bin/install -d $(DESTDIR)/usr/bin
        /usr/bin/install hello $(DESTDIR)/usr/bin

.PHONY: clean
clean:
        rm -rf hello hello.o

一般在 make install 時通常可傳入 DESTDIR 變量指定安全路徑的 prefix, 所以我們在安裝路徑前加上了 $(DESTDIR). 重新產生 SOURCES/hello-1.0.tar.gz, 再試 build

...
Processing files: hello-1.0-1.fc21.x86_64
Processing files: hello-debuginfo-1.0-1.fc21.x86_64
Checking for unpackaged file(s): /usr/lib/rpm/check-files /home/derekdai/rpmbuild/BUILDROOT/hello-1.0-1.fc21.x86_64
error: Installed (but unpackaged) file(s) found:
   /usr/bin/hello


RPM build errors:
    Installed (but unpackaged) file(s) found:
   /usr/bin/hello

這是因為我們沒有在 hello.spec 中指明會安裝進系統的檔案清單. hello 會裝到 /usr/bin 目錄下, 但 hardcode 路徑不是好的做法, .spec 檔中可改用變量 %{_bindir}, 修改如下

...
%file
%{_bindir}/hello

%doc
...

試 build

$ rpmbuild -ba hello.spec 
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.Rh1JXQ
+ umask 022
+ cd /home/derekdai/rpmbuild/BUILD
+ cd /home/derekdai/rpmbuild/BUILD
+ rm -rf hello-1.0
+ /usr/bin/gzip -dc /home/derekdai/rpmbuild/SOURCES/hello-1.0.tar.gz
+ /usr/bin/tar -xf -
+ STATUS=0
+ '[' 0 -ne 0 ']'
+ cd hello-1.0
+ /usr/bin/chmod -Rf a+rX,u+w,g-w,o-w .
+ exit 0
Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.BFJA61
+ umask 022
+ cd /home/derekdai/rpmbuild/BUILD
+ cd hello-1.0
+ make -j4
cc    -c -o hello.o hello.c
cc   hello.o   -o hello
+ exit 0
Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.PIDlqd
+ umask 022
+ cd /home/derekdai/rpmbuild/BUILD
+ '[' /home/derekdai/rpmbuild/BUILDROOT/hello-1.0-1.fc21.x86_64 '!=' / ']'
+ rm -rf /home/derekdai/rpmbuild/BUILDROOT/hello-1.0-1.fc21.x86_64
++ dirname /home/derekdai/rpmbuild/BUILDROOT/hello-1.0-1.fc21.x86_64
+ mkdir -p /home/derekdai/rpmbuild/BUILDROOT
+ mkdir /home/derekdai/rpmbuild/BUILDROOT/hello-1.0-1.fc21.x86_64
+ cd hello-1.0
+ rm -rf /home/derekdai/rpmbuild/BUILDROOT/hello-1.0-1.fc21.x86_64
+ /usr/bin/make install DESTDIR=/home/derekdai/rpmbuild/BUILDROOT/hello-1.0-1.fc21.x86_64
/usr/bin/install -d /home/derekdai/rpmbuild/BUILDROOT/hello-1.0-1.fc21.x86_64/usr/bin
/usr/bin/install hello /home/derekdai/rpmbuild/BUILDROOT/hello-1.0-1.fc21.x86_64/usr/bin
+ /usr/lib/rpm/find-debuginfo.sh --strict-build-id -m --run-dwz --dwz-low-mem-die-limit 10000000 --dwz-max-die-limit 110000000 /home/derekdai/rpmbuild/BUILD/hello-1.0
extracting debug info from /home/derekdai/rpmbuild/BUILDROOT/hello-1.0-1.fc21.x86_64/usr/bin/hello
dwz: Too few files for multifile optimization
/usr/lib/rpm/sepdebugcrcfix: Updated 0 CRC32s, 1 CRC32s did match.
+ '[' '%{buildarch}' = noarch ']'
+ QA_CHECK_RPATHS=1
+ case "${QA_CHECK_RPATHS:-}" in
+ /usr/lib/rpm/check-rpaths
+ /usr/lib/rpm/check-buildroot
+ /usr/lib/rpm/brp-compress
+ /usr/lib/rpm/brp-strip-static-archive /usr/bin/strip
+ /usr/lib/rpm/brp-python-bytecompile /usr/bin/python 1
+ /usr/lib/rpm/brp-python-hardlink
+ /usr/lib/rpm/redhat/brp-java-repack-jars
Processing files: hello-1.0-1.fc21.x86_64
Provides: hello = 1.0-1.fc21 hello(x86-64) = 1.0-1.fc21
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(FileDigests) <= 4.6.0-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Requires: libc.so.6()(64bit) libc.so.6(GLIBC_2.2.5)(64bit) rtld(GNU_HASH)
Processing files: hello-debuginfo-1.0-1.fc21.x86_64
Checking for unpackaged file(s): /usr/lib/rpm/check-files /home/derekdai/rpmbuild/BUILDROOT/hello-1.0-1.fc21.x86_64
Wrote: /home/derekdai/rpmbuild/SRPMS/hello-1.0-1.fc21.src.rpm
Wrote: /home/derekdai/rpmbuild/RPMS/x86_64/hello-1.0-1.fc21.x86_64.rpm
Wrote: /home/derekdai/rpmbuild/RPMS/x86_64/hello-debuginfo-1.0-1.fc21.x86_64.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.Z7vGMp
+ umask 022
+ cd /home/derekdai/rpmbuild/BUILD
+ cd hello-1.0
+ /usr/bin/rm -rf /home/derekdai/rpmbuild/BUILDROOT/hello-1.0-1.fc21.x86_64
+ exit 0

過啦! 確認下

$ ls ../RPMS/x86_64/
hello-1.0-1.fc21.x86_64.rpm  hello-debuginfo-1.0-1.fc21.x86_64.rpm

試安裝

$ sudo dnf install ../RPMS/x86_64/hello-1.0-1.fc21.x86_64.rpm 
Fedora 21 - x86_64 - Updates                                                                                                                 951 kB/s |  22 MB     00:23    
Using metadata from Tue Sep 22 13:12:46 2015 (2 days, 4:47:13 hours old)
Dependencies resolved.
=============================================================================================================================================================================
 Package                               Arch                                   Version                                     Repository                                    Size
=============================================================================================================================================================================
Installing:
 hello                                 x86_64                                 1.0-1.fc21                                  @commandline                                 8.7 k

Transaction Summary
=============================================================================================================================================================================
Install  1 Package

Total size: 8.7 k
Installed size: 7.0 k
Is this ok [y/N]: y
Downloading Packages:
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Installing  : hello-1.0-1.fc21.x86_64                                                                                                                                  1/1 
  Verifying   : hello-1.0-1.fc21.x86_64                                                                                                                                  1/1 

Installed:
  hello.x86_64 1.0-1.fc21                                                                                                                                                    

Complete!

執行看看

$ which hello
/usr/bin/hello
$ hello
hello

移除

$ sudo dnf remove hello
Dependencies resolved.
=============================================================================================================================================================================
 Package                                Arch                                    Version                                       Repository                                Size
=============================================================================================================================================================================
Removing:
 hello                                  x86_64                                  1.0-1.fc21                                    @System                                  7.0 k

Transaction Summary
=============================================================================================================================================================================
Remove  1 Package

Installed size: 7.0 k
Is this ok [y/N]: y
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Erasing     : hello-1.0-1.fc21.x86_64                                                                                                                                  1/1 
  Verifying   : hello-1.0-1.fc21.x86_64                                                                                                                                  1/1 

Removed:
  hello.x86_64 1.0-1.fc21                                                                                                                                                    

Complete!
$ which hello
/usr/bin/which: no hello in (/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/derekdai/.local/bin:/home/derekdai/bin)

參考資料