cmake find_package 搜包命令使用介绍
  4mvkm8WQGQqB 2023年11月02日 33 0

一、find_package 命令基本介绍

在实际开发工程中,经常不可避免会使用到第三方开源库,这些开源库可能是通过apt-get install 命令自动安装到系统目录中的;也有可能是由我们自己下载库的源码,然后通过编译安装到指令目录下。 不管哪种方式安装的库文件,如果我们需要在项目中使用这些库,首先面临的第一个问题,就是怎么找到这些库;其实就是根据我们的需要找到指定版本的库的头文件和库文件所在的路径,或者是链接库路径;从而能够满足我们开发项目的编译链接需要。 在没有CMake的时代,这种库查找链接的工作都需要借助MakeFile中的各种命令来完成,非常的繁琐,而且不方便移植。到了CMake时代,CMake给我们提供了find_package() 命令来查找依赖包。理想情况下,一句find_package()命令就可以把一整个依赖包的头文件包含路径、库路径、库名字、版本号等情况都获取到,后续只管用就好了。

二、find_package命令搜包过程

首先我们需要明确一点,CMake本身不提供任何搜索库的便捷方法,所有的搜索库并给变量赋值的操作必须由CMake代码完成,也就是xxxConfig.cmake以及下面将要提到的Findxxx.cmake配置文件。只不过,库的作者通常会提供这两个文件,以便使用者使用。

2.1 find_package工作模式

ind_package 命令有两种工作模式,这两种工作模式的不同决定了其搜包路径的不同: (1)Module 模式 find_package 命令基础工作模式(Basic Signature),也是默认工作模式。 (2)Config 模式 find_package 命令高级工作模式(Full Signature)。 只有在 find_package() 中指定 CONFIG、 NO_MODULE 等关键字,或者 Module 模式查找失败后才会进入到 Config 模式。 因此,find_package工作模式流程图为: image.png

三、参数解释

3.1 Module 模式

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

3.1.1 参数解释 package:必填参数。需要查找的包名,注意大小写。 version 和 EXACT:可选参数,version 指定的是版本,如果指定就必须检查找到的包的版本是否和 version 兼容。如果指定 EXACT 则表示必须完全匹配的版本而不是兼容版本就可以。 QUIET:可选参数,表示如果查找失败,不会在屏幕进行输出(但是如果指定了 REQUIRED 字段,则 QUIET 无效,仍然会输出查找失败提示语)。 MODULE:可选字段。前面提到说“如果 Module 模式查找失败则回退到 Config 模式进行查找”,但是假如加入了 MODULE 选项,那么就只在 Module 模式查找,如果 Module 模式下查找失败并不切换到 Config 模式查找。 REQUIRED:可选字段。表示一定要找到包,找不到的话就立即停掉整个 CMake。而如果不指定REQUIRED 则 CMake 会继续执行。 COMPONENTS,components:可选字段,表示查找的包中必须要找到的组件(components),如果有任何一个找不到就算失败,类似于 REQUIRED,导致 CMake 停止执行。 3.1.2 Module 模式查找顺序 Module 模式下是要查找到名为 Find<PackageName>.cmake 的配置文件。 Module 模式只有两个查找路径:CMAKE_MODULE_PATH 和 CMake 安装路径下的 Modules 目录,搜包路径依次为:

CMAKE_MODULE_PATH
CMAKE_ROOT

先在 CMAKE_MODULE_PATH 变量对应的路径中查找。如果路径为空,或者路径中查找失败,则在 CMake 安装目录(即 CMAKE_ROOT 变量)下的 Modules 目录下(通常为 /usr/share/cmake-3.10/Modules,3.10 是我的 CMake 版本)查找。这两个变量可以在 CMakeLists.txt 文件中打印查看具体内容:

message(STATUS "CMAKE_MODULE_PATH = ${CMAKE_MODULE_PATH}")
message(STATUS "CMAKE_ROOT = ${CMAKE_ROOT}")

其中 CMAKE_MODULE_PATH 默认为空,可以利用 set 命令赋值。 在安装 CMake 时,CMake 为我们提供了很多开发库的 FindXXX.cmake 模块文件,可以通过命令查询:

cmake --help-module-list | grep -E ^Find

3.2 Config模式 略

四、命令使用

为了能够帮助大家理解 find_package 命令的用法,此处首先用 OpenCV 库举例子,示范如何通过 find_pakcage 命令找到 OpenCV 库并配置,从而能够在我们自己的项目中调用 OpenCV 库,实现特定的功能。 下面的代码主要实现了利用 OpenCV 载入一张图片并显示的简单功能: 注: 此处假设你已经安装了 OpenCV 库, 并对 OpenCV 有稍许的了解即可。 opencv_test.cpp:

#include <cstdio>
#include <iostream>
#include <opencv2/opencv.hpp>
 
using namespace cv;
 
int main() {
  Mat image;
  image = imread("../opencv_test.jpg");
 
  if (!image.data) {
    printf("No image data\n");
    return -1;
  }
 
  namedWindow("Display Image", CV_WINDOW_AUTOSIZE);
  imshow("Display Image", image);
  waitKey(0);
  return 0;
}

CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)
project(find_package_learning)
find_package(OpenCV 3 REQUIRED)
 
message(STATUS "OpenCV_DIR = ${OpenCV_DIR}")
message(STATUS "OpenCV_INCLUDE_DIRS = ${OpenCV_INCLUDE_DIRS}")
message(STATUS "OpenCV_LIBS = ${OpenCV_LIBS}")
 
include_directories(${OPENCV_INCLUDE_DIRS})  
add_executable(opencv_test opencv_test.cpp)  
target_link_libraries(opencv_test ${OpenCV_LIBS})

4.1 编译输出与分析 我的 Ubuntu18.04 系统在 usr/local 路径下安装了 OpencCV3.4.4,在执行上述 cmake 命令时输出为:

-- The C compiler identification is GNU 7.5.0
-- The CXX compiler identification is GNU 7.5.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found OpenCV: /usr/local (found suitable version "3.4.4", minimum required is "3") 
-- OpenCV_DIR = /usr/local/share/OpenCV
-- OpenCV_INCLUDE_DIRS = /usr/local/include;/usr/local/include/opencv
-- OpenCV_LIBS = opencv_calib3d;opencv_core;opencv_dnn;opencv_features2d;opencv_flann;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_shape;opencv_stitching;opencv_superres;opencv_video;opencv_videoio;opencv_videostab;opencv_viz;opencv_aruco;opencv_bgsegm;opencv_bioinspired;opencv_ccalib;opencv_cvv;opencv_datasets;opencv_dnn_objdetect;opencv_dpm;opencv_face;opencv_freetype;opencv_fuzzy;opencv_hdf;opencv_hfs;opencv_img_hash;opencv_line_descriptor;opencv_optflow;opencv_phase_unwrapping;opencv_plot;opencv_reg;opencv_rgbd;opencv_saliency;opencv_stereo;opencv_structured_light;opencv_surface_matching;opencv_text;opencv_tracking;opencv_xfeatures2d;opencv_ximgproc;opencv_xobjdetect;opencv_xphoto
-- Configuring done
-- Generating done
-- Build files have been written to: /home/zhanghm/Programming/programming-learning-examples/cmake_learning/learn_cmake_easily/find_package_learning/build

重点看下其中 OpenCV_DIR、OpenCV_INCLUDE_DIRS 和 OpenCV_LIBS 打印的结果,这是我在 CMakeLists.txt 中用 message 命令输出这三个变量的值的结果。

可以看到在执行 find_package(OpenCV 3 REQUIRED) 命令后,CMake 找到了我们安装的位于 /usr/local 下的 OpenCV 库,并设置了 CMake 变量 OpenCV_DIR 为 OpenCV 库的配置文件所在路径,正是通过载入这个路径下的 OpenCVConfig.cmake 配置文件才能配置好 OpenCV 库,然后在 OpenCVConfig.cmake 配置文件中定义了变量 OpenCV_INCLUDE_DIRS 为 OpenCV 库头文件包含路径,这样我们才能才在代码中使用

#include <opencv2/opencv.hpp>

而不会出现编译错误,同时定义了变量 OpenCV_LIBS 为 OpenCV 链接库路径,这样我们才能正确链接到 OpenCV 中的库文件,而不会出现类似未定义的引用这样的链接错误。 image.png 通过这个例子就可以看出 find_package 本质上就是一个搜包的命令,通过一些特定的规则找到<package_name>Config.cmake 包配置文件,通过执行该配置文件,从而定义了一系列的变量,通过这些变量就可以准确定位到 OpenCV 库的头文件和库文件,完成编译。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  LxKByvFwtHdi   2023年11月02日   61   0   0 xml配置文件功能实现
  LxKByvFwtHdi   2023年11月02日   41   0   0 时序图配置文件Tomcat
  X5zJxoD00Cah   2023年11月19日   15   0   0 YAML配置文件TOML
4mvkm8WQGQqB