The preamble section is the "default" section of an RPM spec file. All spec files begin with a preamble
section that stretches from the top until a new section (e.g. %description) is reached.
In Fedora, a preamble is also referred to as a "tag" or a "field".1
Here is a non-exclusive (but nearly exclusive) list of preambles available:
## these fields MUST be present in a spec fileName: pkgnameVersion: 1.2.3Release: 1%?distSummary: Package summary (do not add period at the end)# As opposed to the guidelines given by RPM, we (and also Fedora!) strongly# recommend using SPDX identifiers.License: MITURL: https://terra.fyralabs.com/Source0: Link to download the source code. If more then one link is needed,specify with Source1:, Source2:, etc.## terra also enforces the following preamble:Packager: username <email@example.com>## these fields are optional and have default valuesEpoch: 0# automatic `Requires:` and `Provides:` generationAutoReqProv: 1# automatic `Requires:` generationAutoReq: 1# automatic `Provides:` generationAutoProv: 1## these fields are optionalPatch:SourceLicense:BugURL:ModularityLabel:DistTag:VCS:Distribution:Copyright:Vendor:ExcludeArch:ExclusiveArch:ExcludeOS:ExclusiveOS:BuildArch:BuildArchitectures:BuildRequires:NoSource:NoPatch:Group:Provides:Obsoletes:Conflicts:Suggests:Recommends:Enhances:Supplements:OrderWithRequires:BuildConflicts:Prefix:Prefixes:Docdir:RemovePathPostFixes:BuildSystem:BuildOption:Icon: (Obsolete)Buildroot: (Obsolete)BuildPrereq: (Obsolete)Prereq: (Obsolete)
If you want to add comments, use %{dnl:…} or start a new line.
Adding # … at the end of a line does not work.
If you are a usual package maintainer, you would instantly notice one very important preamble is
missing: Requires:. Requires: is quite special because it can be further divided into:
Requires: or BuildRequires: must be followed by a space-separated
(comma-separated is accepted but not recommended) list of "query". A "query" (term used here specifically!)
is in the format of x = y (other comparators including >= are accepted) or simply x. RPM will resolve
a "query" by finding a best package that provides the requirement of the query. For example, given the package
gtk4-devel with the following provides:
Step Executing(%generate_buildrequires). Optional. Since rpm >= 4.15.
The stdout is intercepted during this step. The output should be a newline (\n)-separated list of
RPM build dependencies that should be installed.
Once this stage finishes, rpmbuild will attempt to install the list of dependencies. This implies
that you may generate a dynamic dependency list that will be available by the time %build
executes, usually by calling the package manager (e.g. dnf) with Internet access.
This optional script can be used to determine BuildRequires dynamically. If present it is executed after %prep and can though access the unpacked and patched sources. The script must print the found build dependencies to stdout in the same syntax as used after BuildRequires: one dependency per line.
rpmbuild will then check if the dependencies are met before continuing the build. If some dependencies are missing a package with the .buildreqs.nosrc.rpm postfix is created, that - as the name suggests - contains the found build requires but no sources. It can be used to install the build requires and restart the build.
On success the found build dependencies are also added to the source package. As always they depend on the exact circumstance of the build and may be different when bulding based on other packages or even another architecture.
Step Executing(%conf). Optional. Since rpm >= 4.18.
In %conf, the unpacked sources are configured for building.
Different build- and language ecosystems come with their own helper macros, but rpm has helpers for autotools based builds such as itself which typically look like this:
%conf%configure
Macros such as %cmake and %meson should also be placed in this section.
Step Executing(%build). If there is nothing to build, you should still declare this step in your spec.
In %build, the unpacked (and configured) sources are compiled to binaries.
Different build- and language ecosystems come with their own helper macros, but rpm has helpers for autotools based builds such as itself which typically look like this:
In %install, the software installation layout is prepared by creating the necessary directory structure into an initially empty “build root” directory and copying the just-built software in there to appropriate places. For many simple packages this is just:
%install%make_install
%install [is] required for creating packages that contain any files.
In this step, files should be installed to the %{buildroot} folder, e.g.:
Packages should place all their temporaries inside their designated %builddir, which rpm will automatically clean up. Needing a package specific %clean section generally suggests flaws in the spec.
Not a step. Required (practically). %files [-f file] [[-n] subpkg].
This specify all files that the package (or the subpackage) contains.
-f can be used in combination with %find_lang. Or rather, it just needs to be a
file with a list of line-separated paths that should be included into the final RPM package.
RPM generates debug packages (%{name}-debuginfo and %{name}-debugsource) automatically. When you did not
compile your software with debug symbols, you might see the following error:
Files can be specified with optionally an attribute3 (aka. a file directive4).
The following is an exhaustive list of file attributes available:
%artifact …# ╰─ denote files that are more like side-effects of packaging than actual content# the user would be interested in. Such files can be easily filtered out on queries.%caps# ╰─ sets the given POSIX.1e draft 15 capabilities on the file%config(…) … (can be used on it's own or with parameters)# ╰─ exhaustive list:# - config(missingok)# - config(noreplace)%dir …# ╰─ explicitly own the directory itself but not it’s contents%doc …# ╰─ store the file into %{_docdir}%docdir# ╰─ mado: personally never seen this used%ghost …# ╰─ mark a file as owned by the package, but don't actually install the file%license …# ╰─ store the file into %{_defaultlicensedir}%verify(…) …# ╰─ exhaustive list:# - verify(user owner) ← user and owner are same# - verify(group)# - verify(mode)# - verify(filedigest md5) ← same# - verify(size)# - verify(maj)# - verify(min)# - verify(link symlink) ← same# - verify(rdev)# - verify(mtime)# - verify(not ...) (don't verify this attribute)%missingok# ╰─ mark file presence optional%readme# ╰─ Obsolete - use %doc# special:%attr(…) …%defattr(…)
Package scripts execute before and after the main operation (install/remove etc.) of the package inside a transaction.
Package scripts should only be used for actions that are fundamentally package specific.
Domain specific registries, databases, caches and such are much better handled centrally
by file triggers. Similarly, user and group creation should be handled by rpm-sysusers, rather than scripting them.
Transaction scripts run before and after all the other package level
operations (install/remove etc.) in a transaction.
When multiple transaction scripts for a given slot are present in a transaction,
they are executed in the order of their install/removal order within the transaction.
Executed just before an install/update/reinstall transaction on the containing package starts.
No files from the transaction have been installed or removed yet. That is, in a fresh
installation to an empty system root, there are no files around and no interpreter to run,
so the only interpreter that can be reliably used in this slot is the embedded rpm-lua(7) interpreter.
Non-zero exit prevents the installation of the containing package.
This is a very special and a dangerous slot, and is best avoided.
List of sources, one per line. Handled like unnumbered Source tags. For clarity,
mixing Source tags and %sourcelist in one specfile is not recommended.