The RPM ecosystem, software packaging and spec file – build your first package

Software engineering in the Enterprise Linux family: RPM, software packaging and the spec file

In this guide we’ll present, how packages for the business industry-leading systems from the Enterprise Linux family are being prepared. They consist of, among others, Red Hat Enterprise Linux, Oracle Linux, EuroLinux and CentOS. We’ll elaborate on how the packages’ structure looks internally and how one can easily prepare a specification for them.

The more an enterprise grows and the more employees are being hired, the bigger the need for standardization and having a centralized source of truth. It’s a digital system for storing the goodies a required for a unified environment the employees utilize. That source can, in practice, differ depending on a profession. Nevertheless, the concept is identical:

  • a spreadsheet that can be accessed with a browser, which the accounting department uses to cooperate on a document in real-time
  • a personal organizer for a manager used to track tasks and how much time they took
  • a software delivery source used on employees’ workstations.

The last point is worth a closer examination. Since workstations can differ on their configuration, an ecosystem that guarantees a correct installation and operation of the aforementioned software is necessary. Today we’ll discuss the one that EuroLinux uses – RPM.

Why RPM?

RPM has been designed to solve the system-wide software management challenges of the current day and age. We’re talking about the challenges of both the end-users and the engineers that build software and deliver it as packages. As a result we get an ecosystem that consists of the merits below.


RPM delivers an automated update of a complete operating system or individual software packages, without requiring an interruption of the running programs. Custom settings created by a user are preserved after an update for the new software releases.

Rich query language

RPM exposes parameters that allow us to lookup packages, individual files they provide, as well as package dependencies in its database. When in doubt, one can easily and quickly locate the information needed and resolve the doubts.

Upstream sources

One of the more important aspects for software engineers is the fact that RPM packages contain software sources, which have been prepared by upstream (the original authors). An engineer can add a package building specification or their own patches in separate files and deliver a ready-made product in the form of such package.

How to build your own package?

We’ll show you how to create your own binary RPM package based on the sources EuroLinux offers.


  • RPM – an ecosystem that covers a wide spectrum of building and delivering software for the Enterprise Linux system family
  • RPM Package – a file containing other files and metadata that allow it to track dependencies, versions and installation localization, among others.

We distinguish the following terms:

  • source RPM – a package with the upstream software sources along with a specification and patches provided by an engineer
  • binary RPM – a package prepared for an end-user with prebuilt software
  • .spec file – a file containing a specification of how to build software and pack it as a binary RPM
  • RPM macro – a text in a .spec file that will be substituted for a different text in the building process, based on its previous definition.

For example, EuroLinux 8 defines the %{dist} macro as .el8, while EuroLinux 7 as .el7. Depending on the target system release, that macro will be expanded so the final text contains a release number.

Workspace configuration

1. Let’s install the development tools that are required to build a binary RPM from a source RPM.

[[email protected] ~]$ sudo dnf groupinstall -y "Development Tools"
[[email protected] ~]$ sudo dnf install -y rpmdevtools

2. Let’s prepare the directories used by RPM ecosystem as an engineer’s workspace.

[[email protected] ~]$ rpmdev-setuptree

Some packages will require additional development headers as part of their building process. Their installation is covered below as a part of an example.

Building a package

As part of this example, we’ll rebuild an RPM package with a program named mc. We’ll redefine the *%{dist}* macro mentioned earler, build and install a binary RPM and query the system database. This will make us sure the package with the new name has been installed in the system.

1. We download a source RPM and extract its content.

[[email protected] ~]$ wget
[[email protected] ~]$ rpm2cpio mc-4.8.19-9.el8.src.rpm | cpio -idmv -D ~/rpmbuild/SOURCES

2. We edit the *.spec file so we can insert our new macro in there.

[[email protected] ~]$ vim ~/rpmbuild/SOURCES/*.spec
[[email protected] ~]$ grep --line-number -H '.moje_nowe_makro' ~/rpmbuild/SOURCES/*.spec
/home/vagrant/rpmbuild/SOURCES/mc.spec:1:%define dist .moje_nowe_makro

3. We build a binary RPM.

[[email protected] ~]$ sudo dnf install -y yum-utils
[[email protected] ~]$ cd ~/rpmbuild/SOURCES/
[[email protected] SOURCES]$ sudo yum-builddep *.spec
[[email protected] SOURCES]$ rpmbuild -ba *.spec
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.3WFDye
Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.WybFHi
Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.9pLeii
Executing(%doc): /bin/sh -e /var/tmp/rpm-tmp.CQKTkg
Executing(%license): /bin/sh -e /var/tmp/rpm-tmp.txVO3h
Wrote: /home/vagrant/rpmbuild/SRPMS/mc-4.8.19-9.moje_nowe_makro.src.rpm
Wrote: /home/vagrant/rpmbuild/RPMS/x86_64/mc-4.8.19-9.moje_nowe_makro.x86_64.rpm
Wrote: /home/vagrant/rpmbuild/RPMS/x86_64/mc-debugsource-4.8.19-9.moje_nowe_makro.x86_64.rpm
Wrote: /home/vagrant/rpmbuild/RPMS/x86_64/mc-debuginfo-4.8.19-9.moje_nowe_makro.x86_64.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.eNphog
+ umask 022
+ cd /home/vagrant/rpmbuild/BUILD
+ cd mc-4.8.19
+ /usr/bin/rm -rf /home/vagrant/rpmbuild/BUILDROOT/mc-4.8.19-9.moje_nowe_makro.x86_64
+ exit 0

4. We can see that both source RPMs (in the directory /home/vagrant/rpmbuild/SRPMS) and binary RPMs (in the directory /home/vagrant/rpmbuild/RPMS) have been written. Let’s install the binary RPM we just rebuilt.

[[email protected] ~]$ sudo rpm --install /home/vagrant/rpmbuild/RPMS/x86_64/mc-4.8.19-9.moje_nowe_makro.x86_64.rpm

5. Let’s query the system RPM database.

[vagra[email protected] ~]$ rpm -qa mc

6. Let’s also witness our new macro being injected inside mc’s binary as a curiosity.

[[email protected] ~]$ strings $(which mc) | grep -A3 -B3 moje_nowe_makro


We have presented how easy it is to prepare a workspace of an engineer responsible for building and delivering a package for the RPM ecosystem in the example above. As a result, that package is now ready to be deployed to a company’s central source of truth and installed by other employees. A company can create its own software modifications this way, which will be applied to workspaces, after the procedure above has finished.