我找到了一个库,libjson
,我正在尝试将其构建为共享库并在项目中使用。 建筑很简单;修复了生成文件错误后,
# SHARED=1 make install
将在/usr/lib
中编译并安装.so
。 问题是我的系统(Arch Linux)已经有一个名为libjson
的库,Makefile不假思索地为我覆盖了它! Arch 的库是作为依赖项安装的,因此无法替换。 如果其他发行版有一个名为 libjson
的库,大概也会遇到类似的问题。
我能做些什么呢? 我可以重命名库(libjson-mine
或其他东西),但动态链接离魔法只有几步之遥,所以我不知道这是否会破坏一些东西。 如何重命名库?
另一种选择是将库的源代码放入我当前项目的源代码树中,并让构建器创建一个静态库。 (显然,这使我的代码存储库有点混乱,因此是不可取的。 如果我走这条路,我需要让链接器更喜欢我的libjson.a
,而不是/usr/lib
搜索"合适的"(阅读:错误的)库。 如何使链接器首选我的版本?
或者,是否有我不知道的第三个选项?
背景概念
共享库在两点使用:
- 链接器编译 (
ld
) - 由动态加载程序执行
-
如果你使用
-ljson
在 gcc 中编译,则基本名称将存储在可执行文件中在执行时,将在标准路径中搜索该基本名称。
在链接时,链接器必须能够在其搜索路径上找到库。在搜索路径前面附加并不容易:
- GCC 默认情况下如何在默认链接器搜索路径之前添加?LIBRARY_PATH不起作用
- 如何阻止 gcc 使用标准库路径将 -L 传递到链接器
您也许可以摆脱
/usr/local/lib
,这是针对用户编译库的,应该在/usr/lib
之前。但是这样做会破坏任何使用其他
libjson
的东西,所以你可能不希望这样。 -
如果你使用
-l:/full/path/to/libjson.so
在 gcc 中编译,则完整路径将存储在可执行文件中。在执行时,不需要路径搜索,因为我们已经有了完整的路径。
您可以使用以下命令检查存储在可执行文件中的哪些内容:
readelf -d a.out | grep 'Shared library'
可能的解决方案
我没有看到任何不需要编辑项目Makefile
的好解决方案,因此细节是特定于项目的。但一般而言,您可以:
编辑库的生成文件或类似名称,并将基本名称重命名为
libjson_mine.so
。编译需要该库的程序:
-ljson_mine
.这将起作用,因为我们知道/usr/lib
在.so
搜索路径中。这是最好的选择,迟早要做,否则会成为无尽混乱的根源......发送拉取请求!
在同一拉取请求中,还将默认安装目录更改为
/usr/local/lib
而不是/usr/lib
。这是理智的用户编译库默认必须去的地方,正是为了避免覆盖发行版提供的库。如果所有者不想重命名库,请在生成文件中找到一个选项来更改生成的库的基本名称。
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.
在 Makefile 中找到一个选项,用于更改安装库 + 标头的目录,然后使用完全自定义的内容(
~/usr/lib
、~usr/include
),并将其添加到动态加载程序搜索路径中 如何指定库路径的首选项? + 包含搜索路径。参见 DESTDIR 和 PREFIX of make for GNU 方法。然后在编译/执行时,更改包含/动态加载程序搜索路径。
不理想,但可能适用于一次性。
有几种方法:
-
默认情况下安装的库听起来好像您也可以使用这些东西。想过吗?
-
也许您确实可以重命名"其他"json库,并将其安装到
/usr/local/lib
。 -
也许你可以学习在 Arch Linux 上构建一个(pacman?)包。我不知道,但应该不会太难。至少,它不适用于基于 RPM 的系统,所以我认为它也不在 Arch 上。
-
你可以选择介于两者之间的方式:
从其他项目构建静态库,并将其包含在您自己的项目中。这样你就不会弄乱已安装的库,而且你的代码树是干净的。