【问题标题】:Remove precompiler directive from .h header file从 .h 头文件中删除预编译器指令
【发布时间】:2016-10-25 14:29:11
【问题描述】:

我正面临一个我不知道如何解决的问题。

假设将下面的 typedef 结构体放入一个 test.h 头文件中:

typedef struct example_struct {
    #ifdef CONFIG_A
    int A;
    #endif;

    int B;
} example_struct_t;

我正在使用此头文件编译代码,并使用 -D 选项将 CONFIG_A 传递给 GCC。这样我就可以将 A 成员包含到结构中,或者如果给定用例不需要,则将其删除。

现在假设我生成了一个共享库 (.so) 并且我想分发它。所以,我有 .so 库和带有预编译器指令的头文件。问题是我不想在使用库的程序中包含 -DCONFIG_A,我的意思是,我需要将库编译时使用的选项不仅保留在源文件 (.c) 中,还保留在标题。也就是说,如果使用 -DCONFIG_A 选项编译库,我认为使用该库的程序不应该在编译时包含该选项。

预编译头文件是这个问题的解决方案还是有其他替代方案(避免在每个定义预编译器指令的文件中包含 config.h 头文件)?

非常感谢您的指导。

【问题讨论】:

  • 听起来像是 XY 问题:询问如何解决问题的错误解决方案。并选择语言:C 还是 C++?
  • 对于 C++,有 the One Definition Rule (aka ODR)。如果在编译某些translation units 时定义了CONFIG_A,但没有为其他定义,则您有未定义的行为
  • 安装库时,您还可以安装带有适当预处理器选项的mylibrary.pc 文件。然后指示您的用户使用pkg-config --cflags mylibrary
  • 问题提到“.c”作为源文件 - 这意味着这不是 C++ 问题
  • 您真正应该问的第一个问题是,为什么结构需要公开和可见才能使用您的共享对象。像这样公开内部实现细节意味着你不能改变你的库而不强制使用你的库的每个二进制文件都重新编译。如果有人以一种导致与您的库所期望的大小和/或对齐方式不同的方式编译结构,它还会为您带来一些真正有趣的错误。理想情况下,像 struct 定义这样的东西不应该对图书馆用户可见 - 他们应该只通过定义的 API 进行交互。

标签: c conditional-compilation precompile precompiled-headers


【解决方案1】:

您可以“生成”结构定义的代码,并将生成的定义与相应的库一起发布。一个想法是将结构保存在没有#includes 的标题中,在这种情况下,您可以在它们上运行C 预处理器以获取没有#ifdefs 的文件(然后您可以使用它来构建和发布)。

另一种方法是在构建系统中做一些特别的事情。例如,CMake 具有 #cmakedefine,您可以在 C 或 C++ 源文件中使用它,然后从中生成代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-09
    • 2010-11-20
    • 1970-01-01
    • 2018-02-06
    相关资源
    最近更新 更多