当前位置: 首页 > news >正文

CMake 完整入门教程(五)

CMake 使用实例
13.1 例子一
一个经典的 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 的过程,本身也就是一个编程的过程,只有多练才
行。
我们先看看:前面提到的这些都是什么呢?
13.1.1 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 文件中,命令名字是不区分大小写的,而参数和变量是大小写
相关的。
13.1.2 cmake 命令
cmake 命令后跟一个路径 (..) ,用来指出 CMakeList.txt 所在的位置。
由于系统中可能有多套构建环境,我们可以通过 -G 来制定生成哪种工程文件,通
cmake -h 可得到详细信息。 要显示执行构建过程中详细的信息 ( 比如为了得到更详细的出错信息 ) ,可以在
CMakeList.txt 内加入:
SET( CMAKE_VERBOSE_MAKEFILE on )
或者执行 make
$ make VERBOSE=1
或者
$ export VERBOSE=1
$ make
13.2 例子二
一个源文件的例子一似乎没什么意思,拆成 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
例子很简单,没什么可说的。
13.3 例子三
接前面的例子,我们将 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")
就可以了
13.4 例子四
在前面,我们成功地使用了库,可是源代码放在同一个路径下,还是不太正规,怎么办
呢?分开放呗
我们期待是这样一种结构 +
|
+--- 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 ,用来指明头文件所在的路
径。
13.5 例子五
前面还是有一点不爽:如果想让可执行文件在 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")
13.6 例子六
在例子三至五中,我们始终用的静态库,那么用动态库应该更酷一点吧。 试着写一下
如果不考虑 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")
恩,剩下来的工作就和原来一样了。
14 CMake 的局限性
世界上没有完美的东西。 CMake 也有其局限性:
- CMake 并不遵守 GNU 规则。这使得 CMake 对一些开源软件的支持不够。例如,
CMake 生成出的工程在 Linux 下不支持 make uninstall
- CMake 和其他编译系统会打架。处理起来不容易。例如,如果不用 Qt 自带的
QMake ,而是用 CMake 去编译 Qt 工程,那是一件费时费力的事情。
- CMake 不会认识开发者在 IDE 中新增加的文件。必须通过修改 CMakeLists.txt ,才
能让 CMake 知道有新的文件。
15 常用网络资源
15.1 CMake 文档
http://www.cmake.org/cmake/help/v2.8.8/cmake.html
15.2 CMake Wiki
http://www.cmake.org/Wiki/CMake 15.3 CMake 入门
http://zh.wikibooks.org/wiki/CMake_%E5%85%A5%E9%96%80
16 附录
引用资源列表如下。时间仓促,难免有遗漏。如果您发现我引用了你的文章请告知。如果
您不希望您的文章被引用也请告知。可以到我的博客留言
http://blog.csdn.net/dbzhang800/article/details/6314073
http://tzc.is-programmer.com/show/476.html
http://blog.csdn.net/vagrxie/article/details/4743484
http://www.cs.swarthmore.edu/~adanner/tips/cmake.php
http://www.cnblogs.com/doujiu/archive/2009/11/04/1596155.html
http://blog.csdn.net/onion_autotest/article/details/7222954
http://www.cnblogs.com/coderfenghc/archive/2013/01/20/2846621.html
http://blog.csdn.net/gubenpeiyuan/article/details/8667279
http://name5566.com/1795.html
http://blog.sina.com.cn/s/blog_9ce5a1b501015avz.html
http://nullget.sourceforge.net/?q=node/94
http://blog.csdn.net/gubenpeiyuan/article/details/8667035
http://blogs.gnome.org/swilmet/2012/09/05/switch-from-cmake-to-autotools/
http://tech.uc.cn/?p=914

相关文章:

CMake 完整入门教程(五)

CMake 使用实例 13.1 例子一 一个经典的 C 程序&#xff0c;如何用 cmake 来进行构建程序呢&#xff1f; //main.c #include <stdio.h> int main() { printf("Hello World!/n"); return 0; } 编写一个 CMakeList.txt 文件 ( 可看做 cmake 的…...

pgsql中with子句和直接查询差别

1、代码的可读性和维护性&#xff1a; 当查询较为复杂时&#xff0c;WITH子句可以将复杂的查询分解成多个简单的步骤&#xff0c;每个步骤都可以有一个易于理解的名字。这样做提高了代码的可读性&#xff0c;也便于后期维护。 2、代码的重用性&#xff1a; 在WITH子句中定义…...

Day 31 | 贪心算法 理论基础 、455.分发饼干 、 376. 摆动序列 、 53. 最大子序和

理论基础 文章讲解 455.分发饼干 题目 文章讲解 视频讲解 思路&#xff1a;从小饼干开始喂小胃口 class Solution {public int findContentChildren(int[] g, int[] s) {Arrays.sort(g);Arrays.sort(s);int start 0;int count 0;for (int i 0; i < s.length &&a…...

vue3使用is动态切换组件报错Vue received a Component which was made a reactive object.

vue3使用is动态切换组件&#xff0c;activeComponent用ref定义报错 Vue received a Component which was made a reactive object. This can lead to unnecessary performance overhead, and should be avoided by marking the component with markRaw or using shallowRef ins…...

React16源码: React中LegacyContext的源码实现

LegacyContext 老的 contextAPI 也就是我们使用 childContextTypes 这种声明方式来从父节点为它的子树提供 context 内容的这么一种方式遗留的contextAPI 在 react 17 被彻底移除了&#xff0c;就无法使用了那么为什么要彻底移除这个contextAPI的使用方式呢&#xff1f;因为它…...

Gin 框架之jwt 介绍与基本使用

文章目录 一.JWT 介绍二.JWT认证与session认证的区别2.1 基于session认证流程图2.2 基于jwt认证流程图 三. JWT 的构成3.1 header : 头部3.2 payload : 负载3.2.1 标准中注册的声明 (建议但不强制使用)3.2.2 公共的声明3.2.3 私有的声明3.2.4 定义一个payload 3.3 signatrue : …...

从[redis:LinkedList]中学习链表

文章目录 adlistlistNodelistmacros[宏定义]listCreatelistInitNodelistEmptylistReleaselistAddNodeHeadlistLinkNodeHeadlistAddNodeTaillistLinkNodeTaillistInsertNodelistDelNodelistUlinkNodelistIndexredis3.2.100quicklistredis7.2.2quicklist redis的基本数据类型之一…...

Prometheus+grafana配置监控系统

使用docker compose安装 方便拓展, 配置信息都放在在 /docker/prometheus 目录下 1.目录结构如下 . ├── conf │ └── prometheus.yml ├── grafana_data ├── prometheus_data └── prometheus_grafana.yaml2.创建目录文件 mkdir /docker/prometheus &&am…...

Linux之安装配置CentOS 7

一、CentOS简介 CentOS&#xff08;Community Enterprise Operating System&#xff0c;中文意思是社区企业操作系统&#xff09;是Linux发行版之一&#xff0c;它是来自于Red Hat Enterprise Linux依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码&#xff0c…...

神经网络与深度学习Pytorch版 Softmax回归 笔记

Softmax回归 目录 Softmax回归 1. 独热编码 2. Softmax回归的网络架构是一个单层的全连接神经网络。 3. Softmax回归模型概述及其在多分类问题中的应用 4. Softmax运算在多分类问题中的应用及其数学原理 5. 小批量样本分类的矢量计算表达式 6. 交叉熵损失函数 7. 模型预…...

git学习及简单maven打包

前提&#xff1a; 已经有远程仓库地址 和账号密码了 已经安装git了 1.本地新建文件夹A用作本地仓库 2.在A文件夹下右键打开GIT BASH HERE 3.创建用户和密码&#xff0c;方便追踪提交记录 git config --global user.email “caoqingqing0108” //创建邮箱 git config --global …...

如何用MapTalks IDE来发布网站?

简介 MapTalks IDE 全称 MapTalks集成设计环境&#xff08;Integrated Design Environment&#xff09;&#xff0c;是由MapTalks技术团队开发的新一代web地图设计软件。 通过MapTalks IDE&#xff0c;您可以自由的创建二维和三维地图&#xff0c;在其中载入或创建地理数据&a…...

我用selenium开发了一个自动创建任务,解放重复性工作

我用selenium开发了一个自动创建任务&#xff0c;大大解放了我做重复性工作带来的疲惫感&#xff0c;收获了更多的乐趣。 我司有100多个服务&#xff0c;运维忙不过来的时候&#xff0c;就会让我们自己创建云负载&#xff0c;你首先需要在云服务上创建负载&#xff0c;再创建容…...

安卓11修改HDMI自适应分辨率

客户需要hdmi自适应屏幕分辨率&#xff0c;没发现有相关的指令&#xff0c;我发现设置中有个hdmi的Auto选项&#xff0c;于是就试试选中这个选项&#xff0c;试下了可以自适应&#xff0c;于是就找到相关代码&#xff0c;在开机完成后执行这个代码&#xff0c;基本满足需求&…...

Linux实验记录:使用Apache的虚拟主机功能

前言&#xff1a; 本文是一篇关于Linux系统初学者的实验记录。 参考书籍&#xff1a;《Linux就该这么学》 实验环境&#xff1a; VmwareWorkStation 17——虚拟机软件 RedHatEnterpriseLinux[RHEL]8——红帽操作系统 正文&#xff1a; 目录 前言&#xff1a; 正文&…...

分布式空间索引了解与扩展

目录 一、空间索引快速理解 &#xff08;一&#xff09;区域编码 &#xff08;二&#xff09;区域编码检索 &#xff08;三&#xff09;Geohash 编码 &#xff08;四&#xff09;RTree及其变体 二、业内方案选取 三、分布式空间索引架构 &#xff08;一&#xff09;PG数…...

Set和Map的应用场景

Set: 1.成员不能重复 2.只有键值&#xff0c;没有键名&#xff0c;有点类似数组 3.可以遍历&#xff0c;方法 add,delete,has Map: 1.本质上是键值对的集合&#xff0c;类似集合&#xff1b; 2.可以遍历&#xff0c;方法很多&#xff0c;可以干跟各种数据格式转换 Set和…...

小白级教程,10秒开服《幻兽帕鲁》

在帕鲁的世界&#xff0c;你可以选择与神奇的生物「帕鲁」一同享受悠闲的生活&#xff0c;也可以投身于与偷猎者进行生死搏斗的冒险。帕鲁可以进行战斗、繁殖、协助你做农活&#xff0c;也可以为你在工厂工作。你也可以将它们进行售卖&#xff0c;或肢解后食用。 前言 马上过年…...

IDEA 构建开发环境

本博客主要讲解了如何创建一个Maven构建Java项目。&#xff08;本文是创建一个用Maven构建项目的方式&#xff0c;所以需要对Maven有一定的了解&#xff09; IDEA 构建开发环境 一、创建一个空工程二、构建一个普通的Maven模块 一、创建一个空工程 创建一个空的工程 * 设置整…...

归并排序----C语言数据结构

目录 引言 1.归并排序的实现----c2.归并排序的复杂度分析时间复杂度空间复杂度 引言 归并排序&#xff08;Merge Sort) 是一种基于分治法的排序算法&#xff0c;它的基本思想是将原始数组划分成较小的数组&#xff0c;然后递归地对这些小数组进行排序&#xff0c;最后将排好序…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

Reasoning over Uncertain Text by Generative Large Language Models

https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...

在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7

在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤&#xff1a; 第一步&#xff1a; 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为&#xff1a; // 改为 v…...

js 设置3秒后执行

如何在JavaScript中延迟3秒执行操作 在JavaScript中&#xff0c;要设置一个操作在指定延迟后&#xff08;例如3秒&#xff09;执行&#xff0c;可以使用 setTimeout 函数。setTimeout 是JavaScript的核心计时器方法&#xff0c;它接受两个参数&#xff1a; 要执行的函数&…...

Axure零基础跟我学:展开与收回

亲爱的小伙伴,如有帮助请订阅专栏!跟着老师每课一练,系统学习Axure交互设计课程! Axure产品经理精品视频课https://edu.csdn.net/course/detail/40420 课程主题:Axure菜单展开与收回 课程视频:...

Vuex:Vue.js 应用程序的状态管理模式

什么是Vuex&#xff1f; Vuex 是专门为 Vue.js 应用程序开发的状态管理模式 库。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 在大型单页应用中&#xff0c;当多个组件共享状态时&#xff0c;简单的单向数据流…...

比较数据迁移后MySQL数据库和PostgreSQL数据仓库中的表

设计一个MySQL数据库和PostgreSQL数据库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较两…...

MySQL技术内幕1:内容介绍+MySQL编译使用介绍

文章目录 1.整体内容介绍2.下载编译流程2.1 安装编译工具和依赖库2.2 下载编译 3.配置MySQL3.1 数据库初始化3.2 编辑配置文件3.3 启动停止MySQL3.4 登录并修改密码 1.整体内容介绍 MySQL技术系列文章将从MySQL下载编译&#xff0c;使用到MySQL各组件使用原理源码分析&#xf…...