我正在考虑创建一个包含所有开发应用程序和文件的工作站驱动器,并在具有不同 Linux 发行版的许多设备上使用它(即插即用)。那可能吗?
答案1
是的。
然而,有很多警告。如果您的应用程序是用 Perl、Python 或 Posix Shell 脚本等解释语言编写的,那么您所需要做的就是确保您的应用程序依赖的每个模块也与您的应用程序捆绑在一起,并且您不使用假设的构造任何特定的底层平台,即假设小端整数。然后您的应用程序可以在任何具有解释器的平台上运行。如果您的应用程序被编写并编译成字节码,该字节码旨在在像 Java 这样的虚拟机上运行,那么您可以接受与解释语言应用程序相同的约束,假设 java 的一次编写运行在任何地方的承诺没有任何隐藏的陷阱。
另一方面,编译成机器可执行二进制文件的程序要正确地编译要困难得多。它仍然是可行的,但是您必须注意一些陷阱,对于大规模发布,基本上有三种方法可以做到这一点。
假设所有目标都属于同一处理器系列,主要问题可以分为三类:不兼容的内核 API、不兼容或不完整的用户区 ABI 以及新的处理器操作码。第一个很容易理解,Linux 内核经常添加系统调用,如果您的程序尝试在没有该系统调用的旧内核上调用新的系统调用,那么您的程序将无法工作。解决方案是选择任意目标作为基准内核,并确保您的应用程序或依赖项都不使用较新的系统调用。第三类也比较容易理解。处理器系列中较新的处理器将具有旧版本无法解释的操作码。这些较新的操作将出现在 x86_64 平台上,例如 AVX512 SIMD 矢量操作,它们确实可以加速某些计算,但相对较新。解决方案很简单,当您编译程序时,您可以告诉编译器您要专门针对哪个版本的处理器,而您只需针对旧的通用处理器即可。
第二类是事情变得棘手的地方。这是因为默认程序是动态链接的。这意味着生成的二进制文件是不完整的。本身没有足够的信息来创建完整的过程映像,并且中间程序必须解释该文件以在生成过程时基本上完成链接。中间程序是动态链接器,它是系统 C 库的一部分。这导致了一个有点杂乱但很重要的问题,那就是不兼容的 libc / 动态链接器。如果您针对 glibc 构建,那么您的程序可能会使用另一个 libc 运行,但这并不能保证。动态二进制文件将在某处包含运行所依赖的库列表,甚至可能包含有关在开发系统(而非生产系统)上查找这些库的路径信息。这个问题可以通过以下三种方法之一来解决:第一种方法是将应用程序与每个依赖项的副本捆绑在一起的 Microsoft 平台方法。如果您的应用程序包含在非系统目录中,那么您可以使用 POSIX shell 脚本为动态链接器设置必要的路径变量,以查找捆绑的库而不是系统库。有关更多信息,请参阅 ld.so 手册页。第二种解决方案是仅静态链接应用程序。这样您就不必担心动态链接的任何问题。最后,我能想到的解决这个问题的最后一个解决方案是让用户自己构建解决方案,该解决方案只是为了完整性而添加的,实际上并不是一个答案。保留捆绑或静态链接的选项。两者都有优点,但前者击败了动态链接的要点之一,即在内存中拥有库的一个副本,以便应用程序可以从新库中的错误修复中受益。话虽这么说,后者在不同许可证下混合代码时会遇到问题,因此两者都有好有坏。