常用设置

设置编译输出路径

在CMakeList.txt中如下设置后,无论是编译可执行文件还是编译静态库,都会输出到指定目录下,而不再是默认的当前目录。

#静态库输出目录(lib, a)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "lib/")

#编译时动态库输出目录(dll + lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY  "lib/")

#动态库输出目录(dll, so)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY  "lib/")

#可执行文件输出目录
set(EXECUTABLE_OUTPUT_PATH  "bin/")

参考:
is CMake ignoring CMAKE_LIBRARY_OUTPUT_DIRECTORY?
https://stackoverflow.com/a/38450844/1645289

How do I make CMake output into a ‘bin’ dir? https://stackoverflow.com/a/6595001/1645289

cmake 常用设定及函数
https://blog.csdn.net/LaineGates/article/details/79190398

获取指定目录下的所有源文件

获取./src目录下的所有hpp和cpp文件(只获取./src当前目录文件,不递归查询./src下的子目录):

file(GLOB CPP_FILES ./src/*.hpp ./src/*.cpp)
add_library(mylib STATIC ${CPP_FILES})

获取./src/player/目录和./src/monster/目录下的所有cpp文件(同时递归这两个目录下的所有子目录):

file(GLOB_RECURSE CPP_FILES
   ./src/player/*.cpp
   ./src/monster/*.cpp)

参考:How to use cmake GLOB_RECURSE for only some subdirectories
https://stackoverflow.com/a/27994855/1645289

打印log
if (NOT CMAKE_VERSION VERSION_GREATER "3.0")
    message(FATAL_ERROR "cmake version 3.x is required!")
endif()
打印变量
message(STATUS "foo include dir: ${foo_INCLUDE}")
修改默认的CMAKE_MODULE_PATH目录

CMAKE_MODULE_PATH是供find_package搜索第三方库用的。cmake的默认Modules目录在安装目录中:cmake-3.11.3-win64-x64\share\cmake-3.11\Modules
如果要追加Modules目录,有3种方式:

set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_PATH}:${CMAKE_MODULE_PATH}")

LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_PREFIX}")

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
find_package用法

通常情况下,包含第三方库需要写以下内容

include_directories("${project_root_path}/include/")  
link_directories(./lib)
add_executable(myapp myapp.cpp)
target_link_libraries(myapp mylib)  

如果引用的很多个第三方库,那么类似上面的内容会写很多,且如果自己的多个项目都引用了某个第三方库,那么我每个项目的CmakeList.txt都得写一遍,重复劳动很多。那么有没办法为每个第三方库只定义一次它的头文件和库文件信息,然后在自己的工程中只指定名称即可?(类似编译Java的Maven仓库)答案是当然可以,find_package帮你解决。

find_package定义在自己工程的CmakeList.txt中:

find_package( XXX CONFIG REQUIRED )

然后cmake就会在默认的Modules(即CMAKE_MODULE_PATH指定的目录)目录中搜索这个XXX第三方库。
搜索有两种模式:FindXXX.cmakeXXXConfig.cmake。前者叫做Module模式,后者叫做Config模式

  • Module模式
    搜索CMAKE_MODULE_PATH指定路径下的FindXXX.cmake文件,通过该文件从而找到XXX库的头文件和lib文件位置。FindXXX.cmake中需要定义XXX_INCLUDE_DIRSXXX_LIBRARIES
  • Config模式
    搜索XXX_DIR指定路径下的XXXConfig.cmake文件(XXX_DIR定义在自己工程的CMakeList.txt或者cmake-gui的环境变量中),通过该文件从而找到XXX库的头文件和lib文件位置。XXXConfig.cmake中需要定义XXX_INCLUDE_DIRSXXX_LIBRARIES

Config模式示例:
先在自己工程的CMakeList.txt中添加

set(XXX_DIR D:/sdk/XXX-0.9.9.0/bin)
find_package( XXX CONFIG REQUIRED )

其中CONFIG表示使用Config模式搜索,默认是Module模式;然后D:/sdk/XXX-0.9.9.0/cmake目录下必须存在XXXConfig.cmake文件,否则当执行cmake时会提示找不到XXXConfig.cmake。

XXXConfig.cmake和XXXTargets.cmake都不是手动编写的,而是CMake自动生成的!!

生成Config.cmake的参考代码:
https://github.com/g-truc/glm/blob/0d973b40a49e550b1ea7df22a8573bc5fff84f24/CMakeLists.txt#L175

生成Targets.cmake的参考代码:
https://github.com/g-truc/glm/blob/0d973b40a49e550b1ea7df22a8573bc5fff84f24/CMakeLists.txt#L198

使用通配符批量指定头文件或源文件 (include source files batch using wildcard)

GLOB:

FILE(GLOB cpp_files ../src/*.cc)

add_executable(helloworld ${cpp_files})

There’s also GLOB_RECURSE if you want to find the files recursively.

How to use all *.c files in a directory with the Cmake build system?
https://stackoverflow.com/a/3366701

Automatically add all files in a folder to a target using CMake?
https://stackoverflow.com/a/3201211

How to enable Google Sanitizers in CMake

Configuration for GCC in CMakeLists.txt

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize=leak -fsanitize=thread -g")

Configuration for xcode schema
in CMake:

cmake_minimum_required(VERSION 3.13)
set(CMAKE_XCODE_GENERATE_SCHEME ON)
set(CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER ON)
set(CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN ON)

When Build:

xcodebuild -enableAddressSanitizer YES

Reference:
What’s the proper way to enable AddressSanitizer in CMake that works in Xcode
https://stackoverflow.com/a/45940322

How to change the name of CMakeLists.txt

There’s no reasonable excuse that CMake doesn’t use a specified file extension like every other tool in the toolkit. You can do this by putting a dummy CMakeLists.txt, which contains:

cmake_minimum_required(VERSION 3.8)
INCLUDE("meaningfulFilename.cmake")

Then put your actual cmake code in the .cmake file.

Origin:
https://stackoverflow.com/a/53743295/1645289

add_subdirectory: relative patch of subdirectory

Add subdirectory in current directory:

add_subdirectory(Lua)

Add subdirectory in relative path:

add_subdirectory(./../Lua build_lua)

Visual Studio

Set startup project
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT MyExeTarget)

Origin:
https://stackoverflow.com/a/59789571/1645289

Compile with /MT or /MD

How to set Runtime Library for Visual Studio:

set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")

Origin:
Compile with /MT instead of /MD using CMake
https://stackoverflow.com/a/14172871/1645289

Compiler

How to enable C++17 features for compiler
#enable C++17 features
target_compile_features(${MY_PROJECT_NAME} PRIVATE cxx_std_17)

CMake Examples

Comprehensive

Command line C++ barcode reader for Windows, Linux, and macOS.
https://github.com/dynamsoft-dbr/cmake

learning cmake
https://github.com/Akagi201/learning-cmake

Useful CMake Examples
https://github.com/ttroy50/cmake-examples

A curated list of awesome CMake resources, scripts, modules, examples and others.
https://github.com/onqtam/awesome-cmake

A template for modern C++ projects using CMake, clang-format and unit testing, with support for downstream inclusion
https://github.com/filipdutescu/modern-cpp-template

iOS, MacOS

A CMake toolchain file for iOS, watchOS and tvOS C/C++/Obj-C++ development
https://github.com/leetal/ios-cmake

Example. Compile android, iOS, mac static lib on MacOS.
https://github.com/9b9387/CMakeCrossCompiling


伦常乖舛,立见消亡;德不配位,必有灾殃。----《朱子家训》