Este conteúdo não está disponível no idioma selecionado.

Chapter 6. Packaging software


In the following sections, learn the basics of the packaging process with the RPM package manager.

6.1. About spec files

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.

6.1.1. Preamble items of a spec file

The following are some of the directives that you can use in the Preamble section of the RPM spec file.

Expand
Table 6.1. The Preamble section directives
DirectiveDefinition

Name

A base name of the package that must match the spec file name.

Version

An upstream version number of the software.

Release

The number of times the version of the package was released.

Set the initial value to 1%{?dist} and increase it with each new release of the package. Reset to 1 when a new Version of the software is built.

Summary

A brief one-line summary of the package.

License

A license of the software being packaged.

The exact format for how to label the License in your spec file varies depending on which RPM-based Linux distribution guidelines you are following, for example, GPLv3+.

URL

A full URL for more information about the software, for example, an upstream project website for the software being packaged.

Source

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 apply the Source directive either with or without numbers at the end of the directive name. If there is no number given, the number is assigned to the entry internally. You can also give the numbers explicitly, for example, Source0, Source1, Source2, Source3, and so on.

Patch

A name of the first patch to apply to the source code, if necessary.

You can apply the Patch directive either with or without numbers at the end of the directive name. If there is no number given, the number is assigned to the entry internally. You can also give the numbers explicitly, for example, Patch0, Patch1, Patch2, Patch3, and so on.

You can apply the patches individually by using the %patch0, %patch1, %patch2 macro, and so on. Macros are applied within the %prep directive in the Body section of the RPM spec file. Alternatively, you can use the %autopatch macro that automatically applies all patches in the order they are given in the spec file.

BuildArch

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 BuildArch: noarch. If you do not set this value, the software automatically inherits the architecture of the machine on which it is built, for example, x86_64.

BuildRequires

A comma- or whitespace-separated list of packages required to build the program written in a compiled language. There can be multiple entries of BuildRequires, each on its own line in the SPEC file.

Requires

A comma- or whitespace-separated list of packages required by the software to run once installed. There can be multiple entries of Requires, each on its own line in the spec file.

ExcludeArch

If a piece of software cannot operate on a specific processor architecture, you can exclude this architecture in the ExcludeArch directive.

Conflicts

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 Conflicts, each on its own line in the spec file.

Obsoletes

The Obsoletes directive changes the way updates work depending on the following factors:

  • If you use the rpm command directly on a command line, it removes all packages that match obsoletes of packages being installed, or the update is performed by an update or dependency solver.
  • If you use the updates or dependency resolver (DNF), packages containing matching Obsoletes: are added as updates and replace the matching packages.

Provides

If you add the Provides directive to the package, this package can be referred to by dependencies other than its name.

6.1.2. Body items of a spec file

The following are the items used in the Body section of the RPM spec file.

Expand
Table 6.2. The Body section items
DirectiveDefinition

%description

A full description of the software packaged in the RPM. This description can span multiple lines and can be broken into paragraphs.

%prep

A command or series of commands to prepare the software for building, for example, for unpacking the archive in the Source directive. The %prep directive can contain a shell script.

%conf

A command or series of commands to configure the software for building.

%build

A command or series of commands for building the software into machine code (for compiled languages) or bytecode (for some interpreted languages).

%install

A command or series of commands that the rpmbuild utility will use to install the software into the BUILDROOT directory once the software has been built. These commands copy the desired build artifacts from the %_builddir directory, where the build happens, to the %buildroot directory that contains the directory structure with the files to be packaged. This includes copying files from ~/rpmbuild/BUILD to ~/rpmbuild/BUILDROOT and creating the necessary directories in ~/rpmbuild/BUILDROOT.

The %buildroot directory is an empty base directory, which resembles the end user’s system directory layout. In %buildroot, you can create any directories that will contain the installed files. To create such directories, you can use RPM macros without having to hardcode the paths.

Note that %install is only run when you create a package, not when you install it. For more information, see Working with spec files.

%check

A command or series of commands for testing the software, for example, unit tests.

%files

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 %buildroot directory that are not listed in %files, you will receive a warning about possible unpackaged files.

Within the %files section, you can indicate the role of various files by using built-in macros. This is useful for querying the package file manifest metadata by using the rpm command. For example, to indicate that the LICENSE file is a software license file, use the %license macro.

%changelog

A record of changes that happened to the package between different Version or Release builds. These changes include a list of date-stamped entries for each Version-Release of the package. These entries log packaging changes, not software changes, for example, adding a patch or changing the build procedure in the %build section.

6.1.3. Advanced spec file items

A spec file can contain advanced items, such as Scriptlets, File triggers and Triggers. These directives influence not only the spec file, but also the target operating system on which the resulting RPM is installed by updating the system with information from the RPM. Scriptlets, File Triggers and Triggers take effect at different points during the installation process on the target system, not the build process:

  • Scriptlets are unconditionally executed before or after the package is installed or deleted.
  • Triggers are conditionally executed when their specified trigger condition matches other packages on the installed system or in a transaction.
  • File triggers are conditionally executed when their specified path prefix matches other files on the installed system or in a transaction.

6.1.3.1. Scriptlets directives

Scriptlets are arbitrary programs that execute at pre-determined slots related to a package’s lifetime, for example, before or after the package is installed or deleted. By default, scriptlets are short shell scripts declared by the various %pre or %post directives in a spec file. Use scriptlets only for tasks that cannot be done at build time or in a startup script.

Common scriptlet directives 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 accepts for the target machine’s distribution.

6.1.3.2. Scriptlets directives execution order

Scriptlets directives have different order of execution:

  • %pre and %post are executed before and after you installed a package.
  • %preun and %postun are executed before and after you uninstalled the package.
  • %pretrans and %posttrans are executed at start and end of the transaction that installs the package, respectively.

During the package upgrade, the scriptlets are executed in the following order:

Expand
Table 6.3. Scriptlets directives
DirectiveDescription

%pretrans

The %pretrans scriptlet is executed before installing or removing a package.

%pre

The %pre scriptlet is executed before installing a package on the target system.

%post

The %post scriptlet is executed after a package was installed on the target system.

%preun

The %preun scriptlet is executed before uninstalling a package from the target system.

%postun

The %postun scriptlet is executed after a package was uninstalled from the target system.

%posttrans

The %posttrans scriptlet is executed at the end of a transaction.

6.1.3.3. Turning off scriptlets execution

You can turn off the execution of any scriptlet by using the --no option with the scriptlet name.

You can also use the --noscripts option, which is equivalent to turning off the execution of all the following scriptlets:

  • --nopre
  • --nopost
  • --nopreun
  • --nopostun
  • --nopretrans
  • --noposttrans
  • --nopreuntrans
  • --nopostuntrans

For more information, see the rpm man page on your system.

Procedure

  • Turn off the scriptlet execution:

    # rpm --no<scriptlet_name>
    Copy to Clipboard Toggle word wrap

    For example, to turn off the execution of the %pretrans scriptlet, enter:

    # rpm --nopretrans
    Copy to Clipboard Toggle word wrap

6.1.3.4. Example macros for scriptlets

The following are example macros that you can use for scriptlets in a spec file. These macros are real-world macros provided by the systemd-rpm-macros package. You can use these macros for packaging systemd-related things. You can also apply similar principles to other packages.

Packages that contain systemd unit files must use scriptlets to properly handle systemd services. systemd packages provide a set of macros to handle systemd scriptlet operations. For example:

%post
%systemd_post httpd.service

%preun
%systemd_preun httpd.service
Copy to Clipboard Toggle word wrap

These macros expand to the following in a package:

$ rpm --eval "%systemd_preun httpd.service"

if [ $1 -eq 0 ] && [ -x "/usr/lib/systemd/systemd-update-helper" ]; then
    # Package removal, not upgrade
    /usr/lib/systemd/systemd-update-helper remove-system-units httpd.service || :
fi
Copy to Clipboard Toggle word wrap
Note

The way macros behave is subject to change. For example, macros' behavior can change with a package’s development.

6.1.4. The Epoch directive

If setting the Version spec file directive is not enough for comparing package versions, you can use an Epoch directive. For example, you can use Epoch to resolve upgrade path issues that, for example, occurred because of the upstream change in a version numbering scheme in an incompatible manner.

Epoch is a numeric field. If you assign a value to Epoch, it adds a qualifier that RPM uses when comparing package versions. Not having the Epoch directive listed in a spec file means Epoch is not set. This is contrary to the common belief that not setting Epoch results in an Epoch of 0. However, for processing purposes, if you do not set Epoch, RPM treats it the same as if the Epoch was set to 0, and vice versa.

Important

Using Epoch in a spec file is usually omitted because, in the majority of cases, introducing an Epoch value distorts the expected RPM behavior when comparing versions of packages. Therefore, consider using Epoch as a last resort.

For example, you installed the foobar package with Epoch: 1 and Version: 1.0. Another packager packages foobar with Version: 2.0, but without the Epoch directive. As a result, the new version is never considered an update because the Epoch version is preferred over the traditional Name-Version-Release marker that signifies versioning for RPM packages.

6.1.5. Package versioning essentials

The essential part of the package description is the information defined in the Name, Version, and Release (NVR) spec file directives. RPM uses this information to compare package versions and track package dependencies.

When working with RPMs, you can also see mentions of EVR (epoch-version-release), NEVR (name-epoch-version-release), and NEVRA (name-epoch-version-release-architecture). EVR is the full version information of the package that RPM always uses for comparison. RPM compares one component at a time, starting from the first component. RPM stops the comparison when it finds a difference in components. For example, if Epoch differs, RPM does not compare the rest of the EVR components.

You can display the NVR information for a specific package by querying the RPM database, for example:

# rpm -q bash
bash-4.4.19-7.el8.x86_64
Copy to Clipboard Toggle word wrap

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.

Note

The rpm -q command displays the package information in the NEVRA format by default.

6.2. spec file conditionals

By using spec file conditionals, you can enable conditional inclusion of various sections of the spec file.

Conditionals usually deal with the following aspects:

  • Architecture-specific sections.
  • Operating system-specific sections.
  • Compatibility issues between various versions of operating systems.

You can use spec conditionals for different purposes, for example:

  • Conditional expression (%if). You can use %if for multiple purposes. It can have, for example, the following syntax:

    • “If expression is true, then do some action”:

      %if expression
      ...
      %endif
      Copy to Clipboard Toggle word wrap
    • “If expression is true, then do some action, otherwise, another action”:

      %if expression
      ...
      %elsif expression
      ...
      %else
      ...
      %endif
      Copy to Clipboard Toggle word wrap
    • %if can also be followed by an arbitrary number of %elif conditionals (nested %elsif), for example:

      %if expression
      %elif expression
      ...
      %else
      %endif
      Copy to Clipboard Toggle word wrap
  • System architecture (%ifarch, %ifnarch). %ifarch tests whether the current target system architecture matches. You can use %ifarch to build RPM packages for multiple platforms, for example:

    %ifarch s390 s390x
    BuildRequires: s390utils-devel
    %endif
    Copy to Clipboard Toggle word wrap
  • Operating system (%ifos, %ifnos). %ifos controls spec file processing according to the build target operating system.

6.2.1. Example usage of the %if conditionals

The following are examples of the usage of %if RPM conditionals.

Example 6.1. Using the %if conditional to handle compatibility between Red Hat Enterprise Linux 10 and other operating systems

%if 0%{?rhel} == 10
sed -i '/AS_FUNCTION_DESCRIBE/ s/^/#/' configure.in
sed -i '/AS_FUNCTION_DESCRIBE/ s/^/#/' acinclude.m4
%endif
Copy to Clipboard Toggle word wrap

When building a package on RHEL 10, this conditional comments out AS_FUNCTION_DESCRIBE lines from autoconf scripts being considered when the %rhel macro’s value is set to 10.

Example 6.2. 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
Copy to Clipboard Toggle word wrap

This conditional handles the definition of macros. If the %milestone or the %revision macros are set, the %ruby_archive macro, which defines the name of the upstream archive, is redefined.

6.2.2. Specialized variants of %if conditionals

The specialized variants of the %if conditionals include the %ifarch, %ifnarch, and %ifos conditionals. These conditionals are commonly used and, therefore, have their own macros.

Expand
Table 6.4. Table
ConditionalDescription

%ifarch

Use the %ifarch conditional to begin a block of the spec file that is architecture-specific. The conditional is followed by one or more architecture specifiers, each separated by commas or whitespace, for example:

%ifarch i386 sparc
...
%endif
Copy to Clipboard Toggle word wrap

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.

%ifnarch

The %ifnarch conditional has a reverse logic than %ifarch conditional.

%ifnarch aarch64
...
%endif
Copy to Clipboard Toggle word wrap

All the contents of the spec file between %ifnarch and %endif are processed only if not done on a system with the 64-bit ARM architecture.

%ifos

Use the %ifos conditional to control processing based on the operating system of the build. The conditional can be followed by one or more operating system names, for example:

%ifos linux
...​
%endif
Copy to Clipboard Toggle word wrap

All the contents of the spec file between %ifos and %endif are processed only if the build was done on a Linux system.

6.3. BuildRoots

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.

Note

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.

6.4. Working with spec files

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 unpopulated spec file, where you fill the necessary directives and fields.
Note

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.

6.4.1. Creating a new spec file for sample Bash, Python, and C programs

You can create a spec file for each of the three implementations of the Hello World! program by using the rpmdev-newspec utility.

Prerequisites

Procedure

  1. Navigate to the ~/rpmbuild/SPECS directory:

    $ cd ~/rpmbuild/SPECS
    Copy to Clipboard Toggle word wrap
  2. Create a spec file for each of the three implementations of the Hello World! program:

    $ rpmdev-newspec bello
    bello.spec created; type minimal, rpm version >= 4.11.
    
    $ rpmdev-newspec cello
    cello.spec created; type minimal, rpm version >= 4.11.
    
    $ rpmdev-newspec pello
    pello.spec created; type minimal, rpm version >= 4.11.
    Copy to Clipboard Toggle word wrap

    The ~/rpmbuild/SPECS/ directory now contains three spec files named bello.spec, cello.spec, and pello.spec.

  3. Examine the created files.

    The directives in the files represent those described in About spec files. In the following sections, you will populate a particular section in the output files of rpmdev-newspec.

6.4.2. Modifying an original spec file

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

Procedure

  1. Open the ~/rpmbuild/SPECS/<name>.spec file provided by the rpmdev-newspec utility.
  2. Populate the following directives of the spec file Preamble section:

    Name
    Name was already specified as an argument to rpmdev-newspec.
    Version
    Set Version to match the upstream release version of the source code.
    Release
    Release is automatically set to 1%{?dist}, which is initially 1.
    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 the https://example.com/%{name} format.
    Source

    Enter the URL to the upstream software source code. Link directly to the software version being packaged.

    Note

    The 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 the spec file.

    BuildRequires
    Specify build-time dependencies for the package.
    Requires
    Specify run-time dependencies for the package.
    BuildArch
    Specify the software architecture.
  3. 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.
    %conf
    Enter a command or series of commands to configure 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 the BUILDROOT 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 by Day-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.

6.4.3. An example spec file for a sample Bash program

You can use the following example spec file for the bello program written in bash for your reference.

An example spec file for the bello program written in bash

Name:           bello
Version:        0.1
Release:        1%{?dist}
Summary:        Hello World example implemented in bash script

License:        GPLv3+
URL:            https://www.example.com/%{name}
Source0:        https://www.example.com/%{name}/releases/%{name}-%{version}.tar.gz

Requires:       bash

BuildArch:      noarch

%description
The long-tail description for our Hello World Example implemented in
bash script.

%prep
%setup -q

%build

%install

mkdir -p %{buildroot}/%{_bindir}

install -m 0755 %{name} %{buildroot}/%{_bindir}/%{name}

%files
%license LICENSE
%{_bindir}/%{name}

%changelog
* Tue May 31 2016 Adam Miller <maxamillion@fedoraproject.org> - 0.1-1
- First bello package
- Example second item in the changelog for version-release 0.1-1
Copy to Clipboard Toggle word wrap

  • The BuildRequires directive, which specifies build-time dependencies for the package, was deleted because there is no building step for bello. 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 only bash, because the bello script requires only the bash shell environment to execute.
  • The %build section, which specifies how to build the software, is blank, because the bash script does not need to be built.
Note

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.

6.4.4. An example spec file for a sample Python program

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

Name:           pello
Version:        0.1.1
Release:        1%{?dist}
Summary:        Hello World example implemented in Python

License:        GPLv3+
URL:            https://www.example.com/%{name}
Source0:        https://www.example.com/%{name}/releases/%{name}-%{version}.tar.gz

BuildRequires:  python
Requires:       python
Requires:       bash

BuildArch:      noarch

%description
The long-tail description for our Hello World Example implemented in Python.

%prep
%setup -q

%build

python -m compileall %{name}.py

%install

mkdir -p %{buildroot}/%{_bindir}
mkdir -p %{buildroot}/usr/lib/%{name}

cat > %{buildroot}/%{_bindir}/%{name} <<EOF
#!/bin/bash
/usr/bin/python /usr/lib/%{name}/%{name}.pyc
EOF

chmod 0755 %{buildroot}/%{_bindir}/%{name}

install -m 0644 %{name}.py* %{buildroot}/usr/lib/%{name}/

%files
%license LICENSE
%dir /usr/lib/%{name}/
%{_bindir}/%{name}
/usr/lib/%{name}/%{name}.py*

%changelog
* Tue May 31 2016 Adam Miller <maxamillion@fedoraproject.org> - 0.1.1-1
  - First pello package
Copy to Clipboard Toggle word wrap

  • 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 BuildRequires directive, which specifies build-time dependencies for the package, includes only the python package. The pello program requires python 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.

6.4.5. An example spec file for a sample C program

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 cello program written in C

Name:           cello
Version:        1.0
Release:        1%{?dist}
Summary:        Hello World example implemented in C

License:        GPLv3+
URL:            https://www.example.com/%{name}
Source0:        https://www.example.com/%{name}/releases/%{name}-%{version}.tar.gz

Patch0:         cello-output-first-patch.patch

BuildRequires:  gcc
BuildRequires:  make

%description
The long-tail description for our Hello World Example implemented in
C.

%prep
%setup -q

%patch0

%build
make %{?_smp_mflags}

%install
%make_install

%files
%license LICENSE
%{_bindir}/%{name}

%changelog
* Tue May 31 2016 Adam Miller <maxamillion@fedoraproject.org> - 1.0-1
- First cello package
Copy to Clipboard Toggle word wrap

  • 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 by rpmbuild, and the cello program does not require anything outside of the core C standard libraries.
  • The %build section reflects the fact that in this example the Makefile 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.

6.5. Building RPMs

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.

6.5.1. Building a source RPM

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 exact spec 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:

    # dnf install rpm-build
    Copy to Clipboard Toggle word wrap
  • 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

  1. Navigate to the ~/rpmbuild/SPECS/ directive, which contains the created spec file:

    $ cd ~/rpmbuild/SPECS/
    Copy to Clipboard Toggle word wrap
  2. Build the source RPM by entering the rpmbuild command with the specified spec file:

    $ rpmbuild -bs <specfile>
    Copy to Clipboard Toggle word wrap

    The -bs option stands for the build source.

    For example, to build source RPMs for the bello, pello, and cello programs, enter:

    $ rpmbuild -bs bello.spec
    Wrote: /home/admiller/rpmbuild/SRPMS/bello-0.1-1.el8.src.rpm
    
    $ rpmbuild -bs pello.spec
    Wrote: /home/admiller/rpmbuild/SRPMS/pello-0.1.2-1.el8.src.rpm
    
    $ rpmbuild -bs cello.spec
    Wrote: /home/admiller/rpmbuild/SRPMS/cello-1.0-1.el8.src.rpm
    Copy to Clipboard Toggle word wrap

Verification

  • Verify that the rpmbuild/SRPMS directory includes the resulting source RPMs. The directory is a part of the structure expected by rpmbuild.

6.5.2. Rebuilding a binary RPM from a source RPM

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 either of the following directories:

  • ~/rpmbuild/RPMS/YOURARCH, where YOURARCH is your architecture.
  • ~/rpmbuild/RPMS/noarch/, if the package is not architecture-specific.

Prerequisites

  • You have installed the rpmbuild utility on your system:

    # dnf install rpm-build
    Copy to Clipboard Toggle word wrap

Procedure

  1. Navigate to the ~/rpmbuild/SRPMS/ directive, which contains the SRPM:

    $ cd ~/rpmbuild/SRPMS/
    Copy to Clipboard Toggle word wrap
  2. Rebuild the binary RPM from the SRPM:

    $ rpmbuild --rebuild <srpm>
    Copy to Clipboard Toggle word wrap

    For example, to rebuild bello, pello, and cello from their SRPMs, enter:

    $ rpmbuild --rebuild bello-0.1-1.el8.src.rpm
    [output truncated]
    
    $ rpmbuild --rebuild pello-0.1.2-1.el8.src.rpm
    [output truncated]
    
    $ rpmbuild --rebuild cello-1.0-1.el8.src.rpm
    [output truncated]
    Copy to Clipboard Toggle word wrap
Note

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, pello, and cello:

    $ rpm -Uvh ~/rpmbuild/SRPMS/bello-0.1-1.el8.src.rpm
    Updating / installing…​
       1:bello-0.1-1.el8               [100%]
    
    $ rpm -Uvh ~/rpmbuild/SRPMS/pello-0.1.2-1.el8.src.rpm
    Updating / installing…​
    …​1:pello-0.1.2-1.el8              [100%]
    
    $ rpm -Uvh ~/rpmbuild/SRPMS/cello-1.0-1.el8.src.rpm
    Updating / installing…​
    …​1:cello-1.0-1.el8            [100%]
    Copy to Clipboard Toggle word wrap

6.5.3. Building a binary RPM from a spec file

To build a binary RPM from its spec file, use the rpmbuild command with the -bb option.

Prerequisites

  • You have installed the rpmbuild utility on your system:

    # dnf install rpm-build
    Copy to Clipboard Toggle word wrap

Procedure

  1. Navigate to the ~/rpmbuild/SPECS/ directive, which contains spec files:

    $ cd ~/rpmbuild/SPECS/
    Copy to Clipboard Toggle word wrap
  2. Build the binary RPM from its spec:

    $ rpmbuild -bb <spec_file>
    Copy to Clipboard Toggle word wrap

    For example, to build bello, pello, and cello binary RPMs from their spec files, enter:

    $ rpmbuild -bb bello.spec
    
    $ rpmbuild -bb pello.spec
    
    $ rpmbuild -bb cello.spec
    Copy to Clipboard Toggle word wrap

6.6. Logging RPM activity to syslog

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:

    # dnf install rpm-plugin-syslog
    Copy to Clipboard Toggle word wrap
    Note

    The default location for the syslog messages is the /var/log/messages file. However, you can configure syslog to use another location to store the messages.

Procedure

  1. 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.

  2. Search for new lines including the [RPM] string.

6.7. Extracting RPM content

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.

Note

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
    Copy to Clipboard Toggle word wrap

    The resulting file has the .tgz suffix. For example, to create an archive from the bash package, enter:

    $ 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 Toggle word wrap

6.8. Signing RPM packages

You can sign RPM packages to ensure no third party can alter their content by using either of the following software:

  • Sequoia PGP supports the OpenPGP standard. RPM also uses Sequoia PGP to verify software signatures.
  • GNU Privacy Guard (GnuPG) supports older OpenPGP standard versions, which makes GnuPG more compatible with RHEL 9 and earlier versions.
Warning

Starting from version 10.1, RHEL supports OpenPGPv6 and RPMv6 signatures. These signatures are not compatible with earlier versions of RHEL. RPM on these versions ignore such signatures. If a package contains the RPMv4 signature, RPM uses it instead.

However, in RHEL 9.7 and later RHEL 9 versions, you can enable support for OpenPGPv6 and RPMv6 signatures by using the multisig DNF plugin.

6.8.1. Signing RPM packages with GnuPG

You can sign RPM packages by using the GNU Privacy Guard (GnuPG) software.

6.8.1.1. Creating an OpenPGP key for signing packages with GnuPG

To sign an RPM package by using the GNU Privacy Guard (GnuPG) software, you must create an OpenPGP key first.

Prerequisites

  • You have the rpm-sign and pinentry packages installed on your system.

Procedure

  1. Generate an OpenPGP key pair:

    $ gpg --gen-key
    Copy to Clipboard Toggle word wrap
  2. Check the generated key pair:

    $ gpg --list-keys
    Copy to Clipboard Toggle word wrap
  3. Export the public key:

    $ gpg --export -a '<public_key_name>' > RPM-GPG-KEY-pmanager
    Copy to Clipboard Toggle word wrap

6.8.1.2. Configuring RPM to sign a package with GnuPG

To sign an RPM package by using the GNU Privacy Guard (GnuPG) software, you must configure RPM by specifying the %_gpg_name RPM macro.

Prerequisites

Procedure

  • Define the %_gpg_name macro in your $HOME/.rpmmacros directory:

    %_gpg_name <key_ID>
    Copy to Clipboard Toggle word wrap

    A valid key ID value for GnuPG can be a key fingerprint, full name, or email address you provided when creating the key.

6.8.1.3. Adding a signature to an RPM package

Packages are commonly built without signatures. You can add your signature before the package is released.

Prerequisites

Procedure

  • Add a signature to a package:

    $ rpmsign --addsign <package-name>.rpm
    Copy to Clipboard Toggle word wrap

Verification

  1. Import the exported OpenPGP public key into the RPM keyring:

    # rpmkeys --import RPM-GPG-KEY-pmanager
    Copy to Clipboard Toggle word wrap
  2. Display the key ID with GnuPG:

    $ gpg --list-keys
    [...]
    pub   rsa3072 2025-05-13 [SC] [expires: 2028-05-12]
          A8AF1C39AC67A1501450734F6DE8FC866DE0394D
    [...]
    Copy to Clipboard Toggle word wrap

    The key ID is the 40-character string in the command output, for example, A8AF1C39AC67A1501450734F6DE8FC866DE0394D.

  3. Verify that the RPM file has the corresponding signature:

    $ rpm -Kv <package_name>.rpm
    <package_name>.rpm:
        Header V4 RSA/SHA256 Signature, key ID 6de0394d: OK
        Header SHA256 digest: OK
        Header SHA1 digest: OK
        Payload SHA256 digest: OK
        MD5 digest: OK
    Copy to Clipboard Toggle word wrap

    The signature key ID matches the last part of the OpenPGP key ID.

6.8.2. Signing RPM packages with Sequoia PGP

You can use Sequoia PGP to sign RPM packages and ensure no third party can alter their content.

6.8.2.1. Creating an OpenPGP key for signing packages with Sequoia PGP

To sign packages by using the Sequoia PGP software, you must create an OpenPGP key first.

Procedure

  1. Install the Sequoia PGP tools:

    # dnf install sequoia-sq
    Copy to Clipboard Toggle word wrap
  2. Generate an OpenPGP key pair:

    $ sq key generate --own-key --userid <key_name>
    Copy to Clipboard Toggle word wrap
  3. Check the generated key pair:

    $ sq key list
    Copy to Clipboard Toggle word wrap
  4. Export the public key:

    $ sq cert export --cert-userid '<key_name>' > RPM-PGP-KEY-pmanager
    Copy to Clipboard Toggle word wrap

6.8.2.2. Configuring RPM to sign a package with Sequoia PGP

To sign an RPM package with the Sequoia PGP software, you must configure the RPM to use Sequoia PGP and specify the %_gpg_name macro.

Prerequisites

  • You have the rpm-sign package installed on your system.

Procedure

  1. Copy the macros.rpmsign-sequoia file to the /etc/rpm directory:

    # cp /usr/share/doc/rpm/macros.rpmsign-sequoia /etc/rpm/
    Copy to Clipboard Toggle word wrap
  2. Get a valid OpenPGP key fingerprint value from the output of key listing:

    $ sq cert list --cert-userid '<key_name>'
     - 7E4B52101EB3DB08967A1E5EB595D12FDA65BA50
       - created 2025-05-13 10:33:29 UTC
       - will expire 2028-05-13T03:59:50Z
    
       - [    ✓    ] <key_name>
    Copy to Clipboard Toggle word wrap

    The key fingerprint is a 40-character string on the first line of the output, for example, 7E4B52101EB3DB08967A1E5EB595D12FDA65BA50.

  3. Define the %_gpg_name macro in your $HOME/.rpmmacros file as follows:

    %_gpg_name <key_fingerprint>
    Copy to Clipboard Toggle word wrap

    Note that you can also use the full key ID instead of the fingerprint.

    Note

    Unlike GnuPG, Sequoia PGP accepts only the full key ID or fingerprint.

6.8.2.3. Adding a signature to an RPM package

Packages are commonly built without signatures. You can add your signature before the package is released.

Prerequisites

Procedure

  • Add a signature to a package:

    $ rpmsign --addsign <package-name>.rpm
    Copy to Clipboard Toggle word wrap

Verification

  1. Import the exported OpenPGP public key into the RPM keyring:

    # rpmkeys --import RPM-PGP-KEY-pmanager
    Copy to Clipboard Toggle word wrap
  2. Display the key fingerprint of the signing key:

    $ sq key list --cert-userid <key_name>
     - 7E4B52101EB3DB08967A1E5EB595D12FDA65BA50
       - user ID: <key_name> (authenticated)
       - created 2025-05-13 10:33:29 UTC
       - will expire 2028-05-13T03:59:50Z
       - usable for signing
       - @softkeys/7E4B52101EB3DB08967A1E5EB595D12FDA65BA50: available, unlocked
    
       - 78E56DD2E12E02CFEEA27F8B9FE57972D6BCEA6F
         - created 2025-05-13 10:33:29 UTC
         - will expire 2028-05-13T03:59:50Z
         - usable for decryption
         - @softkeys/7E4B52101EB3DB08967A1E5EB595D12FDA65BA50: available, unlocked
       - C06E45F8ABC3E59F44A9E811578DDDB66422E345
         - created 2025-05-13 10:33:29 UTC
         - will expire 2028-05-13T03:59:50Z
         - usable for signing
         - @softkeys/7E4B52101EB3DB08967A1E5EB595D12FDA65BA50: available, unlocked
       - E0BD231AB350AD6802D44C0A270E79FFC39C3B25
         - created 2025-05-13 10:33:29 UTC
         - will expire 2028-05-13T03:59:50Z
         - usable for signing
         - @softkeys/7E4B52101EB3DB08967A1E5EB595D12FDA65BA50: available, unlocked
    Copy to Clipboard Toggle word wrap

    The key fingerprint is usually a signing subkey in the sq key list --cert-userid <key_name> command output, for example, E0BD231AB350AD6802D44C0A270E79FFC39C3B25.

  3. Verify that the RPM file has the corresponding signature, for example:

    $ rpm -Kv <package_name>.rpm
    <package_name>.rpm:
        Header V4 EdDSA/SHA512 Signature, key ID c39c3b25: OK
        Header SHA256 digest: OK
        Header SHA1 digest: OK
        Payload SHA256 digest: OK
        MD5 digest: OK
    Copy to Clipboard Toggle word wrap

    The signature key ID matches the last part of the key fingerprint.

6.8.3. Signing RPM packages with Sequoia PGP by using PQC

Post-quantum cryptography (PQC) is a set of algorithms designed to withstand attacks from quantum computers, thereby enhancing software security. To sign a package with PQC algorithms, you can use Sequoia PGP software.

The RPM package manager uses the OpenPGP standard to sign packages. OpenPGPv6 introduces support for hybrid keys and signatures. They combine the current cryptographic algorithm with the PQC algorithm, preventing a single point of failure and increasing trust in the resulting signature.

Starting from version 10.1, RHEL supports RPMv6 signatures. With this format, you can add multiple OpenPGP signatures to a package, increasing the redundancy on the RPM level.

You can combine both RPMv4 and RPMv6 signatures to sign the package. With this feature, you can use different RPM versions to verify the same signature. Starting from RHEL 10.1, RPM verifies only the RPMv6 signatures, if such exist, and ignores the RPMv4 ones. If no RPMv6 signatures are present in the package, RPM uses the RPMv4 signatures. In earlier RHEL versions, RPM verifies RPMv4 signatures and ignores RPMv6 ones.

6.8.3.1. Creating a PQC key

To sign packages by using post-quantum cryptography (PQC) algorithms, you must create a hybrid key pair with Sequoia PGP first.

Note that you can specify different PQC algorithms. For example, the following procedure uses the ML-DSA-87-Ed448 algorithm.

Procedure

  1. Install the Sequoia PGP tools:

    # dnf install sequoia-sq
    Copy to Clipboard Toggle word wrap
  2. Generate an OpenPGP key pair:

    $ sq key generate --own-key --expiration=never \ --cannot-authenticate --cannot-encrypt \ --email <vendor_email> --name "<vendor_name>" \ --cipher-suite mldsa87 --profile rfc9580
    Copy to Clipboard Toggle word wrap

    Replace <vendor_email> and <vendor_name> with the email and the name of the software vendor that provides the RPM package.

    This command generates a primary key and a signing subkey.

  3. Check the generated key pair:

    $ sq key list --cert-email <vendor_email>
    Copy to Clipboard Toggle word wrap
     - <ml_dsa_fingerprint>
       - user IDs:
         - <vendor_email> (authenticated)
         - <vendor_name> (authenticated)
       - created 2025-10-03 14:36:44 UTC
       - usable for signing
       - @softkeys/<ml_dsa_fingerprint>: available, unlocked
    
       - <subkey_fingerprint>
         - created 2025-10-03 14:36:44 UTC
         - usable for signing
         - @softkeys/<subkey_fingerprint>: available, unlocked
    Copy to Clipboard Toggle word wrap
  4. Export the PQC OpenPGP certificate:

    $ sq cert export --cert-email '<vendor_email>' > RPM-PGP-KEY-VENDOR
    Copy to Clipboard Toggle word wrap

6.8.3.2. Configuring RPM for PQC

After you generate a PQC key you want to use to sign a package, you must configure RPM to use this key.

Configure RPM outside of the build system on a separate signing server. RPM requires macros to support signing packages with Sequoia PGP. These macros are available in a template file.

Prerequisites

  • You created a PQC key pair. For more information, see Creating a PQC key.
  • You have the rpm-sign package installed on your system.

Procedure

  1. Copy the macros.rpmsign-sequoia file to the /etc/rpm directory:

    # cp /usr/share/doc/rpm/macros.rpmsign-sequoia /etc/rpm/
    Copy to Clipboard Toggle word wrap
  2. Check the generated key pair:

    $ sq key list --cert-email <vendor_email>
    Copy to Clipboard Toggle word wrap
     - <ml_dsa_fingerprint>
       - user IDs:
         - <vendor_email> (authenticated)
         - <vendor_name> (authenticated)
       - created 2025-10-03 14:36:44 UTC
       - usable for signing
       - @softkeys/<ml_dsa_fingerprint>: available, unlocked
    
       - <subkey_fingerprint>
         - created 2025-10-03 14:36:44 UTC
         - usable for signing
         - @softkeys/<subkey_fingerprint>: available, unlocked
    Copy to Clipboard Toggle word wrap
  3. Export the key fingerprint to the ~/.rpmmacros file:

    $ echo "%_gpg_name <ml_dsa_fingerprint>" > ~/.rpmmacros
    Copy to Clipboard Toggle word wrap

6.8.3.3. Adding multiple signatures to an RPM

Starting from version 10.1, RHEL supports RPMv6 signatures. With this format, you can add multiple signatures to an RPM package. This results in enhanced security if either of the keys gets compromised or either of the cryptographic algorithms is rendered insecure.

You can run the rpmsign --addsign --rpmv6 command multiple times to sign the RPM with multiple different keys. Note that the first RPMv6 signature, usually generated with an OpenPGPv4 RSA key and compatible with the RPMv4, is also stored as an RPMv4 signature. This allows older RPM versions to trust the package signature.

Important

Always consider adding an RPMv4-compatible signature to the package before adding any RPMv6 signatures that use PQC algorithms. This ensures that the package has a signature that RPM on RHEL versions earlier than RHEL 10.1 can verify.

Prerequisites

Procedure

  1. Add a signature to a package:

    $ rpmsign --addsign --rpmv6 <package_name>.rpm
    Copy to Clipboard Toggle word wrap
  2. To sign the package with multiple RPMv6 signatures, repeat the first step.

Verification

  1. Import the exported PQC OpenPGP certificate into the RPM keyring:

    # rpmkeys --import RPM-PGP-KEY-VENDOR
    Copy to Clipboard Toggle word wrap
  2. Verify that the RPM file has the corresponding signatures, for example:

    $ rpmkeys -Kv <package_name>.rpm
    Copy to Clipboard Toggle word wrap
    <package_name>.rpm:
        Header OpenPGP V6 ML-DSA-87+Ed448/SHA512 signature, key fingerprint: <ml_dsa_fingerprint>: OK
        Header OpenPGP V4 RSA/SHA512 signature, key fingerprint: <rsa_fingerprint>: OK
        Header SHA256 digest: OK
        Payload SHA256 digest: OK
    Copy to Clipboard Toggle word wrap
Voltar ao topo
Red Hat logoGithubredditYoutubeTwitter

Aprender

Experimente, compre e venda

Comunidades

Sobre a documentação da Red Hat

Ajudamos os usuários da Red Hat a inovar e atingir seus objetivos com nossos produtos e serviços com conteúdo em que podem confiar. Explore nossas atualizações recentes.

Tornando o open source mais inclusivo

A Red Hat está comprometida em substituir a linguagem problemática em nosso código, documentação e propriedades da web. Para mais detalhes veja o Blog da Red Hat.

Sobre a Red Hat

Fornecemos soluções robustas que facilitam o trabalho das empresas em plataformas e ambientes, desde o data center principal até a borda da rede.

Theme

© 2025 Red Hat