find_package深度解析及实例应用

news2024/11/23 15:16:46

1. 检索模式

1.1 module模式

        在这个模式下会查找一个名为find.cmake的文件,首先去CMAKE_MODULE_PATH指定的路径下去查找,然后去cmake安装提供的查找模块中查找(安装cmake时生成的一些cmake文件)。找到之后会检查版本,生成一些需要的信息。

1.2 config模式

        在这个模式下会查找一个名为-config.cmake(<小写包名>-config.cmake)或者Config.cmake 的文件,如果指定了版本信息也会搜索名为-config-version.cmake 或者 ConfigVersion.cmake的文件。

1.2.1 搜索路径

        该模式搜索配置和版本文件的路径比module模式复杂的多:

        首先在CMAKE_FIND_PACKAGE_REDIRECTS_DIR指定的路径下查找。如果没有找到配置文件,则按照下面的逻辑进行查找:

        cmake会为包构建可能的前缀,然后再前缀目录下搜索多个可能的目录,cmake指定的安装目录肯定是构建的前缀之一。

        简单解释一下,prefix就是我们cmake编译的时候指定的安装路径(CMAKE_STAGING_PREFIX的路径)(cmake指定的安装目录肯定是搜索路径之一,还可能有其他可能的目录);

        <prefix>/<name>*/(lib/<arch>|lib*|share)/cmake/<name>*/就表示可能在/lib/cmake/或者/lib*/cmake/或者/share/cmake/目录下.

如果FIND_LIBRARY_USE_LIB64_PATHS被置为true,则lib64的路径将再64位平台上被搜索。

如果FIND_LIBRARY_USE_LIB32_PATHS被置为true,则lib32的路径将再32位平台上被搜索。

lib路径始终被搜索。

        使用以下步骤构建安装前缀集(搜索路径的prefix字段)。如果指定NO_DEFAULT_PATH,则启用所有NO_*选项:

        (1). _ROOT环境变量中指定的搜索路径,其中是要查找的包(find_package的第一个参数保留大小写)。如果传递了NO_PACKAGE_ROOT_PATH,或者将CMAKE_FIND_USE_PACKAGE_ROOT_PATH设置为FALSE,则可以跳过此操作。

        (2). 搜索cmake特定缓存变量中指定的路径。通过命令行-DVAR=value传递进来的路径,多个路径需要以分号隔开。包含

CMAKE_PFEFIX_PATH、

CMAKE_FRAMEWORK_PATH、

CMAKE_APPBUNDLE_PATH三个变量;

例如

        cmake -DCMAKE_PREFIX_PATH=/usr/local/lib;/lib。可以通过NO_CMAKE_PATH选项或将CMAKE_FIND_USE_CMAKE_PATH设置为FALSE来跳过

        (3). 搜索特定于cmake的环境变量中指定的路径。如果传递了NO_CMAKE_ENVIRONMENT_PATH,或者将CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH设置为FALSE,则可以跳过此操作:

<PackageName>_DIR

CMAKE_PREFIX_PATH

CMAKE_FRAMEWORK_PATH

CMAKE_APPBUNDLE_PATH

        (4). HINTS指定的路径或者标准系统环境变量指定的路径,例如:PATH,LD_LIBRARY_PATH;在~/.bashrc或者/etc/profile文件中指定

        (5). 搜索当前系统的平台文件中定义的cmake变量(就是当前系统定义的一些cmake相关的变量)

例如:

CMAKE_INSTALL_PREFIX

CMAKE_STAGING_PREFIX

        但是可以被传递NO_CMAKE_INSTALL_PREFIX或者CMAKE_FIND_USE_INSTALL_PREFIX设置为FALSE跳过。

        如果传递了NO_CMAKE_SYSTEM_PATH,或者将CMAKE_FIND_USE_CMAKE_SYSTEM_PATH设置为FALSE,则可以跳过所有这些位置:

CMAKE_SYSTEM_PREFIX_PATH

CMAKE_SYSTEM_FRAMEWORK_PATH

CMAKE_SYSTEM_APPBUNDLE_PATH

这些变量包含的路径一般是系统默认安装路径:/usr/local等。

        (6). PATHS指定的路径

1.2.2 版本配置文件

        当指定version参数,配置模式将仅会查找能兼容指定版本的包,如果指定了EXACT,则会查找精确匹配指定版本的包。

        CMake本身不会对版本号做任何转换,而是通过查找到包的版本校验文件(包自身提供的)<PackageName>ConfigVersion.cmake(或<PackageName>-config-version.cmake),调用版本配置文件做校验,版本配置文件可以通过CMakePackageConfigHelpers模块来辅助创建。

        当find_package命令中指定version参数后,会把version参数解析出来,赋值到PACKAGE_FIND_XXX中,定义了以下变量:

单一版本号:

PACKAGE_FIND_NAME:包名

PACKAGE_FIND_VERSION:全版本字符串

PACKAGE_FIND_VERSION_MAJOR:主版本号,如果未指定则为0

PACKAGE_FIND_VERSION_MINOR:次版本,如果未指定则为0

PACKAGE_FIND_VERSION_PATCH:补丁版本,如果未指定则为0

PACKAGE_FIND_VERSION_TWEAK:小版本,如果未指定则为0

PACKAGE_FIND_VERSION_COUNT:版本组成部分的数量,范围为0~4

范围版本号:

PACKAGE_FIND_VERSION_RANGE:全版本范围字符串

PACKAGE_FIND_VERSION_RANGE_MIN:表示是否包含低版本,当前只支持INCLUDE,也就是说必然会包含低版本

PACKAGE_FIND_VERSION_RANGE_MAX:表示是否包含高版本,当前支持INCLUDE和EXCLUDE

PACKAGE_FIND_VERSION_MIN:低版本的全版本字符串

PACKAGE_FIND_VERSION_MIN_MAJOR:低版本的主版本号,如果未指定则为0

PACKAGE_FIND_VERSION_MIN_MINOR:低版本的次版本号,如果未指定则为0

PACKAGE_FIND_VERSION_MIN_PATCH:低版本的补丁版本号,如果未指定则为0

PACKAGE_FIND_VERSION_MIN_TWEAK:低版本的小版本号,如果未指定则为0

PACKAGE_FIND_VERSION_MIN_COUNT:低版本组成部分的数量,范围为0~4

PACKAGE_FIND_VERSION_MAX:高版本的全版本字符串

PACKAGE_FIND_VERSION_MAX_MAJOR:高版本的主版本号,如果未指定则为0

PACKAGE_FIND_VERSION_MAX_MINOR:高版本的次版本号,如果未指定则为0

PACKAGE_FIND_VERSION_MAX_PATCH:高版本的补丁版本号,如果未指定则为0

PACKAGE_FIND_VERSION_MAX_TWEAK:高版本的小版本号,如果未指定则为0

PACKAGE_FIND_VERSION_MAX_COUNT:高版本组成部分的数量,范围为0~4

        当版本配置文件完成版本校验后,会设置命名如PACKAGE_VERSION_XXX的变量供find_package使用,具体的变量如下:

PACKAGE_VERSION:版本文件中提供的全版本字符串

PACKAGE_VERSION_EXACT:如果精确匹配,那么该变量为True

PACKAGE_VERSION_COMPATIBLE:如果版本兼容,那么该变量为True

PACKAGE_VERSION_UNSUITABLE:如果未找到合适的版本,该变量为True

        上面的PACKAGE_VERSION_XXX几个变量仅用于find_package命令检查配置文件是否提供了一个可接受的版本,一旦find_package命令返回后,这些变量就失效了。

如果版本校验通过,那么如下_VERSION_XXX变量会被设置,供find_package调用者使用:

_VERSION:包的全版本字符串

_VERSION_MAJOR:主版本

_VERSION_MINOR:此版本

_VERSION_PATCH:补丁版本

_VERSION_TWEAK:小版本

_VERSION_COUNT:点分版本组成的数量,范围0~4

2. 命令格式

2.1 基础命令

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])

module模式和config模式都支持该命令格式。

version:请求与该包兼容的版本。有两种可能的形式可以指定它:

(1):格式为major[.minor[.patch]的单一版本,例如:每个部分都是一个数字,均为可选:0.0.0.0或0.0.0或0.0.

(2):格式为versionMin…[<]versionMax,其中versionMin和versionMax具有与单个版本相同的格式和对整数组件的约束(例如:0.0.0.0...1.1.1.1)。默认情况下,包括两个端点。通过指定<,将排除上结束点。版本范围仅支持CMake 3.19或更高版本。

EXACT: 选项要求精确匹配版本。此选项与版本范围的规格不兼容(版本的第二种格式)。

MODULE:只是用module模式进行查找,不进行config模式查找,如果没指定的话,优先使用module模式搜索,如果未找到在进行config模式搜索。

QUIET:禁用信息消息。正常情况当找到包时,CMake会打印一些信息,指定该选项时会禁止掉这些打印。如果找不到包,仍然会输出错误信息并终止执行过程。

REQUIRED:当包没有被找到时,停止处理,及cmake停止继续运行。

COMPONENTS:指定要查找的组件列表,一般一个包可能有很多组件组成(例如一个库生成需要很多其他的依赖库),通常找到这些全部组件才认为包被找到。

OPTIONAL_COMPONENTS:指定要查找的组件列表,与COMPONENTS的区别是,不要求这些组件必须存在。不影响CMake的执行。

REGISTRY_VIEW:用于windows,在这不做考虑。

GLOBAL:将把所有导入的目标提升到导入项目中的全局作用域。可以通过设置CMAKE_FIND_PACKAGE_TARGETS_GLOBAL变量来启用此功能。

2.2 完整命令

find_package(<PackageName> [version] [EXACT] [QUIET]
             [REQUIRED] [[COMPONENTS] [components...]]
             [OPTIONAL_COMPONENTS components...]
             [CONFIG|NO_MODULE]
             [GLOBAL]
             [NO_POLICY_SCOPE]
             [BYPASS_PROVIDER]
             [NAMES name1 [name2 ...]]
             [CONFIGS config1 [config2 ...]]
             [HINTS path1 [path2 ... ]]
             [PATHS path1 [path2 ... ]]
             [REGISTRY_VIEW  (64|32|64_32|32_64|HOST|TARGET|BOTH)]
             [PATH_SUFFIXES suffix1 [suffix2 ...]]
             [NO_DEFAULT_PATH]
             [NO_PACKAGE_ROOT_PATH]
             [NO_CMAKE_PATH]
             [NO_CMAKE_ENVIRONMENT_PATH]
             [NO_SYSTEM_ENVIRONMENT_PATH]
             [NO_CMAKE_PACKAGE_REGISTRY]
             [NO_CMAKE_BUILDS_PATH] # Deprecated; does nothing.
             [NO_CMAKE_SYSTEM_PATH]
             [NO_CMAKE_INSTALL_PREFIX]
             [NO_CMAKE_SYSTEM_PACKAGE_REGISTRY]
             [CMAKE_FIND_ROOT_PATH_BOTH |
              ONLY_CMAKE_FIND_ROOT_PATH |
              NO_CMAKE_FIND_ROOT_PATH])

CONFIG/NO_MODULE:这两个选项二选一即可,表示强制find_package命令使用config模式搜索,忽略module模式搜索。

NAMES:默认情况下find_package命令会查找名为的包。如果NAMES指定了名称,则会使用这些名字来查找包而忽略参数。

PATHS/HINTS:config模式下指定.cmake文件的搜索路径。

NO_XXX_PATH:config模式下忽略指定的路径。

3. find_package实例用法

cmake引用外部自定义库的测试案例:

首先写个加法器,用于生成库文件供其他程序调用,在/home/findpack下创建三个文件:

add.c

#include "./include/add.h"

int add(int first, int second)
{
        int val = 0;
        val = first+second;

        return val;
}

add.h

#ifndef _ADD_H_
#define _ADD_H_

#include <stdio.h>

int add(int first, int second);

#endif

main.c

#include "add.h"

int main(void)
{
        int result = 0;

        result = add(1, 1);

        printf("result = %d\n", result);

        return 0;
}

执行:gcc -shared -fPIC -o libadd.so add.c 生成libadd.so库文件,在该目录下创建 include, lib两个文件,include用于存放add.h,lib用于存放libadd.so,此时当前目录结构如下:

add.c main.c include lib CMakeLists.txt

然后创建cmake目录,cmake目录下创建FindAdd.cmake文件,用于find_package函数查找,内容如下:

//CMAKE_SOURCE_DIR:CMakeLists.txt所在的目录
//在指定目录(${CMAKE_SOURCE_DIR}/include)下查找add.h文件,如果找到将路径返回给ADD_INCLUDE_DIR
find_path(ADD_INCLUDE_DIR add.h ${CMAKE_SOURCE_DIR}/include)
//在指定目录(${CMAKE_SOURCE_DIR}/lib)下查找add.h文件,如果找到将路径返回给ADD_LIBRARY,
//NAMES : 要查找的库名字,可以有多个
//PATHS:查找的路径,可以有多个
find_library(ADD_LIBRARY NAMES add PATHS ${CMAKE_SOURCE_DIR}/lib)

 //如果ADD_INCLUDE_DIR ADD_LIBRARY都有结果,设置ADD_FOUND为真,作为find_package的返回结果
if (ADD_INCLUDE_DIR AND ADD_LIBRARY)
    set(ADD_FOUND TRUE)
endif (ADD_INCLUDE_DIR AND ADD_LIBRARY)

然后返回我们上层目录,编辑我们的CMakeLists.txt:

cmake_minimum_required(VERSION 1.0)
project(TEST)
//指定find_package查找的路径,CMAKE_MODULE_PATH为module模式下邮箱查找的路径
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
add_executable(main main.c)
find_package(Add)

//如果查找完成,找到相应的库就进行头文件和库的引用
if(ADD_FOUND)
    target_include_directories(main PRIVATE ${ADD_INCLUDE_DIR})
    target_link_libraries(main ${ADD_LIBRARY})
endif(ADD_FOUND)

这个时候整个查找流程就完成了,创建build,进入该目录进行cmake编译,执行是没有问题的。

另外cmake有自带的内部依赖库,我们直接find_package(库名),即可;如果想要引用非内部库,例如grpc的库,需要将grpc使用cmake方式进行编译安装,然后find_package直接查找即可。

以上是find_package的module模式的测试方案,感兴趣的话也可以按照我上面的描述自己写一个config模式的查找测试方案。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/579792.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大模型全情投入,低代码也越来越清晰

众所周知&#xff0c;不少互联网企业在大模型领域全情投入。那么在这阵阵浪潮中&#xff0c;我们可以观察到什么样的“众生相”&#xff1f; 今年3月以来&#xff0c;国内已有超过20家企业入局大模型赛道。从百度“文心一言”、阿里“通义千问”的发布&#xff0c;华为“盘古”…

解决Kali的Python版本切换问题以及pip2安装问题

问题背景 需要使用Python2版本运行脚本&#xff0c;但是Kali系统自从2021后Python2&#xff0c;3共存 解决方案 &#xff08;1&#xff09;打开终端输入以下命令&#xff0c;但是需要有root权限 update-alternatives --install /usr/bin/python python /usr/bin/python2 100…

k8s介绍

目录 1&#xff1a;k8s概念 2&#xff1a;为什么引入k8s和k8s特性 2.1 为什么要引入k8s&#xff1a; 2.2 k8s特性 3 K8S架构 1&#xff1a;k8s概念 k8s官方网站&#xff1a;Kubernetes Kubernetes 是一个可移植、可扩展的开源平台&#xff0c;用于管理容器化的工作负载和…

数据库基础——5.运算符

这篇文章我们来讲一下SQL语句中的运算符操作。 说点题外话&#xff1a;SQL本质上也是一种计算机语言&#xff0c;和C&#xff0c;java一样的&#xff0c;只不过SQL是用来操作数据库的。在C&#xff0c;java中也有运算符&#xff0c;这两种语言中的运算符和数学中的运算符差距不…

【形形色色的卷积】差分卷积

文章目录 0. 前言1. 中心差分卷积2. 像素差分卷积3. 参考 0. 前言 普通卷积不能显式地提取图像的梯度信息&#xff0c;因此不能较好地描述细粒度的纹理信息&#xff0c;在人脸活体检测、边缘检测等对细粒度纹理信息敏感的任务中难以取得理想的结果。针对上述问题&#xff0c;O…

基于STM32的定时器--定时中断(HAL库)

基于STM32的定时器--定时中断&#xff08;HAL库&#xff09; 介绍引言定时器介绍 实例项目介绍准备设计流程 介绍 引言 本文旨在介绍如何使用STM32CubeMX配置KEIL 5开发一个每10us定时器中断触发一次的项目。帮助初学者入门STM32的定时器使用。 定时器介绍 定时器是STM32微…

2.信息安全之常用黑客攻击手段

1.自己也可以建CA系统 winserver2003 https 准备2台机器xpsp3(证书,Web),在同一网段,https通讯 –>网络内部网络(同一网段) (iso镜像才有网络和服务…这个镜像已 经安装好了(不能乱删)) sp1 2 3 的网络 改 tcp/ip 属性 ip地址112.26.0.1 和子网掩码255.0.0.0(与ip地址对应,…

opencv_c++学习(二十七)

一、单目相机模型 上图为针孔相机成像原理&#xff0c;蓝色坐标中的O即为镜头光心。成像原理与小孔成像相同。 单目相机映射关系如下&#xff1a; 将上式进行变换&#xff0c;就可以从三位空间映射到2维平面的公式。 相机的畸变公式如下&#xff1a; 二、模型投影函数 vo…

数据结构基础内容-----第五章 串

文章目录 串串的比较串的抽象数据类型串的顺序存储结构朴素的额模式匹配算法kmp模式匹配算法 串 在计算机编程中&#xff0c;串&#xff08;String&#xff09;是指由零个或多个字符组成的有限序列。它是一种基本的数据类型&#xff0c;在许多编程语言中都得到了支持和广泛应用…

STM32之SPI和W25Q128

目录 SPI 介绍 SPI 物理架构 SPI 工作原理 SPI 工作模式 W25Q128 介绍 W25Q128 存储架构 W25Q128 常用指令 W25Q128 状态寄存器 W25Q128 常见操作流程 实验&#xff1a;使用 SPI 通讯读写 W25Q128 模块 硬件接线 cubeMX配置 w25q128_write_nocheck流程图 代码&a…

如何在华为OD机试中获得满分?Java实现【最长回文子串】一文详解!

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: Java华为OD机试真题&#xff08;2022&2023) 文章目录 1. 题目描述2. 输入描述3. 输出描述…

网络原理(八):HTTPS

目录 HTTP 基本工作流程 利用对称密钥进行加密 利用非对称密钥进行加密 引入了第三方权威机构加密 之前在http 协议中说到&#xff1a;我们现在很少有网站直接使用HTTP 协议的&#xff0c;而是使用HTTPS &#xff0c;至于什么原因&#xff0c;本篇会介绍清楚。 HTTPS 其实…

C++11 -- lambda表达式

文章目录 lamaba表达式的引入lambda表达式语法lamabda达式各部分说明捕获列表说明 lamaba表达式底层原理探索 lamaba表达式的引入 在C11之前,如果我们想对自定义类型Goods排序,可以根据姓名,价格,学号按照从大到小或者从小到大的方式排序,可是,这样我们要写额外写6个相关的仿函…

以太坊学习三: Merkle树和验证

Merkle tree简介 Merkle树又称为哈希树&#xff0c;是一种二叉树&#xff0c;由一个根节点、若干中间节点和一组叶节点组成。最底层的叶节点存储数据&#xff0c;在它之上的一层节点为它们对应的Hash值&#xff0c;中间节点是它下面两个子节点的Hash值&#xff0c;根节点是最后…

DAY 66 数据库缓存服务——NoSQL之Redis配置与优化

缓存概念 缓存是为了调节速度不一致的两个或多个不同的物质的速度&#xff0c;在中间对速度较慢的一方起到加速作用&#xff0c;比如CPU的一级、二级缓存是保存了CPU最近经常访问的数据&#xff0c;内存是保存CPU经常访问硬盘的数据&#xff0c;而且硬盘也有大小不一的缓存&am…

爆肝整理,最全单元测试-测试用例总结(全覆盖)及拿即用...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Python自动化测试&…

Maven私服仓库配置-Nexus详解

目录 一、什么是Maven私服&#xff1f;二、Maven 私服优势三、Maven 私服搭建四、Sonatype Nexus介绍五、Nexus仓库属性和分类六、Nexus仓库配置以及创建仓库七、Nexus配置用户角色八、Maven SNAPSHOT(快照)九、项目当中配置Nexus上传依赖十、项目当中配置Nexus下载依赖十一、测…

人工智能基础部分20-生成对抗网络(GAN)的实现应用

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能基础部分20-生成对抗网络(GAN)的实现应用。生成对抗网络是一种由深度学习模型构成的神经网络系统&#xff0c;由一个生成器和一个判别器相互博弈来提升模型的能力。本文将从以下几个方面进行阐述&#xff1…

flutter_学习记录_03_通过事件打开侧边栏

实现类似这样的侧边栏的效果&#xff1a; 可以用Drawer来实现。 1. 在Scaffold组件下设置endDrawer属性 代码如下&#xff1a; import package:flutter/material.dart;class ProductListPage extends StatefulWidget {ProductListPage( {super.key}) ;overrideState<Pro…

首发Yolov8优化:Adam该换了!斯坦福最新Sophia优化器,比Adam快2倍 | 2023.5月斯坦福最新成果

1.Sophia优化器介绍 斯坦福2023.5月发表的最新研究成果,他们提出了「一种叫Sophia的优化器,相比Adam,它在LLM上能够快2倍,可以大幅降低训练成本」。 论文:https://arxiv.org/pdf/2305.14342.pdf 本文介绍了一种新的模型预训练优化器:Sophia(Second-order Clippe…