【问题标题】:separating compilation for to avoid recompilation when I add some debugging to .h file当我向 .h 文件添加一些调试时,分离编译以避免重新编译
【发布时间】:2009-10-06 11:18:00
【问题描述】:

我有一个几乎在整个源代码中都使用的 .h 文件(在我的例子中,它只是一个包含 .cc 和 .h 文件的目录)。基本上,我保留了两个版本的 .h 文件:一个带有一些用于代码分析的调试信息,另一个是常规版本。调试版本只有一个额外的宏和外部函数声明。我经常在两个版本之间切换。但是,这会导致 20 分钟的重新编译。

您建议如何避免这个重新编译问题?也许设置一些标志,创建不同的树?有哪些常见的解决方案以及如何嵌入它们?

新的 .h 文件包含:

extern  void (foo)(/*some params*/);

/***extra stuff****/
#define foo(...) ( /*call_some_function*/) , foo())
/*some_functions*_for_debugging/

正如您所见,这将导致重新编译。我在 Linux AS 3 上使用 gcc 构建

谢谢

【问题讨论】:

  • 我不明白你的代码示例。有一些不匹配的括号。请澄清一下。
  • 我没有看到任何不匹配的括号。基本上,我在用户调用函数 foo 之前添加了一些调试信息,这就是函数名称和宏名称相同的原因。
  • #define foo(...) ( /*call_some_function*/) , foo())
  • 另外,你为什么不改变函数foo本身在它启动时进行调试?
  • 因为我在调用 foo 之前从调用 foo 的函数收集信息。

标签: c++ c debugging gcc header-files


【解决方案1】:

为了避免外部函数的问题,您可以将原型保留在两个版本中,如果不使用,它不会有害。但是宏没机会,你可以忘记它,它需要重新编译代码替换。

我会大量使用预编译的头文件来加快重新编译(因为它无法避免)。 GCC and Precompiled-Headers。对于其他编译器,请使用您最喜欢的搜索引擎。任何现代编译器都应该支持此功能,对于大型项目,您不可避免地必须使用它,否则您将真的没有生产力。

除此之外,如果您有足够的磁盘空间,我会检查两个工作副本。他们每个人都用不同的设置编译。您每次都必须提交和更新才能将更改转移到另一个工作副本,但这肯定需要不到 20 分钟 ;-)

【讨论】:

  • 我倾向于制作两份。让我看看 GCC 和 Precompiled-Headers,因为我从来没有在 linux 上使用过,只在 windows 上使用过。
  • 既然可以让构建系统使用两个不同的构建树,为什么还要有两个代码副本?
  • @Andrei,当然,您必须在各处进行更改才能使用预编译头文件,但这是一次性的工作,在我看来,如果您还没有设置它,您可以大大减少编译时间向上。我的预测是,通过选择正确的标题,您将在 5 分钟内轻松获得...
  • @Artelius,我想他正在使用 automake/autoconf 之类的东西,这就是我发布有关 gcc 的链接的原因。使用自动...脚本,所有内容都构建在源代码树中,并且不太容易进行不同的配置(这可能是可能的,但我在头上掉了很多头发后切换到 cmake ;-) 所以我不热衷于切换回来)
【解决方案2】:

您需要尽量减少依赖于该头文件的代码量(特别是文件数)。除此之外,您无能为力 - 当您需要更改标头时,您将面临重新编译包含它的所有内容。

因此,您需要重新组织您的代码,以便只有选择的文件包含标题。例如,您可以将需要其内容的函数移动到单独的源文件(或多个文件)中,并且仅将标头包含在这些文件中,而将其包含在其他文件中。

【讨论】:

  • 这不是我能适应的解决方案。而且我需要很多文件来依赖那个.h文件(它相当于common.h,因此我在那里添加调试信息)
【解决方案3】:

如果调试宏实际上在大多数包含头文件的文件中使用,那么无论如何都需要重新编译它们!在这种情况下,您有两种选择:

  1. 保留两套目标文件,一套没有调试代码,一套有。使用不同的 makefile/构建配置,以允许它们保存在不同的位置。

  2. 使用全局变量,遵循以下原则:

在你的 common.h 中:

extern int debug;

在你的 debug.c 中:

int debug = 1;

其他任何地方(可以为此使用宏):

if (debug) {
    /*(do_debug_stuff*/
}

这个概念的一个细微变化是在 debug.c 中调用一个实际的 函数,如果禁用调试,它可能什么都不做。

【讨论】:

  • +1 如何以及在哪里设置调试?可以用一个简单的例子来说明1和2的例子吗?
  • 再想一想,它无法工作。请看一下我在 .h 文件中的内容。我更新了问题
  • +1 用于为目标文件保持单独的优化/调试树。这就是我们所做的。只需在您的 makefile 中有 2 个单独的目标,并在您的 make 命令的包装器中使用一个开关来更改 .h 文件的版本以及目标文件的目标。
【解决方案4】:

我不完全理解您的问题。据我了解,您正在尝试创建一个测试框架。我可以提出一些建议。您可以将更改的内容移动到 .c 文件,如下所示。

在新的.h中

extern  void (foo)(/*some params*/);

/***extra stuff****/
#define foo(...) ( /*call_some_function_dummy*/) , foo())
/*some_functions*_for_debugging/

在新的.c 中

call_some_function_dummy()
{

#ifdef _DEBUG

    call_some_function()

#endif

}

现在如果切换到调试模式,只需要重新编译New.c,编译速度会快很多。希望这会对你有所帮助。

解决方案 2:

在 New.h 中

extern void (foo)(/*some params*/);

/***extra stuff****/ 
#define foo(...) ( /*call_some_function[0]*/) , foo()) 
/*some_functions*_for_debugging/

在 New.c 中

#ifdef _DEBUG 

call_some_function[] = 
{
    call_some_function0,
    call_some_function1
};

#else 

call_some_function[]
{
    dummy_nop,
    dummy_nop
};

#endif

【讨论】:

  • 我已经在使用这种东西了,这是一个很好的解决方法。但是,我的应用程序对时间敏感,并且 call_some_function_dummy 函数会增加不必要的开销。
  • 如果您的应用程序对时间敏感,您可以使用函数指针数组而不是虚拟函数。请查看更新后的答案。
  • “我的应用程序是时间敏感的,call_some_function_dummy 函数会增加不必要的开销”:比调试的开销更大?
【解决方案5】:

为什么不将宏移动到它自己的标题中,只在需要的地方包含它。

只是另一个想法。

我看不出如何避免重新编译依赖的源文件。但是,您也许可以加快构建中的其他处理。

例如,您是否可以使用预编译头文件的形式,并且仅将您的头文件包含在代码文件中,而不包含其他头文件。另一种方法是并行构建,或者使用固态硬盘等快速硬件。

记住 hardware is cheap programmers are expensive 引用 wotshisname。

【讨论】:

  • 因为我至少要修改 100 个 cpp 文件
  • 你在问我吗?我不知道!
  • 您可以使用sed 脚本或许多其他方法轻松完成此操作。 (只要确保您先备份/签入!)
  • 它要解决什么问题?我还需要重建所有使用宏的 .c 文件吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-24
相关资源
最近更新 更多