Go to the first, previous, next, last section, table of contents.

Embedding Compiled Routines Inside Yorick

(Very preliminary notes. Not heavily tested either. See the distribution Drat and MathC, and Math directories for examples.)

You can create a custom version of Yorick containing your own C or Fortran compiled code. If you are careful, your custom version will be easily portable to any site where Yorick has been installed. You will considerably ease portability problems (read "future hassles for yourself") by writing in C, which is a portable language, as opposed to Fortran, which is not.

If you do choose Fortran, stick to a strict subset of ANSI Fortran 77, in which you do not attempt to pass character variables into or out of interface routines, nor put them in common blocks. Also, try not to use common blocks to pass inputs to or receive outputs from your interface routines.

Whether you write in Fortran or C, do not attempt to do I/O of any sort in your compiled code. The whole idea of embedding routines inside Yorick is to let Yorick handle all I/O -- text and graphics.

In order to build a custom Yorick, you need to find the Yorick home directory `Y_HOME' on the platform where you will be compiling. You may need to ask whoever installed Yorick where this is. If Yorick was installed as recommended, the home directory will be the `yorhome' sibling of the `bin' directory from which Yorick was launched. The name of Yorick's launch directory is contained in the Y_LAUNCH variable; start Yorick on the machine where you will be compiling and type Y_LAUNCH to print this name.

Make a directory in which to build your custom version of Yorick, and put your C and/or Fortran source files there. Copy `Y_HOME/Maketmpl' into that directory, change its name to "Makefile", and modify its first section to tell make how to compile your source code.

You next need to write a Yorick include file which will be loaded whenever your custom Yorick starts. This file is read not only by Yorick when it starts, but also by the Codger automatic wrapper code generator when you make the custom version. Codger generates a table of all of the compiled objects (functions, global variables, or Fortran common blocks) which can be referenced from the interpreter. It will also generate wrapper code to call your compiled functions, if you decide not to do this yourself. In this include file:

extern my_func;
/* DOCUMENT my_func(input)
     returns the frobnostication of the array INPUT.
 */

connects my_func to a compiled function Y_my_func of type BuiltIn, which you are responsible for writing. See `Y_HOME/ydata.h' for the definition of the BuiltIn function type. This function must pop its arguments off of Yorick's interpreter stack using routines declared in `Y_HOME/ydata.h', and push its result back onto the stack. If you want codger to generate `Y_my_func' for you automatically, do this instead:

func my_func(input)
/* DOCUMENT my_func(input)
     returns the frobnostication of the array INPUT.
 */
{
  return my_func_raw(input, numberof(input));
}
extern my_func_raw;
/* PROTOTYPE
   double my_func_C_name(double array input, long length)
 */

This generates a wrapper for a C function which takes a single array as input and returns a scalar result. If the function had been Fortran, it would have looked like this (Fortran passes all arguments by reference -- that is, as if they were arrays):

func my_func(input)
/* DOCUMENT my_func(input)
     returns the frobnostication of the array INPUT.
 */
{
  return my_func_raw(input, numberof(input));
}
extern my_func_raw;
/* PROTOTYPE FORTRAN
   double my_func_Fortran_name(double array input, long array length)
 */

Legal data types for the function return result in the PROTOTYPE comment are: void (i.e.- a subroutine), char, short, int, long, float, or double.

Legal data types for the function parameters in the PROTOTYPE comment are: void (only if there are no other parameters), char, short, int, long, float, double, string (char *, guaranteed 0-terminated), or pointer (void *). These may be followed by the word "array", which becomes "*" in the C source code, to indicate an array of that type. The parameter name is optional.

The DOCUMENT comment should start with /* DOCUMENT. They will be returned by the interpreted command help, my_func, and be included in the poor- man's document produced by Yorick's "mkdoc" command (see `Y_HOME/include/mkdoc.i').

extern my_global;
reshape, my_global, datatype;

attaches the interpreted variable my_global to a C-compiled global of the same name, which has the data type datatype (this must have been declared in a previous struct or be one of the primitive types). If you want my_global to be attached to a global variable of a different name, use:

extern my_global;
/* EXTERNAL my_global_C_name */
reshape, my_global, datatype;

To attach to a Fortran common block, say

	double var1, var2, var3
	common /my_common/ var1, var2, var3
	save /my_common/

(note that this doesn't make sense unless the common block is saved outside the scope of the functions in which it is used) use:

struct my_common_type { double var1, var2, var3; }
extern my_common;
/* EXTERNAL FORTRAN my_common */
reshape, my_common, my_common_type;

If you mix double, integer, and real data in a single common block, you can ensure that you won't have any alignment difficulties by putting all the doubles first, followed by integers and reals. If you don't do this, you're relying on the existence of a Fortran compiler switch which forces proper data alignment -- some machine someday won't have this.

If you've done it right, to port your code to another machine, you just move your source directory, change Y_HOME in the Makefile to point to the public Yorick directory on the new machine, type "make Makefile" to stuff the correct compiler options into the second part of the Makefile (the part you didn't write), then type "make" to build your code on the new machine.


Go to the first, previous, next, last section, table of contents.