CMake 是一个开源的 C++构建工具生成器,可以很方便的实现跨平台编译,解决 C++库之间的依赖关系。只需要配置 CMakeList.txt 文件就可以实现对 C++源代码构建的控制,而且还是库平台,简直太好用。下面记录了一些常用的 CMake 命令。
命令模式
平台无关的系统命令,用法示例
# 对 my.txt 文件,生成 md5
cmake -E md5sum my.txt
查看更多命令可以直接输入 cmake -E。
CTest
https://www.bookset.io/read/CMake-Cookbook/content-chapter4-4.1-chinese.md
设置 MSVC 编译器编译 utf8 编码格式的源文件
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
禁用特定警告
add_compile_options(“/wd4819”)
安装库
function(INSTALL_PROJECT)
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include"
DESTINATION "include" OPTIONAL)
install(TARGETS ${ARGN}
CONFIGURATIONS Debug
RUNTIME DESTINATION "bin_debug"
LIBRARY DESTINATION "lib_debug"
ARCHIVE DESTINATION "lib_debug")
install(TARGETS ${ARGN}
CONFIGURATIONS Release
RUNTIME DESTINATION "bin"
LIBRARY DESTINATION "lib"
ARCHIVE DESTINATION "lib")
# install target pdb
install(FILES $<TARGET_PDB_FILE:${ARGN}>
CONFIGURATIONS Release
DESTINATION "bin" OPTIONAL)
endfunction()
导入第三方库
这里针对已经只有头文件的库,已经编译好的非 CMake 工程库,和 CMake 工程库。
方式 1
set(EIGEN3_DIR "path_to_eigen_cmake")
if(NOT EXISTS "${EIGEN3_DIR}")
set(EIGEN3_DIR "")
endif()
find_package(EIGEN3 REQUIRED)
if(NOT EIGEN3_FOUND)
message(STATUS "Warning: Eigen was not found.")
else()
message(STATUS "Info: Eigen was found.)
include_directories(${EIGEN3_INCLUDE_DIR})
endif()
file(GLOB PLOG_DIR "path/plog*")
find_path(WITH_PLOG_INC "include/plog/Log.h" "${PLOG_DIR}" NO_DEFAULT_PATH)
if(WITH_PLOG_INC)
set(PLOG_INCLUDE_DIRS "${WITH_PLOG_INC}/include")
include_directories(${PLOG_INCLUDE_DIRS})
else()
message(STATUS "Warning: plog was not found.")
endif()
set(Protobuf_SRC_ROOT_FOLDER "path_protobuf_dir")
if(NOT EXISTS "${Protobuf_SRC_ROOT_FOLDER}")
set(Protobuf_SRC_ROOT_FOLDER "")
endif()
find_package(Protobuf_SRC_ROOT_FOLDER REQUIRED)
if(NOT Protobuf_SRC_ROOT_FOLDER_FOUND)
message(STATUS "Warning: Protobuf was not found.")
else()
message(STATUS "Info: Protobuf was found.)
include_directories(${Protobuf_INCLUDE_DIRS})
endif()
方式 2
使用 CMAKE_PREFIX_PATH
if(WIN32 AND MSVC)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(QT_PATH "qt_path" CACHE PATH "Qt path")
endif()
set(CMAKE_PREFIX_PATH "${QT_PATH}")
mark_as_advance(QT_PATH)
endif()
find_package(Protobuf REQUIRED)
if(NOT Protobuf_FOUND)
message(STATUS "Warning: Protobuf was not found.")
else()
message(STATUS "Info: Protobuf was found.")
include_directories(${Protobuf_INCLUDE_DIRS})
endif()
Qt 翻译文件
https://gitlab.kitware.com/cmake/cmake/-/issues/21549
MACRO 和 FUNCTION
https://blog.csdn.net/weixin_34121282/article/details/87972772
https://www.jianshu.com/p/6be3b104ab70
共同点
形式基本相同。
marco 形式如下:
macro(<name> [arg1 [arg2 [arg3 ...]]])
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
endmacro()
function 形式如下:
function(<name> [arg1 [arg2 [arg3 ...]]])
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
endfunction()
变量的引用:
变量 | 说明 |
---|---|
ARGV# | 同上 |
ARGV | 所有定义时要求传入的参数 |
ARGN | 定义时要求输入的参数以外的参数,比如定义时要求输入 1 个参数,实际输入了 3 个,那么后面两个参数保存在 ARGN 中 |
ARGC | 传入的实际参数个数 |
设置构建 toolset
在高版本的 Visual Studio 可以使用低版本的 toolset 进行编译,比如,vs2019,安装了 vs2017 的构建工具和 sdk 后可以使用 vs2017 构建 cmake 项目。
# 设置 generator
-G "Visual Studio 15 2017"
# 设置 toolset
-T v141
设置输出目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}")
设置工程调试的工作目录
VS_DEBUGGER_WORKING_DIRECTORY
设置工程属性
输出文件名
set_target_properties(LibraryA PROPERTIES OUTPUT_NAME "my_LibraryA")
预处理器定义
set_target_properties(LibraryA PROPERTIES COMPILE_DEFINITIONS "LibraryA_EXPORTS")
工程分组
根目录设置:
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
每个分组下工程设置:
set_target_properties(LibraryA PROPERTIES FOLDER "Utilities")
set_target_properties(LibraryB PROPERTIES FOLDER "Utilities")
源文件分组
source_group("game\\entitysystem\\components" FILES ${components_SRC})
设置 Windows Qt 工程不弹出命令行窗口
#--------------------------------------------------------------------
# Hide the console window in visual studio projects
#--------------------------------------------------------------------
if(MSVC)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
endif()
#--------------------------------------------------------------------
# Hide the console window in visual studio projects - Release
#--------------------------------------------------------------------
if(MSVC)
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
endif()
INCLUDE_DIRECTORIES
作用域
The include directories are added to the INCLUDE_DIRECTORIES directory property for the current CMakeLists file. They are also added to the INCLUDE_DIRECTORIES target property for each target in the current CMakeLists file.
set
用法
set
赋值给一般变量
仅在所在的作用域起作用。除非后面使用 PARENT_SCOPE。举例
// foo 作用域为当前作用域
set(foo "X")
// foo 作用域是当前文件的上一目录的 CMakeList
set(foo "x" PARENT_SCOPE)
set
赋值给缓存变量
第一次运行 cmake 时,这些变量缓存到 CMakeCache.txt 中,在整个 cmake 运行过程中都可以起作用。
当使用 CACHE 时,且缓存中没有该变量时,变量被创建并且存入缓存中,如果原缓存中有该变量,也不会改变原缓存中该变量的值,除非后面使用 FORCE。
// 原缓存中没有 foo,则将 foo 赋值为 x,且存入缓存
// 原缓存中有 foo,则不做改变
set(foo "x" CACHE <type> <docstring>)
// 即使原缓存中存在 foo,也会重新设置 foo
set(foo "x" CACHE <type> <docstring> FORCE)
使用 CACHE 时,要设定<type>
和docstring
。
type | description |
---|---|
FILEPATH | File chooser dialog. |
PATH | Directory chooser dialog. |
STRING | Arbitrary string. |
BOOL | Boolean ON/OFF checkbox. |
INTERNAL | No GUI entry (used for persistent variables). |
可以通过 CMake 变量声明另一个变量
set(${macroparam}_LOCATION “”)
在 CMakeList 文件中使用
message(STATUS ${${macroparam}_LOCATION})
设置后缀
set(CMAKE_DEBUG_POSTFIX "_d")