tl;dr: Use AX_PKG_CHECK_MODULES to split public/private dependencies; use AC_CONFIG_FILES to magically include the API version in the .pc file name.
A few tips for creating a pkg-config file which you will never need to think about maintaining again — because one of the most common problems with pkg-config files is that their dependency lists are years out of date compared to the dependencies checked for in configure.ac. See lower down for some example automake snippets.
- Include the project’s major API version ((Assuming this is the number which will change if backwards-incompatible API/ABI changes are made.)) in the pkg-config file name. e.g. libfoo-1.pc rather than libfoo.pc. This will allow parallel installation of two API-incompatible versions of the library if it becomes necessary in future.
- Split private and public dependencies between Requires and Requires.private. This eliminates over-linking when dynamically linking against the project, since in that case the private dependencies are not needed. This is easily done using the AX_PKG_CHECK_MODULES macro (and perhaps using an upstream macro in future — see pkg-config bug #87154). A dependency is public when its symbols are exposed in public headers installed by your project; it is private otherwise.
- Include useful ancillary variables, such as the paths to any utilities, directories or daemons which ship with the project. For example, glib-2.0.pc has variables giving the paths for its utilities: glib-genmarshal, gobject-query and glib-mkenums. libosinfo-1.0.pc has variables for its database directories. Ensure the variables use a variable form of ${prefix}, allowing it to be overridden when invoking pkg-config using pkg-config --define-variable=prefix=/some/other/prefix. This allows use of libraries installed in one (read only) prefix from binaries in another, while installing ancillary files (e.g. D-Bus service files) to the second prefix.
- Substitute in the Name and Version using @PACKAGE_NAME@ and @PACKAGE_VERSION@ so they don’t fall out of sync.
- Place the .pc.in template in the source code subdirectory for the library it’s for — so if your project produces multiple libraries (or might do in future), the .pc.in files don’t get mixed up at the top level.
Given all those suggestions, here’s a template libmy-project/my-project.pc.in file (updated to incorporate suggestions by Dan Nicholson):
prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ my_project_utility=my-project-utility-binary-name my_project_db_dir=@sysconfdir@/my-project/db Name: @PACKAGE_NAME@ Description: Some brief but informative description Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lmy-project-@API_VERSION@ Cflags: -I${includedir}/my-project-@API_VERSION@ Requires: @AX_PACKAGE_REQUIRES@ Requires.private: @AX_PACKAGE_REQUIRES_PRIVATE@
And here’s a a few snippets from a template configure.ac:
# Release version m4_define([package_version_major],[1]) m4_define([package_version_minor],[2]) m4_define([package_version_micro],[3]) # API version m4_define([api_version],[1]) AC_INIT([my-project], [package_version_major.package_version_minor.package_version_micro], …) # Dependencies PKG_PROG_PKG_CONFIG PKG_INSTALLDIR glib_reqs=2.40 gio_reqs=2.42 gthread_reqs=2.40 nice_reqs=0.1.6 # The first list on each line is public; the second is private. # The AX_PKG_CHECK_MODULES macro substitutes AX_PACKAGE_REQUIRES and # AX_PACKAGE_REQUIRES_PRIVATE. AX_PKG_CHECK_MODULES([GLIB], [glib-2.0 >= $glib_reqs gio-2.0 >= $gio_reqs], [gthread-2.0 >= $gthread_reqs]) AX_PKG_CHECK_MODULES([NICE], [nice >= $nice_reqs], []) AC_SUBST([PACKAGE_VERSION_MAJOR],package_version_major) AC_SUBST([PACKAGE_VERSION_MINOR],package_version_minor) AC_SUBST([PACKAGE_VERSION_MICRO],package_version_micro) AC_SUBST([API_VERSION],api_version) # Output files # Rename the template .pc file to include the API version on configure AC_CONFIG_FILES([ libmy-project/my-project-$API_VERSION.pc:libmy-project/my-project.pc.in … ],[], [API_VERSION='$API_VERSION']) AC_OUTPUT
And finally, the top-level Makefile.am:
# Install the pkg-config file; the directory is set using # PKG_INSTALLDIR in configure.ac. pkgconfig_DATA = libmy-project/my-project-$(API_VERSION).pc
Once that’s all built, you’ll end up with an installed my-project-1.pc file containing the following (assuming a prefix of /usr; note that by default autoconf substitutes in references to variables rather than the values themselves, so pkg-config can continue to be used with --define-variable to override the prefix):
prefix=/usr exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include my_project_utility=my-project-utility-binary-name my_project_db_dir=${prefix}/etc/my-project/db Name: my-project Description: Some brief but informative description Version: 1.2.3 Libs: -L${libdir} -lmy-project-1 Cflags: -I${includedir}/my-project-1 Requires: glib-2.0 >= 2.40 gio-2.0 >= 2.42 nice >= 0.1.6 Requires.private: gthread-2.0 >= 2.40
All code samples in this post are released into the public domain.