CMake指令放入一个名为 CMakeLists.txt 的文件中,CMake命令是不区分大小写的,所以常用的做法是使用小写,参数使用大写。
每个CMakeLists.txt都必须包含cmake_minimum_required作为第一行,设置项目工程依赖CMake的最低版本。如下代码:
cmake_minimum_required(VERSION 3.1)
指定CMake版本为3.1
每个CMakeLists.txt都必须包含cmake_minimum_required作为第一行,设置项目工程依赖CMake的最低版本。
cmake_minimum_required(VERSION 3.7...3.21)
指定CMake版本为3.7到3.21,这意味着这个工程最低可以支持3.7版本,但是也最高在 3.21版本上测试成功过。实际只会设置为3.7版本的特性,因为这些版本处理这个工程没有什么差异。注意:数字3.7...3.21不能有空格。
cmake_minimum_required(VERSION 3.7 FATAL_ERROR)
设置CMake所需的最低版本为3.7,如果使用的CMake版本低于该版本,则会发出致命错误。
CMake版本特性,cmake_minimum_required和cmake_policy搭配使用。
cmake_minimum_required(VERSION 3.7)
if(${CMAKE_VERSION} VERSION_LESS 3.21)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.21)
endif()
如果CMake的版本低于3.21,if 块条件为真,CMake 将会被设置为当前版本。如果CMake版本是3.21或者更高,if 块条件为假,CMake会设置3.21版本。
设置项目名称。
project(MyProject VERSION 1.0
DESCRIPTION "Very nice project"
LANGUAGES CXX)
MyProject是.sln文件的名称,如下图所示。
这里的字符串是带引号的,因此内容中可以带有空格。项目名称是这里的第一个参数。所有的关键字参数都可选的。VERSION 设置了一系列变量,例如 MyProject_VERSION和PROJECT_VERSION。
语言可以是 C,CXX,Fortran,ASM,CUDA(CMake3.8+),CSharp(3.8+),SWIFT(CMake3.15+ experimental),默认是CXX。在 CMake 3.9,可以通过DESCRIPTION 关键词来添加项目的描述。
add_executable指令是生成可执行文件。
add_executable(one two.cpp three.h)
one 既是生成的可执行文件的名称,也是创建的 CMake 目标(target)的名称。紧接着的是源文件的列表,你想列多少个都可以。CMake很聪明,它根据拓展名只编译源文件。在大多数情况下,头文件将会被忽略;列出他们的唯一原因是为了让他们在 IDE 中被展示出来,目标文件在许多 IDE 中被显示为文件夹。
cmake_minimum_required(VERSION 3.7...3.21)
if(${CMAKE_VERSION} VERSION_LESS 3.21)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.21)
endif()
project(Test01 VERSION 1.0
DESCRIPTION "Very nice project"
LANGUAGES CXX)
add_executable(${PROJECT_NAME} main.cpp test01.h test01.cpp)
生成一个库。
add_library(one STATIC two.cpp three.h)
你可以选择库的类型,可以是 STATIC、SHARED或者MODULE。如果你不选择它,CMake 将会通过 BUILD_SHARED_LIBS 的值来选择构建 STATIC 还是 SHARED 类型的库。
在下面的章节中你将会看到,你经常需要生成一个虚构的目标,也就是说,一个不需要编译的目标。例如,只有一个头文件的库。这被叫做 INTERFACE 库,这是另一种选择,和上面唯一的区别是后面不能有文件名。
你也可以用一个现有的库做一个 ALIAS 库,这只是给已有的目标起一个别名。这么做的一个好处是,你可以制作名称中带有::的库。
如果add_library不添加STATIC、SHARED和MODULE任何参数,默认只生成lib文件,如果添加STATIC也只生成lib文件,如果添加SHARED,则只生成dll文件。
如果我们想同时生成lib和dll文件时,就需要给add_library设置SHARED参数,并设置导出符号__declspec(dllimport) 。
添加宏定义
add_definitions(-D宏名称)
-D关键词不能少,且后面紧接着时宏名称,没有空格。
给项目工程加入引用代码目录,也就是引用头文件所在目录。
target_include_directories(one PUBLIC include)
target_include_directories为目标添加了一个目录。PUBLIC 对于一个二进制目标没有什么含义;
但对于库来说,它让CMake知道,任何链接到这个目标的目标也必须包含这个目录。
其他选项还有 PRIVATE(只影响当前目标,不影响依赖),以及 INTERFACE(只影响依赖)。
注意:命令target_include_directories必须放在add_library或者add_executable之后,否则CMake构建工程时报类似“Cannot specify link libraries for target “test“ which is not built by this project.”的错误。
给项目工程加入引用代码目录,也就是引用头文件所在目录,但是include_directories命令包含其子目录。
给项目工程添加库目录。
注意:link_directories必须放在add_executable指令前。
给项目工程添加库目录。
注意:target_link_directories必须放在add_executable指令后。
使用语法如下:
target_link_directories(${PROJECT_NAME} PUBLIC "../tecio/lib")
连接引用库,也就是链接库。
add_library(another STATIC another.cpp another.h)
target_link_libraries(another PUBLIC one)
target_link_libraries可能是CMake中最有用也最令人迷惑的命令。它指定一个目标,并且在给出目标的情况下添加一个依赖关系。如果不存在名称为one的目标,那他会添加一个链接到你路径中one库(这也是命令叫
target_link_libraries 的原因)。或者你可以给定一个库的完整路径,或者是链接器标志。最后再说一个有些迷惑性的知识:),经典的CMake允许你省略 PUBLIC
关键字,但是你在目标链中省略与不省略混用,那么CMake会报出错误。
只要记得在任何使用目标的地方都指定关键字,那么就不会有问题。
编译特性
target_compile_features(calclib PUBLIC cxx_std_11)
目标calclib使用c++11特性。
本地变量、缓存变量和环境变量。
声明一个本地变量MY_VARIABLE
set(MY_VARIABLE "value")
取消常规变量MY_VARIABLE
unset(MY_VARIABLE)
变量名通常全部用大写,变量值跟在其后。你可以通过 ${} 来解析一个变量,例如 ${MY_VARIABLE}。CMake 有作用域的概念,在声明一个变量后,你只可以它的作用域内访问这个变量。如果你将一个函数或一个文件放到一个子目录中,这个变量将不再被定义。你可以通过在变量声明末尾添加 PARENT_SCOPE 来将它的作用域置定为当前的上一级作用域。
set(MY_VARIABLE "value" PARENT_SCOPE)
MY_VARIABLE本地变量在父作用域中。
set(MY_LIST "one" "two")
set(MY_LIST "one;two")
列表就是简单地包含一系列变量,可以通过;分隔变量,这和空格的作用是一样的。
有一些和list(进行协同的命令,separate_arguments可以把一个以空格分隔的字符串分割成一个列表。需要注意的是,在CMake中如果一个值没有空格,那么加和不加引号的效果是一样的。这使你可以在处理知道不可能含有空格的值时不加引号。
当一个变量用${}括起来的时候,空格的解析规则和上述相同。对于路径来说要特别小心,路径很有可能会包含空格,因此你应该总是将解析变量得到的值用引号括起来,也就是应该这样"${MY_PATH}" 。
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/bin)
上面命令,必须在add_subdirectory的前面。
CMake中项目(project指令)和目标(add_library和add_executable指令),与Visual Studio中是不一样的,CMake 项目相当于Visual Studio解决方案,而CMake目标相当于Visual Studio一个一个的不同类型的项目。Visual Studio一个解决方案,可以包含多个项目。
我们非常关心解决方案的属性和项目的属性,包括 名称、版本、语言、路径、描述和网站。
如果用add_subdirectory命令,在子目录的CMakeLists.txt文件中,也有project命令,那么构建后,都会生成项目
我们用include()命令也可以加载 子目录中的CMakeLists.txt文件,例如:
include(sub/CMakeLists.txt)
虽然include()命令与 add_subdirectory()命令,都会加载CMakeLists.txt文件,但是include()命令是将子目录中CMakeLists.txt文件内容导入到父目录的源文件中,而 add_subdirectory() 命令是将子目录中 CMakeLists.txt 添加到构建中。
所以,有一个比较明显的区别,都执行project命令,如果使用include()那么项目会被覆盖,如果使用add_subdirectory()那么会创建子项目。
在编译完lib库后,需要手动拷贝lib文件、头文件给别人,做二次开发,这样相当麻烦。可以使用install指令,将生成的lib文件等拷贝到指定的位置。
配置库文件、头文件和执行文件到install的目录下,cmake中的install根目录为CMAKE_INSTALL_PREFIX变量的路径,如果我们要设置配置路径可以使用set命令设置CMAKE_INSTALL_PREFIX变量的值来改变路径。一般默认情况CMAKE_INSTALL_PREFIX变量的值为,在UNIX系统中为:/usr/local,在windows系统中为:c:/Program Files/${PROJECT_NAME}
打包项目指令如下:
# 设置打包目录
set(CMAKE_INSTALL_PREFIX ${PROJECT_BINARY_DIR})
# 配置可执行文件到安装路径 CMAKE_INSTALL_PREFIX的bin中
install(TARGETS glew DESTINATION glew-sdk/lib)
# 配置程序的头文件到安装路径 CMAKE_INSTALL_PREFIX的include文件中
install(FILES "include/GL/glew.h"
DESTINATION glew-sdk/include)
使用方法1
target_link_libraries ( app
debug ${Boost_FILESYSTEM_LIBRARY_DEBUG}
optimized ${Boost_FILESYSTEM_LIBRARY_RELEASE} )
使用方法2
set( MyFavLib_LIBRARIES
debug debug/module1 optimized release/module1
optimized debug/module2 optimized release/module2 )
target_link_libraries( app ${MyFavLib_LIBRARIES} )
注意,方法2中,module1和module2的lib后缀名要省略,vs会自动补全lib后缀名。
使用方法
if(NOT DEFINED CMAKE_DEBUG_POSTFIX)
set(CMAKE_DEBUG_POSTFIX "_debug")
endif()
if(NOT DEFINED CMAKE_RELEASE_POSTFIX)
set(CMAKE_RELEASE_POSTFIX "_release")
endif()
注意,该指令必须放在add_library之前,如下图所示。
include(${CMAKE_CURRENT_DIR}/../share.cmake)
(1) 设置exe输出目录
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
在Win + VS环境下,会自动在你所设置的目录后面扩展一层
(2) 设置lib输出目录
SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../lib)
在Win + VS环境下,会自动在你所设置的目录后面扩展一层
(3) 设置输出目录
#全局设置一下如下
#可执行文件位置
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
#默认存放动态库的位置
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
#默认存放静态库的位置,以及MSVC中动态库的lib文件的位置
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
# 单独为某个库设置输出目录:
set_target_properties(${target_name}
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/libs"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/libs"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/libs"
FOLDER "lib")
(4) 设置debug和release输出目录
用法1
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/../bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/../bin)
上面两条语句分别设置了Debug版本和Release版本可执行文件的输出目录, 一旦设置上面的属性,在任何环境下生成的可执行文件都将直接放在你所设置的目录.
用法2
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/../lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/../lib)
上面两条语句分别设置了Debug版本和Release版本库文件的输出目录, 一旦设置上面的属性,在任何环境下生成的库文件都将直接放在你所设置的目录.
用法1
set(CMAKE_DEBUG_POSTFIX "_d")
set(CMAKE_RELEASE_POSTFIX "_r")
上面两条语句分别设置了Debug版本和Release版本下库文件的后缀名
用法2
set_target_properties(${TARGET_NAME} PROPERTIES DEBUG_POSTFIX "_d")
set_target_properties(${TARGET_NAME} PROPERTIES RELEASE_POSTFIX "_r")
上面两条语句分别设置了Debug版本和Release版本下可执行文件的后缀名
语法格式
message([<mode>] "message text" ...)
mode 的值包括 FATAL_ERROR、WARNING、AUTHOR_WARNING、STATUS、VERBOSE等。主要使用其中的 2 个——FATAL_ERROR、STATUS。
FATAL_ERROR:产生 CMake Error,会停止编译系统的构建过程;
STATUS:最常用的命令,常用于查看变量值,类似于编程语言中的 DEBUG 级别信息。
"message text"为显示在终端的内容。
使用set函数 + ENV指令
set(ENV{变量名} 值)
注意:
(1)读环境变量时,需要加上$;写环境变量时,不需要加$;
(2)cmake文件内定义的环境变量仅用于cmake编译过程,不能用于目标程序。
例子如下:
message("myenvvar: $ENV{myenvvar}")
# 定义环境变量myenvvar
set(ENV{myenvvar} "123")
message("myenvvar: $ENV{myenvvar}")
CMake中的option用于控制编译流程,相当于C语言中的宏条件编译。
options基本格式如下:
option(<variable> "<help_text>" [value])
variable:定义选项名称
help_text:说明选项的含义
value:定义选项默认状态,一般是OFF或者ON,除去ON之外,其他所有值都为认为是OFF。
if(expression)
#...
elseif(expression2)
#...
else()
#...
endif()
对于 if(string) 来说:
(1)如果 string 为(不区分大小写)1、ON、YES、TRUE、Y、非 0 的数则表示真
(2)如果 string 为(不区分大小写)0、OFF、NO、FALSE、N、IGNORE、空字符串、以 -NOTFOUND 结尾的字符串则表示假
(3)如果 string 不符合上面两种情况,则 string 被认为是一个变量的名字。变量的值为第二条所述的各值则表示假,否则表示真。
表达式中可以包含操作符,操作符包括:
(1) 一元操作符,例如:EXISTS、COMMAND、DEFINED 等
(2) 二元操作符,例如:EQUAL、LESS、GREATER、STRLESS、STREQUAL、STRGREATER 等
(3) NOT(非操作符)
(4) AND(与操作符)、OR(或操作符)
(5) 操作符优先级:一元操作符 > 二元操作符 > NOT > AND > OR
使用例子1
if (variable)
# 当 variable 不为 空值,1,TRUE、ON时为真
if (NOT variable)
# 当 variable 为 空值,0,FALSE,OFF 或者 NOTFOUND 时为真
if (variable1 AND variable2)
# 当 variable1, variable1 同时不为 空值,0,FALSE,OFF 或者 NOTFOUND 时为真
if (variable1 OR variable2)
# 当 variable1, variable1 有一个不为 空值,0,FALSE,OFF 或者 NOTFOUND 时为真
if (COMMAND command-name)
# 当 command-name 是可调用的命令时为真
if (DEFINED variable)
# 当 variable 已经被设置了值时为真
if (EXISTS file-name)
if (EXISTS directory-name)
# 当指定的文件或者目录时为真
if (IS_DIRECTORY name)
if (IS_ABSOLUTE name)
# 当 name 是目录或者是绝对路径是为真
if (name1 IS_NEWER_THAN name2)
# 当 name1 文件的修改时间比 name2 文件的修改时间要新时为真
if (variable MATCHES regex)
if (string MATCHES regex)
# 当给定的变量或者字符串与给定的正则表达式相匹配时为真
使用例子2
if(NOT expression)
//为真的前提是 expression 为假
if(expr1 AND expr2)
//为真的前提是 expr1 和 expr2 都为真
if(expr1 OR expr2)
//为真的前提是 expr1 或者 expr2 为真
if(COMMAND command-name)
//为真的前提是存在 command-name 命令、宏或函数且能够被调用
if(EXISTS name)
//为真的前提是存在 name 的文件或者目录(应该使用绝对路径)
if(file1 IS_NEWER_THAN file2)
//为真的前提是 file1 比 file2 新或者 file1、file2 中有一个文件不存在(应该使用绝对路径)
if(IS_DIRECTORY directory-name)
//为真的前提是 directory-name 表示的是一个目录(应该使用绝对路径)
if(variable|string MATCHES regex)
//为真的前提是变量值或者字符串匹配 regex 正则表达式
if(variable|string LESS variable|string)
if(variable|string GREATER variable|string)
if(variable|string EQUAL variable|string)
//为真的前提是变量值或者字符串为有效的数字且满足小于(大于、等于)的条件
if(variable|string STRLESS variable|string)
if(variable|string STRGREATER variable|string)
if(variable|string STREQUAL variable|string)
//为真的前提是变量值或者字符串以字典序满足小于(大于、等于)的条件
if(DEFINED variable)
//为真的前提是 variable 表示的变量被定义了。
set(VAR a b c)
foreach(f ${VAR})
message(${f})
endforeach()
set(VAR 5)
while(${VAR} GREATER 0)
message(${VAR})
math(EXPR VAR "${VAR} - 1")
endwhile()
IF(WIN32 AND NOT ANDROID)
# GW: no longer required (keep for posterity)
# GL CORE Profile build (OSG must also be built with it)
# FIND_PACKAGE(GLCORE)
#IF(GLCORE_FOUND)
# INCLUDE_DIRECTORIES( ${GLCORE_INCLUDE_DIR} )
# message(status "Found GLCORE headers at ${GLCORE_INCLUDE_DIR}")
#ENDIF()
IF(MSVC)
# This option is to enable the /MP switch for Visual Studio 2005 and above compilers
OPTION(WIN32_USE_MP "Set to ON to build multiprocessor option (/MP)" OFF)
MARK_AS_ADVANCED(WIN32_USE_MP)
IF(WIN32_USE_MP)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
ENDIF(WIN32_USE_MP)
# More MSVC specific compilation flags
ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS)
ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE)
ENDIF(MSVC)
ENDIF(WIN32 AND NOT ANDROID)
mark_as_advanced 将CMake 的缓存变量标记为高级。
mark_as_advanced([CLEAR|FORCE] VAR VAR2 VAR...)
将缓存的变量标记为高级变量。其中,高级变量指的是那些在CMake GUI中,只有当“显示高级选项”被打开时才会被显示的变量。如果CLEAR是第一个选项,参数中的高级变量将变回非高级变量。如果FORCE是第一个选项,参数中的变量会被提升为高级变量。如果两者都未出现,新的变量会被标记为高级变量;如果这个变量已经是高级/非高级状态的话,它将会维持原状。
该命令在脚本中无效。
add_compile_options是设置编译选项指令
(1) 设置utf-8编码
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
(2) 设置使用c++11标准
add_compile_options(-std=c++11)
(3) 设置使用c++17标准
# msvc编译器
if (MSVC_VERSION GREATER_EQUAL "1914")
add_compile_options("/Zc:__cplusplus")
endif()
if (MSVC_VERSION GREATER_EQUAL "1900")
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("/std:c++17" _compiler_supports_cxx17)
if (_compiler_supports_cxx17)
add_compile_options("/std:c++17")
endif()
endif()
# g++编译器
if(CMAKE_COMPILER_IS_GNUCXX)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++17" _compiler_supports_cxx17)
if (_compiler_supports_cxx17)
set(CMAKE_CXX_FLAGS "-std=c++17 ${CMAKE_CXX_FLAGS}")
message(STATUS "optional:-std=c++17")
endif()
endif(CMAKE_COMPILER_IS_GNUCXX)
(4) 取消编译警告提示
if(WIN32)
add_compile_options(/W4)
add_compile_options(/wd4828)
add_compile_options(/wd4100)
add_compile_options(/wd4251)
endif()
当有一些大型程序需要编译时,由于代码的劣质,会出现成千上万的c4828等编译警告,此时,如果使用的qtcreator编译器,会直接导致qtc编译器卡死或者崩溃。
有时候,一个项目中,文件很多,我们想让文件看起来整洁一下,就需要将文件进行分组
file(GLOB LOG "log/*.h" "log/*.cpp")
file(GLOB LOGWIN "log/logan-win/*.h" "log/logan-win/*.cpp")
file(GLOB CLOGAN "log/logan-win/clogan/*.h" "log/logan-win/clogan/*.cpp")
file(GLOB MBEDTLS_INCLUDE "log/logan-win/mbedtls/include/mbedtls/*.h" )
file(GLOB MBEDTLS_LIB "log/logan-win/mbedtls/library/*.h" "log/logan-win/mbedtls/library/*.cpp")
set(group group1.h group1.cpp main.cpp)
source_group(group FILES ${group})
source_group(group/log FILES ${LOG})
source_group(group/log/logan-win FILES ${LOGWIN})
source_group(group/log/logan-win/clogan FILES ${CLOGAN})
source_group(group/log/logan-win/mbedtls/include FILES ${MBEDTLS_INCLUDE})
source_group(group/log/logan-win/mbedtls/library FILES ${MBEDTLS_LIB})
add_executable(${PROJECT_NAME}
${group} ${LOG} ${LOGWIN} ${CLOGAN} ${MBEDTLS_INCLUDE} ${MBEDTLS_LIB})
在使用CMake后,手工维护filter是不现实的。CMake也提供了可以生成filter的机制,就是source_group()命令。结合source_group(), file(), string()等命令,我们可以让实现CMake自动按目录结构生成filter。
(1) 在比较顶层的CMakeLists.txt中定义该宏
定义宏代码:
macro(source_group_by_dir source_files)
if(MSVC)
set(sgbd_cur_dir ${CMAKE_CURRENT_SOURCE_DIR})
foreach(sgbd_file ${${source_files}})
string(REGEX REPLACE ${sgbd_cur_dir}/\(.*\) \\1 sgbd_fpath ${sgbd_file})
string(REGEX REPLACE "\(.*\)/.*" \\1 sgbd_group_name ${sgbd_fpath})
string(COMPARE EQUAL ${sgbd_fpath} ${sgbd_group_name} sgbd_nogroup)
string(REPLACE "/" "\\" sgbd_group_name ${sgbd_group_name})
if(sgbd_nogroup)
set(sgbd_group_name "\\")
endif(sgbd_nogroup)
source_group(${sgbd_group_name} FILES ${sgbd_file})
endforeach(sgbd_file)
endif(MSVC)
endmacro(source_group_by_dir)
(2) 使用宏
在添加工程(add_library或者add_executable)的CMakeLists.txt文件中调用该宏,调用如下:
source_group_by_dir(all_files)
其中all_files是保存了所有文件名的变量。注意,这里用的是变量名,而没有引用其值。
一般这个文件列表可以用file()或者aux_source_directory()来得到。例如对于C++工程,通常是这样的:
file(GLOB_RECURSE project_headers *.h)
file(GLOB_RECURSE project_cpps *.cpp)
set(all_files ${project_headers} ${project_cpps})
source_group_by_dir(all_files)
有时候,一个项目中,可能有很多工程,工程多了后,就会显得杂乱无章,此时我们需要对工程进行分组
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "4") # 分组名称为4
# Visual Studio中的调试工作目录
set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DEBUGGER_WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/bin/Debug)
如果用cmake构建vs项目工程,直接点击debug按钮,启动程序,会提示找不到程序,此时,需要调用上述代码,设置一下启动目录
# 判断配置文件是否存在
if(EXISTS ${PROJECT_BINARY_DIR}/bin/Debug/config)
message(DEBUG "style exist")
else()
file(GLOB CONFIGFILES "${CMAKE_SOURCE_DIR}/config/*")
file(COPY ${CONFIGFILES} DESTINATION ${PROJECT_BINARY_DIR}/bin/Debug/config)
endif()
有时候项目需要一些依赖文件,当程序编译好了后,程序运行都要依赖这些文件,此时可以使用上述代码,进行依赖文件拷贝
# 当调用lib库时,可能出现 debug调用release库
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
# 使用cmake下载github上的库,可能会出现下载不了的情况,可以通过网络代理下载
set(ENV{http_proxy} "http://127.0.0.1:8082")
set(ENV{https_proxy} "http://127.0.0.1:8082")
变量 | 作用 |
---|---|
${CMAKE_CURRENT_SOURCE_DIR} | 当前CMakeLists.txt文件所在目录 |
${CMAKE_CURRENT_BINARY_DIR} | 当前CMakeLists.txt构建输出所在的目录 |
${CMAKE_SOURCE_DIR} | 顶级CMakeLists.txt文件所在路径 |
${CMAKE_BINARY_DIR} | 顶级CMakeLists.txt构建输出所在的目录 |
${PROJECT_SOURCE_DIR} | 项目源码顶层目录 |
${PROJECT_BINARY_DIR} | 项目编译输出目录 |
${PROJECT_NAME} | 项目名称 |
${CMAKE_VERSION} | CMake的版本,由 MAJOR、MINOR、PATCH、TWEAK组成 |
${CMAKE_MAJOR_VERSION} | CMake的主要版本,假设CMake的版本是3.21,那么3就表示主要版本,21表示次要版本 |
${CMAKE_MINOR_VERSION} | CMake的次要版本 |
${CMAKE_PATCH_VERSION} | CMake的补丁版本 |
${CMAKE_TWEAK_VERSION} | CMake的微调版本 |