How do I read this magical “spec-file”?¶
Let’s start with a minimal example spec-file. Here you can see a few examples depending on the build-system/tools used during the packaging.
%global debug_package %{nil}
%global commit 836dc6a0efd9849cb194e88e4aa2387436bb079b
Name: span
Version: 0~20250521git836dc6a
Release: %autorelease
Summary: Implementation of C++20's std::span for older compilers
License: BSL-1.0
URL: https://github.com/tcbrindle/span
Source: %{url}/archive/%{commit}.tar.gz
# Fix build without exceptions
Patch0: https://github.com/tcbrindle/span/pull/53.patch
# Make the project installable
Patch1: span-Fedora_patches.patch
BuildRequires: cmake
BuildRequires: gcc-c++
BuildRequires: cmake(Catch2)
%global _description %{expand:
Single-header implementation of C++20's std::span, conforming to the C++20
committee draft. It is compatible with C++11, but will use newer language
features if they are available.
It differs from the implementation in the Microsoft GSL in that it is
single-header and does not depend on any other GSL facilities. It also works
with C++11, while the GSL version requires C++14.}
%description %{_description}
%package devel
Summary: Development files for span
# Header-only package
Provides: span-static = %{version}-%{release}
%description devel %{_description}
This package contains the development files.
%prep
%autosetup -p1 -n span-%{commit}
%conf
%cmake
%build
%cmake_build
%install
%cmake_install
%check
%ctest
%files devel
%dir %{_includedir}/tcb
%{_includedir}/tcb/span.hpp
%license LICENSE_1_0.txt
%doc README.md
%changelog
%autochangelog
Name: python-pytest-check
Version: 2.5.4
Release: %autorelease
Summary: A pytest plugin that allows multiple failures per test
License: MIT
URL: https://github.com/okken/pytest-check
Source: %{pypi_source pytest_check}
BuildArch: noarch
BuildRequires: python3-devel
%global _description %{expand:
A pytest plugin that allows multiple failures per test.}
%description %_description
%package -n python3-pytest-check
Summary: %{summary}
%description -n python3-pytest-check %_description
%prep
%autosetup -n pytest_check-%{version}
%generate_buildrequires
%pyproject_buildrequires
%build
%pyproject_wheel
%install
%pyproject_install
%pyproject_save_files pytest_check
%check
%pytest
%files -n python3-pytest-check -f %{pyproject_files}
%license LICENSE.txt
%doc README.md
%changelog
%autochangelog
Step1: What is being done?¶
The main parts of the spec file are the build process steps which are separated into various sections:
%prepPrepare (extract) the sources and
%generate_buildrequiresAdd additional
BuildRequiresdynamically (more on that later)%confRun
configureor equivalents%buildDo the main build steps of the project
%installInstall all files in a staging location as they will be seen after you
dnf installthe package%checkRun available tests preferably against the staged files
The sections are executed in that order, and can be omitted.
Let’s look at the minimal example and decompose what’s happening:
%prep
%autosetup -p1 -n span-%{commit}
%conf
%cmake
%build
%cmake_build
%install
%cmake_install
%check
%ctest
%prepExtract the source defined in
Source, apply any patches defined byPatch, andcdinto the folder inside the archive defined by-noption.(Common across all build systems)
%confRun a
cmake(configure) step with any relevant-Doptions%buildRun the
cmake --buildstep%installRun
cmake --install%checkRun the provided
ctest(in the build directory)
%prep
%autosetup -n pytest_check-%{version}
%generate_buildrequires
%pyproject_buildrequires
%build
%pyproject_wheel
%install
%pyproject_install
%pyproject_save_files pytest_check
%check
%pytest
%prepExtract the source defined in
Source, apply any patches defined byPatch, andcdinto the folder inside the archive defined by-noption.(Common across all build systems)
%pyproject_buildrequiresGet all
build-system.requires,project.requiresfrompyproject.tomland add them to the currentBuildRequires%buildRun
pip wheel%installInstall the built wheel
Save the installed file list under
%{pyproject_files}%checkRun
pytest
Step0: Wait, where are the sources coming from?¶
Ok, I’ve lied, the most important thing you should be interested in as a packager is the metadata sections which, among many other things, defines what are the sources (and patches) currently used. Otherwise, there is little variance between the actual build instructions of each package.
Name: span
Version: 0~20250521git836dc6a
Release: %autorelease
Summary: Implementation of C++20's std::span for older compilers
License: BSL-1.0
URL: https://github.com/tcbrindle/span
Source: %{url}/archive/%{commit}.tar.gz
# Fix build without exceptions
Patch0: https://github.com/tcbrindle/span/pull/53.patch
# Make the project installable
Patch1: span-Fedora_patches.patch
BuildRequires: cmake
BuildRequires: gcc-c++
BuildRequires: cmake(Catch2)
Name: python-pytest-check
Version: 2.5.4
Release: %autorelease
Summary: A pytest plugin that allows multiple failures per test
License: MIT
URL: https://github.com/okken/pytest-check
Source: %{pypi_source pytest_check}
BuildArch: noarch
BuildRequires: python3-devel
These Source and Patch lines can point to an external url that would be
downloaded or a local file present next to the spec file.
Tip
Use spectool -g *.spec to download all of the sources defined in the spec
file
Step2: Dependencies¶
Of course the sources and instructions are not sufficient to build the package, you also need the build-time and runtime dependencies of the current package.
Name: span
Version: 0~20250521git836dc6a
Release: %autorelease
Summary: Implementation of C++20's std::span for older compilers
License: BSL-1.0
URL: https://github.com/tcbrindle/span
Source: %{url}/archive/%{commit}.tar.gz
# Fix build without exceptions
Patch0: https://github.com/tcbrindle/span/pull/53.patch
# Make the project installable
Patch1: span-Fedora_patches.patch
BuildRequires: cmake
BuildRequires: gcc-c++
BuildRequires: cmake(Catch2)
Name: python-pytest-check
Version: 2.5.4
Release: %autorelease
Summary: A pytest plugin that allows multiple failures per test
License: MIT
URL: https://github.com/okken/pytest-check
Source: %{pypi_source pytest_check}
BuildArch: noarch
BuildRequires: python3-devel
These are defined with the BuildRequires and Requires fields. Of course
managing these fields manually would be very time-consuming, so often these are
kept to the bare minimum needed. The real dependencies are often defined
dynamically either from the source files for the BuildRequires using
%generate_buildrequires or from the installed files for the Requires which
are handled behind the scenes (e.g. the dependencies on the libraries is never
defined manually instead these are extracted from the binary/library files).
Step3: %files and %package sections¶
After you’ve installed the files, you also need to define the expected files
and their locations to be packaged, which is defined in the %files section.
However, often you would want to separate where the files are located, e.g. the
development files being in a *-devel sub-package, the documentations in a
*-docs sub-package, etc. This is done by defining various %package sections
sharing the same metadata fields as the top level/source package.
%package devel
Summary: Development files for span
# Header-only package
Provides: span-static = %{version}-%{release}
%description devel %{_description}
This package contains the development files.
%files devel
%dir %{_includedir}/tcb
%{_includedir}/tcb/span.hpp
%license LICENSE_1_0.txt
%doc README.md
%package -n python3-pytest-check
Summary: %{summary}
%description -n python3-pytest-check %_description
%files -n python3-pytest-check -f %{pyproject_files}
%license LICENSE.txt
%doc README.md
Step4: Macros¶
As you’ve already seen throughout the files, the spec file is riddled with
macros which you can find as either %{macro_name} or %macro_name. These
simplify the repetition of various parts of the spec file. Some of these are
pre-defined from corresponding fields such as %version or %url, defined in
some commonly sourced /usr/lib/rpm/macros.d/macros.* file such as for the
%cmake, %pyproject_wheel etc., or they can be defined/overriden directly in
the spec file with %global or equivalents.
%global debug_package %{nil}
%global commit 836dc6a0efd9849cb194e88e4aa2387436bb079b
Name: span
Version: 0~20250521git836dc6a
Release: %autorelease
Summary: Implementation of C++20's std::span for older compilers
License: BSL-1.0
URL: https://github.com/tcbrindle/span
Source: %{url}/archive/%{commit}.tar.gz
# Fix build without exceptions
Patch0: https://github.com/tcbrindle/span/pull/53.patch
# Make the project installable
Patch1: span-Fedora_patches.patch
BuildRequires: cmake
BuildRequires: gcc-c++
BuildRequires: cmake(Catch2)
%global _description %{expand:
Single-header implementation of C++20's std::span, conforming to the C++20
committee draft. It is compatible with C++11, but will use newer language
features if they are available.
It differs from the implementation in the Microsoft GSL in that it is
single-header and does not depend on any other GSL facilities. It also works
with C++11, while the GSL version requires C++14.}
%description %{_description}
Name: python-pytest-check
Version: 2.5.4
Release: %autorelease
Summary: A pytest plugin that allows multiple failures per test
License: MIT
URL: https://github.com/okken/pytest-check
Source: %{pypi_source pytest_check}
BuildArch: noarch
BuildRequires: python3-devel
%global _description %{expand:
A pytest plugin that allows multiple failures per test.}
%description %_description
Step5: Control parameters¶
Sometimes you will find a spec file defining %bcond fields which are
basically just control fields to turn on/off a process during the build with
the %if and %with_*/%without_* macros. More on how to actually invoke
them in the how to build section of this guide.
Step6: The rest¶
As you can see not all fields are documented here as this is beyond the scope of this guide. Some of the fields usage is straightforward. Other times the fields usage have quite a bit of nuance attached to it which is best explored with a fellow Fedora packager, most of which being in the Fedora #devel room.