这是本文档旧的修订版!
CMake
- Official Site:cmake.org
- c++跨平台构建工具,开源[BSD]免费。
- CMake 变量列表:
- CMake 变量的作用域:cmake-language-variables
- 父目录里的绑定变量默认会传到子目录的CMakefile作为初始值
Tips
- MSVC中, cmake 默认生成的 release 工程不生成 pdb 文件,可如下添加
if (MSVC) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi") # if build .exe set(CMAKE_EXE_LINKER_FLAGS_RELEASE"${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF" CACHE STRING "" FORCE) # if build .dll set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF" CACHE STRING "" FORCE) # if build static .lib set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF" CACHE STRING "" FORCE) endif (MSVC)
参考 how to generate pdb files..., 或者使用 cmake generator expressions来设置:
target_compile_options(${YourProjName} PRIVATE "$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<CONFIG:Release>>:/Zi>" ) target_link_options(${YourProjName} PRIVATE "$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<CONFIG:Release>>:/DEBUG>" PRIVATE "$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<CONFIG:Release>>:/OPT:REF>" PRIVATE "$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<CONFIG:Release>>:/OPT:ICF>" )
- 给dll右键属性的详细信息里添加git version, 参考zhihu 97512450
add_definitions(-DMAIN_PROJECT_NAME=\"${YourProjName}\") find_package(Git QUIET) if(GIT_FOUND) set(COMMIT_HASH "") set(BRANCH_NAME "") execute_process( COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:%H OUTPUT_VARIABLE COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) execute_process( COMMAND ${GIT_EXECUTABLE} symbolic-ref --short -q HEAD OUTPUT_VARIABLE BRANCH_NAME OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) message(STATUS "Git version is ${BRANCH_NAME}:${COMMIT_HASH}") add_definitions(-DGIT_COMMIT_HASH=\"${COMMIT_HASH}\") add_definitions(-DGIT_BRANCH_NAME=\"${BRANCH_NAME}\") endif()
然后添加VersionInfo.rc
#if (defined GIT_COMMIT_HASH && defined GIT_BRANCH_NAME) #define PRODUCT_VERSION GIT_BRANCH_NAME ":" GIT_COMMIT_HASH #else #define PRODUCT_VERSION "1.0.2" #endif // GIT_COMMIT_HASH && GIT_BRANCH_NAME #ifndef MAIN_PROJECT_NAME #define MAIN_PROJECT_NAME "MyLib" #endif 1 VERSIONINFO FILEVERSION 1,0,0,1 PRODUCTVERSION 1,0,0,1 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x0L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", MAIN_PROJECT_NAME " Binary" VALUE "FileVersion", "1.0.0.1" VALUE "InternalName", MAIN_PROJECT_NAME VALUE "LegalCopyright", "Copyright (C) 2020 " VALUE "OriginalFilename", MAIN_PROJECT_NAME ".dll" VALUE "ProductName", MAIN_PROJECT_NAME VALUE "ProductVersion", PRODUCT_VERSION END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END
- 循环子文件夹来包含子工程,参考 stackoverflow 7787823:
MACRO(SUBDIRLIST result curdir) FILE(GLOB children RELATIVE ${curdir} ${curdir}/*) SET(dirlist "") FOREACH(child ${children}) IF(IS_DIRECTORY ${curdir}/${child} AND EXISTS ${curdir}/${child}/CMakeLists.txt) LIST(APPEND dirlist ${child}) ENDIF() ENDFOREACH() SET(${result} ${dirlist}) ENDMACRO() SUBDIRLIST(SUBDIRS ${CMAKE_CURRENT_SOURCE_DIR}) message(STATUS "valid subdirs: ${SUBDIRS}") FOREACH(subdir ${SUBDIRS}) ADD_SUBDIRECTORY(${subdir}) ENDFOREACH()
- 在 bat 批处理里面,如果cmake命令行报错,参考这里,可加以下一行来进行退出处理
cmake . if errorlevel 1 exit /B
- 屏蔽VC编译 release 时的具体某个 warning,比如c4566, 可用如下,
add_compile_options("$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<CONFIG:Release>>:/wd4566>")
注意
add_compile_options
可影响之后所有target与子项目target, 所以适合在ci(持续集成)时使用。如果只是想具体设置某target, 使用target_compile_options
。另外,不建议开发时屏蔽warning。 - cmake 不支持静态库的 dependence, 本质上,静态库只有二进制的合并,没有 link, 只有MSVC可以加 静态库的dependence然后生成合并后的lib, 但这个其它编译器不一定支持,所以cmake也没有这个选项,如果生成的 a.lib 依赖b.lib, 而 c.exe 依赖 a.lib, 一种不用在 c 的配置中显式增加 b.lib 依赖的写法是利用
add_library(<name> INTERFACE)
:add_library(a STATIC ${STRMBASE_FILES}) # target_link_libraries(a b) # 这是不起作用的,因为 a 是静态库,没有link add_library(ab INTERFACE) # 增加一个 ab, INTERFACE target_link_libraries(ab INTERFACE a b) add_executable(c ...) target_link_libraries(c ab) # 此时 c 工程就包含了a.lib, b.lib
-
- 如果源文件包含该第三方头文件,但头文件中不包含该第三方头文件,采用 PRIVATE;
- 如果源文件和头文件中都包含该第三方头文件,采用 PUBLIC;
- 如果头文件中包含该第三方头文件,但源文件中不包含,采用 INTERFACE。