C/C++跨平台构建工具CMake-----在C++源码中读取CMakeLists.txt配置文件中的内容

文章目录

  • 1.需求描述
  • 2.需求准备
    • 2.1 创建项目
    • 2.2 编辑CMakeLists.txt文件
    • 2.3 编写C++文件
    • 2.4 编译构建项目
  • 3.需求实现
    • 3.1 在CMakeLists.txt中输出日志信息
    • 3.2 增加配置生成C++头文件
    • 3.3在C++ 源码中访问配置的值
    • 3.4 C++文件中读取CMakeLists.txt中的字符串
  • 总结

1.需求描述

当我们开发软件项目时,通常会用到版本控制,每个版本都会有不同的修改,因为软件一旦发布给用户,当我们升级版本的时候,必定会出现一些用户的版本会是旧版本,所以每次发布版本的时候都会有一个版本号标识用户的版本,这个版本号一般都是放到构建的配置文件中,比如Android是放到App目录下的build.gradle文件中,而我们使用CMake工具构建的C/C++的项目中,自然是放在CMakeLists.txt配置文件中啦。在CMakeLists.txt中,会用下面的语句声明版本号:

project(Tutorial VERSION 2.11)

这个版本号假设我们想要在我们的C/C++源码中读取出来,并且上传到服务器做埋点标识。直接读取肯定是不行的,因为CMakeLists.txt和C/C++源文件是属于不同的系统。那么需要如何做呢。本文就是介绍如何从CMakeLists.txt中读取我们设置的值(不只是版本号哦),并且能在C/C++源文件中访问。

2.需求准备

2.1 创建项目

创建一个C/C++演示项目,非常简单,找到一个目录,在目录下新建一个文件夹,并按照下图创建号对应的文件:
在这里插入图片描述目录中包含一个build目录,用于存放构建后的产物,一个构建脚本CmakeLists.txt,一个用于读取构建脚本中值的C++源代码文件:readConfigValue.cpp,然后我们使用IDE打开这个目录,也可以直接编写,反正怎么方便怎么来吧,我使用VScode打开。

2.2 编辑CMakeLists.txt文件

在CMakeLists.txt文件下编写下面的语句代码:

#1.设置最小要求的Cmake版本号
cmake_minimum_required(VERSION 3.10)#2.设置项目名称
project(ReadConfigValue)#3.设置项目的版本号,在C++源文件中会读取这个版本号
project(ReadConfigValue VERSION 1.0)#4.设置C++ 的版本,这里选择的是C++11
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)#5.将项目编译成一个可执行文件,Windows上的 .exe文件
add_executable(ReadConfigValue readConfigValue.cpp)

这里只做了基本的配置,主要是先验证下项目是否跑通,后面还会编辑这个文件,完成我们的最终需求。

2.3 编写C++文件

在ReadConfigValue.cpp文件中编写下面的代码:

#include<iostream>
#include<string>int main(int argc,char* argv[]){std::cout<<"Hello CMake"<<std::endl;return 0;
}

2.4 编译构建项目

进入我们创建的项目目录下,进入build目录,打开命令行工具CMD,输入命令:
cmake ..编译项目, 然后输入命令:cmake --build .构建项目
在这里插入图片描述
执行完上面的命令后会在build目录下生成一些编译后的文件和可执行文件:
在这里插入图片描述我们在命令行执行exe文件后输出我们在C++ 源码中输出的信息就证明我们的环境准备好了,示例项目的输出为: Hello CMake

3.需求实现

项目环境准备好后,我们可以开始实现我们的需求了,其实我们熟悉Android Gradle构建脚本的小伙伴可能会注意到,在编写Android程序的时候,我们可以使用一个类叫BuildConfig,这个类就是在编译期间由Android提供的Gradle插件生成的。这里的CMakeLists.txt实现也和Gradle的方法差不多,这里的大致思想是在编译的时候,将我们想给到C++源码中的值放到一个生成的头文件里面,在C++程序中引用这个头文件就可以了。接下来我们看下具体实现:

3.1 在CMakeLists.txt中输出日志信息

在编写CMakeLists.txt文件时,我们常常需要打印一些信息,这里我们使用一个函数:message(STATUS 内容),如下所示:

#1.设置最小要求的Cmake版本号
cmake_minimum_required(VERSION 3.10)#2.设置项目名称
project(ReadConfigValue)#3.设置项目的版本号,在C++源文件中会读取这个版本号
project(ReadConfigValue VERSION 1.0)#4.设置C++ 的版本,这里选择的是C++11
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)#5.将项目编译成一个可执行文件,Windows上的 .exe文件
add_executable(ReadConfigValue readConfigValue.cpp)#6.打印调试信息
message(STATUS "Hello from CMakeLists.txt")
message(STATUS "${PROJECT_BINARY_DIR}")
message(STATUS "${ReadConfigValue_VERSION_MAJOR}")
message(STATUS "${ReadConfigValue_VERSION_MINOR}")

修改完CMakeLists.txt后,进入项目的build目录,输入命令cmake . 会得到下图中的信息:
在这里插入图片描述

3.2 增加配置生成C++头文件

我们如果要实现在C++中读取到CMakeLists.txt中的值,需要先生成头文件。生成头文件我们需要先在根目录下创建一个config.h.in文件,用于配置生成的头文件信息:创建好的文件如下图所示:
在这里插入图片描述然后在CMakeLists.txt文件中添加代码引用我们新创建的配置文件,代码如下所示:

configure_file(config.h.in config.h)

并且在我们创建的config.h.in中配置我们要给C++访问的值,如下所示:

#define ReadConfigValue_VERSION_MAJOR ${ReadConfigValue_VERSION_MAJOR}
// 可以使用@ 或者${}去获取对应的值
#define ReadConfigValue_VERSION_MINOR @ReadConfigValue_VERSION_MINOR@

3.3在C++ 源码中访问配置的值

编写完上面的配置后,我们在readConfigValue.cpp文件中引用config.h头文件

#include<iostream>
#include<string>
#include "config.h"int main(int argc,char* argv[]){std::cout<<"Hello CMake"<<std::endl;std::cout<<"Major version=>"<<ReadConfigValue_VERSION_MAJOR<<std::endl;std::cout<<"Major version=>"<<ReadConfigValue_VERSION_MINOR<<std::endl;return 0;
}

然后我们编译后会得到一个config.h头文件:
在这里插入图片描述头文件中的内容就是我们在CMakeLists.txt文件中配置的值:
在这里插入图片描述

但是当我们构建时会报错:
在这里插入图片描述
原因就是我们的config.h文件生成成功了,但是没有正确的引用到C++源文件中,也就是说include"config.h"找不到config.h的路径,所以我们需要在CMakeLists.txt文件中配置好这个路径,代码如下所示:

target_include_directories(ReadConfigValue PUBLIC "${PROJECT_BINARY_DIR}")

这里的第一个参数是我们的项目名称,第二个参数可以是PUBLIC、PRIVATE、INTERFACE 目前暂时使用PUBLIC就行,最后一个是我们生成的config.h所在目录的路径,我们的config.h实际上是在build目录下的,我们在前面输出的调试信息中也发现${PROJECT_BINARY_DIR}输出的是build目录的路径,所以配置好它就行了

配置完成后我们再编译构建就发现可以运行并且成功读取到CMakeLists.txt文件的值了。
在这里插入图片描述

3.4 C++文件中读取CMakeLists.txt中的字符串

如果我们想要读取CMakeLists.txt文件中的字符串也是可以的,比较简单,首先在CMakeLists.txt中设置我们要给C++源代码文件中读取的字符串:

#.设置字符串给C++文件读取
set(STR_VALUE "I am String from CMakeLists.txt")

在这里插入图片描述如上图所示,需要注意set()语句的位置,不能放在最后否则这个值无法生成
然后再config.h.in中增加配置:

//必须使用双引号,否则在C++源码读取的时候这里没有双引号包裹,会导致读取错误
#define STR_VALUE "@STR_VALUE@"

注意:配置字符串时必须使用双引号包裹我们的取值语句,否则在C++源码读取的时候这里没有双引号包裹,会导致读取错误
然后在C++文件中访问:

#include<iostream>
#include<string>
#include "config.h"int main(int argc,char* argv[]){std::cout<<"Hello CMake"<<std::endl;std::cout<<"Major version=>"<<ReadConfigValue_VERSION_MAJOR<<std::endl;std::cout<<"Major version=>"<<ReadConfigValue_VERSION_MINOR<<std::endl;std::cout<<"String value from CMakeLists.txt==>"<<STR_VALUE<<std::endl;return 0;
}

最后编译运行:
在这里插入图片描述

总结

本文虽然简单,但是在开发中确实有用,比如我们的程序中想要区分debug环境和release环境的时候就可以在CMakeList中添加配置,就像Android 的gradle 插件生成的BuildCongfig类一样,我们可以方便的用这个类的DEBUG和RELEASE来区分开发环境和正式环境,以此来隔离掉一些开发环境的log。所以建议小伙伴们熟悉这种使用方法。对开发会很有用哦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/148567.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

国庆发生的那些事儿------编写了炫酷的HTML动态鼠标特效,超级炫酷酷酷!

文章目录 前言具体操作总结 前言 国庆假期的欢乐&#xff0c;当然少不了编码爱好者&#xff01;假期编写了炫酷的HTML动态鼠标特效&#xff0c;超级炫酷酷酷&#xff01;让你的页面变得更加炫酷&#xff0c;让你的小伙伴们羡慕的大神编码&#xff01;快来看看大神是如何编写的…

Llama2-Chinese项目:6-模型评测

测试问题筛选自AtomBulb[1]&#xff0c;共95个测试问题&#xff0c;包含&#xff1a;通用知识、语言理解、创作能力、逻辑推理、代码编程、工作技能、使用工具、人格特征八个大的类别。 1.测试中的Prompt   例如对于问题"列出5种可以改善睡眠质量的方法"&#xff…

【Java】微服务——Nacos注册中心

目录 1.Nacos快速入门1.1.服务注册到nacos1&#xff09;引入依赖2&#xff09;配置nacos地址3&#xff09;重启 2.服务分级存储模型2.1.给user-service配置集群2.2.同集群优先的负载均衡 3.权重配置4.环境隔离4.1.创建namespace4.2.给微服务配置namespace 5.Nacos与Eureka的区别…

【Spring】更简单的读取和存储对象

更简单的读取和存储对象 一. 存储 Bean 对象1. 前置工作&#xff1a;配置扫描路径2. 添加注解存储 Bean 对象Controller&#xff08;控制器存储&#xff09;Service&#xff08;服务存储&#xff09;Repository&#xff08;仓库存储&#xff09;Component&#xff08;组件存储&…

Java类型转换和类型提升

目录 一、类型转换 1.1 自动类型转换&#xff08;隐式&#xff09; 1.1.1 int 与 long 之间 1.1.2 float 与 double 之间 1.1.3 int 与 byte 之间 1.2 强制类型转换&#xff08;显示&#xff09; 1.2.1 int 与 long 之间 1.2.2 float 与 double 之间 1.2.3 int 与 d…

云安全之访问控制的常见攻击及防御

访问控制攻击概述 访问控制漏洞即应用程序允许攻击者执行或者访问某种攻击者不具备相应权限的功能或资源。 常见的访问控制可以分为垂直访问控制、水平访问控制及多阶段访问控制 (上下文相关访问控制)&#xff0c;与其相应的访问控制漏洞为也垂直越权漏洞(普通用户可以访问或…

《Attention Is All You Need》论文笔记

下面是对《Attention Is All You Need》这篇论文的浅读。 参考文献&#xff1a; 李沐论文带读 HarvardNLP 《哈工大基于预训练模型的方法》 下面是对这篇论文的初步概览&#xff1a; 对Seq2Seq模型、Transformer的概括&#xff1a; 下面是蒟蒻在阅读完这篇论文后做的一…

Modelsim测试覆盖率操作说明

1、打开Project窗口界面 2、在project界面下&#xff0c;选中所有需要测试覆盖率的.v文件&#xff08;不包括tb文件&#xff09;&#xff0c;鼠标点击右键&#xff0c;在Properties选项中选择Coverage选项&#xff0c;选择需要测试的覆盖率类型 3、重新编译所有的源文件&#x…

一看就懂系列:阿里云服务器ECS和轻量云服务器对比

阿里云服务器ECS和轻量应用服务器有什么区别&#xff1f;轻量和ECS优缺点对比&#xff0c;云服务器ECS是明星级云产品&#xff0c;适合企业专业级的使用场景&#xff0c;轻量应用服务器是在ECS的基础上推出的轻量级云服务器&#xff0c;适合个人开发者单机应用访问量不高的网站…

《机器人SLAM导航核心技术与实战》第1季:第6章_机器人底盘

视频讲解 【第1季】6.第6章_机器人底盘-视频讲解 【第1季】6.1.第6章_机器人底盘_底盘运动学模型-视频讲解 【第1季】6.2.第6章_机器人底盘_底盘性能指标-视频讲解 【第1季】6.3.第6章_机器人底盘_典型机器人底盘搭建-视频讲解 第1季&#xff1a;第6章_机器人底盘 先 导 课…

Endnote 20 修改参考文献(References)的期刊全称为缩写

一、准备&#xff08;下载&#xff09;所需要的期刊缩写列表 &#xff08;Term Lists&#xff09; 我已经下载并上传了一份Trem Lists 链接: 在不列颠哥伦比亚大学图书馆网站导出所有期刊名和缩写&#xff0c;大概1W的期刊名字&#xff0c;期刊名字和缩写截至2021.12.03 哥伦…

Adobe_InDesign_2023_18.4.0.056图文安装教程及下载

Adobe InDesign是Adobe公司的一个桌面出版 (DTP)应用程序&#xff0c;简称“Id”,主要用于各种印刷品的排版编辑。InDesign是一款功能强大的出版物创作、排版和打印软件&#xff0c;可以帮助出版物和广告创作者提高效率&#xff0c;节省时间&#xff0c;改善印刷质量。InDesign…

大模型部署手记(2)baichuan2+Windows GPU

1.简介 组织机构&#xff1a;百川智能&#xff08;前搜狗CEO王小川创立&#xff09; 代码仓&#xff1a;GitHub - baichuan-inc/Baichuan2: A series of large language models developed by Baichuan Intelligent Technology 模型&#xff1a;baichuan-inc/Baichuan2-7B-Ch…

JavaScript Web APIs第一天笔记

复习&#xff1a; splice() 方法用于添加或删除数组中的元素。 **注意&#xff1a;**这种方法会改变原始数组。 删除数组&#xff1a; splice(起始位置&#xff0c; 删除的个数) 比如&#xff1a;1 let arr [red, green, blue] arr.splice(1,1) // 删除green元素 consol…

MyBatisCodeHelper Pro3.x新版本插件自由

1效果图 我的版本为3.2.2 2.资源链接 码云地址点这里 3.使用说明 将我修改好后的MyBatisCodeHelper-Pro-obfuss.jar替换MybatisCodeHelperNew-3.x.x.zip&#xff08;原版本插件&#xff09;\MyBatisCodeHelper-Pro\lib中的MyBatisCodeHelper-Pro-obfuss.jar 4.实现与感谢…

MySQL5.7版本与8.0版本在Ubuntu(WSL环境)系统安装

目录 前提条件 1. MySQL5.7版本在Ubuntu&#xff08;WSL环境&#xff09;系统安装 1. 1 下载apt仓库文件 1.2 配置apt仓库 1.3 更新apt仓库的信息 1.4 检查是否成功配置MySQL5.7的仓库 5. 安装MySQL5.7 1.6 启动MySQL 1.7 对MySQL进行初始化 1.7.1 输入密码 …

长剖与贪心+树上反悔贪心:1004T4

长剖的本质是一种贪心。&#xff08;启发式合并本质也是类似哈夫曼树的过程&#xff09; 在此题中&#xff0c;首先肯定变直径&#xff0c;然后选端点为根。然后选叶子。而每个叶子为了不重复计算&#xff0c;可以只计算其长剖后所在链的贡献。&#xff08;本题精髓&#xff0…

JAVAWeb业务层开发->普通和基于MP

普通方式业务层开发 service定义接口&#xff08;主要实现逻辑层面的业务功能&#xff09; serviceImpl实现该接口 注意事项&#xff1a; 逻辑判断的代码可以使用&#xff1e;号&#xff0c;使得返回结果为布尔类型。 小结&#xff1a;每一个接口写完都要写测试类去检测&#…

uni-app:canvas-绘制图形2

效果 代码 <template><view><!-- 创建了一个宽度为300像素&#xff0c;高度为200像素的canvas元素。canvas-id属性被设置为"firstCanvas"&#xff0c;可以用来在JavaScript中获取该canvas元素的上下文对象。 --><canvas style"width:200px…

分布式事务-Seata

一、理论基础 1、CAP定理 1998年&#xff0c;加州大学的计算机科学家 Eric Brewer 提出&#xff0c;分布式系统有三个指标&#xff1a; • Consistency &#xff08;一致性&#xff09; • Availability &#xff08;可用性&#xff09; • Partition tolerance &#xff08…