CMake与MSVC工程化实践

CMake基础

cmake无疑是最流行的c++跨平台构建工具之一,关于cmake入门指南这里不再赘述,官方文档是最好的参考,这里通过一个例子简述构建一个工程常用的函数和变量。

假设此项目有三个文件hello.h、hello.cpp、main.cpp,hello.h和hello.cpp导出一个void hello();的函数,在main.cpp中使用,CMakeList.txt如下:

# 指明当前CMake的版本不能小于指定版本
cmake_minimum_required (VERSION 3.4)
# 工程名称,如果生成msvc工程,这个同样是解决方案名称
project(MyProject) # 将hello.h、hello.cpp保存到${HELLO_SRC}变量中,作为文件列表
file(GLOB HELLO_SRC
hello.h
hello.cpp
)
file(GLOB MAIN_SRC
main.cpp
) # ${HELLO_SRC}生成为一个共享库,在windows系统自然是dll模块
add_library(hello SHARED ${HELLO_SRC}) # ${MAIN_SRC}生成一个可执行程序main.exe/main.out
add_executable(main ${MAIN_SRC}) # 生产目标main的时候指定链接器链接hello模块
target_link_libraries(main hello)

这样便完成了一个非常简单的CMake工程,同时它也包含了我们工程最关注的一些东西,包括生成库文件,生成可执行文件,如何链接库等等。

Debug与Release

有时候我们希望生成带调试信息的库或者可执行文件与正式发布的文件进行区分,最常见的就是把带调试信息的文件后缀加'd',同时为了目录结构的整齐,需要把它们的生成目录进行区分,那么可以参考以下的CMake命令:

# 取消CMake默认生成的工程选项,仅保留Debug与Release(只对msvc这样的多样化构建ide有效)
if(CMAKE_CONFIGURATION_TYPES)
set(CMAKE_CONFIGURATION_TYPES Debug Release)
set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING
"Reset the configurations to what we need"
FORCE)
endif() # 可执行文件生成目录
# ${PROJECT_BINARY_DIR}运行CMake命令的所在目录(用于CMake的分离式编译)
# ${PROJECT_SOURCE_DIR}是工程的根目录(根CMakeList.txt的所在路径)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_BINARY_DIR}/bin/Debug)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_BINARY_DIR}/bin/Release) # 库文件生成目录
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${PROJECT_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${PROJECT_BINARY_DIR}/lib) # 可执行文件后缀
set_target_properties(${TARGET_NAME} PROPERTIES DEBUG_POSTFIX "d") # 库文件后缀
set(CMAKE_DEBUG_POSTFIX "d")

这时候会发现一些有争议的地方,如果库文件带上了'd'后缀,那么target_link_libraries链接库的时候如何分别链接Debug的库和Release的库的呢。可以分两种情况来说明,如果是上文中类似hello库这种在工程内部'声明'的库,那么我们可以不用考虑,仍然链接hello即可,在生成实际的msvc工程时cmake会为我们自动进行区分;如果使用第三方库,就需要特别的选项去区分:

target_link_libraries(main
debug hello
optimized hellod
)

简单的理解debug选项后面表明带调试信息的库就去搜索hellod,而不带调试信息的库就去搜索hello,特别的对于第三方库,需要注意声明库目录,可以参考link_directories

生成MSVC工程

当编写好一个基本的CMake工程后如何与Visual Studio结合使用呢,可以参考cmake -G命令:

# 在执行CMake命令的地方生成visual studio 2017的解决方案(32位构建选项)
cmake -G 'Visual Studio 15 2017' ${PROJECT_SOURCE_DIR}
# 生成vs2015的64位构建方案
cmake -G 'Visual Studio 14 2015 Win64' ${PROJECT_SOURCE_DIR}
# 根据你计算机内最新的visual studio版本生成解决方案
cmake ${PROJECT_SOURCE_DIR}

打开生成的解决方案会发现除了所有的库的可执行文件对应一个project外,还有ALL_BUILD和一个ZERO_CHECK项目,ALL_BUILD顾名思义就是构建所有的项目了。而构建ZERO_CHECK会触发cmake重新检查CMakeList.txt并且重新加载解决方案,这样就避免了修改CMakeList.txt后重新执行命令生成msvc工程的麻烦了,同时还能保留设置的断点、书签等等。

设置Target Platform Version

有时需要指定winsdk的版本,例如设置为8.1:

set(CMAKE_SYSTEM_VERSION 8.1 CACHE TYPE INTERNAL FORCE)

设置Platform Toolset

有时需要指定工具集的版本,例如生成vs2017工程但是使用vs2015的编译链:

cmake -G "Visual Studio 15 2017" -T v140

结束语

上文所述的仅仅是CMake的冰山一角,还有许许多多的功能和选项可以方便我们进行工程文件的管理。

CMake不仅仅是跨平台构建工程的不二选择,就是仅仅使用它来构建windows工程也提供了许多便利,尤其是鉴于visual studio更新比较频繁,如果我们使用cmake管理我们的工程,同时使用标准的c++去开发,那么visual studio版本的迁移也不是一件头疼的事情了~

CMake与MSVC工程化实践的更多相关文章

  1. [vue]webpack&vue组件工程化实践

    [vue]全局组件和局部组件(嵌套+props引用父组件数据) [vue]组件篇 [vue]组件的创建(componet)和销毁(keep-alive缓存)和父子dom同步nextTick [vue] ...

  2. Vue项目架构设计与工程化实践

    摘自Berwin<Vue项目架构设计与工程化实践>github.com/berwin/Blog/issues/14 1.Vue依赖套件 vuex:项目复杂后,用vuex来管理状态 elem ...

  3. 基于 Vue.js 之 iView UI 框架非工程化实践记要 使用 Newtonsoft.Json 操作 JSON 字符串 基于.net core实现项目自动编译、并生成nuget包 webpack + vue 在dev和production模式下的小小区别 这样入门asp.net core 之 静态文件 这样入门asp.net core,如何

    基于 Vue.js 之 iView UI 框架非工程化实践记要   像我们平日里做惯了 Java 或者 .NET 这种后端程序员,对于前端的认识还常常停留在 jQuery 时代,包括其插件在需要时就引 ...

  4. Vue 项目架构设计与工程化实践

    来源 文中会讲述我从0~1搭建一个前后端分离的vue项目详细过程 Feature: 一套很实用的架构设计 通过 cli 工具生成新项目 通过 cli 工具初始化配置文件 编译源码与自动上传CDN Mo ...

  5. 基于 Vue.js 之 iView UI 框架非工程化实践记要

    像我们平日里做惯了 Java 或者 .NET 这种后端程序员,对于前端的认识还常常停留在 jQuery 时代,包括其插件在需要时就引用一下,不需要就删除.故观念使然,尽管 Nuget 和 Maven ...

  6. CMake区分MSVC版本

    MSVC++ 4.x _MSC_VER == 1000 MSVC++ 5.0 _MSC_VER == 1100 MSVC++ 6.0 _MSC_VER == 1200 MSVC++ 7.0 _MSC_ ...

  7. webpack + react 前端工程化实践和暂不极致优化

    技术结构 webpack + react + react-router 功能实现 关于打包 1.基于react-router的自定义打包code split.2.分包异步按需加载.3.CommonsC ...

  8. 《CMake实践》笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE

    <CMake实践>笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE <CMake实践>笔记二:INSTALL/CMAKE_INSTALL_PREFIX &l ...

  9. 《CMake实践》笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE【转】

    本文转载自:http://www.cnblogs.com/52php/p/5681745.html 前言: 开发了5,6年的时间,如果没有KDE4,也许不会有人或者Linux发行版本重视cmake,因 ...

随机推荐

  1. python常用内置模块

    #持续更新 #在使用内置模块的时候需要导入,例如import abc,则导入abc模块,当然模块也可以自己写,相当于一个类,后面放到类里说,这个因为环境闲置,有些无法执行,只能理解了 #os系统操作 ...

  2. Objects聚合分组,统计结果个数(Count)

    参考:http://python.usyiyi.cn/django/topics/db/aggregation.html from django.db.models import Count toda ...

  3. UNIX高级环境编程(13)信号 - 概念、signal函数、可重入函数

    信号就是软中断. 信号提供了异步处理事件的一种方式.例如,用户在终端按下结束进程键,使一个进程提前终止.   1 信号的概念 每一个信号都有一个名字,它们的名字都以SIG打头.例如,每当进程调用了ab ...

  4. TiDB数据库 使用syncer工具同步实时数据

    mysql> select campaign_id ,count(id) from creative_output group by campaign_id; rows min 44.23 se ...

  5. Fix_And_Hold 使用及存在问题

    RTKLIB中使用FIXANDHOLD没有对各个卫星的方差进行排序,仅仅是使用了截止高度角.而大软件中进行了排序后,使用30°的截止角作为hold条件. 1.总卫星数与hold卫星数,及ratio,全 ...

  6. swift语言的特征:类型系统与函数式编程:swift是面向类型和面向函数编程的语言

    swift语言的特征: 类型系统:值类型与引用类型.泛型.协议类型 函数式编程:

  7. 【转】ios tableView那些事(一)创建一个简单的tableView

    工作也有半年多了!几乎每个项目中的会用到tableview这个神奇而好用的控件,在学习和工作中都会看别人的博客!对我有很大的帮助,就如同站在巨人的肩膀上的感觉吧 哈哈!于是决定重新开始写博客,希望能帮 ...

  8. 拯救U盘之——轻松修复U盘“无法访问”的故障

    在使用U盘或者移动硬盘的过程中,大家是否和我一样,有个不好的操作习惯,明知不好但是在每次使用时都很少记得“安全删除硬件”,随手一把走人.终于出问题了,那天给mm复制完资料,拔了再插到自己的电脑上,打开 ...

  9. Android—将Bitmap图片保存到SD卡目录下或者指定目录

    直接上代码就不废话啦 一:保存到SD卡下 File file = new File(Environment.getExternalStorageDirectory(), System.currentT ...

  10. leetcode650—2 Keys Keyboard

    Initially on a notepad only one character 'A' is present. You can perform two operations on this not ...