gpt4 book ai didi

find_package()使用指南

转载 作者:撒哈拉 更新时间:2025-01-12 22:42:57 57 4
gpt4 key购买 nike

关于find_package()

在使用cmake引用第三方库(比如OpenCV)时,我们总是使用find_package()这个指令来实现对包的查找(比如find_package(OpenCV))。调用完后就可以使用一些似乎凭空出现的变量如${OpenCV_INCLUDE_DIRS}以及${OpenCV_LIBS},分别指示了OpenCV库的头文件路径以及各个库文件位置.

find_package(OpenCV)
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS})
# 这样就可以使用到OpenCV了

cmake官方文档对find_package()的解释是这样的:

find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
             [REQUIRED] [[COMPONENTS] [components...]]
             [OPTIONAL_COMPONENTS components...]
             [REGISTRY_VIEW  (64|32|64_32|32_64|HOST|TARGET|BOTH)]
             [GLOBAL]
             [NO_POLICY_SCOPE]
             [BYPASS_PROVIDER])

其中[]中的内容表示为可选项。下面我们来解释find_package()是如何工作的.

find_package()的工作原理

实际上,find_package(<PackageName>)运行时,会去指定路径查找一些名字为 。

Find<PackageName>.cmake 。

<PackageName>Config.cmake 。

<lowercasePackageName>-config.cmake 。

<lowercasePackageName>-config-version.cmake # 指定版本信息 。

<PackageName>ConfigVersion.cmake # 指定版本信息 。

的文件,注意这里的命名格式是非常的固定的,基本都是FindXXX.cmake或者XXXConfig.cmake。这些后缀为.cmake的文件本质上也是使用cmake语言编写的脚本文件,它们会定义一些变量,比如<PackageName>_INCLUDE_DIRS和<PackageName>_LIBS等。当find_package()找到这些文件时,会执行这些文件并将其中定义的变量引入到当前的cmake环境中.

对于搜索这些后缀为.cmake的文件,find_package()采用两种策略来实现 。

find_package()的模块模式

这里引用官方文档的解释:

在这种模式下,CMake 搜索名为Find<PackageName>.cmake的文件,首先在 CMAKE_MODULE_PATH 中列出的位置中查找,然后在 CMake 提供的 Find Modules 中查找安装。如果找到该文件,CMake 将读取并处理该文件。它负责查找包、检查版本并生成任何需要的消息。一些 Find 模块对版本控制提供有限支持或不支持;检查查找模块的文档.

一般来说,FindXXX.cmake并非为包所提供,大多数包提供的是更为严谨的XXXConfig.cmake,这将在后面说到。也就是说,FindXXX.cmake是一个较为简单的查找模块,大多为用户或者cmake本身自行编写或者提供。查找时,cmake会优先查找cmake环境变量的CMAKE_MODULE_PATH中的路径(这个变量默认为空),然后再查找cmake自带的Find Modules中的路径,这部分可以使用cmake --help-module-list查看cmake自带的模块列表,可以看到很多FindXXX.cmake文件.

或者对于一些轻量级的包,本身并不提供XXXConfig.cmake或者FindXXX.cmake,而是使用其他包管理器(比如package-config,使用后缀为.pc的文件来管理),若想使用find_package()引用这些包,就需要自行编写FindXXX.cmake文件。(当然也可以直接使用cmake中的pkg_check_modules()来引用这些包)。下面给出一个FindXXX.cmake的例子,引用的是ffmpeg这个包.

#FindFFMEPG.cmake
set(FFMPEG_SOURCE /home/ruby/ffmpeg_loc) #指定ffmpeg位置

set(FFMPEG_INCLUDE_DIRS ${FFMPEG_SOURCE}/include)
set(FFMPEG_LIBDIRS_DIRS ${FFMPEG_SOURCE}/lib)

find_library(FFMPEG_AVCODEC_LIBRARY avcodec ${FFMPEG_LIBDIRS_DIR})
find_library(FFMPEG_AVFORMAT_LIBRARY avformat ${FFMPEG_LIBDIRS_DIR})
find_library(FFMPEG_AVUTIL_LIBRARY avutil ${FFMPEG_LIBDIRS_DIR})
find_library(FFMPEG_SWSCALE_LIBRARY swscale ${FFMPEG_LIBDIRS_DIR})
find_library(FFMPEG_SWRESAMPLE_LIBRARY swresample ${FFMPEG_LIBDIRS_DIR})

set(FFMPEG_LIBS ${FFMPEG_AVCODEC_LIBRARY} ${FFMPEG_AVFORMAT_LIBRARY} ${FFMPEG_AVUTIL_LIBRARY} ${FFMPEG_SWSCALE_LIBRARY} ${FFMPEG_SWRESAMPLE_LIBRARY})

可以看到,我们做到工作无非是设置一些变量,这些变量指向了ffmpeg的头文件路径以及库文件路径,然后使用find_library()来查找对应的库文件.

在使用时,我们可以使用set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} /path/to/FindFFMPEG.cmake)来指定FindFFMPEG.cmake的位置,然后使用find_package(FFMPEG)来引用ffmpeg这个包,然后就可以使用${FFMPEG_INCLUDE_DIRS}和${FFMPEG_LIBS}了。若这个脚本就在当前目录下,可以直接使用set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR})来指定.

find_package()的配置模式

这里引用官方文档的解释:

在这种模式下,CMake 搜索名为“<lowercasePackageName>-config.cmake”或“<PackageName>Config.cmake”的文件。如果指定了版本详细信息,它还将查找``<lowercasePackageName>-config-version.cmake`` 或``<PackageName>ConfigVersion.cmake``(请参阅:ref:version selection 以了解如何将它们分开使用版本文件)。

在配置模式下,可以为该命令提供一个名称列表,以作为包名称进行搜索。 CMake 搜索配置和版本文件的位置比模块模式复杂得多。

配置和版本文件通常作为包的一部分安装,因此它们往往比查找模块更可靠。它们通常包含包内容的直接知识,因此不需要在配置或版本文件本身中进行搜索或试探。

对于大多数的第三方包,都会提供XXXConfig.cmake文件,这个文件会定义一些变量,比如XXX_INCLUDE_DIRS和XXX_LIBS/XXX_LIBRARIS等。当模块模式搜索不到时,自动切换到配置模式进行搜索。配置模式的搜索非常繁琐,会尽一切可能去搜索。有一些我也看不懂,这里挑几个比较易懂且常用的来说.

  • XXX_DIR指定的路径下搜索XXXConfig.cmake文件,XXX_DIR为变量或者环境变量,指定到配置文件所在路径
  • CMAKE_PREFIX_PATH指定的路径下搜索XXXConfig.cmake文件
  • 在环境变量PATH下搜索XXXConfig.cmake文件
  • .....

其中,第2和第3种方式提供了一种以前缀路径的方式来指定包的位置,当本级路径搜索不到时,cmake会将本级路径作为前缀去搜索该路径下其他文件中是否有配置文件。匹配规则如下:

image

其中的<prefix>或者<前缀>即为上述指定的根路径,以根路径为前缀,一直去搜索,直到找到配置文件为止。例如find_package(OpenCV),其中PATH指定有一个路径为/usr/lib/x86_64-linux-gnu/,查找时便会找 。

  • /usr/lib/x86_64-linux-gnu/
  • /usr/lib/x86_64-linux-gnu/cmake/
  • /usr/lib/x86_64-linux-gnu/OpenCV(opencv)/
  • /usr/lib/x86_64-linux-gnu/cmake/OpenCV(opencv)/ ....

等能匹配上的路径,注意,这里的<name>*中的name对应于find_package()中的参数,即find_package(OpenCV)中的OpenCV。但是在作为前缀路径时,name参数不区分大小写,且允许有后缀,如opencv4.5。规则中的|代表选其一,<arch>为系统架构,比如x86,64位架构下就会搜索/lib/x86_64-linux-gnu而arm64架构下则会搜索/lib/aarch64-linux-gnu等.

如何灵活使用?

对于自己写的FindXXX.cmake,在使用时用 。

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR})
# or不在本级目录
set(MY_FINDXXX "path/to/FindXXX.cmake")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${MY_FINDXXX})

对于三方库,可以直接用find_package() 。

find_package(OpenCV)

倘若找不到,可以用locate命令查找一下,然后手动指定路径 。

locate OpenCVConfig.cmake

然后将配置文件所在路径赋值给XXX_DIR 。

set(OpenCV_DIR /path/to/opencv)

对于有多个配置文件的项目(如Qt),使用CMAKE_PREFIX_PATH来指定路径 。

set(CMAKE_PREFIX_PATH /path/to/qt)

给出一个例子 进入到可以匹配到路径的路径,我这里是/home/ruby/Qt5.14.0/5.14.0/gcc_64,里面的格式为 。

也就是最好找到带有lib字眼或者cmake字眼的那一级目录即可,然后将这个路径赋值给CMAKE_PREFIX_PATH 。

set(CMAKE_PREFIX_PATH /home/ruby/Qt5.14.0/5.14.0/gcc_64)

即可。使用这个方法可以简便的使用不同版本的Qt,比如我这里有5.14.0和5.15.0两个版本,只需要将CMAKE_PREFIX_PATH指定到对应的路径即可.

set(CMAKE_PREFIX_PATH /home/ruby/Qt5.15.0/5.15.0/gcc_64)
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} /home/ruby/Qt5.14.0/5.14.0/gcc_64)
# 注意,这两个路径正常直接find是find不到的,只能加入CMAKE_PREFIX_PATH中

#find_package(Qt5 <version> COMPONENTS Core Widgets REQUIRED), version填版本号,如

find_package(Qt5 5.15.0 COMPONENTS Core Widgets REQUIRED)
# or
find_package(Qt5 5.14.0 COMPONENTS Core Widgets REQUIRED)
可以加入EXACT来精确匹配,当匹配不到时会报错
find_package(Qt5 5.14.0 EXACT COMPONENTS Core Widgets REQUIRED)

最后此篇关于find_package()使用指南的文章就讲到这里了,如果你想了解更多关于find_package()使用指南的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

57 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com