CMake是一个开源的跨平台自动化构建系统,它使用一个名为**CMakeLists.txt
**的配置文件来定义项目的构建过程。CMake的主要目标是简化和标准化构建过程,特别是在需要跨不同平台(如Windows, Linux, 和 macOS)进行构建的项目中。
它主要用于:
尽管CMake在许多方面提供了改进,但在一些简单的场景中,传统的Makefile可能更直接和简单。选择最佳工具往往取决于项目的具体需求和团队的熟悉度。
2 安装和基本设置:
Windows:
Linux:
使用包管理器: 在大多数Linux发行版中,可以使用包管理器安装CMake。例如,在基于Debian的系统(如Ubuntu)上,可以使用以下命令:
sqlCopy code
sudo apt-get update
sudo apt-get install cmake
手动安装: 如果需要最新版本,可以从CMake官网下载源代码包,然后编译安装。
macOS:
使用Homebrew: 如果安装了Homebrew,可以简单地运行以下命令:
Copy code
brew install cmake
手动安装: 访问CMake官方网站下载适用于macOS的安装包,并按照指示进行安装。
main.cpp
**)。在项目根目录中创建一个名为**CMakeLists.txt
**的文件。
文件内容示例:
cmakeCopy code
cmake_minimum_required(VERSION 3.10) # 指定CMake最低版本要求
project(MyProject) # 定义项目名称
add_executable(myapp main.cpp) # 创建一个名为myapp的可执行文件
这个文件定义了项目的基本信息和构建目标。
打开终端或命令提示符。
切换到项目根目录。
运行以下命令来生成构建系统:
Copy code
cmake .
这会在当前目录生成适用于你系统的构建文件(如Makefile)。
在同一目录下运行构建命令,例如:
cssCopy code
cmake --build .
这将编译源代码并生成可执行文件。
3 编写CMakeLists文件:
CMakeLists.txt 文件是CMake构建系统的核心,它使用CMake专用的语法编写。以下是其基本结构和语法要点:
cmake_minimum_required(VERSION minimum_version)
指定所需的最低CMake版本,这有助于确保构建过程的兼容性。cmake_minimum_required(VERSION 3.10)
project(project_name)
定义项目名称。project(MyProject)
set(VAR_NAME value)
来设置变量。set(SOURCE_FILES main.cpp)
add_executable(executable_name ${SOURCE_FILES})
或 add_library(library_name ${SOURCE_FILES})
。add_executable(myapp ${SOURCE_FILES})
include_directories(dir1 dir2 ...)
和 target_link_libraries(target lib1 lib2 ...)
if
, else
, endif
)和循环语句(如 foreach
, while
)。add_executable
或 add_library
函数中,或者通过设置一个变量来引用。add_executable(myapp main.cpp utility.cpp)
include_directories(your_header_directory)
来包含这些目录。target_compile_options
来为特定目标设置编译器标志。target_compile_options(myapp PRIVATE -Wall -Wextra)
add_definitions(-DDEFINE)
来添加预处理器定义。add_definitions(-DMY_DEFINE)
4 管理项目依赖:
.lib
、.dll
、.so
**等),可以直接将它们包含在项目中。target_link_libraries(target_name path_to_library)
来链接库文件。include_directories(path_to_header_files)
来包含库的头文件。find_package
来定位已安装的库find_package
命令用于在系统中查找并定位已安装的库。
使用格式:find_package(LibraryName REQUIRED)
如果找到,CMake会设置一些变量,比如 LibraryName_FOUND
和库的具体路径。
一旦找到库,可以使用 target_link_libraries
将其链接到你的目标中。
例如,要查找并链接OpenGL库:
cmakeCopy code
find_package(OpenGL REQUIRED)
target_link_libraries(your_target_name ${OPENGL_LIBRARIES})
add_subdirectory(subdir)
来添加包含另一个 CMakeLists.txt
文件的子目录。ExternalProject_Add
命令来下载、配置、构建和安装外部项目。5 创建可执行文件和库:
add_executable
和 add_library
add_executable
:
add_executable( ... )
add_executable(app main.cpp utility.cpp)
add_library
:
add_library( STATIC|SHARED|MODULE ... )
add_library(mylib STATIC library.cpp utility.cpp)
静态库 (Static Libraries):
.lib
或 .a
。动态库 (Dynamic Libraries):
.dll
(Windows), .so
(Linux), 或 .dylib
(macOS)。在选择静态库和动态库时,需要考虑到应用程序的需求、部署策略和平台限制。CMake提供了灵活性来支持这两种类型的库,使得构建过程更加简化和自动化。
5 高级特性:
条件语句:
在 CMakeLists.txt
中,可以使用 if
, elseif
, else
, 和 endif
来创建条件语句。
用于根据不同条件(如平台、变量值等)执行不同的构建操作。
示例:
cmakeCopy code
if(WIN32)
# 特定于Windows的配置
elseif(UNIX)
# 特定于Unix/Linux的配置
endif()
循环语句:
循环语句,如 foreach
和 while
,用于重复执行一组命令。
foreach
循环通常用于迭代列表。
示例:
cmakeCopy code
foreach(src IN ITEMS src1.cpp src2.cpp src3.cpp)
message("Source file: ${src}")
endforeach()
宏(Macro):
宏类似于函数,但不创建新的作用域。
使用 macro(name arg1 arg2 ...)
和 endmacro()
定义宏。
示例:
cmakeCopy code
macro(print_detail var)
message("The value of ${var} is: ${${var}}")
endmacro()
set(VAR1 "Hello")
print_detail(VAR1) # 输出 "The value of VAR1 is: Hello"
函数(Function):
函数创建自己的作用域,参数和内部变量在函数外不可见。
使用 function(name arg1 arg2 ...)
和 endfunction()
定义函数。
示例:
cmakeCopy code
function(print_sum a b)
set(sum ${a} + ${b})
message("Sum: ${sum}")
endfunction()
print_sum(5 10) # 输出 "Sum: 5 + 10"
CMake可以生成导入和导出配置,使其他项目能够轻松使用库。
使用 install(TARGETS ...)
和 export(TARGETS ...)
命令来指定如何安装和导出库。
还可以使用 install(EXPORT ...)
和 export(EXPORT ...)
管理复杂的依赖关系。
示例:
cmakeCopy code
add_library(mylib SHARED src.cpp)
install(TARGETS mylib DESTINATION lib)
install(EXPORT MyLibConfig DESTINATION share/MyLib/cmake)
export(TARGETS mylib FILE MyLibConfig.cmake)
6 测试和安装:
CMake通过集成CTest提供了测试支持。以下是设置和运行测试的基本步骤:
启用测试:
CMakeLists.txt
文件顶部添加enable_testing()
**命令,以启用测试功能。添加测试:
使用**add_test(NAME test_name COMMAND test_executable)
**添加测试。
**test_name
是你给测试起的名字,test_executable
**是执行测试的可执行文件。
示例:
cmakeCopy code
add_executable(test_app test_app.cpp)
add_test(NAME TestApp COMMAND test_app)
运行测试:
ctest
**在终端或命令行中运行测试。ctest -V
**以获得详细的输出。CMake允许你定义安装规则,用于将构建的目标(可执行文件、库、头文件等)安装到适当的位置。
指定安装规则:
使用**install()
**命令指定应如何安装目标和文件。
常见的安装类型包括TARGETS、FILES和DIRECTORY。
示例:
cmakeCopy code
# 安装可执行文件
install(TARGETS myapp DESTINATION bin)
# 安装库
install(TARGETS mylib DESTINATION lib)
# 安装头文件
install(FILES myheader.h DESTINATION include)
生成安装包:
CMakeLists.txt
中包含include(CPack)
**并设置CPack相关的配置。执行安装:
cmake --install .
**安装项目。cmake --install . --prefix "/path/to/install"
。7 最佳实践和常见问题:
CMakeLists.txt
的开始指定最低CMake版本,如cmake_minimum_required(VERSION 3.10)
**。project(ProjectName)
**清晰地命名你的项目。file(GLOB ...)
或file(GLOB_RECURSE ...)
**来自动收集源文件列表。${CMAKE_BINARY_DIR}
、${PROJECT_SOURCE_DIR}
**。add_subdirectory()
**将项目分解为多个模块。target_include_directories()
和target_compile_definitions()
**等,而不是全局命令。set(CMAKE_BUILD_TYPE Release)
**。install(EXPORT)
和export()
**来生成和使用可导入的目标。find_package()
**时,检查是否指定了正确的版本和路径。cmake_minimum_required
**。target_compile_options()
**为特定目标设置编译器标志。8 案例研究和实例:
让我们通过一个简单的C++项目来展示CMake的使用。这个项目将包括一个主要的可执行文件和一个静态库。
假设我们的项目结构如下所示:
scssCopy code
MyProject/
│
├── CMakeLists.txt (项目根CMakeLists文件)
│
├── src/
│ ├── main.cpp (主程序源文件)
│
└── lib/
├── MathFunctions.cpp (库源文件)
├── MathFunctions.h (库头文件)
└── CMakeLists.txt (库的CMakeLists文件)
在项目的根目录下的**CMakeLists.txt
**:
cmakeCopy code
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# 指定C++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# 添加子目录
add_subdirectory(lib)
# 包含头文件目录
include_directories(lib)
# 添加可执行文件
add_executable(myapp src/main.cpp)
# 链接库到可执行文件
target_link_libraries(myapp MathFunctions)
在**lib/
目录下的CMakeLists.txt
**:
cmakeCopy code
# 创建静态库
add_library(MathFunctions MathFunctions.cpp)
# 指定库的公共头文件
target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
cmake_minimum_required(VERSION 3.10)
:指定CMake的最低版本。project(MyProject)
:定义项目名称。add_subdirectory(lib)
:添加子目录,CMake将查找该目录中的CMakeLists.txt。include_directories(lib)
:包含静态库的头文件目录。add_executable(myapp src/main.cpp)
:创建一个名为**myapp
**的可执行文件。target_link_libraries(myapp MathFunctions)
:将**MathFunctions
库链接到myapp
**可执行文件。add_library(MathFunctions MathFunctions.cpp)
:创建一个名为**MathFunctions
**的静态库。target_include_directories
:定义库的头文件目录,这样在项目的其他地方就可以找到这些头文件。9 资源和进一步学习: