【问题标题】:How to limit the visibility of an exported symbol? [closed]如何限制导出符号的可见性? [关闭]
【发布时间】:2018-05-01 11:01:21
【问题描述】:

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

我想避免这个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 代码 - 只需概括地说您希望构建系统执行的操作即可。

【问题讨论】:

  • 如果您将宝贵的foo() 放在单独的静态库中并将其链接到您的libbar.a,会发生什么?
  • 这是一个毫无意义的问题,因为您本质上是在问“如何在不使用唯一名称的情况下避免名称冲突”。
  • 我认为ar 格式的静态库是不可能的。对于.so 格式的动态库(以及对于 Windows DLL),您可以控制导出哪些符号。
  • 我认为在构建库时,您需要为链接器提供一个选项,以从导出的符号中删除 foo
  • @einpoklum 你清楚地说你不能接触源代码,C 和 C++ 是关于代码问题,而不是关于编译和链接。你看过benjarobin提供的链接吗,我想它可能会回答你的问题stackoverflow.com/a/6940389/7076153

标签: gcc cmake static-libraries libraries unix-ar


【解决方案1】:

如果您非静态编译库(创建 .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 中指定的内容

【讨论】:

  • 我猜想在构建动态库时会有更大的灵活性,但还是 +1。另外,我愿意接受一种“不正当”的方式……
  • @einpoklum 我添加了一条注释,试图解释如果静态库和应用程序代码中存在相同的符号会发生什么
  • 我可能找到了解决方案:stackoverflow.com/questions/10157680/…
猜你喜欢
  • 1970-01-01
  • 2013-05-22
  • 2022-01-22
  • 2014-01-31
  • 2020-10-02
  • 2013-04-01
  • 1970-01-01
  • 2014-08-21
  • 2020-01-04
相关资源
最近更新 更多