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. 【转】Linxu学习---top实践

    [原文]https://www.toutiao.com/i6591053058258502147/ 在实际开发中,有时候会收到一些服务的监控报警,比如CPU飙高,内存飙高等,这个时候,我们会登录到服务 ...

  2. 【转】HTTP学习---图解HTTP[三次握手&&ISO模型]

    [转]https://www.toutiao.com/i6592556686068679182/ 首先了解一次完整的HTTP请求到响应的过程需要的步骤: 1. 域名解析 2. 发起TCP的3次握手 3 ...

  3. 49_分析代理类的作用与原理及AOP概念

    生活中的代理 武汉人从武汉的代理商手中买联想电脑和直接跑到北京传智播客旁边来找联想总部买电脑,你觉得最终的主体业务目标有什么区别吗?基本上一样吧,都解决了核心问题,但是,一点区别都没有吗?从代理商那里 ...

  4. CreateEvent

    事件对象就像一个开关:它只有两种状态---开和关.当一个事件处于”开”状态,我们称其为”有信号”否则称为”无信号”.可以在一个线程的执行函数中创建一个事件对象,然后观察它的状态,如果是”无信号”就让该 ...

  5. BeanDefinition及其实现类

    [转自 http://blog.csdn.net/u011179993 ]   目录(?)[+]   一. BeanDefinition及其实现类 BeanDefinition接口 这个接口描述bea ...

  6. 旋转的地球css3

    css3果然博大精深: 1.代码里面还有用box-shadow制作椭圆形阴影的效果,厉害了!之前找了好久都没找到,今天给找到了 html: <section class="stage& ...

  7. 《Linux大棚命令百篇下》网络篇的总结

    本文是<Linux大棚命令百篇下>网络篇的总结 ping -c 指定数量,在windows下会自动停止,linux下会一直ping下去 -q 简短报告 -s 指定每次ping的数据包大小, ...

  8. 使用react-navigation时报错:undefined is not an object (evaluating rngesturehandlermodule.direction)

    问题: 使用react-navigation时报错:undefined is not an object (evaluating rngesturehandlermodule.direction). ...

  9. Android 写一个Activity之间来回跳转的全局工具类(主要是想实现代码的复用)

    废话不多说了,直接上代码,相信大家都能看得懂的. 一.主要工具类 package com.yw.chat.utils; import android.app.Activity; import andr ...

  10. OpenGL笔记(二) 渲染管线

    GLSL着色器代码分为两个部分,即Vertex Shader(顶点着色器)与Fragment Shader(片元着色器). 上下文环境搭建 OGL不负责窗口管理与上下文环境管理,该职责由平台完成.在A ...