Search code examples
packagingpkg-configdnf

How exactly does `dnf install 'pkgconfig(NAME)'` syntax work?


Fedora Packaging Guidelines (permalink) officially recommends using the pkgconfig(NAME) syntax when declaring build dependencies. So for example, instead of BuildRequires: libxcb-devel, you would declare BuildRequires: pkgconfig(xcb). (Similarly, dnf install 'pkgconfig(xcb)' would offer to install libxcb-devel, which is why I assumed this is a feature of dnf as opposed to the SPEC file processor.)

I've always been curious, and honestly it has bugged me throughout these few years I've been doing packaging - how exactly does this work? I know pkg-config (or pkgconf) uses .pc files to determine a library's associated names and arguments, and that those .pc files are shipped with development libraries (*-devel packages on Fedora). But that's the problem - how does the build system (more specifically, dnf) resolve a declaration like pkgconfig(xcb) before installing libxcb-devel which provides the .pc file?

The only possible explanation I can think of at this point is if there's some kind of central registry of all .pc files within the remote repositories that dnf can easily query. But I can find absolutely no documentation for this, nor have I noticed the existence of such a file in various mirrors.

So what kind of magic is dnf install pkgconfig(NAME) doing? Is there a map (or a command to compute a map) between pkgconfig(NAME) and the concrete packages they point to? This would make the process of looking up the right name to declare in BuildRequires: a whole lot easier for me.


Solution

  • So I did some digging, and it turns out the pkgconfig(...) entries are listed as "provides" entries in the package metadata. Therefore there is not really anything special with the pkgconfig(...) syntax; it's just another string in the eyes of dnf. In fact, a quick search in the dnf repository returns nothing at all:

    $ rg 'pkg-?conf(ig)?'
    # nothing printed
    

    During package build, it seems like rpmbuild will look for all *.pc files declared by the spec file, and generate corresponding pkgconfig(...) provides entries. Those entries are stored in the package metadata, which means they are trivially queryable even before installing the package.

    To list the items provided by a package, run:

    $ dnf repoquery --provides <PKG>
    
    # for example (bzip2-devel, RHEL8)
    $ dnf repoquery --provides bzip2-devel
    bzip2-devel = 1.0.6-26.el8
    bzip2-devel(x86-32) = 1.0.6-26.el8
    bzip2-devel(x86-64) = 1.0.6-26.el8
    pkgconfig(bzip2) = 1.0.6
    

    To list the packages that provide an item, run:

    $ dnf provides <ITEM>
    
    # for example (pkgconfig(bzip2), RHEL8)
    # note that parentheses need to be either quoted or escaped
    # see https://unix.stackexchange.com/a/26064/375550
    $ dnf provides 'pkgconfig(bzip2)'
    bzip2-devel-1.0.6-26.el8.i686 : Libraries and header files for apps which will use bzip2
    Repo        : rhel-8-for-x86_64-baseos-rpms
    Matched from:
    Provide    : pkgconfig(bzip2) = 1.0.6
    
    bzip2-devel-1.0.6-26.el8.x86_64 : Libraries and header files for apps which will use bzip2
    Repo        : rhel-8-for-x86_64-baseos-rpms
    Matched from:
    Provide    : pkgconfig(bzip2) = 1.0.6