CMake的基本操作(以Windows平台为例)

一、What(CMake是什么)

        CMake(Cross platform Make)是一个开源的跨平台的自动化构建(编译)工具,可以用简单的语句来描述所有平台的编译过程,并生成各个平台下对应的工程文件,它并不依赖于某特定的编译器

二、Why(为什么要使用CMake)

  • 跨平台
  • 命令使用简单
  • 所有的配置一目了然,很直观

三、How(怎么使用CMake)

1、第一项肯定是下载CMake了,这里以Windows为例,下载地址:https://cmake.org/download/

2、CMake的所有操作都是在CMakeLists.txt里面完成的,所以主要就是完成CMakeLists.txt文件了

四、CMake的使用

1、一个最简单的cmake

在目录下面有一个main.cpp和一个CMakeLists.txt文件

main.cpp内容如下:

#include <iostream>

int main(void) {
	std::cout << "cmake test" << std::endl;
	getchar();
	return 0;
}

然后CMakeLists.txt内容如下:

# 设置cmake的最小版本
cmake_minimum_required(VERSION 3.6)
# 设置项目名称
project(cmake_test)

# 设置C++的版本号
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# 搜集当前目录下的源文件
aux_source_directory(. SRCS)

# 生成可执行程序
add_executable(cmake_exec ${SRCS})

打开cmd,输入命令如下

md build
cd build
cmake ..

然后会生成一个sln文件,如下图所示

 双击打开这个sln,然后将cmake_exec设置为默认启动项编译运行即可

2、设置vs默认启动项,加在add_executable后面

# 设置vs默认启动项
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT cmake_exec)

这个时候删除build目录,然后再重新来一次

3、执行cmake的时候执行编译器版本和输出路径

cmake -G"Visual Studio 14 2015" CMakeLists.txt -B./platforms_project/win32
-G:表示指定编译器的版本
-B:表示要输出的路径

4、到此一个最简单的cmake程序就完了 

五、CMake常用操作指令

1、设置CMake的版本

cmake_minimum_required(VERSION 3.6)

2、设置当前项目的名称

project(project_name)

3、设置当前项目中使用C++的版本

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

4、设置要包含头文件的路劲

include_directories(directories)

5、设置要链接库的路径

link_directories(directories)

6、设置输出路径

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY path)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY path)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY path)
set(EXECUTABLE_OUTPUT_PATH path)

例子:
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/../output/bin/${Configuration})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/../output/bin/${Configuration})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/../output/bin/${Configuration})
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/../output/bin/${Configuration})

7、搜集某个目录下面的源文件

aux_source_directory(${CMAKE_SOURCE_DIR}/src SRCS)

8、生成静态库或动态库

add_library(library_name ${source}) // 默认静态
add_library(library_name SHARED/STATIC ${source})

9、生成可执行程序

add_executable(exec ${SRCS})

10、设置要链接的库

target_link_libraries(name link_name)
比如
target_link_libraries(cmake_exec test_lib)

11、设置链接时候的一些参数

add_link_options(options)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} options")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} options")
例如(Windows下):
# 增量连接
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /IGNOREIDL /INCREMENTAL")
# 设置def
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEF:${CMAKE_CURRENT_SOURCE_DIR}/dll/wemeet.def")

12、添加子目录

add_subdirectory(subdirectory)

  如果不是子目录应该怎么办

add_subdirectory(directory target)

 13、划分目录结构

source_group
一般的用法如下:
source_group(common REGULAR_EXPRESSION *.*/common/*.*)
这样会将common目录下面的文件全部分组为common

14、执行系统命令

execute_process
比如运行一个python脚本:
execute_process(COMMAND python copy.py WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/scripts)
备注:
WORKING_DIRECTORY :表示在哪个目录下执行
copy.py里面就是把一个文件从一个目录拷贝到另外一个目录

15、字符串比较

STREQUAL 相等比较
STRLESS 小于
STRGREATER 大于
使用方法:if("hello" STREQUAL "hello")

16、输出调试打印信息,类似于printf

message("hello")

17、判断某个变量是否设置了

if(DEFINED var)

  判断某个环境变量是否存在

if(ENV{VAR})

  设置环境变量

set(ENV{var} var)

18、判断文件是否存在

if(EXISTS file)

19、判断CMake创建的逻辑目标是否存在

if(TARGET name)
逻辑目标:
add_executable(exec ${SRCS})
这里的exec就是逻辑目标,所以可以写为
if(TARGET exec)

20、设置依赖

ADD_DEPENDENCIES
表示某个工程必须在它之前被执行
比如:
target_link_libraries(cmake_exec test_lib)
表示cmake_exec要连接test_lib,那么我们就要保证test_lib必须在cmake_exec之前生成,这个时候就可以使用ADD_DEPENDENCIES
ADD_DEPENDENCIES(cmake_exec test_lib)

21、设置自定义命令,具体操作可查看文档

add_custume_command

  举个例子,比如我们有的时候想在编译之前、链接之前或者在所有项目生成之后执行某些命令,可以这么做

PRE_BUILD:编译之前
PRE_LINK:链接之前
POST_BUILD:所有操作执行之后

  具体操作可参考:

add_custom_command(TARGET wemeet
                   PRE_BUILD
                   COMMAND ${CMAKE_SOURCE_DIR}/scripts/copy_file.bat
                   COMMENT "copy file")

22、设置fpic

set(CMAKE_POSITION_INDEPENDENT_CODE ON)

23、创建函数

macro(<name> [arg1])
endmacro(<name>)

  比如设置一个函数,按照目录对源文件进行分组

  根据目录划分target

set_property(GLOBAL PROPERTY USE_FOLDERS ON)
macro(set_target_folder_if_exist target folder)
  if(TARGET ${target})
    set_target_properties(${target} PROPERTIES FOLDER ${folder})
  endif()
endmacro()
调用:
set_target_folder_if_exist(cmake_exe cmake)

24、设置警告的等级

add_definitions("/W4 /WX")
也就是将警告视为错误

25、cmake判断平台

Windows平台判断:
if(WIN32)
endif()
LINUX平台判断:
if(UNIX AND NOT APPLE AND NOT ANDROID)
endif()
MAC平台判断:
if(APPLE)
endif()

26、cmake设置编译为release

# SET(CMAKE_BUILD_TYPE Release)   # 这条命令在Windows下面设置不生效
SET(CMAKE_CONFIGURATION_TYPES "Release" CACHE STRING "" FORCE)

27、cmake 区别平台,目前 Windows,Linux,Android,Mac 平台都可以很好的区分,但是没有想到怎么区分 iOS

if(WIN32)
  message("WIN32")
elseif(UNIX AND NOT APPLE AND NOT ANDROID)
  message("LINUX")
elseif(ANDROID)
  message("ANDROID")
elseif(APPLE)
  message("APPLE")
else()
  message("else")
endif()

下面是一些在Windows上常用到的指令

27、设置unicode编码

add_definitions(-DUNICODE -D_UNICODE)

28、release模式下生成pdb文件

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")

29、设置多处理器编译

add_definitions("/MP")

30、设置默认启动项

set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT app_name)

31、引入外部的工程

include_external_msproject
比如外面的一个工程是vcxproj的,但是要在cmake里面使用到就可以这么做
include_external_msproject(cmake_test ${CMAKE_SOURCE_DIR}/../../test/cmake_test.vcxproj)

32、使用预编译头

macro(use_precompiled_header TARGET HEADER_FILE SRC_FILE)
  get_filename_component(HEADER ${HEADER_FILE} NAME)
  if (MSVC AND NOT NMAKE AND NOT OGRE_UNITY_BUILD)
    set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS /Yu"${HEADER}")
    set_source_files_properties(${SRC_FILE} PPROPERTIES COMPILE_FLAGS /Yc"${HEADER}")
  elseif (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGXX)
  endif ()
endmacro()
比如:
use_precompiled_header(cmake_exe ${CMAKE_SOURCE_DIR}/src/stdafx.h
                                 ${CMAKE_SOURCE_DIR}/src/stdafx.cpp)

33、当把警告视为错误的时候,屏蔽掉一些警告

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4100 /wd4505 /wd4996")

34、强制指定Windows sdk的版本号,注意要写在project之前,在设置完cmake_minimum_required之后就需要指定,不然可能会不生效

set(CMAKE_SYSTEM_VERSION "10.0.17763.0" CACHE STRING INTERNAL FORCE)
set(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION "10.0.17763.0" CACHE STRING INTERNAL FORCE)

四、CMake 中 macro、function

1、ARGC,ARGV,ARGN 的含义

ARGC:记录传入的参数个数
ARGV:包含所有传入参数的 list
ARGN:包含传入参数的 list,这个 list 是指 macro、function 指定参数之后的所有参数

测试代码1

function(file_source_group_1)
  message("=== file_source_group_1 ===")
  message(${ARGC})
  message(${ARGV})
  message(${ARGN})
  message("=== file_source_group_1 ===")
endfunction(file_source_group_1)

file_source_group_1(hello include/hello.hpp src/hello.cpp)

输出结果1

=== file_source_group_1 ===
3
helloinclude/hello.hppsrc/hello.cpp
helloinclude/hello.hppsrc/hello.cpp
=== file_source_group_1 ===

可见,如果 function 后面不指定任何参数,那么 ARGV 和 ARGN 结果是一样的

测试代码2

function(file_source_group_2 hello)
  message("=== file_source_group_2 ===")
  message(${ARGC})
  message(${ARGV})
  message(${ARGN})
  message("=== file_source_group_2 ===")
endfunction(file_source_group_2)

file_source_group_2(hello include/hello.hpp src/hello.cpp)

输出结果2

=== file_source_group_2 ===
3
helloinclude/hello.hppsrc/hello.cpp
include/hello.hppsrc/hello.cpp
=== file_source_group_2 ===

在 function(file_source_group_2 hello) 函数里面多指定了一个参数,标识第一个传入的参数用 hello 捕获,这个时候 ARGV 还是所有的参数 list,但是 ARGN 是除了第一个参数的所有参数了

2、使用 function 自动生成 VS 的目录

function(add_source_group file_source)
  # 如果给定路径是一个绝对路径
  if (IS_ABSOLUTE "${file_source}")
    file(RELATIVE_PATH source_rel "${CMAKE_CURRENT_SOURCE_DIR}" "${file_source}")
  else()
    set(source_rel "${file_source}")
  endif()
  get_filename_component(source_dir "${source_rel}" PATH)
  # string(REPLACE "/" "\\" dir_name "${source_path}")
  source_group("${source_dir}" FILES "${file_source}")
endfunction()

function(file_source_group)
  foreach(file_source IN ITEMS ${ARGN})
    add_source_group(${file_source})
  endforeach()
endfunction(file_source_group)

set(DEMO_SOURCE
    ${CMAKE_CURRENT_SOURCE_DIR}/include/hello.hpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/hello.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/include/123/test.h
    )

file_source_group(${DEMO_SOURCE})

四、CMake常见的宏

1、CMAKE_SOURCE_DIR :工程顶层目录所在的路径

2、CMAKE_CURRENT_SOURCE_DIR:当前CMakeLists.txt所在的路径,建议使用CURRENT_SOURCE,不建议使用SOURCE_DIR,因为如果主工程目录改变了,SOURCE_DIR也就会改变,很容易造成编译错误

3、CMAKE_BINARY_DIR:工程编译时的路径

4、PROJECT_NAME:工程名字

5、EXECUTABLE_OUTPUT_PATH:可执行文件的输出路径

6、LIBRARY_OUTPUT_PATH:库的输出路径

五、CMake和conan一起使用

  cmake和conan搭配一起使用,具体代码如下

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
.........
target_link_libraries(name ${CONAN_LIBS})

六、编译

 Linux

cmake .   // .表示CMakeLists.txt所在的路径,也可以新建一个build目录去编译
make

Windows

cmake .
然后使用vs打开生成的sln文件

cmake -G "Visual Studio 15 Win64" .
编译 64 位,默认生成是 32 位

Mac

cmake -G "XCode" .
然后使用XCode打开

七、写在最后
有错误欢迎指正,欢迎一起交流,谢谢!

八、参考资料

https://cmake.org/documentation/

  • 5
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Windows是一种广泛使用的操作系统,而CMake是一个跨平台的开源构建工具。CMake可以帮助开发者在不同的操作系统上生成可执行文件、库文件或者其他项目所需的构建文件。 CMake的主要特点包括: 1. 跨平台CMake可以在多个操作系统上使用,包括Windows、Linux、macOS等。 2. 简化构建过程:CMake使用一种简单的语法来描述项目的构建过程,开发者只需要编写一个CMakeLists.txt文件即可。 3. 自动生成构建文件:CMake可以根据CMakeLists.txt文件自动生成对应的构建文件,如Makefile或者Visual Studio的解决方案文件。 4. 支持多种编译器:CMake可以与多种编译器进行集成,如GCC、Clang、Visual Studio等。 5. 支持多种构建方式:CMake支持多种构建方式,包括本地构建、交叉编译和远程构建等。 在Windows上使用CMake,你可以按照以下步骤进行: 1. 安装CMake:从CMake官方网站下载并安装最新版本的CMake。 2. 创建CMakeLists.txt文件:在项目根目录下创建一个名为CMakeLists.txt的文件,并编写项目的构建规则。 3. 生成构建文件:打开命令提示符或者PowerShell,进入项目根目录,并执行以下命令生成构建文件: ``` cmake . ``` 4. 构建项目:根据生成的构建文件,使用相应的构建工具进行项目的构建,如使用Visual Studio打开生成的解决方案文件并进行编译。 希望以上信息对你有帮助!如果你还有其他问题,请继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值