How to build a signed rpm from scratch by building a source archive using Red Hat Linux

Below explains every field of an rpm in detail

Understanding an rpm package

There are two types of RPM packages:

  • source RPM (SRPM)
  • binary RPM

SRPMs and binary RPMs share the file format and tooling, but have different contents and serve different purposes. An SRPM contains source code, optionally patches to it, and a SPEC file, which describes how to build the source code into a binary RPM. A binary RPM contains the binaries built from the sources and patches.

1. Build Directory Layout

Install necessary rpms which will be used along the way for building our rpm

# yum install rpmdevtools rpm-build rpmsign

To set up a directory layout that is the RPM packaging workspace, use the rpmdev-setuptree utility

# rpmdev-setuptree

Next validate the directory structure

# tree /tmp/rpmbuild/
/tmp/rpmbuild/
├── BUILD
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS

5 directories, 0 files

Below image explains each of the directory and its usage

So now our directory structure is ready, lets start preparing our spec file

2. Create SPEC file

To know in detail about the various arguments used in the spec file follow below link
https://docs.fedoraproject.org/quick-docs/en-US/creating-rpm-packages.html

# vim /tmp/rpmbuild/SPECS/deepak.spec
Name:                   deepak
Summary:                Test Rpm

Version:                1.0.0
Release:                1

Group:                  GoLinuxHub
License:                Not Applicable
URL:                    https://www.golinuxhub.com
SOURCE0:                %{name}-%{version}-%{release}.tar.gz
BuildRoot:              %{_tmppath}/%{name}-%{version}-%{release}-root

%description
This is a test rpm built by Deepak

%prep
%setup -q

%build
#Empty

%install
rm -rf %{buildroot}
mkdir -p %{buildroot}
cp -a * %{buildroot}

%clean
rm -rf %{buildroot}

%files
%defattr(-,root,root,-)
/test1/file1
/test2/file2

%changelog
* Wed Feb 03 2016 Deepak Prasad - 1.0.0-1
- Created first draft

3. Create Source Directory and Content

Now it is time to create our source directory content which we want to get dumped once the rpm is installed.
Since this is a test rpm I will name it "deepak" and I will create some dummy directories and files which will be part of this rpm.

# cd /tmp

Below will be our source directory with base release number of 1.0.0

# mkdir deepak-1.0.0

Next lets create some dummy files and directories

# mkdir -p deepak-1.0.0/test1/file1
# mkdir -p deepak-1.0.0/test2/file2

4. Create archive file with source content

Create an archive with the above content with a format using planned version and release, for example my spec file contains below

Version:                1.0.0
Release:                1

So my archive name would be deepak-1.0.0-1.tar.gz

# cd /tmp
# tar -czvf /tmp/rpmbuild/SOURCES/deepak-1.0.0-1.tar.gz deepak-1.0.0/*

5. Build RPM

We are all done here, time to build our rpm

NOTE: If you have created your source directories in a different path other than home folder of the user then there are chances that rpmbuild will fail with below error
# rpmbuild -ba deepak.spec
error: File /root/rpmbuild/SOURCES/deepak-1.0.0-1.tar.gz: No such file or directory

Follow below article to change the rpmbuild directory

How to change rpmbuild (_tmppath) in a spec file (rpmbuild ignored directory) Linux

# rpmbuild -ba /tmp/rpmbuild/SPECS/deepak.spec
Executing(%prep): /bin/sh -e /tmp/rpmbuild/tmp/rpm-tmp.p63FqV
+ umask 022
+ cd /tmp/rpmbuild/BUILD
+ cd /tmp/rpmbuild/BUILD
+ rm -rf deepak-1.0.0
+ /usr/bin/gzip -dc /tmp/rpmbuild/SOURCES/deepak-1.0.0-1.tar.gz
+ /usr/bin/tar -xf -
+ STATUS=0
+ '[' 0 -ne 0 ']'
+ cd deepak-1.0.0
+ /usr/bin/chmod -Rf a+rX,u+w,g-w,o-w .
+ exit 0
Executing(%build): /bin/sh -e /tmp/rpmbuild/tmp/rpm-tmp.Oekwnu
+ umask 022
+ cd /tmp/rpmbuild/BUILD
+ cd deepak-1.0.0
+ exit 0
Executing(%install): /bin/sh -e /tmp/rpmbuild/tmp/rpm-tmp.My9Zk3
+ umask 022
+ cd /tmp/rpmbuild/BUILD
+ '[' /tmp/rpmbuild/BUILDROOT/deepak-1.0.0-1.x86_64 '!=' / ']'
+ rm -rf /tmp/rpmbuild/BUILDROOT/deepak-1.0.0-1.x86_64
++ dirname /tmp/rpmbuild/BUILDROOT/deepak-1.0.0-1.x86_64
+ mkdir -p /tmp/rpmbuild/BUILDROOT
+ mkdir /tmp/rpmbuild/BUILDROOT/deepak-1.0.0-1.x86_64
+ cd deepak-1.0.0
+ rm -rf /tmp/rpmbuild/BUILDROOT/deepak-1.0.0-1.x86_64
+ mkdir -p /tmp/rpmbuild/BUILDROOT/deepak-1.0.0-1.x86_64
+ cp -a test1 test2 /tmp/rpmbuild/BUILDROOT/deepak-1.0.0-1.x86_64
+ /usr/lib/rpm/find-debuginfo.sh --strict-build-id -m --run-dwz --dwz-low-mem-die-limit 10000000 --dwz-max-die-limit 110000000 /tmp/rpmbuild/BUILD/deepak-1.0.0
/usr/lib/rpm/sepdebugcrcfix: Updated 0 CRC32s, 0 CRC32s did match.
+ /usr/lib/rpm/check-buildroot
+ /usr/lib/rpm/redhat/brp-compress
+ /usr/lib/rpm/redhat/brp-strip-static-archive /usr/bin/strip
+ /usr/lib/rpm/brp-python-bytecompile /usr/bin/python 1
+ /usr/lib/rpm/redhat/brp-python-hardlink
+ /usr/lib/rpm/redhat/brp-java-repack-jars
Processing files: deepak-1.0.0-1.x86_64
Provides: deepak = 1.0.0-1 deepak(x86-64) = 1.0.0-1
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(FileDigests) <= 4.6.0-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Processing files: deepak-debuginfo-1.0.0-1.x86_64
Provides: deepak-debuginfo = 1.0.0-1 deepak-debuginfo(x86-64) = 1.0.0-1
Requires(rpmlib): rpmlib(FileDigests) <= 4.6.0-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1 rpmlib(CompressedFileNames) <= 3.0.4-1
Checking for unpackaged file(s): /usr/lib/rpm/check-files /tmp/rpmbuild/BUILDROOT/deepak-1.0.0-1.x86_64
Wrote: /tmp/rpmbuild/SRPMS/deepak-1.0.0-1.src.rpm
Wrote: /tmp/rpmbuild/RPMS/x86_64/deepak-1.0.0-1.x86_64.rpm
Wrote: /tmp/rpmbuild/RPMS/x86_64/deepak-debuginfo-1.0.0-1.x86_64.rpm
Executing(%clean): /bin/sh -e /tmp/rpmbuild/tmp/rpm-tmp.OipO2Y
+ umask 022
+ cd /tmp/rpmbuild/BUILD
+ cd deepak-1.0.0
+ rm -rf /tmp/rpmbuild/BUILDROOT/deepak-1.0.0-1.x86_64
+ exit 0

All went well and our rpm is placed at

/tmp/rpmbuild/RPMS/x86_64/deepak-1.0.0-1.x86_64.rpm

Let us check the content of our rpm

# rpm -qlp /tmp/rpmbuild/RPMS/x86_64/deepak-1.0.0-1.x86_64.rpm
/test1/file1
/test2/file2

which is as we planned

6. Sign the rpm

Below article explains in detail with

Step by Step Guide on how to sign a key using gpg key (password or password-less) to an rpm in Linux

7. Install and Validate the rpm

Time to install the rpm

# rpm -ivh /tmp/rpmbuild/RPMS/x86_64/deepak-1.0.0-1.x86_64.rpm
Preparing...                          ################################# [100%]
Updating / installing...
   1:deepak-1.0.0-1                   ################################# [100%]

Below command will tell us the content of the rpm again

# rpm -ql deepak
/test1/file1
/test2/file2

Below command will query and give more information about our rpm

# rpm -qpi /tmp/rpmbuild/RPMS/x86_64/deepak-1.0.0-1.x86_64.rpm
Name        : deepak
Version     : 1.0.0
Release     : 1
Architecture: x86_64
Install Date: (not installed)
Group       : GoLinuxHub
Size        : 0
License     : Not Applicable
Signature   : (none)
Source RPM  : deepak-1.0.0-1.src.rpm
Build Date  : Sat 12 May 2018 11:50:43 PM IST
Build Host  : golinuxhub-server.example
Relocations : (not relocatable)
URL         : https://www.golinuxhub.com
Summary     : Test Rpm
Description :
This is a test rpm built by Deepak

I hope the article was useful.