PkgConfigDeps
Important
This feature is still under development, while it is recommended and usable and we will try not to break them in future releases, some breaking changes might still happen if necessary to prepare for the Conan 2.0 release.
PkgConfigDeps
Available since: 1.38.0
The PkgConfigDeps
is the dependencies generator for pkg-config. Generates pkg-config files named <PKG-NAME>.pc
(where <PKG-NAME
is the name declared by dependencies in cpp_info.names["pkg_config"]
if specified),
containing a valid pkg-config file syntax. Indeed, it can also be defined using set_property
and the
property pkg_config_name
(available since Conan 1.36), for instance:
self.cpp_info.components["mycomponent"].set_property("pkg_config_name", "mypkg-config-name")
Note
In Conan 2.0 that will be the default way of setting those properties and also passing custom properties to generators. Check the cpp_info attributes reference for more information.
The prefix
variable is automatically adjusted to the package_folder
.
The PkgConfigDeps
generator can be used by name in conanfiles:
class Pkg(ConanFile):
generators = "PkgConfigDeps"
[generators]
PkgConfigDeps
And it can also be fully instantiated in the conanfile generate()
method:
from conan import ConanFile
from conan.tools.gnu import PkgConfigDeps
class App(ConanFile):
settings = "os", "arch", "compiler", "build_type"
requires = "zlib/1.2.11"
def generate(self):
pc = PkgConfigDeps(self)
pc.generate()
The PkgConfigDeps
will generate the *.pc
file after a conan install
command:
$ conan install .
# Check the [PC_FILE_NAME].pc created in your current folder
Now, running this command using the previous conanfile.py
, you can check the zlib.pc
file created into your current folder:
prefix=/Users/YOUR_USER/.conan/data/zlib/1.2.11/_/_/package/647afeb69d3b0a2d3d316e80b24d38c714cc6900
libdir=${prefix}/lib
includedir=${prefix}/include
Name: zlib
Description: Conan package: zlib
Version: 1.2.11
Libs: -L"${libdir}" -lz -F Frameworks
Cflags: -I"${includedir}"
build_context_activated
Available since: 1.52.0
When you have a build-require, by default, the *.pc
files are not generated.
But you can activate it using the build_context_activated attribute:
tool_requires = ["my_tool/0.0.1"]
def generate(self):
pc = PkgConfigDeps(self)
# generate the *.pc file for the tool require
pc.build_context_activated = ["my_tool"]
pc.generate()
Warning
The build_context_activated
feature will fail if no “build” profile is used. This feature only work when using
the two host and build profiles.
build_context_suffix
Available since: 1.52.0
When you have the same package as a build-require and as a regular require it will cause a conflict in the generator
because the file names of the *.pc
files will collide as well as the names, requires names, etc.
For example, this is a typical situation with some requirements (capnproto, protobuf…) that contain a tool used to generate source code at build time (so it is a build_require), but also providing a library to link to the final application, so you also have a regular require. Solving this conflict is specially important when we are cross-building because the tool (that will run in the building machine) belongs to a different binary package than the library, that will “run” in the host machine.
You can use the build_context_suffix attribute to specify a suffix for a requirement, so the files/requires/names of the requirement in the build context (tool require) will be renamed:
tool_requires = ["my_tool/0.0.1"]
requires = ["my_tool/0.0.1"]
def generate(self):
pc = PkgConfigDeps(self)
# generate the *.pc file for the tool require
pc.build_context_activated = ["my_tool"]
# disambiguate the files, requires, names, etc
pc.build_context_suffix = {"my_tool": "_BUILD"}
pc.generate()
Warning
The build_context_suffix
feature will fail if no “build” profile is used. This feature only work when using
the two host and build profiles.
Components
If a recipe uses components, the files generated will be <[PKG-NAME]-[COMP-NAME]>.pc with their corresponding flags and require relations.
Additionally, a <PKG-NAME>.pc is generated to maintain compatibility for consumers with recipes that start supporting components. This <PKG-NAME>.pc file will declare all the components of the package as requires while the rest of the fields will be empty, relying on the propagation of flags coming from the components <[PKG-NAME]-[COMP-NAME]>.pc files.
Properties
The following properties affect the PkgConfigDeps
generator:
pkg_config_name property will define the name of the generated
*.pc
file (xxxxx.pc
)pkg_config_aliases property sets some aliases of any package/component name for pkg_config generator. This property only accepts list-like Python objects.
pkg_config_custom_content property will add user defined content to the .pc files created by this generator.
component_version property sets a custom version to be used in the
Version
field belonging to the created*.pc
file for that component.
These properties can be defined at global cpp_info
level or at component level.
Example:
def package_info(self):
custom_content = "datadir=${prefix}/share"
self.cpp_info.set_property("pkg_config_custom_content", custom_content)
self.cpp_info.set_property("pkg_config_name", "myname")
self.cpp_info.components["mycomponent"].set_property("pkg_config_name", "componentname")
self.cpp_info.components["mycomponent"].set_property("pkg_config_aliases", ["alias1", "alias2"])
self.cpp_info.components["mycomponent"].set_property("component_version", "1.14.12")
Names and aliases
Aliases are available since: 1.43.0
By default, the *.pc
files will be named following these rules:
For packages, it uses the package name, e.g., package
zlib/1.2.11
->zlib.pc
.For components, the package name + hyphen + component name, e.g.,
openssl/3.0.0
withself.cpp_info.components["crypto"]
->openssl-crypto.pc
.
You can change that default behavior with the pkg_config_name
and pkg_config_aliases
properties. For instance, openssl/3.0.0`
recipe has these pkg_config_name
properties already declared:
from conan import ConanFile
class OpenSSLConan(ConanFile):
name = "openssl"
# any code here
def package_info(self):
self.cpp_info.set_property("pkg_config_name", "openssl")
self.cpp_info.components["crypto"].set_property("pkg_config_name", "libcrypto")
self.cpp_info.components["ssl"].set_property("pkg_config_name", "libssl")
Run conan install openssl/3.0.0@ -g PkgConfigDeps and check the *.pc
files created:
libcrypto.pc
libssl.pc
openssl.pc
zlib.pc (openssl requires zlib)
Their pkg_config_name
properties are used as the final *.pc
file names:
Name: openssl
Description: Conan package: openssl
Version: 3.0.0
Requires: libcrypto libssl
prefix=/Users/conan_user/.conan/data/openssl/3.0.0/_/_/package/88955cec2844f731470e07bd44ce5a3a24ec88b7
libdir1=${prefix}/lib
includedir1=${prefix}/include
Name: libcrypto
Description: Conan component: libcrypto
Version: 3.0.0
Libs: -L"${libdir1}" -lcrypto -F Frameworks
Cflags: -I"${includedir1}"
Requires: zlib
A special mention when a component shares the same *.pc
file name as the root package one:
from conan import ConanFile
class OpenCLConan(ConanFile):
# ...
def package_info(self):
self.cpp_info.set_property("pkg_config_name", "OpenCL") # -> OpenCL.pc
self.cpp_info.components["_opencl-headers"].set_property("pkg_config_name", "OpenCL") # -> OpenCL.pc
The only *.pc
file created will be the one belonging to the component:
OpenCL.pc (from component)
Now, let’s see how pkg_config_aliases
property works step by step.
Let’s create our own myopenssl/1.0.0
recipe and define several aliases like the following:
from conan import ConanFile
class MyOpenSSLConan(ConanFile):
name = "myopenssl"
version = "1.0.0"
def package_info(self):
# Aliases
self.cpp_info.set_property("pkg_config_aliases", ["myopenssl_alias"])
self.cpp_info.components["mycrypto"].set_property("pkg_config_aliases", ["mycrypto", "crp"])
self.cpp_info.components["myssl"].set_property("pkg_config_aliases", ["myssl"])
Then, after creating the package locally with conan create . and consuming it conan install myopenssl/1.0.0@ -g PkgConfigDeps, the files created will be:
myopenssl-mycrypto.pc
myopenssl-myssl.pc
myopenssl.pc
crp.pc (alias of myopenssl-mycrypto)
mycrypto.pc (alias of myopenssl-mycrypto)
myssl.pc (alias of myopenssl-myssl)
myopenssl_alias.pc (alias of myopenssl)
Where any of those aliases files contains something like this:
Name: mycrypto
Description: Alias mycrypto for myopenssl-mycrypto
Version: 1.0.0
Requires: myopenssl-mycrypto
It’s also possible to use both properties together:
from conan import ConanFile
class MyOpenSSLConan(ConanFile):
name = "myopenssl"
version = "1.0.0"
# any code here
def package_info(self):
self.cpp_info.set_property("pkg_config_name", "myopenssl")
self.cpp_info.components["mycrypto"].set_property("pkg_config_name", "libmycrypto")
self.cpp_info.components["myssl"].set_property("pkg_config_name", "libmyssl")
# Aliases
self.cpp_info.set_property("pkg_config_aliases", ["myopenssl_alias"])
self.cpp_info.components["mycrypto"].set_property("pkg_config_aliases", ["mycrypto", "crp"])
self.cpp_info.components["myssl"].set_property("pkg_config_aliases", ["myssl"])
After executing the commands mentioned above, the files are:
libmycrypto.pc
libmyssl.pc
myopenssl.pc
crp.pc (alias of libmycrypto)
mycrypto.pc (alias of libmycrypto)
myssl.pc (alias of libmyssl)
myopenssl_alias.pc (alias of myopenssl)
The only change is which name the alias is pointing to:
Name: mycrypto
Description: Alias mycrypto for libmycrypto
Version: 1.0.0
Requires: libmycrypto