Guile is the GNU Extension Language (I'm not really sure if GUILE is an acronym for anything). It started out as an embeddable scheme interpreter, and has rapidly evolved into a kitchen-sink package including an embeddable scheme interpreter, several graphics options, at least two other languages that can be used along with scheme (Tcl and ctax), a formalism for applets, and hooks for much more.
A scripting language is a programming language which serves as glue between other system programs. In the UNIX world, the traditional scripting language is the Bourne shell, which allows many UNIX commands to be executed in sequence, or in pipelines. Traditional UNIX commands are cleverly written to work well when put together in a script.
Other examples of UNIX scripting languages are AWK, Perl, Scsh (the Scheme Shell: a scheme interpreter enhanced to do good scripting), Python, Tcl, Java @dots{}
UNIX programmers noticed more than 25 years ago that scripting languages can do serious work, so the Bourne shell was written to have variables, operators and control structures just like a full-featured programming language.
What scripting languages have, that traditional programming languages do not, is the ability to run an external program (or a pipeline of external programs) and use the returned values and output from that program in useful ways.
An extension language is a programming language interpreter offered by an applications program, so that users can write macros or even full-fledged programs to extend the original application. Embeddable languages have a C interface (it is usually C, but it could be any other compiled language), and can be given access to the C data structures. Likewise, there are C routines to access the extension language data structures.
Extension languages abound in the software world, even though the name extension language is seldom used. Examples are
One lesson we can learn from looking at classical large software applications is that "writers of large programs" always end up throwing in some kind of parser for configurations or scripting.
Of the examples listed above, Emacs lisp, Tcl, Libscheme and Guile have an important property: they are not added as an afterthought for a specific application. They are general-purpose languages which a user can learn (even in college courses) and then use to customize the application program.
This is a new and (in my opinion) very exciting direction in large-program software engineering: program designers can link to the Guile or Tcl library from the very beginning, and tell their users "You want to customize this program? Just use Scheme (or Tcl, or whatever language), which you already know!"
A few separate threads of events lead to the development of Guile.
In the fall of 1994 Richard Stallman, director of the GNU project, posted an article with the subject "Why you should not use Tcl", in which he argued that Tcl is inadequate as an extension language. This generated a flurry of flames (available in the hypermail archive The Tcl War).
The result was that Stallman then proposed his design for the GNU Extension Language, first called GEL and then renamed Guile. The discussion triggered by that article is also available in a hypermail archive.
One interesting feature of this GNU Extension Language plan was that users should have a choice of languages to use in extending their program. The basic language would be a slightly modified scheme, and translators would be written to convert other languages (like Tcl, Python, C-like languages @dots{}) into scheme.
Tom Lord started working on this project immediately, taking Aubrey Jaffer's small and portable implementation of scheme, SCM, and making it into an embeddable interpreter: callable from C and allowing new scheme procedures to be written in C.
In the spring of 1995, the guile-ii snapshot was released. This made it possible to start writing code in C and Scheme using the guile facilities.
The guile-iii snapshot was released the summer of 1995, and it had fixed enough problems so that the access to scheme data structures from C was almost complete.
Today (March 1996) a new snapshot guile-r0
is available
internally to cygnus; it is not yet clear when the general public will
get it, because there is still a problem coordinating the FSF release of
Guile and the Cygnus extensions.
The guile-r0
release also includes a method for programming and
executing applets, similar to Java applets but written in scheme
and/or Tcl. There is at least one World Wide Web browser
(SurfIt!) which will run these applets.
The latest guile snapshot, guile-r0, can be obtained by anonymous ftp from
ftp://ftp.cygnus.com/pub/not-yet-known/guile-r0.tar.gz
You can unbundle and compile it with
gzcat guile-r0.tar.gz | tar xvf - ./configure --prefix=your-prefix-path make make install
You can read the `INSTALL' document if any of these steps fail, or if you are curious.
Once you have installed guile, you will have some binaries, C libraries, scheme libraries, Tcl/Tk libraries in your directory tree. What should you do now?
You could start by running the actual guile program. In a most basic sense, guile is a souped-up version of Aubrey Jaffer's scheme interpreter SCM.
If the binary directory into which you installed guile is in your path,
you should be able to just type guile
. Here is an example
session:
<shell-prompt> guile ;;; loading modops... ;;; ...loaded /packages/lib/gls/bootstrapping/modops. ;;; loading libguile... ;;; ...loaded /packages/lib/gls/bootstrapping/libguile. ;;; loading slibhooks... ;;; ...loaded /packages/lib/gls/bootstrapping/slibhooks. ;;; loading require... ;;; loading slibcat... ;;; ...loaded /packages/lib/gls/bootstrapping/slibcat. ;;; ...loaded /packages/lib/gls/bootstrapping/require. ;;; loading mule... ;;; ...loaded /packages/lib/gls/bootstrapping/mule. guile> (+ 20 35) 55 ;Evaluation took 0 mSec (0 in scm_gc) 65 cells work, 44 bytes other guile> (define (recursive-factorial n) (if (= n 0) 1 (* n (recursive-factorial (- n 1))))) recursive-factorial ;Evaluation took 0 mSec (0 in scm_gc) 191 cells work, 87 bytes other guile> (recursive-factorial 5) 120 ;Evaluation took 0 mSec (0 in scm_gc) 229 cells work, 42 bytes other guile> (recursive-factorial 500) 1220136825991110068701238785423046926253574342803192842192413588 3858453731538819976054964475022032818630136164771482035841633787 2207817720048078520515932928547790757193933060377296085908627042 9174547882424912726344305670173270769461062802310452644218878789 4657547771498634943677810376442740338273653974713864778784954384 8959553753799042324106127132698432774571554630997720278101456108 1188373709531016356324432987029563896628911658974769572087926928 8712817800702651745077684107196243903943225364226052349458501299 1857150124870696156814162535905669342381300885624924689156412677 5654481886506593847951775360894005745238940335798476363944905313 0623237490664450488246650759467358620746379251842004593696929810 2226397195259719094521782333175693458150855233282076282002340262 6907898342451712006207714640979456116127629145951237229913340169 5523638509428855920187274337951730145863575708283557801587354327 6888868012039988238470215146760544540766353598417443048012893831 3896881639487469658817504506926365338175055478128640000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000 ;Evaluation took 140 mSec (30 in scm_gc) 2042 cells work, 110102 bytes other guile> (quit) ;;; QUIT executed, repl exiting ;Evaluation took 0 mSec (0 in scm_gc) 55 cells work, 40 bytes other <shell-prompt>
In this last example we did some simple arithmetic (+ 20 35)
and
got the answer 55
. Then we defined the classic (and rather
wasteful) factorial function, and got a glimpse of scheme's nice
bignumbers by asking for the factorial of 1000. Then we quit
with (quit)
.
Here are some small programs that use the Tk toolkit to do graphics. More is said about this in section More on the Guile interface to Tk.
Start with a trivial program that brings up a button that destroys itself when clicked:
#!/packages/bin/guile - ; -*-scheme-*- ;; a first learning program for STk, by Mark Galassi (require 'Gwish) (use-library tcl) (use-interface tcl) (use-interface tclhack) (define (quit-callback) (begin (display "quitting now\n") (destroy "."))) ;;(button '.quit :text "quit" :command 'quit-callback) (button '.quit :text "quit" :command (tcl-lambda() (quit-callback))) (pack .quit) (tk-main-loop) (quit)
Notice that in this one-button program, the quit-callback
procedure could have been put on the creation line for that widget:
(button '.quit :text "quit" :command (tcl-lambda() (begin (display "quitting now\n") (destroy "."))))
Now a slightly more intricate use of widgets:
#!/packages/bin/guile - ; -*-scheme-*- (require 'Gwish) (use-library tcl) (use-interface tcl) (use-interface tclhack) ;; create the menubutton, and when the user clicks, invoke the menu .mb.m (menubutton '.mb :text "sample menu" :menu ".mb.m") (pack '.mb) ;; create the actual drop-down menu (menu '.mb.m) (.mb.m 'add 'command :label "Open") (.mb.m 'add 'command :label "Close") (.mb.m 'add 'separator) (.mb.m 'add 'command :label "Exit" :command (tcl-lambda() (destroy "."))) (tk-main-loop) (quit)
Notice that the Exit
menu option will actually work.
The next example shows how to read the mouse in Tk.
#!/packages/bin/guile - ; -*-scheme-*- (require 'Gwish) (use-library tcl) (use-interface tcl) (use-interface tclhack) (canvas '.c) (pack .c :fill "both" :expand "yes") (bind .c "<B1-Motion>" (tcl-lambda ("%x %y" (number x) (number y)) (.c 'create 'rectangle x y x y :width 5))) (tk-main-loop)
More advanced and interesting examples of all these uses of Guile are given in other chapters; the last example I want to show you here involves World Wide Web browsers and applets written in scheme.
You might have noticed that one of the programs created when you
installed scheme is called SurfIt! (invoked by surfit
,
without the !
). SurfIt! is a full-featured (although in early
release) WWW brouser developed by Steve Ball at Australian National
University. It is capable of executing applets written in Tcl,
much like Sun's Hot Java broser and Netscape Navigator can
execute applets written in Java.
The version of SurfIt! shipped with Guile has been extended to allow execution of Guile applets. To see a simple example, do three things:
;; a simple applet that pops up a button (require 'Gwish) (use-library tcl) (use-interface tcl) (use-interface tclhack) (require 'applet) (display "entering learn-applet-0\n") ; just some crap (toplevel '.top-0) ; work from a new top level ;; a callback for the button we create (define (quit-0-callback) (begin (display "quitting now\n") (destroy ".top-0"))) ; A callback for when the user terminates the applet (define-applet-terminate (quit-0-callback)) ;; OK: now make the button and register its callback (button '.top-0.quit-0 :text "quit" :command (tcl-lambda() (quit-0-callback))) (pack .top-0.quit-0) (tk-main-loop) (quit)
<html> <head> <title>Guile applet demo</title> </head> <p> This is a simple Guile applet demonstration <p> <a href="learn-applet-0.scm"> Clike here for learn-applet-0.scm </a> (which should run in its own window) <p> <hr> <address>rosalia@papageno.lanl.gov</address> <!-- hhmts start --> Last modified: Thu Apr 4 11:15:28 1996 <!-- hhmts end --> </body> </html>
guile
, then do (load "surfit.scm")
, and ask
SurfIt! to load the URL file:///tmp/trivial.html
, then click on
the anchor to see the applet execute.
Congratulations! You have just written your first applet, and it has been executed by a browser. [This is also the author's first applet; he is also excited.]
Notice how the applet uses Tk widgets that are shown directly on your own display.
This chapter gives an overview of the new primitives available to Scheme programmers who use Guile. We have already mentioned that Guile has become a kitchen sink language; here you can see how Guile freely takes new commands and constructs from the portable scheme library slib, the Tk widget set, the goonix posix library (useful for UNIX systems programming), various ways you can program OpenGL, the C syntax for Guile ctax, the regular expression library rx, and many more @dots{}
So Guile has many more commands available to it than what are specified in section 'Standard Procedures' in Revised(4) Report on the Algorithmic Language Scheme. On top of that, Guile will interpret almost all standard scheme programs. The only differences between the basic guile language and R4RS scheme are that:
'()
and the false symbol #f
identically: both are equal to the empy list. In this Guile resembles
classical lisp dialects more than Scheme does. Most boolean code will
not suffer from this.
Here is an outline of the broad classes into which these new functions fall:
In this section we give a tutorial introduction to programming in
scheme, with a slant toward the interesting things that can be done in
Guile. Applets are so chic that they get their own section, but this
section will try to touch on all other interesting and cool aspects of
Guile, showing you how new types of problems can be solved with guile.
Note that using guile as a library with libguile.a
is described
in its own chapter (see section Guile in a library - using libguile.a).
Also notice that some small examples are given in section How to start up guile - a quick tour.
To get started you need to know how to program in scheme (a dialect of LISP). Fortunately scheme is a small, clean language and is not hard to learn, and is used in many undergraduate courses to introduce computer programming.
We will not try to teach you scheme here (although you might end up learning by example), since there are many good books on the subject, listed in section Where to find more Guile/Scheme resources. (1)
Our first program is the typical scheme "hello world" program. Put the
following code in a file called hello.scm
#!/whatever-path/guile - ; -*-scheme-*- (display "hello world\n") (quit)
The run guile on it. One way to do so is to start up guile and load this file:
<shell-prompt> guile guile> (load "hello")
Here is some code you can type at the guile>
prompt to see some
of the scheme data types at work (mostly lists and vectors).
guile> (define ls (list 1 2 3 4 5 6 7)) guile> ls guile> (vector? ls) guile> (list? ls) guile> (length ls) guile> (car ls) guile> (cdr ls) guile> (car (cdr (cdr ls))) guile> (caddr ls) guile> (append ls (list 8 9 10)) guile> (reverse ls) guile> (memq 4 ls) guile> (memq 4 (reverse ls)) guile> (map sin ls) guile> (map (lambda (n) (expt n n)) ls)
guile> (define v #(1 2 3 4 5 6 7)) guile> v guile> (vector? v) guile> (list? v) guile> (vector-length v) guile> (vector-ref v 2) guile> (vector-ref (list->vector (reverse (vector->list v))) 2) guile> (vector-set! v 4 "hi there") guile> v
Here are some typical examples of using recursion to process a list.
(define (my-reverse l) (if (null? l) l (append (my-reverse (cdr l)) (list (car l)))))
Suppose you have a matrix represented as a list of lists:
(define m (list (list 7 2 1 3 2 8 5 3 6) (list 4 1 1 1 3 8 9 8 1) (list 5 5 4 8 1 8 2 2 4)))
Then you could apply a certain function to each element of the matrix in the following manner:
;; applies the function func to the matrix m element-by-element; ;; returns a matrix with the result. (define (process-matrix m func) (map (lambda (l) (map func l)) m))
This could then be invoked with (process-matrix m sin)
or
(process-matrix m (lambda (x) (* x x)))
.
To print a representation of the matrix, we could define a generalized routine:
;; proc is a procedure to represent the single element, ;; row-proc is a procedure that is invoked after each row. ;; For example, proc could be (lambda (x) (begin (display x) (display " "))) ;; and row-proc could be (lambda (l) (display "\n")) (define (represent-matrix m proc row-proc) (for-each (lambda (l) (begin (for-each proc l) (row-proc l))) m))
And then invoke it with
(represent-matrix m (lambda (x) (begin (display x) (display " "))) (lambda (l) (begin (display "\n"))))
Now we write a helper routine that uses guile closures to make
objects with state that then receive messages to draw little squares.
These objects can then be passed to represent-matrix
so that we
get a graphical representation of the matrix.
But let us take it one step at a time. I will start by showing you a simple example of object in scheme. The object I make here represents a cell, which could be a cell in a matrix. The cell responds to commands to draw itself, to return the next cell, and so forth. Later I will add graphical messages.
;; cell-object.scm: routines for creating and manipulating cell objects ;; (the-x, the-y) is the initial position of the cell. ;; the-color is a string representing a color; must be something Tk can grok. ;; square-size is the size of the square that gets drawn. ;; (sizex, sizey) is the size of the matrix. (define (MAKE-CELL the-x the-y the-color square-size sizex sizey) (define (get-x) the-x) (define (get-y) the-y) (define (set-x! new-x) (set! the-x new-x) the-x) (define (set-y! new-y) (set! the-y new-y) the-y) (define (set-color! new-color) (set! the-color new-color) the-color) (define (next!) (set! the-x (+ the-x 1)) (if (>= the-x sizex) (begin (set! the-x 0) (set! the-y (+ the-y 1)))) (if (>= the-y sizey) (begin (display "CELL next!: value of y is too big; not changing it\n") (set! the-y (- the-y 1)))) (cons the-x the-y)) (define (draw) (let* ((x0 (* the-x square-size)) (y0 (* the-y square-size)) (x1 (+ x0 square-size)) (y1 (+ y0 square-size))) (display "I should draw a ") (display the-color) (display " rectangle with corners at ") (display x0) (display y0) (display x1) (display y1) )) ;; self is the dispatch procedure (define (self message) (case message ((x) get-x) ((y) get-y) ((set-x!) set-x!) ((set-y!) set-y!) ((set-color!) set-color!) ((next!) next!) ((draw) draw) (else (error "CELL: Unknown message -> " message)))) ;; and now return the dispatch procedure self )
What is this procedure doing? It returns another procedure
(self
) which receives a message (x, y, set-x!, set-y!, @dots{})
and takes an action to return or modify its state. The state consists
of the values of variables the-x
, the-y
, the-color
and so forth.
Here are some examples of how to use MAKE-CELL:
(define c (MAKE-CELL 0 0 "red" 10 7 9)) ((c 'x)) ((c 'y)) ;; change the x coordinate ((c 'set-x!) 5) ((c 'x)) ;; change the color ((c 'color)) ((c 'set-color!) "green") ((c 'color)) ;; now use the next! message ((c 'next!)) ((c 'x)) ((c 'y)) ;; now make things wrap around ((c 'next!)) ((c 'next!)) ((c 'next!)) ((c 'x)) ((c 'y))
You will notice that expressions like (c 'next)
return procedures
that create other procedures to do the job, so we have to use extra
parentheses to make the job happen. This makes for somewhat awkward
syntax; one way around it is to define a send
procedure:
;; send makes object syntax a bit easier; instead of saying ;; ((my-cell 'set-x!) 4) ;; you can say ;; (send my-cell 'set-x! 4) (define (send obj . args) (let ((first-eval (apply obj (list (car args))))) (if (null? (cdr args)) (first-eval) (apply first-eval (cdr args)))))
You can see that send
passes the message to the object, making
sure that things are evaluated the proper number of times. You can now
type:
(send c 'x) (send c 'set-x! 5) (send c 'color) (send c 'set-color! "green") (send c 'next!) (send c 'x) (send c 'y)
Applet is a trendy word in the mid-1990s. It is used to denote a (usually small) program which executes within the context of a parent program.
The most common use for applets is in the World Wide Web. In setting up a web page you put an applet in a document. When a browser visits that document, the applet will be executed locally on the browser's machine.
Having a program execute on the client machine allows many more things to be done with the web, but it also opens a pandora's box of safety, security and privacy issues: if you are running a stranger's program on your workstation, couldn't that program go erase your files, or mail your files to some other person on the net?
Applet system implementors have solved this problem by creating safe execution enviromnents for the languages they support. Guile and Tcl have safe environments in which access to the operating system has to be authorized by the user.
In section Applets in Guile, I showed you how to create a simple applet and an enclosing html document. Then we saw how to load that into a browser (SurfIt!) and execute the applets.
From the `learn-applet-0.scm' example, we can deduce that an applet must take the following steps (this list will expand as we write more complicated applets).
(require 'Gwish) (use-library tcl) (use-interface tcl) (use-interface tclhack)
(require 'applet)
.
(define-applet-terminate thunk)
.
(tk-main-loop)
, or a read-eval-print loop. This is
important because you should not monopolize the CPU.
Now I will show you some other examples of Guile applets. The first one, `learn-applet-1.scm', is very much like `learn-applet-0.scm', but it creates its button in the browser window, rather than creating a new window.
;; Simple button demo; this version uses the browser window instead ;; of making a new top-level window. (require 'Gwish) (use-library tcl) (use-interface tcl) (use-interface tclhack) (require 'applet) (display "entering learn-applet-1\n") ; just some crap (display "applet window name is ") (display applet-window-name) (display "\n") (display "browser window name is ") (display browser-window-name) (display "\n") ;; Clean up before we start. ??? For some reason, this is necessary ;; or surfit! will die when we enter (tk-main-loop). This is a pity ;; because it would be nice to put the button *inside* the current ;; broser window, at the point where the applet is invoked. (applet-newpage) ;; put the button under the broser window (define button-name (string-append browser-window-name ".quit-1")) (define (quit-1-callback) (begin (display "quitting now\n") (destroy button-name))) ; A callback for when the user terminates the applet (boiler plate) (define-applet-terminate (tcl-lambda () (quit-1-callback))) (display "button-name is ") (display button-name) (display "\n") (button (string->symbol button-name) :text "quit-1" :command (tcl-lambda () (quit-1-callback))) (display "about to pack the button\n") (pack (name->window button-name)) (display "about to enter tk-main-loop\n") (tk-main-loop) (quit)
The only difference in `learn-applet-1.scm' is that the button is a
sub-widget of the browser-window-name
widget, rather than being
in a new top level widget.
The next program [??? not yet]
This section has has been written by Gordon Irlam, gordoni@cygnus.com, at Cygnus Support, February 28, 1996. It is included here verbatim.
This section provides the specification for writing Guile applets for use with the SurfIt! demo browser.
Guile Scheme applets are denoted by the mime type application/guile. This is the default type for the file extension .scm.
An applet can be inlined within a HTML document.
An applet may also be invoked when a hyperlink is followed.
An applet is required to be a syntactically well formed Guile Scheme program. When an applet is invoked the corresponding Guile program is retrieved, loaded, and executed.
Every applet is required to include the applet library:
Every applet is required to define a routine to be called by the browser when the browser requires the applet to terminate execution:
An applet will persist for as long as it is accessible -- either externally through it's being displayed on a page, or internally through the Scheme environment.
All applets reside in the same top level environment. This allows state to be shared between applets and to persist between applet invocations.
An applet has access to all the features of a regular Guile Scheme program and to the gTcl/gtk Guile extensions. The features of gtk allow the Guile applet to interactively display itself within the parent document.
Note: While Guile provides the ability to control namespaces, and this is necessary to provide a secure environment within which applets can be run, this has not been done for the SurfIt! Guile demo browser. The SurfIt! Guile demo browser is mainly intended as a research prototype, not a production web browser.
(browser-window 'window 'create applet-embedindex :window applet-window-name).
Applets should not monopolize the cpu. Instead they should be written using a callback or event loop polling based style so that the Tk event handler can continues to operate, and the user can continue to interact with the browser.
An run time error occurring within an applet that goes uncaught will cause the applet to exit, but the browser will continue to function.
In this manual we usually jump into examples and explain them as you type in the code; here will will digress and ramble for a few paragraphs to set some concepts straight, and then let you type (or paste) in fun examples.
In 1995 the author of this manual implemented a large program, Gnudl, using Guile quite extensively. In the design phase of Gnudl I (I switch to first person in this paragraph) found I had to make a choice: should the fundamental data structures be C or scheme data structures?
Guile allows C to see its data structures (scalar types, lists, vectors, strings @dots{}). C also allows guile to see its data structures. As a largre program designer, you have to decide which of those capabilities to use. You have two main choices.
You can write your software mostly in scheme. In this case, your C software will mostly parse the scheme code with Guile calls, and provide some new primitive procedures to be used by scheme. This is what Gnudl does.
Or you can write your software mostly in C, occasionally allowing scheme code to be parsed by Guile, either to allow the user to modify data structures, or to parse a configuration file, @dots{}
Mixing the two approaches seems unwise: the overall layout would be confusing. But who knows? There might be problems that are best solved by a hybrid approach. Please let us know if you think of such a problem.
If you use the former approach, we will say that the master world is scheme, and the C routines serve scheme and access scheme data structures. In the latter case, the master world is C, and scheme routines serve the C code and access C data structures.
In both approaches the libguile.a
library is the same, but a
predominantly different set of routines will be used. To clarify these
two approaches further, when we go through examples of libguile use, we
will point out which is the master world.
Libguile is the library which can be linked to C programs and which allows the C programs to start a scheme interpreter and execute scheme code. There are also facilities in libguile to make C data structures available to scheme and vice versa.
This chapter gives a gentle introduction to libguile.a, presenting some hello world-style programs which Mark Galassi wrote while teaching himself to use libguile.
The Guile Programmer's Manual gives more examples of programs written using libguile, illustrating diverse applications. You can also consult Mark Galassi's Gnudl document to see a large scale project that uses C and scheme code together.
Here is an elementary first program, learn0
, to get going with
libguile. The program (which uses scheme as a master world) is in a
single source file learn0.c
:
#include <stdio.h> /* the include file for guile */ #include <gscm.h> static GSCM_status guile_init() { #if 0 /* don't need any of these extra packages */ scm_init_ctax(); scm_init_unix(); scm_init_posix(); scm_init_ioext(); scm_init_gTcl(); scm_init_gtk(); #endif /* 0 */ } main(int argc, char *argv[]) { GSCM_status status; GSCM_top_level toplev; char *eval_answer; char input_str[200]; int done; printf("hello guile\n"); /* start a scheme interpreter */ status = gscm_run_scm(argc, argv, 0, stdout, stderr, guile_init, 0, "#t"); if (status != GSCM_OK) { fputs(gscm_error_msg(status), stderr); fputc('\n', stderr); exit(1); } /* create the top level environment */ status = gscm_create_top_level(&toplev); if (status != GSCM_OK) { fputs(gscm_error_msg(status), stderr); fputc('\n', stderr); exit(1); } /* for fun, evaluate some simple scheme expressions here */ status = gscm_eval_str(NULL, toplev, "(define (square x) (* x x))"); status = gscm_eval_str(NULL, toplev, "(define (factorial n) (if (= n 1) 1 (* n (factorial (- n 1)))))"); status = gscm_eval_str(NULL, toplev, "(square 9)"); status = gscm_eval_str(NULL, toplev, "(factorial 100)"); /* now sit in a scheme eval loop: I input the expressions, have guile * evaluate them, and then get another expression. */ done = 0; while (!done) { if (gets(input_str) == NULL || strcmp(input_str, "quit") == 0) { done = 1; } else { status = gscm_eval_str(NULL, toplev, input_str); } } /* now clean up and quit */ gscm_destroy_top_level(toplev); exit(0); }
If you name this program learn0.c
, it can now be compiled with:
gcc -g -I/packages/include/guile -c learn0.c -o learn0.o gcc -o learn0 learn0.o -L/packages/lib -lguile -lm(remember to fix the paths if you don't use `/packages' as a prefix).
The program is simple: it creates a scheme interpreter, passes a couple
of strings to it that define new scheme functions square
and
factorial
, and then a couple of strings that invoke those
functions.
It then goes into a read-eval loop, so you could type one-line scheme expressions to it and have them evaluated. For example:
<shell-prompt> ./learn0 hello guile ;;; loading modops... ;;; ...loaded /packages/lib/gls/bootstrapping/modops. ;;; loading libguile... ;;; ...loaded /packages/lib/gls/bootstrapping/libguile. ;;; loading slibhooks... ;;; ...loaded /packages/lib/gls/bootstrapping/slibhooks. ;;; loading require... ;;; loading slibcat... ;;; ...loaded /packages/lib/gls/bootstrapping/slibcat. ;;; ...loaded /packages/lib/gls/bootstrapping/require. ;;; loading mule... ;;; ...loaded /packages/lib/gls/bootstrapping/mule. learn0> (require 'debug) ;;; loading debug... ;;; ...loaded /packages/lib/gls/debug. ; type (init-debug)learn0> learn0> (print (sin 1.3)) 963.558185417193e-3 learn0> (print (factorial 10)) 3628800 learn0> (quit) <shell-prompt>
You should notice the key steps involved in this learn0
program:
#include <gscm.h>
guile_init()
-like routine, which could even be
trivial like the one in this example, to pass to gscm_run_scm()
.
This allows you to tell gscm_run_scm()
which optional guile
packages to use. Note that in this example I am only interested in the
scheme interpreter, and not in the extra packages, so all the extra
package initialization has been #if
-ed out.
gscm_run_scm()
and gscm_create_top_level()
at the beginning of your program. This sets up the scheme interpreter
to which you can then pass strings for evaluation.
gscm_eval_str()
routine.
gscm_destroy_top_level()
.
-lguile
.
The learn0
program shows how you can invoke scheme commands from
a C program. This is not such a great achievement: the same could have
been done by opening a pipe to SCM or any other scheme interpreter.
A true extension language must allow callbacks. Callbacks allow you to write C routines that can be invoked as scheme procedures, thus adding new builting procedures to scheme. This also means that a scheme procedure can modify a C data structure.
Guile allows you to define new scheme procedures in C, and provides a mechanism to go back and forth between C and scheme data types.
Here is a second program, learn1
, which demonstrates these
features. It is split into three source files: learn1.c
,
c_builtins.h
and c_builtins.c
. I am including the code
here, but you might just want to look at the online source code and the
Makefile that come in the learn_libguile distribution. Notice that
learn1
uses a scheme master world, and the C routines in
c_builtins.c
are simply adding new primitives to scheme.
Here is `learn1.c':
#include <stdio.h> #include <gscm.h> /* #include <Tcl.h> #include <tk.h> */ #include "c_builtins.h" static GSCM_status guile_init() { #if 0 /* don't need fancy packages */ scm_init_ctax(); scm_init_unix(); scm_init_posix(); scm_init_ioext(); scm_init_gTcl(); scm_init_gtk(); #endif /* 0 */ } main(int argc, char *argv[]) { GSCM_status status; GSCM_top_level toplev; char *eval_answer; char input_str[200]; /* ugly hack: assume strlen(line) < 200 */ int done; printf("hello guile\n"); /* start an interpreter */ #if 0 /* this is the old way */ status = initialize_gscm(0, argc, argv); #endif /* 0 */ /* start a scheme interpreter */ status = gscm_run_scm(argc, argv, 0, stdout, stderr, guile_init, 0, "#t"); if (status != GSCM_OK) { fputs(gscm_error_msg(status), stderr); fputc('\n', stderr); exit(1); } /* create the top level environment */ status = gscm_create_top_level(&toplev); if (status != GSCM_OK) { fputs(gscm_error_msg(status), stderr); fputc('\n', stderr); exit(1); } /* for fun, evaluate some simple scheme expressions here */ status = gscm_eval_str(NULL, toplev, "(define (square x) (* x x))"); status = gscm_eval_str(NULL, toplev, "(define (factorial n) (if (= n 1) 1 (* n (factorial (- n 1)))))"); status = gscm_eval_str(NULL, toplev, "(square 9)"); status = gscm_eval_str(NULL, toplev, "(factorial 100)"); /* now try to define some new builtins, coded in C, so that they * are available in scheme. note that I have put junk in the documentation * strings because I have not yet read the manual on how doc strings * should be written :-| */ gscm_define_procedure("c-factorial", c_factorial, 1, 1, 0, "hi there"); gscm_define_procedure("c-sin", c_sin, 1, 1, 0, "hi there"); gscm_define_procedure("v-t", vector_test, 1, 1, 0, "hi there"); /* now sit in a scheme eval loop: I input the expressions, have guile * evaluate them, and then get another expression. */ done = 0; fputs("learn1> ", stdout); while (!done) { if (gets(input_str) == NULL || strcmp(input_str, "(quit)") == 0) { done = 1; } else { status = gscm_eval_str(NULL, toplev, input_str); fputs("learn1> ", stdout); } } /* now clean up and quit */ gscm_destroy_top_level(toplev); exit(0); }
Here is `c_builtins.h':
/* builtin function prototypes */ SCM c_factorial(SCM n); SCM c_sin(SCM n); SCM vector_test(SCM s_length);
Here is `c_builtins.c':
#include <stdio.h> #include <math.h> #include <gscm.h> #include "c_builtins.h" /* this is a factorial routine in C, made to be callable by scheme */ SCM c_factorial(SCM s_n) { int i; unsigned long result = 1, n; n = gscm_2_ulong(s_n); GSCM_DEFER_INTS; for (i = 1; i <= n; ++i) { result = result*i; } GSCM_ALLOW_INTS; return gscm_ulong(result); } /* a sin routine in C, callable from scheme. it is named c_sin() * to distinguish it from the default scheme sin function */ SCM c_sin(SCM s_x) { double x = gscm_2_double(s_x); return gscm_double(sin(x)); } /* play around with vectors in guile: this routine creates a * vector of the given length, initializes it all to zero except * element 2 which is set to 1.9. */ SCM vector_test(SCM s_length) { SCM xvec; unsigned long c_length; c_length = gscm_2_ulong(s_length); printf("requested length for vector: %ld\n", c_length); /* create a vector */ xvec = gscm_vector(c_length, gscm_double(0.0)); /* set the second element in it */ gscm_vset(xvec, 2, gscm_double(1.9)); return xvec; }
If you compare learn1 to learn0, you will find that learn1 uses a new
guile construct: the function gscm_define_procedure()
:
/* now try to define some new builtins, coded in C, so that they * are available in scheme. note that I have put junk in the documentation * strings because I have not yet read the manual on how doc strings * should be written :-| */ gscm_define_procedure("c-factorial", c_factorial, 1, 1, 0, "hi there"); gscm_define_procedure("c-sin", c_sin, 1, 1, 0, "hi there"); gscm_define_procedure("v-t", vector_test, 1, 1, 0, "hi there");
It is clear that gscm_define_procedure()
adds a new builtin
routine written in C which can be invoked from scheme. We can now
revise our checklist for programming with libguile, so it includes
adding callbacks.
#include <gscm.h>
guile_init()
-like routine, which could even be
trivial like the one in this example, to pass to gscm_run_scm()
.
This allows you to tell gscm_run_scm()
which optional guile
packages to use. Note that in this example I am only interested in the
scheme interpreter, and not in the extra packages, so all the extra
package initialization has been #if
-ed out.
gscm_run_scm()
and gscm_create_top_level()
at the beginning of your program. This sets up the scheme interpreter
to which you can then pass strings for evaluation. I believe that this
routine will soon be renamed to start with the prefix gscm_
: the
prefix of all the routines in the guile programmer's interface.
gscm_define_procedure()
routine.
gscm_eval_str()
routine.
gscm_destroy_top_level()
(which currently gives
some silly error message).
-lguile
.
I breezed by the issue of how to write your C routines that are registered to be called from scheme. This is non-trivial, and is discussed at length in the Guile Programmer's Manual.
gcc -g -I/packages/include/guile -c learn1.c -o learn1.o gcc -g -I/packages/include/guile -c c_builtins.c -o c_builtins.o gcc -o learn1 learn1.o c_builtins.o -L/packages/lib/scm -L/packages/lib -lguile -lm
If you run learn1
, it will prompt you for a one-line scheme
expression, just as learn0
did. The difference is that you can
use the new C builtin procedures (c-factorial
, c-sin
,
v-t
).
<shell-prompt> ./learn1 hello guile ;;; loading modops... ;;; ...loaded /packages/lib/gls/bootstrapping/modops. ;;; loading libguile... ;;; ...loaded /packages/lib/gls/bootstrapping/libguile. ;;; loading slibhooks... ;;; ...loaded /packages/lib/gls/bootstrapping/slibhooks. ;;; loading require... ;;; loading slibcat... ;;; ...loaded /packages/lib/gls/bootstrapping/slibcat. ;;; ...loaded /packages/lib/gls/bootstrapping/require. ;;; loading mule... ;;; ...loaded /packages/lib/gls/bootstrapping/mule. learn1> (require 'debug) ;;; loading debug... ;;; ...loaded /packages/lib/gls/debug. ; type (init-debug)learn1> learn1> (print (c-factorial 6)) 720 learn1> (print (c-factorial 20)) 2192834560 learn1> (print (c-factorial 100)) 0 learn1> (print (c-sin 1.5)) 997.494986604054e-3 learn1> (print (c-sin 1.5)) 997.494986604054e-3 learn1> (print (v-t 10)) requested length for vector: 10 #(0.0 0.0 1.9 0.0 0.0 0.0 0.0 0.0 0.0 0.0) learn1> (print (v-t 15)) requested length for vector: 15 #(0.0 0.0 1.9 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0) learn1> (quit) <shell-prompt>
As you see, taking (c-factorial 100)
does not use bignumbers and
returns a bogus answer.
Further "idealized" examples are included in the examples
distribution. They include programs to:
A couple of the examples in the quick tour made use of the Tk toolkit. Here we will say more about how Guile interfaces to Tk. We will also give you a recipe for reading Tk documentation, which is written assuming the Tcl interface, and writing scheme code with it.
In this chapter we do not give any sort of introduction to Tk in
general. There are books on Tk, but maybe the best way to learn the Tk
widgets is to go through the wtour
tour of widgets that is
distributed with Tk. It is much more pedagogical than the main book
Tcl and the Tk Toolkit.
The Guile program is usually compiled with the Tk interface, so to use Tk you only need to include this preamble:
(require 'Gwish) (use-library tcl) (use-interface tcl) (use-interface tclhack)
and then conclude the main script with:
(tk-main-loop) (quit)
Note: the preamble is kind of ugly, and it will probably change.
Here are some (out of context) examples of the syntax for creating Tk widgets:
(button '.quit :text "quit" :command (tcl-lambda () (quit-callback))) (text '.a :yscrollcommand ".b set") (scrollbar '.b :command ".a yview") (frame '.button-bar :relief 'raised :bd 2) (canvas '.ca :width 200 :height 300) (label '.lab :text "this is a label")
What can we deduce from these examples of widget creation?
:text
, :command
,
:width
@dots{}
A widget callback (or simply callback) is a procedure that gets invoked when something happens in a widget, for example if the mouse is clicked on a button or scrollbar.
When you first create a Tk widget, you can specify that a procedure
should become the callback, usually with the :command
option
in the widget creation, although a widget could allow several callbacks,
and those could be set by other options such as :yscrollcommand
.
If a command is to invoke a scheme procedure, it is done with
the tcl-lambda
primitive. This is similar to a simple scheme
lambda
expression, but it straightens out the calling convention
between Tcl and scheme.
The tcl-lambda
expression also makes sure that the anonymous
procedure created will not be garbage-collected away while a callback is
not being executed.
Notice that tcl-lambda
is not a clean implementation, and Guile
will probably be fixed eventually so that you can just use
lambda
.
But not all callbacks invoke scheme procedures. In the creation examples just given, the widget created by
(scrollbar '.b :command ".a yview")passes a message to the text widget
.a
. This message passing is
done with the string ".a yview"
, which just maps directly to the
equivalent Tcl code.
Once a widget has been created and its callbacks (if any) have been registered, that widget becomes a new scheme primitive procedure. This procedure can be used to give further instructions to a widget.
One example of this is to add or change configuration options to a
widget after it has been created. Try this self-contained program to
see an example of the config
command being sent to a widget. It
also shows examples of putting several buttons together in a frame, and
illustrates the destroy
command that kills off a Tk widget.
#!/whatever-path/guile - ; -*-scheme-*- ;; an abbreviated version of the quit button program (require 'Gwish) (use-library tcl) (use-interface tcl) (use-interface tclhack) ;; create a frame widget to house the buttons (frame '.button-bar :relief 'raised :bd 2) (pack '.button-bar) ;; create the quite button: its callback destroys the top level widget (button '.button-bar.quit :text "quit" :command (tcl-lambda () (begin (display "quitting now\n") (destroy ".")))) ;; create the "change text" button: its callback changes the text ;; of the "quit" button, and destroys itself. (button '.button-bar.change-text :text "change text" :command (tcl-lambda () (begin (.button-bar.quit 'config :text "hey, it just changed") (destroy ".button-bar.change-text")))) (pack '.button-bar.quit '.button-bar.change-text :side 'left) (tk-main-loop) (quit)
Guile has a module called goonix which implement the posix system calls (a standardized set of UNIX system calls) in scheme. This makes it easy to do things like list directories, create processes and so forth.
Here is an example of using the goonix opendir
, readdir
and closedir
calls.
;; list-dir takes a path and returns a list of files in that directory (define (list-dir path) (letrec ((dport (%opendir path)) (form-dlist ; a procedure that forms the list (lambda (dl) (let ((fname (%readdir dport))) (if (eof-object? fname) dl (form-dlist (cons fname dl)))))) ) (define output-list (form-dlist '())) (%closedir dport) output-list ) )
@paragraphindent 2
@parskip 4pt plus 1pt
This chapter has been written by Takumi Doi at Cygnus Support, March 29 1996. It is included here verbatim.
Among significant improvements made to Guile in this release, this appendix describes the internationalization features that allows Guile manipulate and render characters from various international character sets including Latin, Japanese Kanji, Chinese Hanji, Korean Hangul, et al.
To include internationalization feature in Guile, you should
specify the option --enable-i18n
when you configure
Guile,
such as:
% ./configure --enable-i18n --prefix=`pwd`/=inst
In the current release, the modules affected by this option are only libguile, gls, and gtcltk. In addition, Tcl/Tk that comes with this release incorporates support solely for Japanese EUC patches. This also means the rest of plugin libraries are yet to be internationalized.
In Guile, each character is identified by a unique internal character
code, a 24 bit integer. The function char->integer
can be used
to retrieve the internal character code of a character.
On the other hand, strings are represented as sequences of 8 bit-byte elements, where characters with character codes beyond 255 are split into adjacent bytes to form a multibyte string.
This design decision of using multibyte strings is motivated by one of major goals of Guile; to provide an east-to-integrate underlying implementation for GNU Emacs. Authors also believe that this design allows a single string data type and compact string representation that can easily be support evolving international standards with larger character sets.
While Guile has its own internal character representation, the new internationalization features enable users to easily handle characters from wide variety of existing coded character sets.
By external character encoding the author means any character encoding method other than the Guile Scheme internal encoding, whose coded characters have to be converted when reading from text streams and writing to external devices for saving or rendering.
In Guile Scheme, such conversion is controled by optional arguments to several I/O procedures, in addition to a couple of global variable values to be used as the default conversion method.
Following self-evaluating symbols designate available character encodings for file I/O as well as process I/O:
*sjis*
-- Microsoft Kanji code, or Shift-JIS
*iso-2022-jp*
, aka *junet*
-- encoding used in Japan
to transfer emails and netnews
*iso-2022-int-1*
-- "ISO-2022-INT-1" [So what's this?!]
*old-jis*
-- Obsolete JIS encoding
*ctext*
, aka *iso-8859-1*
-- Compound Text encoding
*euc-japan*
-- Japanese version of Extended Unix Code
*euc-korea*
, aka *euc-kr*
-- Korean version of Extended
Unix Code
*iso-2022-kr*
, aka *korean-mail*
-- encoding used in Korea
to transfer emails and netnews
*iso-2022-ss2-8*
-- ISO-2022 encoding using SS2 for 96-charset
in 8-bit code
*iso-2022-ss2-7*
-- ISO-2022 coding system using SS2 for
96-charset in 7-bit code
*iso-2022-lock*
-- ISO-2022 coding system using Locking-Shift
for 96-charset
*big5*
, aka *big5-eten*
-- BIG5, a Chinese encoding.
*internal*
-- Mule's representation in buffers.
*utf-8*
-- ISO10646 UCS2 (known as Unicode) character set
represented in UTF-8 encoding scheme.
*noconv*
-- for "NO CONVersion"
*autoconv*
-- for "AUTOmatic CONVersion"
These symbols can be specified as encoding parameter for procedures described later in this document.
For precise meaning of these values, see also online Info manuals included in Mule, the Multilingual Emacs. As of this writing, Guile supports as many external coded character sets as the Mule version 2.3, in addition to Unicode.
{Variable} input-coding-system
{Variable} output-coding-system
These variables are used by the function open-file
and its buddies
to determine default external encoding to associate with opened ports.
The value #f
means no conversion takes place on I/O, which is
the default.
{Variable} process-coding-system
Used by functions to determine the character encoding understood by the operating system environment. The value of this variable affects the behavior of each of follwing functions:
open-file
, open-input-file
,
open-output-file
, open-io-file
, call-with-input-file
,
call-with-output-file
.
system
.
getenv
.
The initial value is #f
, meaning that no conversion takes place.
Although not apparent changes, each of string operations now treats a string as a sequence of characters, not a byte chunk. Namely, index value is assumed to be the character position instead of byte position, the length of a string is the number of characters in the string, not the number of bytes, and so on. This is also the case with the uniform vector operations on multibyte strings.
Users who need to operate on byte sequences are encouraged to use byte-vector extensions instead.
Follwing procedures are now extended to form the internationalization features in Guile:
{Function} open-file str mode &optional encoding
{Function} open-input-file str &optional encoding
{Function} open-output-file str &optional encoding
{Function} open-io-file str &optional encoding
These functions open a file specified by str, and return a port associated with the file. str must be a string or a symbol that names the file to open.
The mode argument to open-file
specifies the direction[s]
to which I/O operations are allowed via the returned port. It can be
one of following values:
OPEN_READ
, for input
OPEN_WRITE
, for output
OPEN_BOTH
, for input and output
The optional argument encoding can be a symbol that names
an external character encoding.
If specified, further I/O operations via opened port will convert
the file contents between the specified character encoding and the
Guile Scheme internal character encoding.
If encoding is omitted, the encoding of the file is determined
by the current value of input-coding-system
(for input) and
output-coding-system
(for output).
The functions open-input-file
, open-output-file
and
open-io-file
are similiar to open
, except for opening
a file for read-only, write-only, and read-write, respectively.
{Function} call-with-input-file str proc &optional encoding
{Function} call-with-output-file str proc &optional encoding
Call proc with one argument, a port which is the file named by str.
Both functions close the port after proc returns.
Both return the value of proc.
The optional argument encoding specifies the external character
encoding used in the file str. Default behavior is determined by
the current values of input-coding-system
and
output-coding-system
, respectively.
{Function} load name &optional encoding
Loads the Scheme source file named by name in core. if
encoding is specified, the file name is assumed to have
contents encoded in encoding. Otherwise, the current value of
input-coding-system
is used.
{Function} port-coding port
{Function} set-port-coding! port encoding &optional modes
The function port-coding
retrieves the character encoding used by
port.
port must be an open port object, otherwise an error is signaled.
It returns a symbol that names the character encoding currently used by
port. Refer previous sections for external character encoding symbols
that are available in this release.
The function set-port-coding!
sets the character encoding
attribute of port to encoding.
Following procedures are not immediately relevant to internationalization, however added in the hope they will effectively compliment the uses of raw byte data (such as binary image data and network packet data) that might normally have been implemented using strings:
{Function} uniform-vector->string uve encoding
{Function} string->uniform-vector str encoding
Coerces between byte-vector and string.
In Guile, a byte-vector is a uniform-vector whose prototype is
#\nul
.
If specified, code conversion between encoding and Guile internal encoding is performed. Otherwise, no conversion takes place.
For uniform-vector->string
, programmers must make sure if each
vector element has a valid value to form a string element.
{Function} concatenate &rest args
{Function} concatenate! &rest args
Similiar to string-append
, but works on any uniform vectors.
each of args must be uniform-vector with same element type.
concatenate
returns a newly created vector, where
concatenate!
modifies the original vector.
{Function} subvector vec start end
Returns a uniform-vector formed from elements of the uniform-vector vec, beginning from index start (inclusive) and ending with index end (exclusive).
Note in this release, returned vector is a shared-vector to the original vector. This implementation is subject to change in future releases.
{Function} gscm_foreign_str src len encoding
{Function} gscm_foreign_str0 src encoding
Used for converting a string from the encoding in "foreign" (anywhere outside GSCM) code to Guile Scheme internal encoding.
Similiar to gscm_str
and gscm_str0
respectively, except
for accepting encoding argument. encoding must be of type SCM and
a valid Scheme symbol representing an character encoding.
This means you may have to scm_intern
the encoding name in your
code. This subject to change.
{Function} gscm_2_foreign_str str_out len_out obj_in encoding
Used for converting SCM string contents to "foreign" string encoded in encoding.
Similiar to gscm_2_string
. but accepts encoding
argument. encoding must be of type SCM and a valid Scheme symbol
representing an character encoding. This means you may have to
scm_intern
the encoding name in your code (this is subject to
change).
str_out must be an address to unsigned char *
storage,
but not neccessarily be an allocated memory.
Right now this appendix is just pasted in from the bibliographies in Gnudl and Jacal. It requires format cleanup and some changes.
scm
extensions (beyond Scheme standards).
Documentation on the internal representation and how to extend or
include scm
in other programs.
scm
: the scheme interpreter used in guile
slib
: the portable scheme library
jacal
: a symbolic math system written in scheme
Note: this is the r0 release I picked up on April 12 1996; I am not clued in to the release nomenclature, but I thought it was important to call it r0.3 because version r0 has changed around a few times already.
Other note: the guile-1.0b0 is a version I got from Tom Lord on 1996/04/22. It has diverged significantly from guile-r0.3, and I am now experimenting with it.
The guile-r0.3 snapshot is one Tom Tromey made for me. It contains
fixes to the tcl-lambda()
problem I reported.
I configure it with
./configure --prefix=/packages --enable-i18n
gcc -g -I. -I. -I./../mesa/include -I./../glut -I./../libguile -I../libguile -I/packages/include -L../glut -L../mesa/src -L../mesa/src-glu -L../libguile -o ggl glconsts.o glfns.o glutconsts.o glutfns.o glinvoke.o gglmain.o ../libguile/libguile.a ../threads/libthreads.a -lm -lglut -lMesaGLU -lMesaGL -L/packages/lib -R /packages/lib -lXmu -lX11 -lnsl -lsocket ld: elf error: file ../threads/libthreads.a: unable to locate archive symbol table: Request error: offset out of range ld: fatal: File processing errors. No output written to ggl gmake[1]: *** [ggl] Error 1 gmake[1]: Leaving directory `/nh/toaster/packages-root/.packages/guile/guile-r0.3/src/ggl' gmake: *** [all] Error 1
Ugly hackaround: edit ggl/Makefile, replace the `../threads/libthreads.a' with `../threads/threads.o' and that seems to work.
-lthreads
with `../threads/threads.o'.
Ugly hackaround: I create a dummy function in a dummy .o file,
and add that to the archive (ar qs libthreads.a dummy_file.o
).
Things then work fine!!
scanf
, I get
guile> (require 'scanf) ;;; loading scanf... ;;; ...COULD NOT LOAD scanf from ("" "/packages/lib/gls/bootstrapping/" "/packages/lib/gls/" "/packages/lib/slib/") ERROR: missing CATCH throw: (could-not-load scanf ("" "/packages/lib/gls/bootstrapping/" "/packages/lib/gls/" "/packages/lib/slib/")) ;;; ABORT executed. ;Evaluation took 140 mSec (40 in scm_gc) 7220 cells work, 831 bytes other
tcl-lambda
problem was fixed, but another introduced. That's
fixed in r0.4.
BELOW HERE REFERS TO r0.2
=======================================================
Note: this is the r0 release I picked up on March 29 1996; I am not clued in to the release nomenclature, but I thought it was important to call it r0.2 because version r0 has changed around a few times already.
It is OK to have `..' references in the build tree, but the install
tree should just have #include <threads/whatever.h>
instead.
gcc -g -I. -I. -I./../mesa/include -I./../glut -I./../libguile -I../libguile -I/packages/include -L../glut -L../mesa/src -L../mesa/src-glu -L../libguile -o ggl glconsts.o glfns.o glutconsts.o glutfns.o glinvoke.o gglmain.o ../libguile/libguile.a ../threads/libthreads.a -lm -lglut -lMesaGLU -lMesaGL -lSM -lICE -L/packages/lib -lXmu -lX11 -lnsl -lXext collect2: ld returned 1 exit status /bin/../lib/ld: Unresolved: XInitExtension XESetWireToEvent XESetEventToWire XESetCreateGC XESetCopyGC XESetFlushGC XESetFreeGC XESetCreateFont XESetFreeFont XESetCloseDisplay XESetError XESetErrorString gmake[1]: *** [ggl] Error 1 gmake[1]: Leaving directory `/nh/toaster/u/rosalia/gnudl/guile-doc/guile-cygnus-960321/ggl' gmake: *** [all] Error 1 <82 hotspec->guile-cygnus-960321>
Note: we have our own X11R6 installation in /packages/lib/lib*.a
Ugly hackaround: manually reverse the order of -lX11 and -lXext, so that -lX11 comes after. Seems to work. You might also have to take out -lns.
gcc -DPACKAGE=\"gtcltk\" -DVERSION=\"0.01\" -DHAVE_ALLOCA_H=1 -DHAVE_ALLOCA=1 -I. -I. -DSCM_MAGIC_SNARFER -I./../libguile -I../libguile -I./../tcl/generic -I./../tk/generic -DI18N -DKANJI \ -g -O -I/packages/include -E guile-tk.c \ | grep "^%%%" | sed -e "s/^%%%//" > guile-tk.x gcc -c -DPACKAGE=\"gtcltk\" -DVERSION=\"0.01\" -DHAVE_ALLOCA_H=1 -DHAVE_ALLOCA=1 -I. -I. -I./../libguile -I../libguile -I./../tcl/generic -I./../tk/generic -DI18N -DKANJI -g -O -I/packages/include guile-tk.c rm -f libgtcltk.a ar cru libgtcltk.a guile-tcl.o guile-tk.o ranlib libgtcltk.a No suffix list. don't know how to make all (bu42). *** Error code 1 (bu21)
This one seems to be caused by using make instaed of gmake. Hackaround: use gmake instead of make. It is still a bug because things should compile with make.
gcc -c -g -Wall -I. -I. -DLIBRARY_PATH=\"/packages/lib/\" -DIMPLINIT=\"/packages/lib/gls/bootstrapping/basic-startup.scm\" -DGUILE -DHAVE_CONFIG_H -DHAVE_CONFIG_H -DI18N extchrs.c extchrs.c:96: conflicting types for `scm_num_mbfuns' extchrs.h:95: previous declaration of `scm_num_mbfuns' extchrs.c:107: conflicting types for `xmblen' extchrs.h:110: previous declaration of `xmblen' extchrs.c:146: conflicting types for `xmbtowc' extchrs.h:112: previous declaration of `xmbtowc' gmake[1]: *** [extchrs.o] Error 1 gmake[1]: Leaving directory `/a/toaster/root/packages-root/.packages/guile/guile-r0.2/src/libguile' gmake: *** [all] Error 1
The problem is that somehow the type sizet
must get defined
differently in `extchrs.c' and `extchrs.h'.
ugly hackaround: I went in and did a bogus replacement of
sizet
with int
, and it compiles. It's probably OK.
rm -f libguile.a ar rc libguile.a arbiters.o boolean.o chars.o continuations.o debug.o dynwind.o eq.o error.o eval.o extchrs.o feature.o fports.o files.o gc.o genio.o gscm.o gsubr.o hash.o kw.o lvectors.o marksweep.o mbstrings.o numbers.o pairs.o ports.o print.o procs.o ramap.o read.o repl.o scmsigs.o simpos.o smob.o stackchk.o strings.o strop.o strports.o struct.o symbols.o stime.o throw.o unif.o variable.o vectors.o vports.o weaks.o ranlib libguile.a gmake[1]: Leaving directory `/nh/toaster/packages-root/.packages/guile/guile-r0.2/src/libguile' gmake[1]: Entering directory `/nh/toaster/packages-root/.packages/guile/guile-r0.2/src/ctax' lex ./ctax-lex.l "./ctax-lex.l":line 72: Warning: undefined string "./ctax-lex.l":line 82: Error: syntax error "./ctax-lex.l":line 82: Error: Illegal rule "./ctax-lex.l":line 132: Error: illegal extra "}" gmake[1]: *** [ctax-lex.c] Error 1 gmake[1]: Leaving directory `/nh/toaster/packages-root/.packages/guile/guile-r0.2/src/ctax' gmake: *** [all] Error 1
The problem is that lex does not grok ctax-lex; I installed flex and it seems to work. Maybe it would be nice if ctax-lex.l were written to work with traditional lex.
gmake[1]: Entering directory `/nh/toaster/packages-root/.packages/guile/guile.2/src/glut' gcc -c -g -I. -I. -I./../mesa/include -I/packages/include glut_input.c In file included from glut_input.c:14: /packages/include/X11/extensions/XInput.h:60: XI.h: No such file or directory gmake[1]: *** [glut_input.o] Error 1 gmake[1]: Leaving directory `/nh/toaster/packages-root/.packages/guile/guile-2/src/glut' gmake: *** [all] Error 1
Our X11R6 installation on solaris2 is not perfect, so maybe that's the problem. Ugly hackaround: in any case I copied XInput.h and then XI.h (required by XInput.h) from a linux box (I d
tcl-lambda ()
seems to have a problem in defining menu buttons.
The `learn-guile-3.scm' example of using Tk widgets identifies this
pretty well. The last tcl-lambda () command in any menu item gets
applied to *all menu items* from *all menus*.
I don't yet have a hackaround.
I feel that a few things have not been treated here; either they were missing in the outline, or I don't know much about them. I would like to add them eventually.
Ggl, mesa and glut: Guile has an interface to SGI's Open GL library, using the free GL clone "mesa". This also works with the glut toolkit. There is no documentation; I will have to study the code.
ctax: Ctax is a C-like syntax for scheme, provided as one of the plugin modules for Guile. It would be nice to show examples of ctax, and examples of how to switch from one language to another as you fancy.
threads: Threads are as trendy as applets, and are used in the applet formalism of Guile. What is the interface to threads from C and from scheme?