Clozure CL中文版015:特定于平台的说明
Category:帮助手册特定于平台的说明
概观
在Linux下使用Clozure CL时,您可能拥有的文档和任何经验也适用于在Darwin / MacOS X和FreeBSD下使用它。平台之间存在一些差异,这些差异有时会在实施中暴露出来。
文件系统案例
Darwin和MacOS X默认使用HFS +文件系统; HFS +文件系统通常不区分大小写。大多数Clozure CL的文件系统和路径名代码都假定底层文件系统区分大小写; 这个假设延伸到像EQUAL这样的函数,它假定#p“FOO”和#p“foo”表示不同的,非EQUAL文件名。由于Darwin / MacOS X也可以使用UFS和NFS文件系统,因此相反的假设不会比当前制作的更正确。
无论这个问题的最佳解决方案是什么,都有一些实际的考虑因素。这样做:
? (save-application “DPPCCL”)
在32位DarwinPPC上有一个不幸的副作用,试图在不区分大小写的文件系统上覆盖Darwin Clozure CL内核“dppccl”。
要解决这个问题,Darwin Clozure CL内核要求默认的堆映像文件名是内核自己的文件名,并附加字符串“.image”,因此成语将是:
? (save-application “dppccl.image”)
行终止字符
MacOSX有效支持两种不同的行终止约定。其达尔文基板中的程序遵循Unix惯例,将#\ LineFeed识别为行终止符; 传统的MacOS程序使用#\ Return来达到此目的。许多现代GUI程序试图支持几种不同的行终止约定(理论上用户不应过于关注使用哪种约定,这可能无关紧要。有时这是真的,有时候……没那么多。
Clozure CL遵循Darwin和LinuxPPC上的Unix惯例,但也为读取和编写使用其他约定(包括传统MacOS约定)的文件提供了一些支持。
这种支持(以及类似的东西)本质上是启发式的:它可以在很多时候成功地隐藏新行约定之间的区别,但可能会错误地改变其他正确程序的含义(通常当文件包含#\ Return和#\ Linefeed时)字符或文件包含文本和二进制数据的混合。)由于这种担忧,控制换行转换和解释的一些变量的默认设置有些保守。
虽然多个新行约定的问题主要影响MacOSX用户,但此处描述的功能也可以在LinuxPPC下使用(在那里可能偶尔会有用)。
这些都没有解决与广泛使用的第三个换行符约(“CRLF”)相关的问题(因为该约定不是Clozure CL当前运行的任何平台的原生惯例)。如果将Clozure CL移植到这样的平台,则可能会重新审视该问题。
请注意,某些MacOS程序(包括某些版本的商业MCL)可能使用HFS文件类型信息来识别TEXT和其他文件类型,因此可能无法识别使用Clozure CL或其他Darwin应用程序创建的文件(无论行终止问题如何)。
除非另有说明,否则本文档中提到的符号将从CCL包中导出。
单精度三角函数和超越函数
尽管达尔文的手册页所说,其数学库的早期版本(至少包括OSX 10.2(Jaguar)并未实现超越和trig函数的单精度变体(#_sinf,#_ atanf等)Clozure CL通过将单精度args强制转换为双精度,调用数学库函数的双精度版本,并将结果强制转换为SINGLE-FLOAT来解决这个问题。这些步骤可能会引入舍入错误(以及可能的溢出条件)如果真正的32位变体可用,则可能不存在或严重。
共享库
Darwin / MacOS X区分“共享库”和“捆绑”或“扩展”; Linux和FreeBSD没有。在Darwin中,“共享库”具有文件类型“dylib”:期望在启动可执行文件时由OS创建和加载可执行文件时链接此类文件。后一类 – “捆绑/扩展” – 期望通过类似于Clozure CL的OPEN-SHARED-LIBRARY功能所使用的机制加载到正在运行的应用程序中或从正在运行的应用程序中卸载。
Clozure CL中的可可编程
Cocoa是Apple用于GUI编程的API之一; 对于大多数目的而言,Cocoa的开发速度要快于替代品。你应该对它有一点熟悉,以便更好地理解这一部分。
可以通过评估(REQUIRE’TIIN)然后(CCL :: TINY-SETUP)来调用一个小样本Cocoa程序。该程序提供了一个使用桥梁功能的简单示例。
Tiny演示在运行时动态创建Cocoa对象,这始终是一个选项。但是,对于大型应用程序,使用Apple Interface Builder创建对象通常更方便,并将它们存储在.nib文件中以便在需要时加载。两种方法都可以在一个程序中自由混合。
命令行和窗口系统
Clozure CL通常是一个命令行应用程序(它没有与OSX Window服务器的连接,没有自己的菜单栏或停靠栏图标等)通过打开一些库并跳过一些箍,它能够将自身转换为一个成熟的GUI应用程序(同时保留其原始的基于TTY的监听器。)一般的想法是,这个混合环境可用于测试和原型UI想法,最终的应用程序最终可以完全转换为捆绑式,双击式应用程序。这在某种程度上是可能的,但在许多人发现它之前需要更多的基础设施。
Cocoa应用程序使用NSLog函数将信息/警告/错误消息写入应用程序的标准输出流。当Finder启动时,GUI应用程序的标准输出将转移到可以使用控制台应用程序(位于/Applications/Utilities/Console.app中)进行监视的日志记录工具。在混合环境中,应用程序的标准输出流通常是初始侦听器的标准输出流。由于两个不同的缓冲流机制试图写入相同的底层Unix文件描述符,因此在初始侦听器上看到NSLog输出与lisp输出混合并不罕见。
写(和阅读)Cocoa代码
用于定义Cocoa类和方法的构造的语法已经发生了一些变化(它从未在源代码之外进行过记录,并且根本没有完全记录),这主要是由Randall Beer的桥梁提供的功能的结果; 下面引用的“标准名称映射约定”在他的CocoaBridgeDoc.txt文件中描述,用于调用(“发送消息到”)Cocoa方法的构造也是如此。
下面描述的所有符号目前都是CCL包的内部符号。
objc:@class objc:@selector objc:define-objc-method objc:define-objc-class-method
应用程序工具包和多个线程
Cocoa API分为几个部分。应用程序工具包,亲切地称为AppKit,是处理窗口管理,绘图和处理事件的工具包。AppKit真的希望所有这些事情都由一个“尊贵的线程”来完成。创作,并在一个杰出的线程上绘图。
Apple发布了一些指南,详细讨论了这些问题; 请参阅Apple多线程文档,特别是有关使用多线程应用程序工具包的指南。结果是,在尊重事件线程以外的线程中创建对象时,有时会出现意外行为; 例如,事件线程有时会开始对尚未完全初始化的对象执行操作。
通过在侦听器中键入内容或在Emacs缓冲区中评估“defun”来进行某些类型的探索性编程当然更方便; 这样做有时可能需要了解这个问题。
Cocoa运行时系统中的每个线程都应该维护一个当前的“自动释放池”(NSAutoreleasePool类的一个实例); 新创建的对象通常会添加到当前自动释放池中(通过-autorelease方法),并定期向当前自动释放池发送“-release”消息,这会使其向所有对象发送“-release”消息已添加到它。
如果当前线程没有当前自动释放池,则尝试自动释放任何对象将导致通过NSLog写入严重警告。事件线程维护一个自动释放池(它在每个事件处理后释放当前池并为下一个事件创建一个新的),因此只在该线程中运行的代码不应该引发任何这些看起来很严重的NSLog消息。
为了尝试抑制这些消息(并且仍然参与Cocoa内存管理方案),每个侦听器线程(初始侦听器和通过IDE中的“New Listener”命令创建的任何线程)都被赋予一个默认的自动释放池; 有一些REPL冒号命令用于操作当前监听器的“顶层自动释放池”。
在当前的方案中,每次Cocoa调用lisp代码时,都会建立一个lisp错误处理程序,它将任何lisp条件映射到ObjC异常,并安排在回调lisp返回时引发此异常。每当lisp代码调用Cocoa方法时,它都会使用ObjC异常处理程序; 此处理程序将ObjC异常映射到lisp条件并发出这些条件的信号。
在执行可分辨事件线程的事件循环期间发生的任何未处理的lisp错误或ObjC异常会导致消息为NSLog,并且事件循环为(尝试)继续执行。在最外层的Cocoa方法调用点处理其他线程中发生的任何错误。(请注意,错误不一定在发生错误的动态上下文中“处理”。)
这两种行为都可能得到改善; 它们似乎都比以前的行为有了实质性的改进(例如,拼写错误的消息名称通常会终止应用程序。)
承认
可可桥最初由兰德尔啤酒开发并慷慨捐助。
构建应用程序包
您可能已经注意到(需要“COCOA”)需要很长时间才能加载。可以通过保存已加载所有内容的Lisp堆映像来避免这种情况。有一个示例文件允许您通过生成运行程序的双击应用程序来执行此操作“ccl / examples / cocoa-application.lisp”。首先,加载自己的程序。然后做:
? (require “COCOA-APPLICATION”)
完成后,您应该能够双击ccl目录中的Clozure CL图标,以快速启动您的程序。
操作系统可能已经确定Clozure CL.app不是有效的可执行包,因此不允许您双击它。如果您遇到这种情况,要强制重新考虑,只需更新捆绑包的上次修改时间即可。在终端:
> touch Clozure CL.app
当重新启动包含ObjC类(也是CLOS类)的图像时,这些类被“复活”:所有预先存在的类都破坏性地更新它们的地址,以便维护现有的子类/超类/元类关系。在SAVE-APPLICATION中保留外部实例是不可能的(也可能永远不会)。(可能是NSArchiver和NSCoder以及相关类提供了一些近似值。)
推荐阅读
Mac OS X – Cocoa ,可可核心能力 ,Cocoa基础指南
这些是Apple Mac OS X Developer Library中与Cocoa相关的顶级页面。如果您不熟悉Cocoa,这些链接是很好的起点。
Objective-C编程语言 ,Objective-C运行时编程指南
它们分别为Objective-C提供了语言和运行时的概念性概述和编程指南。
这是两个最重要的Cocoa引用之一; 它涵盖了除GUI编程之外的所有基础知识。这是一个参考,而不是教程。
这是另一个非常重要的Cocoa参考; 它涵盖了使用Cocoa / Application Kit Framework进行GUI编程的深度。这是一个参考,而不是教程。
这是Mac OS X开发人员文档的首页。转到此处查找有关任何其他Mac OS X API的文档。如果您需要有关OS X,Carbon,Cocoa,Core Foundation或Objective-C的一般指导,请转到此处。
这是所有Apple开发人员文档的首页。
操作系统字典
@class class-name[Macro]
班级名称
表示现有类名的字符串,或者可以通过类名的标准名称映射约定映射到此类字符串的符号
用于按名称引用已知的ObjC类。(通过使用LOAD-TIME-VALUE,可以缓存类名 – >类查找的结果。)
objc:@class截至2004年底已经过时了,因为find-class现在适用于ObjC类。这里描述的只是因为一些旧代码仍在使用它。
@selector string[宏]
串
字符串常量,用于规范地引用ObjC方法选择器
用于引用ObjC方法选择器(方法名称)。使用LOAD-TIME-VALUE来缓存字符串 – >选择器查找的结果。
objc:defmethod name-and-result-type ((receiver-arg-and-class) &rest other-args) &body body[Macro]
名称和结果类型
Objective-C消息名称,返回值类型的方法:ID,或包含Objective-C消息名称的列表和具有不同外部结果类型的方法的外部类型说明符。
接收机-ARG-和级
一个两元素列表,其第一个元素是变量名,第二个元素是Objective-C类或元类的Lisp名称。接收方变量名称可以是任何可绑定的lisp变量名称,但SELF可能是合理的选择。接收器变量被声明为“不可设置”; 即,尝试在方法定义的主体中更改接收器的值是错误的。
其他-ARGS
变量名(表示类型的参数:ID)或2元素列表,其第一个元素是变量名,第二个元素是外部类型说明符。
定义Objective-C-callable方法,该方法为现有命名的Objective-C类的实例实现指定的消息选择器。
有关这些功能和限制的详细说明OBJC:DEFMETHOD宏,请参见使用objc:defmethod。
define-objc-method (selector class-name) &body body[Macro]
选择
或者表示选择器名称的字符串,或者描述方法返回类型的列表,选择器组件和参数类型(参见下文。)如果使用第一个表单,则正文中的第一个表单必须是一个列表,根据DEFCALLBACK描述了选择器的参数类型和返回值类型。
班级名称
用于命名现有ObjC类名的字符串,或者是可以通过类名的标准名称映射约定映射到此类字符串的列表符号。(注意“规范”lisp类名称是这样的符号)
定义一个ObjC可调用方法,该方法为现有ObjC类类名的实例实现指定的消息选择器。
define-objc-class-method (selector class-name) &body body[Macro]
根据DEFINE-OBJC-METHOD
像DEFINE-OBJC-METHOD一样,仅用于定义方法 类 由class-name及其子类命名。
对于DEFINE-OBJC-METHOD和DEFINE-OBJC-CLASS-METHOD,“selector”参数可以是一个列表,其第一个元素是方法的返回值类型的外来类型说明符,其后续元素是:
- 非关键字符号,可以根据方法选择器的标准名称映射约定映射到无参数方法的选择器字符串。
- 交替关键字和变量/类型说明符的列表,其中关键字集可以根据方法选择器的标准名称映射约定映射到参数化方法的选择器字符串,并且每个变量/类型说明符都是变量名称(表示类型:ID的值)或CAR是变量名称且其CADR是相应参数的外部类型说明符的列表。
ccl:*alternate-line-terminator*[变量]
此变量目前仅由标准阅读器宏函数用于#\; (单行评论); 该函数读取连续的字符直到EOF,读取#\ NewLine,或者读取* alternate-line-terminator *的值的字符EQL。在Clozure CL for Darwin中,这个变量的值最初是#\ Return; 在Clozure CL中,对于其他操作系统,它最初是NIL。
他们的默认处理由#\; reader宏是#\ Return和#\ Linefeed语法不同的主要方式; 通过扩展#\; 读取器宏(有条件地)处理#\返回作为注释终结符,消除了这种区别。在许多情况下,这似乎使LOAD和COMPILE-FILE对行终止问题不敏感。它可能会失败(希望很少见)LF端接(Unix)文本文件包含嵌入的#\ Return字符,并且这种机制不足以处理换行符嵌入字符串常量或其他标记的情况(并且可能应该从外部约定转换为外部约定):它不会改变READ-CHAR或READ-LINE“see”,
ccl::ns-lisp-string[类]
NS:NS-STRING
:串
一个Lisp字符串,它是新创建的ns-lisp-string的内容。
这个类实现了NSString的接口,这意味着它可以传递给任何需要它的Cocoa或Core Foundation函数。
字符串本身存储在Lisp堆上,这意味着它的内存管理是自动的。但是,ns-lisp-string对象本身是一个外来对象(也就是说,它有一个objc元类),并且驻留在外部堆上。因此,有必要通过发送dealloc消息来明确释放它。
你可以创建一个ns-lisp-string make-instance,就像任何普通的Lisp类一样:
? (defvar *the-string* (make-instance ‘ccl::ns-lisp-string :string “Hello, Cocoa.”))
完成字符串后,必须显式释放它:
? (ccl::send *the-string* ‘dealloc)
您可能希望使用unwind-protect 表单来确保发生这种情况:
(let (*the-string*) (unwind-protect (progn (setq *the-string* (make-instance ‘ccl::ns-lisp-string :string “Hello, Cocoa.”)) (format t “~&The string is ~D characters long.~%” (ccl::send *the-string* ‘length))) (when *the-string* (ccl::send *the-string* ‘dealloc))))
目前,ns-lisp-string在文件ccl / examples / cocoa-backtrace.lisp中定义,这是一个相当尴尬的地方。它本来可能根本不是公用事业。如果把它搬到其他地方就好了。使用风险由您自己承担。
http://mip.i3geek.com