在接受Scott Hanselman 的专访时,来自Novell 的 Aaron Bockover 谈到了创建 Banshee 所遇到的挑战。Banshee 是个跨平台应用,在 Mono 上采用 C#构建,其目标平台是 Linux、Max OS X 及 Windows。
Banshee 由 Aaron 在 2005 年创建,其目标是为 Linux 平台创建一个媒体播放器。由于构建在 Mono 之上,因此它最终成为了一个跨平台应用,可以运行在 Linux 及 Mac OS X(从 1.4 版开始)上,同时在今年的夏末秋初之际它将能够运行在 Windows 上。现在 Banshee 已经能构建并运行在 Windows 之上了,但在发布前还有一些修复工作要做。
创建 Banshee 的目的之一在于展示在 Mono 上构建应用的优势。该项目创建之时正赶上 Mono 的萌芽时期,那时没几个人相信它能成功。其他类似的应用还有 F-Spot(一个照片管理应用)及 Tomboy(一个记事本应用)。
Banshee 因构建于 Mono 之上而受益无穷,不仅如此,Mono 本身也在该媒体播放器的开发过程中对自身进行不断的改进,这也巩固了 Mono,因此可以说这是一个双赢的结果。一个佐证就是在 Mono 的 C#编译器增加了泛型功能后,Banshee 是首个利用该特性的项目,同时在这个过程中一些 bug 也被揪出并得以修复。
Mono 的编译器、垃圾收集器及 JIT 并非简单的将.NET 代码移植到 Linux 上那么简单,而是根据规范重写了所有代码。其.NET 程序库也是根据微软的文档基于公开 API 写成的。这么做的结果就是生成的 MSIL 字节码可以运行在任何平台上:Windows、Linux 及 Max OS。其与.NET 平台的兼容性已经达到了无懈可击的地步了:.NET 框架中的任何 bug 都会反映到 Mono 中以保证运行在不同平台上的应用都会执行同样的代码路径。这种跨平台的方式遇到了很多困难,首当其冲的就是文件访问。当在 Mono 中编写代码时,开发者并不会意识到应用将使用何种文件系统,POSIX 还是 FAT,抑或是 NTFS。Mono 对 System.IO 库有多种实现,为的就是在各种不同的文件系统上都能正常工作。
举个例子吧,看看 System.IO.Directory.GetFiles() 实现,该方法会返回一个数组。调用者需要等到方法构建好数组并返回后才能继续执行下面的代码,而一旦目录中含有大量文件时这么做的效率就很低下了。为了解决这个问题,开发者可以使用 Mono.Posix 程序库来探测目录中的文件,该方法会返回一个 IEnumerable,这速度可快多了。
Banshee 使用了一个 IO 抽象层(默认映射到 System.IO)来实现跨平台的目的,然而一旦应用检测到了 POSIX 系统,它就会使用 Mono.Posix 程序库,因为其性能更好。
有两种抽象层:硬件抽象层及平台抽象层,前者的必要性显而易见,而后者的目的是充分利用平台所提供的最佳特性。比如说 GNOME 抽象层,它能禁用掉妨碍应用的屏幕保护程序,该抽象层构建在桌面环境所提供的特性之上。对于那些没有实现某些必备特性的平台来说,Mono 通过扩展库的方式进行了实现,每个平台一个扩展库。.NET 开发者可以使用这些继承了 Mono.Addins 的 Mono 程序库在 Visual Studio 中进行开发而无需在 Mono 上运行代码, 因为这些库是插件, 可以独立运行。
像 Banshee 这样的 Mono 应用可以在构建期检测其所运行的平台。构建程序会根据应用的目标运行平台创建核心组件和必要的插件。在 Windows 上,所有必要的信息都保存在解决方案文件中,该文件可以用 Visual Studio 打开,同时会在构建期加入所有必要的 DLL。Linux 的构建过程与 Windows 也没什么差异。Linux 是在 Linux 机器上完成构建的,而 Windows 是在 Windows PC 上完成的。我们还可以在运行期检测平台,不过只在某些特定的情况下才这么做,并不推荐。
查看英文原文: Cross-platform Development – Lessons Learned from Banshee/Mono
评论