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
的程序时很容易,但现在我们遇到了一个大问题:
- 我们想支持一个额外的产品,
pineapple
。
libfruit
的开发人员决定分叉 libfruit
,以便每个产品都有不同的版本。
处理两个库非常容易,因为我们现在有一个 libfruit_coconut.so
(重命名为 libfruit.so
)和一个 libfruit_pineapple.so
。从两个库中删除名称冲突的全局导出符号后,这些库可以正常工作。然而,还有一个更大的问题:公开导出的 libfruit_coconut
和 libfruit_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 创建一个单独的新包装器库,并在每个共享库项目,wrap 或 typedef 所有现有符号(有可能发生冲突)具有唯一前缀标识符,例如 pin_
或 coc_
(分别对应菠萝和椰子)。原始 headers 中存在的路径可以替换为指向包装器 headers 中原始位置的符号链接,以缓解 header 问题。这种方法应该消除所有冲突。然后,您可以构建(并交付)一个共享库,其中包含 sub-libraries 的原始 collection 的所有功能。
使用这种方法,虽然公认是蛮力的,而且并不理想,但它为在某种总体设计或项目管理之外开发的应用程序(或库)中的功能扩展提供了一种灵活的前进方式。
背景
我正在使用一个庞大的 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
的程序时很容易,但现在我们遇到了一个大问题:
- 我们想支持一个额外的产品,
pineapple
。 libfruit
的开发人员决定分叉libfruit
,以便每个产品都有不同的版本。
处理两个库非常容易,因为我们现在有一个 libfruit_coconut.so
(重命名为 libfruit.so
)和一个 libfruit_pineapple.so
。从两个库中删除名称冲突的全局导出符号后,这些库可以正常工作。然而,还有一个更大的问题:公开导出的 libfruit_coconut
和 libfruit_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 创建一个单独的新包装器库,并在每个共享库项目,wrap 或 typedef 所有现有符号(有可能发生冲突)具有唯一前缀标识符,例如 pin_
或 coc_
(分别对应菠萝和椰子)。原始 headers 中存在的路径可以替换为指向包装器 headers 中原始位置的符号链接,以缓解 header 问题。这种方法应该消除所有冲突。然后,您可以构建(并交付)一个共享库,其中包含 sub-libraries 的原始 collection 的所有功能。
使用这种方法,虽然公认是蛮力的,而且并不理想,但它为在某种总体设计或项目管理之外开发的应用程序(或库)中的功能扩展提供了一种灵活的前进方式。