一起学习CMake – 02

本节介绍如何用CMake来设置软件的版本号

在《一起学习CMake - 01》中我们看到了如何用CMakeLists.txt来构建一个最简单的工程,这一节里我们一起来看看如何用CMake对开发的软件进行版本号的设置。在介绍这方面的内容时,先简单看一下在软件开发中是如何对版本号进行设置的,如VTK 5.6.1,软件当中的版本都表示什么意思。

*******************************************************************************

关于软件版本号的问题
完全的版本号定义,分三项::<主版本号>.<次版本号>.<修订版本号>,如 1.0.0。
版本号升级原则:
主版本号:功能模块有大的变动,比如增加多个模块或者整体架构发生变化。
次版本号:和主版本相对而言,次版本号的升级对应的只是局部的变动。但该局部的变动造成了程序和以前版本不能兼容,或者对该程序以前的协作关系产生了破坏,或者是功能上有大的改进或增强。
修订版本号:局部的变动,主要是局部函数的功能改进,或者bug的修正,或者功能的扩充。
 
1. 各种软件的版本号是怎么确定的,怎样的跨越才能算是由bate到正式版?
原则上,自第一个稳定版本发布后,修订版本号会经常性改动,而次版本号则依情况作改动,主版本号改动的频率很低,除非有大的重构或功能改进。对于小项目而言,甚至可以简化为:>.<次版本号>.<修订版本号>。
版本号比较自由,至于Beta版或者是正式版跟版本号之间并没有任何关系,只要达到正式版的要求的话,即使版本号是1.0或者0.1都可能是正式版的。
* Alpha版: 此版本表示该软件在此阶段主要是以实现软件功能为主,通常只在软件开发者内部交流,一般而言,该版本软件的Bug较多,需要继续修改。
* Beta版: 该版本相对于α版已有了很大的改进,消除了严重的错误,但还是存在着一些缺陷,需要经过多次测试来进一步消除,此版本主要的修改对像是软件的UI。
* RC版: 该版本已经相当成熟了,基本上不存在导致错误的BUG,与即将发行的正式版相差无几。
* Release版: 该版本意味“最终版本”,在前面版本的一系列测试版之后,终归会有一个正式版本,是最终交付用户使用的一个版本。该版本有时也称为标准版。一般情况下,Release不会以单词形式出现在软件封面上,取而代之的是符号(R)。
2. 版本命名规范
软件版本号由四部分组成,第一个1为主版本号,第二个1为子版本号,第三个1为阶段版本号,第四部分为日期版本号加希腊字母版本号,希腊字母版本号共有5种,分别为:base、alpha、beta、RC、release。例如:1.1.1.110108_beta。
3. 版本号定修改规则
* 主版本号(1):当功能模块有较大的变动,比如增加多个模块或者整体架构发生变化。此版本号由项目决定是否修改。
* 子版本号(1):当功能有一定的增加或变化,比如增加了对权限控制、增加自定义视图等功能。此版本号由项目决定是否修改。
* 阶段版本号(1):一般是 Bug 修复或是一些小的变动,要经常发布修订版,时间间隔不限,修复一个严重的bug即可发布一个修订版。此版本号由项目经理决定是否修改。
* 日期版本号(110108):用于记录修改项目的当前日期,每天对项目的修改都需要更改日期版本号。此版本号由开发人员决定是否修改。
* 希腊字母版本号(beta):此版本号用于标注当前版本的软件处于哪个开发阶段,当软件进入到另一个阶段时需要修改此版本号。此版本号由项目决定是否修改。 

*******************************************************************************

详细的关于软件版本号的问题,可以参考百度百科等资料的介绍。下面开始介绍如何用CMake来对自己开发的软件进行版本号的设置。

在第一节所建的目录里,再建立一个空的文件夹:HelloCMake2(在我机子的完整路径是:D:\CMake\CMake-Study\HelloCMake2),然后把HelloCMake里的文件CMakeLists.txt和HelloCMake.cpp两个文件复制到HelloCMake2目录下,打开该目录下的CMakeLists.txt文件,里面的内容应该是:

cmake_minimum_required(VERSION 2.6)

project(HelloCmake)

add_executable(HelloCMake hellocmake.cpp)

接着把它更改为:

cmake_minimum_required(VERSION 2.6)

project(HelloCmake)

# 在CMake里设置HelloCMake软件的主版本号为1,次版本号为0。

set ( HelloCMake_VERSION_MAJOR 1 )

set ( HelloCMake_VERSION_MINOR 0 )

configure_file(

“${PROJECT_SOURCE_DIR}/HelloCMakeConfig.h.in”

“${PROJECT_BINARY_DIR}/HelloCMakeConfig.h”

)

Include_directories (“${PROJECT_BINARY_DIR}”)

add_executable(HelloCMake hellocmake.cpp)

然后在HelloCMake2目录下创建一个文本文件(txt),重命名为”HelloCMakeConfig.h.in”,这里Windows会弹出对话框警告你文件后缀被更改了(原来是***.txt的,现在改为***.in),问题是否继续,点确认更改。

然后用记事本打开HelloCMakeConfig.h.in文件,在里面输入下面的代码:

// the configured options and settings for HelloCMake

#define HelloCMake_VERSION_MAJOR @[email protected]

#define HelloCMake_VERSION_MINOR @[email protected]

到此为止就完成了用CMake对自己的软件进行版本号设置的一些前期工作,接着打开HelloCMake.cpp文件,把HelloCMakeConfig.h文件包含到该源文件中去,然后在里面加入一些打印HelloCMake软件版本号的信息,看看我们在CMake里设置的版本有没有效果,完整的HelloCMake.cpp代码如下:

#include <iostream>

#include "HelloCMakeConfig.h"

int main(int argc, char *argv[])

{

std::cout<<"HelloCMake软件的主版本号是:"

<< HelloCMake_VERSION_MAJOR << std::endl;

std::cout<<"HelloCMake软件的次版本号是:"

<< HelloCMake_VERSION_MINOR << std::endl;

fprintf(stdout, "%s Version is: %d.%d\n",

argv[0],

HelloCMake_VERSION_MAJOR,

HelloCMake_VERSION_MINOR);

std::cout<<"Study CMake Together - HelloCMake2"<<std::endl;

return 0;

}

打开CMake,根据《一起学习CMake - 01》的流程走一遍CMake。在我机子上我把编译目录设置为:D:\CMake\CMake-Study\HelloCMake2-bin。Configure, Generate完了以后打开HelloCMake2-bin目录下的HelloCMake.sln文件,编译链接,你就会看到整个工程能正确地运行了。

接着我们来看看为什么要这么写,里面的每句代码都表示什么意思。首先看看HelloCMake2目录下的CMakeLists.txt文件,与《一起学习CMake - 01》相比较多了下面的代码:

1. # 在CMake里设置HelloCMake软件的主版本号为1,次版本号为0。

2. set ( HelloCMake_VERSION_MAJOR 1 )

3. set ( HelloCMake_VERSION_MINOR 0 )

4. configure_file(

5.    “${PROJECT_SOURCE_DIR}/HelloCMakeConfig.h.in”

6.    “${PROJECT_BINARY_DIR}/HelloCMakeConfig.h”

7.    )

8. Include_directories (“${PROJECT_BINARY_DIR}”)

第1句,注释作用,在CMake里的注释符号是”#”,这里面的注释已经对第2,3句代码的作用说得很清楚了。”set”是CMake的命令,用于定义变量,即定义了HelloCMake_VERSION_MAJOR和HelloCMake_VERSION_MINOR的值分别为1和0。

第4 – 7句代码,意思就是把” ${PROJECT_SOURCE_DIR}”目录下的文件HelloCMakeConfig.h.in用CMake自动生成后的头文件HelloCMakeConfig.h放到目录“${PROJECT_BINARY_DIR}”。 ” ${PROJECT_SOURCE_DIR}”表示的是工程源文件所在的目录,换句话说就是你在CMake的”where is the source code”里设置的路径;同样”  ${ PROJECT_BINARY_DIR }”就是你在CMake的”where to build the binaries”里设置的路径。这两个变量是CMake里预先定义好的,可以直接拿来用。

第8句代码,意思就是把” ${PROJECT_BINARY_DIR}”路径加入到工程头文件的搜索路径中去,这样工程编译链接时就能够找到HelloCMakeConfig.h这个头文件。因为我们在上面一段已经知道,HelloCMakeConfig.h是CMake根据HelloCMakeConfig.h.in文件自动生成的,并且放在” ${PROJECT_BINARY_DIR}”目录下,所以必须把这个路径加到工程的搜索路径中去。加进去以后你会发现编译环境的变化如下图所示。

< xmlnamespace prefix ="v" ns ="urn:schemas-microsoft-com:vml" />

接着来看看HelloCMake2目录下的文件HelloCMakeConfig.h.in里的内容:

// the configured options and settings for HelloCMake

#define HelloCMake_VERSION_MAJOR @HelloCMake_VERSION_MAJOR@

#define HelloCMake_VERSION_MINOR @[email protected]

很简单,只是定义了两个宏,分别是HelloCMake软件的主版本号和次版本号,”//”这一行当然就表示注释了,你可以打开HelloCMake-bin目录下的自动生成后的HelloCMakeConfig.h文件跟HelloCMakeConfig.h.in文件作一下对比,你会发现它们之前太神似了:

// the configured options and settings for HelloCMake

#define HelloCMake_VERSION_MAJOR 1

#define HelloCMake_VERSION_MINOR 0

“@[email protected]”和”@[email protected]”是取值的意思,这两个值已经在CMakeLists.txt里定义过了,CMake配置工程时要去CMakeLists.txt读取内容,当它发现set ( HelloCMake_VERSION_MAJOR 1 )和set ( HelloCMake_VERSION_MINOR 0 )这两句代码时,CMake就知道变量HelloCMake_VERSION_MAJOR/ HelloCMake_VERSION_MINOR值分别为1和0。然后结合HelloCMakeConfig.h.in生成了头文件HelloCMakeConfig.h,并用这两个变量替代“@[email protected]”和”@[email protected]”的值,于是就有了HelloCMakeConfig.h里的内容。

然后我们又在HelloCMake.cpp里包含了头文件”HelloCMakeConfig.h”,也就是定义了HelloCMake_VERSION_MAJOR和HelloCMake_VERSION_MINOR两个宏,接下HelloCMake里就可以肆无忌惮地去引用这两个宏了。

这就是用CMake设置软件版本号的整个过程,上面介绍的过程是我个人的理解,如果有不对的地方一定要告诉我(水灵,MSN:[email protected], QQ:348774226)。

再结合VTK, ITK, IGSTK等开源工具包,可以加深你对用CMake进行软件版本号设置的理解,以VTK为例,在VTK的源文件中肯定有一个文件叫做VTKConfigure.h.in(我这里使用的是VTK 5.6.1版本),在该文件的第165-168行,有如下的代码:

/* Version number.  */

#define VTK_MAJOR_VERSION @[email protected]

#define VTK_MINOR_VERSION @[email protected]

#define VTK_BUILD_VERSION @[email protected]

比较一下跟我们上面提到的HelloCMakeConfig.h.in里的一样吗?

再打开VTK源文件目录下的CMakeLists.txt文件,在第64-67行你会发现有如下代码:

# VTK version number.  An even minor number corresponds to releases.

SET(VTK_MAJOR_VERSION 5)

SET(VTK_MINOR_VERSION 6)

SET(VTK_BUILD_VERSION 1)

再看看这个文件的第1065行开始,有如下代码:

INCLUDE_DIRECTORIES(

${VTK_INCLUDE_DIRS_BUILD_TREE}

${VTK_INCLUDE_DIRS_SOURCE_TREE}

${VTK_INCLUDE_DIRS_BUILD_TREE_CXX}

${VTK_INCLUDE_DIRS_SYSTEM}

)

又比较一下跟我们例子HelloCMake2里的CMakeLists.txt的内容一样吗?

最后再打开VTK的编译目录,你会有里面发现一个文件叫做VTKConfigure.h这个头文件。

用CMake进行软件版本号的设置是不是很简单?只要在CMakeLists.txt里加入一些代码,准备一个YourProjectConfigure.h.in,然后用CMake来构建工程就OK了。

附HelloCMake2程序执行的结果截图:

转自:http://blog.163.com/jacky_ling0/blog/static/13739257120110822137872/

时间: 2024-08-01 16:19:11

一起学习CMake – 02的相关文章

一起学习CMake – 03

这一节我们就一起来看看如何用CMake来链接自己写的lib库,如何进行这些库文件的管理. 一个团队共同开发软件时,一般都是分模块进行作业的,每个人负责整个软件中的一部分,然后再整合成一个完整的软件系统.具体的做法一般是某个人开发的东西是以链接库的形式供团队中的其他人进行调用,或者供本人负责的程序的其他模块进行调用. 比如,A童鞋开发了一种算法,能做数A与数B的加法运算,A童鞋把它编译成lib库的形式给B童鞋调用,提供给B童鞋的就只有该加法运算的头文件(让B童鞋知道这个函数的接口是怎么样的)以及相

【OpenGL 学习笔记02】宽点画线

我们要知道,有三种绘图操作是最基本的:清除窗口,绘制几何图形,绘制光栅化对象. 光栅化对象后面再解释. 1.清除窗口 比如我们可以同时清除颜色缓冲区和深度缓冲区 glClearColor (0.0, 0.0, 0.0, 0.0);//指定颜色缓冲区清除为黑色 glClearDepth(1.0);//指定深度缓冲区的清除值为1.0 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//指定要清除的缓冲区并清除 2.绘制几何图形 先要设置绘制颜色,

SWIFT学习笔记02

1.//下面的这些浮点字面量都等于十进制的12.1875: let decimalDouble = 12.1875 let exponentDouble = 1.21875e1 let hexadecimalDouble = 0xC.3p0//==12+3*(1/16) 2.//类型别名,用typealias关键字来定义类型别名 typealias AudioSample = UInt16 var maxAmplitudeFound = AudioSample.min 3.//元组 let ht

Blender学习笔记 | 02 | 操作

Shift 点击不同图层 同时显示多图层物件 z 切换 Solid / Wireframe 视图模式 点选物件后M 移动到图层选项 Ctrl + 鼠标左键拖动 自由全选物件 B 方形区域圈选物件 Tab Object / Edit Mode 切换 T 开 / 关 侧栏 Ctrl + Tab 编辑状态下切换编辑对象 E Extrude Region 推挤区域.以发现为轴线. X 删除物件菜单 Blender学习笔记 | 02 | 操作,布布扣,bubuko.com

SQL 学习日志02

SQL数据类型 1.字符类型 char   --定长字符数据   如 char(12)  这字段就会占用12字节的空间,无论这个字段只填写了2个字节.一般在可确定这字段长度时选用,如sex字段(因只有男和女两项可选)就可用 char(2). varvhar   --可变长字符数据  如varchar(50) 这字段最大只能填写50字节,按实际填写的字节存储.一般在不确定这字段长度时使用,如 Smail字段(因邮箱的长度不确定) 就可用varchar(50). text    --用来存储大量非统

Rhythmk 学习 Hibernate 02 - Hibernate 之 瞬时状态 离线状态 持久化状态 三状态

by:rhythmk.cnblogs.com 1.Hibernate 三种状态: 1.1.三种定义(个人理解,不一定准确):  瞬时状态(transient):    不被session接管,且不存在数据库中的对象的状态,类似于新New一个对象  离线状态 (detached):    数据库中存在而不被session接管  持久化状态(persistent): 对象被session管理且数据库中存在此对象 1.2. 状态之间转换关系图 2 .状态转换以及Hibernate数据库执行过程详解:

BME学习总结02

//查询数据库的SQL.XML<?xml version="1.0" encoding="UTF-8"?><sqlmap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.huawei.com/bme/schema/namingsql"> <resultMa

mongodb 学习笔记 02 -- CURD操作

mongodb 学习笔记 02 – CURD操作 CURD代表创建(Create).更新(Update).读取(Read)和删除(Delete)操作 创建库 直接 use 库名 然后创建collection 就可以创建库 创建collecion db.createCollection("collectionName") 隐式创建collection db.collectionName.insert({xxxxxx}) 删除collection db.collectionName.dro

软件测试之loadrunner学习笔记-02集合点

loadrunner学习笔记-02集合点 集合点函数可以帮助我们生成有效可控的并发操作.虽然在Controller中多用户负载的Vuser是一起开始运行脚本的,但是由于计算机的串行处理机制,脚本的运行随着时间的推移,并不能完全达到同步.这个时候需要手工的方式让用户在同一时间点上进行操作来测试系统并发处理的能力,而集合点函数就能实现这个功能. 可通过将集合点插入到 Vuser 脚本来指定会合位置.在 Vuser 执行脚本并遇到集合点时,脚本将暂停执行,Vuser 将等待 Controller 或控