跳到主要内容

CMake 可执行目标

本章将介绍如何使用 CMake 创建和管理可执行目标。

创建可执行目标

基本语法

add_executable(target_name [source1] [source2 ...])

简单示例

cmake_minimum_required(VERSION 3.15)
project(MyApp)

add_executable(myapp main.cpp)

多文件项目

# 方式一:直接列出
add_executable(myapp
src/main.cpp
src/app.cpp
src/utils.cpp
include/app.h
)

# 方式二:使用变量
set(SOURCES
src/main.cpp
src/app.cpp
src/utils.cpp
)
add_executable(myapp ${SOURCES})

使用 GLOB 收集文件

# 收集单个目录
file(GLOB SOURCES "src/*.cpp")

# 递归收集
file(GLOB_RECURSE SOURCES
"src/*.cpp"
"include/*.h"
)

add_executable(myapp ${SOURCES})
注意

使用 GLOB 时,新增文件后需要重新运行 cmake 命令,否则不会自动检测新文件。

可执行文件属性

设置输出名称

add_executable(myapp main.cpp)

# 设置输出文件名
set_target_properties(myapp PROPERTIES
OUTPUT_NAME "my_application"
)

设置输出目录

# 设置可执行文件输出目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

add_executable(myapp main.cpp)

设置 C++ 标准

add_executable(myapp main.cpp)

# 方式一:使用目标属性
set_target_properties(myapp PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
)

# 方式二:使用编译特性
target_compile_features(myapp PUBLIC cxx_std_17)

设置运行时路径

# 设置可执行文件的 RPATH
set_target_properties(myapp PROPERTIES
INSTALL_RPATH "$ORIGIN/../lib"
BUILD_WITH_INSTALL_RPATH FALSE
)

编译选项

头文件路径

target_include_directories(myapp
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)

预处理器定义

target_compile_definitions(myapp
PRIVATE
DEBUG_MODE
VERSION="1.0.0"
PUBLIC
API_EXPORT
)

编译选项

target_compile_options(myapp
PRIVATE
-Wall
-Wextra
-Wpedantic
$<$<CONFIG:Debug>:-g -O0>
$<$<CONFIG:Release>:-O3 -DNDEBUG>
)

链接库

链接项目内库

# 创建库
add_library(mylib src/lib.cpp)
target_include_directories(mylib PUBLIC include)

# 创建可执行文件并链接
add_executable(myapp src/main.cpp)
target_link_libraries(myapp PRIVATE mylib)

链接系统库

# 链接线程库
find_package(Threads REQUIRED)
target_link_libraries(myapp PRIVATE Threads::Threads)

# 链接数学库(Linux)
target_link_libraries(myapp PRIVATE m)

链接外部库

# 使用 find_package
find_package(OpenCV REQUIRED)
target_link_libraries(myapp PRIVATE ${OpenCV_LIBS})

# 或使用现代目标
find_package(fmt REQUIRED)
target_link_libraries(myapp PRIVATE fmt::fmt)

运行可执行文件

基本运行方式

构建完成后,可执行文件将生成在构建目录中。可以通过以下方式运行:

# 在构建目录中直接运行
cd build
./myapp

# 或使用 CMake 的运行命令
cmake --build build --target run

使用自定义运行目标

可以在 CMakeLists.txt 中定义自定义目标来运行可执行文件:

add_custom_target(run
COMMAND myapp
DEPENDS myapp
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)

使用 CTest 运行

可以将可执行文件作为测试运行:

enable_testing()

add_test(NAME myapp_test
COMMAND myapp --test
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)

运行测试:

cd build
ctest

调试运行

对于调试,可以使用 IDE 集成或命令行调试器:

# 使用 GDB 调试
gdb ./myapp

# 使用 LLDB 调试
lldb ./myapp

# 使用 Visual Studio 调试器(Windows)
devenv myapp.exe

运行时环境变量

可以设置运行时环境变量:

# 设置环境变量
set_target_properties(myapp PROPERTIES
ENVIRONMENT "MY_VAR=value"
)

# 或在运行时使用
add_custom_target(run_with_env
COMMAND ${CMAKE_COMMAND} -E env MY_VAR=value ./myapp
DEPENDS myapp
)

跨平台注意事项

平台特定源文件

set(SOURCES
src/main.cpp
src/common.cpp
)

if(WIN32)
list(APPEND SOURCES src/windows_specific.cpp)
elseif(UNIX)
list(APPEND SOURCES src/linux_specific.cpp)
endif()

add_executable(myapp ${SOURCES})

平台特定编译选项

if(MSVC)
target_compile_options(myapp PRIVATE /W4 /utf-8)
else()
target_compile_options(myapp PRIVATE -Wall -Wextra)
endif()

跨平台输出名称

# 根据平台设置不同的输出名称
if(WIN32)
set_target_properties(myapp PROPERTIES
OUTPUT_NAME "myapp_win"
)
elseif(APPLE)
set_target_properties(myapp PROPERTIES
OUTPUT_NAME "myapp_mac"
)
else()
set_target_properties(myapp PROPERTIES
OUTPUT_NAME "myapp_linux"
)
endif()

跨平台运行时依赖

# Windows DLL 路径
if(WIN32)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
else()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
endif()

跨平台安装路径

include(GNUInstallDirs)

install(TARGETS myapp
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)

安装配置

基本安装

add_executable(myapp src/main.cpp)

# 安装可执行文件
install(TARGETS myapp
RUNTIME DESTINATION bin
)

完整安装配置

install(TARGETS myapp
RUNTIME DESTINATION bin
BUNDLE DESTINATION . # macOS 应用包
)

# 安装配置文件
install(FILES config/settings.json
DESTINATION etc/myapp
)

# 安装文档
install(DIRECTORY docs/
DESTINATION share/doc/myapp
)

安装时设置 RPATH

# 设置安装后的 RPATH
set_target_properties(myapp PROPERTIES
INSTALL_RPATH "$ORIGIN/../lib"
)

# 安装时自动设置 RPATH
include(GNUInstallDirs)
install(TARGETS myapp
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

实战示例

完整项目示例

cmake_minimum_required(VERSION 3.15)
project(MyApp VERSION 1.0.0 LANGUAGES CXX)

# 设置默认构建类型
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()

# 设置输出目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

# 收集源文件
file(GLOB_RECURSE SOURCES "src/*.cpp")
file(GLOB_RECURSE HEADERS "include/*.h")

# 创建可执行目标
add_executable(myapp ${SOURCES} ${HEADERS})

# 设置头文件目录
target_include_directories(myapp
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)

# 设置 C++ 标准
target_compile_features(myapp PUBLIC cxx_std_17)

# 编译选项
target_compile_options(myapp
PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/W4 /utf-8>
$<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wpedantic>
$<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Wpedantic>
)

# 预处理器定义
target_compile_definitions(myapp
PRIVATE
PROJECT_VERSION="${PROJECT_VERSION}"
PUBLIC
$<$<CONFIG:Debug>:DEBUG_MODE>
)

# 查找并链接依赖
find_package(Threads REQUIRED)
target_link_libraries(myapp PRIVATE Threads::Threads)

# 安装配置
install(TARGETS myapp RUNTIME DESTINATION bin)

# 添加运行目标
add_custom_target(run
COMMAND myapp
DEPENDS myapp
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)

# 添加测试
enable_testing()
add_test(NAME myapp_test COMMAND myapp --test)

小结

本章我们学习了:

  1. 创建可执行目标:add_executable
  2. 可执行文件属性:输出名称、目录、C++ 标准、RPATH
  3. 编译选项:头文件路径、预处理器定义、编译选项
  4. 链接库:项目内库、系统库、外部库
  5. 运行可执行文件:基本运行、自定义目标、CTest、调试
  6. 跨平台注意事项:平台特定配置、输出名称、安装路径
  7. 安装配置:安装目标文件、设置 RPATH

练习

  1. 创建一个多文件的可执行项目
  2. 配置 Debug 和 Release 不同的编译选项
  3. 实现跨平台的可执行文件构建
  4. 添加自定义运行目标和测试
  5. 编写完整的安装配置,包括跨平台 RPATH 设置