zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C++-Cmake指令:find_package【用于查找包(通常是使用三方库)】【指定第三方库所在路径】

C++ 路径 指定 查找 指令 用于 Find 第三方
2023-09-27 14:20:39 时间

一、搜索模式

find_package用于查找包(通常是使用三方库),并返回关于包的细节(使用包所依赖的头文件、库文件、编译选项、链接选项等)

find_libaray直接在指定搜索目录下搜索库不同,find_package命令可以获取更多的信息,那么它的搜索方式也是与find_libaray不一样,它有两种不同的搜索方式,因此在介绍这个命令的细节之前,先简单介绍一下find_package命令的两种搜索模式:模块模式Module mode)和配置模式Config mode)。

1.1 模块模式(Module mode

在该模式下,Cmake会搜索一个名为Find<PackageName>.cmake的文件,其中<PackageName>为待搜索包的名称。

搜索路径的顺序依次是:

  • 从变量CMAKE_MODULE_PATH指定的路径中进行查找
  • Cmake安装路径中查找。Cmake会在其安装路径下提供很多.cmake文件,例如/XXX/cmake/Modules/目录下(不同的系统安装目录可能不一致)

如果找到文件Find<PackageName>.cmakeCmake会读取并处理该文件,简而言之,它负责检查一些条件(如版本号是否满足等)是否满足,并在找到包后,返回给调用者一些变量,用以获取包的详细信息。

一般来说,Find<PackageName>.cmake文件不是随包本身一起提供的,更多的是外部针对已有包的重新包装,例如操作系统、Cmake程序、甚至是调用find_package命令的工程针对已有的包提供针对该包的.cmake文件。

1.2 配置模式(Config mode

该模式下,CMake会搜索<lowercasePackageName>-config.cmake文件或<PackageName>Config.cmake文件。如果find_package命令中指定了具体的版本,也会搜索<lowercasePackageName>-config-version.cmake<PackageName>ConfigVersion.cmake文件,因此配置模式下通常会提供配置文件和版本文件(注意形式上要保持一致),并且作为包的一部分一起提供给使用者。

该模式下对.cmake文件的搜索路径的顺序比较复杂,具体见本文的4.1节。

.cmake后缀文件的作用是什么?

find_package的两种搜索模式都会按照一定规则从路径下搜索.cmake后缀的文件,两种模式下的.cmake文件作用都是为了给find_package命令的调用方返回有关包的信息(头文件路径、库文件路径、编译连接选项、版本信息等等)

二、命令格式

find_package命令有两种格式,基本命令格式完整命令格式

2.1 基本命令

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

几个重要的参数介绍:

  • PackageName:待查找包的名称。此外它还决定两种搜索模下的.cmake文件名称:例如模块模式下的名称为Find<PackageName>.cmake,而配置模式下为<lowercasePackageName>-config.cmake/<lowercasePackageName>-config-version.cmake
  • MODULE:该选项指定find_package命令只使用模块模式搜索方式查找。未指定该选项时,find_package会优先使用模块模式搜索,仍未找到包时,会切换成配置模式搜索。
  • version:待查找包的版本号要求,版本号为点分格式,由四个部分组成,每个部分都是一个数字,均为可选:major[.minor[.patch[.tweak]]],例如1.1.1.11.0、等。同样也可以指定版本范围(CMake 3.19及之后才支持),格式为:versionMin...[<]versionMaxversionMinversionMax均是major[.minor[.patch[.tweak]]]形式的版本号,默认情况下会包含这个指定区间两端的版本号,但如果指定了<,那么会排除掉versionMax,例如1.1.1.1...1.1.2.01.1.1.1...<1.1.2.0等。
  • EXACT:该选项要求待查找包的版本必须与指定的版本精确匹配,因此如果指定的是一个版本范围,不能使用该参数。
  • QUIET:禁止输出信息,正常情况当找到包时,CMake会打印一些信息,指定该选项时会禁止掉这些打印。例外是当同时指定QUIET时,如果找不到包,仍然会输出错误信息并终止执行过程。
  • REQUIRED:当未找到满足条件的包(例如版本号不匹配,或指定组件未找到等),会终止CMake的执行过程,并输出一条错误信息。如果未指定该选项,即使未找到满足条件的包,CMake的执行过程也会继续。
  • COMPONENTS:指定要查找的组件。通常一个包可能包含多个组件(可以理解为多个库,例如把C++的std看成一个包的概念,那么vector就是std下的其中一个组件),我们的工程可能会依赖包下的具体某个组件,因此可以通过这个选项来检测这些组件是否存在。通常的约定是,该选项后的组件应该都找到时才认为包找到,否则认为未找到满足条件的包。这个约束会依赖包的.cmake来实现,通过find_package命令传入的COMPONENTS可以通过<PackName>_FIND_COMPONENTS这个变量来获得。举个简单的例子:
    # mymathConfig.cmake,假定它位于./mymath/mymath目录下
    # 作用就是校验COMPONENTS是否是test,只有当COMPONENTS为空或者为test时,包mymath才会被找到
    
    message(${mymath_FIND_COMPONENTS}) # `find_package`命令的`COMPONENTS`传入的
    if(${mymath_FIND_COMPONENTS} STREQUAL "")
        message("Empty comps.")
        set(mymath_INCLUDE_DIR "/XXX/mymath")
        set(mymath_LIBRARY "/XXX/mymath/libmymath.a")
    else()
        foreach(comp ${mymath_FIND_COMPONENTS})
            if (comp MATCHES "test")
                message("Find comp test")
                set(mymath_INCLUDE_DIR "/XXX/mymath")
                set(mymath_LIBRARY "/XXX/mymath/libmymath.a")
            endif()
        endforeach()
    endif()
    # 顶层目录的CMakeLists.txt
    cmake_minimum_required(VERSION 3.10.2)
    project(find_package_test)
    find_package(mymath
        CONFIG
        REQUIRED
        COMPONENTS test
        PATHS ./mymath/mymath
    )
    
    if(mymath_FOUND)
        message("Find mymath: ${mymath_INCLUDE_DIR}; ${mymath_LIBRARY};")
    endif()
    # 执行cmake .
    cmake .
    
    # 输出为
    test
    Find comp test
    Find mymath: /XXX/mymath; /XXX/mymath/libmymath.a;

  • OPTIONAL_COMPONENTS:与COMPONENTS的区别是,不强制要求这些组件必须存在。不影响CMake的执行。

2.2 完整命令

find_package(<PackageName> [version] [EXACT] [QUIET]
  [REQUIRED] [[COMPONENTS] [components...]]
  [OPTIONAL_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_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_SYSTEM_PACKAGE_REGISTRY]
  [CMAKE_FIND_ROOT_PATH_BOTH |
  ONLY_CMAKE_FIND_ROOT_PATH |
  NO_CMAKE_FIND_ROOT_PATH])

这里介绍一下与基本命令有差异的地方:

  • CONFIG|NO_MODULE:这两个选项二选一即可,表示强制find_package命令使用配置模式搜索,忽略模块模式搜索。
  • NAMES:默认情况下find_package命令会查找名为<PackageName>的包。如果NAMES选项后指定了名称,则会使用这些名字来查找包而忽略<PackageName>参数。
  • PATHS/HINTS:配置模式下指定.cmake文件的搜索路径。
  • NO_XXX_PATH:配置模式下忽略指定的路径,具体的含义可以参考4.1.2节。



 

Cmake命令之find_package介绍 - 简书

Cmake中find_package命令的搜索模式之模块模式(Module mode) - 简书

 Cmake中find_package命令的搜索模式之配置模式(Config mode) - 简书