在Linux上处理库依赖问题

5
我正在使用libcurl作为我的项目依赖项,但在运行时需要openssl和一些其他.so文件。这种依赖关系比较麻烦,因为不同的发行版/版本可能包含不同的openssl版本。例如,如果我在Ubuntu 9.10上编译我的应用程序,那么在Ubuntu 11.10上运行时会遇到问题。
我看到了两种解决方案,但对于我的情况都不够好: 1. 打包我的应用程序并让软件包管理器解决此类问题。 2. 静态链接所有依赖项。
我的应用程序非常小,打包/维护它是过度设计。而且,其中一个要求是它必须能够下载和运行。所以,选项(1)对我来说不是一个选择。
静态链接(2)似乎是一个不错的解决方案,但似乎没有libopenssl、libcrypto和其他随libcurl附带的传递依赖项的静态二进制分发包。
理论上,我可以尝试手动构建libcurl背后的所有库,但这将使维护工作变得更加复杂。所以,这里的问题是 - 我是否遗漏了什么?在Linux世界(特别是Ubuntu)中有没有更简单的方法来做我想做的事情?欢迎任何建议。

如果您没有使用大量的libcurl函数,您可以自己编写简单的GET、POST调用,并手动解析HTTP响应。您很容易找到有关如何解析这些数据的示例代码。 - Vikram.exe
1
如果您没有使用 GUI,我想不出除了三四个库之外是否有更多的库可供使用。而您提到的两个库:libcurl 和 openssl 在向后兼容方面非常出色。问题是:您确定这里真的有问题吗? - paulsm4
如果是一个小型应用程序,可以使用Python编写,因为这些库是标准的,版本控制也不是很重要。 - Maxim Egorushkin
实际上,我做不到。好吧,至少它不会像看起来那么简单。问题在于这个应用程序是跨平台的,应该能够在Windows / Linux / Mac上工作,我需要libcurl作为抽象层。此外,我不仅需要普通的HTTP,还需要HTTPS,这使事情变得有点更加复杂。 - Eugene Loy
Python和其他需要虚拟机的东西都不是一个选项。该应用程序是跨平台的,强制Windows用户安装虚拟机是我无法承受的事情。 - Eugene Loy
@paulsm4 实际上我需要的只是进行简单的HTTPS GET/POST。令人惊讶的是,如果您想使解决方案真正跨平台,这可能是一个非常棘手的任务。令人惊讶的是,选择并不多,大多数都是基于openssl构建的,而openssl有一堆传递依赖关系。一切都很顺利,直到您尝试像我这样稍微偏离道路。 - Eugene Loy
4个回答

3
我在我的项目中使用libcurl,它依赖于openssl和一堆其他的.so文件在运行时。这种依赖关系有点麻烦,因为不同的发行版/版本可能包含不同的openssl版本。例如,如果我在Ubuntu 9.10上编译了我的应用程序,在Ubuntu 11.10上运行时就会遇到问题。
首先,这有什么问题吗?如果您从旧版Ubuntu升级到新版,就不应该有问题。如果我没记错的话,您只需要指定所需库的最低版本,软件包管理器就应该能够安装合适的版本。除非您正在使用弃用的功能,否则较新版本的库不应该破坏现有的应用程序。
我的应用程序非常小,打包/维护它将是过度杀伤力。此外,其中一个要求是它应该可以下载并运行。因此,对我来说,选项1不可行。
对于Linux(特别是Ubuntu、Fedora和其他顶级发行版),打包真的是分发应用程序的方式。下载-安装-运行是Windows的事情,而且这不是Linux用户安装软件的方式(好吧,新手可能会...)。
你还应该尝试获得发行版的认可,这将减轻你的负担。在Ubuntu上,至少要迈出的第一步是创建自己的PPA(https://help.launchpad.net/Packaging/PPA)。

静态链接(2)也不是一个坏办法,但似乎没有libcurl附带的静态二进制分发所需的libopenssl、libcrypto和其他传递依赖项。

这通常是一个非常非常糟糕的事情。静态链接或仅将库与应用程序捆绑在一起会使更新的负担落在你身上,如果你不更新它们,就会产生影响。因此,我不建议采用这种方法。请参阅此处以获取更多详细信息:http://www.dwheeler.com/blog/2012/04/03/#insecure-libraries
这里是 Fedora 的政策: http://fedoraproject.org/wiki/Packaging:No_Bundled_Libraries 所以,问题来了 - 我有什么遗漏吗?在 Linux 世界中(具体来说是 Ubuntu),有没有更少痛苦的方式来做我想要的事情?欢迎任何建议。
这里实际上有两件事要做:
  1. 打包:理想情况下,这将是 Ubuntu/Debian 的 deb 包和 Fedora/Suse 的 rpm 包。另一个流行的选择是使用 autotools(autoconf/automake),以便用户可以使用所需的前置条件构建您的应用程序。最后一种选择是提供一个 Makefile 和一个 README,并期望您的用户做正确的事情。
  2. 分发:理想情况下,这是通过发行版存储库进行的。Ubuntu PPA 是一个好的起点。另一种选择是在自己的网站上托管二进制文件/软件包。
大多数流行的应用程序都会提供 .deb/.rpm 适用于流行的 Linux 发行版,以及 .tar.gz 与 autotools 适用于具有不同打包系统的发行版的构建。
最后,让我问你一句:你的重点是让你提供应用程序更少痛苦,还是让你的用户获取应用程序更少痛苦?

感谢您的回复。关于libcurl和Ubuntu版本:这是因为我尝试仅静态链接libcurl(而不是传递依赖项)所致。结果是:一些这些依赖项在静态链接的libcurl所需的版本中不存在。 - Eugene Loy
关于静态构建:嗯,我已经深入研究了一下,现在我明白这只适用于Windows,而不是我在Linux上应该遵循的方式。我正在学习如何在我的工具链中打包deb软件包,因此这很有可能成为我的最终解决方案。 - Eugene Loy
关于最后一个问题:实际上,我正在寻找折衷方案。这个工具很可能每个世纪只更新一次,因此其他开发人员(也许不是我)支持它应该尽可能容易。另一方面,这个工具应该尽可能简单和轻便,因此用户体验也很重要(我可能更喜欢包,但我在野外没有看到许多非开发的Linux用户,这就是为什么我对打包存在疑虑的原因)。 - Eugene Loy

1

还有第三种选择:

创建一个符合您需求的归档文件,并包含所需的.so/.dll文件,具体取决于平台。ZIP归档文件应该适用于Linux和Windows。

然后,在您的Linux安装中使用LD_LIBRARY_PATH在包装器脚本中(它允许您将.so文件放置在某个特殊位置,通常是在libs目录中)。据我所知,Windows使用CWD作为查找二进制文件所需的.dll文件的第一个位置,因此您只需要将它们放置在与二进制文件相同的目录中即可。

使用这种方法,您可以保持您的“分发”小而且不需要静态链接或任何其他特殊处理。

只需确保分析实际的.so/.dll文件的依赖链,以避免在目标环境中加载一些意外的库。


一个适用于Windows的包装批处理文件也可以工作,它需要类似这样的东西:http://pastebin.com/eqfgNUwa - smerlin
嗯,这似乎是一个选项。然而,看起来有点脆弱,仍需要一些努力。我还在犹豫,但我想我会尝试进行静态构建,如果情况变糟,我会回退到这个选项。谢谢。 - Eugene Loy

0

您考虑过使用Qt吗?在那里您根本不会遇到这些问题,而且他们对SSL和HTTP也有强大而易用的支持。


是的,我考虑过这个问题,但它会使应用程序变得更加沉重,而我无法承受。Qt仅为QtCore添加了约50MB,而QtNetwork则不知道添加了多少。更不用说由于其许可政策,我将无法将所有内容静态链接到一个大型可执行文件中。 - Eugene Loy
这不是真的。你可以在一个exe中链接。而且你也不需要部署dlls,包管理器可以为你处理。如果需要,dlls也可以更小。我可以为你提供一些帮助,构建静态qt或构建小型、可用的qt库。 - muma
此外,似乎没有开箱即用的HTTPS支持。至少乍一看是这样。 - Eugene Loy
据我所知,这应该可以与OpenSSL结合使用。 - muma
你考虑过使用Boost库吗?我不确定他们如何支持它,但除了他们之外,我想你没有太多其他选择了。 - muma
显示剩余5条评论

0

所以你问:“有没有更少痛苦的方法。”我喜欢其他答案,特别是Naveen的答案。所以你有两个解决方案:

  1. 使用操作系统中的.so文件(共享库),并建议您的用户使用“至少版本x”。这几乎可以解决所有问题。

  2. 将非共享(静态)库——.a文件——与您的应用程序捆绑在一起,或者将共享库——.so文件——与您的应用程序捆绑在一起。

从源代码使用./configure脚本构建静态.a文件非常简单。您可以轻松获取.so文件,但是您需要相当巧妙才能将它们与您的应用程序捆绑在一起。.so文件可以进行修补;它们内部有路径,说明依赖项应该从哪里加载。因此,捆绑.so文件并不是不可能的,甚至可能是避免为一系列依赖项构建.a文件的手动步骤的便捷方式——如果您找到并使用重定位.so文件的脚本。

你写道:

理论上,我可以尝试手动构建libcurl后面的所有库,但似乎这会使维护变得更加复杂。

是的,因为你想要安全补丁及时更新,对吧?所以最好的方法是第一种——让用户安装他能找到的最新版本,并承担起使系统安全的责任。

当你遇到一个无法使用第一种解决方案的客户需要定制工作时,第二种解决方案就很方便了。在这种情况下,你可以按计划定期发布软件,包括最新的依赖项及其修复程序。小型软件通常会达到一个不再需要更改的点。但如果你的软件没有变化,而你仍然因为依赖项有更新而定期发布,那么这种解决方案并不适用于小型软件。因此,除非客户确实需要,否则不要使用此解决方案。从长远来看,这样做会更加昂贵。

希望这可以帮助你!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接