(转)Windows上使用CMake
CMake简介
原文:http://blog.gclxry.com/use-cmake-on-windows/
你或许听过好几种 Make 工具,例如 GNU Make ,QT 的 qmake ,微软的 MS nmake,BSD Make(pmake),Makepp,等等。这些 Make 工具遵循着不同的规范和标准,所执行的 Makefile 格式也千差万别。这样就带来了一个严峻的问题:如果软件想跨平台,必须要保证能够在不同平台编译。而如果使用上面的 Make 工具,就得为每一种标准写一次 Makefile ,这将是一件让人抓狂的工作。
CMake就是针对上面问题所设计的工具:它首先允许开发者编写一种平台无关的 CMakeList.txt 文件来定制整个编译流程,然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件,如 Unix 的 Makefile 或 Windows 的 Visual Studio 工程。从而做到“Write once, run everywhere”。
Windows上使用CMake
Windows上使用CMake也很方便,除了传统的命令行方式使用CMake,还有一个简单的GUI程序cmake-gui.exe来使用CMake。
安装CMake
Windows上安装CMake很简单,去https://cmake.org/ 上面下载最新的CMake安装包就可以了。安装的时候还可以选择是否把CMake加到系统的PATH中,如下图所示:

为了方便起见,可以把CMake加到系统PATH中。
CMake的GUI用法
安装好CMake,会创建一个快捷方式,点击运行就会运行CMake-gui.exe,这个是CMake的GUI程序,以下图所示:

source code编辑框就是输入代码的所在的路径,这个路径能够找到一个CMakeLists.txt文件。
build the binaries编辑框就是编译输出的中间文件和最终的二进制文件的目录。
因为CMake最终通过CMakeLists.txt文件生成Windows上对应的vs工程文件,不同的vs版本也会影响到最终生成vs工程文件,所以configure对话框就是选择代码编译工具的,如图所示:

下面以google test工程的代码为例来使用CMake-gui,输入google test对应的路径,点击Generate按钮就会在E:/googletest/googletest/build目录生成vs编译工程文件:


用vs打开gtest.sln文件,就可以编译google test代码了。
CMake的命令行用法
CMake的命令行用法比GUI的用法复杂,但是功能更加强大,值得一学。以下是CMake命令行调用的方法:
|
1
2
3
4
5
|
cmake [<options>] (<path-to-source> | <path-to-existing-build>)
cmake [(-D<var>=<value>)...] -P <cmake-script-file>
cmake --build <dir> [<options>] [-- <build-tool-options>...]
cmake -E <command> [<options>...]
cmake --find-package <options>...
|
生成编译工程文件
cmake <CMakeLists.txt_Path>就是生成可以编译工程文件。当时运行的目录在哪里,生成的可编译工程文件就在哪个目录。比如CMakeLists.txt文件在f:cmake目录,而当时在f:cmakebuild目录运行cmake ..,则生成的编译工程文件在f:cmakebuild目录。
也可以再生成编译工程文件的时候通过-D来添加变量值,比如CMakeLists.txt内容如下:
|
1
2
3
4
|
cmake_minimum_required (VERSION 2.6)
project (a)
message(${EXECUTABLE_OUTPUT_PATH})
add_executable(b b.cpp)
|
我们可以通过-D选择来设置EXECUTABLE_OUTPUT_PATH的值,也是编译的文件的输出目录:
|
1
|
cmake -D EXECUTABLE_OUTPUT_PATH="another_output" ..
|
这样,我们就给CMakeLists.txt编译脚本传递了新的EXECUTABLE_OUTPUT_PATH值。
编译工程
CMake除了生成编译工程文件,它也可以调用系统的编译工程来编译工程,如:
|
1
|
cmake --build .
|
默认是编译debug模式,也可以传递在–后面传递MSBUILD参数来控制:
|
1
|
cmake --build . -- /p:Configuration=Release
|
命令行工具模式
CMake有一个-E的命令行工具模式,提供了一些常用的功能,比复制文件、创建目录、读写注册表、读写环境变量、计算md5值等等。脚本可以调用这些功能。
编写CMakeLists.txt
创建可以执行程序工程
首先从创建一个最简单的可执行程序开始,CMakeLists.txt内容如下:
|
1
2
3
4
5
|
cmake_minimum_required (VERSION 2.6)
project (LearnCMake)
message(${LearnCMake_SOURCE_DIR})
message(${LearnCMake_BINARY_DIR})
add_executable(FirstExecutable hello_world.cpp)
|
第1行是cmake需要的最低版本,目前这个是VERSION 2.6,一般不用修改。
第2~4行表示我们创建了一个名为LearnCMake工程,对应生成一个LearnCMake.sln。project函数表示创建一个工程。同时,也生成了4个变量:
- PROJECT_SOURCE_DIR, <PROJECT-NAME>_SOURCE_DIR。工程的源代码目录。
- PROJECT_BINARY_DIR, <PROJECT-NAME>_BINARY_DIR。工程的二进制文件目录。
第5行表示添加一个名为FirstExecutable的可执行程序项目,它的源代码为hello_world.cpp。下面是add_executable的完整用法:
|
1
2
3
|
add_executable(<name> [WIN32] [MACOSX_BUNDLE]
[EXCLUDE_FROM_ALL]
source1 [source2 ...])
|
默认的是创建控制台工程,加上WIN32表示创建的是win32工程,如下:
|
1
|
add_executable(FirstExecutable WIN32 hello_world.cpp)
|
后面是项目的代码,可以添加多个代码文件,用空格分开。
创建库工程
创建库工程跟创建可执行程序工程类似,创建库工程使用add_library函数,如下例子:
|
1
2
3
4
5
6
|
cmake_minimum_required (VERSION 3.0)
project (LearnCMake)
add_library(FirstLibrary first_library.cpp)
add_library(SecondLibrary second_library.cpp)
add_executable(FirstExecutable hello_world.cpp)
target_link_libraries(FirstExecutable FirstLibrary)
|
add_library的用法如下:
|
1
2
3
|
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
source1 [source2 ...])
|
默认的是静态库,也可以显式的设置库是否为静态库、动态库或者是模块。另外BUILD_SHARED_LIBS也可控制编译成哪种库。
target_link_libraries用来链接库,用法如下:
|
1
2
|
target_link_libraries(<target> [item1 [item2 [...]]]
[[debug|optimized|general] <item>] ...)
|
set设置变量
add_library、add_executable都可以添加多个源文件,如下:
|
1
2
3
4
|
cmake_minimum_required (VERSION 3.0)
project (LearnCMake)
add_executable(FirstExecutable main.cpp app_util.h app_util.cpp)
add_library(FirstLibrary app_util.h app_util.cpp)
|
我们可以通过定义一个AppUtilSrc变量来代替app_util.h app_util.cpp,如下:
|
1
2
3
4
5
|
cmake_minimum_required (VERSION 3.0)
project (LearnCMake)
set(AppUtilSrcs app_util.h app_util.cpp)
add_executable(FirstExecutable main.cpp ${AppUtilSrcs})
add_library(FirstLibrary ${AppUtilSrcs})
|
效果是跟上面等价的。还可以累积值:
|
1
2
|
set(AppUtilSrcs app_util.h app_util.cpp)
set(AppUtilSrcs ${AppUtilSrcs} b.cpp)
|
这样AppUtilSrcs就代表着3个文件了。
设置编译模式
设置mt编译模式:
|
1
2
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
|
设置md编译模式:
|
1
2
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd")
|
默认是多字节模式,设置成unicode模式:
|
1
|
add_definitions(-D_UNICODE)
|
另外add_definitions还可以设置其他的选项。
添加其他CMakeLists.txt
一个CMakeLists.txt里面的target如果要链接其他CMakeLists.txt中的target,可以使用add_subdirectory,我们以使用googletest库为例:
|
1
2
3
4
5
6
7
8
|
add_subdirectory("../thirdparty/googletest/googletest/" gtest)
file(GLOB_RECURSE gtest_lib_head_files "../thirdparty/googletest/googletest/*.h")
source_group("gtest" FILES ${gtest_lib_head_files})
include_directories("../thirdparty/googletest/googletest/include")
aux_source_directory("./pbase_unittest/src" pbase_unittest_src_files)
file(GLOB_RECURSE pbase_unittest_include_files "./pbase_unittest/include/*.h")
add_executable(pbase_unittest ${pbase_unittest_src_files} ${pbase_unittest_include_files} ${gtest_lib_head_files})
target_link_libraries(pbase_unittest gtest)
|
代码控制
如果想把./pbase/src目录下的所有源文件加入到工程,可以用aux_source_directory把某个目录下的源文件加入到某个变量中,稍后就可以使用这个变量代表的代码了,如:
|
1
2
|
aux_source_directory("./pbase/src" pbase_lib_src_files)
add_library(pbase ${pbase_lib_src_files})
|
添加头文件包含目录是:
|
1
|
include_directories("../thirdparty/googletest/googletest/include")
|
但是include_directories中的文件不会体现先visual studio工程中,而aux_source_directory只会添加源文件,会忽略头文件,如果想生存的visual studio工程里面也包含头文件,可以这样:
|
1
2
3
|
# add head files
file(GLOB_RECURSE pbase_lib_head_files "./pbase/include/*.h")
add_library(pbase ${pbase_lib_head_files})
|
如果想生存visual studio中的filter,可以使用source_group:
|
1
2
|
file(GLOB_RECURSE gtest_lib_head_files "../thirdparty/googletest/googletest/*.h")
source_group("gtest" FILES ${gtest_lib_head_files})
|
最终添加头文件到工程里标准模板是:
|
1
2
3
4
|
file(GLOB_RECURSE gtest_lib_head_files "../thirdparty/googletest/googletest/*.h")
source_group("gtest" FILES ${gtest_lib_head_files})
include_directories("../thirdparty/googletest/googletest/include")
add_executable(pbase_unittest ${gtest_lib_head_files})
|
作者gclxry发布于三月 4, 2016分类代不该代的码标签cmake、CMakeLists.txt、visual studio
发表评论
(转)Windows上使用CMake的更多相关文章
- 在Windows上使用CMake+CMakeLists.txt生成VS项目编译DlibDotnet库
一.下次源库 地址:https://github.com/takuya-takeuchi/DlibDotNet 二.下载CMake3以上版本 地址:https://cmake.org/download ...
- 在Windows上编译和调试CoreCLR
生成CoreCLR - Windows篇 本文的唯一目的就是让你运行Hello World 运行环境 Window 7+ Visual studio 2015 确保C++ 工具已经被安装,默认是不安装 ...
- 在Windows上一键编译各种版本的Protobuf
所需工具 : cmake for windows 和 git for windows 原理:protobuf 是google的一个开源项目,其源代码在github上可以下载到,并且源码都采用cm ...
- 在windows上构建LLVM 7.0.1
关于在windows上构建LLVM,网上有不少文章,但都是互相抄来的,写作时极不认真,不是少这个,就是少那个,没有一篇是可以完整照着做下来的,实在气人. 本文的安装和配置过程,我亲自操作过好几遍,不惜 ...
- 在windows上一键编译各种版本的protobuf(2017-12-05修改)
所需工具 : cmake for windows 和 git for windows 原理:protobuf 是google的一个开源项目,其源代码在github上可以下载到,并且源码都采用cm ...
- netcdf源码在windows上的编译
作者:朱金灿 来源:http://blog.csdn.net/clever101 今天搞搞netcdf源码在windows上的编译,折腾了半天,算是搞成了,特地记录一下过程.我的目标是要生成netcd ...
- 基于TDengine-ver-1.6.4.4在windows 10下cmake+msys2编译(windows cgo 使用)
目录 基于TDengine-ver-1.6.4.4在windows 10下cmake+msys2编译(windows cgo 使用) 背景 下载地址 仓库地址 安装部署 msys2 安装 配置环境变量 ...
- 关于pytorch在windows上编辑的问题集合
cmake在windows上自动寻找v140(VS2015)的编译器,现在只有VS2013的IDE,所以要修改编译器 修改掉VS2015的编译器名称,报错提示参数CMAKE_C_COMPILER和CM ...
- JVM 源码分析(二):搭建 JDK 8 源码调试环境(Windows 上使用 CLion)
前言 一.准备源码 二.安装 "Bootstrap JDK" 三.配置编译环境 四.编译与测试 五.安装 CMake 和 GDB 五.准备远程调试 六.开始远程调试 前言 上一篇文 ...
随机推荐
- Flash的不同位宽与CPU地址线的接线问题?
一般Flash都有8.16.32等这些不同的位宽,当然说白了就是Flash的数据线位数. 在Flash与CPU的地址线的连接问题时:不同位宽的有不同的连接方法: 一般是:位宽为8时CPU的ADDR0与 ...
- Web图片编辑控件开发文档-Xproer.ImageEditor
版权所有 2009-2014 荆门泽优软件有限公司 保留所有权利 官方网站:http://www.ncmem.com 产品首页:http://www.ncmem.com/webplug/image-e ...
- ISE、vivado、QuartusII调用notepad++、UE汇总(整理)
我已经用惯了notepad++编写Verilog代码,很喜欢这款编辑器,功能真的非常强大.所以,当需要对vivado.ISE或quartus ii中的工程进行Verilog代码上的编写或修改时,只需双 ...
- Linux C 网络编程——3. TCP套接口编程
1. 基本流程 2. socket() int socket(int domain, int type, int protocol); socket()打开一个网络通讯端口,如果成功的话,就像open ...
- Android-进程理解/进程的优先级别
进程理解 Android系统最小的控制单元是:进程 process 应用/CPU最小的控制单元是:线程 thread 一个应用一个 process 进程 一个应用一个 package(包是唯一的) 一 ...
- 采购文件中 RFI、RFQ、RFP、IFB的区别
[PMBOK的描述] 采购文件用于征求潜在卖方的建议书.如果主要依据价格来选择卖方(如购买商业或标准产品时),通常就使用标书.投标或报价等术语.如果主要依据其他考虑(如技术能力或技术方法)来选择卖方, ...
- App与微信WebAPP
我的App与微信搞上了 小麦积分墙摘自网络 最近有很多开发者关心的一个问题是如何提升app的下载量,透过现象开本质,app下载量的终极目标还是为多少客户提供了服务,抛开下载量KPI,app真心关心的问 ...
- 原生态在Hadoop上运行Java程序
第一种:原生态运行jar包1,利用eclipse编写Map-Reduce方法,一般引入Hadoop-core-1.1.2.jar.注意这里eclipse里没有安装hadoop的插件,只是引入其匝包,该 ...
- 配置ssh使用socks代理
ssh -o ProxyCommand='nc -x 127.0.0.1:1080 %h %p' username@server
- 使用Toolbar + DrawerLayou实现菜单侧滑,改变toolbar左上角图标
侧边栏具体实现可以参照http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0303/2522.html getSupportActio ...