如何使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 中单击 Configure
和 Generate
以使更改生效。赋给变量的值不重要,可以留空
调试完成后,返回cmake-gui并删除相应的条目。 别忘了Configure
和Generate
。
我在一个小项目中测试过,似乎可以正常工作。
注意:如果你在同一个CMakeLists.txt(=在同一个子目录)中创建多个目标(add_library
或add_executable
),我还没有找到办法以一种方式构建一个目标,以另一种方式构建一个目标:似乎唯一重要的是 CMake 完成解析文件时 CMAKE_BUILD_TYPE
目录的值。
为了回答您的评论,您可以在构建时通过在块中添加以下行来打印提醒:
add_custom_target(info_${THIS_DIR} ALL COMMAND echo Targets in directory ${THIS_DIR} are built Debug)
我给出的解决方案如下:
我创建了一个宏,它将读取二进制目录中的配置文件并根据其内容设置编译类型。
当这个文件改变时,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)
改写了问题。
我遇到以下问题:
我的项目有几个二进制文件和库,它们位于主项目文件夹下的不同子目录中。 能够只调试其中的一个子集,而不用在调试模式下重新编译整个项目是很有用的。
我希望能够以半自动方式仅更改此子集的编译模式。
如何使用 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 中单击 Configure
和 Generate
以使更改生效。赋给变量的值不重要,可以留空
调试完成后,返回cmake-gui并删除相应的条目。 别忘了Configure
和Generate
。
我在一个小项目中测试过,似乎可以正常工作。
注意:如果你在同一个CMakeLists.txt(=在同一个子目录)中创建多个目标(add_library
或add_executable
),我还没有找到办法以一种方式构建一个目标,以另一种方式构建一个目标:似乎唯一重要的是 CMake 完成解析文件时 CMAKE_BUILD_TYPE
目录的值。
为了回答您的评论,您可以在构建时通过在块中添加以下行来打印提醒:
add_custom_target(info_${THIS_DIR} ALL COMMAND echo Targets in directory ${THIS_DIR} are built Debug)
我给出的解决方案如下:
我创建了一个宏,它将读取二进制目录中的配置文件并根据其内容设置编译类型。
当这个文件改变时,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)