基本结构
- CMake 最低版本声明
用于指定需要的最低 CMake 版本,确保兼容性。
cmake
cmake_minimum_required(VERSION 3.10)
- 指定 CMake 的最低版本。
- 确保用户的 CMake 版本符合项目需求,否则报错。
- 版本选择建议根据项目使用的功能决定。例如,3.10 引入了
target_link_directories
。
- 项目名称和语言定义
定义项目的名称及支持的编程语言。
cmake
project(ProjectName LANGUAGES C CXX)
ProjectName
:项目名称,自动赋值给变量${PROJECT_NAME}
。LANGUAGES
:指定项目支持的语言,可以是C
、CXX
(C++)、Fortran
等。- 默认生成变量:
${PROJECT_SOURCE_DIR}
:项目根目录。${PROJECT_BINARY_DIR}
:构建目录。
- 设置编译选项
设置标准版本(如 C++17)或添加额外的编译器选项。
cmake
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
CMAKE_CXX_STANDARD
:设置 C++ 标准(如 11、14、17、20)。CMAKE_CXX_STANDARD_REQUIRED
:强制使用指定版本。CMAKE_CXX_EXTENSIONS
:是否使用非标准扩展(如-std=gnu++17
)。
- 定义源文件和头文件路径
将源代码组织到变量中,或直接指定路径。
cmake
set(SOURCES src/main.cpp src/foo.cpp)
set(INCLUDES include/)
- 生成可执行文件或库
指定目标类型(可执行文件、静态库、动态库)。
cmake
# 添加可执行文件
add_executable(MyApp ${SOURCES})
# 添加静态库
add_library(MyStaticLib STATIC src/foo.cpp src/bar.cpp)
# 添加动态库
add_library(MySharedLib SHARED src/foo.cpp src/bar.cpp)
- 设置目标的头文件路径
将头文件目录添加到目标的构建路径中。
cmake
target_include_directories(MyApp PRIVATE ${INCLUDES})
- 链接内部库
链接外部依赖库或内部生成的库。
cmake
target_link_libraries(MyApp PRIVATE MyLib)
- 查找外部库(可选)
查找并使用外部库(如 Boost 或 OpenCV)。
cmake
find_package(OpenCV REQUIRED)
target_link_libraries(MyApp PRIVATE ${OpenCV_LIBS})
- 安装规则
指定生成的二进制文件、配置文件等的安装路径。
cmake
install(TARGETS MyApp DESTINATION bin)
install(FILES config/settings.conf DESTINATION etc)
install()
定义安装文件的位置。- 常见用途:
- 安装可执行文件到
bin
。 - 安装库到
lib
。 - 安装配置文件到
etc
。
- 安装可执行文件到
- 测试支持(可选)
启用单元测试功能。
cmake
enable_testing()
add_test(NAME MyTest COMMAND MyApp --test)
- 子目录管理(可选)
用于大型项目,将多个模块分割到不同的子目录。
cmake
add_subdirectory(src/module1)
- 对于大型项目,将代码分割到子目录中,通过
add_subdirectory()
引入。
子模块的 CMakeLists.txt
:
cmake
add_library(Module1 STATIC module1.cpp)
target_include_directories(Module1 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
- 添加自定义命令和目标(可选)
- 添加自定义命令:
cmake
add_custom_command(
OUTPUT generated.cpp
COMMAND python generate.py > generated.cpp
DEPENDS generate.py
)
- 添加自定义目标:
cmake
add_custom_target(GenerateCode ALL DEPENDS generated.cpp)
- 使用变量和条件(动态配置)
- 条件语句:
cmake
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
message("Debug build")
endif()
- 变量替换:
cmake
set(VERSION "1.0.0")
message("Project version: ${VERSION}")
示例1:单模块(c++)
项目结构
css
MyProject/
├── CMakeLists.txt
├── src/
│ ├── main.cpp
│ ├── foo.cpp
├── include/
│ └── foo.h
└── config/
└── settings.conf
代码文件
src/main.cpp
:
c++
#include <iostream>
#include "foo.h"
int main() {
std::cout << "Sum of 3 and 5 is: " << add(3, 5) << std::endl;
return 0;
}
src/foo.cpp
:
c++
#include "foo.h"
int add(int a, int b) {
return a + b;
}
include/foo.h
:
c++
#ifndef FOO_H
#define FOO_H
int add(int a, int b);
#endif
config/settings.conf
:
txt
# This is a placeholder configuration file
CMakelist.txt
cmake
# 设置 CMake 最低版本
cmake_minimum_required(VERSION 3.10)
# 定义项目名称和语言
project(MyProject LANGUAGES CXX)
# 设置编译选项
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 定义源文件和头文件目录
set(SOURCES
src/main.cpp
src/foo.cpp
)
set(INCLUDES
include/
)
# 添加可执行目标
add_executable(MyApp ${SOURCES})
# 配置头文件路径
target_include_directories(MyApp PRIVATE ${INCLUDES})
# 安装规则
install(TARGETS MyApp DESTINATION bin)
install(FILES config/settings.conf DESTINATION etc)
# 启用测试支持
enable_testing()
add_test(NAME RunTests COMMAND MyApp)
构建和运行
1. 创建构建目录
为了保持源文件清晰,推荐在源代码目录外创建构建目录:
bash
mkdir build
cd build
2. 运行 CMake
使用 CMake 生成构建文件:
bash
cmake ..
3. 编译项目
使用 CMake 的构建命令:
bash
cmake --build .
4. 运行程序
bash
./MyApp
5. 安装程序
将可执行文件和配置文件安装到指定目录:
bash
cmake --install .
示例2:多模块(c++)
项目结构
css
MyProject/
├── CMakeLists.txt # 顶层 CMakeLists.txt
├── module1/ # 模块1
│ ├── CMakeLists.txt # 模块1的 CMakeLists.txt
│ ├── module1.cpp
│ └── module1.h
├── module2/ # 模块2
│ ├── CMakeLists.txt # 模块2的 CMakeLists.txt
│ ├── module2.cpp
│ └── module2.h
├── app/ # 主程序
│ ├── CMakeLists.txt # 主程序的 CMakeLists.txt
│ ├── main.cpp
└── build/ # 构建目录
顶层 CMakeLists.txt
顶层的 CMakeLists.txt
文件负责整体项目的配置,包括引入各个模块、设置编译选项以及定义最终的构建目标。
cmake
# 设置最低 CMake 版本
cmake_minimum_required(VERSION 3.10)
# 定义项目名称和语言
project(MyProject LANGUAGES CXX)
# 设置编译选项
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 添加子模块目录
add_subdirectory(module1)
add_subdirectory(module2)
add_subdirectory(app)
模块1的 CMakeLists.txt
模块1构建为一个静态库,提供对其他模块的功能支持。
cmake
# 定义模块1的库
add_library(Module1 STATIC module1.cpp)
# 指定模块1的头文件路径
target_include_directories(Module1 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
# 可选:设置特定的编译选项(如果模块需要)
target_compile_options(Module1 PRIVATE -Wall -Wextra)
模块2的 CMakeLists.txt
模块2构建为一个动态库,并依赖模块1。
cmake
# 定义模块2的库
add_library(Module2 SHARED module2.cpp)
# 指定模块2的头文件路径
target_include_directories(Module2 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
# 链接模块1
target_link_libraries(Module2 PUBLIC Module1)
主程序的 CMakeLists.txt
主程序依赖模块1和模块2,并最终生成可执行文件。
cmake
# 定义主程序的可执行目标
add_executable(MyApp main.cpp)
# 链接模块1和模块2
target_link_libraries(MyApp PRIVATE Module1 Module2)
# 指定主程序的头文件路径(如果需要)
target_include_directories(MyApp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
示例代码
- module1/module1.h
c++
#ifndef MODULE1_H
#define MODULE1_H
int add(int a, int b);
#endif
- module1/module1.cpp
c++
#include "module1.h"
int add(int a, int b) {
return a + b;
}
- module2/module2.h
c++
#ifndef MODULE2_H
#define MODULE2_H
int multiply(int a, int b);
#endif
- module2/module2.cpp
c++
#include "module2.h"
#include "module1.h"
int multiply(int a, int b) {
return a * add(a, b); // 使用模块1的功能
}
- app/main.cpp
c++
#include <iostream>
#include "module1.h"
#include "module2.h"
int main() {
int a = 3, b = 5;
std::cout << "Add: " << add(a, b) << std::endl;
std::cout << "Multiply: " << multiply(a, b) << std::endl;
return 0;
}
功能扩展
-
模块化管理 : 将子模块组织到不同目录,并通过
add_subdirectory()
引入。 -
外部库集成 : 使用
find_package()
和target_link_libraries()
管理外部库。 -
生成静态库 : 使用
add_library()
定义静态库目标,并链接到其他可执行文件。 -
跨平台支持: CMake 支持跨平台构建(如 Makefile、Visual Studio 项目文件等)。