【问题标题】:Path/namespace collisions for identical C libraries相同 C 库的路径/命名空间冲突
【发布时间】:2017-11-20 14:10:56
【问题描述】:

背景

我正在使用一个庞大的 C 库,用于与我们的产品交互。我们最初只有一个产品coconut,它使用libfruit.so,以及libfruit 的所有相关API 头文件。头文件本身不使用相对路径包含,而是项目根包含。例如,考虑这两个实际的标题:

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

coconut.h文件中,包含base.h via:

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

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


问题

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

  1. 我们希望支持另一个产品,pineapple
  2. libfruit 的开发人员决定分叉 libfruit,以便为每个产品提供不同的版本。

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

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 被覆盖取决于我首先复制的两个依赖项中的哪一个。我所做的第一步是将每个库移动到我的构建环境中它自己的不同子目录中:

~/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

但这并没有完全解决我的问题:两个库提供的头文件不使用相对包含路径,并且库头文件抱怨无法从同一个库中找到其他头文件,除非我设置了包含路径对于 both 组标题,即:

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

这似乎有效地使项目无法同时利用两个库,而没有不确定地解析标头。


问题

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

【问题讨论】:

  • 一种非常有用的方法是要求项目负责人提交用于项目请求的每个库,然后为特定库的所有符号使用唯一的短(例如 3 个字符)前缀以被出口。这几乎可以保证库之间不会发生冲突。例如coc_func1() 代表椰子。 pin_func1() 菠萝。
  • “假设我无法更改任何一个 libfruit 库、它们的标头等” 当您需要添加 libfruit_orange 时,这似乎很麻烦。为什么不为每个单独的水果提供一个基础库和附加库?

标签: c linux gcc makefile shared-libraries


【解决方案1】:

鉴于您无法更改现有库或标头,唯一的方法是为每个现有库/标头创建一个单独的新包装库,并在每个共享库项目中,wrap typedef 具有唯一前缀标识符的所有现有符号(可能会发生冲突),例如 pin_coc_(分别代表菠萝、椰子)。原始标头中存在的路径可以替换为包装标头中原始位置的符号链接,以减轻标头问题。这种方法应该消除所有冲突。然后,您可以构建(并交付)一个共享库,其中包含原始子库集合的所有功能。

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

【讨论】:

    猜你喜欢
    • 2012-12-18
    • 1970-01-01
    • 2021-11-22
    • 2011-08-06
    • 1970-01-01
    • 1970-01-01
    • 2010-09-20
    • 1970-01-01
    相关资源
    最近更新 更多