EusLisp compiler is used to speed the execution of Lisp programs. You can expect 5 to 30 times faster execution and notable reduction of garbage collection time elapsed by macro expansion.
Euscomp does optimization for arithmetic operation and vector access. Sometimes proper type declarations are needed to inform the compiler applicability of optimization.
Compile-function compiles functions one by one. Compile-file compiles an entire source file. During the execution of Compile-file, each form in a file is read and evaluated. This may change the current EusLisp environment. For examples, defparameter may set a new value to a symbol and defun may substitute the existing compiled function with its non-compiled version. To avoid these unexpected effects, use the eval-when special form without compile time situation, or use euscomp command to run the compiler as a separate process.
Euscomp is a unix command, which is usually a symbolic link to eus. It recognizes several options. -O flag indicates optimization of the C compiler. Each of -O1,-O2, -O3 indicates optimization level of EusLisp compiler, which is equivalent to proclaiming (optimize 1 or 2 or 3). Each of -S0, -S1, -S2, -S3 set 0,1,2 and 3 to compiler:*safety*. If *safety* is less than 2, no code for checking interrupt is emitted, and you will lose control if the program enters an infinite loop. If *safety* is zero, the number of required arguments is not checked. -V flag is used to print function names when they are compiled (verbose). -c flag prevents from forking and exec'ing cc. -D pushes next argument to the *features* list, which can be used for conditional compilation in conjunction with #- and #+ read-macro.
The compiler translates EusLisp source program named as "xxx.l" into the intermediate C program file named "xxx.c" and the header file named "xxx.h". Then the C compiler is run and "xxx.o" is generated. Intermediate files "xxx.c" and "xxx.h" are left for the purpose of cross compilation: usually you only need to compile "xxx.c" files by cc unix command when you wish to use the code on machines of different architecture. Compiled code is loaded to EusLisp by '(load "xxx")'.
Each intermediate file refers to the "eus.h" header file, which is supposed to be located in the *eusdir*/c directory. *eusdir* is copied from the EUSDIR environment variable. If none is set, /usr/local/eus/ is taken as the default directory.
When compiled, intermediate C programs are usually much bigger than the original source code. For example, 1,161 lines of "l/common.l" lisp source expands to 8,194 lines of "l/common.c" and 544 lines of "l/common.h". Compiling 1,000 lines of lisp source is not a hard task, but optimized compililation of nearly 10,000 lines of C program not only takes long time (several minutes), but also consumes much disk space. So if you are compiling relatively big programs, be sure your machine has sufficient /var/tmp disk, otherwise CC may die. Setting the TEMPDIR environment variable to a bigger disk slice may help.
As the linkage is performed at load-time or at run-time, no recompilation is required even the eus kernel is updated. On the other hand, run-time linkage may impose you another inconvenience. Suppose you have two functions A and B in a file "x.l" and A calls B. After compiling "x.l", you load "x.o" and tries to call A which internally calles B. Then you find a bug in B, and probably you would redefine B. Here, you have compiled A and non-compiled B. You may call A again, but nothing will change, since A still calls old compiled B which is linked regidly when A first called B. To avoid this problem, A must be redefined again, or B must be redefined just after "x.o" is loaded and before A is called.
When a compiled-code is loaded, its top level code, which is normally a series of defun, defmethod, etc., is excuted. This top level code is defined as the entry function of the load module. The compiler names the entry function, and the loader has to know the exact name of this function. To make the situation simple, both the compiler and the loader assume the entry function name is identical to the basename of the object file. For example, if you are compile and load "fib.l", the compiler produce "fib(...)" as the entry function of "fib.c", and the loader looks for "fib" in the "fib.o" object file. Since the final object file is produced by "cc" and "ld" of unix, this entry function name has to satisfy the naming rule of C functions. Therefore, you have to avoid C's reserved keywords such as "int", "struct", "union", "register", "extern", etc., or the private identifiers defined in "c/eus.h" such as "pointer", "cons", "makeint", etc., to be used as the name of the file. If you have to use one of these reserved words as the name of the source file, you specify it for :entry arguments of the compiler and the loader.
A restriction exists for the usage of closure: return-from special form in closures and clean-up forms in unwind-protect is not always correctly compiled.
Disassemble is not implemented. In order to analyze compiled code, see the intermediate C program or use adb.
euscomp {filename}* [unix-command]
compile-file-if-src-newer srcfile &key compiler-options [function]
k-okada 2013-05-21