REALbasic内幕:插件与程序编译
作者:kmzs 日期:2008-12-07
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生成的是编译执行的程序,这一点是毋容置疑的。
没有被点名
作者:kmzs 日期:2008-11-20
有人不高兴点了,说可以随便玩。因为有N年没被人点过了,就自虐一下。
规则如下:
First, 被点到名字的要在自己日志里写下自己的答案,然后去掉一个问题,再加上一个问题,仍然组成20个问题,传给其他10个人,列出10个需要回答问题的人的名字,还要到10个人的校内里留言通知对方-你被点名了,被点名者不得拒绝回答问题,完成游戏的人将会永远得到大家的祝福。
Second, 这10个人要在自己的日志里注明是从哪里接到题的,并且再想一个题目传给其他10个人,让游戏继续下去,不得回传。被点到名字的人将得到大家的祝福,并且所有的美丽愿望都会在不久的以后实现,这是博客里流行的击鼓传花传给谁谁就得接着,否则就得挨罚,请认真对待,不要怕暴露隐私。
1,最郁闷的时候怎样度过?
数钱,擦贵金属器物。
2,遇到一个你爱的人和一个爱你的人你如何选择?
可以两个都要不?(爱做广义理解啦)
3,你最想去哪个地方?为什么?
我爱的人在的地方。(爱做广义理解啦...其实我就愿意宅在家)
4,你会同时喜欢上两个人吗?
如果“爱”必须狭义理解的话:不会,肯定,爱一个就够受了!
5,你觉得怎样的人值得相信,愿意为他付出一辈子?
我不会为任何男人(“他”)付出一辈子,女人的话,会相信投缘的,考虑付出半辈子。。。
6,你对自己现在的生活满意吗?
基本满意,不满意就改变它。
7,你最想要的生活是什么样的?
自由自在,无拘无束,随心所欲,恣意妄为
8,你觉得自己虚伪吗?
我很直爽的(虽然开玩笑的时候爱拐弯)
9,如果距离远了 你还会那么爱他/她吗?
继续柏拉图式恋情+自己YY应该不是问题
10,在事业和家庭中做个选择,你选择前者还是后者?
不知道啊,我只是想干啥就干些啥而已
11,到现在为止,你最大的遗憾是什么?
我很遗憾能见到这么多无聊的问题。
没有其他遗憾。
12,最近最快乐的事情是什么?
好像能开出工资了。。。
13,如果你爱的人不爱你你会怎么办?
回家继续宅着(是好女孩的话就追到底。。。)
14,如果你与你爱的人走散了,你会找他还是在原地等他?
在马路上抓狂(我怎么又忘带手机和小灵通了!)
15,到现在为止,最近听起来最有感觉的是哪首歌?
最近没空听。。。
16,你理想的结婚年龄是多大?
65以后吧,退休了闲着没事做可以结婚玩。似乎我对仪式和人堆都不感冒。。。
17,你现在最想做的事情是什么?
将工作列表上的事情减少到一件——为啥老妈没给我生个多进程的脑袋?
18,如果阿拉丁神灯可以实现你一个愿望,你希望是什么?
我的一个愿望是:请阿拉丁神灯同意为我实现one more愿望,然后继续循环,直到他说“我同意”说道无聊至极地自己钻回灯里(啊神灯再见,天下太平了!)
19,你是否知道父母的生日?
老妈的当然啦。。。男人之间要干脆,记得生日这种事情会被不屑的。。。
20,你做过最疯狂的事情是什么?
有好多啊。。。正想尝试更疯狂的呢。。。
既然神灯的灯神已经被我虐待地保证不再出来混了,还是把第18个换成:假如您和我一样是旱鸭子,某日溺水了,正在半死不活之际,恍恍悠悠见到一漂亮的龙女,您觉得她会干啥啊?(估计会把我变成只中华大蟾蜍也说不定。。。)
备忘录2
作者:kmzs 日期:2008-11-20
HUMAN
最近见到的人:Nick
会见到的人:初中同学?聚会还是...算了吧。最近正懒着呢。
会离开的人:n/a
喜欢的人:我喜欢人吗?
--------------
READING
正在读的图书资料:
技术类:《Flex与ActionScript编程》(王睿,机械工业出版社)、《Real OOP with REALbasic》Guyren G Howe著
非技术类:《以色列史》(张倩红,人民出版社)
杂志(技术类):看光了
邮件列表:暂时没空翻
准备读的图书资料:
技术类:《精通正则表达式》(机械工业出版社)
非技术类:《阿拉伯帝国》(三秦出版社)
原计划完成情况:
1、《Cocoa入门——使用Objective-C》未完成、未开始
2、《Interface Builder User Guide》未完成、未开始
3、《德川家康(第10、11部)》未完成、未开始
4、《俄国史》超额完成,还附带看了本更厚重的东欧史专家刘祖熙的《波兰通史》(商务印书馆)
另灭掉《次贷危机》(中国经济出版社)一本,《程序员》9、10、11月号各一本。
--------------
WORK
与上次的“光看书来的,最近消极怠工”相反,最近2个月光干活+睡觉了。
--------------
CONSUMPTION/INVESTMENT
每年10-11月都是花钱很冲的日子,最近似乎用掉了4K。。。不算什么,换成AU99的话还没一盎司呢。。。
备忘录
作者:kmzs 日期:2008-08-11
HUMAN
最近见到的人:小陨、小垒;老朱;程喆
最近会见到的人:Nick;小夔;可能还有Doug?
会离开的人:
小陨(美国,读本,UVa?)
小暐(美国,读研,普渡)
老朱(美国,读博,哈佛)
小夔(读研,南大)
会来的人:
可能是我PP、口爱的表妹之一?
会呆在哪儿:我希望是继续宅在家
--------------
READING
正在读的图书资料:
技术类:《AppleScript Studio Terminology Reference》(Apple, Inc.,Apple, Inc.)
非技术类:《意大利简史》(路易吉·萨尔瓦托雷利,商务印书馆)
杂志(技术类):《程序员(8月号)》
邮件列表:REALbasic (REAL Software, Inc.)、AppleScript Studio (Apple, Inc.)等
准备读的图书资料:
技术类:
1)《Cocoa入门——使用Objective-C》(James Davidson & Apple, Inc,O'REILLY & 中国电力出版社)
2) 《Interface Builder User Guide》(Apple, Inc.,Apple, Inc.)
非技术类:
1)《德川家康(第10、11部)》(山冈庄八,南海出版社)
2)《俄国史》(张建华,人民出版社)
--------------
WORK
光看书来的,最近消极怠工(下月的米怎么办...)。
翻译之误(断章)
作者:kmzs 日期:2008-08-11
我发现一些日文中的汉语词汇被翻译成中文时经常会出现意译不完全的状况,也就是一个句子或词组中的汉语词汇被办意译半直译,得到一个“Jinese”的结果。