Packaging Tutorial 2: GNU Hello
This tutorial demonstrates RPM packaging by packaging the GNU Hello program. While the program itself is simple, it also comes with many peripheral components of a FOSS project: configuration/build/install environment, documentation, internationalization,etc.
This tutorial is the second part of Fedora packaging tutorial. It follows the same basic structure as part 1. If you have not completed it yet, please do so before continuing with this tutorial.
The steps in this part are similar to part 1. However, GNU Hello has more quirks than Banner does, so some workarounds and custom steps are needed. Each package’s quirks are unique, so these are best viewed as examples of the kind of problems that may arise when packaging.
Installing Packager Tools
Follow Installing Packager Tools.
Creating the package directory
For GNU Hello, the package can simply be named hello
.
This is also the name of Fedora’s official GNU Hello package.
$ mkdir hello && cd hello
Inside a Spec File
Create a file called hello.spec
and paste the following minimal specfile.
This already has BuildRequires
tags for gcc
and make
,
since that topic was already covered in part 1.
Similarly, %files
section already includes the resulting binary, man pages, documentation and license file.
For GNU Hello, all these files are very similar to corresponding files in Banner,
and were thus already covered in part 1.
Also, for reasons that are too complex to explain in a tutorial,
in some situations texinfo
package is also needed,
and so a BuildRequires
line is added for it.
Name: hello
Version: 2.10
Release: %autorelease
Summary: Produces a familiar, friendly greeting
License: GPL-3.0-or-later
URL: https://www.gnu.org/software/hello/
Source: https://ftp.gnu.org/gnu/hello/hello-%{version}.tar.gz
BuildRequires: gcc
BuildRequires: make
BuildRequires: texinfo
%description
The GNU Hello program produces a familiar, friendly greeting. Yes, this is
another implementation of the classic program that prints "Hello, world!" when
you run it.
%prep
%autosetup
%build
%configure
%make_build
%install
%make_install
%files
%{_bindir}/hello
%{_mandir}/man1/hello.1.*
%doc AUTHORS ChangeLog NEWS README THANKS TODO
%license COPYING
%changelog
%autochangelog
Downloading source
Download sources and check that you now have them:
$ spectool -g hello.spec $ ls *.tar.gz hello-2.10.tar.gz
Building the Package
$ fedpkg --release f40 mockbuild
This command fails because of unpackaged files.
Installing files
As in part 1, we will go through the file list one by one.
Run fedpkg --release f40 mockbuild
again after each change to see the progress.
Texinfo pages
Installed (but unpackaged) file(s) found: /usr/share/info/dir /usr/share/info/hello.info.gz
These are Texinfo pages.
Texinfo is a documentation system like man pages, but much less common.
Texinfo pages are handled much in the same way as man pages.
The directory is defined by the default macro {_infodir}
,
so the Texinfo manual can be added as follows:
%files
⋮
%{_infodir}/hello.info.*
The dir
file generated by GNU Hello build script indexes all texinfo pages in your system.
Because the installed pages differ among systems, the file cannot be prebuilt and packaged.
Instead it needs to be created and updated when the package is installed.
The update is automatically performed by RPM triggers in info
binary package of
texinfo source package.
To prevent from installing the dir
file,
remove it from the buildroot at the end of the %install
section with rm
command.
However, GNU Hello build script only generates the dir
file
if info
package is installed during the build.
Blindly removing the file would raise an error if
the hello
package were built on a system without info
package.
To handle both cases, delete the file if it exists:
%install
⋮
test -f %{buildroot}/%{_infodir}/dir && rm %{buildroot}/%{_infodir}/dir
Translations
Installed (but unpackaged) file(s) found: /usr/share/locale/bg/LC_MESSAGES/hello.mo /usr/share/locale/ca/LC_MESSAGES/hello.mo /usr/share/locale/da/LC_MESSAGES/hello.mo ⋮
Since our program uses translations and internationalization, we are seeing a lot of undeclared i18n files. The recommended method to declare them is:
-
Add the required build dependency with
BuildRequires: gettext
. -
Find the filenames in the
%install
step with%find_lang %{name}
. -
Install the files with
%files -f %{name}.lang
.
After these changes, build succeeds.
Running tests
GNU Hello, like many other projects,
includes an automated test suite in the sources.
If at all possible,
the test suite should be run during the rpm build.
This helps ensuring that a working build was produced.
This is done by adding the test suite invocation
to specfile %check%
section,
which comes after %install
in order.
In GNU Hello’s case:
%check
make check
Run a mockbuild again and check the output to ensure that the tests were actually run. Something like this should be somewhere in the output:
============================================================================ Testsuite summary for GNU Hello 2.10 ============================================================================ # TOTAL: 5 # PASS: 4 # SKIP: 1 # XFAIL: 0 # FAIL: 0 # XPASS: 0 # ERROR: 0 ============================================================================
Fixing automagic
Now the package successfully builds.
But that does not mean that the .spec
file is correct.
Listing all build-time dependencies
If you carefully read a build output,
you can discover lines which mention sed
command:
+ /usr/bin/make -O -j4 V=1 VERBOSE=1 rm -f lib/arg-nonnull.h-t lib/arg-nonnull.h && \ sed -n -e '/GL_ARG_NONNULL/,$p' \
Therefore you need to add this line close to other BuildRequires lines:
BuildRequires: sed
Similarly, studying configure
script in the unpackaged sources,
which is executed by %configure
macro,
reveals it’s a /bin/sh
script:
$ head configure #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for GNU Hello 2.10.
Thus you also should record this dependency on bash
:
BuildRequires: bash
Why on bash
?
Because /bin/sh
program is provided by bash
package:
$ rpm --queryformat '%{name}\n' --query --file /bin/sh bash
Specifying all used dependencies helps
to make the .spec
file resilient against changes in the build environment.
If e.g. sed
package were removed from the environment,
this GNU Hello package would fail to build.
Listing all build options
The GNU Hello build script, configure
has many build options
which enable or disable optional features.
Their nondefault forms can be listed with --help
option:
$ ./configure --help `configure' configures GNU Hello 2.10 to adapt to many kinds of systems. Usage: ./configure [OPTION]... [VAR=VALUE]... ⋮ Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --disable-nls do not use Native Language Support --disable-rpath do not hardcode runtime library paths
Some of them are already specified within %configure
and %make_build
macros. The rest of the options, if they are important for the built package,
should be explicitly written in the .spec
file to prevent from their
sudden and unnoticed changes. Either because a new Hello version changes the
default, or because a package which they depend on appears of disappears from
the build environment.
Therefore modify %configure
invocation in %build
section like this:
%configure --enable-nls --disable-rpath
Checking the result with rpmlint
Check with fedpkg lint
reveals a problem:
$ fedpkg --release f40 lint hello.x86_64: W: file-not-utf8 /usr/share/doc/hello/THANKS
In order to ensure a pure utf-8 installation, the file needs to be converted in %prep
.
This can be done with the iconv
utility which is provided by glibc-common
package,
and mv
tool from coreutils
:
BuildRequires: coreutils BuildRequires: glibc-common ⋮ %prep ⋮ mv THANKS THANKS.old iconv --from-code=ISO-8859-1 --to-code=UTF-8 --output=THANKS THANKS.old
Run fedpkg lint
again and observe that the warning is fixed.
A Complete hello.spec File
Here is the final version of hello.spec
:
Name: hello
Version: 2.10
Release: %autorelease
Summary: Produces a familiar, friendly greeting
License: GPL-3.0-or-later
URL: https://ftp.gnu.org/gnu/%{name}
Source: https://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.gz
BuildRequires: bash
BuildRequires: coreutils
BuildRequires: gcc
BuildRequires: gettext
BuildRequires: glibc-common
BuildRequires: make
BuildRequires: sed
BuildRequires: texinfo
%description
The GNU Hello program produces a familiar, friendly greeting. Yes, this is
another implementation of the classic program that prints "Hello, world!" when
you run it.
%prep
%autosetup
mv THANKS THANKS.old
iconv --from-code=ISO-8859-1 --to-code=UTF-8 --output=THANKS THANKS.old
%build
%configure --enable-nls --disable-rpath
%make_build
%install
%make_install
test -f %{buildroot}/%{_infodir}/dir && rm %{buildroot}/%{_infodir}/dir
%find_lang %{name}
%check
make check
%files -f %{name}.lang
%{_mandir}/man1/hello.1.*
%{_infodir}/hello.info.*
%{_bindir}/hello
%doc AUTHORS ChangeLog NEWS README THANKS TODO
%license COPYING
%changelog
%autochangelog
With this .spec
file,
you should be able to successfully complete the build process,
and create the source and binary RPM packages.
Checking the result
You can now check the result with rpm
, like was done in part 1.
Files
List the files contained in the package:
$ rpm --query --package --list results_hello/2.10/1.fc40/hello-2.10-1.fc40.x86_64.rpm /usr/bin/hello /usr/lib/.build-id /usr/lib/.build-id/39 /usr/lib/.build-id/39/c97ecb15c6292ce23e8b00e15e6e72a61e5072 /usr/share/doc/hello /usr/share/doc/hello/AUTHORS ⋮ /usr/share/doc/hello/TODO /usr/share/info/hello.info.gz /usr/share/licenses/hello /usr/share/licenses/hello/COPYING /usr/share/locale/bg/LC_MESSAGES/hello.mo ⋮ /usr/share/locale/zh_TW/LC_MESSAGES/hello.mo /usr/share/man/man1/hello.1.gz
You can see that all the files listed in the specfile %files
section are included,
including the automatically processed locale files.
Also the .build-id
file is there, just like in part 1.
Requires and Provides
You can list list the package’s runtime dependencies and the capabilities it provides with the following two commands. The output is similar to corresponding output in part 1.
$ rpm --query --package --requires results_hello/2.10/1.fc40/hello-2.10-1.fc40.x86_64.rpm $ rpm --query --package --provides results_hello/2.10/1.fc40/hello-2.10-1.fc40.x86_64.rpm
Want to help? Learn how to contribute to Fedora Docs ›