如何重命名共享库以避免同名冲突



我找到了一个库,libjson,我正在尝试将其构建为共享库并在项目中使用。 建筑很简单;修复了生成文件错误后,

# SHARED=1 make install

将在/usr/lib中编译并安装.so。 问题是我的系统(Arch Linux)已经有一个名为libjson的库,Makefile不假思索地为我覆盖了它! Arch 的库是作为依赖项安装的,因此无法替换。 如果其他发行版有一个名为 libjson 的库,大概也会遇到类似的问题。

我能做些什么呢? 我可以重命名库(libjson-mine或其他东西),但动态链接离魔法只有几步之遥,所以我不知道这是否会破坏一些东西。 如何重命名库?

另一种选择是将库的源代码放入我当前项目的源代码树中,并让构建器创建一个静态库。 (显然,这使我的代码存储库有点混乱,因此是不可取的。 如果我走这条路,我需要让链接器更喜欢我的libjson.a,而不是/usr/lib搜索"合适的"(阅读:错误的)库。 如何使链接器首选我的版本?

或者,是否有我不知道的第三个选项?

背景概念

共享库在两点使用:

  • 链接器编译 ( ld
  • 由动态加载程序执行
  1. 如果你使用 -ljson 在 gcc 中编译,则基本名称将存储在可执行文件中

    在执行时,将在标准路径中搜索该基本名称。

    在链接时,链接器必须能够在其搜索路径上找到库。在搜索路径前面附加并不容易:

    • GCC 默认情况下如何在默认链接器搜索路径之前添加?LIBRARY_PATH不起作用
    • 如何阻止 gcc 使用标准库路径将 -L 传递到链接器

    您也许可以摆脱/usr/local/lib,这是针对用户编译库的,应该在/usr/lib之前。

    但是这样做会破坏任何使用其他libjson的东西,所以你可能不希望这样。

  2. 如果你使用 -l:/full/path/to/libjson.so 在 gcc 中编译,则完整路径将存储在可执行文件中。

    在执行时,不需要路径搜索,因为我们已经有了完整的路径。

您可以使用以下命令检查存储在可执行文件中的哪些内容:

readelf -d a.out | grep 'Shared library'

可能的解决方案

我没有看到任何不需要编辑项目Makefile的好解决方案,因此细节是特定于项目的。但一般而言,您可以:

  1. 编辑库的生成文件或类似名称,并将基本名称重命名为 libjson_mine.so

    编译需要该库的程序:-ljson_mine .这将起作用,因为我们知道/usr/lib.so搜索路径中。

    这是最好的选择,迟早要做,否则会成为无尽混乱的根源......发送拉取请求!

    在同一拉取请求中,还将默认安装目录更改为 /usr/local/lib 而不是 /usr/lib 。这是理智的用户编译库默认必须去的地方,正是为了避免覆盖发行版提供的库。

  2. 如果所有者不想重命名库,请在生成文件中找到一个选项来更改生成的库的基本名称。

If such option does not exist, pull request. If the owner does not want to accept that, fork the project ;-)
Then you and your distribution can use that option when compiling.
  1. 在 Makefile 中找到一个选项,用于更改安装库 + 标头的目录,然后使用完全自定义的内容(~/usr/lib~usr/include ),并将其添加到动态加载程序搜索路径中 如何指定库路径的首选项? + 包含搜索路径。参见 DESTDIR 和 PREFIX of make for GNU 方法。

    然后在编译/执行时,更改包含/动态加载程序搜索路径。

    不理想,但可能适用于一次性。

有几种方法:

  • 默认情况下安装的库听起来好像您也可以使用这些东西。想过吗?

  • 也许您确实可以重命名"其他"json库,并将其安装到/usr/local/lib

  • 也许你可以学习在 Arch Linux 上构建一个(pacman?)包。我不知道,但应该不会太难。至少,它不适用于基于 RPM 的系统,所以我认为它也不在 Arch 上。

  • 你可以选择介于两者之间的方式:

    从其他项目构建静态库,并将其包含在您自己的项目中。这样你就不会弄乱已安装的库,而且你的代码树是干净的。

最新更新