将函数保密到 C 中的库中
Keep functions private into a lib in C
我最近不得不面对一个关于库管理的相当复杂的问题,但我会很惊讶成为第一个。
假设您正在 C 中创建一个名为 lib1
的库(静态或动态)。在 lib1
中有一些函数通过 API 公开,还有一些其他函数保持私有。
理想情况下,私有函数应该是 static
。不幸的是,我们假设其中一个名为 extmod.c
的源文件来自另一个项目,并且最好不修改它。因此,static
它定义的函数变得不切实际。
因此,extmod
中定义的所有函数都出现在 lib1
ABI 中,但 API 中没有,因为相关的 *.h
未发布。所以没有人注意到。
不幸的是,在后期,有人想要 link 同时 lib1
和另一个 lib2
,其中还包括 extmod
。由于重复定义,它会导致 linking 错误。
在C++
中,这个问题的答案是一个简单的命名空间。在 C 中,我们就没那么幸运了。
这个问题有几个解决方案,但我想询问是否有人相信已经找到了一种有效且非侵入性的方法。 "non-invasive",我指的是一种尽可能避免修改 extmod.c
.
的方法
在可能的解决方法中,可以使用不同的前缀更改 extmod.c
中的所有定义,从而有效地模拟命名空间。或者将 extmod.c
的内容放入 extmod.h
并静态化所有内容的可能性。这两种方法都广泛修改 extmod
虽然 ...
请注意,我查看了 this previous answer,但它没有解决这个具体问题。
您可以通过从您的构建中排除 extmod.c 并将其作为头文件以某种方式处理来实现您的 'different prefix' 解决方案。使用 C 预处理器可以有效地修改文件,而无需实际修改它。例如,如果 extmod.c 包含:
void print_hello()
{
printf("hello!");
}
从您的构建中排除此文件并添加一个名为 ns_extmod.c 的文件。该文件的内容应如下所示:
#define print_hello ns_print_hello
#include "extmod.c"
在编译时,print_hello 将被 C 预处理器重命名为 ns_print_hello,但原始文件将保持不变。
或者,当且仅当函数未被 extmod.c 内部调用时,使用预处理器以相同的方式使它们成为静态的可能有效:
#define print_hello static print_hello
#include "extmod.c"
假设您可以控制构建过程,这应该对您有用。
无需实际编辑即可添加前缀的一种方法 extmod.c 如下:
创建一个新的头文件extmod_prefix.h为:
#ifndef EXTMOD_PREFIX_H
#define EXTMOD_PREFIX_H
#ifdef LIB1
#define PREFIX lib1_
#else
#ifdef LIB2
#define PREFIX lib2_
#endif
#endif
#define function_in_extmod PREFIX##function_in_extmod
/* Do this for all the functions in extmod.c */
#endif
将此文件包含在 extmod.h 中,并在 lib1 的构建过程中定义 LIB1,在 lib2 中定义 LIB2。
这样,extmod.c中的所有函数将在 lib1 中以 lib1_ 为前缀,在 lib2 中以 lib2_ 为前缀。
Here's the answer(以问题的形式)。相关部分:
objcopy --prefix-symbols
allows me to prefix all symbols exported by
an object file / static library.
我最近不得不面对一个关于库管理的相当复杂的问题,但我会很惊讶成为第一个。
假设您正在 C 中创建一个名为 lib1
的库(静态或动态)。在 lib1
中有一些函数通过 API 公开,还有一些其他函数保持私有。
理想情况下,私有函数应该是 static
。不幸的是,我们假设其中一个名为 extmod.c
的源文件来自另一个项目,并且最好不修改它。因此,static
它定义的函数变得不切实际。
因此,extmod
中定义的所有函数都出现在 lib1
ABI 中,但 API 中没有,因为相关的 *.h
未发布。所以没有人注意到。
不幸的是,在后期,有人想要 link 同时 lib1
和另一个 lib2
,其中还包括 extmod
。由于重复定义,它会导致 linking 错误。
在C++
中,这个问题的答案是一个简单的命名空间。在 C 中,我们就没那么幸运了。
这个问题有几个解决方案,但我想询问是否有人相信已经找到了一种有效且非侵入性的方法。 "non-invasive",我指的是一种尽可能避免修改 extmod.c
.
在可能的解决方法中,可以使用不同的前缀更改 extmod.c
中的所有定义,从而有效地模拟命名空间。或者将 extmod.c
的内容放入 extmod.h
并静态化所有内容的可能性。这两种方法都广泛修改 extmod
虽然 ...
请注意,我查看了 this previous answer,但它没有解决这个具体问题。
您可以通过从您的构建中排除 extmod.c 并将其作为头文件以某种方式处理来实现您的 'different prefix' 解决方案。使用 C 预处理器可以有效地修改文件,而无需实际修改它。例如,如果 extmod.c 包含:
void print_hello()
{
printf("hello!");
}
从您的构建中排除此文件并添加一个名为 ns_extmod.c 的文件。该文件的内容应如下所示:
#define print_hello ns_print_hello
#include "extmod.c"
在编译时,print_hello 将被 C 预处理器重命名为 ns_print_hello,但原始文件将保持不变。
或者,当且仅当函数未被 extmod.c 内部调用时,使用预处理器以相同的方式使它们成为静态的可能有效:
#define print_hello static print_hello
#include "extmod.c"
假设您可以控制构建过程,这应该对您有用。
无需实际编辑即可添加前缀的一种方法 extmod.c 如下:
创建一个新的头文件extmod_prefix.h为:
#ifndef EXTMOD_PREFIX_H
#define EXTMOD_PREFIX_H
#ifdef LIB1
#define PREFIX lib1_
#else
#ifdef LIB2
#define PREFIX lib2_
#endif
#endif
#define function_in_extmod PREFIX##function_in_extmod
/* Do this for all the functions in extmod.c */
#endif
将此文件包含在 extmod.h 中,并在 lib1 的构建过程中定义 LIB1,在 lib2 中定义 LIB2。
这样,extmod.c中的所有函数将在 lib1 中以 lib1_ 为前缀,在 lib2 中以 lib2_ 为前缀。
Here's the answer(以问题的形式)。相关部分:
objcopy --prefix-symbols
allows me to prefix all symbols exported by an object file / static library.