【问题标题】:Overriding macros using compiler options使用编译器选项覆盖宏
【发布时间】:2010-11-15 04:48:31
【问题描述】:

我需要通过我的头文件覆盖某些宏定义。而且我不允许更改源代码。而且我必须使用 gcc,但如果有人知道任何其他编译器上有类似的东西,那么它也会有所帮助。

这是我真正需要的:

假设我有很多 .c 文件的代码库。这些 .c 文件包括 .h 文件。在为每个文件包含所有 .h 文件之后,我希望编译器的行为就像我有另一个 extra.h 文件一样,我想在调用编译器时指定该文件。我在那个 .h 文件中所做的是 #undef 一些宏,并按照我想要的方式重新定义宏。

注意:我知道 gcc 中的 --preinclude 选项,但使用 --preinclude 会通过原始源代码的 .h 覆盖我的 extra.h。我需要的是某种帖子包含选项。

【问题讨论】:

  • 我不知道为什么一行变成了大字体和粗体。如果您觉得这很烦人,我深表歉意。
  • 为什么不能改源代码?这与家庭作业有关吗?
  • 不,这不是我的作业。我需要包装某些宏调用并收集并进行一些预处理和后处理。我不能更改源代码的原因是客户希望他们的代码被触动。

标签: gcc c-preprocessor


【解决方案1】:

除非你统一有一个特定的头文件总是最后包含在源文件中,否则这会很棘手。

如果我不得不这样做,我认为我的处理方式是:

  • 创建一个新目录,命名为headers
  • 在其中放入与常规标头同名的合适的虚拟标头,最后将包含#include "extra.h"(或者可能是#include <extra.h>,但我会尽量避免这种情况)。
  • 虚拟标头还会通过某种机制包含原始文件,甚至可能使用#include "/usr/include/header.h",但最好使用其他技术 - 例如#include "include/header."
  • extra.h 标头将始终重新定义其所有宏 - 它不会具有正常的 #ifndef EXTRA_H_INCLUDED / #define EXTRA_H_INCLUDED / #endif 多个包含保护,因此每次包含它时,它都会重新定义相关宏.
  • 因此,extra.h 无法定义任何类型。 (或者,更准确地说,如果确实如此,则必须通过多个包含保护来保护它们免受多重定义;关键是每次包含文件时都必须定义宏 - 有点像<assert.h>。)
  • 每个重新定义的宏都将受到#undef REDEFINED_MACRO#define REDEFINED_MACRO ... 的显式保护。
  • 在取消定义之前测试宏是否已定义是没有意义的。
  • 构建过程将被修改为先查看headers 目录,然后再查看其他任何位置。编译器选项将是 -I./headers 或类似的选项,具体取决于您找到 headers 目录的确切位置。
  • 根据您决定如何定位正常版本的标头,您可能需要另一个-I 选项(例如-I/usr,如果您使用#include "include/header.h" 表示法)再次定位标准标头。

结果是编译器直接使用您的私有头文件,但它们包含标准头文件,然后是您的 extra.h 头文件 - 从而在不修改 C 源代码或普通头文件的情况下实现您想要的。

但是整个尝试有些误导......你最好不要尝试这个。

【讨论】:

  • 这种方法的问题是头文件保存在多个地方。我正在使用内核源代码,然后是自定义内核模块。对 extra.h 中的所有头文件进行 #include 是错误的。虽然我只有一个统一的头文件,但我想在所有包含文件的末尾使用它。
  • @user420536:正如我所暗示的,这完全令人毛骨悚然,而且不是非常可靠,但是“最后包含的标题”的概念是不可靠的,并且没有明确定义。为什么你认为你需要重写内核宏?这听起来像是彻底灾难的秘诀。内核定义了它所期望的。如果你重新定义它所期望的以匹配你所期望的,它就会获胜——当你混淆它时,它会在你的代码中崩溃。为您的目的使用您自己的宏;严格保留内核宏。 不要对你的编译器或内核撒谎
  • @user420536:我建议你让那些对你提出限制的人不要更改代码来完成这项工作 - 或者向你解释他们希望你如何去做。他们不合理。
  • @user420536:为什么客户坚持让您在不对代码进行任何更改的情况下让代码正常工作?我离开这里;我建议你也出去,虽然进展顺利。在规则改变之前,您无法获胜。它们不必改变太多,但必须改变。此外,您始终可以复制代码并编辑副本。如果你连这点都做不到,那就没时间出城了。
  • @user420536:所以,如果源代码显示:some_macro(arg1, arg2),请将其修改为 SOME_MACRO(arg1, arg2),然后在 extra.h 标头中写入 SOME_MACRO 以执行您想要的操作,然后使用some_macro() 来自内核,然后做任何你想做的清理工作。这可能是一个临时措施——当你解决你遇到的任何问题时——或者它可能是一个永久性的固定装置。但是,如果您正在编译代码,您可以对其进行编辑并在短期内解决问题。并使用 VCS 跟踪您在做什么。
【解决方案2】:

Makefile 可用于通过 -U 和 -D 编译器 (gcc) 选项重新定义宏。但是为什么要在评估原件后重新定义它们呢?我想不出需要这样的东西。你能说出你希望通过这个实现什么吗?

【讨论】:

  • -U-D 选项类似于 pre-include - 它们在开头设置,然后处理标题,可能忽略命令行设置,尤其是任何 -U选项。我不确定我是否认真地使用过-U。它只允许您撤消内置(预定义)宏,AFAIK。
  • 你可以这样想,我只是想在每次调用特定的宏时添加一个调试语句,但不允许我更改源代码。
  • 您可以尝试通过文档或此类资源更好地了解与底层平台相关的 Linux 内核代码库。调试是为了了解某些行为并调查其原因。您感兴趣的行为是什么?
【解决方案3】:

要求是在 .c 文件中的所有其他 .h 文件之后插入 extra.h。因此,在每个 .h 文件的末尾添加它会将其插入到 .c 文件中按顺序包含的两个 .h 文件之间,这不是本意。

您可以在 makefile(s) 中使用 sed/awk 来: - 首先创建重复的 .c 文件,在每个 .c 文件内的其他 #include 行之后插入 '#include "extra.h"'(在 .c 文件内解析 #ifdef 块会很乏味/棘手) - 然后实现你的目标编译那些重复的 .c 文件 - 最后删除重复的 .c 文件

【讨论】:

  • 谢谢大家。最后,不接触代码是不可行的。我最终将我的 extra.h 放在我想要修改的每个头文件的末尾。正如有人已经提到的那样,C 对包含的最后一个头文件没有明确的划分,并且宏不限于 .h 文件。所以这是不可能的。谢谢大家。
【解决方案4】:

你可以使用 -include file GCC 的选项,因为这个特性:

If multiple -include options are given, the files are included in the order they appear on the command line.

据我了解,您必须从命令行包含所有 *.h 文件,只需将“extra.h”保留在 -include 选项列表中的最后一个标题,您就应该得到您想要的。

【讨论】:

    【解决方案5】:

    根据您的要求,我可以想到两种方法,希望都比较简单。

    第一种方法根本不涉及源代码,但是它要求您从中#undef'ing 的每个头文件都有一个头保护。您可以将需要“更改”内容的每个头文件复制并连接到一个整体文件中,即“extra.h”文件。然后在该文件的末尾,继续并重新定义您需要的所有宏。然后在编译时包含这个文件。标头保护将阻止包含原始标头。显然,这种方法存在许多潜在问题,而且一般情况下肯定行不通。

    第二种方式更简洁、更可靠,但它需要您直接编辑代码,尽管不是侵入式的。对于您需要重新定义的每个标头,使用“.orig”后缀或其他内容制作该标头的副本,然后直接编辑实际的头文件。在您完成所有您正在做的事情之后,只需在您的客户获取代码之前将所有“.orig”文件复制回实际的标题中。我假设您的要求不是那么严格,以至于您甚至暂时都无法更改代码。

    如果这些都不起作用,那么我怀疑你会从没有直接破解 GCC 并自己添加“-postinclude”选项的任何人那里找到有效的答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-05
      • 2014-04-09
      • 1970-01-01
      相关资源
      最近更新 更多