cmake 学习笔记(一)

2023-05-16

  • 最大的Qt4程序群(KDE4)采用cmake作为构建系统
  • Qt4的python绑定(pyside)采用了cmake作为构建系统
  • 开源的图像处理库 opencv 采用cmake 作为构建系统
  • ...

看来不学习一下cmake是不行了,一点一点来吧,找个最简单的C程序,慢慢复杂化,试试看:

例子一

单个源文件 main.c

例子二

==>分解成多个 main.c hello.h hello.c

例子三

==>先生成一个静态库,链接该库

例子四

==>将源文件放置到不同的目录

例子五

==>控制生成的程序和库所在的目录

例子六

==>使用动态库而不是静态库

例子一

一个经典的C程序,如何用cmake来进行构建程序呢?


//main.c
#include <stdio.h>
int main()
{
    printf("Hello World!/n");
    return 0;
}  

编写一个 CMakeList.txt 文件(可看做cmake的工程文件):


project(HELLO)
set(SRC_LIST main.c)
add_executable(hello ${SRC_LIST})  

然后,建立一个任意目录(比如本目录下创建一个build子目录),在该build目录下调用cmake

  • 注意:为了简单起见,我们从一开始就采用cmake的 out-of-source 方式来构建(即生成中间产物与源代码分离),并始终坚持这种方法,这也就是此处为什么单独创建一个目录,然后在该目录下执行 cmake 的原因

cmake .. -G"NMake Makefiles"
nmake  

或者


cmake .. -G"MinGW Makefiles"
make  

即可生成可执行程序 hello(.exe)

目录结构


+
| 
+--- main.c
+--- CMakeList.txt
|
/--+ build/
   |
   +--- hello.exe  

cmake 真的不太好用哈,使用cmake的过程,本身也就是一个编程的过程,只有多练才行。

我们先看看:前面提到的这些都是什么呢?

CMakeList.txt

第一行 project 不是强制性的,但最好始终都加上。这一行会引入两个变量

  • HELLO_BINARY_DIR 和 HELLO_SOURCE_DIR

同时,cmake自动定义了两个等价的变量

  • PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR

因为是out-of-source方式构建,所以我们要时刻区分这两个变量对应的目录

可以通过message来输出变量的值


message(${PROJECT_SOURCE_DIR})  

set 命令用来设置变量

add_exectuable 告诉工程生成一个可执行文件。

add_library 则告诉生成一个库文件。

  • 注意:CMakeList.txt 文件中,命令名字是不区分大小写的,而参数和变量是大小写相关的。

cmake命令

cmake 命令后跟一个路径(..),用来指出 CMakeList.txt 所在的位置。

由于系统中可能有多套构建环境,我们可以通过-G来制定生成哪种工程文件,通过 cmake -h 可得到详细信息。

要显示执行构建过程中详细的信息(比如为了得到更详细的出错信息),可以在CMakeList.txt内加入:

  • SET( CMAKE_VERBOSE_MAKEFILE on )

或者执行make时

  • $ make VERBOSE=1

或者

  • $ export VERBOSE=1
  • $ make

例子二

一个源文件的例子一似乎没什么意思,拆成3个文件再试试看:

  • hello.h 头文件

#ifndef DBZHANG_HELLO_
#define DBZHANG_HELLO_
void hello(const char* name);
#endif //DBZHANG_HELLO_  
  • hello.c

#include <stdio.h>
#include "hello.h"

void hello(const char * name)
{
    printf ("Hello %s!/n", name);
}  
  • main.c

#include "hello.h"
int main()
{
    hello("World");
    return 0;
}  
  • 然后准备好CMakeList.txt 文件

 


project(HELLO)
set(SRC_LIST main.c hello.c)
add_executable(hello ${SRC_LIST})  

执行cmake的过程同上,目录结构

 


+
| 
+--- main.c
+--- hello.h
+--- hello.c
+--- CMakeList.txt
|
/--+ build/
   |
   +--- hello.exe  

例子很简单,没什么可说的。

例子三

接前面的例子,我们将 hello.c 生成一个库,然后再使用会怎么样?

改写一下前面的CMakeList.txt文件试试:


project(HELLO)
set(LIB_SRC hello.c)
set(APP_SRC main.c)
add_library(libhello ${LIB_SRC})
add_executable(hello ${APP_SRC})
target_link_libraries(hello libhello)  

和前面相比,我们添加了一个新的目标 libhello,并将其链接进hello程序

然后想前面一样,运行cmake,得到


+
| 
+--- main.c
+--- hello.h
+--- hello.c
+--- CMakeList.txt
|
/--+ build/
   |
   +--- hello.exe
   +--- libhello.lib  

里面有一点不爽,对不?

  • 因为我的可执行程序(add_executable)占据了 hello 这个名字,所以 add_library 就不能使用这个名字了
  • 然后,我们去了个libhello 的名字,这将导致生成的库为 libhello.lib(或 liblibhello.a),很不爽
  • 想生成 hello.lib(或libhello.a) 怎么办?

添加一行


set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")  

就可以了

例子四

在前面,我们成功地使用了库,可是源代码放在同一个路径下,还是不太正规,怎么办呢?分开放呗

我们期待是这样一种结构


+
|
+--- CMakeList.txt
+--+ src/
|  |
|  +--- main.c
|  /--- CMakeList.txt
|
+--+ libhello/
|  |
|  +--- hello.h
|  +--- hello.c
|  /--- CMakeList.txt
|
/--+ build/  

哇,现在需要3个CMakeList.txt 文件了,每个源文件目录都需要一个,还好,每一个都不是太复杂

  • 顶层的CMakeList.txt 文件

project(HELLO)
add_subdirectory(src)
add_subdirectory(libhello)  
  • src 中的 CMakeList.txt 文件

include_directories(${PROJECT_SOURCE_DIR}/libhello)
set(APP_SRC main.c)
add_executable(hello ${APP_SRC})
target_link_libraries(hello libhello)  
  • libhello 中的 CMakeList.txt 文件

set(LIB_SRC hello.c)
add_library(libhello ${LIB_SRC})
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")  

恩,和前面一样,建立一个build目录,在其内运行cmake,然后可以得到

  • build/src/hello.exe
  • build/libhello/hello.lib

回头看看,这次多了点什么,顶层的 CMakeList.txt 文件中使用 add_subdirectory 告诉cmake去子目录寻找新的CMakeList.txt 子文件

在 src 的 CMakeList.txt 文件中,新增加了include_directories,用来指明头文件所在的路径。

例子五

前面还是有一点不爽:如果想让可执行文件在 bin 目录,库文件在 lib 目录怎么办?

就像下面显示的一样:


   + build/
   |
   +--+ bin/
   |  |
   |  /--- hello.exe
   |
   /--+ lib/
      |
      /--- hello.lib  
  • 一种办法:修改顶级的 CMakeList.txt 文件

project(HELLO)
add_subdirectory(src bin)
add_subdirectory(libhello lib)  

不是build中的目录默认和源代码中结构一样么,我们可以指定其对应的目录在build中的名字。

这样一来:build/src 就成了 build/bin 了,可是除了 hello.exe,中间产物也进来了。还不是我们最想要的。

  • 另一种方法:不修改顶级的文件,修改其他两个文件

src/CMakeList.txt 文件


include_directories(${PROJECT_SOURCE_DIR}/libhello)
#link_directories(${PROJECT_BINARY_DIR}/lib)
set(APP_SRC main.c)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
add_executable(hello ${APP_SRC})
target_link_libraries(hello libhello)  

libhello/CMakeList.txt 文件


set(LIB_SRC hello.c)
add_library(libhello ${LIB_SRC})
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")  

例子六

在例子三至五中,我们始终用的静态库,那么用动态库应该更酷一点吧。 试着写一下

如果不考虑windows下,这个例子应该是很简单的,只需要在上个例子的 libhello/CMakeList.txt 文件中的add_library命令中加入一个SHARED参数:


add_library(libhello SHARED ${LIB_SRC})  

可是,我们既然用cmake了,还是兼顾不同的平台吧,于是,事情有点复杂:

  • 修改 hello.h 文件

#ifndef DBZHANG_HELLO_
#define DBZHANG_HELLO_
#if defined _WIN32
    #if LIBHELLO_BUILD
        #define LIBHELLO_API __declspec(dllexport)
    #else
        #define LIBHELLO_API __declspec(dllimport)
    #endif
#else
    #define LIBHELLO_API
#endif
LIBHELLO_API void hello(const char* name);
#endif //DBZHANG_HELLO_  
  • 修改 libhello/CMakeList.txt 文件

set(LIB_SRC hello.c)
add_definitions("-DLIBHELLO_BUILD")
add_library(libhello SHARED ${LIB_SRC})
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")  

恩,剩下来的工作就和原来一样了。

 

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

cmake 学习笔记(一) 的相关文章

  • Linux单片机串口通信总结

    这是一个目录 Linux与单片机串口通信运行ROS串口发送节点后异常中断栈溢出问题catkin make报错 xff1a 函数未定义的引用ERROR L107 ADDRESS SPACE OVERFLOW串口实验总结程序组织串口调试 Lin
  • Apache Options指令详解

    前言 xff1a Options指令是Apache配置文件中一个比较常见也比较重要的指令 xff0c Options指令可以在Apache服务器核心配置 server config 虚拟主机配置 virtual host 特定目录配置 di
  • 欠驱动机械臂运动学仿真

    这是个目录 三轴机械臂建模及运动学仿真各仿真项目的个人理解三轴机械臂 xff08 欠驱动 xff09 分析难点更改RTB中逆解求解源码求解析解数值求解工作空间筛选 实用的解析解法总结 三轴机械臂建模及运动学仿真 在开始具体的机械结构及驱动结
  • postman安装使用教程(标贝科技)

    postman安装使用教程 文章目录 postman安装使用教程前言一 postman安装二 postman使用 前言 postman是Chrome浏览器的插件 xff0c 是一款功能强大的网页调试工具 xff08 接口调试神器 xff09
  • 流媒体推流原理

    我们知道一个完整的直播过程 xff0c 包括采集 处理 编码 封包 推流 传输 转码 分发 解码 播放等 xff0c 这一过程所采用的技术 xff0c 我们也称之为 流媒体技术 其中推流是指使用推流工具等内容抓取软件把直播内容传输到服务器的
  • 机器学习必知必会10大算法!

    Datawhale干货 作者 xff1a Fahim ul Haq xff0c 编译 xff1a InfoQ 现在 xff0c 机器学习有很多算法 如此多的算法 xff0c 可能对于初学者来说 xff0c 是相当不堪重负的 今天 xff0c
  • C语言结构体及链表定义

    最近在看 大话数据结构 xff0c 一边看书一边跑一下书中的案例 xff0c 加深下理解 书中的案例都是C写的 xff0c 顺便熟悉下C语言 此处第三章线性表链式存储 xff1a 在用代码描述单链表之前 xff0c 我们需要定义一个结构体来
  • 【ROS教程 005】ROS可视化

    在ROS系统中它可以通过一些通用工具轻松绘制标量数据图 xff0c 它要求对每一个标量字段数据分别绘制成二维曲线 xff08 1 xff09 用rxplot画出时间趋势曲线 在ROS系统中 xff0c 标量数据可以根据消息中提供的时间戳作为
  • C/C++/Windows/VC/MFC/Unix/Linux编程书籍推荐

    C C 43 43 编程书籍 C Primer Plus C 43 43 Primer C 43 43 Primer Plus C和指针 C陷阱与缺陷 C专家编程 C 43 43 沉思录 C语言深度剖析 Effective C 43 43
  • 使用CPM管理CMake C++工程中的外部依赖库

    严正声明 xff1a 本文系作者davidhopper原创 xff0c 未经许可 xff0c 不得转载 众所周知 xff0c 对于外部依赖库的管理是CMake C 43 43 工程中一个令人头疼的问题 人们一直希望能有一个工具来自动配置CM
  • 字典和集合2:高效性和可哈希

    目录 1 字典和集合的高效性 2 散列表操作 2 1 散列表的写入 2 2 散列表的查找 2 3 散列表的缺点 3 可哈希 1 字典和集合的高效性 许多时候 xff0c 将列表改为字典或集合后 xff0c 执行效率将会有巨大的飞跃 xff0
  • 卡尔曼滤波(Kalman filter)公式推导详细版

    卡尔曼滤波 xff08 Kalman filter xff09 公式推导详细版 记得很早的时候 xff0c 我曾经手工推导过卡尔曼滤波 xff0c 但是之前的已经大多记不起来了 今天帮着老师整理PPT的时候 xff0c 老师让我补充完相应的
  • 4g dtu透传模块

    4g dtu透传模块 xff0c 是一款支持双向透明传输的产品 xff0c 用户使用无需关心复杂的协议 xff0c 产品为双向透传 xff0c 只需要简单配置即可 同时产品为4G全网通 xff0c 支持国内全部运营商网络 xff0c 通讯模
  • PCB设计学习笔记(一)原理图界面

    一 画原理图库 多个引脚可以ctrl 43 c一个引脚后 xff0c 编辑 gt 设置粘贴阵列 xff0c 一次性复制出来多个引脚 二 原理图界面 生成原理图库 xff1a 在一个现成的原理图界面可以直接将现有的原理图内的原件生成一个原理图
  • novatel计算odom--GPS坐标与UTM坐标转换

    保证你的novatel的driver是在ros drivers上的驱动 1 简介 1 1 消息 gps common定义了两个通用消息 xff0c 供GPS驱动程序输出 xff1a gps common GPSFix和gps common
  • 搭建自己的slam系统

    手头有的传感器 一个vlp16线激光雷达 一个120 的fisheye相机 一整套novatel GPS 43 IMU 采集了一个闭环的bag 第一步 数据预处理 将camera的数据单独提取出来 因为没有时间戳 因此无法做到传感器的紧耦合
  • KCF_ROS + TLD_ROS 原理以及源码分析

    扩展链接 xff1a 百度搜素vot2016 xff0c 会有相关的资料 KCF缺点是有边界效应 有一个改进的版本是 xff1a SRDCF 大牛的 CSDN博客 说明 xff1a http blog csdn net app 120620
  • 数据结构+算法=程序

    xff08 1 xff09 数据结构 43 算法 61 程序 每个学计算机的人都听过这个公式 这个公式是尼克劳斯沃斯在1976年出版 算法 43 数据结构 xff1a 程序 一书中提出 尼克劳斯沃斯还是Pascal编程语言的发明人 xff0
  • librealsense源码编译-- Failed to identify Internet connection, disabling BUILD_WITH_TM2

    问题概述 xff1a 由于Realsense t265源码编译需要在CMakeList txt中将BUILD WITH TM2设置为ON xff0c 但是由于国内网络原因 xff0c 无法通过网络连接检测 xff0c 因此我通过查找文件 x
  • 内外网映射环境配置

    一 环境搭建 1 环境说明 此环境由内 外网组成 xff0c 主要实现内外网映射功能 2 环境配置图 本手册中 xff0c 内网使用78 网段 xff0c 外网使用 20 网段 外网交换机IP 地址为 192 168 20 1 3 配置路由

随机推荐

  • 浅析extern “C”的作用

    浅析extern C 的作用 关于extern C 的作用和意思 xff0c 网上资料已经有很多了 xff08 我也参考了几篇 xff09 xff0c 不过我还是觉得有必要自己总结一下 xff0c 毕竟 好记性不如烂笔头 嘛 到C标准函数库
  • 使用prometheus+grafana监控k8s集群

    Prometheus官网地址 xff1a https prometheus io GitHub地址 xff1a https github com prometheus prometheus 一 prometheus的安装 Prometheu
  • ARM 学习笔记(四) 快速上下文切换(FCSE)技术

    接上回说 xff0c 我们已经了解存储器管理的方法 xff0c 现在我们来看一下 xff0c ARM 对不同进程的地址管理 快速上下文切换技术 xff08 Fast Context Switch Extension FCSE xff09 F
  • Linux与Windows串口通信

    串口是常用的计算机与外部串行设备之间的数据传输通道 xff0c 由于串行通信方便易行 xff0c 所以应用广泛 现在国际上不断有串口新技术及新规格推出 xff0c 结合社会各方面需要 xff0c 串口通信发展的空间庞大 串口通讯技术因其自身
  • Git代码下载以及子模块更新git submodule update --init

    Git代码下载 加速代码下载 xff1a git clone https ghproxy com https github com 加入https ghproxy com 后下载速度会快很多 xff0c 还是由于科学上网的问题 子模块下载
  • 解决UnicodeEncodeError: 'gbk' codec can't encode character '\xbb' in position

    在抓取网页上面的一些源代码的时候 xff0c 将uft 8的编码写入文档 xff0c 并输出的时候 xff0c 出现这了这个报错 xff0c 说gbk无法编码 xbb 查找相关资料 xff1a 1 str转bytes叫encode xff0
  • FIFO(First-In First-Out)先进先出页面置换算法详解

    FIFO xff08 First In First Out xff09 先进先出页面置换算法 xff1a FIFO淘汰算法总是淘汰最先装入内存的页面 xff0c 即选择在内存中驻留时间最久的页面进行淘汰 该算法实现只需把一个进程已调入内存的
  • 解决方法:git遇到过的错误

    用git也是走了很多弯路 比如 xff1a 这种错误 1 git commit a fatal Unable to create 39 E git index lock 39 File exists Another git process
  • 路径规划学习入门

    运动规划简介 当虚拟人开始一次漫游时 xff0c 首先全局规划器根据已有的长期信息进行全局静态规划 xff0c 确定虚拟人应该经过的最优化路线 然后全局规划器控制执行系统按照该路径运动 在运动过程中 xff0c 感知系统会持续对周围环境进行
  • 测试开发工程师面试题目

    测试开发工程师面试题目 1 什么是兼容性测试 兼容性测试侧重哪些方面 主要检验的是软件的可移植性 xff0c 检查软件在不同的硬件平台软件平台上是否可以正常的运行 细分会有 xff1a 平台的兼容 xff0c 网络兼容 xff0c 数据库兼
  • 【ROS2】四、使用tf坐标变换实现小海龟跟随

    1 创建功能包 创建工作空间并在工作空间下创建功能包 xff1a span class token function mkdir span p turtle tf ws src span class token builtin class
  • 滑模控制简单理解(hm-1)

    变结构控制 xff08 VSC xff09 是一种特殊的非线性控制器 xff0c 表现为控制的不连续性 xff0c 又称滑模控制 xff08 SMC xff09 一般步骤为滑模面的设计 趋近率的设计 控制器的求解 滑模控制的理解 如图所示
  • BP神经网络的数学本质

    原创文章 xff0c 转载请说明来自 老饼讲解 BP神经网络 xff1a bp bbbdata com 目录 一 隐神经元与tansig函数 二 BP本质 三 BP神经网络的曲线拟合要素 一 误差函数 二 拟合基函数 三 待解参数与求解算法
  • GAZEBO_PLUGIN_PATH 设置方法

    http answers gazebosim org question 13391 how to set gazebo plugin path correctly and add the plugin into gazebo ros Hi
  • Linux 0.11 系统调用的实现机制

    Linux 0 11 系统调用的实现机制 一 系统调用概述 系统调用本质上是一种中断 xff0c 中断号为0x80 xff0c 即128号中断 通常我们使用的是库函数 xff0c 而不是直接使用系统调用 xff0c 这主要是因为库函数一般都
  • 滤波算法及优缺点

    传感器比如关节力矩传感器采用滑动平均滤波算法 xff0c 滤波点数选1则为原始数据 xff0c 选点数100则采样100个求平均 点数越大滤波延迟越大 xff0c 越平滑 所以需要根据实际项目测试 在matlab中采用了三种滤波方法 xff
  • putty支持多标签,支持log每行加时间

    在现在的免费telnet 串口连接工具中 Tera Term 支持脚本ttl 且有每行时间记录 有一个不好的是个终端连接不友好 xff0c 也能用 xff0c 就是看起来不方便 xff0c 是一个外挂的补丁 putty 不支持多标签 不支持
  • Jetson xavier nx 入门系列—— jeston系列性能对比

    官方对比网址 xff1a https developer nvidia com embedded develop hardware family 算力对比 参考 xff1a https blog csdn net u013673476 ar
  • 在C语言中,字符串总是以‘\0‘作为结尾

    字符串结束标志 xff08 划重点 xff09 字符串是一系列连续的字符的组合 xff0c 要想在内存中定位一个字符串 xff0c 除了要知道它的开头 xff0c 还要知道它的结尾 找到字符串的开头很容易 xff0c 知道它的名字 xff0
  • cmake 学习笔记(一)

    最大的Qt4程序群 KDE4 采用cmake作为构建系统Qt4的python绑定 pyside 采用了cmake作为构建系统开源的图像处理库 opencv 采用cmake 作为构建系统 看来不学习一下cmake是不行了 xff0c 一点一点