精华内容
下载资源
问答
  • CMake: find_package

    2020-09-21 22:56:27
    CMake: find_package基本标志与模块模式全部标志与配置模式版本选择查找过程包文件接口变量参考 ***查找外部项目, 并记载它的设置。 *** 基本标志与模块模式 find_package(<PackageName> [version] [EXACT] ...

    查找外部项目, 并加载它的设置

    基本标志与模块模式

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

    执行该命令之后, 可以通过查询混_Found这个变量来确定是否找到的对应的包。QUIET选项的设置可以用来关闭相关消息的输出, 包括非必须包未能找到的消息。REQUIRED选项设置后,当所查找的包未能找到之后会输出一个错误信息并终止处理过程。指定包所需的特定部件的列表可以跟在COMPONENTS之后。额外的可选部件列表可以跟在OPTIONAL_COMPONENTS后面。

    [version] 给出了所找包的版本兼容性要求。版本一般的格式是:major[.minor[.patch[.tweak]]]。 其中major是一个大版本,这种版本变化一般伴随着API的修改之类的变化,可能会存在一些兼容性问题;minor一般是指API增加一类的修改;path通常指的是功能实现、函数实现方式的修改之类的。选项EXACT 指明了版本必须精确匹配。

    这个命令用来搜索包有两个模式:模块模式(Module)和配置模式(Config)。默认模式是模块模式,如果在模块模式下没有找到包,则该命令会自动切换到配置模式下进行包的搜索, 可以通过设置标志CMAKE_FIND_PACKAGE_PREFER_CONFIG来确定优先使用Config模式。如果指定了搜索模式,则不会发生这种自动切换模式的搜索策略。在Module模式下,CMake会去搜索一个名为Find.cmake的文件。这个文件会先在CMAKE_MODULE_PATH下搜索, 然后再在CMake安装路径下的Find Module下搜索。如果找到了对应的文件,它会被读取并进行处理。 处理过程中包括查找相应的文件、核验版本和生成所需的信息。

    全部标志与配置模式

    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模式下指定了[version]参数的时候, 只会寻找与给定版本需求相兼容的包。如果EXACT选项给出了,则表明只查找确定版本的包, 而不是兼容包。CMake没有建立版本号的协议,包的版本号校验需要利用包中的版本文件来进行校验。对于一个候选包的配置文件.cmake, 对应的版本文件存在与之同样的位置,名字通常为-version.cmake 或者Version.cmake。 如果没有这样的版本文件,则认为该包不与任何版本兼容。一个基本的版本文件可以使用CMakePackageConfigHelpers模块来进行生成。当一个版本文件被找到之后,则会被加载以用来进行版本校验。版本文件被加载进入一个内嵌的作用域内,其内定义了一些变量。

    变量描述
    PACKAGE_FIND_NAMEPackageName
    PACKAGE_FIND_VERSIONfull requested version string
    PACKAGE_FIND_VERSION_MAJORmajor version if requested, else 0
    PACKAGE_FIND_VERSION_MINORminor version if requested, else 0
    PACKAGE_FIND_VERSION_PATCHpatch version if requested, else 0
    PACKAGE_FIND_VERSION_TWEAKtweak version if requested, else 0
    PACKAGE_FIND_VERSION_COUNTnumber of version components, 0 to 4

    版本文件经过核验之后,如果满足了相应的版本要求则会设置以下几个变量。

    变量描述
    PACKAGE_VERSIONfull provided version string
    PACKAGE_VERSION_EXACTtrue if version is exact match
    PACKAGE_VERSION_COMPATIBLEtrue if version is compatible
    PACKAGE_VERSION_UNSUITABLEtrue if unsuitable as any version

    以下几个变量会被find_package命令进行校验,并决定配置文件是否提供了一个可以接受的版本。如果包满足需求,则以下几个变量会被设置且配置文件会被加载。当多个包的配置文件是可用且未指明具体那个包被选择的时候:除非设置了变量CMAKE_FIND_PACKAGE_SORT_ORDER, 则会选择一个最高或者最相近的版本。

    变量描述
    _VERSIONfull requested version string
    _VERSION_MAJORmajor version if requested, else 0
    _VERSION_MINORminor version if requested, else 0
    _VERSION_PATCHpatch version if requested, else 0
    _VERSION_TWEAKtweak version if requested, else 0
    _VERSION_COUNTnumber of version components, 0 to 4

    为了控制find_package命令校验包的兼容性顺序,会用到两个变量:CMAKE_FIND_PACKAGE_SORT_ORDER 和 CMAKE_FIND_PACKAGE_SORT_DIRECTION。例如,如果需要选定最高版本的兼容包,可以在使用find_package命令之前这样设置:

    SET(CMAKE_FIND_PACKAGE_SORT_ORDER  NATURAL)
    SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
    

    查找过程

    CMake构建了一组可能的包安装路径前缀。在每个前缀路径之下,含有多个目录可以用来搜索配置文件。下表列出了一些可以搜索的文件夹。每个条目都对应各自可能的系统环境(W:windows, U:UNIX; A:Apple)。

    路径系统
    <prefix>/(W)
    <prefix>/(cmake|CMake)/(W)
    <prefix>/<name>*/(W)
    <prefix>/<name>*/(cmake|CMake)/(W)
    <prefix>/(lib/<arch>|lib*|share)/cmake/<name>*/(U)
    <prefix>/(lib/<arch>|lib*|share)/<name>*/(U)
    <prefix>/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/(U)
    <prefix>/<name>*/(lib/<arch>|lib*|share)/cmake/<name>*/(W/U)
    <prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/(W/U)
    <prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/(W/U)

    在上述表中,是大小写敏感的并对应于任意的或者NAEMS所指定的名称。
    如果CMAKE_LIBRARY_ARCHITECTURE变量被设置后, lib/这个路径可以被使用。lib* 包括了一个或者多个值,如lib64, lib32, libx32, 或者lib。其中:

    • lib64:如果FIND_LIBRARY_USE_LIB64_PATH属性被设置为TRUE时, 会在64位平台的该路径下搜索的库;
    • lib32:如果FIND_LIBRARY_USE_LIB32_PATH属性被设置为TRUE时, 会在32位平台的该路径下搜索的库;
    • libx32:如果FIND_LIBRARY_USE_LIBX32_PATHS属性被设置为TRUE时, 会在使用x32 ABI 的平台该路径下搜索库;
    • lib: 这个路径使用会被搜索。

    如果PATH_SUFFIXES被设定了,这这些后缀会在上标中每个条目的后面进行一一追加。

    这一组安装前缀是通过以下步骤进行构建起来的。如果NO_DEFAULT_PATH被指定,那么所有的NO_* 选项将会被激活。

    1. 搜索路径是被CMake变量或者系统环境变量_ROOT 所指定了包的查找路径。包的根目录变量被保存为堆栈,所以在一个查找模块中调用,那么其父查找模块中的路径也会被搜索。通过传递参数CMAKE_PACKAGE_ROOT_PACKAGE或者设置CMAKE_FIND_PACKAGE_ROOT_PATH为FALSE来跳过这个查找。
    2. 搜索路径在CMAKE缓存变量中被指定。这种设计可以在命令行中添加-DVAR=value来进行。可以被设置的缓存变量有:CMAKE_PREFIX_PATH、CMAKE_FRAMEWORK_PATH、CMAKE_APPBUNDLE_PATH。
    3. 搜索路径可以通过cmake指定的系统环境变量中进行设置。这种设计可以使得用户可以在shell文件中进行设置。设定的环境变量有:<PackageName>_DIR、CMAKE_PREFIX_PATH、CMAKE_FRAMEWORK_PATH、CMAKE_APPBUNDLE_PATH。
    4. 所有路径通过HINTS选项指定。此时可以通过其已经找到的库的路径来进行计算提示。如果采用硬编码的方式指定路径,可以参考使用PATHS选项来进行设置。
    5. 搜索标准的系统环境变量。如果传递了参数NO_SYSTEM_ENVIRONMENT_PATH或者将变量CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH设置为FALSE时,这步将会跳过不执行。含有/bin或者/sbin关键项目结尾的路径将会自动转换为其父目录。
    6. 搜索通过CMAKE User Package Registry 进行存储的路径。这一步可以通过已经方式进行跳过:传递参数NO_CMAKE_PACKAGE_REGISTRY; 设置变量CMAKE_FIND_USE_PACKAGE_REGISTRY为FALSE; 设置变量CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY为TRUE。
    7. 搜索当前系统平台文件中所定义的cmake变量:CMAKE_SYSTEM_PREFIX_PATH、CMAKE_SYSTEM_FRAMEWORK_PATH、CMAKE_SYSTEM_APPBUNDLE_PATH。这一步可以通过传递参数NO_CMAKE_SYSTEM_PATH或者设置变量CMAKE_FIND_USE_CMAKE_SYSTEM_PATH为FALSE。
    8. 搜索通过CMAKE System Package Registry 存储的路径。这一步可以通过已经方式进行跳过:传递参数NO_CMAKE_SYSTEM_PACKAGE_REGISTRY; 设置变量CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY为FALSE; 设置变量CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY为TRUE。
    9. 搜索通过PATH选项设置的路径。这一步主要用于硬编码。

    CMake 变量CMAKE_FIND_ROOT_PATH指定了一个或者多个目录, 则会预置多个其他的搜索目录(这里应该是将这个变量作为上述表格中的prefix)。默认情况是这个变量值是空的。
    变量CMAKE_SYSROOT也可以被用来指明一个目录作为prefix。 设置CMAKE_SYSROOT同时也会带来其他影响。
    这些变量在跨平台编译时指定目标环境根目录的时候非常有用。默认情况下是先搜索CMAKE_FIND_ROOT_PATH,然后再搜索CMAKE_SYSROOT目录,最后是搜索非根目录。这种默认的行为可以通过设CMAKE_FIND_ROOT_PATH_MODE_PACKAGE来进行调整。通过手动设置下列选项可以进行调整:

    变量功能
    CMAKE_FIND_ROOT_PATH_BOTHSearch in the order described above
    NO_CMAKE_FIND_ROOT_PATHDo not use the CMAKE_FIND_ROOT_PATH variable
    ONLY_CMAKE_FIND_ROOT_PATHSearch only the re-rooted directories and directories below CMAKE_STAGING_PREFIX

    大多数情况下默认的搜索路径设计一般是从细到宽的设计。项目可以重写顺序通过多次调用带有NO_*的命令。

    find_package (<PackageName> PATHS paths... NO_DEFAULT_PATH)
    find_package (<PackageName>)
    

    一旦某个调用成功了则会对相应的变量进行设置并存储在缓存中,之后的调用则不会再进行搜索。

    参考

    [1] CMake 官方文档
    [2] find_package与CMake如何查找链接库详解

    展开全文
  • 简单的find_package的示例, 一、目录结构如下: 二、代码文件&安装目录: 1、lib目录: demo.h: #include <iostream> #include <string> namespace test{ std::string run(); } demo...

    简单的find_package Module模式示例,通过Findxxx.cmake查找依赖库的安装信息。

    一、目录结构如下:

                                          

    二、代码文件&安装目录:

    1、lib目录:

    demo.h:

    #include <iostream>
    #include <string>
    
    namespace test{
    
        std::string run();
    
    }

    demo.cpp:

    #include "demo.h"
    
    namespace test{
    
        std::string run()
        {
            return "find_package_demo";
        }
    }
    

    CMakeLists.txt:

    cmake_minimum_required( VERSION 3.8 FATAL_ERROR)
    project(demo VERSION 1.0.0 LANGUAGES CXX)
    SET(CMAKE_EXPORT_COMPILE_COMMANDS ON)
    
    set(PROJECT_ROOT ${CMAKE_CURRENT_LIST_DIR}/..)
    set(CMAKE_INSTALL_PREFIX ${PROJECT_ROOT}/install/)#安装目录
    
    #set compile flags
    #add_definitions(-std=c++11 -g -rdynamic)
    set(CMAKE_CXX_FLAGS "-g3 -rdynamic -std=c++11")
    set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fsanitize=address -fno-omit-frame-pointer -fsanitize=leak")
    set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
    
    
    SET(BIN_DESTINATION ${PROJECT_SOURCE_DIR}/bin)
    SET(INSTALL_DESTION ${PROJECT_SOURCE_DIR}/install)
    SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BIN_DESTINATION})
    SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BIN_DESTINATION})
    SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BIN_DESTINATION})
    
    #include dirs
    include_directories(./)
    
    #libraries
    SET(SRC demo.cpp)
    add_library(demo SHARED ${SRC})
    SET_TARGET_PROPERTIES(demo PROPERTIES VERSION ${PROJECT_VERSION}) 
    SET_TARGET_PROPERTIES(demo PROPERTIES PUBLIC_HEADER ${CMAKE_CURRENT_LIST_DIR}/demo.h)
    
    install(TARGETS demo
        EXPORT  demo
        LIBRARY DESTINATION lib  # 动态库安装路径
        ARCHIVE DESTINATION lib  # 静态库安装路径
        RUNTIME DESTINATION bin  # 可执行文件安装路径
        PUBLIC_HEADER DESTINATION include  # 头文件安装路径
        )
    

    2、main目录

    main.cpp:

    #include <iostream>
    #include <string>
    
    #include "demo.h"
    
    using namespace std;
    
    int main(int argc,char *argv[])
    {
        cout<<"main..."<<endl;
        cout<<test::run()<<endl;
        cout<<"exit."<<endl;
        return 0;
    }

    CMakeLists.txt:

    cmake_minimum_required( VERSION 3.8 FATAL_ERROR)
    project(main VERSION 1.0.0 LANGUAGES CXX)
    SET(CMAKE_EXPORT_COMPILE_COMMANDS ON)
    
    set(PROJECT_ROOT ${CMAKE_CURRENT_LIST_DIR}/..)
    message(${PROJECT_ROOT})
    set(CMAKE_INSTALL_PREFIX ${PROJECT_ROOT}/install/)
    
    #set compile flags
    #add_definitions(-std=c++11 -g -rdynamic)
    set(CMAKE_CXX_FLAGS "-g3 -rdynamic -std=c++11")
    set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fsanitize=address -fno-omit-frame-pointer -fsanitize=leak")
    set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
    
    #set dirs
    SET(BIN_DESTINATION ${PROJECT_SOURCE_DIR}/bin)
    SET(INSTALL_DESTION ${PROJECT_SOURCE_DIR}/install)
    SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BIN_DESTINATION})
    SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BIN_DESTINATION})
    SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BIN_DESTINATION})
    
    
    #设置查找Finddemo.cmake的路径
    set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_LIST_DIR}/cmake/)
    message("cmake_module_path:${CMAKE_MODULE_PATH}")
    
    #使用find_package查找demo(这里会从CMAKE_MODULE_PATH设置的路径中查找)
    find_package(demo REQUIRED MODULE)
    
    #如果找到了(demo_FOUND会被设置为True,是一种约定,你也可以使用自己喜欢的变量<但是不建议这么做>)
    if (demo_FOUND)
        #打印相关的信息
        message("demo_FOUND:${demo_FOUND}")
        message("demo_version:${demo_VERSION}")
        message("demo_include:${demo_INCLUDE_DIR}")
        message("demo_library:${demo_LIBRARY}")
    endif()
    
    #include dirs
    include_directories(./ ${demo_INCLUDE_DIR}) #把demo.h所在的路径demo_INCLUDE_DIR添加到include dir中(Finddemo.cmake已经设置了demo_INCLUDE_DIR变量)
    #link dirs
    link_directories(${BIN_DESTINATION})
    
    #execute 
    SET(SRC_MAIN main.cpp)
    add_executable( ${PROJECT_NAME} ${SRC_MAIN})
    SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION}) 
    target_link_libraries(${PROJECT_NAME} ${demo_LIBRARY}) #链接libdemo.so(Finddemo.cmake设置了demo_LIBRARY变量)
    
    install(TARGETS main
        EXPORT  main
        LIBRARY DESTINATION lib  # 动态库安装路径
        ARCHIVE DESTINATION lib  # 静态库安装路径
        RUNTIME DESTINATION bin  # 可执行文件安装路径
        PUBLIC_HEADER DESTINATION include  # 头文件安装路径
        )
    
    

    cmake目录:

    Finddemo.cmake文件

    message("now using Finddemo.cmake find demo lib")
    
    #find demo.h
    FIND_PATH(demo_INCLUDE_DIR demo.h 
        /usr/include/demo/ 
        /usr/local/demo/include/ 
        ~/work/demo/find_package_simple/install/include/)
    
    message("include_dir: ${demo_INCLUDE_DIR}")
    
    #find libdemo.so
    FIND_LIBRARY(demo_LIBRARY libdemo.so 
        /usr/local/demo/lib/ 
        ~/work/demo/find_package_simple/install/lib/)
    
    message("libs: ${demo_LIBRARY}")
    
    if(demo_INCLUDE_DIR AND demo_LIBRARY)
        set(demo_FOUND TRUE)
        set(demo_VERSION 1.0.0)
    endif(demo_INCLUDE_DIR AND demo_LIBRARY)

    3、install目录

    bin目录:

    lib目录:

    include目录:

    三、find_package原理说明:

    构建main的时候,cmake会在main目录的CMakeLists.txt的第24行指定的目录查找Finddemo.cmake文件,第28行的find_package(demo)通过Finddemo.cmake文件查找demo的安装信息(头文件、.so或.a、版本信息等等),Finddemo.cmake文件设置了与demo的安装信息相关的变量(demo_FOUND、demo_INCLUDE_DIR、demo_LIBRARY、demo_VERSION等),由demo_FOUND指示了是否查找成功,查找成功后即可在CMakeLists.txt文件中使用这些变量了

    四、代码:

              详见https://download.csdn.net/download/lianshaohua/12830796

    展开全文
  • find_package()的使用

    2020-11-16 09:20:00
    find_package()命令是用来查找依赖包的,理想情况下,一句find_package()把一整个依赖包的头文件包含路径、库路径、库名字、版本号等情况都获取到,后续只管用就好了。但实际中往往CMake失败就是出在find_package()...

    find_package()命令是用来查找依赖包的,理想情况下,一句find_package()把一整个依赖包的头文件包含路径、库路径、库名字、版本号等情况都获取到,后续只管用就好了。但实际中往往CMake失败就是出在find_package()的失败上(这里不考虑后续make/nmake/msbuild以及编译器、链接器直接执行时的编译、链接出错,只讨论cmake根据CMakeLists.txt执行时候的情况),例如:

    • 多个OpenCV版本的问题

      • apt或brew等系统包管理工具安装的opencv,和手动编译的OpenCV共存问题
      • 手动编译安装了多个版本的OpenCV问题,也许你同时需要opencv2和opencv3,甚至opencv4
    • 多个protobuf版本问题

      • protobuf的python包需要和proto C编译器protoc版本一致,否则带python layer的prototxt解析失败
      • 安装了TensorFlow时被迫安装的protobuf3,但是Caffe这边用的python2,python protobuf包的版本问题

    上面列出的opencv和protobuf是重灾区,还有没有列出来的比如boost版本问题等。解决起来也不难:

    • 明确find_package()的N大查找顺序
    • 知道如何让find_package()找到非CMake构建安装的依赖包

    find_package()原理解读

    根据cmake官方文档可以知道,find_package()有Module模式(基本用法,basic signature)和Config模式(full signature,完全用法),其中Module模式是基础,Config模式则更复杂高级些。

    区分Module模式和Config模式

    Module模式也就是基础用法(Basic Signature,这里Signature表示“用法”,而不是“签名”),Config模式也就是高级用法(Full Signature)。

    The CONFIG option, the synonymous NO_MODULE option, or the use of options not specified in the basic signature all enforce pure Config mode. In pure Config mode, the command skips Module mode search and proceeds at once with Config mode search.

    也就是说,只有这3种情况下才是Config模式:

    • find_package()中指定CONFIG关键字
    • find_package()中指定NO_MODULE关键字
    • find_package()中使用了不在"basic signature"(也就是Module模式下所有支持的配置)关键字

    换句话说,只要我不指定"CONFIG",不指定“NO_MODULE",也不使用"full signature"中的关键字,那我就是在Module模式。排查find_package()的第一步,应当判断它是Module模式还是Config模式。

    Module模式下find_package()的用法

    find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]

    Module模式下,相比于Config模式,可选配置参数少一些,并且如果按用户指定的配置却找不到包,就会自动进入Config模式(如上图所示)。

    关键字解释

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

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

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

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

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

    OPTIONAL_COMPONENTS和components:可选的模块,找不到也不会让cmake停止执行。

    Module模式查找顺序

    Module模式下是要查找到名为Find .cmake的文件。

    先在CMAKE_MODULE_PATH变量对应的路径中查找。如果路径为空,或者路径中查找失败,则在cmake module directory(cmake安装时的Modules目录,比如/usr/local/share/cmake/Modules)查找。

    Config模式下find_package()的用法

    find_package(<PackageName> [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_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模式下的查找顺序,比Module模式下要多得多。而且,新版本的CMake比老版本的有更多的查找顺序(新增的在最优先的查找顺序)。它要找的文件名字也不一样,Config模式要找 Config.cmake或 -config.cmake。查找顺序为:

    1. 名为 _ROOT的cmake变量或环境变量。CMake3.12新增。设定CMP0074 Policy来关闭。
      注意:如果定义了 _DIR cmake变量,那么 _ROOT 不起作用。举例:
    cmake_minimum_required(VERSION 3.13)
    
    project(fk_cmk)
    
    set(OpenCV_ROOT "F:/zhangzhuo/lib/opencv_249/build")
    
    set(OpenCV_DIR "F:/zhangzhuo/lib/opencv_300/build")
    
    find_package(OpenCV QUIET
        NO_MODULE
        NO_DEFAULT_PATH
        NO_CMAKE_PATH
        NO_CMAKE_ENVIRONMENT_PATH
        NO_SYSTEM_ENVIRONMENT_PATH
        NO_CMAKE_PACKAGE_REGISTRY
        NO_CMAKE_BUILDS_PATH
        NO_CMAKE_SYSTEM_PATH
        NO_CMAKE_SYSTEM_PACKAGE_REGISTRY
    )
    
    message(STATUS "OpenCV library status:")
    message(STATUS "    version: ${OpenCV_VERSION}")
    message(STATUS "    libraries: ${OpenCV_LIBS}")
    message(STATUS "    include path: ${OpenCV_INCLUDE_DIRS}")

    实际上会找到opencv300,也就是OpenCV_DIR这一cmake变量的值最先起作用。

    1. cmake特定的缓存变量:
    CMAKE_PREFIX_PATH
    CMAKE_FRAMEWORK_PATH
    CMAKE_APPBUNDLE_PATH
    可以通过设定NO_CMAKE_PATH来关闭这一查找顺序
    1. cmake特定的环境变量
    <PackageName>_DIR
    CMAKE_PREFIX_PATH
    CMAKE_FRAMEWORK_PATH
    CMAKE_APPBUNDLE_PATH
    可以通过NO_CMAKE_ENVIRONMENT_PATH来跳过。
    1. HINT字段指定的路径

    2. 搜索标准的系统环境变量PATH。
      其中如果是以/bin或者/sbin结尾的,会自动转化为其父目录。
      通过指定NO_SYSTEM_ENVIRONMENT_PATH来跳过。

    3. 存储在cmake的"User Package Registry"(用户包注册表)中的路径。
      通过设定NO_CMAKE_PACKAGE_REGISTRY,或者:
      设定CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY为true,
      来避开。

    4. 设定为当前系统定义的cmake变量:

    CMAKE_SYSTEM_PREFIX_PATH
    CMAKE_SYSTEM_FRAMEWORK_PATH
    CMAKE_SYSTEM_APPBUNDLE_PATH
    通过设定NO_CMAKE_SYSTEM_PATH来跳过
    1. 在cmake的"System Package Registry"(系统包注册表)中查找。
      通过设定NO_CMAKE_SYSTEM_PACKAGE_REGISTRY跳过。
      或者通过设定CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY为true。

    2. 从PATHS字段指定的路径中查找。

    再次总结思路:

      1. 判断find_package()实际执行的是module模式还是config模式
      • 1.1 find_package( )这样的用法并不能看出是module模式还是config模式。要看CMAKE_MODULE_PATH或cmake安装路径下是否有Find .cmake脚本存在,并且这个脚本是否能正确的找到包。如果上述两个位置不存在Find .cmake,或者这个Find .cmake执行失败,则进入config模式。
      • 1.2 通过CONFIG、NO_MODULE、CONFIG模式特有字段,来设定为config模式
      1. 明确 _DIR是config模式特有的缓存变量
      • 2.1可以在find_package()前设定 _DIR,指向包含 Config.cmake或 -config.cmake的目录。 _ROOT先设定,再设定 _DIR,最后find_package( );并且两个都能找到包,则 _DIR起作用。
      • 2.2 也可在find_package()后使用例如打印。
      • 2.3 module模式下在find_package()前使用 _DIR,并不能用来帮助find_package()找到包;并且在find_package()后,也并没有 _DIR缓存变量自动存在。
      1. 明确 _ROOT是cmake3.12起支持的变量 _ROOT变量被find_package, find_library, find_path, find_program, find_file支持。因此,尽管从find_package()文档页看会以为 _ROOT只被config模式支持而不被module模式支持,但是module模式下通过另外4个find命令会间接的使用到 _ROOT,从而find_package命令的module模式间接的支持 _ROOT变量。 _ROOT设定后,find_package()的config模式会在 _ROOT目录及其子目录下寻找cmake的config文件;而 _DIR则很傻,不会在子目录中寻找。
      1. 检查路径是否拼写正确
        以上的3点是正确的,但有时候总发现幺蛾子,怀疑上面三点说的不对。这时候要检查路径是否拼写正确。
      • 4.1 路径是否拼写错误,比如少字母、字母写错、大小写拼错
      • 4.2 如果使用了环境变量来构成cmake变量,注意使用\(ENV{varName}而不是\)varName。
    展开全文
  • 一、find_package可以解决的问题 当构建一个依赖第三库或外部库的project时(即:project需要链接第三方库或外部库),我们需要知道以下信息: 去哪儿找第三 方库的头文件 .h 对比GCC的 -I 参数 去哪儿找第三...

    一、find_package可以解决的问题

    当构建一个依赖第三库或外部库的project时(即:project需要链接第三方库或外部库),我们需要知道以下信息:

    去哪儿找第三 方库的头文件 .h对比GCC的 -I 参数
    去哪儿找第三方库的链接文件 (.so/.dll/.lib/.dylib/…)对比GCC的 -L 参数
    链接的第三方库的文件的名字对比GCC的 -l 参数

    知道上面的信息后,就可以在CMakeLists.txt中方便的包含第三方库的头文件、访问的链接第三方库的库文件(.a、.so)了;

    二、为什么使用find_package

              第三方库的安装路径,在不同的机器上可能不同,所以在CMakeLists.txt中指定包含路径、链接路径和库,不太现实,除非你指定工程所需要的依赖库安装在固定的目录(貌似不太现实),否则在你的机器上构建成功了,在别人的机器上可能构建失败。或修改了第三方库的安装路径或版本升级后,在自己的机器上可能也无法构建成功。

              使用cmake的find_package可解决上面的问题。

             举个栗子:

                  比如说,我们需要一个第三方库 curl,那么我们的 CMakeLists.txt 需要指定头文件目录,和库文件,类似:

                     include_directiories(/usr/include/curl)
                     target_link_libraries(myprogram path/curl.so)
                   如果借助于cmake提供的finder会怎么样呢?使用cmake的Modules目录下的FindCURL.cmake,相应的CMakeList.txt 文件:
                     find_package(CURL REQUIRED)
                     include_directories(${CURL_INCLUDE_DIR})
                     target_link_libraries(curltest ${CURL_LIBRARY})

                      #使用find_package,不用关心curl具体安状在什么位置,find_package会替我们解决,那么是如何智能查找的呢?

    三、find_package的原理

               find_package首先会在模块路径中寻找Findxxxx.cmake,这是查找库的典型方式。具体查找路径依次为CMake变量${CMAKE_MODULE_PATH}中的所有目录,如果没有,再查找它自己的模块目录/share/cmake-x.y/Modules/($CMAKE_ROOT的具体值可以通过CMake中message命令输出)。如果找到了xxxx模块,那么Findxxxx.cmake一般会设置以下变量供CMakeLists.txt使用:

              xxxx_FOUND    #为true

              xxxx_INCLUDE_DIRS   #include路径

              xxxx_LIBRARY_DIRS    #library路径

              xxxx_LIBRARIES           #library的名字

              xxxx_yyyy_VERSION    #具体详见Findxxxx.cmake

              为了能支持各种常见的库和包,CMake自带了很多Findxxxx模块。可以通过命令 cmake –help-module-list (输入cmake –help,然后双击Tab会有命令提示)得到你的CMake支持的模块的列表,也可以直接查看模块路径: ls /usr/share/cmake/Modules/

    四、基本语法和模式

            根据cmake官方文档可以知道,find_package()有Module模式(基本用法,basic signature)和Config模式(full signature,完全用法),其中Module模式是基础,Config模式则更复杂高级些。

            Module模式基本语法:

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

            Config模式基本语法:                                              

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

        更详细的请参见:https://cmake.org/cmake/help/v3.18/command/find_package.html#find-package

        只有以下3种情况下才是Config模式:

                    find_package()中指定CONFIG关键字
                    find_package()中指定NO_MODULE关键字
                     find_package()中使用了不在"basic signature"(也就是Module模式下所有支持的配置)关键字
         只要不指定"CONFIG",不指定“NO_MODULE",也不使用"full signature"中的关键字,那我就是在Module模式。排查find_package()的第一步,应当判断它是Module模式还是Config模式。

    五、基本用法

        1、Module模式下find_package()的用法         

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

    Module模式下,相比于Config模式,可选配置参数少一些,并且如果按用户指定的配置却找不到包,就会自动进入Config模式(如上图所示)。

    关键字解释

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

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

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

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

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

    OPTIONAL_COMPONENTS和components:可选的模块,找不到也不会让cmake停止执行。

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

    先在CMAKE_MODULE_PATH变量对应的路径中查找。如果路径为空,或者路径中查找失败,则在cmake module directory(cmake安装时的Modules目录,比如/usr/local/share/cmake/Modules)查找。

      2、Config模式下find_package()的用法

    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模式下的查找顺序

    比Module模式下要多得多。而且,新版本的CMake比老版本的有更多的查找顺序(新增的在最优先的查找顺序)。它要找的文件名字也不一样,Config模式要找<PackageName>Config.cmake或<lower-case-package-name>-config.cmake。查找顺序为:

    名为<PackageName>_ROOT的cmake变量或环境变量。CMake3.12新增。设定CMP0074 Policy来关闭。
    注意:如果定义了<PackageName>_DIR cmake变量,那么<PackageName>_ROOT 不起作用。

    cmake特定的缓存变量:

    CMAKE_PREFIX_PATH
    CMAKE_FRAMEWORK_PATH
    CMAKE_APPBUNDLE_PATH
    可以通过设定NO_CMAKE_PATH来关闭这一查找顺序

    cmake特定的环境变量

    <PackageName>_DIR
    CMAKE_PREFIX_PATH
    CMAKE_FRAMEWORK_PATH
    CMAKE_APPBUNDLE_PATH
    可以通过NO_CMAKE_ENVIRONMENT_PATH来跳过。

    HINT字段指定的路径

    搜索标准的系统环境变量PATH。
    其中如果是以/bin或者/sbin结尾的,会自动转化为其父目录。
    通过指定NO_SYSTEM_ENVIRONMENT_PATH来跳过。

    存储在cmake的"User Package Registry"(用户包注册表)中的路径。
    通过设定NO_CMAKE_PACKAGE_REGISTRY,或者:
    设定CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY为true,
    来避开。

    设定为当前系统定义的cmake变量:

    CMAKE_SYSTEM_PREFIX_PATH
    CMAKE_SYSTEM_FRAMEWORK_PATH
    CMAKE_SYSTEM_APPBUNDLE_PATH
    通过设定NO_CMAKE_SYSTEM_PATH来跳过。

    在cmake的"System Package Registry"(系统包注册表)中查找。
    通过设定NO_CMAKE_SYSTEM_PACKAGE_REGISTRY跳过。
    或者通过设定CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY为true。

    从PATHS字段指定的路径中查找。

     

    展开全文
  • cmake:指定find_package的搜索路径

    千次阅读 2021-03-25 14:07:56
    find_package(OpenCV PATHS /opt/opencv NO_DEFAULT_PATH REQUIRED) if (OpenCV_FOUND) include_directories(${OpenCV_INCLUDE_DIRS}) message( ${OpenCV_LIBS}) else() message("OpenCV not found, so we won...
  • time) #find boost components find_package(gflags REQUIRED COMPONENTS static) #find gflags #set compile flags #add_definitions(-std=c++11 -g -rdynamic) set(CMAKE_CXX_FLAGS "-g3 -rdynamic -std=c++11") ...
  • cmake(7):find_package命令详解

    千次阅读 2020-10-20 11:09:33
    cmake的find_package命令对于构建软件提供了极大的便利,虽然知道怎么使用已经能解决大部分问题,但是cmake支持哪些包?为什么它能找到需要的包?如果是自己编写的库,需要如何做才能使用该命令进行构建等原理性问题...
  • 转载总结自深入理解CMake(3):find_package()的使用 CMake学习日志之find_package 一、首先明确一下默认查找的路径 <package>_DIR CMAKE_PREFIX_PATH CMAKE_FRAMEWORK_PATH CMAKE_APPBUNDLE_PATH PATH 二、...
  • “轻松搞定CMake”系列之find_package用法详解

    千次阅读 多人点赞 2020-04-12 13:27:37
    本文是“轻松搞定CMake”系列博客中的一篇,该篇文章的主要目的是详细讲解一下CMake中搜包命令find_package的使用和原理。 find_packakge命令基本介绍 在我们实际开发过程中,经常不可避免会使用到第三方开源库,...
  • find_package()的搜索路径

    千次阅读 2021-11-11 15:51:21
    find_package() 首先明确,find_package()肯定需要个.cmake文件,不然它根本就不知道package的名字具体是啥(大写?小写?),去哪找??? Module模式 (1)是否有CMAKE_MODULE_PATH,有的话,优先在这里找Find<...
  • cmake教程4(find_package使用)

    万次阅读 多人点赞 2018-06-03 19:34:31
    1. cmake find_package的基本原理 2. 如何编写自己的 cmake module模块 3. 使用cmake find_package 使用不同版本的opencv lib问题(opencv 安装在指定的目录,不是系统的目录) 1. cmake find_package的...
  • find_package_simple.rar

    2020-09-10 09:06:53
    find_package module模式的示例代码,包含了依赖库的构建文件、main的构建文件、Findxxx.cmake的查找文件
  • FIND_PACKAGE( <name> [version] [EXACT] [QUIET] [NO_MODULE] [ [ REQUIRED | COMPONENTS ] [ componets... ] ] )
  • Cmake之深入理解find_package()的用法

    千次阅读 2020-04-08 16:37:04
    使用find_package引入外部依赖包 本章节通过示例演示Cmake中find_package的用法。 1.通过Cmake内置模块引入依赖包 为了方便我们在项目中引入外部依赖包,cmake官方为我们预定义了许多寻找依赖包的Module,他们...
  • 在用cmake编译项目的时候,很多时候需要用find_package来导入一些库,比如opencv,cuda等。但是有时候,下载了预编译好的项目时,怎么手动指定路径呢? 解决方案 通过设定一个project_DIR变量来指定路径,该路径是...
  • find_package与CMake如何查找链接库详解

    千次阅读 2017-10-15 15:51:22
    CMake使用 find_package 命令来解决这个问题。本文讨论了如何在CMake项目中使用外部库,以及如何给没有查找模块的库写一个。 1 FIND_PACKAGE FIND_PACKAGE( [version] [EXACT] [QUIET] [NO_MODULE] [ [ REQU
  • find_package的查找路径

    2021-04-15 17:59:36
    Find×××.cmake ${CMAKE_MODULE_PATH} <CMAKE_ROOT>/share/cmake-x.y/Modules ×××Config.cmake 或×××-config.cmake ${CMAKE_PREFIX_PATH} /usr/local/share 办法 将需要的.cmake放在同一个...
  • find_package()函数

    千次阅读 2019-03-13 09:59:44
    find_package引言1.find_package用法2.find_package原理3.A required library with LAPACK API not found. 错误解决4.其他 引言 一个库文件已经安装但是在程序调用时候,报错找不到库文件API。 LAPACK库已经是安装...
  • 问题一: 最近正在自学古月的《ros...The manifest of package “learning_communication” (with format version 2) must not contain the following tags: run_depend Please replace <run_depend> tags with
  • 本文介绍 CMake 中两种查找库的方式:find_package 以及 pkg_check_modules 的用法与区别。 find_package 如果编译软件使用了外部库,事先并不知道它的头文件和链接库的位置,得在编译和链接命令中加上包含它们的...
  • cmake中经常使用find_package寻找模块,使用起来非常方便.find_package的原理是什么呢?如果自己写个模块,如何提供给别人使用.如果别人希望用find_package的形式使用你的模块中的库,我该如何用cmake写这个库呢?...
  • 一种方法是 直接将catkin package放到项目工程中,这样每个工程都要复制一个,太麻烦。 另一种方法是,安装catkin及其依赖项。但可能是ros未安装的原因,cmake .. 时总是找不到catkin,以下是解决方法。 问题描述...
  • [CMake] find_package 指定路径

    千次阅读 2021-02-19 10:38:56
    CMakeLists.txt 中使用 find_package find_package(Torch required) 报错找不到 Torch,因为安装位置不在系统默认路径下。 让 find_package 到指定路径找包,有三种方法: 设置 DIR set(Torch_DIR ~/libtorch-1.0.0...
  • cmake中find_package()函数的使用

    千次阅读 2020-05-19 17:23:24
    cmake中find_package()函数的使用 背景 今天在玩一个密码学库,它是使用cmake构建的,编译安装过程很曲折,出现了一些错误。作为一个不怎么熟悉 cmake 的新手,单单一个 find_package() 函数就让我花费了很多时间。 ...
  • find_package()的底层运行机制

    千次阅读 2020-06-02 13:32:31
    马斯克的龙飞船中的操作...find_package(xxx) 然后就会有对应的 ${XXX_INCLUDE_DIRS}和${XXX_LIBRARIES} 如果find_package(xxx)失败的话,就不会生成这两个环境变量. 这里讲一下这两个环境变量是怎么产生的. 1 find
  • Cmake入门(四)find_package

    千次阅读 2019-04-12 20:39:41
    find_package是Cmake中非常重要的一条指令,用法简单,功能强大。 先介绍一下它的运作流程,以用途最大的opencv为例: 1.find_package在一些目录中查找OpenCV的配置文件。 2.找到后,find_package会将头文件目录...
  • 实际上,通过 find_package() 可以顺利查找任何符合 cmake package 标准的外部工程。 find_pacage() 方法签名如下: find_package(<package> [version] [EXACT] [QUIET] [MODULE] [REQUIRED] [[COMPONENTS] ...
  • cmake find_package opencv 找不到

    千次阅读 2020-12-09 18:58:22
    cmake find_package opencv找不到 #find opencv lib find_package(OpenCV REQUIRED NO_MODULE # should be optional, tells CMake to use config mode PATHS /usr/local # look here NO_DEFAULT_PATH) # and ...
  • Cmake语句find_package()函数

    千次阅读 2019-05-14 15:11:38
    如果我们在cmake某个程序的时候,经常会提示找不到某个所依赖的库,那么这是时候我们就需要检查我们引入依赖库的路径对不对了, Cmake中一个自动寻找函数find_package()可以帮我们实现这个功能。 使用方法 //以...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 274,902
精华内容 109,960
关键字:

find_package