背景
find_package应该算是我们使用最多的cmake命令了。但是它是如何找到上游库的.cmake
文件的?
根据官方文档,整理下find_package涉及到的搜索模式。
搜索模式
find_package涉及到的搜索模式有两种:模块模式(Module mode)和配置模式(Config mode)。
模块模式
在此模式下,CMake搜索名为Find<PackageName>.cmake
的文件,首先在CMAKE_MODULE_PATH
中列出的位置查找,然后在CMake安装提供的查找模块(Find moduls)
中查找。查找模块(Find moduls)的主要任务是确定软件包是否可用,设置<PackageName>_FOUND
变量以反映这一点,并提供使用该软件包所需的任何变量、宏和导入目标。在上游库未提供配置文件包的情况下,查找模块非常有用。
Find.cmake 文件通常不是由上游库本身提供的。我们发现在安装CMake时,会一并安装一些上游库的查找模块(Find modules)
。
以Ubuntu上的CMake为例,在/usr/share/cmake-3.22/Modules
目录下可以查看到CMake提供的查找模块(Find modules)
,仅列举部分文件。
FindALSA.cmake
FindBZip2.cmake
FindCUDA.cmake
FindCURL.cmake
FindGTK2.cmake
FindJPEG.cmake
FindLibXml2.cmake
FindOpenGL.cmake
FindOpenSSL.cmake
FindProtobuf.cmake
FindQt.cmake
FindRuby.cmake
FindSDL.cmake
FindSQLite3.cmake
FindVulkan.cmake
FindX11.cmake
由于这些查找模块(Find modules)
是由CMake维护的,所以有可能会过时。
我们可以使用CMAKE_MODULE_PATH
添加自定义的模块搜索路径。CMAKE_MODULE_PATH
的值默认为空,其自定义搜索路径的优先级比默认模块搜索路径高。
配置模式(Config mode)
在此模式下,CMake搜索名为<lowercasePackageName>-config.cmake
或<PackageName>Config.cmake
的文件。如果指定了版本详细信息,它还会查找<lowercasePackageName>-config-version.cmake
或<PackageName>ConfigVersion.cmake
。
配置和版本文件通常作为上游库安装文件的一部分,因此它们往往比查找模块(Find modules)
更可靠。
配置模式(Config mode)会搜索指定目录下的.cmake
文件。以Ubuntu系统为例,其搜索路径如下:
<prefix>/(lib/<arch>|lib*|share)/cmake/<name>*/
<prefix>/(lib/<arch>|lib*|share)/<name>*/
<prefix>/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/
<prefix>/<name>*/(lib/<arch>|lib*|share)/cmake/<name>*/
<prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/
<prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/
其中<prefix>
可通过变量CMAKE_PREFIX_PATH
设置。需要注意<name>
不区分大小写,并且对应于指定的<PackageName>
。
以Ubuntu系统上安装的ITK(Insight Toolkit)库为例,我们可以找到ITKConfig.cmake
和ITKConfigVersion.cmake
$ dpkg -L libinsighttoolkit5-dev | grep -i cmake
/usr/lib/cmake
/usr/lib/cmake/ITK-5.2
/usr/lib/cmake/ITK-5.2/ITKConfig.cmake
/usr/lib/cmake/ITK-5.2/ITKConfigVersion.cmake
...
典型用法
find_package的典型用法如下,是基本签名(basic signature)的一个简化形式。
find_package(<PackageName> [<version>] [REQUIRED] [COMPONENTS <components>...])
在这种典型用法下,命令首先在模块模式下搜索。如果未找到相应的Find<PackageName>.cmake
文件,则回退到配置模式继续搜索。
当然我们也可以通过显示设置MODULE
或是CONFIG
参数指定只使用模块模式或者配置模式。
find_package(<PackageName> [<version>] [CONFIG|MODULE] [REQUIRED] [COMPONENTS <components>...])
参考资料
- https://cmake.org/cmake/help/latest/command/find_package.html