本文记录使用 CMake 构建 C++ 项目时的一些常用设置, 以供后面查阅。
一、 编译特性设置(Debug / Release)
不同编译特性设置对应的优化参数如下:
Debug -> -g
Release -> -O3 -DNDEBUG
RelWithDebInfo -> -O2 -g -DNDEBUG
MinSizeRel -> -Os -DNDEBUG
非Debug模式下都会传递一个 NDEBUG 的宏, 假如有需要可以在代码中把这个宏利用起来。Linux 和 Mac平台在构建项目的直接指定, 因为这两个平台只会构建一个编译版本,如下指定参数:
cmake -S . -B build -D CMAKE_BUILD_TYPE=Release
//或者直接在 CMakeLists.txt 中指定
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release )
endif()
但是windows构建的时候会直接构建出四个版本,所以需要在编译的时候指定需要编译的版本:
cmake --build ./build --config Release
二、 配置输出路径
2.1 静态库
静态库的输出路径指定,windows 平台默认情况下会给每种编译模式都创建一个同名的文件夹,有时候需要在 CMakeLists.txt 中指定, 最好是将编译版本信息一起带上,这样就可以直接在目标文件夹内查询到编译结果,不然 windows 下还会多生成一层编译版本的目录:
set(LIB_PATH ${CMAKE_SOURCE_DIR}/lib)
set_target_properties(project PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${LIB_PATH}
ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${LIB_PATH }/debug
ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${LIB_PATH }/release
)
除了 debug 和 release 都默认输出到 LIB_PATH 路径下。
2.2 动态库
动态库的输出目录和可执行程序的输出目录配置方法相同。
set(DLL_PATH ${CMAKE_SOURCE_DIR}/lib)
set_target_properties(project PROPERTIES
# windows 平台下动态库的符号文件 .lib 的输出目录
ARCHIVE_OUTPUT_DIRECTORY ${LIB_PATH }
ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${LIB_PATH }/debug
ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${LIB_PATH }/release
# windos .dll 或者 .exe 文件输出路径
RUNTIME_OUTPUT_DIRECTORY ${DLL_PATH }
RUNTIME_OUTPUT_DIRECTORY_DEBUG ${DLL_PATH }/debug
RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PE_PATH }/release
#linux .so 和mac
LIBRARY_OUTPUT_DIRECTORY ${LIB_PATH }
LIBRARY_OUTPUT_DIRECTORY_DEBUG ${LIB_PATH }/debug
LIBRARY_OUTPUT_DIRECTORY_RELEASE ${LIB_PATH }/release
#windows .pdb符号调试文件目录
PDB_OUTPUT_DIRECTORY ${LIB_PATH }/pdb
PDB_OUTPUT_DIRECTORY_DEBUG ${LIB_PATH }/pdb
)
给 debug 版本的生成个文件添加一个后缀名:
if(MSVC)
set_target_properties(project PROPERTIES
DEBUG_POSTFIX "d"
)
endif()
三、 VS调试目录
设置 VS 的调试目录,主要是用 VS IDE调试时经常会使用一些资源文件,通过这种方式来指定调试路径,避免资源文件加载失败的情况。根据编译版本来区分 debug 和 release。
VS_DEBUGGER_WORKING_DIRECTORY $<IF:$<CONFIG:Debug>,${DLL_PATH }/debug,${DLL_PATH }/release>
四、 windows 平台设置运行时库
set_target_properties(project PROPERTIES
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>"
)
MultiThreaded
Compile with -MT or equivalent flag(s) to use a multi-threaded statically-linked runtime library.
MultiThreadedDLL
Compile with -MD or equivalent flag(s) to use a multi-threaded dynamically-linked runtime library.
MultiThreadedDebug
Compile with -MTd or equivalent flag(s) to use a multi-threaded statically-linked runtime library.
MultiThreadedDebugDLL
Compile with -MDd or equivalent flag(s) to use a multi-threaded dynamically-linked runtime library.
五、 设置 Visual Studio 的文件分类
Visual Studio 不像 VSCode 那样可以通过文件目录来分组源码,当源码文件个数太多的时候不分组的话就不方便预览调试了。假设有类实现在 a.cpp 中,声明在 a.h 。那么分组可以设置为:
source_group(src FILES a.cpp b.cpp)
source_group(include FILES a.h b.h)
假如要在 include 分组中再内嵌一个分组可以设置为:
source_group(TREE . PREFIX include/inc FILES b.h)
六、 install 安装指定目录
编译完成后需要对编译结果进行一个统一的部署,比如一个动态库工程需要将头文件(.h),符号文件(.lib) , 动态库(.dll)三者进行安装部署,避免手动挨个进行文件拷贝。 CMakeLists.txt 中代码实例如下:
install(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION ${CMAKE_SOURCE_DIR}/install # 执行程序和dll文件输出
ARCHIVE DESTINATION ${CMAKE_SOURCE_DIR}/install # 静态库和windows动态库导出符号 .lib
LIBRARY DESTINATION ${CMAKE_SOURCE_DIR}/install # linux和mac的动态库 .so .dylib
PUBLIC_HEADER DESTINATION ${CMAKE_SOURCE_DIR}/install #公开头文件,比如接口类文件
PRIVATE_HEADER DESTINATION ${CMAKE_SOURCE_DIR}/install #内部头文件
)
windows平台下假如需要进行调试的话,也需要把 PDB 文件一起部署给库的使用者:
install(FILES $<TARGET_PDB_FILE:${PROJECT_NAME}> DESTINATION ${CMAKE_SOURCE_DIR}/install OPTIONAL)
安装时可以通过 cmake 命令进行安装,也可以直接在 CMakeLists.txt 中直接配置。
cmake --install ./build --config Release #部署 Release
cmake --install ./build --config Debug #部署 Debug
导出多个头文件示例:
set(LIST_PUBLIC_HEADER
${CMAKE_SOURCE_DIR}/src/readerbase.h
${CMAKE_SOURCE_DIR}/src/factory.h
)
set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${LIST_PUBLIC_HEADER}")