RPM-DEPENDENCY-GENERATORS(7)

πŸ“¦ version 6.1.0, in ubuntu stonking

πŸ’– RPM-DEPENDENCY-GENERATORS πŸ’–

okay bestie, welcome to rpm-dependency-generators(7) β€” Miscellaneous Information Manual energy, but make it cute. this is the page about how RPM clocks file attributes and dependency generators, and yes it's a lot, but we're gonna get through it together ✨


🌸 NAME 🌸

rpm-dependency-generators β€” the whole RPM file attribute and dependency generator interface, no cap πŸŽ€


πŸ“‹ SYNOPSIS πŸ“‹

πŸ—‚οΈ File attributes

%__NAME_path PATH_RE
%__NAME_magic MAGIC_RE
%__NAME_mime MIME_RE

%__NAME_exclude_path PATH_RE
%__NAME_exclude_magic MAGIC_RE
%__NAME_exclude_mime MIME_RE

%__NAME_flags FLAG[,FLAG ...]
%__NAME_exclude_flags FLAG[,FLAG ...]

βš™οΈ Generators

%__NAME_TYPE COMMAND
%__NAME_TYPE() BODY

%__NAME_protocol {singlefile|multifile}

πŸŽ›οΈ Per-package tunables

%_local_file_attrs NAME[:NAME ...]
%__TYPE_exclude DEPSTRING_RE
%__TYPE_exclude_from PATH_RE
%__NAME_TYPE_opts OPTS

πŸ“ Notes

so TYPE lowkey has a whole roster, it can be one of conflicts, enhances, obsoletes, orderwithrequires, provides, recommends, requires, suggests and supplements. and FLAG? that one's just exeonly and magic_and_path, that's the whole list bestie πŸ’…


🌈 DESCRIPTION 🌈

RPM runs a pluggable interface married to a file classifier, and together they sprinkle dependency info onto packages at build time. the system leans on specialized executables called generators β€” they're the ones doing the heavy lifting, extracting dependencies from files in their domain, which is called a file attribute. it's giving teamwork. and it complements the manual tags you already know and love β€” stuff like Requires or Provides over in rpm-spec(5) files 🫢


πŸ¦‹ FILE ATTRIBUTES πŸ¦‹

a file attribute is basically a logical label RPM slaps onto one or more files in the buildroot. how does it decide? based on a set of matching rules and their tunables, all defined as macros. an attribute can stand for one single file type (hello, ELF πŸ‘‹) or a whole broader domain, like everything installed into a specific location, or every file written in some particular programming language. versatile icon behavior.

these attributes are not the same as filesystem file attributes, jsyk. they only live in memory during package builds. one file can carry an arbitrary number of attributes, and one attribute can land on an arbitrary number of files. everyone's thriving, everyone's coexisting πŸ’–

want to introduce a file attribute called NAME for use during package builds? drop an rpm-macrofile(5) named NAME.attr into the %{_fileattrsdir} directory. that file should define at least one of the matching rules described below, periodt.

🎯 Matching rules

  • %__NAME_path PATH_RE β€” match the regex(7) string PATH_RE, macro-expanded on use, against filenames without the %{buildroot} prefix (like /bin/bash, for example).
  • %__NAME_magic MAGIC_RE β€” match the regex(7) string MAGIC_RE, macro-expanded on use, against file magic(5).

to figure out a compatible MAGIC_RE, run:

file -z -e tokens /some/file
  • %__NAME_mime MIME_RE β€” match the regex(7) string MIME_RE, macro-expanded on use, against MIME file types.

to figure out a compatible MIME_RE, run:

file --mime /some/file
  • %__NAME_exclude_path PATH_RE
  • %__NAME_exclude_magic MAGIC_RE
  • %__NAME_exclude_mime MIME_RE β€” filter out files matching the given regex(7). these rules are the exclusion counterparts of the inclusion rules above, the little shadow selves πŸ–€

okay so here's the matching situation: matching is inclusive unless a flag changes it (flags are below, bestie). if the path matches, or the magic matches, or both match, the file is said to have the attribute in question β€” unless there's a matching exclusion rule (which is also inclusive by default) or a flag that prevents the match. and heads up: if both the magic and mime rules are defined, the magic rule gets ignored and a warning gets printed 😭

πŸŽ›οΈ Tunables

  • %__NAME_flags FLAGS
  • %__NAME_exclude_flags FLAGS β€” tweak the inclusion rules and the exclusion rules respectively.

FLAGS is a comma-separated list, and the possible values are:

  • exeonly: require executable bit set
  • magic_and_path: require both magic and path to match

⚑ GENERATORS ⚑

a generator is an executable that reads filenames from standard input and writes dependencies of a single type to standard output, according to a protocol. it's written for one specific file attribute, and it gets defined as a macro inside the respective NAME.attr file. zero or more generators can be defined for a single file attribute β€” one for each supported type. so like, pick your roster, no pressure πŸ’…

🧚 Generator macros

  • %__NAME_conflicts COMMAND
  • %__NAME_enhances COMMAND
  • %__NAME_obsoletes COMMAND
  • %__NAME_orderwithrequires COMMAND (Added: 4.17.0)
  • %__NAME_provides COMMAND
  • %__NAME_recommends COMMAND
  • %__NAME_requires COMMAND
  • %__NAME_suggests COMMAND
  • %__NAME_supplements COMMAND

these generate dependencies of the respective type. COMMAND (a program name plus any arguments) gets executed, and RPM passes it one or more filenames that carry the file attribute NAME on standard input, then reads dependency strings from its standard output. for the whole tea on the input and output format, check Protocols πŸ“

πŸ“‘ Protocols

  • %__NAME_protocol PROTOCOL β€” use PROTOCOL when running dependency generators for the file attribute NAME. this decides the standard input and standard output format that the generators have to implement.

PROTOCOL can be one of these two:

  • singlefile
    • stdin: one matching filename at a time
    • stdout: dependency strings, one per line
  • multifile
    • stdin: all matching filenames at once, one per line
    • stdout: dependency strings, one per line, with the original filename, prepended with ; (semicolon), printed on its own line before the dependencies for that file (Added: 4.20.0)

if this macro isn't defined at all, the singlefile protocol is the one that gets used. and for newly written generators, multifile is the recommended pick since it's more performant β€” go fast, bestie 🏎️

unlike the PATH_RE in file attributes, generators receive filenames with the %{buildroot} prefix, so that they can actually access the real file contents on disk.

generators must always consume all of standard input. and for backwards compatibility reasons, generators should not make any assumptions about how many files get passed, regardless of which protocol is in use. stay flexible ✨

πŸ“€ Exported macros

on top of the globally defined macros, these following ones get automatically exported to generators, on a subpackage basis:

  • %{name}
  • %{epoch}
  • %{version}
  • %{release}

Added: 4.15.0

πŸͺ„ Parametric generators

if a generator is declared as a parametric macro, then the macro itself gets called for dependency generation, with the filename as its first argument (%1). the macro expansion itself counts as the generated dependencies, one per line.

here's a trivial little example that creates provides from path basenames β€” and it's enormously faster than the equivalent traditional generator that shells out to execute a script calling basename(1):

%__foo_provides()   %{basename:%{1}}

RPM's own macro primitives are kinda limited ngl, but busting out %{lua} unlocks writing complicated, macro-only generators. iconic.

see PARAMETRIC MACROS and Lua expansion in rpm-macros(7) for the details πŸ’œ

Added: 4.16.0

πŸ”Œ External generators

  • %__find_TYPE COMMAND β€” generate dependencies of the respective TYPE. COMMAND (a program name plus any arguments) gets executed, and RPM passes it the entire file list of the package at once, then reads dependency strings from its standard output. see Generator macros for the possible TYPE values.
⚠️ okay so this one is a legacy, deprecated interface. it's only available for v4 packages for backwards compatibility, and it should not be used. packages built this way carry less data about their files β€” like no "color" information (which is vital for RPM's functionality on multiarch systems), no file type information, and no per-file dependency tracking. so like, please don't 😭

if you want to enable this interface anyway, define the macro:

%_use_internal_dependency_generator 0

πŸŽ€ PER-PACKAGE TUNABLES πŸŽ€

these following macros can be used on a per-package basis β€” either by defining them straight up in the rpm-spec(5) file, or by passing them to rpmbuild(1) through the --define option:

  • %_local_file_attrs NAMES β€” register file attribute NAMES (separated by colons) for the duration of the build. the respective file attribute and generator macros have to be defined separately, so don't forget that part.

this is super useful for running generators that are shipped by the package itself 🫢

Added: 4.20.0

  • %__TYPE_exclude DEPSTRING_RE β€” filter out unwanted dependencies of TYPE by matching the regex(7) string DEPSTRING_RE, macro-expanded on use, against dependency strings. see Generator macros for the possible TYPE values.

Example:

%define __requires_exclude ^lib.*$
  • %__TYPE_exclude_from PATH_RE β€” filter out unwanted dependencies of TYPE by matching the regex(7) string PATH_RE, macro-expanded on use, against filenames without the %{buildroot} prefix (like /bin/bash, for example). see Generator macros for the possible TYPE values.

Example:

%define __provides_exclude_from ^%{_libdir}/mypkg/.*.so$
  • %__NAME_TYPE_opts OPTS β€” pass additional command line switches to the TYPE generator. see Generator macros for the possible TYPE values.
note that this macro should NOT be used when writing a file attribute file. instead, just pass the required arguments directly on the generator's command line when you define it. simplicity is the vibe ✨

πŸ” TROUBLESHOOTING πŸ”

πŸ› Displaying debug information

rpmbuild(1) and rpmdeps(1) both have a hidden --rpmfcdebug switch that turns on extra output for the dependency generation stage. the output format is currently roughly like this:

<file number> <on-disk path> <color info> <file attribute matches>
    <list of dependencies associated with this file>

file attribute matches are the names of the rules that matched for the file, and that's exactly where rule troubleshooting typically starts: a file with no attributes will not have any dependencies attached. a whole snack with nothing on it, basically πŸ™ˆ

🌍 Global excludes

global variants of the per-package exclusion macros can also be defined on the system:

  • %__global_TYPE_exclude DEPSTRING_RE
  • %__global_TYPE_exclude_from PATH_RE

these apply to all package builds and thus may affect the output of a particular generator in ways you did not expect. so if something's acting cursed, make sure to inspect the contents of these macros first πŸ‘€


πŸ’– EXAMPLES πŸ’–

okay bestie this is the part where it all clicks, i promise 🌈


🌸 Example 1. A trivial multifile generator 🌸

say we've got a %{_fileattrsdir}/frob.attr file and it looks exactly like this:

%__frob_provides %{_rpmconfigdir}/frobnize --provides
%__frob_requires %{_rpmconfigdir}/frobnize --requires
%__frob_protocol multifile
%__frob_path \.frob$
%__frob_magic ^.* a frob file .*$

so this file is defining a file attribute named frob, and it's got two generators hanging off it, and both of them call on a frobnize script that speaks the multifile protocol πŸ’… and the file attribute matches every file with the .frob suffix plus any file containing that "a frob file" magic string. both. either. slay ✨

and %{_rpmconfigdir}/frobnize looks like this:

#!/bin/bash
# Frob dependency extractor

# Type of dependency strings to print
mode=$1

# Process every file on standard input
while read -r file; do
    # Print currently processed file as per multifile protocol
    echo ";$file"

    # Get basename and first line
    name=$(basename $file | cut -f1 -d.)
    line=$(head -n1 $file)

    # Print dependency strings
    case $mode in
       --provides)
           echo "frob($name)"
           echo "frob($line)"
           ;;
       --requires)
           echo "bard($name)"
           echo "bard($line)"
           ;;
    esac
done

now imagine there's a frob.spec file that installs a file called hello.frob whose contents are "world", dropping it somewhere on the filesystem. when that spec gets built, the resulting package ends up with these provides and requires πŸ‘‘

$ rpmbuild -bb /path/to/frob.spec
...
$ rpm -qp --provides --requires /path/to/frob.rpm
...
frob(hello)
frob(world)
bard(hello)
bard(world)
...

and here's the cute part πŸŽ€ if the package had multiple files with the .frob suffix or the "a frob file" magic, the frobnize script would still only get executed once, with all the matching filenames passed in at the same time. efficiency, she ate ⭐

lowkey important though bestie: if that generator ever decided to dip out of the while loop early, it would have to discard whatever input was still left over before exiting β€” that's the protocol, no cap 😭 β€” and that cleanup can be done with this command placed after the loop:
cat > /dev/null

πŸ¦‹ Example 2. Spec-local generators πŸ¦‹

this spec file snippet brings in two spec-local file attributes, frob and bard, and they match literally any and all files. their generators use a frobnize and a bardize.sh script respectively β€” one shipped by the package itself, and one only included with the sources. iconic πŸ’œ

...
Source1: bardize.sh
...
%define _local_file_attrs frob:bard
%define __frob_provides %{buildroot}/%{_rpmconfigdir}/frobnize
%define __frob_path .*
%define __bard_provides %{SOURCE1}
%define __bard_path .*
...

🧚 Example 3. Bundled file attributes and generators 🧚

%{_fileattrsdir}/*.attr
%{_rpmconfigdir}/*.req
%{_rpmconfigdir}/*.prov

this right here is a small, carefully curated set of file attributes and their generators that come bundled with RPM itself πŸ’– they cover the core domains you'd find on a UNIX/Linux system β€” think ELF binaries, executable scripts, or sysusers.d(5) files. the essentials, periodt ✨


πŸ‘‘ SEE ALSO πŸ‘‘

like, go read these too, they're all part of the lore 🌈


and that's the whole page bestie, you made it to the end πŸ«ΆπŸ’– this was RPM 6.1.0, dated 2026-08-20 β€” go forth and generate dependencies, you absolute main character πŸ‘‘βœ¨

πŸ“¦ where this page comes from