Path/namespace 相同 C 库的冲突

Path/namespace collisions for identical C libraries

背景

我正在使用一个庞大的 C 库来连接我们的产品。我们最初只有一个产品 coconut,它利用了 libfruit.so,以及 libfruit 的所有相关 API header 文件。 header 文件本身不使用相对路径包含,而是使用项目根目录包含。例如,考虑这两个实际的 headers:

${LIBFRUIT_BASE}/headers/Include/fruit/framework/beta/base.h
${LIBFRUIT_BASE}/headers/Include/fruit/framework/beta/coconut.h

coconut.h 文件中,它包括 base.h 通过:

#include "Include/fruit/framework/beta/base.h"

它通过设置 CFLAGS+= -I ${LIBFRUIT_BASE}/headers 之类的东西来做到这一点。针对 libfruit 构建的外部程序类似地设置路径标志来解析 headers.


问题

这在构建 libfruit 时有效,并且在构建依赖于 libfruit 的程序时很容易,但现在我们遇到了一个大问题:

  1. 我们想支持一个额外的产品,pineapple
  2. libfruit 的开发人员决定分叉 libfruit,以便每个产品都有不同的版本。

处理两个库非常容易,因为我们现在有一个 libfruit_coconut.so(重命名为 libfruit.so)和一个 libfruit_pineapple.so。从两个库中删除名称冲突的全局导出符号后,这些库可以正常工作。然而,还有一个更大的问题:公开导出的 libfruit_coconutlibfruit_pineapple 的 header 会发生冲突,即:

libfruit_coconut:

~/projects/myapp/dependencies/headers/Include/fruit/framework/beta/base.h
~/projects/myapp/dependencies/headers/Include/fruit/framework/beta/coconut.h

libfruit_pineapple:

~/projects/myapp/dependencies/headers/Include/fruit/framework/beta/base.h
~/projects/myapp/dependencies/headers/Include/fruit/framework/beta/pineapple.h

这是一切都崩溃的地方:我必须使用两个版本的几乎相同的库,并且 base.h 被覆盖取决于我首先复制的两个依赖项中的哪一个。我做的第一步是将每个库移动到我的构建环境中它自己独特的 sub-directory:

~/projects/myapp/dependencies/libfruit_coconut/headers/Include/fruit/framework/beta/base.h
~/projects/myapp/dependencies/libfruit_coconut/headers/Include/fruit/framework/beta/coconut.h
~/projects/myapp/dependencies/libfruit_pineapple/headers/Include/fruit/framework/beta/base.h
~/projects/myapp/dependencies/libfruit_pineapple/headers/Include/fruit/framework/beta/pineapple.h

虽然这并没有完全解决我的问题:两个库提供的 headers 不使用相对包含路径,并且库 headers 抱怨无法找到来自同一库的其他 headers,除非我为 both 组 headers 设置我的包含路径,即:

CFLAGS += -I~/projects/myapp/dependencies/libfruit_coconut   \
          -I~/projects/myapp/dependencies/libfruit_pineapple

这似乎有效地使项目不可能在不解决 header 的情况下同时使用两个库 non-deterministically。


问题

假设我无法更改任何一个 libfruit 库、它们的 header 等;有什么理智的方法可以在一个项目中同时使用这两个库吗?我的问题的中心似乎是库 header 本身如何相互引用。还是我一直在强迫库开发人员为他们的 API header 使用相对包含路径,或者在他们所有的 header 中插入 libfruit_${VARIANT_NAME}

鉴于您无法更改现有的库或 headers,唯一的方法就是为每个现有的 library/header 创建一个单独的新包装器库,并在每个共享库项目,wraptypedef 所有现有符号(有可能发生冲突)具有唯一前缀标识符,例如 pin_coc_(分别对应菠萝和椰子)。原始 headers 中存在的路径可以替换为指向包装器 headers 中原始位置的符号链接,以缓解 header 问题。这种方法应该消除所有冲突。然后,您可以构建(并交付)一个共享库,其中包含 sub-libraries 的原始 collection 的所有功能。

使用这种方法,虽然公认是蛮力的,而且并不理想,但它为在某种总体设计或项目管理之外开发的应用程序(或库)中的功能扩展提供了一种灵活的前进方式。