【问题标题】:EXPORT_SYMBOL in header causes "exported twice" errors标头中的 EXPORT_SYMBOL 导致“导出两次”错误
【发布时间】:2023-11-17 04:33:01
【问题描述】:

我有一个头文件,其中声明了几个全局变量,格式如下:

constants.h

#ifndef CONSTANTS_H
#define CONSTANTS_H

extern unsigned var;
EXPORT_SYMBOL(var);

#endif

constants.c

#include "constants.h"
unsigned var = 10;

foo.c

#include "constants.h"

当我尝试编译内核模块时,每个导出的符号都会出现以下错误:

WARNING: /home/vilhelm/proj/constants: 'var' exported twice. Previous export was in /home/vilhelm/proj/foo.ko

我怀疑每次包含 constants.h 头文件时都会导出符号,但我不明白为什么。 constants.h 中的包含守卫不应该防止EXPORT_SYMBOL(var) 被多次读取吗?

【问题讨论】:

  • 我认为您应该将 EXPORT_SYMBOL 宏移至 constants.c 文件。这样,您只需将其导出一次。请注意,每次包含标头时,它实际上都会将其复制粘贴到您的 c 文件中。如您所见,每次包含 constants.h 时,宏都会触发。
  • 我意识到由于包含,它被多次触发,但我更想了解为什么包含保护不能阻止这种情况的发生。
  • 当你编译这段代码时,你会创建两个目标文件。第一个是来自constants.h和constants.c的constants.o,第二个是由foo.c和constants.h创建的foo.o。现在,它们都导出符号 var。在链接方面,链接器看到 var 由 constants.o 和 foo.o 导出并发出警告。标头保护不能防止这种情况,因为问题发生在链接期间,而不是编译。

标签: c linux gcc linux-kernel c99


【解决方案1】:

constants.h 中的 include 守卫不应该阻止 EXPORT_SYMBOL(var) 被多次读取?

包含保护防止标头在相同源文件中多次包含。它不能阻止它通过多个源文件被包含。请记住,所有来源的对象都链接到一个对象中,因此会发生冲突。

假设您有另一个头文件,它也包含在源文件中,称为 foo.h,它又包含 constants.h。文件 constants.c 将尝试包含 constants.h 两次(一次直接通过 constants.h,另一次通过 foo.h)。 include 守卫在这里起作用,constants.h 只会被包含一次。

同样的事情也会发生在 foo.c 上。它将尝试包含 constants.h 两次(一次直接通过 constants.h,再次通过 foo.h)。 include 守卫在这里也有效,constants.h 只会被包含一次。

但随后这两个对象,constants.o 和 foo.o 将被链接在一起,每个对象都有其通过 constants.h 的 EXPORT 的单个副本。这加起来是两个。

您希望确保导出仅在最终链接中出现一次。一种方法是将它们从常量.h 等通用文件中取出,并将它们移动到名为exports.c 的文件中。

【讨论】: