返回

Cmake Note

目录

起手式

1
2
3
4
5
cmake_minimum_required(VERSION 3.21.0)
project(myproj VERSION 0.1.0 LANGUAGES C CXX)
add_executable(myapp main.cpp ...)#编译为myapp.exe
add_library(test STATIC test.hpp)#编译为静态库
add_library(math SHARED main.hpp)#编译为动态库

生成配置

1
2
3
4
5
6
7
8
9
mkdir cmake-build 
cd cmake-build
cmake ..


cmake --build .
//启用多线程
cmake --build . -- -m:4
cmake --build . -- -j:4

build.sh

1
2
3
4
5
6
7
set -e

mkdir -p build
cd build

cmake ..
cmake --build . --target myapp --config Release

基本用法

1
2
3
4
5
set(BUILD_SHARED_LIBS ON) #设置bool值
message(STATUS/NOTICE/FATAL_ERROR "BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}")
#给布尔变量设置默认值。参数:变量的变量名,注释,默认值。
option(BUILD_LIBS "Compile sources into a library" OFF)
 #打印变量

message(“This is the NOTICE message”)
This is the NOTICE message

message(STATUS “This is the STATUS message”)
– This is the STATUS message

message(FATAL_ERROR “This is the FATAL_ERROR message”)
CMake Error at CMakeLists.txt:5 (message):
This is the FATAL_ERROR message

– Configuring incomplete, errors occurred!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
list(APPEND sources main.cpp test.hpp tes.cpp)
add_executable(myapp ${sources})   #列举

#访问环境变量
if(DEFINED ENV{TEMP})
  message("TEMP=$ENV{TEMP}")
endif()

#条件变量
if(BUILD_LIBS)
    ...
else()
    ...
endif()
#布尔表达式
NOT BUILD_LIBS 取反
A AND B A OR B A STREQUAL B 两个字符串 A  B 相等
EXIST PATH 路径为 PATH 的文件或目录存在
DEFINED VAR 变量 VAR 有定义

添加附加依赖项

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
target_link_libraries(myapp PRIVATE math)
target_include_directories(myapp PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")

事实上:
add_executable(myapp main.cpp test.cpp)
等于
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE test)

如果子模块中有定义的宏
target_compile_definitions(module PRIVATE 宏名)

生成动态库

1
2
3
4
5
6
//要在需生成动态库的模块中配置
#ifdef EXPORT
#define DECL_API __declspec(dllexport)
#else
#define DECL_API __declspec(dllimport)
#endif

模板

导出成静态库

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
set(MODULE_NAME "my_static_lib" CACHE STRING "静态库模块名称")

# 收集 .c/.cpp 源文件
file(GLOB_RECURSE MODULE_SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/*.c
    ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
)

# 收集 .h/.hpp 头文件
file(GLOB_RECURSE MODULE_HEADERS
    ${CMAKE_CURRENT_SOURCE_DIR}/*.h
    ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp
)

if(NOT MODULE_SOURCES)
    message(WARNING "模块 ${MODULE_NAME} 未找到任何 .c/.cpp 源文件,跳过静态库构建!")
    return()
endif()

add_library(${MODULE_NAME} STATIC
    ${MODULE_SOURCES}
    ${MODULE_HEADERS}
)

# 5. 设置静态库的属性
# 5.1 设置库的输出目录
set_target_properties(${MODULE_NAME} PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib  # 静态库输出到 build/lib
    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib  # 动态库(此处用不到,仅预留)
    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin  # 可执行文件(此处用不到,仅预留)
)

# 设置头文件搜索路径
target_include_directories(${MODULE_NAME}
    PUBLIC  # PUBLIC:上层可继承该头文件路径;PRIVATE:仅本模块内部使用
    ${CMAKE_CURRENT_SOURCE_DIR}  # 当前目录作为头文件根路径
)

# target_compile_options(${MODULE_NAME} PRIVATE -Wall -Wextra -O2)

# 链接其他依赖库(如果本模块依赖其他库,如:pthread、fmt 等)
# target_link_libraries(${MODULE_NAME} PRIVATE pthread fmt)

# 打印信息
message(STATUS "模块 ${MODULE_NAME} 构建配置:")
message(STATUS "  - 源文件数量:${CMAKE_ARGC}")
list(LENGTH MODULE_SOURCES SRC_COUNT)
message(STATUS "  - 源文件数量:${SRC_COUNT}")
message(STATUS "  - 头文件数量:${CMAKE_ARGC}")
list(LENGTH MODULE_HEADERS HDR_COUNT)
message(STATUS "  - 头文件数量:${HDR_COUNT}")
message(STATUS "  - 输出路径:${CMAKE_BINARY_DIR}/lib")

上层使用

1
2
3
4
5
6
# 1. 添加模块子目录(会自动执行模块内的 CMakeLists.txt)
add_subdirectory(my_module)

# 2. 链接静态库到目标(如可执行程序)
add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE my_static_lib)  # 链接模块静态库
Licensed under CC BY-NC-SA 4.0