Tuesday, February 26, 2019

How to create / build an rpm package in CentOS / Redhat Linux


RPM - is RPM package manager. Formerly known as Redhat package manager. It is the standard package management system for Redhat Linux distributions. The files manageable by rpm will have an extension of '.rpm'. It is also used in other Linux operating systems like CentOS, Fedora, Oracle Linux and some versions of IBM AIX.

So if we need a new software to be installed on the mentioned linux systems, we download the rpm package for the software and its dependencies and install it like
# rpm -ivh package_name.rpm
Well. If we are a software developer and we want to package our software as rpm? How do we create a rpm file? In this post we will learn how to build rpm package and understanding rpmbuild spec file.

In this example we will create a simple rpm which will install a single script "HelloWorld" which will give output  "Hello World! from HelloWorld RPM." when it is executed. yeah. That simple.

For building the rpm, we need a few softwares to be installed. We can install these using yum.
# yum install rpm-build
# yum install redhat-rpm-config
# yum install rpmdevtools
You need to create the rpm as a normal user. NOT as ROOT user. If you create rpm as root user, it will not create rpm, it will just install the software in your system.
[root@development ~]# adduser build
[root@development ~]# sudo su - build
[build@development ~]$
Once we install all the dependencies, we need to run the following command. It will create the necessary folder structure to put our source code, configuration files etc. 
[build@development ~]$ rpmdev-setuptree
It will create the folder structure in the home directory under the directory named rpmbuild. When you list the files in the directory you can see the following directories.
[build@development ~]$ ls
[build@development ~]$ cd rpmbuild/
[build@development rpmbuild]$ ls
Now we need to create the spec file for the rpm. Spec file is the main configuration file for building the rpm. We need to create the spec file under the SPECS directory inside rpmbuild.
[build@development rpmbuild]$ cd SPECS/
[build@development SPECS]$ ls
[build@development SPECS]$
Currently this directory is empty.

We will now create the spec file using the command rpmdev-newspec.
[build@development SPECS]$ rpmdev-newspec HelloWorld
HelloWorld.spec created; type minimal, rpm version >= 4.11.
We can see that a brand new spec file is created.
[build@development SPECS]$ ls
[build@development SPECS]$
We need to edit this file according to our needs. There are a lot of fields. But we will use only the fields we requires in the spec.
[build@development SPECS]$ cat HelloWorld.spec
Name:           HelloWorld
Version:        1.0
Release:        1%{?dist}
Summary:     Installs the HelloWorld script to print "Hello World! from HelloWorld RPM."
License:        GPL - 3
URL:             https://www.linuxhelp.in
Source0:        HelloWorld
Installs the HelloWorld script
mkdir -p %{buildroot}/usr/bin/
install -m 755 HelloWorld %{buildroot}/usr/bin/HelloWorld
%attr(0755, root, root) /usr/bin/HelloWorld
[build@development SPECS]$
We have to  keep the script to be installed with the rpm under the directory SOURCES in rpmuild.
[build@development SPECS]$cd ..
[build@development rpmbuild]$ cd SOURCES/
[build@development SOURCES]$ ls
[root@development ~]# cat rpmbuild/SOURCES/HelloWorld
echo "Hello World! from HelloWorld RPM."
[root@development ~]#
Now we will run the command to create the rpm.
[build@development SPECS]$ rpmbuild -ba HelloWorld.spec
Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.VKHbKH
+ umask 022
+ cd /home/build/rpmbuild/BUILD
+ '[' /home/build/rpmbuild/BUILDROOT/HelloWorld-1.0-1.el7.x86_64 '!=' / ']'
+ rm -rf /home/build/rpmbuild/BUILDROOT/HelloWorld-1.0-1.el7.x86_64
++ dirname /home/build/rpmbuild/BUILDROOT/HelloWorld-1.0-1.el7.x86_64
+ mkdir -p /home/build/rpmbuild/BUILDROOT
+ mkdir /home/build/rpmbuild/BUILDROOT/HelloWorld-1.0-1.el7.x86_64
+ mkdir -p /home/build/rpmbuild/BUILDROOT/HelloWorld-1.0-1.el7.x86_64/usr/bin/
+ install -m 755 HelloWorld /home/build/rpmbuild/BUILDROOT/HelloWorld-1.0-1.el7.x86_64/usr/bin/HelloWorld
+ '[' '%{buildarch}' = noarch ']'
+ case "${QA_CHECK_RPATHS:-}" in
+ /usr/lib/rpm/check-rpaths
+ /usr/lib/rpm/check-buildroot
+ /usr/lib/rpm/redhat/brp-compress
+ /usr/lib/rpm/redhat/brp-strip /usr/bin/strip
+ /usr/lib/rpm/redhat/brp-strip-comment-note /usr/bin/strip /usr/bin/objdump
+ /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: HelloWorld-1.0-1.el7.x86_64
Provides: HelloWorld = 1.0-1.el7 HelloWorld(x86-64) = 1.0-1.el7
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(FileDigests) <= 4.6.0-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Checking for unpackaged file(s): /usr/lib/rpm/check-files /home/build/rpmbuild/BUILDROOT/HelloWorld-1.0-1.el7.x86_64
Wrote: /home/build/rpmbuild/SRPMS/HelloWorld-1.0-1.el7.src.rpm
Wrote: /home/build/rpmbuild/RPMS/x86_64/HelloWorld-1.0-1.el7.x86_64.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.lSteSm
+ umask 022
+ cd /home/build/rpmbuild/BUILD
+ /usr/bin/rm -rf /home/build/rpmbuild/BUILDROOT/HelloWorld-1.0-1.el7.x86_64
+ exit 0
[build@development SPECS]$
The command has exited with exit status 0. It means all right.

We will get the created rpm in the RPMS directory under rpmbuild
[build@development rpmbuild]$ cd RPMS/
[build@development RPMS]$ ls
[build@development RPMS]$ cd x86_64/
[build@development x86_64]$ ls
Here the RPM is created under x86_64 because we didn't specify any architecture, it took the current system architecture.

We can check what are the files included in the rpm.
[build@development x86_64]$ rpm -qpl HelloWorld-1.0-1.el7.x86_64.rpm
Lets install it.
[root@development ~]# rpm -ivh /tmp/HelloWorld-1.0-1.el7.x86_64.rpm
Preparing...                          ################################# [100%]
Updating / installing...
   1:HelloWorld-1.0-1.el7             ################################# [100%]
Checking if the script is installed:
[root@development ~]# ll /usr/bin/HelloWorld
-rwxr-xr-x. 1 root root 52 Feb 26 13:12 /usr/bin/HelloWorld
Checking the source of the script file. 
[root@development ~]# rpm -qf /usr/bin/HelloWorld
Now running the command to check the result.
[root@development ~]# /usr/bin/HelloWorld
Hello World! from HelloWorld RPM.
All good. That is it. Now create your own rpms and let me know if  you have any queries.

1 comment:

  1. A better approach will be to spin up a docker container, and build there. So that you don't have to worry about the dependencies in your system mess up the build process.


Be nice. That's all.