我有一个旧应用程序,需要旧版 OpenCV(<=2.4.9),但在新版本上会崩溃(OpenCV 自 2.5 版起部分放弃了对 C API 的支持)。我以前只使用非常旧的发行版并将 opencv 更新列入黑名单,但是由于该版本不再受支持 - 我被迫进行更新。openCV 的当前版本是 3.1。
我可以使用容器吗?我只需要一个旧的库。我可以编译旧的 OpenCV,但我有点担心 X 支持 - 它是图形应用程序,显然使用相机。或者也许有更好的解决方案?
答案1
仅仅替换 OpenVZ 的问题在于,许多库互相依赖(旧的“DLL Hell”问题)。一些库依赖于 OpenVZ,而 OpenVZ 又依赖于其他库,而这些库又依赖于更多的库,等等。
根据您需要使用的时间,您可以通过将旧库的“内聚子集”引入目录来避免使用容器,然后使用LD_LIBRARY_PATH
环境变量将动态加载器指向您的旧库。
如果主机系统上的 libstdc++ 和 libc 版本(在 /lib 或 /usr/lib 中)是ABI 兼容使用编译和链接旧版 OpenCV(及其依赖项)时使用的版本。遗憾的是,与 Linux 内核 ABI 不同,libc ABI 偶尔会更改,而 libstdc++ ABI 更改相对频繁。
因此,获取所需版本的旧 OpenCV 二进制文件大致需要遵循以下步骤:
- 尝试只是LD_LIBRARY_PATH 目录中的旧 OpenCV 库。如果不起作用,您将收到有关缺少库的错误(假设依赖项正确进行版本控制);获取那些缺少的库并将它们放在与旧 OpenCV 相同的目录中。重复此操作,直到缺少库的错误消失。
- 如果您遇到 libstdc++ 或 libc 中的符号查找错误,或者收到有关 glibc 版本不佳的投诉,那么您就陷入了困境,而您唯一的解决方案(除了虚拟化和安装旧的操作系统版本)是......
扁平包装
http://flatpak.org/- 包含所有依赖库的应用程序打包格式:)
和
容器
容器是一种很好的方法,因为好的容器解决方案(如 LXC 和 LXD)完全隔离了客户机,甚至让客户机运行自己的PID 1
(init 守护程序)。基本上,要在 Linux 上启动任何进程,某些东西必须在您已经运行的内容和您正在启动的内容之间兼容,因为例如动态加载器(libdl)必须能够加载共享库。但容器有一种完全隔离它的方法,因此您可以在同一个主机内核上使用不兼容版本的 libc、libdl 和 libstdc++。
如果您运行 Ubuntu >= 16.04,我建议您使用 LXD;如果您运行旧的 Debian 或 CentOS/RHEL 主机系统,我建议您使用 OpenVZ。不幸的是,LXD 在非 Ubuntu 发行版上设置起来并不太容易,而 OpenVZ 尚不支持最新的发行版。
Linux 内核的优点在于,除了驱动程序特定的接口(如直接渲染管理器)的少数例外,Linux 内核 ABI稳定的很长一段时间。这意味着:
- 旧的“用户空间”(在内核之上而不是在内核内部运行的所有内容)应该可以在很多较新的内核上运行。
- 新的用户空间应该可以在相当多的旧内核上运行。
实际上,这意味着除非您在容器中使用 3D 图形驱动程序或其他类型的专用硬件,否则它应该“正常工作”,而不管容器系统和主机内核之间的年龄差异有多大(在一定限制内;为早于 2.6.9 的 Linux 内核编译的软件通常无法在现代内核上运行,而早于 2.6.0 的版本肯定无法运行。)
这样就留下了运行旧库(或依赖于旧库的二进制文件)所需的“最少努力”的等级,具体取决于旧库的年龄和深度:
- 最小限度:将旧版本的库放入目录中,设置 LD_LIBRARY_PATH 即可完成。
- 典型(这用于许多专有游戏和程序):删除旧版本的库及其所有依赖项除了libc,设置 LD_LIBRARY_PATH 就完成了。
- 广泛的库替换(有缺陷;可能不起作用):将旧版本的库、libstdc++、libc、libdl 及其所有依赖项放入目录中,设置 LD_LIBRARY_PATH,即可完成。
- 容器:在主机内核上为另一个较旧的操作系统安装完整的基础系统,而无需运行任何虚拟化(您仍然只运行 Linux 内核的一个副本)。快速地,但占用了几GB的磁盘空间。极其与您可以扔给它的任何东西兼容(包括古老的发行版)。
- 虚拟机:可以运行任何东西,甚至非 Linux 操作系统,只要客户操作系统软件与硬件在同一个 CPU 上运行,兼容性就不是问题。