初识CMake,如何编写一个CMake工程(下)
如何编写一个CMake工程
- 上文分析了针对一个源文件、多个源文件、多个目录的情况
- 1 CMake自定义编译选项Demo4
- 1.1 效果展示
- 2 CMake安装(make install)与测试(make test)Demo5
- 2.1 安装(make install)
- 2.2 测试(make test)
- 3 配置Debug,添加版本号Demo6
- 3.1 Debug/Release配置
- 3.2 添加版本号
初识CMake,如何编写一个CMake工程(上)
https://blog.csdn.net/weixin_39956356/article/details/115253373
上文分析了针对一个源文件、多个源文件、多个目录的情况
接下来会继续分享自定义编译选项、安装与测试、生成安装包、环境检查等内容
1 CMake自定义编译选项Demo4
如下图,如何实现如下效果,当然,这是很常见的。
首先,应该添加一个宏名–USE_MYMATH,使用option(宏名 描述 默认值)
,如上图,默认值是ON
option(USE_MYMATH "use provided math implementation" ON)# 加入一个配置头文件config.h.in,用于编译选项的设置,注意这个文件必须用户提前建立,否则编译错误--找不到该文件
configure_file("${PROJECT_SOURCE_DIR}/config.h.in""${PROJECT_BINARY_DIR}/config.h"
)
进而,一种想法油然而生,条件编译,为了适应不同的平台、不同操作系统、不同系统环境。使用条件编译就会让CMake编译出适应当前环境、当前操作系统、当前平台的可执行程序。
目标:我们自己写了一个计算次方的函数,当然系统math.h也有,通过USE_MYMATH来选择是否使用自己的函数?
下面的代码,利用USE_MYMATH
进行条件编译,
- 指示应该包含的头文件路径
include_directories
- 需要编译math文件夹
add_subdirectory
,生成的库名是mathfun - 最后将
mathfun
赋值给EXTRA_LIBS
,主要是方便最后的链接,如果利用系统的math.h,那么EXTRA_LIBS
就是空啦
# 是否加入mathfun
if (USE_MYMATH)# include_directories("${PROJECT_SOURCE_DIR}/math")add_subdirectory(math) # 编译其他文件夹的源代码set(EXTRA_LIBS mathfun)
endif(USE_MYMATH)# 编译当前目录下的源文件
aux_source_directory(. DIR_SRC)
add_executable(Demo ${DIR_SRC})# 链接其他文件夹下的动态、静态库
target_link_libraries(Demo ${EXTRA_LIBS})
这时候main.cc需要对应的修改,逻辑上,如果定义了USE_MYMATH
,就是用自己的头文件,进而计算一个次方。
注意
1. 这里最重要的是包含了一个#include "config.h"
,尤其注意,这个文件是CMake自动生成的,而且必须包含进来,否则怎么也不会使用自己的函数库mathfun
流程
编程人员需要建立一个config.h.in
文件,并配置好,CMake通过这个文件自动生成config.h
,最后由用户包含进main中
#include <stdio.h>
#include <stdlib.h>
#include "config.h"#ifdef USE_MYMATH#include "math/MathFunctions.h"
#else#include <math.h>
#endifint main(int argc, char *argv[])
{if (argc < 3){printf("Usage: %s base exponent \n", argv[0]);return 1;}double base = atof(argv[1]);int exponent = atoi(argv[2]);#ifdef USE_MYMATHprintf("Now we use our own Math library. \n");double result = power(base, exponent);
#elseprintf("Now we use the standard library. \n");double result = pow(base, exponent);
#endifprintf("%g ^ %d is %g\n", base, exponent, result);return 0;
}
1.1 效果展示
工程结构
.
├── CMakeLists.txt
├── config.h.in-------------(提前创建并写入配置,不然会报错)
├── main.cc
└── math├── CMakeLists.txt├── MathFunctions.cc└── MathFunctions.h
首先配置config.h.in,告诉CMake我们需要使用宏名USE_MYMATH
// 表示启用宏名USE_MYMATH,而且会在config.h中自动加入对应代码
#cmakedefine USE_MYMATH
目标:想使用自己的库?
有图形界面的同学可以修改图中ON或者OFF,观察输出。没有直接在源码修改即可
option(USE_MYMATH "use provided math implementation" ON) # 修改ON或者OFF
自动生成的config.h
// 表示启用宏名USE_MYMATH,而且会在config.h中自动加入对应代码
#define USE_MYMATH
结果:和预期相同,使用自己函数库
➜ Demo4 git:(master) ✗ ./Demo 2 6
Now we use our own Math library.
2 ^ 6 is 64
假如我想使用系统库?
自动生成的config.h
// 表示启用宏名USE_MYMATH,而且会在config.h中自动加入对应代码
/* #undef USE_MYMATH */
结果:和预期相同,使用自己库函数
➜ Demo4 git:(master) ✗ ./Demo 5 6
Now we use the standard library.
5 ^ 6 is 15625
细心的同学会发现,使用math系统库的时候,连mathfun都没有编译,这是符合实际的。不是使用谁就去链接谁,而是不使用编译都不会
2 CMake安装(make install)与测试(make test)Demo5
一个软件在编译成功需要安装到用户的系统中,同时还可以测试一些简单的案例。现在分享下怎么实现的。
首先
install和test是Makefile(名字只有两种写法,这是一种,不要乱写)伪目标
,CMake通过简单的语法就可以帮助自动在Makefile生成这些伪目标。
2.1 安装(make install)
安装是一个复杂的过程,因为需要拷贝所有的头文件、静态/动态库到系统的目录中,同时需要提升权限。
头文件散落在各种目录下,需要一个不多一个不少的拷贝
,当然这不是本文的重心,下面就简单示意下
使用install()
就可以执行安装操作,其实就是一个拷贝的过程,当然,拷贝对象不是单一的,可能有单一文件
或者目录
等。CMake提供不同的关键字
比如,拷贝文件–拷贝指定文件到指定目标,DESTINATION
后面是目标目录,同理TARGETS。
更多的信息可以参考官方,或者学习经典的openCV、openVINO等开源工程的使用方法
install(FILES 源文件 DESTINATION 目标目录)
# 安装(make isntall)
# Installing Targets
install(TARGETS Demo DESTINATION bin)
# Installing Files
install(FILES "${PROJECT_BINARY_DIR}/config.h" DESTINATION include)
使用
- 先编译哈,
cmake . && make
- 安装,记得提升权限
sudo make install
➜ Demo5 git:(master) ✗ sudo make install
[sudo] password for topeet:
[ 50%] Built target mathfun
[100%] Built target Demo
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/bin/Demo
-- Installing: /usr/local/include/config.h
2.2 测试(make test)
废话不多说,直接看模板
- 使用测试功能
enable_testing
- 添加测试用例
add_test
- 和预设值比对
set_tests_properties
,PROPERTIES PASS_REGULAR_EXPRESSION "is 25"
通过表达式值是26—FAILED
# 测试(make test)--相同的测试案例会自动忽略
# 使能测试
enable_testing()# 3号测试,结果是25,其他都会失败
add_test(test_5_2 Demo 5 2)
set_tests_properties(test_5_2 PROPERTIES PASS_REGULAR_EXPRESSION "is 26") # 不写is也可以,会自动匹配答案
output
Start 3: test_5_2
3/7 Test #3: test_5_2 .........................***Failed Required regular expression not found.Regex=[26
当然比还可以写很多测试,但是这就很繁琐了。。。
如何简化工作,使用宏函数macro
,也就是一个函数咯
- 注意语法形式,do_test是宏函数名字
- arg1 arg2 result表示两个输入,一个结果。注意CMake语法中都没有逗号,因为它不是函数,是宏,说函数好理解,
- ${arg1}表示取arg1的值,CMake支持shell语法
# 大量测试--定义一个宏,简化测试工作
macro(do_test arg1 arg2 result)add_test(test_${arg1}_${arg2} Demo ${arg1} ${arg2})set_tests_properties(test_${arg1}_${arg2} PROPERTIES PASS_REGULAR_EXPRESSION ${result})
endmacro(do_test)do_test(5 3 "is 125")
do_test(2 9 "is 512")
do_test(10 5 "is 100000")
注意,一摸一样的测试案例,是不会执行的
3 配置Debug,添加版本号Demo6
CMake编译的程序支持Debug/Release,也支持版本管理
3.1 Debug/Release配置
结果大家可以测试,Debug加了调试信息,Demo会大些
,可以验证是否出错
CMAKE_BUILD_TYPE
取Debug/Release- 实际上是靠
CMAKE_CXX_FLAGS_DEBUG
也即是gcc编译参数,-g即生成调试,最低优化(不优化),-wall表示让编译时能显示更多的错误信息,,,使其编译更准确,,,
- 其他的编译参数可以参考gcc官方文档
# 1 版本配置,Debug生成的文件会大些
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
# set(CMAKE_BUILD_TYPE "Release")
# set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
3.2 添加版本号
先自定义两个主次版本号的宏名Demo_VERSION_MAJOR
、Demo_VERSION_MINOR
后在config.h.in写入配置
最后使用
- 根CMakeLists.txt
# 2 添加版本号,还需要再config.h.in添加宏定义
set(Demo_VERSION_MAJOR 1)
set(Demo_VERSION_MINOR 0)
- 配置config.h.in
// 版本号的宏定义
#define Demo_VERSION_MAJOR @Demo_VERSION_MAJOR@
#define Demo_VERSION_MINOR @Demo_VERSION_MINOR@
- main.cc
if (argc < 3){// print version infoprintf("%s Version %d.%d\n",argv[0],Demo_VERSION_MAJOR,Demo_VERSION_MINOR);printf("Usage: %s base exponent \n", argv[0]);return 1;}
一个案例
./Demo Version 1.0
Usage: ./Demo base exponent
初识CMake,如何编写一个CMake工程(下)相关推荐
- 初识CMake,如何编写一个CMake工程(上)
如何编写一个CMake工程 笔者想分享CMake工程的原因? 1 接触CMake 1.1 认识CMake被广泛的使用? 1.2 了解CMake运行流程 1.3 Make和Makefile是什么关系? ...
- 【ceph】cmake管理Ceph编译+Ceph工程目录+cmake 实战学习
前言 Ceph cmake 工程 cmake生成的目录 cmake工程添加新模块(CMakeLists.txt) 添加动态库依赖 cmake导入外部链接库 *.cmake文件 cmake生成编译DEB ...
- Cmake知识----编写CMakeLists.txt文件编译C/C++程序
1.CMake编译原理 CMake是一种跨平台编译工具,比make更为高级,使用起来要方便得多.CMake主要是编写CMakeLists.txt文件,然后用cmake命令将CMakeLists.txt ...
- linux cmake 编译项目,使用CMake构建复杂工程
0. 什么是CMake CMake是一个跨平台的编译.安装.测试以及打包工具:CMake不直接编译软件,而是结合原生构建系统来构建软件.CMake配置文件是CMakeList.txt文件(每个源码文件 ...
- (CMake) 从下载到构建第一个CMake应用
文章目录 前言 下载和配置 下载 配置 第一个demo 创建基本项目结构 基本code 生成项目 构建 常用指令 总Code 变量 函数 message() 输出信息 cmake_minimum_re ...
- 从零开始自制实现WebServer(十六)---- 学习新工具CMake自动编写MakeFile 分门别类整理源文件心情愉悦
文章目录 全流程实现博客链接 前引 (十六)---- 学习新工具CMake自动编写MakeFile 小改小动项目接近尾声 1.学习新工具 cmake / shell脚本 需要耐心与时间 2.分门别类整 ...
- 一步一步SharePoint 2007之二十三:编写一个最简单的WebPart(1)——创建工程
摘要 在前面的文章中,我们讲解了很多基础的内容,主要包括安装配置.Form认证等.可能这些对很多朋友来说,是太容易了.那么,从下一篇文章开始,就让我们进入SharePoint的高级课题之旅吧. 本篇文 ...
- Linux下CMake简明教程(三)同一目录下多个源文件
如果在同一目录下有多个源文件,那么只要在add_executable里把所有源文件都添加进去就可以了.但是如果有一百个源文件,再这样做就有点坑了,无法体现cmake的优越性,cmake提供了一个命令可 ...
- 记录一个CMake编译报错undefined reference to vtable问题的解决
在编写一个简单的CMake demo: 问题描述 文件结构如下:头文件和cpp分别放在两个文件夹下面 如果使用下面的写法,会报错"undefined reference to vtable ...
最新文章
- 使用NPOI时ICSharpCode.SharpZipLib版本冲突问题解决
- [导入]微软研究院Detour开发包之API拦截技术
- 【MM】更改供应商账户组
- 关于管理的十个经典故事
- 把wasm反编译出来
- Vmware+Virtualbox+Ubuntu+debian+USB转串口+kermit
- Spring源码之bean的初始化initializeBean方法解读
- WORD排版视频教程
- 英语四六级听力调频广播电台方案
- 塔防类游戏实现(一)
- 新思课堂C语言答案,新思课堂APP最新版下载_新思课堂APP官方版1.6.8下载_QQ下载站...
- 北大元培学院数学与计算机,通识教育试验的尴尬 北京大学元培学院近距离观察...
- 西南大学2019春计算机作业答案,2019年西南大学作业答案[1175]《仪器分析》
- python序列的应用
- Android 学习笔记(十二):安卓中的事件分发机制
- 学会这三招引流方法,让你的淘宝店铺流量暴增
- web前端基础——第八章
- Jupyter 是什么
- 聊一聊IT行业哪个专业工资高?
- Excel快速对比两列数据
热门文章
- 什么学习软件需要身份证验证_什么是两层身份验证,为什么我需要它?
- 粉丝时代,明星不需要公关?
- 三极管类型及工作状态判断
- [笔记]n个点的基环树数量
- python绘制幂函数曲线_基于matplotlib的yaxis力指数幂函数
- Uncaught SyntaxError: The requested module ‘/node_modules/.vite/vue.js?v=bd1817bb‘ does not provide
- java设计模式-观察者模式和中介者模式的异同
- Redis学习之incr命令
- python_练习2:输入a,b,c,d 4个整数,计算a+b-c*d的结果
- 旋转矩阵、欧拉角、旋转矢量及四元数的介绍和工程应用