ch25.finding_things
Chapter 25. Finding Things
Part 3 Preface...
- Projects often need to interact with external entities rather than operating in isolation.
- Interaction happens in two main ways:
- Dependencies: Projects may need external files, libraries, executables, and packages.
- Consumers: Projects may be integrated by others either at the source level or through pre-built binaries; they may also be expected to be installed system-wide.
- Providing a project as a standalone package or for consumption by other projects requires maintaining a certain level of quality.
- Automated testing is crucial in ensuring software quality and should be easy to define, execute, and report results.
- The CMake suite assists in managing dependencies, automated testing through CTest, and packaging with CPack.
- CMake also offers tools like presets to handle the increasing complexity in configuring, building, and testing projects as they scale, beneficial for developers and continuous integration builds.
- The book section on CMake focuses on maximizing its benefits and avoiding common mistakes in managing external project interactions.
Ch 25 preface ...
- Projects often depend on external resources such as libraries, tools, configuration files, or header files.
- CMake aids in managing these dependencies by:
- Finding Resources: Using
find_...()commands to locate specific files, libraries, programs, or complete packages. - Integration Capabilities: Enabling projects to be easily found and integrated into other projects.
- Modules and pkg-config: Leveraging CMake modules and pkg-config to obtain and provide information about external packages.
- Package Files: Facilitating the creation of package files for consumption by other projects.
- Finding Resources: Using
25.1. Finding Files And Paths
- The
find_...()command in CMake can search for a file using a single name or a list of names with theNAMESoption. - Naming Variations: Useful when the file has different names across operating systems or versions.
- Search Order: Names should be listed in preferred order; CMake stops searching after the first match.
- Version Numbering: Names without version details should be listed before those with version details to prioritize locally built files.
- Search Locations: Conducted in a well-defined order with options to skip certain locations.
- Tailoring Search: Options allow customization of the search process to bypass certain locations if needed.
| Location | Skip option |
|---|---|
| Package root variables | NO_PACKAGE_ROOT_PATH |
| Cache variables (CMake-specific) | NO_CMAKE_PATH |
| Environment variables (CMake-specific) | NO_CMAKE_ENVIRONMENT_PATH |
| Paths specified via the HINTS option | X can't skip |
| Environment variables (system-specific) | NO_SYSTEM_ENVIRONMENT_PATH |
| Cache variables (platform-specific) | NO_CMAKE_SYSTEM_PATH |
| Paths specified via the PATHS option | X can't skip |
-
Package Root Variables (CMake >= 3.12):
- Only searched when
find_file()is invoked via a script duringfind_package()execution.
- Only searched when
-
Cache Variables (CMake-specific):
CMAKE_PREFIX_PATH: Central variable affecting allfind_...()commands; assumes a directory structure with subdirectories likebin,lib,include.- For
find_file(), searches<prefix>/includeand<prefix>/include/${CMAKE_LIBRARY_ARCHITECTURE}ifCMAKE_LIBRARY_ARCHITECTUREis set, giving priority to architecture-specific directories.
- For
CMAKE_INCLUDE_PATHandCMAKE_FRAMEWORK_PATH:- Provide directories for specific searches when not included in standard layouts.
CMAKE_INCLUDE_PATHused byfind_file()andfind_path(); does not append subdirectories.CMAKE_FRAMEWORK_PATHused byfind_file(),find_path(), andfind_library(); handled similarly toCMAKE_INCLUDE_PATH.
-
CMAKE_LIBRARY_ARCHITECTURE:
- Automatically set by CMake to prioritize architecture-specific directories; not typically user-modified.
-
Environment Variables (CMake-specific):
- Variables: Utilizes
CMAKE_PREFIX_PATH,CMAKE_INCLUDE_PATH, andCMAKE_FRAMEWORK_PATH. - Behavior: Treated similarly to their corresponding cache variables.
- Platform Specifics:
- On Unix platforms, list items in these environment variables are separated by a colon (
:) instead of a semi-colon (;), aligning with Unix path list conventions.
- On Unix platforms, list items in these environment variables are separated by a colon (
- Control Variable (CMake 3.16+):
CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATHcan be set to control default search behavior akin toCMAKE_FIND_USE_CMAKE_PATH.
- Variables: Utilizes
-
Environment Variables (System-specific):
- Variables: Utilizes
INCLUDEandPATH, which may contain a list of directories separated by platform-specific path separators (colon on Unix, semi-colon on Windows). - Search Location Addition:
INCLUDEdirectories are added to the search locations before those fromPATH.
- Windows-Specific Processing:
- For each
PATHentry, the base path is derived by removing any trailingbinorsbinsubdirectory. - If
CMAKE_LIBRARY_ARCHITECTUREis defined, the search includes<base>/include/${CMAKE_LIBRARY_ARCHITECTURE}. - Regardless of
CMAKE_LIBRARY_ARCHITECTURE,<base>/includeis always added. - These paths are positioned immediately before their corresponding unmodified
PATHentry in the search order.
- For each
- Control Variable (CMake 3.16+):
CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATHcan be set to control default search behavior similar toCMAKE_FIND_USE_CMAKE_PATH.
- Variables: Utilizes
-
Cache Variables (Platform-specific):
-
Variables: Includes
CMAKE_SYSTEM_PREFIX_PATH,CMAKE_SYSTEM_INCLUDE_PATH, andCMAKE_SYSTEM_FRAMEWORK_PATH. -
Purpose: These variables are set automatically by CMake to reflect compiler and platform-specific locations as part of the platform toolchain setup.
-
Developer Control:
- Generally, developers should not manually set these variables.
- An exception is when using a custom toolchain file, where setting these variables might be appropriate.
-
Behavior Control Variable (CMake 3.16+):
CMAKE_FIND_USE_CMAKE_SYSTEM_PATHcan be set to control the default search behavior, similar toCMAKE_FIND_USE_CMAKE_PATH.
-
Install Prefix Considerations:
- CMAKE_SYSTEM_PREFIX_PATH: May include the base install location, which could lead to undesirable search results.
- CMake 3.24 Updates:
- Introduced
NO_CMAKE_INSTALL_PREFIXto ignore install prefixes inCMAKE_SYSTEM_PREFIX_PATH.
- Introduced
- CMAKE_FIND_USE_INSTALL_PREFIX:
- Set to
trueto block searching an install prefix by default.
- Set to
- CMAKE_FIND_NO_INSTALL_PREFIX:
- Used in CMake 3.23 and earlier to similar effect, but with negated meaning.
- The newer
CMAKE_FIND_USE_INSTALL_PREFIXshould be preferred and overrides the older variable if both are defined.
-
-
HINTS and PATHS Overview:
-
Purpose: Allow projects to specify additional search paths for locating files and packages.
-
Difference between HINTS and PATHS:
- HINTS: Typically computed from dynamic variables or previously found locations.
- PATHS: Fixed locations, usually searched last and do not depend on other values.
-
Environment Variables in HINTS and PATHS:
- Supported by specifying the environment variable with
ENV, e.g.,PATHS ENV FooDirs. - Allows for platform-specific path separators: colon-separated on Unix, semicolon-separated on Windows.
- Supported by specifying the environment variable with
-
Skip Options and Search Customization:
- NO_..._PATH: Skip specific sets of locations.
- NO_DEFAULT_PATH: Limits search to only the specified HINTS and PATHS.
- Overrides any default behavior set by
CMAKE_FIND_USE_...variables.
-
PATH_SUFFIXES:
- Used to check additional subdirectories beneath each search location, expanding the total number of search locations.
-
Simplified Command Usage:
- For basic needs, projects might only need to specify a single file and a few paths (similar to using the PATHS option).
- Example of simplified command:
find_file(outVar name [path1 [path2...]]).
-
Enforcing Search Priorities:
-
Projects can prioritize specific paths by invoking
find_file()multiple times with different options. -
Subsequent searches skip if the file is found, controlled by cache variable settings.
-
Example for prioritized path:
find_file(FOO_HEADER foo.h PATHS /opt/foo/include NO_DEFAULT_PATH ) find_file(FOO_HEADER foo.h)
-
-
-
Handling Unfound Files and Errors:
-
If a file is not found, the result variable evaluates to false in an
if()expression. -
From CMake 3.18, the
REQUIREDoption simplifies error handling for unfound files:find_file(FOO_HEADER foo.h PATHS /opt/foo/include NO_DEFAULT_PATH ) find_file(FOO_HEADER foo.h REQUIRED)
-
25.1.1. Apple-specific Behavior (Skip)
25.1.2. Cross-compilation Controls
-
Complexity in Cross-Compiling:
- Cross-compiling setups typically use a distinct directory structure for the toolchain, separate from the host toolchain, to prioritize finding target platform-specific versions of files, programs, and libraries.
-
Search Locations and Variables:
CMAKE_FIND_ROOT_PATH: Allows re-rooting the set of search locations by prepending directories to each search location.CMAKE_SYSROOT: Acts as the system root directory in cross-compiling scenarios, affecting both the search locations and compilation flags.CMAKE_SYSROOT_COMPILEandCMAKE_SYSROOT_LINK(From CMake 3.9): Similar toCMAKE_SYSROOT, affecting the root for compiling and linking.- These variables are typically set in the toolchain file, not directly by the project.
-
Handling Non-Rooted Locations:
- Paths already under directories specified by
CMAKE_FIND_ROOT_PATH,CMAKE_SYSROOT,CMAKE_SYSROOT_COMPILE, orCMAKE_SYSROOT_LINKare not re-rooted. - Paths under
CMAKE_STAGING_PREFIXor starting with a~(indicating a user’s home directory) are also not re-rooted.
- Paths already under directories specified by
-
Search Order Control:
- CMAKE_FIND_ROOT_PATH_MODE_INCLUDE: Controls the default order of searching among re-rooted and non-rooted locations.
- Can be overridden per command call with options:
CMAKE_FIND_ROOT_PATH_BOTH,ONLY_CMAKE_FIND_ROOT_PATH, orNO_CMAKE_FIND_ROOT_PATH.
-
Reliability in Cross-Compiling Contexts:
- The
find_file()command provides only one location, which may not be reliable in scenarios supporting switching between device and simulator builds without re-running CMake. This could lead to discrepancies iffind_file()results depend on the build context.
- The
25.1.3. Validators
- Typically, the existence of a file is enough for it to be accepted as the found file. In more advanced scenarios, the file may need to pass other criteria for it to be accepted.
- Advanced File Validation in CMake 3.25+:
- VALIDATOR Keyword: Introduced to add a custom validation step to the file-finding process using
find_file(). - Validator Function Requirements:
- Must accept two arguments:
- Result Variable Name: The name of a result variable to be set in the calling scope.
- File Absolute Path: The absolute path to the candidate file.
- The file is accepted as found if the function does not set the result variable to false before returning.
- Must accept two arguments:
- VALIDATOR Keyword: Introduced to add a custom validation step to the file-finding process using
# Only accept files that define a version string
function(has_version result_var file)
file(STRINGS "${file}" version_line
REGEX "#define +THING_VERSION" LIMIT_COUNT 1
)
if(version_line STREQUAL "")
set(${result_var} FALSE PARENT_SCOPE)
endif()
endfunction()
find_file(THING_HEADER thing.h VALIDATOR has_version)
# Require a companion version file in the same directory
function(has_version_file result_var file)
cmake_path(GET file PARENT_PATH dir)
if(NOT EXISTS "${dir}/thing_version.h")
set(${result_var} FALSE PARENT_SCOPE)
endif()
endfunction()
find_file(THING_HEADER thing.h VALIDATOR has_version_file)
25.2. Finding Paths
- The
find_path()command provides this functionality and is identical tofind_file()in every way except that the directory of the file to be found is stored in the result variable
25.3. Finding Programs
- Differences Between
find_file()andfind_program():
-
Cache Variables (CMake-specific):
- find_file(): Appends
includeto each item inCMAKE_PREFIX_PATH. - find_program(): Appends
binandsbininstead ofinclude;CMAKE_LIBRARY_ARCHITECTUREhas no effect. - CMAKE_PROGRAM_PATH: Replaces
CMAKE_INCLUDE_PATH, used specifically byfind_program(). - CMAKE_APPBUNDLE_PATH: Replaces
CMAKE_FRAMEWORK_PATH, used by bothfind_program()andfind_package().
- find_file(): Appends
-
Environment Variables (System-specific):
- INCLUDE: Not applicable for
find_program(). - PATH: Items are checked directly without modification, consistent across all platforms.
- INCLUDE: Not applicable for
-
General Behavioral Differences:
NAMES_PER_DIROption: Added in CMake 3.4, reverses the search order to check each name at a specific location before moving to the next location.- Windows Specifics: Automatically checks for
.comand.exeextensions;.batand.cmdfiles are not searched automatically. - CMAKE_FIND_APPBUNDLE: Replaces
CMAKE_FIND_FRAMEWORKinfind_program(), controlling the search between app bundle and non-bundle paths on Apple platforms, targetingContents/MacOSsubdirectory within app bundles. - CMAKE_FIND_ROOT_PATH_MODE_PROGRAM: Replaces
CMAKE_FIND_ROOT_PATH_MODE_INCLUDEforfind_program(), usually set toNEVERin cross-compiling scenarios to prioritize host platform tools.
25.4. Finding Libraries
-
Library Finding Similarities and Differences in CMake:
find_library()is similar tofind_file()but includesNAMES_PER_DIRand behaves differently in specific areas like cache variables, environment variables, and general search behavior.
-
Cache Variables:
- Under
CMAKE_PREFIX_PATH,find_file()appends "include", whilefind_library()appends "lib". CMAKE_LIBRARY_PATHis used instead ofCMAKE_INCLUDE_PATHforfind_library().- Both use
CMAKE_LIBRARY_ARCHITECTUREsimilarly.
- Under
-
Environment Variables:
find_library()uses "LIB" environment variable instead of "INCLUDE".- On Windows, both commands use a complex logic involving "PATH", appending "lib" for libraries.
-
General Search Options:
NAMES_PER_DIRbehaves the same as infind_program(), effective in CMake 3.4 or later.CMAKE_FIND_FRAMEWORKsets search order between framework and non-framework paths; stores framework directory name in result if found.CMAKE_FIND_ROOT_PATH_MODE_LIBRARYreplacesCMAKE_FIND_ROOT_PATH_MODE_INCLUDEfor library searches, particularly affecting search paths on Apple platforms.
-
Platform-Specific Naming and Extensions:
- Library names usually prefixed with "lib" on Unix; Windows uses DLLs with associated import libraries.
find_library()abstracts most differences; however, may require overriding to prioritize static over shared libraries.
-
Techniques to Prioritize Static Libraries:
-
Simple example giving priority to static libraries on Linux but not on macOS or Windows:
# WARNING: Not robust! find_library(FOOBAR_LIBRARY NAMES libfoobar.a foobar) -
Robust method ensuring static library priority across all locations:
# Better, static library now has priority across all search locations find_library(FOOBAR_LIBRARY libfoobar.a) find_library(FOOBAR_LIBRARY foobar)
-
-
Handling Import Libraries on Windows with CMake 3.25 or Later:
-
Using
VALIDATORto distinguish static libraries from import libraries using Visual Studio'slibtool:function(is_import_lib result_var file) cmake_path(GET file FILENAME filename) string(TOLOWER "${filename}" filename_lower) string(REGEX REPLACE "\\.lib$" ".dll" dll_filename_lower "${filename_lower}") execute_process( COMMAND ${CMAKE_AR} /nologo /list "${file}" RESULT_VARIABLE result OUTPUT_VARIABLE output ERROR_VARIABLE errors ) string(TOLOWER "${output}" output_lower) if(result OR NOT errors STREQUAL "" OR NOT output_lower MATCHES "(^|\n|\\)${dll_filename_lower}(\n|$)") set(${result_var} FALSE PARENT_SCOPE) endif() endfunction()
-
-
Architecture-Specific Directory Search:
- Different platforms and distributions use various directories for 32-bit and 64-bit libraries.
- CMake properties like
FIND_LIBRARY_USE_LIB32_PATHS,FIND_LIBRARY_USE_LIB64_PATHS, andFIND_LIBRARY_USE_LIBX32_PATHShelp manage these searches. CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIXcan override default suffixes for specific project needs.
-
Special Considerations:
- When using CMake with Xcode, direct specification of linker flags without paths might be necessary due to the inability of
find_library()to differentiate between device and simulator libraries in cache.
- When using CMake with Xcode, direct specification of linker flags without paths might be necessary due to the inability of
25.5. Finding Packages
-
Package Discovery in CMake: CMake allows finding packages as a whole using the
find_package()command, catering to project needs for version numbers or feature support without manual integration of components. -
Definition Methods: Packages in CMake can be defined through two main methods:
- Module: Defined externally, often by CMake or the project itself, and can become outdated as the package evolves.
- Config: Defined within the package, aligns closely with
find_package()functionality, providing more up-to-date integration.
-
Package Elements: Both methods typically specify variables, imported targets, and possibly functions or macros, influencing how projects use the packages (e.g., specifying program locations, library paths).
-
Preference for Imported Targets: Newer definitions lean towards providing imported targets over variables for better robustness and integration with CMake’s features, especially transitive dependencies.
-
Version Handling:
find_package()can include a version argument specifying required minimum versions or exact matches, with newer CMake versions supporting version ranges to define upper and lower version limits. -
Optional and Mandatory Packages: Projects can declare packages as optional or mandatory using
REQUIRED. Messages regarding failures or discoveries can be controlled via theQUIEToption. -
Component Specification: Allows specifying which parts of a package are needed, with
COMPONENTSfor mandatory parts andOPTIONAL_COMPONENTSfor optional parts. Not all packages support component-based selection. -
Global Imported Targets: Recent CMake versions allow the use of the
GLOBALkeyword infind_package()to create global visibility for imported targets, enhancing consistency across different directory scopes. -
Search Mechanisms and Keywords: The
MODULEkeyword restricts searches to module packages, while the absence of it allows for config packages as well. Other keywords likeNO_POLICY_SCOPEandREGISTRY_VIEWprovide additional control and compatibility adjustments. -
Module and Config File Differences:
- Module Files: Typically located via
CMAKE_MODULE_PATHand responsible for locating the package, checking versions, and handling components. - Config Files: Located by default naming conventions (e.g.,
<packageName>Config.cmake), providing richer, more robust package details and supporting additional search customization through theCONFIGSoption.
- Module Files: Typically located via
-
Search Locations: CMake searches multiple potential directories for packages, with the ability to skip certain paths through specific NO_... keywords, reflecting a comprehensive approach to locate needed package components effectively.
<prefix>/
<prefix>/(cmake|CMake)/
<prefix>/<packageName>*/
<prefix>/<packageName>*/(cmake|CMake)/
<prefix>/<packageName>*/(cmake|CMake)/<packageName>*/
<prefix>/(lib/<arch>|lib*|share)/cmake/<packageName>*/
<prefix>/(lib/<arch>|lib*|share)/<packageName>*/
<prefix>/(lib/<arch>|lib*|share)/<packageName>*/(cmake|CMake)/
<prefix>/<packageName>*/(lib/<arch>|lib*|share)/cmake/<packageName>*/
<prefix>/<packageName>*/(lib/<arch>|lib*|share)/<packageName>*/
<prefix>/<packageName>*/(lib/<arch>|lib*|share)/<packageName>*/(cmake|CMake)/
- In the above,
<packageName>is treated case-insensitively and thelib/<arch>subdirectories are only searched ifCMAKE_LIBRARY_ARCHITECTUREis set. - The
lib*subdirectories represent a set of directories that may include lib64, lib32, libx32 and lib, the last of which is always checked. - If the
NAMESoption is given to find_package(), all of the above directories are checked for each name provided. - Most search locations can be disabled by adding the associated NO_… keyword
| Location | Skip Option |
|---|---|
| Package root variables | NO_PACKAGE_ROOT_PATH |
| Cache variables (CMake-specific) | NO_CMAKE_PATH |
| Environment variables (CMake-specific) | NO_CMAKE_ENVIRONMENT_PATH |
| Paths specified via the HINTS option | No skip |
| Environment variables (system-specific) | NO_SYSTEM_ENVIRONMENT_PATH |
| User package registry | NO_CMAKE_PACKAGE_REGISTRY |
| Cache variables (platform-specific) | NO_CMAKE_SYSTEM_PATH |
| System package registry | NO_CMAKE_SYSTEM_PACKAGE_REGISTRY |
| Paths specified via the PATHS option | No skip |
CMake Package Root Variables Overview
-
Package Root Variables (Use CMake >=3.12):
- Variables like
<packageName>_ROOTare used to specify search paths forfind_package()and related commands. - These paths are prioritized in the same manner as
CMAKE_PREFIX_PATH.
- Variables like
-
Usage:
- When a
find_package()command loads a module (e.g.,FindFoo.cmake), it uses<Foo_ROOT>and$ENV{Foo_ROOT}as initial search paths. - Nested modules inherit and prioritize these paths, enhancing search efficiency without manual path specification.
- When a
CMake Cache and Environment Variables
-
Cache Variables:
- Include
CMAKE_PREFIX_PATH,CMAKE_FRAMEWORK_PATH, andCMAKE_APPBUNDLE_PATH. - Directly represent package installation points without additional directory specifications.
- Include
-
Environment Variables:
CMAKE_PREFIX_PATH,CMAKE_INCLUDE_PATH,CMAKE_FRAMEWORK_PATHadhere to platform-specific path separators.<packageName>_DIRis checked before other path variables.
System and Platform-Specific Variables
-
System-Specific Variables:
- Supported system-specific variable is
PATH, used as a package install base point.
- Supported system-specific variable is
-
Platform-Specific Cache Variables:
- Include
CMAKE_SYSTEM_PREFIX_PATH,CMAKE_SYSTEM_FRAMEWORK_PATH, andCMAKE_SYSTEM_APPBUNDLE_PATH.
- Include
Additional Search Options
-
Package Registries:
- Provide alternative package discovery methods outside standard system locations.
-
Search Control Options:
NO_...options andPATH_SUFFIXESoffer controls over search locations.CMAKE_FIND_PACKAGE_SORT_DIRECTIONandCMAKE_FIND_PACKAGE_SORT_ORDERhelp in prioritizing package versions.
Advanced Usage
-
Caching and Config Files:
- Once a config file for a package is found, subsequent searches are accelerated by using
<packageName>_DIR. - If a newer package version is installed elsewhere, the cache may need updating to recognize this.
- Once a config file for a package is found, subsequent searches are accelerated by using
-
Disabling Package Discovery:
CMAKE_DISABLE_FIND_PACKAGE_<packageName>prevents discovery unlessREQUIREDis specified.CMAKE_REQUIRE_FIND_PACKAGE_<packageName>forces mandatory discovery of a package, influencing build process error handling.
25.5.1. Package Registries
-
Purpose:
- Simplify package discovery by allowing packages to be registered in a centralized location accessible by CMake without additional configuration.
-
Functionality:
- Supports referencing locations within standard system directories, custom directories, or build tree directories.
Creating and Managing Package Entries
-
Adding to Registry:
- Use
export(PACKAGE packageName)within CMakeLists.txt to add a package's build directory to the user package registry. - Ensures that the required config file is present in the directory; otherwise, the registry entry is removed if permissions allow.
- Use
-
Naming Conventions:
- Registry entries typically use the MD5 hash of the directory path to avoid name collisions.
-
Potential Issues:
- Exported locations can remain in the registry unintentionally, leading to unexpected behaviors in builds.
- May cause issues in continuous integration systems by inadvertently using outdated or incorrect build directories.
Disabling Export Command
-
Pre CMake 3.15 Behavior:
- By default,
export(PACKAGE)modifies the package registry unlessCMAKE_EXPORT_NO_PACKAGE_REGISTRYis set to true.
- By default,
-
Post CMake 3.15 Behavior:
- Introduces policy CMP0090; when set to NEW,
export(PACKAGE)requiresCMAKE_EXPORT_PACKAGE_REGISTRYset to true to modify the registry.
- Introduces policy CMP0090; when set to NEW,
Controlling Package Registry Usage
-
Legacy Variables:
CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRYandCMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRYcontrol the reading from user and system package registries, respectively.
-
Updated Variables (from CMake 3.16):
- Replaced by
CMAKE_FIND_USE_PACKAGE_REGISTRYandCMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRYfor more consistent behavior with other CMAKE_FIND_USE... variables.
- Replaced by
In practice: Underutilization
- Due to the manual effort required to manage entries and the limited automation support, package registries are infrequently used.
- Automatic registration/unregistration by package installers/uninstallers is conceptually straightforward but rarely implemented due to the complexity of varying installation methods.
25.5.2. FindPkgConfig
Limitations of Some Find Modules
- Outdated Modules: Some modules do not use modern CMake practices, such as creating imported targets, instead defining variables that projects must manage manually.
- Incompatibility: Modules may not be updated to accommodate the latest package releases, potentially leading to incorrect configurations.
Alternative: PkgConfig Support
- PkgConfig Module: Utilizes pkg-config for package information, which is typically more up-to-date as it is provided directly by the package.
- Automatic Target Creation: Imported targets can be created automatically, simplifying project configuration.
Implementation of PkgConfig in CMake
- FindPkgConfig Module:
- Locates the pkg-config executable and sets variables like
PKG_CONFIG_FOUNDandPKG_CONFIG_VERSION_STRING. - Functions such as
pkg_check_modules()andpkg_search_module()are used to find package details through pkg-config.
- Locates the pkg-config executable and sets variables like
Key Functions and Their Usage
pkg_check_modules(prefix
[REQUIRED] [QUIET]
[IMPORTED_TARGET [GLOBAL] ]
[NO_CMAKE_PATH]
[NO_CMAKE_ENVIRONMENT_PATH]
moduleSpec1 [moduleSpec2...]
)
pkg_search_module(prefix
[REQUIRED] [QUIET]
[IMPORTED_TARGET [GLOBAL] ]
[NO_CMAKE_PATH]
[NO_CMAKE_ENVIRONMENT_PATH]
moduleSpec1 [moduleSpec2...]
)
pkg_check_modules():- Checks all modules listed in its arguments and sets variables based on package details from .pc files.
pkg_search_module():- Stops searching after finding the first module that meets the criteria, setting variables for that specific module.
Advanced Options and Variables
- Imported Targets:
- From CMake 3.6, the
IMPORTED_TARGEToption allows the creation of an imported target with the namePkgConfig::<prefix>. GLOBALkeyword (CMake 3.13+) gives the imported targets global visibility.
- From CMake 3.6, the
- Variable Settings:
- Version requirements in module specifications can influence the search, e.g.,
name>=version. - Variables such as
YYY_VERSION,YYY_PREFIX,YYY_INCLUDEDIR, andYYY_LIBDIRare set based on .pc file data.
- Version requirements in module specifications can influence the search, e.g.,
Considerations and Best Practices
- CMake Version Compatibility:
- Ensure CMake 3.15 or later is used to avoid bugs in earlier versions, especially when using
pkg_get_variable()to extract specific .pc file variables.
- Ensure CMake 3.15 or later is used to avoid bugs in earlier versions, especially when using
- System-Specific Limitations:
- Some older systems may have outdated versions of pkg-config, affecting the functionality of the FindPkgConfig module.
Recommendations
- Prefer Imported Targets: When possible, use the
IMPORTED_TARGEToption to automate the handling of package details. - Version Management: Specify minimum required versions of CMake and pkg-config to avoid compatibility issues.
- System Compatibility Checks: Validate the version of pkg-config on older systems to ensure reliable operation of the FindPkgConfig functions.