Linux#
Packaging#
RPMs#
RPMs are the packages used by Redhat systems (so in our case usually CentOS). The acronym RPM orignially came from Red Hat Package Manager.
Most of the information is taken from the RPM Packaging Guide, that you should consult for more details, examples, explanations, etc.
There are two kinds of rpms: binary and source.
A source binary contains the source code of a package and the spec
file to build a binary package from it.
Binary packages contain the compiled binaries or libraries, scripts, and if neccessary include files along with sometimes configuration files (pkgconfig, cmake, …) and a license.
Very often different binary packages are built, one for general use, one for development (usually package-devel
) and one with debug information.
Rpmbuild will build the debug one automatically, if everything is set up correctly, the devel
part has to be specified.
If possible you should use a new machine for building the package, so that you don’t forget any dependencies.
There you need to install for CentOS 8:
dnf install gcc rpm-build rpm-devel rpmlint make python2 bash diffutils patch rpmdevtools
and for CentOS 7:
yum install gcc rpm-build rpm-devel rpmlint make python bash coreutils diffutils patch rpmdevtools
After installing everything you need it is advised to switch to a non-root user for security reasons.
As this user you can setup the needed directory structure by calling
rpmdev-setuptree
This will create an rpmbuild
directory in your home with the following subdirectories.
BUILD
: This is where rpmbuild will build your applicationRPMS
: This will contain the binary rpms when they are builtSOURCE
: Directory for the tar packed source codeSPEC
: Directory for the spec files that contain all information on a packageSRPMS
: This will contain the source rpms
The spec file#
Each package you want to create needs a spec file called package-name.spec
in the SPEC
directory.
As soon as you create such a file, it will be filled with basic boilerplate.
This file consists of different sections.
First, basic information is filled in, that can be later used as variables. Then you can specify commands that should prepare, build and install the application.
Finally you need to specify the files that should be added to the package.
In case anything goes wrong you can see the created files of the make install
directive in the BUILDROOT
directory for comparison.
They will appear there in the same structure as they will on the system once you installed the package.
For more information and examples on the spec files, see the RPM Packaging Guide, as mentioned above.
If you want to build a normal and a devel package you can add additional subpackage sections like %package devel
.
These can have different Summary and Requires fields, and it will need an own %files devel
section.
The nice thing with package managers is, that all dependencies you added to the spec file will be automatically installed, if you install you newly built package with yum or dnf on any machine.
Of course that also means that you have to take care to list all needed packages in the Requires:
field!
Building it#
Of course you need the source code to build the application.
You can either pack it yourself into a tar.gz
archive or if you have a link to it add this link to the Source0
field in the spec file and download it via
spectool -g -R package.spec
Either way, once you have added the tarball to the SOURCES
directory you can build both source and binary packages with
rpmbuild -ba package.spec
(-bb
will build only binary, -bs
only source package)
And that’s it! This will create packages based on the information you gave in the spec file.
The name of the package will usually be {packagename}-{version}-{rpmrelease}.{distro}.{arch}.rpm
.
Keys and local repository#
Two more things you can do to make everything more professional are signing your package and creating a local repository for all your packages.
For signing a package you need to create a GPG key and give the --signed
argument to rpmbuild
.
This will help making sure, that the package people are installing is definitely from you and has not been swapped with malicious software.
The local repo does not make sense for single packages or single machines, but rather if you have a lot of packages, that will be installed to several machines and updated regularly.
In the end you create a file specifying the local folder containing all the packages you want to be able to install and add this to the repository lists of yum/dnf.
For more information on both of these approaches: www.google.com
A working spec file for building user, devlopment and debuginfo packages of spdlog
looks like this:
Name: spdlog
Version: 1.8.0
Release: 1%{?dist}
Summary: Very fast, header-only/compiled, C++ logging library.
License: MIT
URL: https://github.com/gabime/spdlog
Source0: https://github.com/gabime/%{name}/archive/v%{version}.tar.gz
BuildRequires: cmake3,devtoolset-7-gcc,devtoolset-7-gcc-c++
%description
Very fast, header-only/compiled, C++ logging library.
%package devel
Summary: Spdlog development files
Provides: spdlog-devel
%description devel
Deveoplment files for Spdlog, a very fast, header-only/compiled, C++ logging library.
%prep
%setup -q
%build
cmake3 -DSPDLOG_BUILD_TESTS=OFF -DSPDLOG_BUILD_SHARED=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr .
%install
%make_install
%files
%license LICENSE
/usr/lib64/libspdlog.so.*
%files devel
%license LICENSE
/usr/lib64/*
/usr/include/*
%changelog
* Thu Sep 03 2020 Sophie Wenzel-Teuber <sophie.wenzel-teuber@ichec.ie> - v1.8.0
- First spdlog package
DEB packages#
The basic dependencies for the steps in this tutorial are:
apt-get update
apt-get install build-essential debhelper dh-make
The approach is to create a source package first, and then build the binary from it.
To do that you need to add a debian
directory to the source, create a few files in there and make sure that everything has the correct names.
There are lots of different scripts and packages to help you in the process.
It seems to be a rabbit hole in itself to look through them and compare them.
The guide mentioned above is mainly using debmake
, but later on also dh
, which is what I will be using in the following.
As far as I understood the differences are more because of historic reasons, the typical approach to introducing something new to make everything easier, that usually ends up in just confusing people who are new to the whole process.
To make everything a bit clearer, I will add examples for building a spdlog package.
Download the upstream source#
The original code you want to package is called the “upstream source”, assuming that you might want to make changes to it, that are needed for the package (like the debian
folder), ending up at the real source.
Download the source as a tar.gz
archive and unpack it, or create one from a source directory.
Either way you need to change the names in order to end up with an unpacked directory called package-version
and an archive package_version.orig.tar.gz
wget https://github.com/gabime/spdlog/archive/v1.8.0.tar.gz
tar -zxvf v1.8.0.tar.gz
mv v1.8.0.tar.gz spdlog_1.8.0.orig.tar.gz
# unpacked directory spdlog-1.8.0 already has the correct name
Make sure that the -
and _
are correct, because yes, it does make a difference.
Prepare packaging files#
To create the additional files needed to create a package a very easy and seemingly accepted approach is to call dh_make
in you new source directory (the unpacked one from before with the -
).
You should run this as a normal user instead of root. It will also use the variable $LOGNAME
for filling in information about who is building that package.
In this case we are building a library, so choose l
when asked.
This command will create a debian
subdirectory with a lot of files.
In this example most of them are filled out fine per default, and there only four files that you always need to update:
control
rules
copyright
changelog
debian/changelog#
The whole process assumes that you will make changes to the original code before packaging it. This is contained in the changelog file.
If you close a bug, you can add the bug number in this file and it will autmoatically mark this bug as closed, but I assume we will harldy use that.
The changelog file for spdlog looks like this:
spdlog (1.8.0-1) unstable; urgency=medium
* Initial release (Closes: #nnnn) <nnnn is the bug number of your ITP>
-- unknown <builder_monkey@unknown> Tue, 08 Sep 2020 12:52:33 +0000
which should be fine for now.
debian/control#
The control file contains metadata to your package. Of course you will want to add lots of information there along with nice descriptions once you really get into it, but for now this should suffice:
Source: spdlog
Priority: optional
Maintainer: unknown <builder_monkey@unknown>
Build-Depends: cmake,g++,debhelper (>= 11)
Standards-Version: 4.1.3
Section: libs
Homepage: https://github.com/gabime/spdlog
#Vcs-Browser: https://salsa.debian.org/debian/spdlog
#Vcs-Git: https://salsa.debian.org/debian/spdlog.git
Package: spdlog-custom-dev
Section: libdevel
Architecture: any
Multi-Arch: same
Depends: spdlog-custom (= ${binary:Version}), ${misc:Depends}
Description: <insert up to 60 chars description>
<insert long description, indented with spaces>
Package: spdlog-custom
Architecture: any
Multi-Arch: same
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: <insert up to 60 chars description>
<insert long description, indented with spaces>
I only added build requirements, the homepage and changed the package names compared to the the automatically created file.
The architecture is set to any
in this case, which is good: Any
means that it has to be build for a specific architecture, whereas all
would be independent (ie a package consisting of bash scripts).
debian/copyright#
As we all now, copyright is important, but I am not planning to release this package, so I’ll skip this here.
debian/rules#
For what I assume are again historic reasons, rules
is a Makefile and will contain all steps to build your package.
When you look at the generated file though, it will more or less just contain two lines:
%:
dh $@
The magical dh
is a master command for a whole chain of debhelper
commands.
If you want to know which commands this entails have a look at the manpage debhelper(7)
.
This command chain that is executed by dh
constist of commands, all starting with dh_
to configure, build and install whatever the package should contain.
In the spdlog case, the Makefile works as is, magically finding cmake, running and building it. However, you might want to customise certain steps of this process (ie additional cmake flags). For that purpose, each step can be overridden in the rules file.
For example the dh_auto_configure
part can be changed by setting override_dh_auto_configure
like this:
override_dh_auto_configure:
dh_auto_configure -- \
-DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) \
-DSPDLOG_BUILD_TESTS=OFF \
-DSPDLOG_BUILD_SHARED=ON \
-DCMAKE_INSTALL_PREFIX:PATH=/usr
Building the package#
As with every step of this tutorial, there are several ways to build the package in the end.
The ones that work fine with the steps explained above are debuild
and dpkg-buildpackage
.
Running dpkg-buildpackage -us -uc
in the source package will create package files in the upper directory.
The us
and uc
flags tell the comamnd not to sign the source or the changes.
If you are developing decent software and have great plans for it, you should sign it of course.
What we end up with is:
spdlog-1.8.0
: the source directory we were working inspdlog_1.8.0-1.dsc
: a text file containing the metadata along with checksumsspdlog-custom-dev_1.8.0-1_amd64.deb
: the package for developmentspdlog_1.8.0-1_amd64.buildinfo
: Information on metadata and the build environment, including all systemwide installed packagesspdlog-custom_1.8.0-1_amd64.deb
: the main packagespdlog_1.8.0-1_amd64.changes
: And another file with metadata, also including a list of files and the changelog.spdlog_1.8.0-1.debian.tar.xz
: The archived files with all changes for debian (so basically the source package)spdlog_1.8.0.orig.tar.gz
: The original, “upstream” source that we created/downloaded before
Most of them are only used for uploading the package to an official repository and I assume they can be ignored otherwise.
Now you can install the newly created package with
apt install ./spdlog-custom_1.8.0-1_amd64.deb
Additional tips#
If you want to look at the debian/*
files of a working package, you can download the source of that package with
apt-get source package-name
After adding deb-src http://deb.debian.org/debian buster main
or similar to /etc/apt/sources.list
.
This will create a directory with all the contents needed to create the package.
The metadata information like requirements, etc can be found in the .dsc
file.