find_package()工作方式介绍

find_package()工作方式介绍

find_package()原理简介

图像相关的工程中,最常用的第三方包OpenCV需要通过CMakeLists来配置,常见写法如下:

find_package(OpenCV 4 REQUIRED)

include_directories(${OpenCV_INCLUDE_DIRS})

add_executable(main src/main.cpp)
target_link_libraries(main ${OpenCV_LIBRARIES})

上面的配置中,find_package从目录中寻找OpenCV,找到后将头文件目录设置为${OpenCV_INCLUDE_DIRS},库文件设为${OpenCV_LIBRARIES},然后在工程中包含OpenCV头文件目录,生成可执行文件,最后链接OpenCV库。

find_package()工作模式

find_package命令有两种工作模式,这两种工作模式的不同决定了其搜包路径的不同:

Module模式

find_package命令基础工作模式(Basic Signature),也是默认工作模式。
Module模式的参数为:

find_package(<package> [version] [EXACT] [QUIET] [MODULE]
             [REQUIRED] [[COMPONENTS] [components...]]
             [OPTIONAL_COMPONENTS components...]
             [NO_POLICY_SCOPE])

参数解释:
package:必填参数。需要查找的包名,注意大小写。

version和EXACT:可选参数,version指定的是版本,如果指定就必须检查找到的包的版本是否和version兼容。如果指定EXACT则表示必须完全匹配的版本而不是兼容版本就可以。

QUIET:可选参数,表示如果查找失败,不会在屏幕进行输出(但是如果指定了REQUIRED字段,则QUIET无效,仍然会输出查找失败提示语)。

MODULE:可选字段。前面提到说“如果Module模式查找失败则回退到Config模式进行查找”,但是假如加入了MODULE选项,那么就只在Module模式查找,如果Module模式下查找失败并不切换到Config模式查找。

REQUIRED:可选字段。表示一定要找到包,找不到的话就立即停掉整个CMake。而如果不指定REQUIRED则CMake会继续执行。

COMPONENTS,components:可选字段,表示查找的包中必须要找到的组件(components),如果有任何一个找不到就算失败,类似于REQUIRED,导致CMake停止执行。

Module模式下是要查找到名为Find<PackageName>.cmake的配置文件。

Module模式只有两个查找路径:CMAKE_MODULE_PATHCMake安装路径下的Modules目录,

搜索路径
搜包路径依次为:

CMAKE_MODULE_PATH
CMAKE_ROOT

先在CMAKE_MODULE_PATH变量对应的路径中查找。其中CMAKE_MODULE_PATH默认为空,可以利用set命令赋值。如果路径为空,或者路径中查找失败,则在CMake安装目录(即CMAKE_ROOT变量)下的Modules目录下(通常为/usr/share/cmake-3.10/Modules,3.10是我的CMake版本)查找。这两个变量可以在CMakeLists.txt文件中打印查看具体内容:

message(STATUS "CMAKE_MODULE_PATH = ${CMAKE_MODULE_PATH}")
message(STATUS "CMAKE_ROOT = ${CMAKE_ROOT}")

Config模式

find_package命令高级工作模式(Full Signature)。 只有在find_package()中指定CONFIG、NO_MODULE等关键字,或者Module模式查找失败后才会进入到Config模式。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uZT7Sh03-1650790402686)(./1650784514195.png)]

Config模式的完整命令参数为:

find_package(<package> [version] [EXACT] [QUIET]
             [REQUIRED] [[COMPONENTS] [components...]]
             [CONFIG|NO_MODULE]
             [NO_POLICY_SCOPE]
             [NAMES name1 [name2 ...]]
             [CONFIGS config1 [config2 ...]]
             [HINTS path1 [path2 ... ]]
             [PATHS path1 [path2 ... ]]
             [PATH_SUFFIXES suffix1 [suffix2 ...]]
             [NO_DEFAULT_PATH]
             [NO_CMAKE_ENVIRONMENT_PATH]
             [NO_CMAKE_PATH]
             [NO_SYSTEM_ENVIRONMENT_PATH]
             [NO_CMAKE_PACKAGE_REGISTRY]
             [NO_CMAKE_BUILDS_PATH] # Deprecated; does nothing.
             [NO_CMAKE_SYSTEM_PATH]
             [NO_CMAKE_SYSTEM_PACKAGE_REGISTRY]
             [CMAKE_FIND_ROOT_PATH_BOTH |
              ONLY_CMAKE_FIND_ROOT_PATH |
              NO_CMAKE_FIND_ROOT_PATH])

相比于Module模式,Config模式的参数更多,也更复杂,但实际在使用过程中我们并不会用到所有参数,大部分参数都是可选的,我们只需要掌握基本的参数用法即可。

其中具体查找库并给XXX_INCLUDE_DIRSXXX_LIBRARIES两个变量赋值的操作由XXXConfig.cmake模块完成。

两种模式看起来似乎差不多,不过CMake默认采取Module模式,如果Module模式未找到库,才会采取Config模式。如果XXX_DIR路径下找不到XXXConfig.cmake文件,则会找/usr/local/lib/cmake/XXX/中的XXXConfig.cmake文件。总之,Config模式是一个备选策略。通常,库安装时会拷贝一份XXXConfig.cmake到系统目录中,因此在没有显式指定搜索路径时也可以顺利找到。

搜索路径
Config模式下是要查找名为<PackageName>Config.cmake<lower-case-package-name>-config.cmake的模块文件。
Config模式需要查找的路径非常多,也要匹配很多的可能性。

具体查找顺序为:
1、名为<PackageName>_DIR的CMake变量或环境变量路径
默认为空。
这个路径是非根目录路径,需要指定到<PackageName>Config.cmake<lower-case-package-name>-config.cmake文件所在目录才能找到。
2、名为CMAKE_PREFIX_PATHCMAKE_FRAMEWORK_PATHCMAKE_APPBUNDLE_PATHCMake变量环境变量路径根目录,默认都为空。
注意如果你电脑中安装了ROS并配置好之后,你在终端执行echo $CMAKE_PREFIX_PATH会发现ROS会将CMAKE_PREFIX_PATH这个变量设置为ROS中的库的路径,意思是会首先查找ROS安装的库,如果恰好你在ROS中安装了OpenCV库,就会发现首先找到的是ROS中的OpenCV,而不是你自己安装到系统中的OpenCV。
3、PATH环境变量路径
根目录,默认为系统环境PATH环境变量值。
其实这个路径才是Config模式大部分情况下能够查找到安装到系统中各种库的原因。
这个路径的查找规则为:
遍历PATH环境变量中的各路径,如果该路径如果以bin或sbin结尾,则自动回退到上一级目录得到根目录。例如我的PATH路径包括:

$ echo $PATH
/home/zhanghm/.local/bin:/usr/local/cuda-10.1/bin:/opt/ros/melodic/bin:/home/zhanghm/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

在上述指明的是根目录路径时,CMake会首先检查这些根目录路径下是否有名为Config.cmake或-config.cmake的模块文件,如果没有,CMake会继续检查或匹配这些根目录下的以下路径(_DIR路径不是根目录路径):

<prefix>/(lib/<arch>|lib|share)/cmake/<name>*/
<prefix>/(lib/<arch>|lib|share)/<name>*/ 
<prefix>/(lib/<arch>|lib|share)/<name>*/(cmake|CMake)/

其中为系统架构名,如Ubuntu下一般为:/usr/lib/x86_64-linux-gnu,整个(lib/<arch>|lib|share)为可选路径,例如OpenCV库而言会检查或匹配<prefix>/OpenCV/,<prefix>/lib/x86_64-linuxnu/OpenCV/,
<prefix>/lib/share/OpenCV/<prefix>/share/OpenCV/等路径;name为包名,不区分大小写**< name >***意思是包名后接一些版本后等字符也是合法的,如pcl-1.9也会被找到。

设置find_package建议

上面的查找规则整体看起来好像很复杂,但其实我们在安装库的时候都会自动配置安装到对的位置,一般都不会出现问题。如果我们需要指定特定的库,我们也只需要设置优先级最高的几个变量名即可。包括下面两种情况:

1、如果你明确知道想要查找的库<PackageName>Config.cmake<lower-case-package-name>-config.cmake文件所在路径,为了能够准确定位到这个包,可以直接设置变量`_DIR为具体路径,如:

set(OpenCV_DIR "/home/zhanghm/Softwares/enviroment_config/opencv3_4_4/opencv/build")
就可以明确需要查找的OpenCV包的路径了。

2、如果你有多个包的配置文件需要查找,可以将这些配置文件都统一放在一个命名为cmake的文件夹下,然后设置变量CMAKE_PREFIX_PATH变量指向这个cmake文件夹路径,需要注意根据上述的匹配规则,此时每个包的配置文件需要单独放置在命名为包名的文件夹下(文件夹名不区分大小写),否则会提示找不到。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`find_package` 是 CMake 中用于查找和加载外部依赖库的命令。它会在系统中搜索指定名称的库,并自动配置编译选项。一般情况下,我们需要在 CMakeLists.txt 文件中使用 `find_package` 命令来查找我们需要的库,然后将它们链接到我们的项目中。 下面是使用 `find_package` 命令的一般步骤: 1. 在 CMakeLists.txt 文件中使用 `find_package` 命令,指定要查找的库的名称和版本。 例如,要查找 Boost 库,可以使用以下命令: ``` find_package(Boost 1.46 REQUIRED COMPONENTS system thread) ``` 2. 如果库没有被找到,可以通过设置 `CMAKE_PREFIX_PATH` 环境变量或者 `CMAKE_MODULE_PATH` 变量来指定库的安装路径或者 CMake 模块所在路径。 3. 如果找到了库,`find_package` 命令会自动定义一些变量,用于指定库的路径、头文件路径和库文件路径等信息。 例如,对于 Boost 库,`find_package` 命令会定义以下变量: ``` Boost_FOUND Boost_INCLUDE_DIRS Boost_LIBRARY_DIRS Boost_LIBRARIES ``` 4. 在项目中使用这些变量,例如: ``` include_directories(${Boost_INCLUDE_DIRS}) link_directories(${Boost_LIBRARY_DIRS}) target_link_libraries(my_target ${Boost_LIBRARIES}) ``` 这些变量包含了库的路径信息,可以用来编译和链接项目。 需要注意的是,`find_package` 命令只能用于已经被 CMake 支持的库。对于一些非常规的库,可能需要手动配置编译选项来使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值