CMake:根据 C 宏定义有选择地重新编译 C++ 程序模块
CMake: recompile C++ program modules selectively based on C macro definition
我有一个包含多个模块的程序,例如:moduleA、moduleB 和 moduleC。
我还有一个头文件 debug_flags.h,我在其中定义了三个宏:
#define DEBUG_MODULE_A 1
#define DEBUG_MODULE_B 0
#define DEBUG_MODULE_C 0
当 DEBUG_MODULE_X 设置为 1 时,将为模块 X 启用额外的调试功能
(如详细的日志记录、将中间结果保存到文件等)。
目前,每当我更改 DEBUG_MODULE_X 的值时,所有三个模块都会重新编译(这是相当昂贵的)。相反,我只想重建模块 X(因为 DEBUG_MODULE_X 宏仅在模块 X 中使用)。
一种解决方案是使用三个不同的头文件:
debug_flags_A.h -> defines DEBUG_MODULE_A
debug_flags_B.h -> defines DEBUG_MODULE_B
debug_flags_C.h -> defines DEBUG_MODULE_C
这将分别包含在模块 A、B 和 C 中。
然而,使用该解决方案,我不得不经常在头文件之间跳转
enable/disable 在开发期间调试模块(我有 3 个以上的模块)。
而且我也不清楚目前启用了哪些调试标志..
理想情况下,我希望在单个头文件中定义所有调试标志,
但以某种方式强制 CMake 仅重新编译相关模块(即 DEBUG_MACRO_X 已更改的模块)。这可能吗?
我不确定这是否有帮助:可以从模块 X 中包含 debug_flags.h
如下:
#define INCLUDE_FROM_MODULE_X
#include "debug_flags.h"
然后,在debug_flags.h中我们知道这个头文件是从哪个模块包含的。也许,通过使用这些信息,我们可以以某种方式触发选择性重新编译??
为什么不让CMake在编译时为你添加定义:
cmake_minimum_required(VERSION 3.0)
project(debugflags)
add_library(moduleA STATIC moduleA.cpp)
add_library(moduleB STATIC moduleB.cpp)
add_library(moduleC STATIC moduleC.cpp)
target_compile_definitions(moduleA PRIVATE DEBUG_MODULE_A)
# target_compile_definitions(moduleB PRIVATE DEBUG_MODULE_B)
target_compile_definitions(moduleC PRIVATE DEBUG_MODULE_C)
(Un)注释 target_compile_definitions
之一只会重新编译那个模块。如果你需要跨模块调试标志,你可以这样做:
if(DEBUG_MODULE_A)
target_compile_definitions(moduleA PRIVATE DEBUG_MODULE_A)
target_compile_definitions(moduleA2 PRIVATE DEBUG_MODULE_A)
endif(DEBUG_MODULE_A)
并设置相应的CMake变量。
根据上面@Botje 的建议,我终于停止了一个稍微不同的解决方案,如果您不想创建许多小型静态库(例如,如果您的“模块”只包含几个文件),这可能会更好).
思路就是简单的让cmake生成debug头文件,如下:
set(DEBUG_MODULE_A 0)
configure_file(${PROJECT_SOURCE_DIR}/cmake/debug_module_a.h.in ${PROJECT_SOURCE_DIR}/debug_module_a.h)
set(DEBUG_MODULE_B 1)
configure_file(${PROJECT_SOURCE_DIR}/cmake/debug_module_b.h.in ${PROJECT_SOURCE_DIR}/debug_module_b.h)
set(DEBUG_MODULE_C 1)
configure_file(${PROJECT_SOURCE_DIR}/cmake/debug_module_c.h.in ${PROJECT_SOURCE_DIR}/debug_module_c.h)
当然也可以使用更复杂的结构,例如:
if(${DEBUG_MODULE_B} OR ${DEBUG_MODULE_C})
set(DEBUG_COMMON 1)
else()
set(DEBUG_COMMON 0)
endif()
其中 debug_module_X.h.in 文件如下:
#pragma once
#define DEBUG_MODULE_X @DEBUG_MODULE_X@
// alternatively use: #cmakedefine DEBUG_MODULE_X or cmakedefine01 DEBUG_MODULE_X
然后,每个模块X包含对应的cmake-generated头文件:
#include "debug_module_x.h"
这样,如果您更改任何变量 DEBUG_MODULE_X,只有包含的文件
debug_module_x.h 将被重新编译。
我有一个包含多个模块的程序,例如:moduleA、moduleB 和 moduleC。 我还有一个头文件 debug_flags.h,我在其中定义了三个宏:
#define DEBUG_MODULE_A 1
#define DEBUG_MODULE_B 0
#define DEBUG_MODULE_C 0
当 DEBUG_MODULE_X 设置为 1 时,将为模块 X 启用额外的调试功能 (如详细的日志记录、将中间结果保存到文件等)。
目前,每当我更改 DEBUG_MODULE_X 的值时,所有三个模块都会重新编译(这是相当昂贵的)。相反,我只想重建模块 X(因为 DEBUG_MODULE_X 宏仅在模块 X 中使用)。
一种解决方案是使用三个不同的头文件:
debug_flags_A.h -> defines DEBUG_MODULE_A
debug_flags_B.h -> defines DEBUG_MODULE_B
debug_flags_C.h -> defines DEBUG_MODULE_C
这将分别包含在模块 A、B 和 C 中。 然而,使用该解决方案,我不得不经常在头文件之间跳转 enable/disable 在开发期间调试模块(我有 3 个以上的模块)。 而且我也不清楚目前启用了哪些调试标志..
理想情况下,我希望在单个头文件中定义所有调试标志, 但以某种方式强制 CMake 仅重新编译相关模块(即 DEBUG_MACRO_X 已更改的模块)。这可能吗?
我不确定这是否有帮助:可以从模块 X 中包含 debug_flags.h 如下:
#define INCLUDE_FROM_MODULE_X
#include "debug_flags.h"
然后,在debug_flags.h中我们知道这个头文件是从哪个模块包含的。也许,通过使用这些信息,我们可以以某种方式触发选择性重新编译??
为什么不让CMake在编译时为你添加定义:
cmake_minimum_required(VERSION 3.0)
project(debugflags)
add_library(moduleA STATIC moduleA.cpp)
add_library(moduleB STATIC moduleB.cpp)
add_library(moduleC STATIC moduleC.cpp)
target_compile_definitions(moduleA PRIVATE DEBUG_MODULE_A)
# target_compile_definitions(moduleB PRIVATE DEBUG_MODULE_B)
target_compile_definitions(moduleC PRIVATE DEBUG_MODULE_C)
(Un)注释 target_compile_definitions
之一只会重新编译那个模块。如果你需要跨模块调试标志,你可以这样做:
if(DEBUG_MODULE_A)
target_compile_definitions(moduleA PRIVATE DEBUG_MODULE_A)
target_compile_definitions(moduleA2 PRIVATE DEBUG_MODULE_A)
endif(DEBUG_MODULE_A)
并设置相应的CMake变量。
根据上面@Botje 的建议,我终于停止了一个稍微不同的解决方案,如果您不想创建许多小型静态库(例如,如果您的“模块”只包含几个文件),这可能会更好).
思路就是简单的让cmake生成debug头文件,如下:
set(DEBUG_MODULE_A 0)
configure_file(${PROJECT_SOURCE_DIR}/cmake/debug_module_a.h.in ${PROJECT_SOURCE_DIR}/debug_module_a.h)
set(DEBUG_MODULE_B 1)
configure_file(${PROJECT_SOURCE_DIR}/cmake/debug_module_b.h.in ${PROJECT_SOURCE_DIR}/debug_module_b.h)
set(DEBUG_MODULE_C 1)
configure_file(${PROJECT_SOURCE_DIR}/cmake/debug_module_c.h.in ${PROJECT_SOURCE_DIR}/debug_module_c.h)
当然也可以使用更复杂的结构,例如:
if(${DEBUG_MODULE_B} OR ${DEBUG_MODULE_C})
set(DEBUG_COMMON 1)
else()
set(DEBUG_COMMON 0)
endif()
其中 debug_module_X.h.in 文件如下:
#pragma once
#define DEBUG_MODULE_X @DEBUG_MODULE_X@
// alternatively use: #cmakedefine DEBUG_MODULE_X or cmakedefine01 DEBUG_MODULE_X
然后,每个模块X包含对应的cmake-generated头文件:
#include "debug_module_x.h"
这样,如果您更改任何变量 DEBUG_MODULE_X,只有包含的文件 debug_module_x.h 将被重新编译。