PREV UP next SCM

6.4.1: Finishing Dynamic Linking

Scott Schwartz <schwartz@galapagos.cse.psu.edu> suggests: One way to tidy up the dynamic loading stuff would be to grab the code from perl5.

VMS

George Carrette (gjc@mitech.com) outlines how to dynamically link on VMS. There is already some code in `dynl.c' to do this, but someone with a VMS system needs to finish and debug it.

  1. Say you have this `main.c' program:
    main() {init_lisp();  lisp_repl();}
    
  2. and you have your lisp in files `repl.c', `gc.c', eval.c and there are some toplevel non-static variables in use called the_heap, the_environment, and some read-only toplevel structures, such as the_subr_table.
    $ LINK/SHARE=LISPRTL.EXE/DEBUG REPL.OBJ,GC.OBJ,EVAL.OBJ,LISPRTL.OPT/OPT
    
  3. where `LISPRTL.OPT' must contain at least this:
    SYS$LIBRARY:VAXCRTL/SHARE UNIVERSAL=init_lisp UNIVERSAL=lisp_repl PSECT_ATTR=the_subr_table,SHR,NOWRT,LCL PSECT_ATTR=the_heap,NOSHR,LCL PSECT_ATTR=the_environment,NOSHR,LCL
    

    Notice: The psect (Program Section) attributes.

    LCL
    means to keep the name local to the shared library. You almost always want to do that for a good clean library.
    SHR,NOWRT
    means shared-read-only. Which is the default for code, and is also good for efficiency of some data structures.
    NOSHR,LCL
    is what you want for everything else.

    Note: If you do not have a handy list of all these toplevel variables, do not dispair. Just do your link with the /MAP=LISPRTL.MAP/FULL and then search the map file,

    $SEARCH/OUT=LISPRTL.LOSERS LISPRTL.MAP  ",  SHR,NOEXE,  RD,  WRT"
    

    And use an emacs keyboard macro to muck the result into the proper form. Of course only the programmer can tell if things can be made read-only. I have a DCL command procedure to do this if you want it.

  4. Now MAIN.EXE would be linked thusly:
    $ DEFINE LISPRTL USER$DISK:[JAFFER]LISPRTL.EXE  $LINK MAIN.OBJ,SYS$INPUT:/OPT  SYS$LIBRARY:VAXCRTL/SHARE  LISPRTL/SHARE
    

    Note the definition of the LISPRTL logical name. Without such a definition you will need to copy `LISPRTL.EXE' over to `SYS$SHARE:' (aka `SYS$LIBRARY:') in order to invoke the main program once it is linked.

  5. Now say you have a file of optional subrs, `MYSUBRS.C'. And there is a routine INIT_MYSUBRS that must be called before using it.
    $ CC MYSUBRS.C $ LINK/SHARE=MYSUBRS.EXE MYSUBRS.OBJ,SYS$INPUT:/OPT   SYS$LIBRARY:VAXCRTL/SHARE   LISPRTL/SHARE   UNIVERSAL=INIT_MYSUBRS
    

    Ok. Another hint is that you can avoid having to add the PSECT declaration of NOSHR,LCL by declaring variables status in the C language source. That works great for most things.

  6. Then the dynamic loader would have to do this:
    {void (*init_fcn)();  long retval;  retval = lib$find_image_symbol("MYSUBRS","INIT_MYSUBRS",&init_fcn,                                 "SYS$DISK:[].EXE");  if (retval != SS$_NORMAL) error(...);  (*init_fcn)();}
    

    But of course all string arguments must be (struct dsc$descriptor *) and the last argument is optional if MYSUBRS is defined as a logical name or if `MYSUBRS.EXE' has been copied over to `SYS$SHARE'. The other consideration is that you will want to turn off C-C or other interrupt handling while you are inside most lib$ calls.

    As far as the generation of all the UNIVERSAL=... declarations. Well, you could do well to have that automatically generated from the public `LISPRTL.H' file, of course.

    VMS has a good manual called the Guide to Writing Modular Procedures or something like that, which covers this whole area rather well, and also talks about advanced techniques, such as a way to declare a program section with a pointer to a procedure that will be automatically invoked whenever any shared image is dynamically activated. Also, how to set up a handler for normal or abnormal program exit so that you can clean up side effects (such as opening a database). But for use with LISPRTL you probably don't need that hair.

    One fancier option that is useful under VMS for `LISPLIB.EXE' is to define all your exported procedures through an call vector instead of having them just be pointers into random places in the image, which is what you get by using UNIVERSAL.

    If you set up the call vector thing correctly it will allow you to modify and relink `LISPLIB.EXE' without having to relink programs that have been linked against it.

Windows NT

George Carrette (gjc@mitech.com) outlines how to dynamically link on Windows NT: