如何限制导出符号的可见性?



我正在编译和归档一个库(称之为libbar.a(。该库中的关键翻译单元使用void foo()foo.cpp中定义的函数(非静态(,该函数也会被编译并放入库中。

我想避免这种情况void foo()与代码库中其他地方的其他符号冲突(使用该库(。现在,你可以说 - 只是不要包含声明void foo()的标题;但是 - 如果我确实在其他地方使用相同的void foo()怎么办?尽管在我的整个代码库中只使用一次更有效,但我实际上希望使用该库的人忘记内部使用的void foo()的实现细节。所以 - 我希望没有人能够在libbar.a中查找该符号,但libbar.a中的代码仍然能够使用它。

我怎样才能做到这一点?

笔记:

  • 代码(foo和我的库(是 C 和/或 C++。假设它是仅 C 或仅 C++ 的答案也是相关的。
  • 我意识到,如果我更改名称(例如更改为void bar_foo()(,或void foo()放入命名空间中,可能会产生预期的效果。但我不需要这样做,即我需要继续使用相同的代码进行void foo()而不进行更改。我只愿意在使用void foo()的库代码和构建机制中更改内容。
  • 我正在 Linux 上使用 gcc;不过,我希望一些与 clang 一起使用或与编译器无关的东西。我也使用 CMake 自动化我的构建,但不要费心编写 CMake 代码 - 只需笼统地说出您希望构建系统做什么。

如果您非静态编译库(创建 .so 或 .dll(,这是可能的。您可以选择要导出的符号:基本上,您可以隐藏所有符号并向公共符号添加属性。

你可以用这种宏来实现这一点:

#ifdef BUILD_STATIC_LIB
# define LIB_EXPORT
#elif (defined BUILD_DYN_LIB)
# if (defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)
#  ifdef __GNUC__    
#   define LIB_EXPORT  __cdecl __attribute__((dllexport))
#  else
#   define LIB_EXPORT  __cdecl __declspec(dllexport)
#  endif
# else
#  define LIB_EXPORT  __attribute__ ((visibility ("default")))
# endif
#else
# if (defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)
#  ifdef __GNUC__
#   define LIB_EXPORT  __cdecl
#  else
#   define LIB_EXPORT  __declspec(dllexport)
#  endif
# else
#  define LIB_EXPORT
# endif
#endif

为所有公共符号准备宏LIB_EXPORT,并使用-DBUILD_DYN_LIB构建源代码。 在 Linux 上,添加链接器标志-fvisibility=hidden

但是如果你想用静态库(.a(来实现这一点,那么唯一正确的方法是把每个私有函数放在一个命名空间中......

使用静态库也可能是"危险的":如果应用程序提供的符号与静态库中提供的符号相同,则链接器不会发出警告(至少默认情况下是这样(,应用程序将被链接/创建。 链接器将从应用程序中选择符号,而不是从静态库中选择符号。

如果可以的话,你可以使用这里描述的技巧来修补libbar.a的所有符号 https://stackoverflow.com/a/6940389/808101:

在您的应用程序中,如果您需要使用"修补的"libbar.a 中的符号(函数(,则必须在符号名称前面加上您在--prefix-symbols中指定的符号名称

相关内容

  • 没有找到相关文章