如何使cMake仅对项目中的部分目录使用Debug编译模式?

How to make cMake use Debug compilation mode for only a subset of directories in a project?

改写了问题。

我遇到以下问题:

我的项目有几个二进制文件和库,它们位于主项目文件夹下的不同子目录中。 能够只调试其中的一个子集,而不用在调试模式下重新编译整个项目是很有用的。

我希望能够以半自动方式仅更改此子集的编译模式。

如何使用 CMake 完成此操作?

如果更改构建类型,整个项目将从头开始重新编译。通常您保留 2 个独立的构建树,一个已配置的调试和一个已配置的发布。

注意 CMAKE_BUILD_TYPE 可以从命令行或 cmake-gui 设置,你不应该在 CMakeLists.txt 文件中设置它。


要在调试模式下仅编译项目的一部分,您可以按以下步骤进行。在您的主 CMakeLists.txt 中,在包含任何子目录之前,定义以下宏:

macro (CHECK_IF_DEBUG)
  if (NOT (CMAKE_BUILD_TYPE MATCHES Debug))
    get_filename_component(THIS_DIR ${CMAKE_CURRENT_SOURCE_DIR} NAME)
    STRING(REGEX REPLACE " " "_" THIS_DIR ${THIS_DIR}) #Replace spaces with underscores
    if (DEFINED DEBUG_${THIS_DIR})
      message(STATUS "Note: Targets in directory ${THIS_DIR} will be built Debug") #A reminder
      set (CMAKE_BUILD_TYPE Debug)
    endif()
  endif()
endmacro()

然后,在每个子目录中添加(在CMakelists.txt开头)宏调用

 CHECK_IF_DEBUG()

当你需要临时调试项目的一部分(子目录)时,在cmake-gui中打开你的项目,并定义一个名为DEBUG_<DirectoryName>的变量("Add Entry")。您可以定义多个。 如果您的目录名包含空格,请在变量名中将其替换为下划线。不要忘记在 cmake-gui 中单击 ConfigureGenerate 以使更改生效。赋给变量的值不重要,可以留空

调试完成后,返回cmake-gui并删除相应的条目。 别忘了ConfigureGenerate

我在一个小项目中测试过,似乎可以正常工作。

注意:如果你在同一个CMakeLists.txt(=在同一个子目录)中创建多个目标(add_libraryadd_executable),我还没有找到办法以一种方式构建一个目标,以另一种方式构建一个目标:似乎唯一重要的是 CMake 完成解析文件时 CMAKE_BUILD_TYPE 目录的值。


为了回答您的评论,您可以在构建时通过在块中添加以下行来打印提醒:

add_custom_target(info_${THIS_DIR} ALL COMMAND echo Targets in directory ${THIS_DIR} are built Debug)

参见 add_custom_target

我给出的解决方案如下:

我创建了一个宏,它将读取二进制目录中的配置文件并根据其内容设置编译类型。

当这个文件改变时,cMake 将只在那个目录上重新运行,它也会重新编译它,因为它的依赖关系改变了。这正是我需要的。

宏如下:

macro(set_buildmode _local_app_name)
  if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/BUILDMODE)
    file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/BUILDMODE ${CMAKE_BUILD_TYPE})
    message(" *** Creating file 'BUILDMODE' with type '${CMAKE_BUILD_TYPE}' for '${_local_app_name}'")
  endif()
  configure_file( ${CMAKE_CURRENT_BINARY_DIR}/BUILDMODE 
                  ${CMAKE_CURRENT_BINARY_DIR}/BUILDMODE.junk)
  file(READ ${CMAKE_CURRENT_BINARY_DIR}/BUILDMODE CMAKE_BUILD_TYPE)
  string(STRIP ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE)
endmacro()

为了确保我始终知道我是否在发布以外的任何其他模式下编译,我还有这个宏:

macro(add_buildmode_message _local_app_name_full)
  get_filename_component(_local_app_name ${_local_app_name_full} NAME)
  add_custom_target(Checking_BUILDMODE_for_${_local_app_name} ALL
                    COMMAND bash -c "if [ \"${CMAKE_BUILD_TYPE}\" != \"Release\" ] ; then echo -e \"       ${BoldRed}${_local_app_name} was built with type '${CMAKE_BUILD_TYPE}'${ColourReset}\" ; fi"
                 VERBATIM)
endmacro()

这是它的用法示例:

set(appname example)
###### Call set_buildmode here
set_buildmode(${appname})
set(${appname}_SRCS
example.cpp
main.cpp)

set(${appname}_HDRS
example.h)

set(${appname}_LIBS)

set(BUILD_SHARED_LIBS ON)

execute_process(COMMAND ln -frs ${${appname}_HDRS} ${CMAKE_BINARY_DIR}/include/
                WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})

set(MYLIB_VERSION_MAJOR 2)
set(MYLIB_VERSION_MINOR 1)
set(MYLIB_VERSION_PATCH 0)
set(MYLIB_VERSION_STRING
    ${MYLIB_VERSION_MAJOR}.${MYLIB_VERSION_MINOR}.${MYLIB_VERSION_PATCH})
add_library(${appname} ${${appname}_SRCS})
target_link_libraries (${appname} ${${appname}_LIBS} ${CMAKE_THREAD_LIBS_INIT})

##### Add the fake target for checking the build mode
add_buildmode_message(${appname})
set_target_properties(${appname} PROPERTIES VERSION ${MYLIB_VERSION_STRING}
                       SOVERSION ${MYLIB_VERSION_MAJOR})
install(TARGETS ${appname} DESTINATION lib)