避免名称冲突的静态库建议
Suggestions for static library to avoid name collision
我们有两个库 - lib1 和 lib2。这两个库都使用第三个库,比如 lib3。如果我们的客户在使用静态链接的同一应用程序中使用 lib1 和 lib2,由于 lib3 中的函数在 lib1 和 lib2 中很常见,客户将面临符号冲突导致的链接问题。
我们可以访问 lib1、lib2、lib3 源代码。我们应该做哪些更改来避免命名冲突?
看了一些帖子后,C++ 中的命名空间似乎可以解决问题?但它在我们的例子中是否有效,因为 lib3 仍将被加载两次?
我会留下一个答案,因为这不适合评论。
据我了解,您为 lib1
和 lib2
部署了某种软件开发工具包。每个 SDK 都包含一些 public headers 以及 lib1
和 lib2
静态库。这两个库都是用 lib3
静态 linked 的,这是一个内部库。
所以 SDK 可能看起来像这样:
lib1 SDK
├── lib
│ ├── lib1.lib
├── headers
│ └── lib1.h
lib2 SDK
├── lib
│ ├── lib2.lib
├── headers
│ └── lib2.h
除客户同时需要 lib1
和 lib2
的情况外,这非常有用。我们的建议是:不要静态 link lib3
,而是将其部署在 lib1
和 lib2
SDK 中。在这种情况下,您的客户只需将他们的构建脚本更新为 link 已经包含的 lib3
。因此 lib1
客户现在将 link 与 lib1
和 lib3
; lib2
客户现在 link lib2
和 lib3
。您已经将 lib3
部署给客户,只是不是作为 stand-alone 文件,而是包含在 lib1
和 lib2
库中,因此这里没有大的变化。
这意味着同时使用两者的客户可以选择您提供的 lib3
之一,然后 link 反对它。
您的 SDK 现在看起来像这样:
lib2 SDK
├── lib
│ ├── lib2.lib
├── headers
│ └── lib2.h
├── dependencies
│ └── lib3.lib
(same for lib1)
现在存在客户使用 lib1 1.0
的风险,这取决于 lib3 1.0
和 lib2 2.0
这取决于 lib3 2.0
,这两个 lib3
版本是二进制兼容的(linking 将成功用于 lib1
和 lib2
,而不管 lib3
版本如何),但两者之间有 API 变化lib3
个会产生 运行 时间错误的版本。
在这种情况下,您必须能够在构建时验证兼容性(当您不控制构建过程时更难做到),或者在 运行 时(只要这样做的 lib3
API 不会改变)。
您也可以尝试通过为 lib1
和 lib2
提供通用 SDK 来满足这些客户的需求,该 SDK 始终包含保证与两者兼容的 lib3
版本。但是,这对您来说可能不是一个具有成本效益的策略。
编辑:正如@lalala 所提到的,存在 multi-threaded 可能使这变得不可行的担忧。例如,如果 lib3
不是线程安全的,使 lib1
和 lib2
使用相同的 lib3
将导致竞争条件、死锁等。
我们终于使用动态命名空间解决了问题
首先,为命名空间定义一个宏
#ifndef LIB_NAMESPACE
#define LIB_NAMESPACE SomeNameSpace
#endif
然后在每个 class 周围添加命名空间。
编译时从编译器命令行覆盖宏,例如
g++ -DMY_LIB_NAMESPACE=Lib1Namespace ...
g++ -DMY_LIB_NAMESPACE=Lib2Namespace ...
唯一的缺点是由于重复代码,最终可执行文件的大小会稍大。
我们有两个库 - lib1 和 lib2。这两个库都使用第三个库,比如 lib3。如果我们的客户在使用静态链接的同一应用程序中使用 lib1 和 lib2,由于 lib3 中的函数在 lib1 和 lib2 中很常见,客户将面临符号冲突导致的链接问题。
我们可以访问 lib1、lib2、lib3 源代码。我们应该做哪些更改来避免命名冲突?
看了一些帖子后,C++ 中的命名空间似乎可以解决问题?但它在我们的例子中是否有效,因为 lib3 仍将被加载两次?
我会留下一个答案,因为这不适合评论。
据我了解,您为 lib1
和 lib2
部署了某种软件开发工具包。每个 SDK 都包含一些 public headers 以及 lib1
和 lib2
静态库。这两个库都是用 lib3
静态 linked 的,这是一个内部库。
所以 SDK 可能看起来像这样:
lib1 SDK
├── lib
│ ├── lib1.lib
├── headers
│ └── lib1.h
lib2 SDK
├── lib
│ ├── lib2.lib
├── headers
│ └── lib2.h
除客户同时需要 lib1
和 lib2
的情况外,这非常有用。我们的建议是:不要静态 link lib3
,而是将其部署在 lib1
和 lib2
SDK 中。在这种情况下,您的客户只需将他们的构建脚本更新为 link 已经包含的 lib3
。因此 lib1
客户现在将 link 与 lib1
和 lib3
; lib2
客户现在 link lib2
和 lib3
。您已经将 lib3
部署给客户,只是不是作为 stand-alone 文件,而是包含在 lib1
和 lib2
库中,因此这里没有大的变化。
这意味着同时使用两者的客户可以选择您提供的 lib3
之一,然后 link 反对它。
您的 SDK 现在看起来像这样:
lib2 SDK
├── lib
│ ├── lib2.lib
├── headers
│ └── lib2.h
├── dependencies
│ └── lib3.lib
(same for lib1)
现在存在客户使用 lib1 1.0
的风险,这取决于 lib3 1.0
和 lib2 2.0
这取决于 lib3 2.0
,这两个 lib3
版本是二进制兼容的(linking 将成功用于 lib1
和 lib2
,而不管 lib3
版本如何),但两者之间有 API 变化lib3
个会产生 运行 时间错误的版本。
在这种情况下,您必须能够在构建时验证兼容性(当您不控制构建过程时更难做到),或者在 运行 时(只要这样做的 lib3
API 不会改变)。
您也可以尝试通过为 lib1
和 lib2
提供通用 SDK 来满足这些客户的需求,该 SDK 始终包含保证与两者兼容的 lib3
版本。但是,这对您来说可能不是一个具有成本效益的策略。
编辑:正如@lalala 所提到的,存在 multi-threaded 可能使这变得不可行的担忧。例如,如果 lib3
不是线程安全的,使 lib1
和 lib2
使用相同的 lib3
将导致竞争条件、死锁等。
我们终于使用动态命名空间解决了问题
首先,为命名空间定义一个宏
#ifndef LIB_NAMESPACE
#define LIB_NAMESPACE SomeNameSpace
#endif
然后在每个 class 周围添加命名空间。
编译时从编译器命令行覆盖宏,例如
g++ -DMY_LIB_NAMESPACE=Lib1Namespace ...
g++ -DMY_LIB_NAMESPACE=Lib2Namespace ...
唯一的缺点是由于重复代码,最终可执行文件的大小会稍大。