跳至主要內容

CMake教程

ekskei大约 6 分钟C/C++CMake

CMake教程

CMake是一个跨平台的管理源代码构建的工具。最初CMake被设计为的Makefile的生成器,现在CMake也可以生成现代的构建系统,如Ninja以及Visual Studio和Xcode等IDE的项目文件。CMake被广泛用于C和C++语言,也可以用于构建其他语言的源代码。

CMakeLists.txt 文件的编写

CMakeLists.txt 是 CMake 的配置文件,用于定义项目的源代码、依赖项和构建选项。在编写 CMakeLists.txt 文件时,通常需要包括以下几个部分:

CMake 最低版本要求

在 CMakeLists.txt 文件的开头,需要指定 CMake 的最低版本要求。这可以通过 cmake_minimum_required 命令来实现,例如:

cmake_minimum_required(VERSION 3.10)

项目名称和源代码

接下来,需要指定项目的名称和源代码。这可以通过 project 和 add_executable 命令来实现,例如:

project(MyProject)

add_executable(my_exe main.cpp)

在这个例子中,我们指定了项目名称为 MyProject,将 main.cpp 文件添加到源代码中,并将生成的可执行文件命名为 my_exe。

依赖项

如果项目依赖于其他库或框架,需要在 CMakeLists.txt 文件中指定这些依赖项。这可以通过 find_package 命令和 target_link_libraries 命令来实现。例如,如果项目依赖于 Boost 库,可以使用以下命令:

find_package(Boost REQUIRED)

target_link_libraries(my_exe Boost::boost)

构建选项

最后,需要指定构建选项,例如编译器选项、链接器选项、目标平台等。这可以通过 add_compile_options 命令和 set 命令来实现。

例如,如果要使用 C++11 标准编译源代码,可以使用以下命令:

add_compile_options(-std=c++11)

在编译时启用警告信息可以帮助发现代码中的潜在问题,例如:

add_compile_options(-Wall)

这样可以启用所有警告信息,也可以根据需要启用特定的警告选项。

项目配置和构建

在编写完 CMakeLists.txt 文件后,就可以进行项目配置和构建了。

下面是基本的项目配置和构建步骤:

创建构建目录

首先,需要创建一个新的目录,用于构建项目。建议将该目录与源代码目录分开,并将其命名为 build,例如:

mkdir build

cd build

配置项目

接下来,需要在构建目录中运行 CMake,以配置项目。可以使用以下命令:

cmake /path/to/source

其中,/path/to/source 是源代码目录的路径,一般就是上一层目录 .. 。

在配置项目时,可以指定一些选项,例如构建类型、目标平台等。这些选项可以通过 -D 参数传递给 CMake,例如:

cmake -DCMAKE_BUILD_TYPE=Release /path/to/source
这个命令将指定构建类型为 Release。

构建项目

配置完成后,就可以构建项目了。

可以使用以下命令:

cmake --build .

这个命令将使用默认的构建工具来构建项目。如果要使用特定的构建工具,可以使用 -G 参数,例如:

cmake -G "Unix Makefiles" --build .

这个命令将使用 Make 构建工具来构建项目,此时也可以直接运行 make 。

运行项目

构建完成后,就可以运行生成的可执行文件了。如果使用默认的名称和路径,可以使用以下命令:

./my_exe

如果生成的可执行文件位于其他目录中,需要指定其完整路径,例如:

/path/to/build/my_exe

交叉编译

CMake 支持交叉编译,可以在本地主机上构建针对嵌入式设备的代码。以下是几种不同的配置交叉编译的方法:

设置交叉编译工具链

在 CMakeLists.txt 文件中,使用 set 命令设置交叉编译工具链,例如:

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER /path/to/arm-linux-gcc)
set(CMAKE_CXX_COMPILER /path/to/arm-linux-g++)

这里将系统名称设置为 Linux,处理器设置为 arm,C 编译器和 C++ 编译器设置为 arm-linux-gcc 和 arm-linux-g++,这些设置应根据实际情况进行修改。

可以将以上设置的内容保存到 arm-linux.cmake 文件中,然后在 CMakeLists.txt 中包含进去,例如:

include(/path/to/arm-linux.cmake)

设置交叉编译器的根路径

在 CMakeLists.txt 文件中,使用 set 命令设置交叉编译器的根路径,例如:

set(CMAKE_FIND_ROOT_PATH /path/to/toolchain/)
set(CMAKE_SYSROOT /path/to/sysroot/)

这里将交叉编译器根路径设置为 /path/to/toolchain/,系统根目录设置为 /path/to/sysroot/,这些路径应根据实际情况进行修改。

传参数指定交叉编译工具链的.cmake文件

使用 -DCMAKE_TOOLCHAIN_FILE 选项指定交叉编译工具链的路径,例如:

cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/arm-linux.cmake ..

这里将交叉编译工具链的路径设置为 /path/to/arm-linux.cmake,这样 CMake 就可以使用交叉编译工具链来生成针对嵌入式设备的代码。

经验总结

使用变量

使用变量可以使 CMakeLists.txt 文件更加简洁和易读,并且可以方便地修改编译选项和路径等常量。例如:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(SOURCE_FILES main.cpp)
add_executable(my_exe ${SOURCE_FILES})

CMake 提供了许多内置变量来自定义构建过程,例如:

CMAKE_BUILD_TYPE:指定构建类型,可选值包括:

  • Debug:用于在没有优化的情况下,使用带有调试符号构建库或可执行文件
  • Release:用于构建的优化的库或可执行文件,不包含调试符号
  • RelWithDebInfo:由于构建较少的优化库或可执行文件,包含调试符号
  • MinSizeRel:用于不增加目标代码大小的优化方式,来构建或可执行文件

CMAKE_INSTALL_PREFIX:指定安装目录的路径。

CMAKE_CXX_COMPILER:指定 C++ 编译器的路径。

使用这些变量可以方便地定制构建过程,以满足特定的需求。

使用 find_package

使用 find_package 命令可以方便地查找和配置依赖项,例如:

find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(my_exe ${OpenCV_LIBS})

这样可以方便地使用 OpenCV 库,而不需要手动指定头文件和库文件路径。

使用 add_subdirectory

实际项目中,通常会有多个模块,每个模块相当于一个子项目,使用 add_subdirectory 命令可以方便地构建子项目,例如:

add_subdirectory(my_lib)

target_link_libraries(my_exe my_lib)

这样可以方便地使用 my_lib 子项目,并将它链接到 my_exe 可执行文件中。

使用 configure_file

使用 configure_file 命令可以方便地生成配置文件,例如:

set (VERSION_MAJOR 1)
set (VERSION_MINOR 0)
set (SOFT_VERSION V${VERSION_MAJOR}.${VERSION_MINOR})

configure_file(config.h.in config.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR})

这样可以在生成过程中自动生成 config.h 文件,并将其包含在项目中。

config.h.in内容如下:

#ifndef CONFIG_H_IN
#define CONFIG_H_IN

/**
* 可配置版本号、日期等信息
*/

#define VERSION_MAJOR @VERSION_MAJOR@
#define VERSION_MINOR @VERSION_MINOR@
#define SOFT_VERSION @SOFT_VERSION@

#endif

自定义构建规则

使用 add_custom_command 和 add_custom_target 命令可以方便地添加自定义构建规则,例如:

add_custom_command(
  OUTPUT my_output.txt
  COMMAND my_command arg1 arg2 > my_output.txt
  DEPENDS my_input.txt
)

add_custom_target(my_target DEPENDS my_output.txt)

这样可以在编译过程中执行自定义命令,并生成指定的输出文件。

获取文件夹名称

get_filename_component(CURRENT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} NAME)