Guide to pkg-config

Dan Nicholson

Overview

This document aims to give an overview to using the pkg-config tool from the perspective of both a user and a developer. It reviews the concepts behind pkg-config, how to write pkg-config files to support your project, and how to use pkg-config to integrate with 3rd party projects.

More information on pkg-config can be found at the website and in the pkg-config(1) manual page.

This document assumes usage of pkg-config on a Unix-like operating system such as Linux. Some of the details may be different on other platforms.

Why?

Modern computer systems use many layered components to provide applications to the user. One of the difficulties in assembling these parts is properly integrating them. pkg-config collects metadata about the installed libraries on the system and easily provides it to the user.

Without a metadata system such as pkg-config, it can be very difficult to locate and obtain details about the services provided on a given computer. For a developer, installing pkg-config files with your package greatly eases adoption of your API.

Concepts

The primary use of pkg-config is to provide the necessary details for compiling and linking a program to a library. This metadata is stored in pkg-config files. These files have the suffix .pc and reside in specific locations known to the pkg-config tool. This will be described in more detail later.

The file format contains predefined metadata keywords and freeform variables. An example may be illustrative:

prefix=/usr/local
exec_prefix=${prefix}
includedir=${prefix}/include
libdir=${exec_prefix}/lib

Name: foo
Description: The foo library
Version: 1.0.0
Cflags: -I${includedir}/foo
Libs: -L${libdir} -lfoo

The keyword definitions such as Name: begin with a keyword followed by a colon and the value. The variables such as prefix= are a string and value separated by an equals sign. The keywords are defined and exported by pkg-config. The variables are not necessary, but can be used by the keyword definitions for flexibility or to store data not covered by pkg-config.

Here is a short description of the keyword fields. A more in depth description of these fields and how to use them effectively will be given in the Writing pkg-config files section.

Writing pkg-config files

When creating pkg-config files for a package, it is first necessary to decide how they will be distributed. Each file is best used to describe a single library, so each package should have at least as many pkg-config files as they do installed libraries.

The package name is determined through the filename of the pkg-config metadata file. This is the portion of the filename prior to the .pc suffix. A common choice is to match the library name to the .pc name. For instance, a package installing libfoo.so would have a corresponding libfoo.pc file containing the pkg-config metadata. This choice is not necessary; the .pc file should simply be a unique identifier for your library. Following the above example, foo.pc or foolib.pc would probably work just as well.

The Name, Description and URL fields are purely informational and should be easy to fill in. The Version field is a bit trickier to ensure that it is usable by consumers of the data. pkg-config uses the algorithm from RPM for version comparisons. This works best with a dotted decimal number such as 1.2.3 since letters can cause unexpected results. The number should be monotonically increasing and be as specific as possible in describing the library. Usually it's sufficient to use the package's version number here since it's easy for consumers to track.

Before describing the more useful fields, it will be helpful to demonstrate variable definitions. The most common usage is to define the installation paths so that they don't clutter the metadata fields. Since the variables are expanded recursively, this is very helpful when used in conjunction with autoconf derived paths.

prefix=/usr/local
includedir=${prefix}/include

Cflags: -I${includedir}/foo

The most important pkg-config metadata fields are Requires, Requires.private, Cflags, Libs and Libs.private. They will define the metadata used by external projects to compile and link with the library.

Requires and Requires.private define other modules needed by the library. It is usually preferred to use the private variant of Requires to avoid exposing unnecessary libraries to the program that is linking with your library. If the program will not be using the symbols of the required library, it should not be linking directly to that library. See the discussion of overlinking for a more thorough explanation.

Since pkg-config always exposes the link flags of the Requires libraries, these modules will become direct dependencies of the program. On the other hand, libraries from Requires.private will only be included when static linking. For this reason, it is usually only appropriate to add modules from the same package in Requires.

The Libs field contains the link flags necessary to use that library. In addition, Libs and Libs.private contain link flags for other libraries not supported by pkg-config. Similar to the Requires field, it is preferred to add link flags for external libraries to the Libs.private field so programs do not acquire an additional direct dependency.

Finally, the Cflags contains the compiler flags for using the library. Unlike the Libs field, there is not a private variant of Cflags. This is because the data types and macro definitions are needed regardless of the linking scenario.

Using pkg-config files

Assuming that there are .pc files installed on the system, the pkg-config tool is used to extract the metadata for usage. A short description of the options can be seen by executing pkg-config --help. A more in depth discussion can be found in the pkg-config(1) manual page. This section will provide a brief explanation of common usages.

Consider a system with two modules, foo and bar. Their .pc files might look like this:

foo.pc:
prefix=/usr
exec_prefix=${prefix}
includedir=${prefix}/include
libdir=${exec_prefix}/lib

Name: foo
Description: The foo library
Version: 1.0.0
Cflags: -I${includedir}/foo
Libs: -L${libdir} -lfoo

bar.pc:
prefix=/usr
exec_prefix=${prefix}
includedir=${prefix}/include
libdir=${exec_prefix}/lib

Name: bar
Description: The bar library
Version: 2.1.2
Requires.private: foo >= 0.7
Cflags: -I${includedir}
Libs: -L${libdir} -lbar

The version of the modules can be obtained with the --modversion option.

$ pkg-config --modversion foo
1.0.0
$ pkg-config --modversion bar
2.1.2

To print the link flags needed for each module, use the --libs option.

$ pkg-config --libs foo
-lfoo
$ pkg-config --libs bar
-lbar

Notice that pkg-config has suppressed part of the Libs field for both modules. This is because it treats the -L flag specially and knows that the ${libdir} directory /usr/lib is part of the system linker search path. This keeps pkg-config from interfering with the linker operation.

Also, although foo is required by bar, the link flags for foo are not output. This is because foo is not directly needed by an application that only wants to use the bar library. For statically linking a bar application, we need both sets of linker flags:

$ pkg-config --libs --static bar
-lbar -lfoo

pkg-config needs to output both sets of link flags in this case to ensure that the statically linked application will find all the necessary symbols. On the other hand, it will always output all the Cflags.

$ pkg-config --cflags bar
-I/usr/include/foo  
$ pkg-config --cflags --static bar
-I/usr/include/foo

Another useful option, --exists, can be used to test for a module's availability.

$ pkg-config --exists foo
$ echo $?
0

One of the nicest features of pkg-config is providing version checking. It can be used to determine if a sufficient version is available.

$ pkg-config --libs "bar >= 2.7"
Requested 'bar >= 2.7' but version of bar is 2.1.2

Some commands will provide more verbose output when combined with the --print-errors option.

$ pkg-config --exists --print-errors xoxo
Package xoxo was not found in the pkg-config search path.
Perhaps you should add the directory containing `xoxo.pc'
to the PKG_CONFIG_PATH environment variable
No package 'xoxo' found

The message above references the PKG_CONFIG_PATH environment variable. This variable is used to augment pkg-config's search path. On a typical Unix system, it will search in the directories /usr/lib/pkgconfig and /usr/share/pkgconfig. This will usually cover system installed modules. However, some local modules may be installed in a different prefix such as /usr/local. In that case, it's necessary to prepend the search path so that pkg-config can locate the .pc files.

$ pkg-config --modversion hello
Package hello was not found in the pkg-config search path.
Perhaps you should add the directory containing `hello.pc'
to the PKG_CONFIG_PATH environment variable
No package 'hello' found
$ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
$ pkg-config --modversion hello
1.0.0

A few autoconf macros are also provided to ease integration of pkg-config modules into projects.

Frequently asked questions

  1. My program uses library x. What do I do?
  2. The pkg-config output can easily be used on the compiler command line. Assuming the x library has a x.pc pkg-config file:

    cc `pkg-config --cflags --libs x` -o myapp myapp.c

    The integration can be more robust when used with autoconf and automake. By using the supplied PKG_CHECK_MODULES macro, the metadata is easily accessed in the build process.

    configure.ac:
    PKG_CHECK_MODULES([X], [x])
    
    Makefile.am:
    myapp_CFLAGS = $(X_CFLAGS)
    myapp_LDADD = $(X_LIBS)

    If the x module is found, the macro will fill and substitute the X_CFLAGS and X_LIBS variables. If the module is not found, an error will be produced. Optional 3rd and 4th arguments can be supplied to PKG_CHECK_MODULES to control actions when the module is found or not.

  3. My library z installs header files which include libx headers. What do I put in my z.pc file?
  4. If the x library has pkg-config support, add it to the Requires.private field. If it does not, augment the Cflags field with the necessary compiler flags for using the libx headers. In either case, pkg-config will output the compiler flags when --static is used or not.

  5. My library z uses libx internally, but does not expose libx data types in its public API. What do I put in my z.pc file?
  6. Again, add the module to Requires.private if it supports pkg-config. In this case, the compiler flags will be emitted unnecessarily, but it ensures that the linker flags will be present when linking statically. If libx does not support pkg-config, add the necessary linker flags to Libs.private.


Dan Nicholson <dbn.lists (at) gmail (dot) com>

Copyright (C) 2010 Dan Nicholson.
This document is licensed under the GNU General Public License, Version 2 or any later version.