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)
小结
本章我们学习了:
- 创建可执行目标:add_executable
- 可执行文件属性:输出名称、目录、C++ 标准、RPATH
- 编译选项:头文件路径、预处理器定义、编译选项
- 链接库:项目内库、系统库、外部库
- 运行可执行文件:基本运行、自定义目标、CTest、调试
- 跨平台注意事项:平台特定配置、输出名称、安装路径
- 安装配置:安装目标文件、设置 RPATH
练习
- 创建一个多文件的可执行项目
- 配置 Debug 和 Release 不同的编译选项
- 实现跨平台的可执行文件构建
- 添加自定义运行目标和测试
- 编写完整的安装配置,包括跨平台 RPATH 设置