如果您想让人们运行您的二进制程序,那么尝试让他们不要使用针对特定操作系统的系统调用;最好使用标准的 POSIX 系统调用。这是软件开发的一个良好的习惯做法。
基于内核的模拟器可以捕捉到到达它的系统调用。用户空间模拟器,比如 lxrun,会等待应用程序尝试进行系统调用。由于 Linux 系统调用功能与 Solaris 或 SCO UNIX 上的系统调用功能不同,所以结果是发生一个代码段错误。然后,lxrun 程序像一个调试器那样纠正这个错误并使系统调用继续运行 —— 但是,实际上,它已经截取了这个系统调用,并向底层操作系统进行相应的系统调用,而且解决了所有问题。聪明!
文件系统结构
文件系统的问题通常更为微妙。访问文件系统极其简单。不简单的是如何找到您想要的文件。
如果您的程序在模拟环境中运行,那么要访问的文件系统可能与您开发程序时使用的文件系统有本质上的不同。例如,如果您的程序使用了 /proc 文件系统(常用来获得内核状态和信息),那么在较新的内核中常见的特性在较老的系统中可能并不存在。
这里的开发人员比专有系统上的开发人员拥有巨大的优势,因为不同的 Linux 发行版本以不同方式安排文件,所以大部分程序员都非常清楚如何避免过分依赖于文件系统设计。但是 —— 有时 —— 不得不将文件名嵌入到程序之中。
许多模拟器解决这个难题所采取的一个方案是:建立一个针对文件系统调用的额外的解释层。例如,在 NetBSD 的 Linux 模拟环境代码中,首先根据 /emul/linux 中的文件检查对文件的访问,之后才对系统真正的 root 目录中的文件进行检查。这就使得当 Linux 二进制程序不能使用标准文件时,系统可以提供“覆盖(override)”系统文件的文件。
实际上,这一方法的主要用途在于程序库和其他支持文件,不过也同样提供了许多系统二进制程序。例如,如果 Linux 二进制程序尝试调用 uname 来得到内核版本,却得到了 NetBSD 的版本号,这将非常令人迷惑。取而代之,它应得到所预期的 Linux 版本号。
共享程序库
如前所述,共享程序库是能够被模拟的二进制程序找到却不能够被系统二进制程序找到的一个非常好的例子。由于在不同的系统上共享程序库的格式和 ABI 细节可能各异,所以不能随意假定所有的系统都可以共享某个给定的程序库。名称可能冲突 —— 例如,当前 NetBSD 和 SUSE 7.3 都拥有一个名为 libncurses.so.5 的文件。重要的是要使用其中正确的那一个。