Packaging and distributing software
Packaging software by using the RPM package management system
Abstract
Providing feedback on Red Hat documentation Copy linkLink copied to clipboard!
We appreciate your feedback on our documentation. Let us know how we can improve it.
Submitting feedback through Jira (account required)
- Log in to the Jira website.
- Click Create in the top navigation bar.
- Enter a descriptive title in the Summary field.
- Enter your suggestion for improvement in the Description field. Include links to the relevant parts of the documentation.
- Click Create at the bottom of the dialogue.
Chapter 1. Introduction to RPM Copy linkLink copied to clipboard!
The RPM Package Manager (RPM) is a package management system that runs on Red Hat Enterprise Linux (RHEL), CentOS, and Fedora. You can use RPM to distribute, manage, and update software that you create for any of these operating systems.
The RPM package management system has the following advantages over distributing software in conventional archive files:
- RPM manages software in the form of packages that you can install, update, or remove independently of each other, which makes the maintenance of an operating system easier.
- RPM simplifies the distribution of software because RPM packages are standalone binary files, similar to compressed archives. These packages are built for a specific operating system and hardware architecture. RPMs contain files such as compiled executables and libraries that are placed into the appropriate paths on the filesystem when the package is installed.
With RPM, you can perform the following tasks:
- Install, upgrade, and remove packaged software.
- Query detailed information about packaged software.
- Verify the integrity of packaged software.
- Build your own packages from software sources and complete build instructions.
- Digitally sign your packages by using the GNU Privacy Guard (GPG) utility.
- Publish your packages in a YUM repository.
In Red Hat Enterprise Linux, RPM is fully integrated into the higher-level package management software, such as YUM or PackageKit. Although RPM provides its own command-line interface, most users need to interact with RPM only through this software. However, when building RPM packages, you must use the RPM utilities such as rpmbuild(8)
.
1.1. RPM packages Copy linkLink copied to clipboard!
An RPM package consists of an archive of files and metadata used to install and erase these files. Specifically, the RPM package contains the following parts:
- GPG signature
- The GPG signature is used to verify the integrity of the package.
- Header (package metadata)
- The RPM package manager uses this metadata to determine package dependencies, where to install files, and other information.
- Payload
-
The payload is a
cpio
archive that contains files to install to the system.
There are two types of RPM packages. Both types share the file format and tooling, but have different contents and serve different purposes:
Source RPM (SRPM)
An SRPM contains source code and a
spec
file, which describes how to build the source code into a binary RPM. Optionally, the SRPM can contain patches to source code.Binary RPM
A binary RPM contains the binaries built from the sources and patches.
1.2. Listing RPM packaging utilities Copy linkLink copied to clipboard!
In addition to the rpmbuild(8)
program for building packages, RPM provides other utilities to make the process of creating packages easier. You can find these programs in the rpmdevtools
package.
Prerequisites
The
rpmdevtools
package has been installed:yum install rpmdevtools
# yum install rpmdevtools
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Procedure
Use one of the following methods to list RPM packaging utilities:
To list certain utilities provided by the
rpmdevtools
package and their short descriptions, enter:rpm -qi rpmdevtools
$ rpm -qi rpmdevtools
Copy to Clipboard Copied! Toggle word wrap Toggle overflow To list all utilities, enter:
rpm -ql rpmdevtools | grep ^/usr/bin
$ rpm -ql rpmdevtools | grep ^/usr/bin
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Chapter 2. Creating software for RPM packaging Copy linkLink copied to clipboard!
To prepare software for RPM packaging, you must understand what source code is and how to create software from it.
2.1. What is source code Copy linkLink copied to clipboard!
Source code is human-readable instructions to the computer that describe how to perform a computation. Source code is expressed by using a programming language.
The following versions of the Hello World
program written in three different programming languages cover major RPM Package Manager use cases:
Hello World
written in BashThe bello project implements
Hello World
in Bash. The implementation contains only thebello
shell script. The purpose of this program is to outputHello World
on the command line.The
bello
file has the following contents:#!/bin/bash printf "Hello World\n"
#!/bin/bash printf "Hello World\n"
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Hello World
written in PythonThe pello project implements
Hello World
in Python. The implementation contains only thepello.py
program. The purpose of the program is to outputHello World
on the command line.The
pello.py
file has the following contents:#!/usr/bin/python3 print("Hello World")
#!/usr/bin/python3 print("Hello World")
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Hello World
written in CThe cello project implements
Hello World
in C. The implementation contains only thecello.c
andMakefile
files. The resultingtar.gz
archive therefore has two files in addition to theLICENSE
file. The purpose of the program is to outputHello World
on the command line.The
cello.c
file has the following contents:Copy to Clipboard Copied! Toggle word wrap Toggle overflow
The packaging process is different for each version of the Hello World
program.
2.2. Methods of creating software Copy linkLink copied to clipboard!
You can convert the human-readable source code into machine code by using one the following methods:
- Natively compile software.
- Interpret software by using a language interpreter or language virtual machine. You can either raw-interpret or byte-compile software.
2.2.1. Natively compiled software Copy linkLink copied to clipboard!
Natively compiled software is software written in a programming language that compiles to machine code with a resulting binary executable file. Natively compiled software is standalone software.
Natively compiled RPM packages are architecture-specific.
If you compile such software on a computer that uses a 64-bit (x86_64) AMD or Intel processor, it does not run on a 32-bit (x86) AMD or Intel processor. The resulting package has the architecture specified in its name.
2.2.2. Interpreted software Copy linkLink copied to clipboard!
Some programming languages, such as Bash or Python, do not compile to machine code. Instead, a language interpreter or a language virtual machine executes the programs' source code step-by-step without prior transformations.
Software written entirely in interpreted programming languages is not architecture-specific. Therefore, the resulting RPM package has the noarch
string in its name.
You can either raw-interpret or byte-compile software written in interpreted languages:
Raw-interpreted software
You do not need to compile this type of software. Raw-interpreted software is directly executed by the interpreter.
Byte-compiled software
You must first compile this type of software into bytecode, which is then executed by the language virtual machine.
NoteSome byte-compiled languages can be either raw-interpreted or byte-compiled.
Note that the way you build and package software by using RPM is different for these two software types.
2.3. Building software from source Copy linkLink copied to clipboard!
During the software building process, the source code is turned into software artifacts that you can package by using RPM.
2.3.1. Building software from natively compiled code Copy linkLink copied to clipboard!
You can build software written in a compiled language into an executable by using one of the following methods:
- Manual building
- Automated building
2.3.1.1. Manually building a sample C program Copy linkLink copied to clipboard!
You can use manual building to build software written in a compiled language.
A sample Hello World
program written in C (cello.c
) has the following contents:
Procedure
Invoke the C compiler from the GNU Compiler Collection to compile the source code into binary:
gcc -g -o cello cello.c
$ gcc -g -o cello cello.c
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Run the resulting binary
cello
:./cello
$ ./cello Hello World
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
2.3.1.2. Setting up automated building for a sample C program Copy linkLink copied to clipboard!
Large-scale software commonly uses automated building. You can set up automated building by creating the Makefile
file and then running the GNU make
utility.
Procedure
Create the
Makefile
file with the following content in the same directory ascello.c
:Copy to Clipboard Copied! Toggle word wrap Toggle overflow Note that the lines under
cello:
,clean:
, andinstall:
must begin with a tabulation character (tab).Build the software:
make
$ make make: 'cello' is up to date.
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Because a build is already available in the current directory, enter the
make clean
command, and then enter themake
command again:make clean make
$ make clean rm cello $ make gcc -g -o cello cello.c
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Note that trying to build the program again at this point has no effect because the GNU
make
system detects the existing binary:make
$ make make: 'cello' is up to date.
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Run the program:
./cello
$ ./cello Hello World
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
2.3.2. Interpreting source code Copy linkLink copied to clipboard!
You can convert the source code written in an interpreted programming language into machine code by using one of the following methods:
Byte-compiling
The procedure for byte-compiling software varies depending on the following factors:
- Programming language
- Language’s virtual machine
Tools and processes used with that language
NoteYou can byte-compile software written, for example, in Python. Python software intended for distribution is often byte-compiled, but not in the way described in this document. The described procedure aims not to conform to the community standards, but to be simple. For real-world Python guidelines, see Software Packaging and Distribution.
You can also raw-interpret Python source code. However, the byte-compiled version is faster. Therefore, RPM packagers prefer to package the byte-compiled version for distribution to end users.
Raw-interpreting
Software written in shell scripting languages, such as Bash, is always executed by raw-interpreting.
2.3.2.1. Byte-compiling a sample Python program Copy linkLink copied to clipboard!
By choosing byte-compiling over raw-interpreting of Python source code, you can create faster software.
A sample Hello World
program written in the Python programming language (pello.py
) has the following contents:
print("Hello World")
print("Hello World")
Procedure
Byte-compile the
pello.py
file:python -m compileall pello.py
$ python -m compileall pello.py
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Verify that a byte-compiled version of the file is created:
ls __pycache__
$ ls __pycache__ pello.cpython-311.pyc
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Note that the package version in the output might differ depending on which Python version is installed.
Run the program in
pello.py
:python pello.py
$ python pello.py Hello World
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
2.3.2.2. Raw-interpreting a sample Bash program Copy linkLink copied to clipboard!
A sample Hello World
program written in Bash shell built-in language (bello
) has the following contents:
#!/bin/bash printf "Hello World\n"
#!/bin/bash
printf "Hello World\n"
The shebang (#!
) sign at the top of the bello
file is not part of the programming language source code.
Use the shebang to turn a text file into an executable. The system program loader parses the line containing the shebang to get a path to the binary executable, which is then used as the programming language interpreter.
Procedure
Make the file with source code executable:
chmod +x bello
$ chmod +x bello
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Run the created file:
./bello
$ ./bello Hello World
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Chapter 3. Preparing software for RPM packaging Copy linkLink copied to clipboard!
To prepare a piece of software for packaging with RPM, you can first patch the software, create a LICENSE file for it, and archive it as a tarball.
3.1. Patching software Copy linkLink copied to clipboard!
When packaging software, you might need to make certain changes to the original source code, such as fixing a bug or changing a configuration file. In RPM packaging, you can instead leave the original source code intact and apply patches on it.
A patch is a piece of text that updates a source code file. The patch has a diff format, because it represents the difference between two versions of the text. You can create a patch by using the diff
utility, and then apply the patch to the source code by using the patch
utility.
Software developers often use Version Control Systems such as Git to manage their code base. Such tools offer their own methods of creating diffs or patching software.
3.1.1. Creating a patch file for a sample C program Copy linkLink copied to clipboard!
You can create a patch from the original source code by using the diff
utility. For example, to patch a Hello world
program written in C (cello.c
), complete the following steps.
Prerequisites
You installed the
diff
utility on your system:yum install diffutils
# yum install diffutils
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Procedure
Back up the original source code:
cp -p cello.c cello.c.orig
$ cp -p cello.c cello.c.orig
Copy to Clipboard Copied! Toggle word wrap Toggle overflow The
-p
option preserves mode, ownership, and timestamps.Modify
cello.c
as needed:Copy to Clipboard Copied! Toggle word wrap Toggle overflow Generate a patch:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Lines that start with
+
replace the lines that start with-
.NoteUsing the
Naur
options with thediff
command is recommended because it fits the majority of use cases:-N
(--new-file
)The
-N
option handles absent files as empty files.-a
(--text
)The
-a
option treats all files as text. As a result, thediff
utility does not ignore the files it classified as binaries.-u
(-U NUM
or--unified[=NUM]
)The
-u
option returns output in the form of output NUM (default 3) lines of unified context. This is a compact and an easily readable format commonly used in patch files.-r
(--recursive
)The
-r
option recursively compares any subdirectories that thediff
utility found.
However, note that in this particular case, only the
-u
option is necessary.Save the patch to a file:
diff -Naur cello.c.orig cello.c > cello.patch
$ diff -Naur cello.c.orig cello.c > cello.patch
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Restore the original
cello.c
:mv cello.c.orig cello.c
$ mv cello.c.orig cello.c
Copy to Clipboard Copied! Toggle word wrap Toggle overflow ImportantYou must retain the original
cello.c
because the RPM package manager uses the original file, not the modified one, when building an RPM package. For more information, see Working with spec files.
3.1.2. Patching a sample C program Copy linkLink copied to clipboard!
To apply code patches on your software, you can use the patch
utility.
Prerequisites
You installed the
patch
utility on your system:yum install patch
# yum install patch
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - You created a patch from the original source code. For instructions, see Creating a patch file for a sample C program.
Procedure
The following steps apply a previously created cello.patch
file on the cello.c
file.
Redirect the patch file to the
patch
command:patch < cello.patch
$ patch < cello.patch patching file cello.c
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Check that the contents of
cello.c
now reflect the desired change:Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Verification
Build the patched
cello.c
program:make
$ make gcc -g -o cello cello.c
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Run the built
cello.c
program:./cello
$ ./cello Hello World from my very first patch!
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
3.2. Creating a LICENSE file Copy linkLink copied to clipboard!
It is recommended that you distribute your software with a software license.
A software license file informs users of what they can and cannot do with a source code. Having no license for your source code means that you retain all rights to this code and no one can reproduce, distribute, or create derivative works from your source code.
Procedure
Create the
LICENSE
file with the required license statement:vim LICENSE
$ vim LICENSE
Copy to Clipboard Copied! Toggle word wrap Toggle overflow The following is an example content of the LICENSE file:
Example 3.1. Example GPLv3
LICENSE
file textCopy to Clipboard Copied! Toggle word wrap Toggle overflow
3.3. Creating a source code archive for distribution Copy linkLink copied to clipboard!
An archive file is a file with the .tar.gz
or .tgz
suffix. Putting source code into the archive is a common way to release the software to be later packaged for distribution.
3.3.1. Creating a source code archive for a sample Bash program Copy linkLink copied to clipboard!
The bello project is a Hello World
file in Bash.
The following example contains only the bello
shell script. Therefore, the resulting tar.gz
archive has only one file in addition to the LICENSE
file.
The patch
file is not distributed in the archive with the program. The RPM package manager applies the patch when the RPM is built. The patch will be placed into the ~/rpmbuild/SOURCES/
directory together with the tar.gz
archive.
Prerequisites
-
Assume that the
0.1
version of thebello
program is used. - You have configured the packaging workspace. For more information, see Configuring RPM packaging workspace.
-
You created a
LICENSE
file. For instructions, see Creating a LICENSE file.
Procedure
Move all required files into a single directory:
mkdir bello-0.1 mv bello bello-0.1/ mv LICENSE bello-0.1/
$ mkdir bello-0.1 $ mv bello bello-0.1/ $ mv LICENSE bello-0.1/
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Create the archive for distribution:
tar -cvzf bello-0.1.tar.gz bello-0.1
$ tar -cvzf bello-0.1.tar.gz bello-0.1 bello-0.1/ bello-0.1/LICENSE bello-0.1/bello
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Move the created archive to the
~/rpmbuild/SOURCES/
directory, which is the default directory where therpmbuild
command stores the files for building packages:mv bello-0.1.tar.gz ~/rpmbuild/SOURCES/
$ mv bello-0.1.tar.gz ~/rpmbuild/SOURCES/
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
3.3.2. Creating a source code archive for a sample C program Copy linkLink copied to clipboard!
The cello project is a Hello World
file in C.
The following example contains only the cello.c
and the Makefile
files. Therefore, the resulting tar.gz
archive has two files in addition to the LICENSE
file.
The patch
file is not distributed in the archive with the program. The RPM package manager applies the patch when the RPM is built. The patch will be placed into the ~/rpmbuild/SOURCES/
directory together with the tar.gz
archive.
Prerequisites
-
Assume that the
1.0
version of thecello
program is used. - You have configured the packaging workspace. For more information, see Configuring RPM packaging workspace.
-
You created a
LICENSE
file. For instructions, see Creating a LICENSE file.
Procedure
Move all required files into a single directory:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Create the archive for distribution:
tar -cvzf cello-1.0.tar.gz cello-1.0
$ tar -cvzf cello-1.0.tar.gz cello-1.0 cello-1.0/ cello-1.0/Makefile cello-1.0/cello.c cello-1.0/LICENSE
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Move the created archive to the
~/rpmbuild/SOURCES/
directory, which is the default directory where therpmbuild
command stores the files for building packages:mv cello-1.0.tar.gz ~/rpmbuild/SOURCES/
$ mv cello-1.0.tar.gz ~/rpmbuild/SOURCES/
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Chapter 4. Packaging software Copy linkLink copied to clipboard!
In the following sections, learn the basics of the packaging process with the RPM package manager.
4.1. Setting up RPM packaging workspace Copy linkLink copied to clipboard!
To build RPM packages, you must first create a special workspace that consists of directories used for different packaging purposes.
4.1.1. Configuring RPM packaging workspace Copy linkLink copied to clipboard!
To configure the RPM packaging workspace, you can set up a directory layout by using the rpmdev-setuptree
utility.
Prerequisites
You installed the
rpmdevtools
package, which provides utilities for packaging RPMs:yum install rpmdevtools
# yum install rpmdevtools
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Procedure
Run the
rpmdev-setuptree
utility:Copy to Clipboard Copied! Toggle word wrap Toggle overflow
4.1.2. RPM packaging workspace directories Copy linkLink copied to clipboard!
The following are the RPM packaging workspace directories created by using the rpmdev-setuptree
utility:
Directory | Purpose |
---|---|
|
Contains build artifacts compiled from the source files from the |
|
Binary RPMs are created under the |
|
Contains compressed source code archives and patches. The |
|
Contains |
|
When you use the |
4.2. About spec files Copy linkLink copied to clipboard!
A spec
file is a file with instructions that the rpmbuild
utility uses to build an RPM package. This file provides necessary information to the build system by defining instructions in a series of sections. These sections are defined in the Preamble and the Body part of the spec
file:
- The Preamble section contains a series of metadata items that are used in the Body section.
- The Body section represents the main part of the instructions.
4.2.1. Preamble items Copy linkLink copied to clipboard!
The following are some of the directives that you can use in the Preamble section of the RPM spec
file.
Directive | Definition |
---|---|
|
A base name of the package that must match the |
| An upstream version number of the software. |
| The number of times the version of the package was released.
Set the initial value to |
| A brief one-line summary of the package. |
| A license of the software being packaged.
The exact format for how to label the |
| A full URL for more information about the software, for example, an upstream project website for the software being packaged. |
| A path or URL to the compressed archive of the unpatched upstream source code. This link must point to an accessible and reliable storage of the archive, for example, the upstream page, not the packager’s local storage.
You can define multiple |
| A name of the first patch to apply to the source code, if necessary.
You can apply the
You can apply the patches individually by using the |
| An architecture that the software will be built for.
If the software is not architecture-dependent, for example, if you wrote the software entirely in an interpreted programming language, set the value to |
|
A comma- or whitespace-separated list of packages required to build the program written in a compiled language. There can be multiple entries of |
|
A comma- or whitespace-separated list of packages required by the software to run once installed. There can be multiple entries of |
|
If a piece of software cannot operate on a specific processor architecture, you can exclude this architecture in the |
|
A comma- or whitespace-separated list of packages that must not be installed on the system in order for your software to function properly when installed. There can be multiple entries of |
|
The
|
|
If you add the |
The Name
, Version
, and Release
(NVR) directives comprise the file name of the RPM package in the name-version-release
format.
You can display the NVR information for a specific package by querying RPM database by using the rpm
command, for example:
rpm -q bash
# rpm -q bash
bash-4.4.19-7.el8.x86_64
Here, bash
is the package name, 4.4.19
is the version, and 7.el8
is the release. The x86_64
marker is the package architecture. Unlike NVR, the architecture marker is not under direct control of the RPM packager, but is defined by the rpmbuild
build environment. The exception to this is the architecture-independent noarch
package.
4.2.2. Body items Copy linkLink copied to clipboard!
The following are the items used in the Body section of the RPM spec
file.
Directive | Definition |
---|---|
| A full description of the software packaged in the RPM. This description can span multiple lines and can be broken into paragraphs. |
|
A command or series of commands to prepare the software for building, for example, for unpacking the archive in the |
| A command or series of commands for building the software into machine code (for compiled languages) or bytecode (for some interpreted languages). |
|
A command or series of commands that the
The
Note that |
| A command or series of commands for testing the software, for example, unit tests. |
| A list of files, provided by the RPM package, to be installed in the user’s system and their full path location on the system.
During the build, if there are files in the
Within the |
|
A record of changes that happened to the package between different |
4.2.3. Advanced items Copy linkLink copied to clipboard!
A spec
file can contain advanced items, such as Scriptlets or Triggers.
Scriptlets and Triggers take effect at different points during the installation process on the end user’s system, not the build process.
4.3. BuildRoots Copy linkLink copied to clipboard!
In the context of RPM packaging, buildroot
is a chroot environment. The build artifacts are placed here by using the same file system hierarchy as the future hierarchy in the end user’s system, with buildroot
acting as the root directory. The placement of build artifacts must comply with the file system hierarchy standard of the end user’s system.
The files in buildroot
are later put into a cpio
archive, which becomes the main part of the RPM. When RPM is installed on the end user’s system, these files are extracted in the root
directory, preserving the correct hierarchy.
The rpmbuild
program has its own defaults. Overriding these defaults can cause certain issues. Therefore, avoid defining your own value of the buildroot
macro. Use the default %{buildroot}
macro instead.
4.4. RPM macros Copy linkLink copied to clipboard!
An rpm macro is a straight text substitution that can be conditionally assigned based on the optional evaluation of a statement when certain built-in functionality is used. Therefore, RPM can perform text substitutions for you.
For example, you can define Version of the packaged software only once in the %{version}
macro, and use this macro throughout the spec
file. Every occurrence is automatically substituted by Version that you defined in the macro.
If you see an unfamiliar macro, you can evaluate it with the following command:
rpm --eval %{MACRO}
$ rpm --eval %{MACRO}
For example, to evaluate the %{_bindir}
and %{_libexecdir}
macros, enter:
rpm --eval %{_bindir} rpm --eval %{_libexecdir}
$ rpm --eval %{_bindir}
/usr/bin
$ rpm --eval %{_libexecdir}
/usr/libexec
4.5. Working with spec files Copy linkLink copied to clipboard!
To package new software, you must create a spec
file. You can create the spec
file either of the following ways:
-
Write the new
spec
file manually from scratch. -
Use the
rpmdev-newspec
utility. This utility creates an unpopulatedspec
file, where you fill the necessary directives and fields.
Some programmer-focused text editors pre-populate a new spec
file with their own spec
template. The rpmdev-newspec
utility provides an editor-agnostic method.
4.5.1. Creating a new spec file for sample Bash, Python, and C programs Copy linkLink copied to clipboard!
You can create a spec
file for each of the three implementations of the Hello World!
program by using the rpmdev-newspec
utility.
Prerequisites
The following
Hello World!
program implementations were placed into the~/rpmbuild/SOURCES
directory:
Procedure
Navigate to the
~/rpmbuild/SPECS
directory:cd ~/rpmbuild/SPECS
$ cd ~/rpmbuild/SPECS
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Create a
spec
file for each of the three implementations of theHello World!
program:Copy to Clipboard Copied! Toggle word wrap Toggle overflow ImportantWhen packaging a Python project into RPM, always add the
python-
prefix to the original name of the project. The project name here isPello
and, therefore, the name of thespec
ispython-pello
.The
~/rpmbuild/SPECS/
directory now contains threespec
files namedbello.spec
,cello.spec
, andpython-pello.spec
.Examine the created files.
The directives in the files represent those described in About spec files. In the following sections, you will populate particular section in the output files of
rpmdev-newspec
.
4.5.2. Modifying an original spec file Copy linkLink copied to clipboard!
The original output spec
file generated by the rpmdev-newspec
utility represents a template that you must modify to provide necessary instructions for the rpmbuild
utility. rpmbuild
then uses these instructions to build an RPM package.
Prerequisites
-
The unpopulated
~/rpmbuild/SPECS/<name>.spec
spec
file was created by using therpmdev-newspec
utility. For more information, see Creating a new spec file for sample Bash, Python, and C programs.
Procedure
-
Open the
~/rpmbuild/SPECS/<name>.spec
file provided by therpmdev-newspec
utility. Populate the following directives of the
spec
file Preamble section:Name
-
Name
was already specified as an argument torpmdev-newspec
. Version
-
Set
Version
to match the upstream release version of the source code. Release
-
Release
is automatically set to1%{?dist}
, which is initially1
. Summary
- Enter a one-line explanation of the package.
License
- Enter the software license associated with the source code.
URL
-
Enter the URL to the upstream software website. For consistency, utilize the
%{name}
RPM macro variable and use thehttps://example.com/%{name}
format. Source
Enter the URL to the upstream software source code. Link directly to the software version being packaged.
NoteThe example URLs in this documentation include hard-coded values that could possibly change in the future. Similarly, the release version can change as well. To simplify these potential future changes, use the
%{name}
and%{version}
macros. By using these macros, you need to update only one field in thespec
file.BuildRequires
- Specify build-time dependencies for the package.
Requires
- Specify run-time dependencies for the package.
BuildArch
- Specify the software architecture.
Populate the following directives of the
spec
file Body section. You can think of these directives as section headings, because these directives can define multi-line, multi-instruction, or scripted tasks to occur.%description
- Enter the full description of the software.
%prep
- Enter a command or series of commands to prepare software for building.
%build
- Enter a command or series of commands for building software.
%install
-
Enter a command or series of commands that instruct the
rpmbuild
command on how to install the software into theBUILDROOT
directory. %files
- Specify the list of files, provided by the RPM package, to be installed on your system.
%changelog
Enter the list of datestamped entries for each
Version-Release
of the package.Start the first line of the
%changelog
section with an asterisk (*
) character followed byDay-of-Week Month Day Year Name Surname <email> - Version-Release
.For the actual change entry, follow these rules:
- Each change entry can contain multiple items, one for each change.
- Each item starts on a new line.
-
Each item begins with a hyphen (
-
) character.
You have now written an entire spec
file for the required program.
4.5.3. An example spec file for a sample Bash program Copy linkLink copied to clipboard!
You can use the following example spec
file for the bello program written in bash for your reference.
An example spec file for the program written in bash
-
The
BuildRequires
directive, which specifies build-time dependencies for the package, was deleted because there is no building step forbello
. Bash is a raw interpreted programming language, and the files are just installed to their location on the system. -
The
Requires
directive, which specifies run-time dependencies for the package, includes onlybash
, because thebello
script requires only thebash
shell environment to execute. -
The
%autosetup
macro unpacks the source archive, referred to by theSource0
directive, and changes to it. -
The
%build
section, which specifies how to build the software, is blank, because thebash
script does not need to be built.
To install bello
, you must create the destination directory and install the executable bash
script file there. Therefore, you can use the install
command in the %install
section. You can use RPM macros to do this without hardcoding paths.
4.5.4. An example spec file for a sample Python program Copy linkLink copied to clipboard!
You can use the following example spec
file for the pello program written in the Python programming language for your reference.
An example spec file for the pello program written in Python
The
Requires
directive, which specifies run-time dependencies for the package, includes two packages:-
The
python
package required to execute the byte-compiled code at runtime. -
The
bash
package required to execute the small entry-point script.
-
The
-
The
BuildRequires
directive, which specifies build-time dependencies for the package, includes only thepython
package. Thepello
program requirespython
to perform the byte-compile build process. -
The
%build
section, which specifies how to build the software, creates a byte-compiled version of the script. Note that in real-world packaging, it is usually done automatically, depending on the distribution used. -
The
%install
section corresponds to the fact that you must install the byte-compiled file into a library directory on the system so that it can be accessed.
This example of creating a wrapper script in-line in the spec
file shows that the spec
file itself is scriptable. This wrapper script executes the Python byte-compiled code by using the here document
.
4.5.5. An example spec file for a sample C program Copy linkLink copied to clipboard!
You can use the following example spec
file for the cello program that was written in the C programming language for your reference.
An example spec file for the program written in C
The
BuildRequires
directive, which specifies build-time dependencies for the package, includes the following packages required to perform the compilation build process:-
gcc
-
make
-
-
The
Requires
directive, which specifies run-time dependencies for the package, is omitted in this example. All runtime requirements are handled byrpmbuild
, and thecello
program does not require anything outside of the core C standard libraries. -
The
%autosetup
macro unpacks the source archive, referred to by theSource0
directive, and changes to it. -
The
%build
section reflects that in this example, theMakefile
file for the cello program was written. Therefore, you can use the GNU make command. However, you must remove the call to%configure
because you did not provide a configure script.
You can install the cello program by using the %make_install
macro. This is possible because the Makefile
file for the cello program is available.
4.6. Building RPMs Copy linkLink copied to clipboard!
You can build RPM packages by using the rpmbuild
command. When using this command, a certain directory and file structure is expected, which is the same as the structure that was set up by the rpmdev-setuptree
utility.
Different use cases and desired outcomes require different combinations of arguments to the rpmbuild
command. The following are the main use cases:
- Building source RPMs.
Building binary RPMs:
- Rebuilding a binary RPM from a source RPM.
-
Building a binary RPM from the
spec
file.
4.6.1. Building source RPMs Copy linkLink copied to clipboard!
Building a Source RPM (SRPM) has the following advantages:
-
You can preserve the exact source of a certain
Name-Version-Release
of an RPM file that was deployed to an environment. This includes the exactspec
file, the source code, and all relevant patches. This is useful for tracking and debugging purposes. - You can build a binary RPM on a different hardware platform or architecture.
Prerequisites
You have installed the
rpmbuild
utility on your system:yum install rpm-build
# yum install rpm-build
Copy to Clipboard Copied! Toggle word wrap Toggle overflow The following
Hello World!
implementations were placed into the~/rpmbuild/SOURCES/
directory:-
A
spec
file for the program that you want to package exists.
Procedure
Navigate to the
~/rpmbuild/SPECS/
directive, which contains the createdspec
file:cd ~/rpmbuild/SPECS/
$ cd ~/rpmbuild/SPECS/
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Build the source RPM by entering the
rpmbuild
command with the specifiedspec
file:rpmbuild -bs <specfile>
$ rpmbuild -bs <specfile>
Copy to Clipboard Copied! Toggle word wrap Toggle overflow The
-bs
option stands for build source.For example, to build source RPMs for the
bello
,pello
, andcello
programs, enter:Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Verification
-
Verify that the
rpmbuild/SRPMS
directory includes the resulting source RPMs. The directory is a part of the structure expected byrpmbuild
.
4.6.2. Rebuilding a binary RPM from a source RPM Copy linkLink copied to clipboard!
To rebuild a binary RPM from a source RPM (SRPM), use the rpmbuild
command with the --rebuild
option.
The output generated when creating the binary RPM is verbose, which is helpful for debugging. The output varies for different examples and corresponds to their spec
files.
The resulting binary RPMs are located in the ~/rpmbuild/RPMS/YOURARCH
directory, where YOURARCH
is your architecture, or in the ~/rpmbuild/RPMS/noarch/
directory, if the package is not architecture-specific.
Prerequisites
You have installed the
rpmbuild
utility on your system:yum install rpm-build
# yum install rpm-build
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Procedure
Navigate to the
~/rpmbuild/SRPMS/
directive, which contains the source RPM:cd ~/rpmbuild/SRPMS/
$ cd ~/rpmbuild/SRPMS/
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Rebuild the binary RPM from the source RPM:
rpmbuild --rebuild <srpm>
$ rpmbuild --rebuild <srpm>
Copy to Clipboard Copied! Toggle word wrap Toggle overflow For example, to rebuild
bello
,pello
, andcello
from their SRPMs, enter:Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Invoking rpmbuild --rebuild
involves the following processes:
-
Installing the contents of the SRPM (the
spec
file and the source code) into the~/rpmbuild/
directory. - Building an RPM by using the installed contents.
-
Removing the
spec
file and the source code.
You can retain the spec
file and the source code after building either of the following ways:
-
When building the RPM, use the
rpmbuild
command with the--recompile
option instead of the--rebuild
option. Install SRPMs for
bello
,python-pello
, andcello
:Copy to Clipboard Copied! Toggle word wrap Toggle overflow
4.6.3. Building a binary RPM from the spec file Copy linkLink copied to clipboard!
To build a binary RPM from its spec
file, use the rpmbuild
command with the -bb
option. The -bb
option stands for build binary.
Prerequisites
You have installed the
rpmbuild
utility on your system:yum install rpm-build
# yum install rpm-build
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Procedure
Navigate to the
~/rpmbuild/SPECS/
directive, which containsspec
files:cd ~/rpmbuild/SPECS/
$ cd ~/rpmbuild/SPECS/
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Build the binary RPM from its
spec
:rpmbuild -bb <spec_file>
$ rpmbuild -bb <spec_file>
Copy to Clipboard Copied! Toggle word wrap Toggle overflow For example, to build
bello
,pello
, andcello
binary RPMs from theirspec
files, enter:rpmbuild -bb bello.spec rpmbuild -bb python-pello.spec rpmbuild -bb cello.spec
$ rpmbuild -bb bello.spec $ rpmbuild -bb python-pello.spec $ rpmbuild -bb cello.spec
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
4.7. Checking RPMs for common errors Copy linkLink copied to clipboard!
After creating a package, you might want to check the quality of the package. The main tool for checking package quality is rpmlint
.
With the rpmlint
tool, you can perform the following actions:
- Improve RPM maintainability.
- Enable content validation by performing static analysis of the RPM.
- Enable error checking by performing static analysis of the RPM.
You can use rpmlint
to check binary RPMs, source RPMs (SRPMs), and spec
files. Therefore, this tool is useful for all stages of packaging.
Note that rpmlint
has strict guidelines. Therefore, it is sometimes acceptable to skip some of its errors and warnings as shown in the following sections.
In the examples described in the following sections, rpmlint
is run without any options, which produces a non-verbose output. For detailed explanations of each error or warning, run rpmlint -i
instead.
4.7.1. Checking a sample Bash program for common errors Copy linkLink copied to clipboard!
In the following sections, investigate possible warnings and errors that can occur when checking an RPM for common errors on the example of the bello
spec
file, bello
SRPM, and bello
binary RPM.
4.7.1.1. Checking the bello spec file for common errors Copy linkLink copied to clipboard!
Inspect the outputs of the following examples to learn how to check a bello
spec
file for common errors.
Output of running the rpmlint
command on the bello
spec
file
rpmlint bello.spec
$ rpmlint bello.spec
bello.spec: W: invalid-url Source0: https://www.example.com/bello/releases/bello-0.1.tar.gz HTTP Error 404: Not Found
0 packages and 1 specfiles checked; 0 errors, 1 warnings.
For bello.spec
, there is only one invalid-url Source0
warning. This warning means that the URL listed in the Source0
directive is unreachable. This is expected, because the specified example.com
URL does not exist. Assuming that this URL will be valid in the future, you can ignore this warning.
4.7.1.2. Checking the bello SRPM for common errors Copy linkLink copied to clipboard!
Inspect the outputs of the following examples to learn how to check a bello
source RPM (SRPM) for common errors.
Output of running the rpmlint
command on the bello
SRPM
rpmlint ~/rpmbuild/SRPMS/bello-0.1-1.el8.src.rpm
$ rpmlint ~/rpmbuild/SRPMS/bello-0.1-1.el8.src.rpm
bello.src: W: invalid-url URL: https://www.example.com/bello HTTP Error 404: Not Found
bello.src: W: invalid-url Source0: https://www.example.com/bello/releases/bello-0.1.tar.gz HTTP Error 404: Not Found
1 packages and 0 specfiles checked; 0 errors, 2 warnings.
For the bello
SRPM, there is the invalid-url URL
warning that means that the URL specified in the URL
directive is unreachable. Assuming that this URL will be valid in the future, you can ignore this warning.
4.7.1.3. Checking the bello binary RPM for common errors Copy linkLink copied to clipboard!
When checking binary RPMs, the rpmlint
command checks the following items:
- Documentation
- Manual pages
- Consistent use of the filesystem hierarchy standard
Inspect the outputs of the following example to learn how to check a bello
binary RPM for common errors.
Output of running the rpmlint
command on the bello
binary RPM
rpmlint ~/rpmbuild/RPMS/noarch/bello-0.1-1.el8.noarch.rpm
$ rpmlint ~/rpmbuild/RPMS/noarch/bello-0.1-1.el8.noarch.rpm
bello.noarch: W: invalid-url URL: https://www.example.com/bello HTTP Error 404: Not Found
bello.noarch: W: no-documentation
bello.noarch: W: no-manual-page-for-binary bello
1 packages and 0 specfiles checked; 0 errors, 3 warnings.
The no-documentation
and no-manual-page-for-binary
warnings mean that the RPM has no documentation or manual pages, because you did not provide any. Apart from the output warnings, the RPM passed rpmlint
checks.
4.7.2. Checking a sample Python program for common errors Copy linkLink copied to clipboard!
In the following sections, investigate possible warnings and errors that can occur when checking an RPM for common errors on the example of the pello
spec
file, pello
SRPM, and pello
binary RPM.
4.7.2.1. Checking the pello spec file for common errors Copy linkLink copied to clipboard!
Inspect the outputs of the following examples to learn how to check a pello
spec
file for common errors.
Output of running the rpmlint
command on the pello
spec
file
rpmlint python-pello.spec
$ rpmlint python-pello.spec
0 packages and 1 specfiles checked; 0 errors, 0 warnings.
For the python-pello
spec
file, the rpmlint
utility detected zero errors or warnings, which means that the file was composed correctly.
For packages going into production, make sure to properly check the spec
file for errors and warnings.
4.7.2.2. Checking the pello SRPM for common errors Copy linkLink copied to clipboard!
Inspect the outputs of the following examples to learn how to check a pello
source RPM (SRPM) for common errors.
Output of running the rpmlint
command on the SRPM for pello
rpmlint ~/rpmbuild/SRPMS/pello-0.1.2-1.el8.src.rpm
$ rpmlint ~/rpmbuild/SRPMS/pello-0.1.2-1.el8.src.rpm
python-pello.src: E: description-line-too-long C Pello is an example package with an executable that prints Hello World! on the command line.
1 packages and 0 specfiles checked; 1 errors, 0 warnings.
The description-line-too-long
error means that the description you provided exceeded the allowed number of characters.
Apart from the output error, the SRPM passed rpmlint
checks.
4.7.2.3. Checking the pello binary RPM for common errors Copy linkLink copied to clipboard!
When checking binary RPMs, the rpmlint
command checks the following items:
- Documentation
- Manual pages
- Consistent use of the Filesystem Hierarchy Standard
Inspect the outputs of the following example to learn how to check a pello
binary RPM for common errors.
Output of running the rpmlint
command on the pello
binary RPM
~/rpmbuild/RPMS/noarch/python3.12-pello-1.0.2-1.el8.noarch.rpm
$ ~/rpmbuild/RPMS/noarch/python3.12-pello-1.0.2-1.el8.noarch.rpm
pello-1.0.2-1.el8.noarch.rpm
python3.12-pello.noarch: E: description-line-too-long C Pello is an example package with an executable that prints Hello World! on the command line.
python3.12-pello.noarch: W: no-manual-page-for-binary pello_greeting
1 packages and 0 specfiles checked; 2 errors, 1 warnings.
-
The
no-manual-page-for-binary
warning means that the RPM has no manual pages because you did not provide any. -
The
description-line-too-long
error means that the description you provided exceeded the allowed number of characters.
Apart from the output warnings and errors, the RPM passed rpmlint
checks.
4.7.3. Checking a sample C program for common errors Copy linkLink copied to clipboard!
In the following sections, investigate possible warnings and errors that can occur when checking an RPM for common errors on the example of the cello
spec
file, cello
SRPM, and cello
binary RPM.
4.7.3.1. Checking the cello spec file for common errors Copy linkLink copied to clipboard!
Inspect the outputs of the following examples to learn how to check a cello
spec
file for common errors.
Output of running the rpmlint
command on the cello
spec
file
rpmlint ~/rpmbuild/SPECS/cello.spec
$ rpmlint ~/rpmbuild/SPECS/cello.spec
/home/admiller/rpmbuild/SPECS/cello.spec: W: invalid-url Source0: https://www.example.com/cello/releases/cello-1.0.tar.gz HTTP Error 404: Not Found
0 packages and 1 specfiles checked; 0 errors, 1 warnings.
For cello.spec
, there is only one invalid-url Source0
warning. This warning means that the URL listed in the Source0
directive is unreachable. This is expected because the specified example.com
URL does not exist. Assuming that this URL will be valid in the future, you can ignore this warning.
4.7.3.2. Checking the cello SRPM for common errors Copy linkLink copied to clipboard!
Inspect the outputs of the following examples to learn how to check a cello
source RPM (SRPM) for common errors.
Output of running the rpmlint
command on the cello
SRPM
rpmlint ~/rpmbuild/SRPMS/cello-1.0-1.el8.src.rpm
$ rpmlint ~/rpmbuild/SRPMS/cello-1.0-1.el8.src.rpm
cello.src: W: invalid-url URL: https://www.example.com/cello HTTP Error 404: Not Found
cello.src: W: invalid-url Source0: https://www.example.com/cello/releases/cello-1.0.tar.gz HTTP Error 404: Not Found
1 packages and 0 specfiles checked; 0 errors, 2 warnings.
For the cello
SRPM, there is the invalid-url URL
warning. This warning means that the URL specified in the URL
directive is unreachable. Assuming that this URL will be valid in the future, you can ignore this warning.
4.7.3.3. Checking the cello binary RPM for common errors Copy linkLink copied to clipboard!
When checking binary RPMs, the rpmlint
command checks the following items:
- Documentation
- Manual pages
- Consistent use of the filesystem hierarchy standard
Inspect the outputs of the following example to learn how to check a cello
binary RPM for common errors.
Output of running the rpmlint
command on the cello
binary RPM
rpmlint ~/rpmbuild/RPMS/x86_64/cello-1.0-1.el8.x86_64.rpm
$ rpmlint ~/rpmbuild/RPMS/x86_64/cello-1.0-1.el8.x86_64.rpm
cello.x86_64: W: invalid-url URL: https://www.example.com/cello HTTP Error 404: Not Found
cello.x86_64: W: no-documentation
cello.x86_64: W: no-manual-page-for-binary cello
1 packages and 0 specfiles checked; 0 errors, 3 warnings.
The no-documentation
and no-manual-page-for-binary
warnings mean that the RPM has no documentation or manual pages because you did not provide any.
Apart from the output warnings, the RPM passed rpmlint
checks.
4.8. Logging RPM activity to syslog Copy linkLink copied to clipboard!
You can log any RPM activity or transaction by using the System Logging protocol (syslog
).
Prerequisites
The
syslog
plug-in is installed on the system:yum install rpm-plugin-syslog
# yum install rpm-plugin-syslog
Copy to Clipboard Copied! Toggle word wrap Toggle overflow NoteThe default location for the
syslog
messages is the/var/log/messages
file. However, you can configuresyslog
to use another location to store the messages.
Procedure
Open the file that you configured to store the
syslog
messages.Alternatively, if you use the default
syslog
configuration, open the/var/log/messages
file.-
Search for new lines including the
[RPM]
string.
4.9. Extracting RPM content Copy linkLink copied to clipboard!
In some cases, for example, if a package required by RPM is damaged, you might need to extract the content of the package. In such cases, if an RPM installation is still working despite the damage, you can use the rpm2archive
utility to convert an .rpm
file to a tar archive to use the content of the package.
If the RPM installation is severely damaged, you can use the rpm2cpio
utility to convert the RPM package file to a cpio
archive.
Procedure
Convert the RPM file to the tar archive:
rpm2archive <filename>.rpm
$ rpm2archive <filename>.rpm
Copy to Clipboard Copied! Toggle word wrap Toggle overflow The resulting file has the
.tgz
suffix. For example, to create an archive from thebash
package, enter:rpm2archive bash-4.4.19-6.el8.x86_64.rpm ls bash-4.4.19-6.el8.x86_64.rpm.tgz
$ rpm2archive bash-4.4.19-6.el8.x86_64.rpm $ ls bash-4.4.19-6.el8.x86_64.rpm.tgz bash-4.4.19-6.el8.x86_64.rpm.tgz
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Chapter 5. Advanced topics Copy linkLink copied to clipboard!
This section covers topics that are beyond the scope of the introductory tutorial but are useful in real-world RPM packaging.
5.1. Signing RPM packages Copy linkLink copied to clipboard!
You can sign RPM packages to ensure that no third party can alter their content. To add an additional layer of security, use the HTTPS protocol when downloading the package.
You can sign a package by using the --addsign
option provided by the rpm-sign
package.
Prerequisites
- You have created a GNU Privacy Guard (GPG) key as described in Creating a GPG key.
5.1.1. Creating a GPG key Copy linkLink copied to clipboard!
Use the following procedure to create a GNU Privacy Guard (GPG) key required for signing packages.
Procedure
Generate a GPG key pair:
gpg --gen-key
# gpg --gen-key
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Check the generated key pair:
gpg --list-keys
# gpg --list-keys
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Export the public key:
gpg --export -a '<Key_name>' > RPM-GPG-KEY-pmanager
# gpg --export -a '<Key_name>' > RPM-GPG-KEY-pmanager
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Replace <Key_name> with the real key name that you have selected.
Import the exported public key into an RPM database:
rpm --import RPM-GPG-KEY-pmanager
# rpm --import RPM-GPG-KEY-pmanager
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
5.1.2. Configuring RPM to sign a package Copy linkLink copied to clipboard!
To be able to sign an RPM package, you need to specify the %_gpg_name
RPM macro.
The following procedure describes how to configure RPM for signing a package.
Procedure
Define the
%_gpg_name
macro in your$HOME/.rpmmacros
file as follows:%_gpg_name Key ID
%_gpg_name Key ID
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Replace Key ID with the GNU Privacy Guard (GPG) key ID that you will use to sign a package. A valid GPG key ID value is either a full name or email address of the user who created the key.
5.1.3. Adding a signature to an RPM package Copy linkLink copied to clipboard!
The most usual case is when a package is built without a signature. The signature is added just before the release of the package.
To add a signature to an RPM package, use the --addsign
option provided by the rpm-sign
package.
Procedure
Add a signature to a package:
rpm --addsign package-name.rpm
$ rpm --addsign package-name.rpm
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Replace package-name with the name of an RPM package you want to sign.
NoteYou must enter the password to unlock the secret key for the signature.
5.2. More on macros Copy linkLink copied to clipboard!
This section covers selected built-in RPM Macros.
5.2.1. Defining your own macros Copy linkLink copied to clipboard!
The following section describes how to create a custom macro.
Procedure
Include the following line in the RPM
spec
file:%global <name>[(opts)] <body>
%global <name>[(opts)] <body>
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
All whitespace surrounding <body>
is removed. Name may be composed of alphanumeric characters, and the character _
and must be at least 3 characters in length. Inclusion of the (opts)
field is optional:
-
Simple
macros do not contain the(opts)
field. In this case, only recursive macro expansion is performed. -
Parametrized
macros contain the(opts)
field. Theopts
string between parentheses is passed togetopt(3)
forargc/argv
processing at the beginning of a macro invocation.
Older RPM spec
files use the %define <name> <body>
macro pattern instead. The differences between %define
and %global
macros are as follows:
-
%define
has local scope. It applies to a specific part of aspec
file. The body of a%define
macro is expanded when used. -
%global
has global scope. It applies to an entirespec
file. The body of a%global
macro is expanded at definition time.
Macros are evaluated even if they are commented out or the name of the macro is given into the %changelog
section of the spec
file. To comment out a macro, use %%
. For example: %%global
.
5.2.2. Using the %setup macro Copy linkLink copied to clipboard!
This section describes how to build packages with source code tarballs using different variants of the %setup
macro. Note that the macro variants can be combined. The rpmbuild
output illustrates standard behavior of the %setup
macro. At the beginning of each phase, the macro outputs Executing(%…)
, as shown in the below example.
Example 5.1. Example %setup
macro output
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.DhddsG
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.DhddsG
The shell output is set with set -x
enabled. To see the content of /var/tmp/rpm-tmp.DhddsG
, use the --debug
option because rpmbuild
deletes temporary files after a successful build. This displays the setup of environment variables followed by for example:
The %setup
macro:
- Ensures that we are working in the correct directory.
- Removes residues of previous builds.
- Unpacks the source tarball.
- Sets up some default privileges.
5.2.2.1. Using the %setup -q macro Copy linkLink copied to clipboard!
The -q
option limits the verbosity of the %setup
macro. Only tar -xof
is executed instead of tar -xvvof
. Use this option as the first option.
5.2.2.2. Using the %setup -n macro Copy linkLink copied to clipboard!
The -n
option is used to specify the name of the directory from expanded tarball.
This is used in cases when the directory from expanded tarball has a different name from what is expected (%{name}-%{version}
), which can lead to an error of the %setup
macro.
For example, if the package name is cello
, but the source code is archived in hello-1.0.tgz
and contains the hello/
directory, the spec
file content needs to be as follows:
Name: cello Source0: https://example.com/%{name}/release/hello-%{version}.tar.gz … %prep %setup -n hello
Name: cello
Source0: https://example.com/%{name}/release/hello-%{version}.tar.gz
…
%prep
%setup -n hello
5.2.2.3. Using the %setup -c macro Copy linkLink copied to clipboard!
The -c
option is used if the source code tarball does not contain any subdirectories and after unpacking, files from an archive fills the current directory.
The -c
option then creates the directory and steps into the archive expansion as shown below:
/usr/bin/mkdir -p cello-1.0 cd 'cello-1.0'
/usr/bin/mkdir -p cello-1.0
cd 'cello-1.0'
The directory is not changed after archive expansion.
5.2.2.4. Using the %setup -D and %setup -T macros Copy linkLink copied to clipboard!
The -D
option disables deleting of source code directory, and is particularly useful if the %setup
macro is used several times. With the -D
option, the following lines are not used:
rm -rf 'cello-1.0'
rm -rf 'cello-1.0'
The -T
option disables expansion of the source code tarball by removing the following line from the script:
/usr/bin/gzip -dc '/builddir/build/SOURCES/cello-1.0.tar.gz' | /usr/bin/tar -xvvof -
/usr/bin/gzip -dc '/builddir/build/SOURCES/cello-1.0.tar.gz' | /usr/bin/tar -xvvof -
5.2.2.5. Using the %setup -a and %setup -b macros Copy linkLink copied to clipboard!
The -a
and -b
options expand specific sources:
-
The
-b
option stands forbefore
. This option expands specific sources before entering the working directory. -
The
-a
option stands forafter
. This option expands those sources after entering. Their arguments are source numbers from thespec
file preamble.
In the following example, the cello-1.0.tar.gz
archive contains an empty examples
directory. The examples are shipped in a separate examples.tar.gz
tarball and they expand into the directory of the same name. In this case, use -a 1
if you want to expand Source1
after entering the working directory:
Source0: https://example.com/%{name}/release/%{name}-%{version}.tar.gz Source1: examples.tar.gz … %prep %setup -a 1
Source0: https://example.com/%{name}/release/%{name}-%{version}.tar.gz
Source1: examples.tar.gz
…
%prep
%setup -a 1
In the following example, examples are provided in a separate cello-1.0-examples.tar.gz
tarball, which expands into cello-1.0/examples
. In this case, use -b 1
to expand Source1
before entering the working directory:
Source0: https://example.com/%{name}/release/%{name}-%{version}.tar.gz Source1: %{name}-%{version}-examples.tar.gz … %prep %setup -b 1
Source0: https://example.com/%{name}/release/%{name}-%{version}.tar.gz
Source1: %{name}-%{version}-examples.tar.gz
…
%prep
%setup -b 1
5.2.3. Common RPM macros in the %files section Copy linkLink copied to clipboard!
The following table lists advanced RPM Macros that are needed in the %files
section of a spec
file.
Macro | Definition |
---|---|
%license |
The |
%doc |
The |
%dir |
The |
%config(noreplace) |
The |
5.2.4. Displaying the built-in macros Copy linkLink copied to clipboard!
Red Hat Enterprise Linux provides multiple built-in RPM macros.
Procedure
To display all built-in RPM macros, run:
rpm --showrc
rpm --showrc
Copy to Clipboard Copied! Toggle word wrap Toggle overflow NoteThe output is quite sizeable. To narrow the result, use the command above with the
grep
command.To find information about the RPMs macros for your system’s version of RPM, run:
rpm -ql rpm
rpm -ql rpm
Copy to Clipboard Copied! Toggle word wrap Toggle overflow NoteRPM macros are the files titled
macros
in the output directory structure.
5.2.5. RPM distribution macros Copy linkLink copied to clipboard!
Different distributions provide different sets of recommended RPM macros based on the language implementation of the software being packaged or the specific guidelines of the distribution.
The sets of recommended RPM macros are often provided as RPM packages, ready to be installed with the yum
package manager.
Once installed, the macro files can be found in the /usr/lib/rpm/macros.d/
directory.
Procedure
To display the raw RPM macro definitions, run:
rpm --showrc
rpm --showrc
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
The above output displays the raw RPM macro definitions.
To determine what a macro does and how it can be helpful when packaging RPMs, run the
rpm --eval
command with the name of the macro used as its argument:rpm --eval %{_MACRO}
rpm --eval %{_MACRO}
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
5.2.6. Creating custom macros Copy linkLink copied to clipboard!
You can override the distribution macros in the ~/.rpmmacros
file with your custom macros. Any changes that you make affect every build on your machine.
Defining any new macros in the ~/.rpmmacros
file is not recommended. Such macros would not be present on other machines, where users may want to try to rebuild your package.
Procedure
To override a macro, run:
%_topdir /opt/some/working/directory/rpmbuild
%_topdir /opt/some/working/directory/rpmbuild
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
You can create the directory from the example above, including all subdirectories through the rpmdev-setuptree
utility. The value of this macro is by default ~/rpmbuild
.
%_smp_mflags -l3
%_smp_mflags -l3
The macro above is often used to pass to Makefile, for example make %{?_smp_mflags}
, and to set a number of concurrent processes during the build phase. By default, it is set to -jX
, where X
is a number of cores. If you alter the number of cores, you can speed up or slow down a build of packages.
5.3. Epoch, Scriptlets and Triggers Copy linkLink copied to clipboard!
This section covers Epoch
, Scriptlets
, and Triggers
, which represent advanced directives for RMP spec
files.
All these directives influence not only the spec
file, but also the end machine on which the resulting RPM is installed.
5.3.1. The Epoch directive Copy linkLink copied to clipboard!
The Epoch
directive enables to define weighted dependencies based on version numbers.
If this directive is not listed in the RPM spec
file, the Epoch
directive is not set at all. This is contrary to common belief that not setting Epoch
results in an Epoch
of 0. However, the yum
utility treats an unset Epoch
as the same as an Epoch
of 0 for the purposes of depsolving.
However, listing Epoch
in a spec
file is usually omitted because in majority of cases introducing an Epoch
value skews the expected RPM behavior when comparing versions of packages.
Example 5.2. Using Epoch
If you install the foobar
package with Epoch: 1
and Version: 1.0
, and someone else packages foobar
with Version: 2.0
but without the Epoch
directive, the new version will never be considered an update. The reason being that the Epoch
version is preferred over the traditional Name-Version-Release
marker that signifies versioning for RPM Packages.
Using of Epoch
is thus quite rare. However, Epoch
is typically used to resolve an upgrade ordering issue. The issue can appear as a side effect of upstream change in software version number schemes or versions incorporating alphabetical characters that cannot always be compared reliably based on encoding.
5.3.2. Scriptlets directives Copy linkLink copied to clipboard!
Scriptlets are a series of RPM directives that are executed before or after packages are installed or deleted.
Use Scriptlets only for tasks that cannot be done at build time or in an start up script.
A set of common Scriptlet directives exists. They are similar to the spec
file section headers, such as %build
or %install
. They are defined by multi-line segments of code, which are often written as a standard POSIX shell script. However, they can also be written in other programming languages that RPM for the target machine’s distribution accepts. RPM Documentation includes an exhaustive list of available languages.
The following table includes Scriptlet directives listed in their execution order. Note that a package containing the scripts is installed between the %pre
and %post
directive, and it is uninstalled between the %preun
and %postun
directive.
Directive | Definition |
---|---|
| Scriptlet that is executed just before installing or removing any package. |
| Scriptlet that is executed just before installing the package on the target system. |
| Scriptlet that is executed just after the package was installed on the target system. |
| Scriptlet that is executed just before uninstalling the package from the target system. |
| Scriptlet that is executed just after the package was uninstalled from the target system. |
| Scriptlet that is executed at the end of the transaction. |
5.3.3. Turning off a scriptlet execution Copy linkLink copied to clipboard!
The following procedure describes how to turn off the execution of any scriptlet using the rpm
command together with the --no_scriptlet_name_
option.
Procedure
For example, to turn off the execution of the
%pretrans
scriptlets, run:rpm --nopretrans
# rpm --nopretrans
Copy to Clipboard Copied! Toggle word wrap Toggle overflow You can also use the
-- noscripts
option, which is equivalent to all of the following:-
--nopre
-
--nopost
-
--nopreun
-
--nopostun
-
--nopretrans
-
--noposttrans
-
5.3.4. Scriptlets macros Copy linkLink copied to clipboard!
The Scriptlets directives also work with RPM macros.
The following example shows the use of systemd scriptlet macro, which ensures that systemd is notified about a new unit file.
5.3.5. The Triggers directives Copy linkLink copied to clipboard!
Triggers are RPM directives which provide a method for interaction during package installation and uninstallation.
Triggers may be executed at an unexpected time, for example on update of the containing package. Triggers are difficult to debug, therefore they need to be implemented in a robust way so that they do not break anything when executed unexpectedly. For these reasons, Red Hat recommends to minimize the use of Triggers.
The order of execution on a single package upgrade and the details for each existing Triggers are listed below:
The above items are found in the /usr/share/doc/rpm-4.*/triggers
file.
5.3.6. Using non-shell scripts in a spec file Copy linkLink copied to clipboard!
The -p
scriptlet option in a spec
file enables the user to invoke a specific interpreter instead of the default shell scripts interpreter (-p /bin/sh
).
The following procedure describes how to create a script, which prints out a message after installation of the pello.py
program:
Procedure
-
Open the
pello.spec
file. Find the following line:
install -m 0644 %{name}.py* %{buildroot}/usr/lib/%{name}/
install -m 0644 %{name}.py* %{buildroot}/usr/lib/%{name}/
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Under the above line, insert:
%post -p /usr/bin/python3 print("This is {} code".format("python"))
%post -p /usr/bin/python3 print("This is {} code".format("python"))
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Build your package as described in Building RPMs.
Install your package:
yum install /home/<username>/rpmbuild/RPMS/noarch/pello-0.1.2-1.el8.noarch.rpm
# yum install /home/<username>/rpmbuild/RPMS/noarch/pello-0.1.2-1.el8.noarch.rpm
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Check the output message after the installation:
Installing : pello-0.1.2-1.el8.noarch 1/1 Running scriptlet: pello-0.1.2-1.el8.noarch 1/1 This is python code
Installing : pello-0.1.2-1.el8.noarch 1/1 Running scriptlet: pello-0.1.2-1.el8.noarch 1/1 This is python code
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
To use a Python 3 script, include the following line under install -m
in a spec
file:
%post -p /usr/bin/python3
%post -p /usr/bin/python3
To use a Lua script, include the following line under install -m
in a SPEC file:
%post -p <lua>
%post -p <lua>
This way, you can specify any interpreter in a spec
file.
5.4. RPM conditionals Copy linkLink copied to clipboard!
RPM Conditionals enable conditional inclusion of various sections of the spec
file.
Conditional inclusions usually deal with:
- Architecture-specific sections
- Operating system-specific sections
- Compatibility issues between various versions of operating systems
- Existence and definition of macros
5.4.1. RPM conditionals syntax Copy linkLink copied to clipboard!
RPM conditionals use the following syntax:
If expression is true, then do some action:
%if expression … %endif
%if expression
…
%endif
If expression is true, then do some action, in other case, do another action:
%if expression … %else … %endif
%if expression
…
%else
…
%endif
5.4.2. The %if conditionals Copy linkLink copied to clipboard!
The following examples shows the usage of %if
RPM conditionals.
Example 5.3. Using the %if conditional to handle compatibility between Red Hat Enterprise Linux 8 and other operating systems
%if 0%{?rhel} == 8 sed -i '/AS_FUNCTION_DESCRIBE/ s/^/#/' configure.in sed -i '/AS_FUNCTION_DESCRIBE/ s/^/#/' acinclude.m4 %endif
%if 0%{?rhel} == 8
sed -i '/AS_FUNCTION_DESCRIBE/ s/^/#/' configure.in
sed -i '/AS_FUNCTION_DESCRIBE/ s/^/#/' acinclude.m4
%endif
This conditional handles compatibility between RHEL 8 and other operating systems in terms of support of the AS_FUNCTION_DESCRIBE macro. If the package is built for RHEL, the %rhel
macro is defined, and it is expanded to RHEL version. If its value is 8, meaning the package is build for RHEL 8, then the references to AS_FUNCTION_DESCRIBE, which is not supported by RHEL 8, are deleted from autoconfig scripts.
Example 5.4. Using the %if conditional to handle definition of macros
%define ruby_archive %{name}-%{ruby_version} %if 0%{?milestone:1}%{?revision:1} != 0 %define ruby_archive %{ruby_archive}-%{?milestone}%{?!milestone:%{?revision:r%{revision}}} %endif
%define ruby_archive %{name}-%{ruby_version}
%if 0%{?milestone:1}%{?revision:1} != 0
%define ruby_archive %{ruby_archive}-%{?milestone}%{?!milestone:%{?revision:r%{revision}}}
%endif
This conditional handles definition of macros. If the %milestone
or the %revision
macros are set, the %ruby_archive
macro, which defines the name of the upstream tarball, is redefined.
5.4.3. Specialized variants of %if conditionals Copy linkLink copied to clipboard!
The %ifarch
conditional, %ifnarch
conditional and %ifos
conditional are specialized variants of the %if
conditionals. These variants are commonly used, hence they have their own macros.
The %ifarch conditional
The %ifarch
conditional is used to begin a block of the spec
file that is architecture-specific. It is followed by one or more architecture specifiers, each separated by commas or whitespace.
Example 5.5. An example use of the %ifarch conditional
%ifarch i386 sparc … %endif
%ifarch i386 sparc
…
%endif
All the contents of the spec
file between %ifarch
and %endif
are processed only on the 32-bit AMD and Intel architectures or Sun SPARC-based systems.
The %ifnarch conditional
The %ifnarch
conditional has a reverse logic than %ifarch
conditional.
Example 5.6. An example use of the %ifnarch conditional
%ifnarch alpha … %endif
%ifnarch alpha
…
%endif
All the contents of the spec
file between %ifnarch
and %endif
are processed only if not done on a Digital Alpha/AXP-based system.
The %ifos conditional
The %ifos
conditional is used to control processing based on the operating system of the build. It can be followed by one or more operating system names.
Example 5.7. An example use of the %ifos conditional
%ifos linux … %endif
%ifos linux
…
%endif
All the contents of the spec
file between %ifos
and %endif
are processed only if the build was done on a Linux system.
5.5. Packaging Python 3 RPMs Copy linkLink copied to clipboard!
Most Python projects use Setuptools for packaging, and define package information in the setup.py
file. For more information about Setuptools packaging, see the Setuptools documentation.
You can also package your Python project into an RPM package, which provides the following advantages compared to Setuptools packaging:
- Specification of dependencies of a package on other RPMs (even non-Python)
Cryptographic signing
With cryptographic signing, content of RPM packages can be verified, integrated, and tested with the rest of the operating system.
5.5.1. The spec file description for a Python package Copy linkLink copied to clipboard!
A spec
file contains instructions that the rpmbuild
utility uses to build an RPM. The instructions are included in a series of sections. A spec
file has two main parts in which the sections are defined:
- Preamble (contains a series of metadata items that are used in the Body)
- Body (contains the main part of the instructions)
An RPM SPEC file for Python projects has some specifics compared to non-Python RPM SPEC files. Most notably, a name of any RPM package of a Python library must always include the prefix determining the version, for example, python3
for Python 3.6, python38
for Python 3.8, python39
for Python 3.9, python3.11
for Python 3.11, or python3.12
for Python 3.12.
Other specifics are shown in the following spec
file example for the python3-detox
package. For description of such specifics, see the notes below the example.
- 1
- The modname macro contains the name of the Python project. In this example it is
detox
. - 2
- When packaging a Python project into RPM, the
python3
prefix always needs to be added to the original name of the project. The original name here isdetox
and the name of the RPM ispython3-detox
. - 3
- BuildRequires specifies what packages are required to build and test this package. In BuildRequires, always include items providing tools necessary for building Python packages:
python36-devel
andpython3-setuptools
. Thepython36-rpm-macros
package is required so that files with/usr/bin/python3
interpreter directives are automatically changed to/usr/bin/python3.6
. - 4
- Every Python package requires some other packages to work correctly. Such packages need to be specified in the
spec
file as well. To specify the dependencies, you can use the %python_enable_dependency_generator macro to automatically use dependencies defined in thesetup.py
file. If a package has dependencies that are not specified using Setuptools, specify them within additionalRequires
directives. - 5
- The %py3_build and %py3_install macros run the
setup.py build
andsetup.py install
commands, respectively, with additional arguments to specify installation locations, the interpreter to use, and other details. - 6
- The check section provides a macro that runs the correct version of Python. The %{__python3} macro contains a path for the Python 3 interpreter, for example
/usr/bin/python3
. We recommend to always use the macro rather than a literal path.
5.5.2. Common macros for Python 3 RPMs Copy linkLink copied to clipboard!
In a spec
file, always use the macros that are described in the following Macros for Python 3 RPMs table rather than hardcoding their values.
In macro names, always use python3
or python2
instead of unversioned python
. Configure the particular Python 3 version in the BuildRequires
section of the SPEC file to python36-rpm-macros
, python38-rpm-macros
, python39-rpm-macros
, python3.11-rpm-macros
, or python3.12-rpm-macros
.
Macro | Normal Definition | Description |
---|---|---|
%{__python3} | /usr/bin/python3 | Python 3 interpreter |
%{python3_version} | 3.6 | The full version of the Python 3 interpreter. |
%{python3_sitelib} | /usr/lib/python3.6/site-packages | Where pure-Python modules are installed. |
%{python3_sitearch} | /usr/lib64/python3.6/site-packages | Where modules containing architecture-specific extensions are installed. |
%py3_build |
Runs the | |
%py3_install |
Runs the |
5.5.3. Automatic provides for Python RPMs Copy linkLink copied to clipboard!
When packaging a Python project, make sure that the following directories are included in the resulting RPM if these directories are present:
-
.dist-info
-
.egg-info
-
.egg-link
From these directories, the RPM build process automatically generates virtual pythonX.Ydist
provides, for example, python3.6dist(detox)
. These virtual provides are used by packages that are specified by the %python_enable_dependency_generator macro.
5.6. Handling interpreter directives in Python scripts Copy linkLink copied to clipboard!
In Red Hat Enterprise Linux 8, executable Python scripts are expected to use interpreter directives (also known as hashbangs or shebangs) that explicitly specify at a minimum the major Python version. For example:
The /usr/lib/rpm/redhat/brp-mangle-shebangs
buildroot policy (BRP) script is run automatically when building any RPM package, and attempts to correct interpreter directives in all executable files.
The BRP script generates errors when encountering a Python script with an ambiguous interpreter directive, such as:
#!/usr/bin/python
#!/usr/bin/python
or
#!/usr/bin/env python
#!/usr/bin/env python
5.6.1. Modifying interpreter directives in Python scripts Copy linkLink copied to clipboard!
Modify interpreter directives in the Python scripts that cause the build errors at RPM build time.
Prerequisites
- Some of the interpreter directives in your Python scripts cause a build error.
Procedure
To modify interpreter directives, complete one of the following tasks:
Apply the
pathfix.py
script from theplatform-python-devel
package:pathfix.py -pn -i %{__python3} PATH …
# pathfix.py -pn -i %{__python3} PATH …
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Note that multiple
PATHs
can be specified. If aPATH
is a directory,pathfix.py
recursively scans for any Python scripts matching the pattern^[a-zA-Z0-9_]+\.py$
, not only those with an ambiguous interpreter directive. Add this command to the%prep
section or at the end of the%install
section.-
Modify the packaged Python scripts so that they conform to the expected format. For this purpose,
pathfix.py
can be used outside the RPM build process, too. When runningpathfix.py
outside an RPM build, replace%{__python3}
from the example above with a path for the interpreter directive, such as/usr/bin/python3
.
If the packaged Python scripts require a version other than Python 3.6, adjust the preceding commands to include the required version.
5.6.2. Changing /usr/bin/python3 interpreter directives in your custom packages Copy linkLink copied to clipboard!
By default, interpreter directives in the form of /usr/bin/python3
are replaced with interpreter directives pointing to Python from the platform-python
package, which is used for system tools with Red Hat Enterprise Linux. You can change the /usr/bin/python3
interpreter directives in your custom packages to point to a specific version of Python that you have installed from the AppStream repository.
Procedure
To build your package for a specific version of Python, add the
python*-rpm-macros
subpackage of the respectivepython
package to the BuildRequires section of thespec
file. For example, for Python 3.6, include the following line:BuildRequires: python36-rpm-macros
BuildRequires: python36-rpm-macros
Copy to Clipboard Copied! Toggle word wrap Toggle overflow As a result, the
/usr/bin/python3
interpreter directives in your custom package are automatically converted to/usr/bin/python3.6
.
To prevent the BRP script from checking and modifying interpreter directives, use the following RPM directive:
%undefine __brp_mangle_shebangs
%undefine __brp_mangle_shebangs
5.7. RubyGems packages Copy linkLink copied to clipboard!
This section explains what RubyGems packages are, and how to re-package them into RPM.
5.7.1. What RubyGems are Copy linkLink copied to clipboard!
Ruby is a dynamic, interpreted, reflective, object-oriented, general-purpose programming language.
Programs written in Ruby are typically packaged using the RubyGems project, which provides a specific Ruby packaging format.
Packages created by RubyGems are called gems, and they can be re-packaged into RPM as well.
This documentation refers to terms related to the RubyGems concept with the gem
prefix, for example .gemspec is used for the gem specification
, and terms related to RPM are unqualified.
5.7.2. How RubyGems relate to RPM Copy linkLink copied to clipboard!
RubyGems represent Ruby’s own packaging format. However, RubyGems contain metadata similar to those needed by RPM, which enables the conversion from RubyGems to RPM.
According to Ruby Packaging Guidelines, it is possible to re-package RubyGems packages into RPM in this way:
- Such RPMs fit with the rest of the distribution.
- End users are able to satisfy dependencies of a gem by installing the appropriate RPM-packaged gem.
RubyGems use similar terminology as RPM, such as spec
files, package names, dependencies and other items.
To fit into the rest of RHEL RPM distribution, packages created by RubyGems must follow the conventions listed below:
Names of gems must follow this pattern:
rubygem-%{gem_name}
rubygem-%{gem_name}
Copy to Clipboard Copied! Toggle word wrap Toggle overflow To implement a shebang line, the following string must be used:
#!/usr/bin/ruby
#!/usr/bin/ruby
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
5.7.3. Creating RPM packages from RubyGems packages Copy linkLink copied to clipboard!
To create a source RPM for a RubyGems package, the following files are needed:
- A gem file
-
An RPM
spec
file
The following sections describe how to create RPM packages from packages created by RubyGems.
5.7.3.1. RubyGems spec file conventions Copy linkLink copied to clipboard!
A RubyGems spec
file must meet the following conventions:
-
Contain a definition of
%{gem_name}
, which is the name from the gem’s specification. - The source of the package must be the full URL to the released gem archive; the version of the package must be the gem’s version.
Contain the
BuildRequires:
a directive defined as follows to be able to pull in the macros needed to build.BuildRequires:rubygems-devel
BuildRequires:rubygems-devel
Copy to Clipboard Copied! Toggle word wrap Toggle overflow -
Not contain any RubyGems
Requires
orProvides
, because those are autogenerated. Not contain the
BuildRequires:
directive defined as follows, unless you want to explicitly specify Ruby version compatibility:Requires: ruby(release)
Requires: ruby(release)
Copy to Clipboard Copied! Toggle word wrap Toggle overflow The automatically generated dependency on RubyGems (
Requires: ruby(rubygems)
) is sufficient.
5.7.3.2. RubyGems macros Copy linkLink copied to clipboard!
The following table lists macros useful for packages created by RubyGems. These macros are provided by the rubygems-devel
packages.
Macro name | Extended path | Usage |
---|---|---|
%{gem_dir} | /usr/share/gems | Top directory for the gem structure. |
%{gem_instdir} | %{gem_dir}/gems/%{gem_name}-%{version} | Directory with the actual content of the gem. |
%{gem_libdir} | %{gem_instdir}/lib | The library directory of the gem. |
%{gem_cache} | %{gem_dir}/cache/%{gem_name}-%{version}.gem | The cached gem. |
%{gem_spec} | %{gem_dir}/specifications/%{gem_name}-%{version}.gemspec | The gem specification file. |
%{gem_docdir} | %{gem_dir}/doc/%{gem_name}-%{version} | The RDoc documentation of the gem. |
%{gem_extdir_mri} | %{_libdir}/gems/ruby/%{gem_name}-%{version} | The directory for gem extension. |
5.7.3.3. RubyGems spec file example Copy linkLink copied to clipboard!
Example spec
file for building gems together with an explanation of its particular sections follows.
An example RubyGems spec file
The following table explains the specifics of particular items in a RubyGems spec
file:
Directive | RubyGems specifics |
---|---|
%prep |
RPM can directly unpack gem archives, so you can run the |
%build |
This directive includes commands or series of commands for building the software into machine code. The
The
The |
%install |
The installation is performed into the |
5.7.3.4. Converting RubyGems packages to RPM spec files with gem2rpm Copy linkLink copied to clipboard!
The gem2rpm
utility converts RubyGems packages to RPM spec
files.
The following sections describe how to:
-
Install the
gem2rpm
utility -
Display all
gem2rpm
options -
Use
gem2rpm
to convert RubyGems packages to RPMspec
files -
Edit
gem2rpm
templates
5.7.3.4.1. Installing gem2rpm Copy linkLink copied to clipboard!
The following procedure describes how to install the gem2rpm
utility.
Procedure
-
To install
gem2rpm
from RubyGems.org, run:
gem install gem2rpm
$ gem install gem2rpm
5.7.3.4.2. Displaying all options of gem2rpm Copy linkLink copied to clipboard!
The following procedure describes how to display all options of the gem2rpm
utility.
Procedure
To see all options of
gem2rpm
, run:gem2rpm --help
$ gem2rpm --help
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
5.7.3.4.3. Using gem2rpm to convert RubyGems packages to RPM spec files Copy linkLink copied to clipboard!
The following procedure describes how to use the gem2rpm
utility to convert RubyGems packages to RPM spec
files.
Procedure
Download a gem in its latest version, and generate the RPM
spec
file for this gem:gem2rpm --fetch <gem_name> > <gem_name>.spec
$ gem2rpm --fetch <gem_name> > <gem_name>.spec
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
The described procedure creates an RPM spec
file based on the information provided in the gem’s metadata. However, the gem misses some important information that is usually provided in RPMs, such as the license and the changelog. The generated spec
file thus needs to be edited.
5.7.3.4.4. gem2rpm templates Copy linkLink copied to clipboard!
The gem2rpm
template is a standard Embedded Ruby (ERB) file, which includes variables listed in the following table.
Variable | Explanation |
---|---|
package |
The |
spec |
The |
config |
The |
runtime_dependencies |
The |
development_dependencies |
The |
tests |
The |
files |
The |
main_files |
The |
doc_files |
The |
format |
The |
5.7.3.4.5. Listing available gem2rpm templates Copy linkLink copied to clipboard!
Use the following procedure describes to list all available gem2rpm
templates.
Procedure
To see all available templates, run:
gem2rpm --templates
$ gem2rpm --templates
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
5.7.3.4.6. Editing gem2rpm templates Copy linkLink copied to clipboard!
You can edit the template from which the RPM spec
file is generated instead of editing the generated spec
file.
Use the following procedure to edit the gem2rpm
templates.
Procedure
Save the default template:
gem2rpm -T > rubygem-<gem_name>.spec.template
$ gem2rpm -T > rubygem-<gem_name>.spec.template
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Edit the template as needed.
Generate the
spec
file by using the edited template:gem2rpm -t rubygem-<gem_name>.spec.template <gem_name>-<latest_version.gem > <gem_name>-GEM.spec
$ gem2rpm -t rubygem-<gem_name>.spec.template <gem_name>-<latest_version.gem > <gem_name>-GEM.spec
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
You can now build an RPM package by using the edited template as described in Building RPMs.
5.8. How to handle RPM packages with Perls scripts Copy linkLink copied to clipboard!
Since RHEL 8, the Perl programming language is not included in the default buildroot. Therefore, the RPM packages that include Perl scripts must explicitly indicate the dependency on Perl using the BuildRequires:
directive in RPM spec
file.
5.8.2. Using a specific Perl module Copy linkLink copied to clipboard!
If a specific Perl module is required at build time, use the following procedure:
Procedure
Apply the following syntax in your RPM
spec
file:BuildRequires: perl(MODULE)
BuildRequires: perl(MODULE)
Copy to Clipboard Copied! Toggle word wrap Toggle overflow NoteApply this syntax to Perl core modules as well, because they can move in and out of the
perl
package over time.
5.8.3. Limiting a package to a specific Perl version Copy linkLink copied to clipboard!
To limit your package to a specific Perl version, follow this procedure:
Procedure
Use the
perl(:VERSION)
dependency with the desired version constraint in your RPMspec
file:For example, to limit a package to Perl version 5.22 and later, use:
BuildRequires: perl(:VERSION) >= 5.22
BuildRequires: perl(:VERSION) >= 5.22
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Do not use a comparison against the version of the perl
package because it includes an epoch number.
5.8.4. Ensuring that a package uses the correct Perl interpreter Copy linkLink copied to clipboard!
Red Hat provides multiple Perl interpreters, which are not fully compatible. Therefore, any package that delivers a Perl module must use at run time the same Perl interpreter that was used at build time.
To ensure this, follow the procedure below:
Procedure
Include versioned
MODULE_COMPAT
Requires
in RPMspec
file for any package that delivers a Perl module:Requires: perl(:MODULE_COMPAT_%(eval `perl -V:version`; echo $version))
Requires: perl(:MODULE_COMPAT_%(eval `perl -V:version`; echo $version))
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Chapter 6. New features in RHEL 8 Copy linkLink copied to clipboard!
This section documents the most notable changes in RPM packaging between Red Hat Enterprise Linux 7 and 8.
6.1. Support for Weak dependencies Copy linkLink copied to clipboard!
Weak dependencies
are variants of the Requires
directive. These variants are matched against virtual Provides:
and package names using Epoch-Version-Release
range comparisons.
Weak dependencies
have two strengths (weak
and hint
) and two directions (forward
and backward
), as summarized in the following table.
The forward
direction is analogous to Requires:
. The backward
has no analog in the previous dependency system.
Strength/Direction | Forward | Backward |
---|---|---|
Weak | Recommends: | Supplements: |
Hint | Suggests: | Enhances: |
The main advantages of the Weak dependencies
policy are:
- It allows smaller minimal installations while keeping the default installation feature rich.
- Packages can specify preferences for specific providers while maintaining the flexibility of virtual provides.
6.1.1. Introduction to Weak dependencies Copy linkLink copied to clipboard!
By default, Weak dependencies
are treated similarly to regular Requires:
. Matching packages are included in the YUM transaction. If adding the package leads to an error, YUM by default ignores the dependency. Hence, users can exclude packages that would be added by Weak dependencies
or remove them later.
Conditions of use
You can use Weak dependencies
only if the package still functions without the dependency.
It is acceptable to create packages with very limited functionality without adding any of its weak requirements.
Use cases
Use Weak dependencies
especially where it is possible to minimize the installation for reasonable use cases, such as building virtual machines or containers that have a single purpose and do not require the full feature set of the package.
Typical use cases for Weak dependencies
are:
Documentation
- Documentation viewers if missing them is handled gracefully
- Examples
Plug-ins or add-ons
- Support for file formats
- Support for protocols
6.1.2. The Hints strength Copy linkLink copied to clipboard!
Hints
are by default ignored by YUM. They can be used by GUI tools to offer add-on packages that are not installed by default but can be useful in combination with the installed packages.
Do not use Hints
for the requirements of the main use cases of a package. Include such requirements in the strong or Weak dependencies
instead.
Package Preference
YUM uses Weak dependencies
and Hints
to decide which package to use if there is a choice between multiple equally valid packages. Packages that are pointed at by dependencies from installed or to be installed packages are preferred.
Note, the normal rules of dependency resolution are not influenced by this feature. For example, Weak dependencies
cannot enforce an older version of a package to be chosen.
If there are multiple providers for a dependency, the requiring package can add a Suggests:
to provide a hint to the dependency resolver about which option is preferred.
Enhances:
is only used when the main package and other providers agree that adding the hint to the required package is for some reason the cleaner solution.
Example 6.1. Using Hints to prefer one package over another
Package A: Requires: mysql Package mariadb: Provides: mysql Package community-mysql: Provides: mysql
Package A: Requires: mysql
Package mariadb: Provides: mysql
Package community-mysql: Provides: mysql
If you want to prefer the mariadb
package over the community-mysql
package → use:
Suggests: mariadb to Package A.
Suggests: mariadb to Package A.
6.1.3. Forward and Backward dependencies Copy linkLink copied to clipboard!
Forward dependencies
are, similarly to Requires
, evaluated for packages that are being installed. The best of the matching packages are also installed.
In general, prefer Forward dependencies
. Add the dependency to the package when getting the other package added to the system.
For Backward dependencies
, the packages containing the dependency are installed if a matching package is installed as well.
Backward dependencies
are mainly designed for third party vendors who can attach their plug-ins, add-ons, or extensions to distribution or other third party packages.
6.2. Support for Boolean dependencies Copy linkLink copied to clipboard!
Starting with version 4.13, RPM is able to process boolean expressions in the following dependencies:
-
Requires
-
Recommends
-
Suggests
-
Supplements
-
Enhances
-
Conflicts
The following sections describe boolean dependencies syntax, provides a list of boolean operators, and explains boolean dependencies nesting as well as boolean dependencies semantics.
6.2.1. Boolean dependencies syntax Copy linkLink copied to clipboard!
Boolean expressions are always enclosed with parenthesis.
They are build out of normal dependencies:
- Name only or name
- Comparison
- Version description
6.2.2. Boolean operators Copy linkLink copied to clipboard!
RPM 4.13 introduced the following boolean operators:
Boolean operator | Description | Example use |
---|---|---|
| Requires all operands to be fulfilled for the term to be true. | Conflicts: (pkgA and pkgB) |
| Requires one of the operands to be fulfilled for the term to be true. | Requires: (pkgA >= 3.2 or pkgB) |
| Requires the first operand to be fulfilled if the second is. (reverse implication) | Recommends: (myPkg-langCZ if langsupportCZ) |
|
Same as the | Requires: myPkg-backend-mariaDB if mariaDB else sqlite |
RPM 4.14 introduced the following additional boolean operators:
Boolean operator | Description | Example use |
---|---|---|
| Requires all operands to be fulfilled by the same package for the term to be true. | Requires: (pkgA-foo with pkgA-bar) |
| Requires a single package that satisfies the first operand but not the second. (set subtraction) | Requires: (pkgA-foo without pkgA-bar) |
| Requires the first operand to be fulfilled if the second is not. (reverse negative implication) | Conflicts: (myPkg-driverA unless driverB) |
|
Same as the | Conflicts: (myPkg-backend-SDL1 unless myPkg-backend-SDL2 else SDL2) |
The if
operator cannot be used in the same context with the or
operator, and the unless
operator cannot be used in the same context with and
.
6.2.3. Nesting Copy linkLink copied to clipboard!
Operands themselves can be used as boolean expressions, as shown in the below examples.
Note that in such case, operands also need to be surrounded by parenthesis. You can chain the and
and or
operators together repeating the same operator with only one set of surrounding parenthesis.
Example 6.2. Example use of operands applied as boolean expressions
Requires: (pkgA or pkgB or pkgC)
Requires: (pkgA or pkgB or pkgC)
Requires: (pkgA or (pkgB and pkgC))
Requires: (pkgA or (pkgB and pkgC))
Supplements: (foo and (lang-support-cz or lang-support-all))
Supplements: (foo and (lang-support-cz or lang-support-all))
Requires: (pkgA with capB) or (pkgB without capA)
Requires: (pkgA with capB) or (pkgB without capA)
Supplements: ((driverA and driverA-tools) unless driverB)
Supplements: ((driverA and driverA-tools) unless driverB)
Recommends: myPkg-langCZ and (font1-langCZ or font2-langCZ) if langsupportCZ
Recommends: myPkg-langCZ and (font1-langCZ or font2-langCZ) if langsupportCZ
6.2.4. Semantics Copy linkLink copied to clipboard!
Using Boolean dependencies
does not change the semantic of regular dependencies.
If Boolean dependencies
are used, checking for one match all names are checked and the boolean value of there being a match is then aggregated over the Boolean operators.
For all dependencies with the exception of Conflicts:
, the result has to be True
to not prevent an install. For Conflicts:
, the result has to be False
to not prevent an install.
Provides
are not dependencies and cannot contain boolean expressions.
6.2.5. Understanding the output of the if operator Copy linkLink copied to clipboard!
The if
operator is also returning a boolean value, which is usually close to what the intuitive understanding is. However, the below examples show that in some cases intuitive understanding of if
can be misleading.
Example 6.3. Misleading outputs of the if operator
This statement is true if pkgB is not installed. However, if this statement is used where the default result is false, things become complicated:
Requires: (pkgA if pkgB)
Requires: (pkgA if pkgB)
This statement is a conflict unless pkgB is installed and pkgA is not:
Conflicts: (pkgA if pkgB)
Conflicts: (pkgA if pkgB)
So you might rather want to use:
Conflicts: (pkgA and pkgB)
Conflicts: (pkgA and pkgB)
The same is true if the if
operator is nested in or
terms:
Requires: ((pkgA if pkgB) or pkgC or pkg)
Requires: ((pkgA if pkgB) or pkgC or pkg)
This also makes the whole term true, because the if
term is true if pkgB is not installed. If pkgA only helps if pkgB is installed, use and
instead:
Requires: ((pkgA and pkgB) or pkgC or pkg)
Requires: ((pkgA and pkgB) or pkgC or pkg)
6.3. Support for File triggers Copy linkLink copied to clipboard!
File triggers
are a kind of RPM scriptlets,
which are defined in a spec
file of a package.
Similar to Triggers, they are declared in one package but executed when another package that contains the matching files is installed or removed.
A common use of File triggers
is to update registries or caches. In such use case, the package containing or managing the registry or cache should contain also one or more File triggers
. Including File triggers
saves time compared to the situation when the package controls updating itself.
6.3.1. File triggers syntax Copy linkLink copied to clipboard!
File triggers
have the following syntax:
%file_trigger_tag [FILE_TRIGGER_OPTIONS] — PATHPREFIX… body_of_script
%file_trigger_tag [FILE_TRIGGER_OPTIONS] — PATHPREFIX…
body_of_script
Where:
file_trigger_tag
defines a type of file trigger. Allowed types are:
-
filetriggerin
-
filetriggerun
-
filetriggerpostun
-
transfiletriggerin
-
transfiletriggerun
-
transfiletriggerpostun
FILE_TRIGGER_OPTIONS
have the same purpose as RPM scriptlets options, except for the -P
option.
The priority of a trigger is defined by a number. The bigger number, the sooner the file trigger script is executed. Triggers with priority greater than 100000 are executed before standard scriptlets, and the other triggers are executed after standard scriptlets. The default priority is set to 1000000.
Every file trigger of each type must contain one or more path prefixes and scripts.
6.3.2. Examples of File triggers syntax Copy linkLink copied to clipboard!
The following example shows the File triggers
syntax:
%filetriggerin — /lib, /lib64, /usr/lib, /usr/lib64 /usr/sbin/ldconfig
%filetriggerin — /lib, /lib64, /usr/lib, /usr/lib64
/usr/sbin/ldconfig
This file trigger executes /usr/bin/ldconfig
directly after the installation of a package that contains a file having a path starting with /usr/lib
or /lib
. The file trigger is executed just once even if the package includes multiple files with the path starting with /usr/lib
or /lib
. However, all file names starting with /usr/lib
or /lib
are passed to standard input of trigger script so that you can filter inside of your script as shown below:
%filetriggerin — /lib, /lib64, /usr/lib, /usr/lib64 grep "foo" && /usr/sbin/ldconfig
%filetriggerin — /lib, /lib64, /usr/lib, /usr/lib64
grep "foo" && /usr/sbin/ldconfig
This file trigger executes /usr/bin/ldconfig
for each package containing files starting with /usr/lib
and containing foo
at the same time. Note that the prefix-matched files include all types of files including regular files, directories, symlinks and others.
6.3.3. File triggers types Copy linkLink copied to clipboard!
File triggers
have two main types:
File triggers
are further divided based on the time of execution as follows:
- Before or after installation or erasure of a package
- Before or after a transaction
6.3.3.1. Executed once per package File triggers Copy linkLink copied to clipboard!
File triggers
executed once per package are:
- %filetriggerin
- %filetriggerun
- %filetriggerpostun
%filetriggerin
This file trigger is executed after installation of a package if this package contains one or more files that match the prefix of this trigger. It is also executed after installation of a package that contains this file trigger and there is one or more files matching the prefix of this file trigger in the rpmdb
database.
%filetriggerun
This file trigger is executed before uninstallation of a package if this package contains one or more files that match the prefix of this trigger. It is also executed before uninstallation of a package that contains this file trigger and there is one or more files matching the prefix of this file trigger in rpmdb
.
%filetriggerpostun
This file trigger is executed after uninstallation of a package if this package contains one or more files that match the prefix of this trigger.
6.3.3.2. Executed once per transaction File triggers Copy linkLink copied to clipboard!
File triggers
executed once per transaction are:
- %transfiletriggerin
- %transfiletriggerun
- %transfiletriggerpostun
%transfiletriggerin
This file trigger is executed once after a transaction for all installed packages that contain one or more files that match the prefix of this trigger. It is also executed after a transaction if there was a package containing this file trigger in that transaction and there is one or more files matching the prefix of this trigger in rpmdb
.
%transfiletriggerun
This file trigger is executed once before a transaction for all packages that meet the following conditions:
- The package will be uninstalled in this transaction
- The package contains one or more files that match the prefix of this trigger
It is also executed before a transaction if there is a package containing this file trigger in that transaction and there is one or more files matching the prefix of this trigger in rpmdb
.
%transfiletriggerpostun
This file trigger is executed once after a transaction for all uninstalled packages that contain one or more file that matches the prefix of this trigger.
The list of triggering files is not available in this trigger type.
Therefore, if you install or uninstall multiple packages that contain libraries, the ldconfig cache is updated at the end of the whole transaction. This significantly improves the performance compared to RHEL 7 where the cache was updated for each package separately. Also the scriptlets which called ldconfig in %post and %postun in spec
file of every package are no longer needed.
6.3.4. Example use of File triggers in glibc Copy linkLink copied to clipboard!
The following example shows a real-world usage of File triggers
within the glibc
package.
In RHEL 8, File triggers
are implemented in glibc
to call the ldconfig
command at the end of an installation or uninstallation transaction.
This is ensured by including the following scriptlets in the glibc’s
SPEC file:
Therefore, if you install or uninstall multiple packages, the ldconfig
cache is updated for all installed libraries after the whole transaction is finished. Consequently, it is no longer necessary to include the scriptlets calling ldconfig
in RPM spec
files of individual packages. This improves the performance compared to RHEL 7, where the cache was updated for each package separately.
6.4. Stricter SPEC parser Copy linkLink copied to clipboard!
The SPEC parser has now some changes incorporated. Hence, it can identify new issues that were previously ignored.
6.5. Support for files above 4 GB Copy linkLink copied to clipboard!
On Red Hat Enterprise Linux 8, RPM can use 64-bit variables and tags, which enables operating on files and packages bigger than 4 GB.
6.5.1. 64-bit RPM tags Copy linkLink copied to clipboard!
Several RPM tags exist in both 64-bit versions and previous 32-bit versions. Note that the 64-bit versions have the LONG
string in front of their name.
32-bit variant tag name | 62-bit variant tag name | Tag description |
---|---|---|
RPMTAG_SIGSIZE | RPMTAG_LONGSIGSIZE | Header and compressed payload size. |
RPMTAG_ARCHIVESIZE | RPMTAG_LONGARCHIVESIZE | Uncompressed payload size. |
RPMTAG_FILESIZES | RPMTAG_LONGFILESIZES | Array of file sizes. |
RPMTAG_SIZE | RPMTAG_LONGSIZE | Sum of all file sizes. |
6.5.2. Using 64-bit tags on command line Copy linkLink copied to clipboard!
The LONG
extensions are always enabled on the command line. If you previously used scripts containing the rpm -q --qf
command, you can add long
to the name of such tags:
rpm -qp --qf="[%{filenames} %{longfilesizes}\n]"
rpm -qp --qf="[%{filenames} %{longfilesizes}\n]"
6.6. Other features Copy linkLink copied to clipboard!
Other new features related to RPM packaging in Red Hat Enterprise Linux 8 are:
- Simplified signature checking output in non-verbose mode
- Support for the enforced payload verification
- Support for the enforcing signature checking mode
- Additions and deprecations in macros
Red Hat Software Collections Overview - The Red Hat Software Collections offering provides continuously updated development tools in latest stable versions.
Red Hat Software Collections - The Packaging Guide provides an explanation of Software Collections and details how to build and package them. Developers and system administrators with basic understanding of software packaging with RPM can use this Guide to get started with Software Collections.
Mock - Mock provides a community-supported package building solution for various architectures and different Fedora or RHEL versions than has the build host.
RPM Documentation - The official RPM documentation.
Fedora Packaging Guidelines - The official packaging guidelines for Fedora, useful for all RPM-based distributions.