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

时间:2018-05-01 11:01:21

标签: gcc cmake static-libraries libraries ar

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

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

我怎样才能做到这一点?

注意:

  • 代码(foo和我的库)都是C和/或C ++。假设它只是C-C或C ++的答案也是相关的。
  • 我意识到,如果我更改名称(例如更改为void bar_foo()),或将void foo()放入命名空间,则可能会产生预期效果。但我不需要这样做,即我需要继续使用void foo()的相同代码而不做任何更改。我只愿意改变使用void foo()和构建机制的库代码中的东西。
  • 我在Linux上使用gcc;我希望有一些与clang一起工作或者与编译器无关的东西。我还使用CMake自动化我的构建,但是不要费心编写CMake代码 - 只需说明构建系统要做的一般事项。

1 个答案:

答案 0 :(得分:2)

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

你可以用这种MACRO来实现这个目标:

#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

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

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

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

如果可以,您可以使用此处描述的技巧修补libbar.a的所有符号:https://stackoverflow.com/a/6940389/808101

在您的应用程序中,如果您需要使用" patched"中的符号(函数)。 libbar.a,您必须在符号名称前加上--prefix-symbols

中指定的内容