How to do RPM packaging and distribute software

How to do RPM packaging and distribute software

rpm_packaging

Here in this article we will see how we can prepare source code, build and package the source code into RPM packages using the RPM package management tools and utilities. We will using a very basic python program to demonstrate this activity.

Test Environment

Fedora 36 server

What is RPM

RPM also called RPM Package Management system is a tool that helps in distributing, managing and updating the software on the system. It’s used on Linux based system (ie. Redhat, CentOS, Fedora). Some of the advantages of RPM management system is that it helps in installing, updating, removing and verify the software packages. The information related to packages that are installed is stored in a RPM database which can be queries.

It is also used to prepare the RPM packages with the sources files, utilities and build instructions which can be further distributed using by uploading them into the RPM repositories. Also it provides us with the facilities to sign the RPM packages using GNU GPG signing keys for maintaing the integrity of the packages.

If you are interested in watching the video. Here is the YouTube video on the same step by step procedure outlined below.

Procedure

Step1: Create a Python Hello World Program

Source code file contains human readable instructions which are given to the computer for carrying out the computational task. Here is a simple python helloworld source code which we will use here to package as an RPM for Fedora OS.

[admin@fedser36 ~]$ mkdir rpmpackaging
[admin@fedser36 ~]$ cd rpmpackaging/

[admin@fedser36 rpmpackaging]$ cat helloworld.py 
#!/usr/bin/env python3

print("Hello Python!!")

Step2: Building Python Source code

For software written in compiled languages, the source code goes through a build process, producing machine code (eg. C/C++ language).
For software written in raw interpreted languages, the source code is not built, but executed directly (eg. Bash language).
For software written in byte-compiled interpreted languages, the source code is compiled into byte code, which is then executed by the language virtual machine (eg. Python).

In our case as we are building a Python source code so it comes in the third category of the software build process.

Compile the Python source code

[admin@fedser36 rpmpackaging]$ python3 -m compileall helloworld.py 
Compiling 'helloworld.py'...
[admin@fedser36 rpmpackaging]$ tree .
.
├── helloworld.py
└── __pycache__
    └── helloworld.cpython-310.pyc

As you can see the above step generates a compiled python file in pycache folder.

NOTE: Python is often byte-compiled, but not in the way described here. The following procedure aims not to conform to the community standards, but to be simple. For real-
world Python guidelines, see Software Packaging and Distribution.

Step3: Packaging the source code into a tarball

Developers often distribute software as compressed archives of source code, which are then used to create packages. Before packaging the source code make sure we create a license file as shown below to be incorporated into our package as the software should always be distributed with a software license.

[admin@fedser36 rpmpackaging]$ cat LICENSE 
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Create a folder with version for the packaging and put required source code and license file for packaging

[admin@fedser36 rpmpackaging]$ mkdir ./helloworld-0.1.1
[admin@fedser36 rpmpackaging]$ mv helloworld.py ./helloworld-0.1.1/
[admin@fedser36 rpmpackaging]$ cp LICENSE ./helloworld-0.1.1/

Create the archive for distribution

[admin@fedser36 rpmpackaging]$ tar -cvzf helloworld-0.1.1.tar.gz helloworld-0.1.1
helloworld-0.1.1/
helloworld-0.1.1/helloworld.py
helloworld-0.1.1/LICENSE
[admin@fedser36 rpmpackaging]$ ls -ltr helloworld-0.1.1.tar.gz 
-rw-r--r--. 1 admin admin 600 Jun 25 13:43 helloworld-0.1.1.tar.gz

Step4: Install RPM packaging tool

Here in this step we are going to install the core tools for RPM packaging provided by rpmdevtools package. Along with that we are going to install rpmlint for carrying out package sanity (ie. verification) and git as a week dependency for source code management.

[admin@fedser36 rpmpackaging]$ sudo dnf install rpmdevtools rpmlint git-all
...
Installed:
  ansible-srpm-macros-1-5.fc36.noarch         binutils-2.37-27.fc36.x86_64                    binutils-gold-2.37-27.fc36.x86_64                debugedit-5.0-3.fc36.x86_64                   
  dwz-0.14-2.fc35.x86_64                      efi-srpm-macros-5-5.fc36.noarch                 fakeroot-1.29-1.fc36.x86_64                      fakeroot-libs-1.29-1.fc36.x86_64              
  fonts-srpm-macros-1:2.0.5-7.fc36.noarch     fpc-srpm-macros-1.3-5.fc36.noarch               ghc-srpm-macros-1.5.0-6.fc36.noarch              gnat-srpm-macros-4-15.fc36.noarch             
  go-srpm-macros-3.0.15-1.fc36.noarch         http-parser-2.9.4-6.fc36.x86_64                 kernel-srpm-macros-1.0-14.fc36.noarch            koji-1.29.0-1.fc36.noarch                     
  libgit2-1.3.0-2.fc36.x86_64                 libssh2-1.10.0-4.fc36.x86_64                    lua-srpm-macros-1-6.fc36.noarch                  nim-srpm-macros-3-6.fc36.noarch               
  ocaml-srpm-macros-6-6.fc36.noarch           openblas-srpm-macros-2-11.fc36.noarch           package-notes-srpm-macros-0.4-14.fc36.noarch     patch-2.7.6-16.fc36.x86_64                    
  perl-srpm-macros-1-43.fc36.noarch           python-srpm-macros-3.10-18.fc36.noarch          python3-babel-2.9.1-5.fc36.noarch                python3-decorator-5.1.1-2.fc36.noarch         
  python3-gssapi-1.7.2-2.fc36.x86_64          python3-koji-1.29.0-1.fc36.noarch               python3-progressbar2-3.53.2-4.fc36.noarch        python3-pygit2-1.7.1-3.fc36.x86_64            
  python3-pytz-2022.1-1.fc36.noarch           python3-requests-gssapi-1.2.3-4.fc36.noarch     python3-rpmautospec-0.2.6-1.fc36.noarch          python3-utils-2.5.6-5.fc36.noarch             
  qt5-srpm-macros-5.15.3-1.fc36.noarch        redhat-rpm-config-221-1.fc36.noarch             rpm-build-4.17.0-10.fc36.x86_64                  rpmautospec-rpm-macros-0.2.6-1.fc36.noarch    
  rpmdevtools-9.6-1.fc36.noarch               rust-srpm-macros-21-1.fc36.noarch               systemd-rpm-macros-250.3-8.fc36.noarch           zstd-1.5.2-2.fc36.x86_64                      
...
Complete!

We can list the RPM packaging utilities provides by the above package as shown below.

[admin@fedser36 rpmpackaging]$ rpm -ql rpmdevtools | grep bin
/usr/bin/rpmargs
/usr/bin/rpmdev-bumpspec
/usr/bin/rpmdev-checksig
/usr/bin/rpmdev-cksum
/usr/bin/rpmdev-diff
/usr/bin/rpmdev-extract
/usr/bin/rpmdev-md5
/usr/bin/rpmdev-newinit
/usr/bin/rpmdev-newspec
/usr/bin/rpmdev-packager
/usr/bin/rpmdev-rmdevelrpms
/usr/bin/rpmdev-setuptree
/usr/bin/rpmdev-sha1
/usr/bin/rpmdev-sha224
/usr/bin/rpmdev-sha256
/usr/bin/rpmdev-sha384
/usr/bin/rpmdev-sha512
/usr/bin/rpmdev-sort
/usr/bin/rpmdev-spectool
/usr/bin/rpmdev-sum
/usr/bin/rpmdev-vercmp
/usr/bin/rpmdev-wipetree
/usr/bin/rpmelfsym
/usr/bin/rpmfile
/usr/bin/rpminfo
/usr/bin/rpmls
/usr/bin/rpmpeek
/usr/bin/rpmsodiff
/usr/bin/rpmsoname
/usr/bin/spectool

Step5: Setup RPM packaging workspace

The below step helps in preparing the skeleton workspace directory structure for RPM package building.

[admin@fedser36 rpmpackaging]$ rpmdev-setuptree
[admin@fedser36 rpmpackaging]$ tree ~
/home/admin/
├── rpmbuild
│   ├── BUILD
│   ├── RPMS
│   ├── SOURCES
│   ├── SPECS
│   └── SRPMS

Step6: Copy the Compressed source file package into RPM build workspace

Copy the compressed tar archive of source code into the RPM packing workspace location as shown below.

[admin@fedser36 rpmpackaging]$ cp helloworld-0.1.1.tar.gz ~/rpmbuild/SOURCES/

Step7: Create new RPM build spec file

A build spec file contains information that is required by rpmbuild utility to build an RPM. There are two types of RPM packages that we could build.

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 patches to source code are included as well.
Binary RPM (RPM) – A binary RPM contains the binaries built from the sources and patches.

The spec file can be divided into two sections, they are preamble and body part. The Preamble part contains a series of metadata items that are used in the Body part. The Body part represents the main part of the instructions. We can create a new build spec file with the below command.

[admin@fedser36 rpmpackaging]$ cd ~/rpmbuild/SPECS
[admin@fedser36 SPECS]$ rpmdev-newspec helloworld
helloworld.spec created; type minimal, rpm version >= 4.17.

Update the spec file as shown below with the server details as per your hostname. These are just dummy references provided.

[admin@fedser36 SPECS]$ cat helloworld.spec 
Name:           helloworld
Version:	0.1.1        
Release:        1%{?dist}
Summary:        Python HelloWorld package

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

BuildRequires:  python3
Requires:       python3
Requires:	bash

BuildArch:	noarch

%description
This is simple python helloworld rpm package

%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/python3 /usr/lib/%{name}/%{name}.py
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
* Sat Jun 25 2022 admin	- 0.1.1
- Hello World Python Package

Step8: Building Source RPM package

Here in this step we are going to build the source rpm (ie. SRPM) as shown below. This will write the SRPM into the build workspace under SRPMS subfolder as shown below.

[admin@fedser36 SPECS]$ rpmbuild -bs helloworld.spec 
setting SOURCE_DATE_EPOCH=1656115200
Wrote: /home/admin/rpmbuild/SRPMS/helloworld-0.1.1-1.fc36.src.rpm

[admin@fedser36 SPECS]$ rpm -ql /home/admin/rpmbuild/SRPMS/helloworld-0.1.1-1.fc36.src.rpm
helloworld-0.1.1.tar.gz
helloworld.spec

Step9: Building Binary RPM package

Here in this step we are going to build the binary rpm (ie. RPM) as shown below. This will write the Binary RPM into the build workspace under RPMS subfolder as shown below.

[admin@fedser36 SPECS]$ rpmbuild -bs helloworld.spec 
setting SOURCE_DATE_EPOCH=1656115200
Wrote: /home/admin/rpmbuild/SRPMS/helloworld-0.1.1-1.fc36.src.rpm
[admin@fedser36 SPECS]$ 
[admin@fedser36 SPECS]$ rpmbuild -bb helloworld.spec 
setting SOURCE_DATE_EPOCH=1656115200
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.XbA2iy
+ umask 022
+ cd /home/admin/rpmbuild/BUILD
+ cd /home/admin/rpmbuild/BUILD
+ rm -rf helloworld-0.1.1
+ /usr/bin/gzip -dc /home/admin/rpmbuild/SOURCES/helloworld-0.1.1.tar.gz
+ /usr/bin/tar -xof -
+ STATUS=0
+ '[' 0 -ne 0 ']'
+ cd helloworld-0.1.1
+ /usr/bin/chmod -Rf a+rX,u+w,g-w,o-w .
+ RPM_EC=0
++ jobs -p
+ exit 0
Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.nnunTZ
+ umask 022
+ cd /home/admin/rpmbuild/BUILD
+ CFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -m64  -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection'
+ export CFLAGS
+ CXXFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -m64  -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection'
+ export CXXFLAGS
+ FFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -m64  -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -I/usr/lib64/gfortran/modules'
+ export FFLAGS
+ FCFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -m64  -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -I/usr/lib64/gfortran/modules'
+ export FCFLAGS
+ LDFLAGS='-Wl,-z,relro -Wl,--as-needed  -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -Wl,--build-id=sha1 -Wl,-dT,/home/admin/rpmbuild/BUILD/helloworld-0.1.1/.package_note-helloworld-0.1.1-1.fc36.x86_64.ld'
+ export LDFLAGS
+ LT_SYS_LIBRARY_PATH=/usr/lib64:
+ export LT_SYS_LIBRARY_PATH
+ CC=gcc
+ export CC
+ CXX=g++
+ export CXX
+ '[' -f /usr/lib/rpm/generate-rpm-note.sh ']'
+ /usr/lib/rpm/generate-rpm-note.sh helloworld 0.1.1-1.fc36 x86_64
+ cd helloworld-0.1.1
+ python3 -m compileall helloworld.py
Compiling 'helloworld.py'...
+ RPM_EC=0
++ jobs -p
+ exit 0
Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.qMBnXh
+ umask 022
+ cd /home/admin/rpmbuild/BUILD
+ '[' /home/admin/rpmbuild/BUILDROOT/helloworld-0.1.1-1.fc36.x86_64 '!=' / ']'
+ rm -rf /home/admin/rpmbuild/BUILDROOT/helloworld-0.1.1-1.fc36.x86_64
++ dirname /home/admin/rpmbuild/BUILDROOT/helloworld-0.1.1-1.fc36.x86_64
+ mkdir -p /home/admin/rpmbuild/BUILDROOT
+ mkdir /home/admin/rpmbuild/BUILDROOT/helloworld-0.1.1-1.fc36.x86_64
+ CFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -m64  -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection'
+ export CFLAGS
+ CXXFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -m64  -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection'
+ export CXXFLAGS
+ FFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -m64  -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -I/usr/lib64/gfortran/modules'
+ export FFLAGS
+ FCFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -m64  -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -I/usr/lib64/gfortran/modules'
+ export FCFLAGS
+ LDFLAGS='-Wl,-z,relro -Wl,--as-needed  -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -Wl,--build-id=sha1 -Wl,-dT,/home/admin/rpmbuild/BUILD/helloworld-0.1.1/.package_note-helloworld-0.1.1-1.fc36.x86_64.ld'
+ export LDFLAGS
+ LT_SYS_LIBRARY_PATH=/usr/lib64:
+ export LT_SYS_LIBRARY_PATH
+ CC=gcc
+ export CC
+ CXX=g++
+ export CXX
+ cd helloworld-0.1.1
+ mkdir -p /home/admin/rpmbuild/BUILDROOT/helloworld-0.1.1-1.fc36.x86_64//usr/bin
+ mkdir -p /home/admin/rpmbuild/BUILDROOT/helloworld-0.1.1-1.fc36.x86_64/usr/lib/helloworld
+ cat
+ chmod 0755 /home/admin/rpmbuild/BUILDROOT/helloworld-0.1.1-1.fc36.x86_64//usr/bin/helloworld
+ install -m 0644 helloworld.py /home/admin/rpmbuild/BUILDROOT/helloworld-0.1.1-1.fc36.x86_64/usr/lib/helloworld/
+ /usr/bin/find-debuginfo -j8 --strict-build-id -m -i --build-id-seed 0.1.1-1.fc36 --unique-debug-suffix -0.1.1-1.fc36.x86_64 --unique-debug-src-base helloworld-0.1.1-1.fc36.x86_64 --run-dwz --dwz-low-mem-die-limit 10000000 --dwz-max-die-limit 110000000 -S debugsourcefiles.list /home/admin/rpmbuild/BUILD/helloworld-0.1.1
find: 'debug': No such file or directory
+ '[' '%{buildarch}' = noarch ']'
+ QA_CHECK_RPATHS=1
+ case "${QA_CHECK_RPATHS:-}" in
+ /usr/lib/rpm/check-rpaths
+ /usr/lib/rpm/check-buildroot
+ /usr/lib/rpm/redhat/brp-ldconfig
+ /usr/lib/rpm/brp-compress
+ /usr/lib/rpm/redhat/brp-strip-lto /usr/bin/strip
+ /usr/lib/rpm/brp-strip-static-archive /usr/bin/strip
+ /usr/lib/rpm/check-rpaths
+ /usr/lib/rpm/redhat/brp-mangle-shebangs
mangling shebang in /usr/bin/helloworld from /bin/bash to #!/usr/bin/bash
+ /usr/lib/rpm/brp-remove-la-files
+ /usr/lib/rpm/redhat/brp-python-bytecompile '' 1 0
+ /usr/lib/rpm/redhat/brp-python-hardlink
Processing files: helloworld-0.1.1-1.fc36.noarch
Executing(%license): /bin/sh -e /var/tmp/rpm-tmp.XgK7fI
+ umask 022
+ cd /home/admin/rpmbuild/BUILD
+ cd helloworld-0.1.1
+ LICENSEDIR=/home/admin/rpmbuild/BUILDROOT/helloworld-0.1.1-1.fc36.x86_64/usr/share/licenses/helloworld
+ export LC_ALL=C
+ LC_ALL=C
+ export LICENSEDIR
+ /usr/bin/mkdir -p /home/admin/rpmbuild/BUILDROOT/helloworld-0.1.1-1.fc36.x86_64/usr/share/licenses/helloworld
+ cp -pr LICENSE /home/admin/rpmbuild/BUILDROOT/helloworld-0.1.1-1.fc36.x86_64/usr/share/licenses/helloworld
+ RPM_EC=0
++ jobs -p
+ exit 0
Provides: helloworld = 0.1.1-1.fc36
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(FileDigests) <= 4.6.0-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Requires: /usr/bin/bash
Checking for unpackaged file(s): /usr/lib/rpm/check-files /home/admin/rpmbuild/BUILDROOT/helloworld-0.1.1-1.fc36.x86_64
Wrote: /home/admin/rpmbuild/RPMS/noarch/helloworld-0.1.1-1.fc36.noarch.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.6uuykP
+ umask 022
+ cd /home/admin/rpmbuild/BUILD
+ cd helloworld-0.1.1
+ /usr/bin/rm -rf /home/admin/rpmbuild/BUILDROOT/helloworld-0.1.1-1.fc36.x86_64
+ RPM_EC=0
++ jobs -p
+ exit 0

Step10: Checking the RPM spec for sanity

rpmlint is a tool provided to validate the SPEC files and RPMS that were build to check for common errors in rpm packages.

Checking the build spec file

[admin@fedser36 SPECS]$ rpmlint helloworld.spec 
=================================================================================== rpmlint session starts ===================================================================================
rpmlint: 2.2.0
configuration:
    /usr/lib/python3.10/site-packages/rpmlint/configdefaults.toml
    /etc/xdg/rpmlint/fedora.toml
    /etc/xdg/rpmlint/licenses.toml
    /etc/xdg/rpmlint/scoring.toml
    /etc/xdg/rpmlint/users-groups.toml
    /etc/xdg/rpmlint/warn-on-functions.toml
checks: 32, packages: 1

helloworld.spec:2: W: mixed-use-of-spaces-and-tabs (spaces: line 1, tab: line 2)
==================================================== 0 packages and 1 specfiles checked; 0 errors, 1 warnings, 0 badness; has taken 0.0 s ====================================================

Checking the Source RPM

[admin@fedser36 SPECS]$ rpmlint ~/rpmbuild/SRPMS/helloworld-0.1.1-1.fc36.src.rpm 
=================================================================================== rpmlint session starts ===================================================================================
rpmlint: 2.2.0
configuration:
    /usr/lib/python3.10/site-packages/rpmlint/configdefaults.toml
    /etc/xdg/rpmlint/fedora.toml
    /etc/xdg/rpmlint/licenses.toml
    /etc/xdg/rpmlint/scoring.toml
    /etc/xdg/rpmlint/users-groups.toml
    /etc/xdg/rpmlint/warn-on-functions.toml
checks: 32, packages: 1

helloworld.src: W: name-repeated-in-summary HelloWorld
helloworld.spec:2: W: mixed-use-of-spaces-and-tabs (spaces: line 1, tab: line 2)
==================================================== 1 packages and 0 specfiles checked; 0 errors, 2 warnings, 0 badness; has taken 0.1 s ====================================================

Checking the Binary RPM

[admin@fedser36 SPECS]$ rpmlint ~/rpmbuild/RPMS/noarch/helloworld-0.1.1-1.fc36.noarch.rpm 
=================================================================================== rpmlint session starts ===================================================================================
rpmlint: 2.2.0
configuration:
    /usr/lib/python3.10/site-packages/rpmlint/configdefaults.toml
    /etc/xdg/rpmlint/fedora.toml
    /etc/xdg/rpmlint/licenses.toml
    /etc/xdg/rpmlint/scoring.toml
    /etc/xdg/rpmlint/users-groups.toml
    /etc/xdg/rpmlint/warn-on-functions.toml
checks: 32, packages: 1

helloworld.noarch: W: only-non-binary-in-usr-lib
helloworld.noarch: E: non-executable-script /usr/lib/helloworld/helloworld.py 644 /usr/bin/env python3
helloworld.noarch: W: no-manual-page-for-binary helloworld
helloworld.noarch: W: no-documentation
helloworld.noarch: W: name-repeated-in-summary HelloWorld
helloworld.noarch: W: incoherent-version-in-changelog 0.1.1 ['0.1.1-1.fc36', '0.1.1-1']
==================================================== 1 packages and 0 specfiles checked; 1 errors, 5 warnings, 1 badness; has taken 0.0 s ====================================================

The non-executable-script error warns that the /usr/lib/helloworld/helloworld.py file has no execute permissions. The rpmlint tool expects the file to be executable, because the file contains the shebang. For the purpose of this example, you can leave this file without execute permissions and ignore this error.

Step11: Logging RPM activity to syslog

The below logging package installation allows us to track all the activities related to the package in the syslog messages which will help in later troubleshooting if any issues with the RPM management.

[admin@fedser36 SPECS]$ sudo dnf install rpm-plugin-syslog

Step12: Install Binary RPM package

[admin@fedser36 SPECS]$ sudo dnf install ~/rpmbuild/RPMS/noarch/helloworld-0.1.1-1.fc36.noarch.rpm 
Last metadata expiration check: 2:51:26 ago on Saturday 25 June 2022 12:31:24 PM.
Dependencies resolved.
==============================================================================================================================================================================================
 Package                                      Architecture                             Version                                           Repository                                      Size
==============================================================================================================================================================================================
Installing:
 helloworld                                   noarch                                   0.1.1-1.fc36                                      @commandline                                   7.7 k

Transaction Summary
==============================================================================================================================================================================================
Install  1 Package

Total size: 7.7 k
Installed size: 724  
Is this ok [y/N]: y
Downloading Packages:
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                                                                                                                                      1/1 
  Installing       : helloworld-0.1.1-1.fc36.noarch                                                                                                                                       1/1 
  Running scriptlet: helloworld-0.1.1-1.fc36.noarch                                                                                                                                       1/1 
  Verifying        : helloworld-0.1.1-1.fc36.noarch                                                                                                                                       1/1 

Installed:
  helloworld-0.1.1-1.fc36.noarch                                                                                                                                                              

Complete!

Now that we have our Binary RPM package installed, let us verify the information related to our RPM package as shown below.

[admin@fedser36 SPECS]$ rpm -qi helloworld 
Name        : helloworld
Version     : 0.1.1
Release     : 1.fc36
Architecture: noarch
Install Date: Saturday 25 June 2022 03:22:54 PM
Group       : Unspecified
Size        : 724
License     : GPLv3+
Signature   : (none)
Source RPM  : helloworld-0.1.1-1.fc36.src.rpm
Build Date  : Saturday 25 June 2022 03:06:39 PM
Build Host  : fedser36.stack.com
URL         : https://fedser36.stack.com/helloworld
Summary     : Python HelloWorld package
Description :
This is simple python helloworld rpm package

Now, let us list the package file which are installed on the system.

Now, let us list the package file which are installed on the system.

[admin@fedser36 SPECS]$ rpm -ql helloworld 
/usr/bin/helloworld
/usr/lib/helloworld
/usr/lib/helloworld/helloworld.py
/usr/share/licenses/helloworld
/usr/share/licenses/helloworld/LICENSE

Now, we are ready to run our “Hello Python” software as a binary shown below.

[admin@fedser36 SPECS]$ helloworld 
Hello Python!!

NOTE: Files installed from the RPM packages are placed according to Filesystem Hierarchy Standard (ie. FHS). For example, an executable file should go into a directory that is in the system $PATH variable.

Hope you enjoyed reading this article. Thank you..