把扩展能力带到更多程序
GNU Guile的早期工作围绕一个实际问题:应用程序的用户怎样改变软件行为,而不必每次都重写底层程序。GNU Emacs已通过Lisp提供这种能力。1994年10月19日,理查德·斯托尔曼在《GNU扩展语言计划》中提出,让GNU程序尽可能共享扩展语言,使使用者学到的知识能够跨程序使用。
公告所谈的选择权也很具体。若一个程序只嵌入某一种解释器,用户便只能用作者选定的语言写扩展。斯托尔曼希望建立共同的执行基础,再在它上面实现不同语言。这份有日期的公开设计,与随后可下载的发行版本属于不同阶段。
参考:[1]
已有解释器与嵌入改造
汤姆·洛德承担了早期嵌入工作的核心部分。他把奥布里·贾弗的SCM解释器改造成能供别的程序链接的库,项目起初称为GNU扩展语言GEL,后来改名Guile。SCM本身又承接乔治·卡雷特的SIOD解释器,形成一条有具体作者的实现谱系。
Guile 1.0的贡献者说明保留了这种分工:洛德负责把SCM库化,并连接Tcl/Tk及正则表达式工具;贾弗贡献性能和解释器内部机制;加里·休斯敦参与Unix系统调用支持。到1.0时,主要维护者为吉姆·布兰迪,马克·加拉西则参与高层接口和手册。
设计目标与实施路线
1994年的计划以修改过的Scheme为基础,列出异常处理、字符串操作、Unix系统调用以及调用C代码的接口,再考虑把其他语言翻译到这个基础上。公告还向熟悉Scheme实现的志愿者征集帮助,并以洛德作为联系者。这是一项组织开发工作的方案,而非宣告所有目标已经完成。
嵌入意味着应用程序仍能保留自己的C代码,同时交给用户一个可解释执行的高层语言环境。早期使用说明要求程序链接libguile.a,并分别介绍初始化、执行字符串或文件、定义可从Scheme调用的C函数。配置规则、交互命令和较复杂的扩展,因此能够与底层实现分开编写。
1995年的发行与模块拆分
维护者温戈后来整理的发布表把guile-i记为1995年2月4日,把guile-ii记为4月6日;后者增加低层模块系统和Tcl/Tk支持。Guile 1.0所附早期用户手册也把guile-ii置于1995年春,把guile-iii置于同年夏季,说明公开计划之后已有连续的开发发行。
guile-iii发行包的公告强调,先前集中在一起的功能开始拆成附加包。用户可将Tcl/Tk相关包放进同一源代码树,再按configure、make的过程构建所需组合。这种组织方式回应了两类需求:一些人要较小的解释器,另一些人需要图形工具等较多功能。
一个C与Scheme互相调用的例子
1997年Guile 1.0发行包的gh_test_c.c给出了具体演示。C程序通过gh_enter启动解释器,再用gh_eval_str交入Scheme代码;其中先定义平方函数,随后求square 9。按这段定义,运算所得为81。程序并不另造一套表达式解析器,而是把表达式交给已有语言环境。
另一个方向则由c_sin函数展示:它将Scheme数值转成C的double,调用数学库的sin,再把结果转回Scheme对象。程序用gh_new_procedure1_0把它登记为名为c_sin的单参数过程。如此,用户写Scheme扩展时就能使用应用程序提供的C功能;调用两端各自负责数据转换和实际计算。
参考:[3]
整合、取舍与后续分流
Guile 1.0的README称它是自由软件基金会制作的第一个Guile发行版,同时明确承认Cygnus Support已有更早的版本。因此“1.0”所标记的是一轮维护与整合,不是此前工作从未公开。其NEWS还记录将假值与空表重新分开等调整,显示最初为兼容其他Lisp而作的选择会在使用中修订。
Kawa项目的参与者回顾,Cygnus在1995年接到增强Guile的合同,线程等工作也由不同开发者承担;后来客户同意转向基于Java的实现路线,Kawa于1996年继续发展。Guile与这条分流并行延续,其早期历史由公告、发行包和维护交接共同构成。