cmake教程4(find_package使用)

2023-05-16

本文主要内容如下:
1. cmake find_package的基本原理
2. 如何编写自己的 cmake module模块
3. 使用cmake find_package 使用不同版本的opencv lib问题(opencv 安装在指定的目录,不是系统的目录)

1. cmake find_package的基本原理

当编译一个需要使用第三方库的软件时,我们需要知道:

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

比如说,我们需要一个第三方库 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})

那么cmake是如何查找的呢?

find_package()命令首先会在模块路径中寻找Find.cmake,这是查找库的一个典型方式。具体查找路径依次为CMake:变量${CMAKE_MODULE_PATH}中的所有目录。如果没有,然后再查看它自己的模块目录/share/cmake-x.y/Modules/$CMAKE_ROOT的具体值可以通过CMake中message命令输出)。这称为模块模式。

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

ll -th /usr/share/cmake-3.5/Modules/
......
-rw-r--r--  1 root root  76K Sep 27  2016 FindBoost.cmake
-rw-r--r--  1 root root 2.7K Mar 24  2016 FindCoin3D.cmake
-rw-r--r--  1 root root  77K Mar 24  2016 FindCUDA.cmake
-rw-r--r--  1 root root 3.1K Mar 24  2016 FindCups.cmake
-rw-r--r--  1 root root 2.4K Mar 24  2016 FindCURL.cmake
........

让我们以bzip2库为例。CMake中有个 FindBZip2.cmake 模块。只要使用 find_package(BZip2) 调用这个模块,cmake会自动给一些变量赋值,然后就可以在CMake脚本中使用它们了。变量的列表可以查看cmake模块文件,或者使用命令:

root@xy:~/cmake_practice/cmake_build/build_demo10# cmake --help-module FindBZip2
FindBZip2
---------

Try to find BZip2

Once done this will define
::
BZIP2_FOUND - system has BZip2
BZIP2_INCLUDE_DIR - the BZip2 include directory
BZIP2_LIBRARIES - Link these to use BZip2
BZIP2_NEED_PREFIX - this is set if the functions are prefixed with BZ2_
BZIP2_VERSION_STRING - the version of BZip2 found (since CMake 2.8.8)

cmake 会将路径赋值给对应的变量,我们以curl的cmake为例,其部分内容如下:


find_path(CURL_INCLUDE_DIR NAMES curl/curl.h)
mark_as_advanced(CURL_INCLUDE_DIR)

# Look for the library (sorted from most current/relevant entry to least).
find_library(CURL_LIBRARY NAMES
        curl
        # Windows MSVC prebuilts:
        curllib
        libcurl_imp
        curllib_static
        # Windows older "Win32 - MSVC" prebuilts (libcurl.lib, e.g. libcurl-7.15.5-win32-msvc.zip):
        libcurl
        )

比如一个使用bzip2的简单程序,编译器需要知道 bzlib.h 的位置,链接器需要找到bzip2库(动态链接的话,Unix上是 libbz2.so 类似的文件,Windows上是 libbz2.dll )

project(helloworld)
add_executable(helloworld hello.c)
find_package (BZip2)
if (BZIP2_FOUND)
    include_directories(${BZIP_INCLUDE_DIRS})
    target_link_libraries (helloworld ${BZIP2_LIBRARIES})
endif (BZIP2_FOUND)

2. 如何编写自己的 cmake module模块

下面以工程demo9为示例, 项目目录结构如下:

├── cmake
│   └── FindDEMO9LIB.cmake
├── CMakeLists.txt
├── demo9.cpp
├── demo9.h
└── demo9_main.cpp

其中demo9.h和demo9.cpp生成lib, demo9_main.cpp link对应的lib生成可执行文件

文件内容如下:

//=========================demo9.h===================
#ifndef PROJECT_DEMO9_H
#define PROJECT_DEMO9_H

namespace demo9{
    void print_demo9();
}

#endif //PROJECT_DEMO3_H_H


//======================demo9.cpp==================
#include "demo9.h"
#include <iostream>

namespace demo9{
    void print_demo9(){
        std::cout<<"this is demo9"<<std::endl;
    }
}

//======================demo9_main.cpp==================

#include "demo9.h"

int main(){
    demo9::print_demo9();
    return 0;
}

首先我们使用demo9.h and demo9.cpp 生成静态lib,并安装:

-- Installing: /usr/local/demo9/lib/libdemo9_lib.a
-- Installing: /usr/local/demo9/include/demo9.h

FindDEMO9LIB.cmake的内容如下(精简版本):

# 辅助输出信息
message("now using FindDEMO9LIB.cmake find demo9 lib")

# 将demo9.h文件路径赋值给DEMO9LIB_INCLUDE_DIR
FIND_PATH(DEMO9LIB_INCLUDE_DIR demo9.h /usr/include/demo9/
        /usr/local/demo9/include/)
message("./h dir ${DEMO9LIB_INCLUDE_DIR}")

# 将libdemo9_lib.a文件路径赋值给DEMO9LIB_LIBRARY
FIND_LIBRARY(DEMO9LIB_LIBRARY libdemo9_lib.a /usr/local/demo9/lib/)
message("lib dir: ${DEMO9LIB_LIBRARY}")

if(DEMO9LIB_INCLUDE_DIR AND DEMO9LIB_LIBRARY)
    # 设置变量结果
    set(DEMO9LIB_FOUND TRUE)
endif(DEMO9LIB_INCLUDE_DIR AND DEMO9LIB_LIBRARY)

主CMakeLists.txt内容如下:

cmake_minimum_required(VERSION 3.5)

project(demo9)

# create libdemo9_lib.a
set(SRC_LIB demo9.cpp)
add_library(demo9_lib STATIC ${SRC_LIB})

# install it
install(TARGETS demo9_lib DESTINATION demo9/lib)
install(FILES demo9.h DESTINATION demo9/include)

# create demo9_main exectuable
set(SRC_EXE demo9_main.cpp)

# set demo9_lib cmake module path
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
message("cmake_module_path: ${CMAKE_MODULE_PATH}")
find_package(DEMO9LIB)

if(DEMO9LIB_FOUND)
    add_executable(demo9_main ${SRC_EXE})
    message("found demo9 ${DEMO9LIB_INCLUDE_DIR} ${DEMO9LIB_LIBRARY}")
    include_directories(${DEMO9LIB_INCLUDE_DIR})
    target_link_libraries(demo9_main ${DEMO9LIB_LIBRARY})
else()
    message("not found DEMO9LIB_FOUND")
endif(DEMO9LIB_FOUND)

编译输出信息如下:

root@xy:~/cmake_practice/cmake_build/build_demo9# cmake ../../cmake_tuorial/demo9/
cmake_module_path: /home/xy/cmake_practice/cmake_tuorial/demo9/cmake
now using FindDEMO9LIB.cmake find demo9 lib
./h dir /usr/local/demo9/include
lib dir: /usr/local/demo9/lib/libdemo9_lib.a
found demo9 /usr/local/demo9/include /usr/local/demo9/lib/libdemo9_lib.a

make

root@xy:~/cmake_practice/cmake_build/build_demo9# make -j10
cmake_module_path: /home/xy/cmake_practice/cmake_tuorial/demo9/cmake
now using FindDEMO9LIB.cmake find demo9 lib
./h dir /usr/local/demo9/include
lib dir: /usr/local/demo9/lib/libdemo9_lib.a
found demo9 /usr/local/demo9/include /usr/local/demo9/lib/libdemo9_lib.a
-- Configuring done
.......................................

运行:

root@xy:~/cmake_practice/cmake_build/build_demo9# ./demo9_main 
this is demo9

3. 使用cmake find_package 使用不同版本的opencv lib问题(opencv 安装在指定的目录,不是系统的目录)

下面在给出一个opencv的示例,opencv3.1安装在/home/xy/opencv3.1_install/lib/目录下(可以参考这篇英文blog安装)。

最终安装完成会有对应的cmake文件,查看如下:

xy@xy:~/opencv_demo/demo1$ ll -th ~/opencv3.1_install/lib/share/OpenCV/
total 60K
drwxrwxr-x 5 xy xy 4.0K May 28 19:00 ./
......
-rw-r--r-- 1 xy xy  16K May 28 18:56 OpenCVConfig.cmake
-rw-r--r-- 1 xy xy  418 May 28 18:56 OpenCVConfig-version.cmake
-rw-r--r-- 1 xy xy 4.5K May 28 18:56 OpenCVModules.cmake
-rw-r--r-- 1 xy xy  11K May 28 18:56 OpenCVModules-release.cmake

测试代码如下:

#include <stdio.h>
#include "opencv2/opencv.hpp"
#include<iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv )
{

    cout << "OpenCV version : " << CV_VERSION << endl;
    cout << "Major version : " << CV_MAJOR_VERSION << endl;
    cout << "Minor version : " << CV_MINOR_VERSION << endl;

    if ( argc != 2 )
    {
        printf("usage: DisplayImage.out <Image_Path>\n");
        return -1;
    }
    Mat image;
    image = imread( argv[1], 1 );
    if ( !image.data )
    {
        printf("No image data \n");
        return -1;
    }
    cout<<image.size()<<endl;
    cout<<image.size().width<<endl;
    cout<<image.size().height<<endl;
    namedWindow("Display Image", WINDOW_AUTOSIZE );
    imshow("Display Image", image);
    waitKey(0);
    return 0;
}

对应的cmake 如下:

cmake_minimum_required(VERSION 3.5.0)
project(demo1)
//set cmake module path
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}  
                          "~/opencv3.1_install/lib/share/OpenCV/"
)

find_package( OpenCV 3.1.0 REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
message("OpenCV_INCLUDE_DIRS: ${OpenCV_INCLUDE_DIRS}")
message("OpenCV_LIBS: ${OpenCV_LIBS}")
add_executable( demo1 demo.cpp )
target_link_libraries( demo1 ${OpenCV_LIBS} )

cmake build输出如下:

xy@xy:~/opencv_demo/demo1$ cmake .
OpenCV_INCLUDE_DIRS: /home/xy/opencv3.1_install/lib/include/opencv;/home/xy/opencv3.1_install/lib/include
OpenCV_LIBS: opencv_videostab;opencv_videoio;.....

程序运行如下:

这里写图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

cmake教程4(find_package使用) 的相关文章

随机推荐

  • 信息与不确定性

    最近学习了吴军的 信息论40讲 xff0c 深有感触 xff0c 有感而发 xff01 本博文想要给你传递 xff08 或者说洗脑 xff09 两个主要观点 xff1a 信息是可以量化的 xff0c 用事件的不确定性表示 xff0c 增加相
  • AlexeyAB/darknet (YOLO)的编译 和 作为动态库进行使用 以及 训练 自定义 数据(检测网络和分类网络)

    ubuntu 编译 https github com AlexeyAB darknet 这个库很贴心了 xff0c 当然 xff0c 主要是 darknet的实现也很硬核 xff0c 自带图像编解码 xff0c 各种造轮子 文档 把 各种用
  • LoRa和NB-IoT有什么区别?LoRa的优势在哪些方面?

    对于LoRa技术 xff0c 行业内人士都不会陌生 xff0c 它也经常会被拿来和NB IoT技术比较 作为低功耗广域网 xff08 LPWAN xff09 的新兴技术 xff0c 两种技术都备受关注 对于LoRa技术 xff0c 行业内人
  • Source Insight 4.0最好看的主题

    推荐一款sourceinsight主题 xff0c 4 0适用 xff0c 配色本人觉得非常舒服 使用方法 xff1a 1 安装Sourceinsight 2 安装字体 xff1a YaHei Consolas Hybrid 1 12 tt
  • Notepad++最好看的主题

    Notepad 43 43 最好看的主题 xff0c 收藏了很久 xff0c 现在拿出来和大家分享 配色如下 xff1a 使用方法 xff1a 1 安装Notepad 43 43 2 将KamiTheme xml放到 Notepad 43
  • DTLS协议中client/server的认证过程和密钥协商过程

    1 DTLS介绍 1 1 DTLS的作用 互联网先驱们最开始在设计互联网协议时主要考虑的是可用性 xff0c 安全性是没有考虑在其中的 xff0c 所以传输层的TCP UDP协议本身都不具备安全性 SSL TLS协议是基于TCP socke
  • Ubuntu18.04 实现串口通信

    最近由于项目需要 xff0c 研究了关于在ubuntu下串口通信的功能实现 期间遇到一些问题 xff0c 跟大家分享下 1 代码 comm service h ifndef comm service h define comm servic
  • [STM32] 串口数据帧处理(第一弹)

    文章目录 1 串口使用的常用场景2 字节帧处理总结 1 串口使用的常用场景 使用串口的主要目的是实现数据的交互 xff0c 数据的交互的方法脱身于常用的场景 这里描述一个比较典型的场景 xff1a MCU作为主控制器通过串口和外部的设备或者
  • 串口编程—(1)串口基本知识

    串口是用来干什么的 xff1f 串行接口 简称串口 xff0c 也称 串行通信 接口或 串行通讯接口 xff08 通常指 COM接口 xff09 xff0c 是采用 串行通信 方式的扩展接口 串行接口 Serial Interface 是指
  • C语言操作redis数据库

    文章目录 1 开发环境2 C语言redis库 hiredi安装配置2 1 下载并且解压hiredis2 2 hiredis安装 3 hiredis简单测试4 运行出错解决办法5 验证5 1 运行程序5 2 redis客户端验证 1 开发环境
  • 5.0 NuttX File System

    转载请注明出处 xff1a 5 0 NuttX File System Alvin Peng的博客 CSDN博客 文章均出自个人理解 前言 前一段时间折腾了几个驱动 xff08 PWM Serial I2C xff09 xff0c 这次来折
  • 使用cmake构建一个大型项目框架

    文章目录 使用CMake构建一个大型项目工程1 大型工程目录结构介绍1 1 工程目录结构介绍1 2 工程目录说明 xff08 我是这样设计的 xff0c 你们也可以参考类似这样设计 xff09 1 3 最外层CMakeLists txt说明
  • github下载加速的几种方法

    文章目录 1 github加速的几种办法1 1 把github的代码 xff0c 转到码云上1 2 有人做了github的代下载网站 xff0c 可以从上面进行下载1 3 使用cnpmjs镜像进行加速1 4 使用国外服务器进行搭桥 2 总结
  • EasyLogger的代码解读和移植(linux和stm)

    文章目录 1 EasyLogger目录结构分析 2 EasyLogger之docs查看总结 2 1 EasyLogger之docs查看 2 1 2 api gt kernel md文档 2 1 3 port gt kernel md文档 2
  • C++之socket.io编译使用

    文章目录 1 什么是socket io2 开发环境配置2 1 获取socket io的源码2 2 cmake安装2 3 boost安装2 3 1 获取源码2 3 2 解压编译下载 2 4 rapidjson下载2 5 websocketpp
  • github push的改版

    1 记录一次github 推送时的错误 错误如下 xff1a remote Please see https github blog 2020 12 15 token authentication requirements for git
  • Frp内网穿透

    Frp内网穿透 所有经过服务器的内网穿透都是有一个服务端和客户端 因为都需要借助服务器的公网ip来访问进而达到内网穿透的效果 frp的github开源地址 https github com fatedier frp frp的说明文档 htt
  • linux常见的几种排序方法

    我们以数组a 61 2 6 8 9 1 2 进行排序输出作为列子 xff1a 下面我来总结几种方法来帮助大家学习 1 xff1a 常规排序 首先2和6对比 xff0c 2不比6大不因此不交换 xff0c 所以还是268912 xff0c 然
  • 值得推荐的C/C++框架和库

    值得学习的C语言开源项目 Libevent libev是一个开源的事件驱动库 xff0c 基于epoll xff0c kqueue等OS提供的基础设施 其以高效出名 xff0c 它可以将IO事件 xff0c 定时器 xff0c 和信号统一起
  • cmake教程4(find_package使用)

    本文主要内容如下 xff1a 1 cmake find package的基本原理 2 如何编写自己的 cmake module模块 3 使用cmake find package 使用不同版本的opencv lib问题 xff08 openc