在库中隐藏非 API 符号
Hiding non-API symbols in library
假设我有一个库 foo,它包含模块 foo 和 util 以及具有以下源代码树:
foo/
foo.c
foo.h
util.c
util.h
库的 public API 在 foo.h 中定义,所有全局标识符都以 foo_
为前缀或 util_
。模块 util 仅由 foo 使用。为了防止名称与其他名为 util 的模块发生冲突,我想创建一个(静态)库,其中只有来自模块 foo 的标识符可见。我该怎么做?
编辑:我在互联网上进行了相当广泛的搜索,但令人惊讶的是,这似乎是计算机科学中未解决的问题之一。
可能还有其他可能的方法,但这里有一个:
您可以考虑将文件 util.c
包含在 foo.c
中并将所有实用程序函数/全局变量设为静态。即:
#include "util.c"
// ...
这与 *.h
文件的工作方式相同,它只是将整个源代码移植到 foo.c
,嵌套 util.c
并使所有静态数据可用。
执行此操作时,我将文件重命名为 .inc
(即 util.c
=> util.inc
)...
#include "util.inc"
// ...
...这是我在某处找到的旧约定,尽管它可能与汇编程序文件冲突,因此您必须自行判断。
编辑
另一种方法可能需要特定于链接器的指令。例如,this SO answer details GNU's ld
to achieve this goal。还有其他方法,列在同一个线程中。
以下是特定于 GCC 的。
您可以用
标记每个效用函数
__attribute__((visibility ("hidden")))
这将防止它被链接到另一个共享对象。
您可以将其应用到一系列声明中,方法是用
包围它们
#pragma GCC visibility push(hidden)
/* ... */
#pragma GCC visibility pop
或在编译对象时使用-fvisibility=hidden
,这适用于没有明确可见性的声明(例如,既不是__attribute__((visibility))
也不是#pragma GCC visibility
)。
在util.h
中的每个变量和函数声明之前,定义一个宏常量,通过添加库前缀foo_
来重命名声明的标识符,例如
#define util_x foo_util_x
extern int util_x;
#define util_f foo_util_f
void util_f(void);
...
有了这些定义,不需要更改代码的其他部分,并且目标文件 util.o
中的所有全局符号都将以 foo_
为前缀。这意味着不太可能发生名称冲突。
假设我有一个库 foo,它包含模块 foo 和 util 以及具有以下源代码树:
foo/
foo.c
foo.h
util.c
util.h
库的 public API 在 foo.h 中定义,所有全局标识符都以 foo_
为前缀或 util_
。模块 util 仅由 foo 使用。为了防止名称与其他名为 util 的模块发生冲突,我想创建一个(静态)库,其中只有来自模块 foo 的标识符可见。我该怎么做?
编辑:我在互联网上进行了相当广泛的搜索,但令人惊讶的是,这似乎是计算机科学中未解决的问题之一。
可能还有其他可能的方法,但这里有一个:
您可以考虑将文件 util.c
包含在 foo.c
中并将所有实用程序函数/全局变量设为静态。即:
#include "util.c"
// ...
这与 *.h
文件的工作方式相同,它只是将整个源代码移植到 foo.c
,嵌套 util.c
并使所有静态数据可用。
执行此操作时,我将文件重命名为 .inc
(即 util.c
=> util.inc
)...
#include "util.inc"
// ...
...这是我在某处找到的旧约定,尽管它可能与汇编程序文件冲突,因此您必须自行判断。
编辑
另一种方法可能需要特定于链接器的指令。例如,this SO answer details GNU's ld
to achieve this goal。还有其他方法,列在同一个线程中。
以下是特定于 GCC 的。
您可以用
标记每个效用函数__attribute__((visibility ("hidden")))
这将防止它被链接到另一个共享对象。
您可以将其应用到一系列声明中,方法是用
包围它们#pragma GCC visibility push(hidden)
/* ... */
#pragma GCC visibility pop
或在编译对象时使用-fvisibility=hidden
,这适用于没有明确可见性的声明(例如,既不是__attribute__((visibility))
也不是#pragma GCC visibility
)。
在util.h
中的每个变量和函数声明之前,定义一个宏常量,通过添加库前缀foo_
来重命名声明的标识符,例如
#define util_x foo_util_x
extern int util_x;
#define util_f foo_util_f
void util_f(void);
...
有了这些定义,不需要更改代码的其他部分,并且目标文件 util.o
中的所有全局符号都将以 foo_
为前缀。这意味着不太可能发生名称冲突。