首页 > 其他分享 >find_package()使用指南

find_package()使用指南

时间:2025-01-12 21:10:35浏览次数:1  
标签:cmake FFMPEG package CMAKE PATH 使用指南 find

关于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_DIRSXXX_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-gnuarm64架构下则会搜索/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,里面的格式为
image

也就是最好找到带有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)

标签:cmake,FFMPEG,package,CMAKE,PATH,使用指南,find
From: https://www.cnblogs.com/CrescentWind/p/18667194

相关文章

  • Python时间序列分析工具Aeon使用指南
    Aeon 是一个专注于时间序列处理的开源Python库,其设计理念遵循scikit-learn的API风格,为数据科学家和研究人员提供了一套完整的时间序列分析工具。该项目保持活跃开发,截至2024年仍持续更新。Aeon提供了以下主要功能模块:时间序列分类-支持多种分类算法实现-包含基于间隔、字典......
  • 使用 GitHub Actions 构建 CosyVoice 项目的运行环境镜像并推送到阿里云容器镜像服务
    使用GitHubActions构建CosyVoice项目的运行环境镜像并推送到阿里云容器镜像服务和GitHubPackageRegistry概述本文介绍了如何使用GitHubActions构建CosyVoice项目的运行环境Docker镜像,并将其推送到阿里云容器镜像服务(ACR)和GitHubPackageRegistry。通过挂载本地......
  • cursor无限使用指南
    准备邮箱新邮箱每次用新邮箱都去各大邮箱网站注册一个新的邮箱google邮箱别名在原有邮箱的「local-part」后面添加「+任意字符」,就对应了google邮箱别名例如现在拥有一个google邮箱:tucaoB@gmail.com那么对应的别名邮箱可以是:tucaoB+1@gmail.com、tucaoB+2@gmail.com、t......
  • 《ESP32-S3使用指南—IDF版 V1.6》第一章 本书学习方法
    第一章本书学习方法1)实验平台:正点原子DNESP32S3开发板2)章节摘自【正点原子】ESP32-S3使用指南—IDF版V1.63)购买链接:https://detail.tmall.com/item.htm?&id=7684993426594)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/esp32/ATK-DNESP32S3.html5)正点......
  • Streamlit,Streamlit会话及使用指南,将Streamlit部署到云端,通过Streamlit实现聊天机
    Streamlit介绍Streamlit是一个开源的Python库,专为快速创建数据可视化Web应用而设计。它的核心优势在于能够将简单的Python脚本迅速转换成交互式的Web应用,从而使数据科学家和工程师能够以最少的前端开发投入分享他们的数据分析成果。我们本门课程使用Streamlit构建我们的实战项目......
  • PyQ5中findChild() 方法,为什么是none
    第一个代码是kimi生成的,调用findchild方法可以使用;第二个调用findchild是none,为什么?importsysfromPyQt5.QtWidgetsimportQApplication,QMainWindow,QLineEditclassMainWindow(QMainWindow):def__init__(self):super().__init__()self.setGeom......
  • Latex写作-Critical Package ctex Error: CTeX fontset `fandol‘ is unavailable in
     今天打算开始写我的大论文,打开模版,就看到报错:CriticalPackagectexError:CTeXfontset`fandol‘isunavailableincurrent。 报错原因:这个错误表明你正在使用的LaTeX编译器在尝试加载CTeX宏包时,无法找到名为 fandol 的CTeX字体集。fandol 是一种常用的中文T......
  • wx.showRedPackage
    wx.showRedPackage(Objectobject)基础库2.10.0开始支持,低版本需做兼容处理。以Promise风格调用:支持小程序插件:不支持微信Mac版:支持微信鸿蒙OS版:支持功能描述拉取h5领取红包封面页。获取参考红包封面地址参考微信红包封面开发平台。参数Objectobject......
  • find命令
    [root@localhost~]#find/demo-maxdepth1-name"*.txt"/demo/aaa.txt/demo/bbb.txt/demo/c.txt/demo/alex.txt/demo/sort.txt/demo/sort1.txt/demo/ip.txt/demo/luffy.txt/demo/1alex.txt/demo/2alex.txt/demo/3alex.txt/demo/4alex.txt/demo/5al......
  • IDEA maven生存期中package和插件中的jar有什么区别
    在IntelliJIDEA中使用Maven时,你可能会遇到两种类型的JAR文件:打包(package)过程中生成的JAR和Maven插件中的JAR。这两种JAR文件有不同的来源和用途:1.打包(Package)过程中生成的JAR这些JAR文件是由你的Maven项目构建过程中生成的。当你运行 mvnpackage 或......