【问题标题】:Conditional compilation strategies - how to avoid undefined symbols in C条件编译策略——如何避免 C 中未定义的符号
【发布时间】:2015-04-02 10:35:34
【问题描述】:

我正在尝试用 C 语言制作一个模块化项目。 我正在为嵌入式 ARM CPU 编写固件。它由不同的部分组成,由于内存限制,不能同时编译。

简单来说,假设我有一个模块 A,它管理固件的所有可选部分,每个部分都在其模块中编码(B、C、D 等...)

在模块 A 中,我使用 #ifdef 子句:

#ifdef USE_B
  #include "B.h"
#endif

#ifdef USE_C
  #include "C.h"
#endif

...

除此之外,我只需为我想要包含的模块#define 关键字。

我在文件 Z.c 中有一些全局变量应该保留在那里。由于我的目标是尽量减少内存使用,因此我也将它们的声明附在 #ifdef 中

#ifdef USE_B
  uint8_t usedonlybyb;
#endif

#ifdef USE_C
  uint8_t usedonlybyc;
#endif

...

发生的情况是,即使文件 B 和文件 C 在编译时与项目的其他部分完全断开连接,在编译结束时,外部变量“usedonlybyx”也会出现“未定义符号”错误,它们是禁用的模块无法访问。

我想保留在模块 Z 中声明的 usedonlybyx 变量,因为那个是通用设置模块。

有没有一种优雅的方法来抑制这些错误,并且仍然能够在我的范围内取得成功?

我是否应该简单地将整个模块 B、C、... 包含在 #ifdef / #endif 中?

【问题讨论】:

  • 如果编译时定义了USE_C,二进制文件不会覆盖之前编译的定义USE_B的文件吗?这可能是找不到符号的原因吗?
  • 你提到没有足够的空间同时编译所有模块。然后建议将一些文件分解为子文件。使用非多线程的 make 文件。一个一个地编译文件。然后有最后的链接步骤将它们链接在一起。
  • 我觉得我的表述不清楚,我编译整个项目没有问题,但是我无法在目标CPU上运行“完整”的项目。我基本上需要根据 CPU 型号和客户要求来定制我想要编译的功能。但我想保留一个独特的项目,因为它更实用。

标签: c conditional-compilation keil


【解决方案1】:

更简单的解决方案是将整个实现和声明包含在 b.hb.c 文件内 #ifdef USE_B#endif 内。其他模块也一样。这样一来,一个模块的所有条件编译都是隔离的,不必贯穿使用#include "b.h" 的其他代码。

// b.h
#ifdef USE_B
// declarations and include guards
#endif

// b.c
#ifdef USE_B
// definitions
#endif

// a.c
#include "b.h" // <- no USE_B needed here

【讨论】:

    【解决方案2】:

    您可以尝试将 B 和 C 模块拆分为独立的库组件,确保这些库使用的所有全局变量都包含在其中。这可能需要将变量的 extern 声明移动到库接口文件中,或根据需要提供访问器方法。

    或者,如果您使用的是 GCC,编译器有一个 __attribute__((weak)) 形式的语言扩展,它将声明一个 'just-in-case-it's-not-defined-anywhere-else' 版本让链接器满意的变量。

    【讨论】:

      猜你喜欢
      • 2010-12-31
      • 2013-03-07
      • 2010-10-03
      • 2019-03-24
      • 1970-01-01
      • 2013-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多