我正在编译和归档一个库(称之为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
中指定的符号名称