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

Gcc 如何限制导出符号的可见性?,gcc,cmake,static-libraries,libraries,unix-ar,Gcc,Cmake,Static Libraries,Libraries,Unix Ar,我正在编译和归档一个库(称之为libbar.a)。该库中的关键翻译单元使用在foo.cpp中定义(非静态)的函数void foo() 我希望避免此void foo()与代码库(使用该库)中其他地方的其他符号冲突。现在,您可以说-只是不要包含声明void foo()的标题;但是-如果我真的在其他地方使用相同的void foo(),会怎么样?尽管在我的整个代码库中只使用一次会更有效,但实际上我希望任何使用该库的人都能忘记内部使用的void foo()的实现细节。所以-我希望没有人能够在libbar.

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

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

我怎样才能做到这一点

注:

    代码(对于<代码> Foo和我的库)都是C和/或C++。假设它是C-only或C++-only的答案也是相关的
  • 我意识到,如果我更改名称(例如,更改为
    void bar\u foo()
    ),或将
    void foo()
    放入命名空间中,可能会产生预期的效果。但我不需要这样做,也就是说,我需要在
    void foo()
    中继续使用相同的代码,而不做任何更改。我只愿意更改使用
    void foo()
    的库代码和构建机制中的内容
  • 我在Linux上与gcc合作;不过,我希望有一些东西能与叮当一起工作,或者是编译器不可知论的。我还使用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\u EXPORT
预先绑定到所有公共符号,并使用
-DBUILD\u DYN\u LIB
构建源代码。 在Linux上,添加链接器标志
-fvisibility=hidden

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

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

如果可以,可以使用下面介绍的技巧修补libbar.a的所有符号:


在应用程序中,如果需要使用“修补”libbar.a中的符号(函数),则必须在符号名称前面加上您在
--前缀符号

中指定的符号名称
在一个单独的静态库中,并将其链接到您的
libbar.a
?这是一个毫无意义的问题,因为您本质上是在问“如何在不使用唯一名称的情况下避免名称冲突”。我认为
ar
格式化静态库是不可能的。对于
。因此
格式化动态库(对于Windows DLL),您可以控制导出哪些符号。我认为在构建库时,您需要为链接器提供一个选项,以便从导出的库中删除foosymbols@einpoklum你清楚地说你不能触摸源代码,C和C++是关于代码问题,而不是编译和链接。如果你看过benjarobin提供的链接,我想它可能会回答你的问题,我猜在构建动态库时会有更多的灵活性,但仍然是+1。此外,我愿意接受一种“不恰当”的方式…@einpoklum我添加了一个注释,试图解释如果相同的符号在静态库和应用程序代码中会发生什么情况,我可能已经找到了解决方案: