6. CLush: Compiled Lush

Author(s): Leon Bottou, Yann LeCun

[under construction]

One of Lush's most interesting features is its Lisp-to-C compiler and the ability to freely intermix Lisp and C code in a single function. Unlike many other interpreted/compiled languages, and contrary to many well established principles of language design, the two dialects that the Lush interpreter and the Lush compiler implement are two very different languages, though they share the same syntax. The compiled dialect is strongly typed, lexically bound, and has no garbage collector, while the interpreted dialect has loose typing, is dynamically bound, and is garbage collected.

In fact, the Lush compiler is not designed to replace the interpreter, but rather to complement it. Lush applications are generally a combination of compiled and interpreted code. The compiled part is often itself a combination of Lush and C code. The compiled code will generally contain the "expensive" and heavily numerical parts of an application, where performance is the main requirement, while the interpreted part will contain the high-level logic, the user interface, the memory management, etc, where flexibility is more important than pure performance.



6.0. A Simple Example


[under construction]

Numerous examples of compiled functions with and without in-line C-code are available in the libraries (in directories lsh and packages).



6.1. Using libload and dhc-make


Lush contains convenient functions that implement capabilities similar to make. Properly using these functions ensures that the Lush interpreter loads the most recent version of the functions as necessary, and that all functions are judiciously recompiled when functions they call have been redefined.

Users should just follow the following four rules:


See: (libload libname [ opt ])
See: (dhc-make fname fspec1 ... fspecN )


6.2. Compilation Functions




6.2.0. High-Level Compilation Functions




6.2.0.0. (dhc-make fname fspec1...fspecN)
[DM] (lsh/compiler/dh-compile.lsh)


Function dhc-make controls the compilation of classes and functions specified by the fspecs arguments.

Although this function can be used from the command line, it mostly is used within a Lush file to control the compilation of classes and functions defined in this file. We will assume now that dhc-make is invoked from a Lush file.

The first argument fname is either the empty list or a string representing filenames of the C and object files output by the Lush compiler.

Each of the following arguments fspec is either a function name or a list composed of a class name and method names. The following example, for instance, first compiles function foo , then compiles methods rectangle and area of class rectangle , and finally compiles function bar .
        (dhc-make () 
                  foo 
                  (rectangle rectangle area)
                  bar )
The order of the fspec arguments is important because no function, class or method can be compiled before compiling all functions, classes, or methods it references. This order can be different from the function and class definition order in the Lush file.

Before starting the compilation, function dhc-make tests whether the target files already exist and are up-to-date:

The C file will be generated if any of the following conditions is true.

The object file will be generated if any of the following conditions is true:

Finally dhc-make performs a mod-load of the object file and checks that the compiled functions are now executable. It returns the name of the object file.

Note: Function dhc-make can also be invoked from the command line. When this is the case, it always generates fresh C and object files, and derives their names from the last fspec argument.



6.2.0.1. (dhc-make-with-libs fname libs fspec1...fspecN)
[DM] (lsh/compiler/dh-compile.lsh)


See: (dhc-make fname fspec1 ... fspecN )
This function is similar to dhc-make but takes an additional argument libs to handle cases where the compiled functions depend on external C libraries. This argument can take two values:



6.2.0.2. (dhc-make-with-c++ fname libs fspec1...fspecN)
[DM] (lsh/compiler/dh-compile.lsh)


See: (dhc-make fname fspec1 ... fspecN )
See: (cinline format var1 ... varn )


This function is similar to dhc-make-with-libs but uses the C++ compiler instead of the C compiler to generate the object file. This makes no difference except that one can use C++ constructs when inlining C code with cinline . This is particularly handy when interfacing external C++ libraries.



6.2.0.3. (dhc-make-all fname fspeclist libs)
[DE] (lsh/compiler/dh-compile.lsh)


See: (dhc-make fname fspec1 ... fspecN )
See: (dhc-make-with-libs fname libs fspec1 ... fspecN )


This is the elementary function called by dhc-make , dhc-make-with-libs and dhc-make-with-c++ .

Argument fspeclist is a list containing the fspec1 ... fspecN arguments of function dhc-make . Argument fname is similar to the fname argument of functions dhc-make or dhc-make-with-libs . Argument libs is similar to the libs argument of function dhc-make-with-libs .



6.2.1. Customizing the Behavior of dhc-make


The following variables control the behavior of dhc-make .



6.2.1.0. dhc-make-force
[VAR] (lsh/compiler/dh-compile.lsh)


Setting this variable to a non null value forces the recompilation of all files, even when they have not been modified.

The following example, for instance, forces the compilation of functions foo and bar .

(let ((dhc-make-force t))
   (dhc-make () (foo bar)) )


6.2.1.1. dhc-make-lushflags
[VAR] (lsh/compiler/dh-compile.lsh)


This variable contains a string containing the compilation flags for invoking the C or C++ compiler. The following example, for instance, insert additional options "-w -DMMX" for the C compiler:
 (let ((dhc-make-lushflags (concat dhc-make-lushflags " -w -DMMX")))
    (dhc-make () (foo bar)) )

The initial value is derived from the Makefile variable LUSHFLAGS . It might reference other predefined varibales prefixed with character $ . These variables are expanded using dhc-substitute-env .



6.2.1.2. dhc-make-command
[VAR] (lsh/compiler/dh-compile.lsh)


This variable is a string containing the command for generating object files. Variables prefixed with $ will be expanded using dhc-substitute-env . Four additional variables are defined:
See: (find-c-include name )




6.2.1.3. dhc-make-overrides
[VAR] (lsh/compiler/dh-compile.lsh)


This variable contains an a-list of additional variable definitions for interpreting dhc-make-lushflags and dhc-make-commands . Definitions provided in dhc-make-overrides take precedence over the defaults provided by Lush.

The following example, for instance, invokes the C++ compiler instead of the C compiler:

(let ((dhc-make-overrides 
         (cons (cons "CC" (dhc-substitute-env "$CXX")) dhc-make-overrides) ))
  (dhc-make () (foo bar)) )


6.2.2. Querying File Dependencies


The following functions can be used to determine whether dhc-make will invoke the compiler.



6.2.2.0. (dhc-make-get-dependencies [lushfile])
[DE]


Returns the list of Lush files on which file lushfile is dependent. These are the files directly or indirectly loaded using libload . When argument lushfile is not provided, file-being-loaded is assumed.



6.2.2.1. (dhc-make-test fname)
[DE]


This function tests whether a subsequent invocation of dhc-make with the same fname argument needs to generate a new version of the C file. When there is no need to generate a new C file, function dhc-make-test makes sure that the object file is up-to-date and returns the name of the object file. Otherwise it returns the empty list.

This function is useful to avoid processing long files when we are only interested in precompiled functions. See "packages/lapack/lapack-s.lsh" for an example.



6.2.3. Low-Level Compilation Functions


Most users will rarely use the functions described in this section, but they come in handy in certain cases.



6.2.3.0. (dhc-make-o-filename src)
[DE]


Returns a suitable filename for the object file



6.2.3.1. (dhc-generate-c filename '([func1 [funcn]]))
[DE]


Translate lisp functions and classes func1 ... funcn to C code and produces a source file suitable for a file named filename . Argument filename should be provided without the ".c" suffix and must be a legal C identifier as it is used for the initialization function in the C code.



6.2.3.2. (dhc-substitute-env str [htable])
[DE]


Returns a copy of string str after substituting all environment variables. Substitution values are searched in htable when available, then passed to functions getconf and getenv .



6.2.3.3. (dhc-make-c fname fsymblist)
[DE]


Compile functions or classes fsymblist into a new source file fname . Argument fname must be provided without the ".c" suffix.



6.2.3.4. (dhc-make-o src-file [obj-file [lushflags]])
[DE]


Compile C source file src-file generated by the dh compiler into object file obj-file . Argument lushflags is an optional string containing compiler options.



6.2.3.5. (dhc-make-c-maybe snname fname fsymblist)
[DE]


Compile functions or classes fsymblist producing the file fname . Argument fname must be provided without the suffix ".c". Compilation will only occur if the existing fname was created before the file snname or any file loaded from snname using libload .



6.2.3.6. (dhc-make-o-maybe src-file [obj-file [cflags]])
[DE]


Same as dhc-make-o but only recompiles if source file is newer than object file



6.3. Design Philosophy


The design philosophy of the Lush compiler is somewhat unusual, and, admitedly, in stark violation of many commonly accepted principles of good programming language design. First, The Lush compiler is not designed to replace the interpreter, but to complement it. Lush applications are often a combination of compiled code for things where performance takes precedence over flexibility (e.g. "expensive" and heavily numerical functions), and interpreted code for things where flexibility takes precedence over performance (high-level logic, user interface, memory management).

Therefore, the Lush compiler is designed to generate very efficient code (practically as good as its C equivalent), but has limitations as to what it can and cannot compile. What that means for the programmer is that, although the compiled and interpreted Lush dialects use the same syntax, they are really two different languages. From now on, the compiled Lush dialect will be called CLush, while the interpreted Lush dialect will be called simply Lush.

This deliberate difference between the two dialects allows all kinds of really juicy hacks (with no performance penalty), that would be difficult to achieve if the two dialects were identical by design. Within a single program you can simultaneously have in-line C code in the compiled part, run-time construction of code in the interpreted part (including run-time self modifying expressions like DMD splicing macros) with no hidden performance penalty.

The main differences between Lush and CLush are as follows:



6.4. What is Compilable, and What is Not


[under construction]

There is a simple test to determine if a particular function is compilable or not: (compilablep func ). This may returns 'yes , 'maybe or () . The value 'maybe is returned when the argument is a macro whose compilability cannot be determined without expansion.

Basically the kinds of things that can be compiled by the CLush compiler are the kinds of things that you expect to be compilable in a "conventional" language like C. All the really "Lispish" stuff like eval , lambda , etc is not compilable (those things don't exist in C).

There are three types of things that cannot be compiled:



6.4.0. (compilablep function)
[DE]


Tests if a function is compilable. Returns t, maybe or (). The value 'maybe is returned when the argument is a macro whose compilability cannot be determined without expansion.



6.5. CLush Specific Functions and Constructs




6.5.0. Numerical Type Declarations




6.5.0.0. ((-double-) var1 ... varn)


declare double precision floating point variables.



6.5.0.1. ((-float-) var1 ... varn)


declare single precision floating point variables.



6.5.0.2. ((-int-) var1 ... varn)


declare integer variables (32 bits).



6.5.0.3. ((-short-) var1 ... varn)


declare short integer variables (16 bits).



6.5.0.4. ((-byte-) var1 ... varn)


declare signed byte variables (8 bits).



6.5.0.5. ((-ubyte-) var1 ... varn)


declare unsigned byte variables (8 bits).



6.5.0.6. ((-str-) var1...varN)


declare character string variables.



6.5.0.7. ((-gptr- [spec]) var1 ... varn)


This declares the symbols var1 ... varn as C-style pointers. In the absence of a spec the pointers will be equivalent to universal pointers ( void * ). An optional string spec can be specified to explicitely declare the C type of the pointer. Examples:
  ((-gptr- "int *") integer-pointer)
  ((-gptr- "FILE *") file-pointer)
  (cpheader "<my_header_file.h>")
  ((-gptr- "MyObjectType *") myobject-pointer)

Argument spec may also be a list containing a Lisp class name. This will define the type of the variable as a pointer to the C version of that class. Example:

  ((-gptr- (myclass)) myclass-pointer)

The C type of myclass-pointer will be "struct CClass_myclass *" .



6.5.0.8. ((-obj- (class)) var1...varN)


This syntax declares the variables var1 ... varN as being instances of the class class .



6.5.0.9. ((-idx0- (type)) var1...varN)


This syntax declares the variables var1 ... varN as idx0 (scalars) of type type , where type is one of the Lush numerical types (-ubyte-, -double-, -float-, etc).



6.5.0.10. ((-idx1- (type)) var1...varN)


This syntax declares the variables var1 ... varN as idx1 (vector) of type type , where type is one of the Lush numerical types (-ubyte-, -double-, -float-, etc).



6.5.0.11. ((-idx2- (type)) var1...varN)


This syntax declares the variables var1 ... varN as idx2 (matrix) of type type , where type is one of the Lush numerical types (-ubyte-, -double-, -float-, etc).



6.5.0.12. ((-idx3- (type)) var1...varN)


This syntax declares the variables var1 ... varN as idx3 (3-tensor) of type type , where type is one of the Lush numerical types (-ubyte-, -double-, -float-, etc).



6.5.0.13. ((-idx4- (type)) var1...varN)


This syntax declares the variables var1 ... varN as idx4 (4-tensor) of type type , where type is one of the Lush numerical types (-ubyte-, -double-, -float-, etc).



6.5.0.14. ((-idx5- (type)) var1...varN)


This syntax declares the variables var1 ... varN as idx5 (5-tensor) of type type , where type is one of the Lush numerical types (-ubyte-, -double-, -float-, etc).



6.5.0.15. ((-idx6- (type)) var1...varN)


This syntax declares the variables var1 ... varN as idx6 (6-tensor) of type type , where type is one of the Lush numerical types (-ubyte-, -double-, -float-, etc).



6.5.0.16. ((-idx7- (type)) var1...varN)


This syntax declares the variables var1 ... varN as idx7 (7-tensor) of type type , where type is one of the Lush numerical types (-ubyte-, -double-, -float-, etc).



6.5.1. Class Declaration and Compilation


Classes can be compiled with some restrictions. In short:

Here is an example of compiled class declaration syntax (taken from packages/gblearning/modules.lsh ):

(defclass mle-cost sn-module
  ((-obj- (logadd-layer)) logadder)
  ((-obj- (idx1-ddstate)) logadded-dist)
  ((-idx1- (-int-)) label2classindex))
Essentially, the type of each slot must be declared using the same syntax as parameters of a function.

Compiling a class with dhc-make and its variants is done by passing a list whose first element is the class name and the remaining elements are the methods to be compiled. Here is an example:

  (dhc-make ()
    (sn-module)
    (mle-cost mle-cost fprop bprop bbprop))
It is not required to compile all the methods of a class. A compiled class can have a mixture of compiled and non-compiled methods.



6.5.2. Type Conversions


Functions are provided to convert objects from one type to another. Their behavior is somewhat different in interpreted and compiled mode.



6.5.2.0. Numerical Type Conversions


These functions convert one numerical or object type to another. In compiled mode, they behave like C casts. In interpreted mode, the argument is casted to the corresponding C type, and then converted back to double since double is the only numerical type manipulated by the interpreter.



6.5.2.0.0. (to-int arg)
[DX]


Casts arg into an integer.



6.5.2.0.1. (to-float arg)
[DX]


Casts arg into a single precision number.



6.5.2.0.2. (to-double arg)
[DX]


Casts arg into a double precision number.



6.5.2.0.3. (to-bool arg)
[DX]


Casts arg into a boolean.



6.5.2.0.4. (to-flt arg)
[DX]


Casts arg into a single precision number (deprecated name for to-float).



6.5.2.0.5. (to-real arg)
[DX]


Casts arg into a double precision number (deprecated name for to-double).



6.5.2.1. Non-Numerical Type Conversions




6.5.2.1.0. (to-gptr arg)
[DX]


Casts arg into a GPTR.

In interpreted mode to-gptr simply returns a gptr containing the address the C object associated with the object passed as argument (which can be an index, storage, string, a compiled function, or any object).

This function may not be used to convert an integer (or other numerical types) to a gptr, but merely to obtain the address of an object.

In compiled mode, it is useful to know that a gptr does not carry enough information to allow the compiler to determine when the corresponding object must be released. The following function is a sure looser:

   (de never-do-this()
       (gptr (new myclass)) )

The compiler cannot understand that the object created by new is returned as a Gptr and may be used outside this function. The object is freed before returning, making the gptr useless. To prevent this, the object should be allocated in a pool using in-pool from lsh/libstd/dynamic.lsh .



6.5.2.1.1. (to-obj [class] arg)
[DX]


Casts arg into an object of class class . Argument arg must be a gptr or an object. Argument class is mandatory in compiled mode.



6.5.3. Inline C Code


CLush allows to freely intermix Lisp and C code within a single function. This can be done in several ways, the simplest of which is the "hash-brace" construct.



6.5.3.0. Hash-Brace Construct


The macro character pair #{ c-code #} allows easy embedding of C code inside a Lisp function. The embedded C code is delimited by #{ and #} . Functions containing hash-brace segments cannot be executed by the interpreter and must be compiled.

Any C code can be written within a hash-brace construct. Lisp expressions and variables can be evaluated and refered to in the Lisp code by preceding them with a dollar sign.

Examples:

 [under construction]
 [insert juicy hash-brace examples here]
The hash-brace macro calls the lower-level compiler macro cinline .

Example:

 (de add-to-integer( intg arg )
   ((-int-) intg arg)
   #{ $intg += $arg; #}
   intg )

expands to:

 (de add-to-integer (intg arg)
   ((-int-) intg arg)
   (cinline " %s += %s; " intg arg)
   intg )

See: (cinline format [ arg1 [ arg2 ... [ argn ]]])



6.5.3.1. C Directives and Macros




6.5.3.1.0. (cpheader string)
[DE]


This directive can be used to insert a line in the C file generated by the CLush compiler. This is primarily used to include header files or to define macros. Examples:
  (cpheader "#include <stdio.h>")

The lines are inserted at the beginning of the C file, before all the Lush header files.



6.5.3.1.1. (cheader string)
[DF]


Same as cpheader , but inserts the lines after the Lush header files instead of before.



6.5.3.1.2. (ccall string)
[DE]


Call a C function. This is somewhat obsolete. Most users will prefer the hash-brace construct.



6.5.3.1.3. (cinline format var1...varn)
[DF]


Insert C code in the C file generated by the Lush compiler. The format is an printf-like format where instances of "%s" are substituted by the C name of the lisp variables var1 ... varn . Example:
  ;; set element 2 of v to x.
  (de choucroute (v x) 
    ((-idx1- (-int-)) v) 
    ((-double-) x)
    (cinline "(IDX_PTR(%s,int))[2] = (int)(%s);" v x) ())
The C function generated by the Lush compiler looks like this:
    extern_c char
    C_choucroute (struct idx *L1_v, real L1_x)
    {
      TRACE_PUSH ("C_choucroute");
      {
        (IDX_PTR (L1_v, int))[2] = (int) (L1_x);
        TRACE_POP ("C_choucroute");
        return 0;
      }
    }
Function cinline is rarely used, as most users will prefer to use the hash-brace construct.



6.5.3.2. Locating Include Files and Libraries




6.5.3.2.0. c-include-path
[VAR] (sysenv.lsh,)


See: (find-c-include name )
See: dhc-make-command


This variable is initialized by the Lush startup code and contains a list of directories containing potential include files. Include files along this path can be searched using function find-c-include .

Furthermore, the compilation command, defined by variable dhc-make-command , typically uses the macro "$INCS" to specify all these directories to the compiler. Appending directories to c-include-path is then the easiest way to handle additional directories for include files.



6.5.3.2.1. shared-library-path
[VAR] (sysenv.lsh,)


See: (find-shared-library name [ extlist ])


This variable is initialized by the Lush startup code and contains a list of directories containing potential shared libraries. Function find-shared-library should be used to locate libraries located along this path, or in standard system locations.



6.5.3.2.2. static-library-path
[VAR] (sysenv.lsh,)


See: (find-static-library name [ extlist ])


This variable is initialized by the Lush startup code and contains a list of directories containing potential shared libraries. Function find-static-library should be used to locate libraries located along this path.



6.5.3.2.3. (find-c-include name)
[DE] (sysenv.lsh)


Returns the pathname of a C include file named name . Include files are searched in the directories specified by variable c-include-path which is initialized by "lushenv.lsh" .
? (find-c-include "stdio.h")
= "/usr/include/stdio.h"

Here is an example of how to use find-c-include to precompute an include file:
  (libload "libc/constants")
  (defconstant qqq (sprintf "#include \"%s\"" (find-c-include "stdio.h")))
  = "qqq"
  ? (de asd () (cpheader @qqq) #{ printf("asd\n") #} ())
  = asd
  ? (dhc-make "junk" asd)



6.5.4. Compiler Directives




6.5.4.0. (ifcompiled compiled-expr interpreted-expr)
[DM]


This allows to execute different codes in interpreted mode and in compiled mode.



6.5.4.1. (ifdef symb expr1 expr2)
[DM]


[under construction]



6.5.4.2. #@expr
[DMC]


Expressions prefixed by #@ are not evaluated unless dhc-debug-flag is set to t . This can be used to insert debugging code.



6.5.4.3. dhc-debug-flag
[VAR]


Turns on execution of code prefixed with |#@|



6.5.5. Dynamic Allocation in Compiled Code


[under construction] This will eventually become a tutorial on how to use the pool class defined in libstd/dynamic.lsh . The reference manual for dynamic.lsh is available in the standard library section of this manual.
See: Dynamic Allocation with Pools.




6.6. Interfacing Existing C/C++/FORTRAN Libraries to Lush


[under construction]



6.6.1. Interfacing C/C++ Code


Using Lush's inline C capability and the mod-load function, interfacing existing C code to Lush is extremely simple.



6.6.1.0. Calling C/C++ functions defined in a library


If the code is available as a dynamic library libasd.so or a static library libasd.a , one merely needs to include the library and the header file in a call to dhc-make-with-libs . Let's assume that our library defines a function cblah that we would like to call in a Lush function blah . Here is an example:
 (de blah (x) ((-double-) x) (to-double #{ cblah($x) #}))

 (dhc-make-with-libs ()
   '("libasd.so")
   #{ #include <asd.h> #}
   blah)
This will only work if libasd.so is in the system's library search path, and if asd.h is in the standard header file search path.

Let's say that libasd.so and asd.h were placed in the same directory as our Lush file, we can do the following:

 (de blah (x) ((-double-) x) (to-double #{ cblah($x) #}))

 (libload "libc/make")
 (let* ((current-dir (dirname file-being-loaded))
        (dhc-make-lushflags (concat dhc-make-lushflags (sprintf " -I%s" current-dir))))

   (dhc-make-with-libs ()
     (list (concat current-dir "/libpng.so"))
     #{ #include "asd.h" #}
   blah))



6.6.1.1. Calling C/C++ functions defined in an object file


If the code is available as an object file /wherever/asd.o , one merely needs to do (mod-load "/wherever/asd.o") . The C functions and global variables defined in asd.o are automatically visible from inline C code in Lush.

Here is a simple example of a Lush file that dynamically loads asd.o and defines a function blah that calls the C function cblah defined in asd.o :

 (de blah (x) ((-double-) x) (to-double #{ cblah($x) #}))
 
 (mod-load "/wherever/asd.o")
 (dhc-make ()
   #{ double cblah(double); #}
   blah)

Rather than explicitely defining the C prototype of cblah in the dhc-make call, one may prefer to include the header file asd.h that corresponds to asd.o . This can be done easily:

 (de blah (x) ((-double-) x) (to-double #{ cblah($x) #}))
 
 (mod-load "/wherever/asd.o")
 (dhc-make ()
   #{ #include "/wherever/asd.h" #}
   blah)

Naturally, rather than refering to absolute paths, we may prefer to put asd.o and asd.h in the same directory as our Lush file. In that case, we need to tell Lush and the C compiler where to find everything:

 (de blah (x) ((-double-) x) (to-double #{ cblah($x) #}))
 
 (let* ((current-dir (dirname file-being-loaded))
        (dhc-make-lushflags (concat dhc-make-lushflags (sprintf " -I%s" current-dir))))
   (mod-load (concat current-dir "/asd.o"))
   (dhc-make ()
     #{ #include "asd.h" #}
   blah))
Redefining dhc-make-lushflags like this will add the directory where the Lush file resides to the path in which the C compiler looks for header files.

Naturally, all of this assumes that asd.o has previously been compiled. Lush conveniently provides a "make"-like utility to compile C files and specify dependencies called LushMake (see the corresponding documentation. Using LushMake as shown below will automatically generate asd.o when the Lush file is loaded, whenever asd.c or asd.h have been modified:

 (de blah (x) ((-double-) x) (to-double #{ cblah($x) #}))

 (libload "libc/make")
 (let* ((current-dir (dirname file-being-loaded))
        (dhc-make-lushflags (concat dhc-make-lushflags (sprintf " -I%s" current-dir)))
        (lm (new LushMake current-dir)))
   ;; compile asd.c to asd.o and mod-load asd.o
   (==> lm setflags (sprintf "-I%s" current-dir))
   (==> lm rule "asd.o"  '("asd.c" "asd.h"))
   (==> lm load)

   (dhc-make ()
     #{ #include "asd.h" #}
   blah))

Perhaps the functions defined in asd.o call functions from a library that must be linked-in, say libpng.so . These libraries can easily be added into using dhc-make-with-libs instead of dhc-make :

 (de blah (x) ((-double-) x) (to-double #{ cblah($x) #}))

 (libload "libc/make")
 (let* ((current-dir (dirname file-being-loaded))
        (dhc-make-lushflags (concat dhc-make-lushflags (sprintf " -I%s" current-dir)))
        (lm (new LushMake current-dir)))
   ;; compile asd.c to asd.o and mod-load asd.o
   (==> lm setflags (sprintf "-I%s" current-dir))
   (==> lm rule "asd.o"  '("asd.c" "asd.h"))
   (==> lm load)

   (dhc-make-with-libs ()
     '("libpng.so")
     #{ #include "asd.h" #}
   blah))

If our code in asd.c is written in C++ instead of C, we must replace the call to dhc-make-with-libs with dhc-make-with-c++ .



6.6.2. Interfacing FORTRAN Code


[This section is under construction]

Basically, this works like calling C code. FORTRAN libraries can be loaded



6.8. More on the Lisp-C Interface


[under construction]



6.8.0. DH: the Compiled Function Class




6.8.0.0. (dhinfo-t dhfunc)
[DX]


[under construction]



6.8.0.1. (dhinfo-c dhfunc)
[DX]


[under construction]



6.8.1. Classinfo




6.8.1.0. (classinfo-t class)
[DX]


[under construction]

Similar to the SN3 function but takes a class as argument instead of now obsolete cclass objects.



6.8.1.1. (classinfo-c class)
[DX]


[under construction]

Similar to the SN3 function but takes a class as argument instead of now obsolete cclass objects.



6.8.2. Controling the Lisp/C Interface




6.8.2.0. (lisp-c-map [arg])
[DX]


This function displays the internal data structure of the interface between Lisp and Compiled code. The LISP-C interface maitains a sorted avl tree of all objects currently allocated. This table relates the address of the compiled structure, the type of the structure, the way the object was created and possibly the Lisp representation of this object.

You can redirect the output of this command using function writing .

Example:

? (lisp-c-map)
= 12
? (lisp-c-map ())
  =                L 0x1e29b0 str              "A string for class c1"
 <                 L 0x2f10a0 idx              ::INDEX1:<3>
<                  L 0x2f12e0 obj:c2           ::c2:2f1330
 =                 L 0x2f1370 idx              ::INDEX1:<3>
=                   L 0x2f1c98 srg              ::FSTORAGE:static@2fe820
  =                L 0x2f1e18 str              "A second string for class c1"
 =                 L 0x2ff050 str              "A third string for class c1"
  =                L 0x2ff068 obj:c1           ::c1:2f1b08
=                  L 0x2ff080 idx              ::INDEX1:<3>
  =                L 0x2ff0a8 srg              ::FSTORAGE:static@2fe82c
 =                 L 0x31cb20 obj:c1           ::c1:1e2980
  =                L 0x31cb38 srg              ::FSTORAGE:ram@1e2968:<3>
= 12
The first character describes the position of the entry in the balanced
tree.  The second character tells wether the object was created by LISP (L)
or by compiled code (C) (e.g. Pool). Each entry displays then the address
of the compiled object and the lisp representation of the object. An object
created by C code may have no lisp representation until it is referenced by
a represented object or until the proper GPTR is casted by function <obj>.


6.8.2.1. (lisp-c-dont-track-cside)
[DX]


Restrict the synchronization of the lisp and C data structures in a way similar to previous versions of the system (SN3.x). C objects managed by compiled code will appear as gptrs in Lisp code instead of being translated into equivalent Lisp objects.



6.8.2.2. (lisp-c-no-warnings ..exprs..)
[DY]


Evaluates expressions ..exprs.. like function progn without displaying the usual diagnostic about the synchronization of the lisp and C data structures.



6.9. Compiler Internals




6.9.74. u-nodes


[under construction]