预览模式: 普通 | 列表

REALbasic内幕:插件与程序编译

跨平台开发环境REALbasic内幕:插件与程序编译


1、REALbasic插件格式
    REALbasic的插件并非是对IDE功能的扩展,它实际上是对REALbasic框架包的功能扩展。REALbasic的框架包的主要部分本身就是一组RBX格式的插件,它们可以在Resources目录下的Internal Plugins文件夹中找到(Mac OS X版中,Resources目录在应用程序Bundle内部,需要先在Finder中对应用程序Bundle使用“显示包内容”命令)。框架包的另一部分在Resources目录下的Frameworks文件夹中,稍后再介绍,我们先说说插件文件。
    RBX文件是由一组或几组动态库/共享库文件和一些要在IDE中使用的资源打包而成的。其中的每一组动态库通常至少包含一个用于Win32的dll文件,一个用于Mac的UB(通用二进制)格式的dylib或bundle文件,和一个用于Linux x86的so共享库文件。其中UB格式的库能用来为Intel、PowerPC和UB三种目标编译应用程序。但是对于UB格式(也就是既含有Intel CPU指令,又含有PowerPC CPU指令的Mac程序)的支持是从REALbasic 2006第四版开始的,因此许多第三方的插件还提供一个仅用于PowerPC CPU的dylib文件来支持较旧的REALbasic。
    除了PE格式的dll,MachO格式的dylib/bundle,和ELF格式的so之外,有些第三方插件还提供一个PEF格式的库以支持Mac OS 9及以前的操作系统。不过也是在2006年,REALbasic不再提供对Mac OS 9及以前的Mac OS的支持,也不再支持为Mac OS X生成PEF格式的应用程序,因而现有的大部分第三方插件都只含有针对MachO格式的Mac可执行文件的库。
    插件中每一组动态库/共享库文件提供基本相同的功能,有几乎一致的接口,具体功能的实现则因系统系统而异。
    除了这些库文件之外,插件中还有一些其它资源,比如要在REALbasic IDE的控件列表中显示的图标(当然,只有插件提供的是继承自Control类的控件才需要)、要在语言参考窗口中显示的帮助信息,等等。
    所有这些文件是用REALbasic的虚拟宗卷格式封装在一起的。即使您不使用专门处理插件的工具,只要用REALbasic自带的VirtualVolume类编写少量代码,就能一窥RBX文件中的究竟。

2、插件的载入
    REALbasic IDE和REALbasic程序都会在启动时载入所需的插件,载入它们的目的却不同。IDE载入插件是为了读取其中的接口信息,以便给出语法提示和在编译时进行语法检查。用REALbasic开发的程序载入它们,则是为了确保这些库中含有所有运行时所需的例程,并获得函数指针以便在需要时能立即调用和执行这些例程的已映射到内存中的CPU指令代码。
    对于不同平台,应用程序载入插件的方法也有差异。比如,对于Mac OS X的MachO程序格式而言。由于MachO可执行文件本身和其它Unix/Linux可执行文件格式类似,是个没有图标没有扩展名,可以从控制台直接调用的实用程序(utility)。Apple出于多种目的——比如为了让它看上去好看些,为了易于本地化和国际化等等——将文本、界面描述、图标、图形图像和其它一些资源与可执行文件本身保存在一个目录结构中。并使这个目录结构在默认情况下显示为单一的程序文件。因此您的工程中所使用的插件里面的MachO格式的共享库,在生成MachO程序时,会被放到这个目录结构中,保存在Frameworks子文件夹下面。这样Mac OS X的加载器(loader)会自动将这些共享库加载到内存中(通常dylib必须在启动时加载,而bundle可以随需加载并且支持在不需要时卸载)。
    在REALbasic 2008第一版以后,Windows上的情况也基本是这样。所需的插件中的用于Windows平台的dll,在程序编译后会被写出并保存在程序所在目录下的“<程序名>  Libs”文件夹中。它们必须与主程序一同安装,且该自文件夹的名称不应被更改。在程序启动时会要求Windows的映像加载器来载入这些动态链接库。
    在REALbasic 2007及以前的版本中,这些dll是作为资源写入Windows程序中的,然后REALbasic程序会调用系统API(应该是LoadLibrary和LoadModule之类的Win32 API)来载入这些dll或其中的例程,也就是自己实现一个简单的载入器。但是这对某些插件在一些特定情况下会产生问题,微软技术支持中心应一些用户的要求曾与数名Windows系统内核和载入器方面的专家花了数个小时跟踪调试,以研究问题的原因,其结论是由于各种原因这些API函数在行为上与系统的映像加载器有些微妙的差异,因此建议REALbasic将这些dll外部化,以便使用系统本身的加载器来加载它们。在运行时再将这些dll写出到临时文件夹也是一种办法,不过考虑到会被一些比较敏感的杀毒软件拦截,因此否决了这个方案。这就是在2008第一版开始,这些dll不再被内置的原因。
    至于Linux,目前没有太多资料,但观察,以前似乎也是将so共享库文件写入到可执行文件本体中,然后调用什么系统功能来载入它们的。不过最新的REALbasic Linux版编译的程序会在启动时将这些so文件写出到一个隐藏的临时文件夹中。这个行为改变在Ubuntu等Linux发行版上没有产生什么问题。但笔者曾遇到过CentOS 5的SELinux阻止了REALbasic 2008第四版所编译的程序,不让它继续运行的问题,在对SELinux进行设置一些后基本予以解决。

3、REALbasic的编译器与RBScript
    既然REALbasic的IDE是用REALbasic语言写的,而用REALbasic语言为自己写编译器似乎不是个好主意,因此RB的编译器是用C/C++(据笔者所知,还有一些Pascal)写成的。C++代码要与REALbasic程序一起工作当然要制作成插件。因此REALbasic的编译器也是个插件。
    这个被称为Spawn Compiler的插件是不公开的,不过其中的部分动态链接库/共享库还是能被找到的。比如在REALbasic 2008及更高版本中,您可以在“REALbasic 200X Libs”文件夹中找到一个名为“Spawn Compiler.dll”的文件。这就是Windows版的编译器。如果将这个文件复制到Plugins文件夹中,并重启REALbasic的IDE,随后尝试输入一些代码,您会看到IDE的关键字自动完成列表会暴露出一些Spawn Compiler的插件中的类和函数的接口。不过这个插件貌似非常复杂,没有文档还真没办法用。
    但是有一个简化定制版的REALbasic编译器是公开的,这就是REALbasic自带的RBScript类(对应于Internal Plugins文件夹中RBScript.rbx文件)。RBScript能在内存中编译REALbasic脚本,并将编译好的CPU指令直接映射到当前的进程空间中执行,并返回执行结果。
    这使得在用REALbasic编写的程序中可以实时编译执行REALbasic代码。REALbasic IDE脚本功能就是使用RBScript使得自动化控制IDE以及自动化实现复杂的编译构建过程成为可能。除此之外,Inspiring Applications公司制作的网页开发工具YUMA也依赖于它。YUMA的主要原理是使用一个用REALbasic编写的后台服务程序从网页中解析出内嵌的REALbasic代码,然后调用RBScript来编译并执行这些代码,再用返回结果生成需要传回给用户的动态页面。除了所支持的是REALbasic语言的一个子集之外,它与PHP、ASP等没有本质上的区别,并且YUMA的企业版也能与Apache等一同使用。与PHP等相比的主要优点在于,网页内嵌的脚本是编译执行,而不是解释执行的。据称,在同等条件下,平均运算速度为PHP的2倍,JavaScript的4倍左右。

4、REALbasic程序的编译
    从广义上说编译包括两大步骤:
    第一步是将高级语言代码编译成原生的CPU指令(即机器码)。执行这一任务的模块即狭义上的编译器(compiler),或称编译器前端。有时也会有专门用来处理资源的资源编译器,本文不对它进行讨论。既然REALbasic的编译器插件叫做Spawn Compiler,可想而知,生成CPU指令是其主要功能。由于CPU指令不受操作系统影响——也就是说不论是Windows、Intel Mac还是Linux x86,处于相同状况下的RB代码“a=1+2”,理论上可以编译为一组完全相同的CPU指令——因此REALbasic的编译器只要能将REALbasic代码为x86和PowerPC系列CPU编译成两类不同的机器码就可以了。
    第二步是将编译好的CPU指令、各种资源按照操作系统支持的文件格式组合成应用程序文件。执行这一任务的模块就是连接器(Linker),或称编译器后端。MachO格式的Mac程序将资源保存在外部,因此连接工作相对比较简单,在Windows和Linux上则比较复杂。实际上REALbasic并没有Windows和Linux版的连接器,其连接工作依赖于Resources目录下的Frameworks文件夹中的一组文件。
    在Frameworks文件夹中,App Resources Carbon、HXRuntime Carbon Mach-O、HXRuntime Mach-O Console等文件是生成有图形界面(桌面的)或无图形界面(控制台的或后台服务的)Mac程序时所需的资源文件和一些预先编译好的功能。它们相当于静态库,其中的资源或功能是大多数程序都需要的,这也包括初始化程序和载入及处理插件等所需的代码。因此由REALbasic直接提供而无需另外编写或另外附带插件。在编译Mac程序时,它们将与主程序连接在一起。
    而X86RunHoudini.exe、X86HoudiniConsole.exe等文件则是一些预编译连接好的空壳程序文件,可以称之为占位文件。它们基本上是用C/C++写成的,必要的资源或功能也已经连接到其中。REALbasic在为Windows/Linux程序编译好CPU指令后,对这些占位文件进行修改,将CPU指令和各种资源填入到占位文件的代码段和数据段中,最终生成您的Windows/Linux程序。
    因此不必怀疑REALbasic生成的Windows/Linux程序不是编译执行的。可以说,是不是编译执行,主要看得看编译过程的第一大部生成的是不是机器码。对于REALbasic程序来说,不论是里面那些由预编译好的占位文件所提供的、用C++编写的部分,还是后插入的、用REALbasic编写并编译出来的部分,都是原生的CPU指令,都会直接送给CPU去执行,而不是先送给解释器去解释为CPU指令,再由CPU执行。因为REALbasic生成的是编译执行的程序,这一点是毋容置疑的。

查看更多...

Tags: REALbasic

分类:编程开发 | 固定链接 | 评论: 0 | 引用: -3 | 查看次数: 8331