我有一个应用程序想要使用共享库(
libwayland-client.so
)(如果可用),但即使它不可用,仍然需要运行。 实现这一点的通常方法是使用 dlopen()
和 dlsym()
手动读取共享库,但这需要编写一堆粘合代码并阻止我直接使用开发标头。 有没有办法以 ELF 加载器可以理解的方式在 ELF 二进制文件中将共享库依赖项标记为可选?
请注意,这与将共享库中的符号标记为可选不同(这可以通过将其标记为弱符号来完成)。 我问的是如何弱化整个库的依赖。
另请注意,这与构建时依赖关系无关 - 我可以在构建时依赖共享库,但我不想强迫我的用户在他们的计算机上拥有该共享库。
(在我的具体情况下,我希望我的应用程序同时支持 X11 和 Wayland,但为了正确支持 Wayland,它需要对
libwayland-client.so
进行几次调用。但是,我想避免为纯 X11 用户提供单独的二进制文件.)
有没有办法让 Linux ELF 二进制文件具有可选的共享库依赖项而无需 dlopen()?
Linux 使用的 ELF 风格没有办法将共享库依赖项标记为可选(如果任何其他风格也这样做,我会感到惊讶)。
实现这一点的通常方法是使用 dlopen() 和 dlsym() 手动读取共享库,
这是唯一的方式。 但是,如果您需要
dlopen()
ed 库中的少量符号,那就没什么意思了。
但这需要编写一堆粘合代码并阻止我直接使用开发标头。
如果您支持同一程序的两种不同的显示系统,那么您已经拥有一堆粘合代码,并且可以利用它。 这有多困难取决于您当前代码的分解程度,但一种相当好的前进方法是将所有 X11 代码放在一个共享库中,将所有 Wayland 代码放在另一个共享库中,并让每个代码实现相同的 API,通过该 API程序的其余部分访问它。 您必须至少已经拥有一些类似的东西。
您不一定需要使用
dlopen()
来访问那些特定于显示系统的库。 由于它们提供了相同 API 的替代实现,您可以改为
提供可执行文件的替代版本,仅在链接的库中有所不同。
为两个库指定相同的 SONAME。然后通过操作程序加载器的搜索路径或预加载您想要的路径或类似的方式来控制在运行时使用哪个路径。
...或者也许是另一个类似的选择。 其中任何一个都可能受益于包装脚本,该脚本隐藏了为所选执行环境正确启动程序的详细信息。