Skip to main content

How to package open source applications as RPMs

Want to use a piece of third-party software but there's no RPM to install it? No problem: You can customize third-party software packages with RPM.
Hands holding a small package

Photo by Liza Summer from Pexels

Recently, I wrote about packaging your own software with Red Hat Package Manager (RPM). Another common scenario is that you find a piece of software you want to use, but there is no RPM for it. This article shows you how to create RPMs for third-party applications.

Prerequisites include:

  • You have basic knowledge of how to use RPM to query packages and install or delete packages. If not, get familiar with these concepts first and then come back here for some fun.
  • You have Make, Git, GCC, and Java installed, as you'll need them to complete the exercises included here. It's not required, but it would be nice if you practice as I move along.

To install Make, GCC, Java 11, and Git using the DNF package manager, run:

$ sudo dnf install \
make git gcc-10 \

For this example, I'll use a Java benchmark I like from NASA: NAS Parallel Benchmarks (NPB3.0). I took this code and made a fork, adding only an improved build using Gradle. Here are the steps.

Step 1: Write a skeleton spec file

$  rpmdev-newspec --output ~/rpmbuild/SPECS/NPB.spec \
--type minimal

/home/josevnz/rpmbuild/SPECS/npb.spec created;
type minimal, rpm version >= 4.16.

The resulting file looks like this:

Name:           npb
Release:        1%{?dist}







%license add-license-file-here
%doc add-docs-here

* Tue Oct 05 2021 Jose Vicente Nunez <>

Next, remove the following tags from this skeleton file, as they do not apply to this task:

  • %autosetup: You will unpack the software yourself without patches
  • %configure and %make_build: You will use Gradle instead

Install the prerequisites, Java and Gradle:

$ sudo dnf install java-11-openjdk
$ sudo -i mkdir -p /opt/gradle
$ sudo -i curl --silent --location --fail \
--output /opt/gradle/ \
$ cd /opt/gradle
$ sudo unzip
$ sudo /bin/rm -f /opt/gradle/

Now you are ready to change the spec file.

[ Get more tips by downloading the Bash shell scripting cheat sheet. ]

Step 2: Fill in the building blocks for the Java RPM

After several changes, like adding Gradle as part of the build, you have:

Name:           NPB
Version:        3.0
Release:        1%{?dist}
Summary:        Small set of programs designed to help evaluate the performance of parallel supercomputers

License:        NOSA

BuildRequires:  java-11-openjdk-headless,tar,gzip,rpmdevtools,rpmlint
Requires:       java-11-openjdk-headless

# Custom macros (
# If you want to see the value of many of these macros, just run this: /usr/bin/rpm --showrc
%global debug_package %{nil}
%global gradle /opt/gradle/gradle-7.2/bin/gradle
%global curl /bin/curl --location --fail --silent --output
%global JAVA_DIR NPB3_0_JAV


The NAS Parallel Benchmarks (NPB) are a small set of programs designed to help evaluate the performance
of parallel supercomputers. The benchmarks are derived from computational fluid dynamics (CFD)
applications and consist of five kernels and three pseudo-applications in the original "pencil-and-paper"
specification (NPB 1). The benchmark suite has been extended to include new benchmarks for unstructured
adaptive meshes, parallel I/O, multi-zone applications, and computational grids. Problem sizes in NPB are
predefined and indicated as different classes. Reference implementations of NPB are available in
commonly-used programming models like MPI and OpenMP (NPB 2 and NPB 3).

test ! -x %{gradle} && echo "ERROR: Gradle not installed!" && exit 100
# On a production environment you MOST LIKELY point to your private copy of the build artifacts
/bin/curl --location --fail --silent --output %{_sourcedir}/%{name}%{version}.tar.gz{name}%{version}.tar.gz
%setup -q -n %{name}%{version}

cd %{name}%{version}-JAV
# If you are not familiar with Gradle, you should read the following:
// Gradle build file dynamically created for %{name}%{version}
plugins {

java {
    toolchain {

sourceSets {
    main {
        java {

    test {
        java {
%{gradle} clean java jar

/bin/rm -rf %{buildroot}
/bin/mkdir -v -p %{buildroot}/%{_bindir}
/bin/mkdir -v -p %{buildroot}/%{_libdir}
/bin/mkdir -v -p %{buildroot}/%{_pkgdocdir}
/bin/cp -p -v %{_builddir}/%{name}%{version}/%{name}%{version}-JAV/build/libs/%{name}%{version}-JAV.jar %{buildroot}/%{_libdir}

# On a production environment you MOST LIKELY point to your private copy of the build artifacts
%{curl} %{buildroot}/%{_pkgdocdir}/LICENSE{name}%{version}-JAV-FORK/main/LICENSE
%{curl} %{buildroot}/%{_pkgdocdir}/{name}%{version}-JAV-FORK/blob/main/%{name}%{version}-JAV/
%{curl} %{buildroot}/%{_bindir}/testAllS
%{curl} %{buildroot}/%{_bindir}/testAllW
/bin/chmod a+xr %{buildroot}/%{_bindir}/{testAllS,testAllW}

/bin/rm -rf %{buildroot}

%license %{_pkgdocdir}/LICENSE
%doc %{_pkgdocdir}/

* Tue Oct 05 2021 Jose Vicente Nunez <>
- First RPM 

The spec file is heavily commented, and you can see how I used the original tar.gz file without any changes and added a new build system on top of that, plus two wrapper scripts (testAIIS and testAIIW) to run the Java code after it is installed.

Next, create the new RPM:

$ rpmbuild -ba ~/rpmbuild/SPECS/npb.spec
Requires: /usr/bin/bash
Checking for unpackaged file(s): /usr/lib/rpm/check-files /home/josevnz/rpmbuild/BUILDROOT/NPB-3.0-1.fc33.x86_64
Wrote: /home/josevnz/rpmbuild/SRPMS/NPB-3.0-1.fc33.src.rpm
Wrote: /home/josevnz/rpmbuild/RPMS/x86_64/NPB-3.0-1.fc33.x86_64.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.JGJ4Ky

Step 3: Install your custom RPM

With your RPM built, you can now install it:

$ sudo rpm -ihv ~/rpmbuild/RPMS/x86_64/NPB-3.0-1.fc33.x86_64.rpm
[sudo] password for josevnz: 
Verifying...              ################## [100%]
Preparing...              ################## [100%]
Updating / installing...
   1:NPB-3.0-1.fc33       ################## [100%]

The output indicates success:

+ /usr/lib/jvm/java-11-openjdk- -classpath
[...]rpmbuild/BUILD/NPB3.0/NPB3.0-JAV/build/libs/NPB3.0-JAV.jar NPB3_0_JAV.BT
-np2 CLASS=S
 NAS Parallel Benchmarks Java version (NPB3_0_JAV)
 Multithreaded Version BT.S np=2
No input file, Using compiled defaults
Size: 12 X 12 X 12
Iterations: 60 dt: 0.01
Time step 1
Time step 20
Time step 40
Time step 60
Verification being performed for class S
accuracy setting for epsilon = 1.0000000000000005E-8
Comparison of RMS-norms of residual
BT.S: Verification Successful

Learn more

Packaging software with RPM—whether it's your own or someone else's open source application—may look intimidating at first, but with a little bit of patience, you will get there in no time. As you encounter issues, you will also find proper ways to improve your code. Below are some resources and final recommendations:

  • Do yourself a big favor and get a copy of the RPM Packaging Guide written by Adam Miller, Maxim Svistunov, and Marie Doleželová. It is very complete and well organized. Seriously, do it now; it is that good.
  • The official RPM Packaging Guide and the Fedora RPM guide are also full of details; keep them a bookmark away.
  • Use rpmlint. You will be surprised how many little things you can catch and fix before shipping your RPM packages.
  • Not enough? Fedora has a list of tricks you can use when packaging software.
  • Thirsty for more? You should definitely take a look at RPM Packaging guidelines.
Topics:   Linux   Software   Package management  
Author’s photo

Jose Vicente Nunez

Proud dad and husband, software developer and sysadmin. Recreational runner and geek. More about me

Try Red Hat Enterprise Linux

Download it at no charge from the Red Hat Developer program.