9.8.3.3 Examples
  1. The character-based SICStus development system executable (sicstus) can be created using
              % spld --main=prolog -o sicstus
         

    This will create a development system that is dynamically linked and has no pre-linked foreign resources.

  2.           % spld --static -D --resources=random -o main -ltk8.0 -ltcl8.0
         

    This will create a statically linked executable called main that has the resource random pre-linked (statically). The linker will receive -ltk8.0 -ltcl8.0, which will work under UNIX (if Tcl/Tk is installed correctly) but will probably fail under Windows.

  3. The following is a little more advanced example demonstrating two things. One is how to use the --userhook option to perform initializations in development systems before SP_initialize() is called. It also demonstrates how to use this mechanism to redefine the memory manager bottom layer.
              /* --------------------------------------------------------------
               * userhook.c - an example of how to use SU_initialize() to
               *              define your own memory manager bottom layer.
               *
               * The following commands create a sicstus-executable 'msicstus' that
               * uses malloc() as its own memory manager bottom layer. In addition
               * these memory hooks print out messages when they are called.
               *
               * --------------------------------------------------------------
               */
              
              #include <stdarg.h>
              #include <stdio.h>
              #include <stdlib.h>
              #include <sicstus/sicstus.h>
              
              #ifdef __GLIBC__
              #include <malloc.h>             /* for mallopt() */
              #endif
              
              static char* memman_earliest_start;
              static char* memman_latest_end;
              static size_t memman_alignment;
              static int SPCDECL
              SU_init_mem_hook(size_t alignment,
                                void* earliest_start,
                                void* latest_end,
                                void *cookie)
              {
                fprintf(stderr, "Inside SU_init_mem_hook(%ld, 0x%lx, 0x%lx, 0x%lx)\n",
                       (long)alignment,
                       (unsigned long)earliest_start, (unsigned long)latest_end,
                       (unsigned long)cookie);
              
              #if __GLIBC__
                /* By default glibc malloc will use mmap for large requests. mmap
                   returns addresses outside the constrained range so we try to
                   prevent malloc from using mmap. There is no guarantee that mmap
                   is not used anyway, especially with threads.
                */
                mallopt(M_MMAP_MAX, 0);
              #endif /* __GLIBC__ */
              
                memman_earliest_start = (char*)earliest_start;
                memman_latest_end = (char*)latest_end;
                memman_alignment = alignment;
                (void)cookie;                 /* ignored */
                return 1;                     /* success */
              }
              static void SPCDECL
              SU_deinit_mem_hook(void *cookie)
              {
              
              
              
              
              
                fprintf(stderr, "Inside SU_deinit_mem_hook(0x%lx)\n",
                       (unsigned long)cookie);
                (void)cookie;                 /* ignored */
              }
              static void * SPCDECL
              SU_alloc_mem_hook(size_t size,  /* in bytes */
                           size_t *pactualsize,
                           int constrained,
                           void *cookie)
              {
                size_t actual_size;
                char *p;
                (void)cookie;                 /* ignored */
                /* Ensure there is room for an aligned block regardless of alignment
                   from malloc(). */
                actual_size = size+memman_alignment;
                p = (char*)malloc(actual_size);
                fprintf(stderr, "Inside SU_alloc_mem_hook(%ld,%s) "
                        "allocated %ldbyte block at 0x%lx\n",
                       (long)size,
                       (constrained ? "constrained" : "unconstrained"),
                       (long)actual_size,
                       (unsigned long)p);
              
                if (p!=NULL && constrained)
                  {
                    if (! (memman_earliest_start <= p && p < memman_latest_end
                           &&  actual_size < (size_t)(memman_latest_end-p)))
                      {                       /* did not get a suitable block */
                        fprintf(stderr,
                                "Inside SU_alloc_mem_hook(%ld,constrained)"
                                "ERROR [0x%lx,0x%lx) is not within [0x%lx,0x%lx)\n",
                               (long)size,
                               (unsigned long)p,
                               (unsigned long)(p+actual_size),
                               (unsigned long)memman_earliest_start,
                               (unsigned long)memman_latest_end);
                        free(p);
                        p = NULL;
                      }
                  }
              
                if (p)
                  {
                    *pactualsize = actual_size;
                    return p;
                  }
                else
                  {
                    fprintf(stderr, "Inside SU_alloc_mem_hook(%ld,%s) "
                            "ERROR failed to allocate memory\n",
                           (long)size,
                           (constrained ? "constrained" : "unconstrained"));
                    return NULL;
                  }
              }
              static int SPCDECL
              SU_free_mem_hook(void *mem,
                          size_t size,
                          int constrained,
                          int force,
                          void *cookie)
              {
                fprintf(stderr, "Inside SU_free_mem_hook(0x%lx, %ld, %s, %s, 0x%lx)\n",
                       (unsigned long)mem,
                       (long)size,
                       (constrained ? "constrained" : "unconstrained"),
                       (force ? "FORCE" : "!FORCE"),
                       (unsigned long)cookie
                       );
                /* We ignore all these since free() knows how to free anyway. */
                (void)size;
                (void)constrained;
                (void)force;
                (void)cookie;
                free(mem);
                return 1;                     /* could reclaim the memory */
              }
              /* Entry point for initializations to be done before SP_initialize() */
              int SPCDECL
              SU_initialize (int argc, char **argv)
              {
                void *cookie = NULL;          /* we do not use this */
                int hints = 0;                /* should be zero */
                (void)argc;
                (void)argv;
              
                if (!SP_set_memalloc_hooks(hints,
                                           SU_init_mem_hook,
                                           SU_deinit_mem_hook,
                                           SU_alloc_mem_hook,
                                           SU_free_mem_hook,
                                           cookie))
                  {
                    fprintf(stderr, "Inside SU_initialize, "
                            "ERROR from SP_set_memalloc_hooks");
                    return 1;
                  }
                return 0;
              }
         

    Compile userhook.c like this:

              % spld -D --userhook userhook.c -o msicstus.exe
              ...
              Created "msicstus.exe"
              % ./msicstus.exe -i -f
              Inside(SU_init_mem_hook(8, 0x8, 0x10000000, 0x0)
              Inside SU_alloc_mem_hook(131088,constrained) allocated 131096byte block at 0x410048
              Inside SU_alloc_mem_hook(1572880,unconstrained) allocated 1572888byte block at 0x510020
              SICStus 3.12.11 ...
              Licensed to SICS
              | ?-
         
  4. An all-in-one executable with a home-built foreign resource.

    This example is similar to the example in All-in-one Executables, with the addition of a foreign resource of our own.

                                       
    % bar.pl
    :- use_module(library(system)). :- use_module(library(clpfd)). % This will be called when the application starts: user:runtime_entry(start) :- %% You may consider putting some other code here... write('hello world'),nl, write('Getting host name:'),nl, host_name(HostName), % from system write(HostName),nl, ( all_different([3,9]) -> % from clpfd write('3 != 9'),nl ; otherwise -> write('3 = 9!?'),nl ), '$pint'(4711). % from our own foreign resource 'bar' foreign(print_int, '$pint'(+integer)). foreign_resource(bar, [print_int]). :- load_foreign_resource(bar).
                                    
    /* bar.c */
    #include <sicstus/sicstus.h> #include <stdio.h> /* bar_glue.h is generated by splfr from the foreign/[2,3] facts. Always include the glue header in your foreign resource code. */ #include "bar_glue.h" extern void print_int(long a); void print_int(long a) { printf("a=%lu\n", a); }

    To create the saved-state bar.sav we will compile the file bar.pl and save it with save_program('bar.sav'). When compiling the file the directive :- load_foreign_resource(bar). is called so a dynamic foreign resource must be present.

    Thus, first we build a dynamic foreign resource.

              % splfr bar.c bar.pl
         

    Then we create the saved-state.

              % sicstus --goal "compile(bar), save_program('bar.sav'), halt."
         

    We also need a static foreign resource to embed in our all-in-one executable.

              % splfr --static bar.c bar.pl
         

    Lastly we build the all-in-one executable with spld. We do not need to list the foreign resources needed. spld will extract their names from the .sav file. Adding the --verbose option will make spld output lots of progress information, among which are the names of the foreign resources that are needed. Look for “Found resource name” in the output.

              % spld --verbose --static --main=restore --respath=. --resources=bar.sav=/mystuff/bar.sav --output=bar
         

    In this case four foreign resource names are extracted from the .sav file: bar, clpfd, random and system. The source file bar.pl loads the foreign resource named bar. Is also uses the system module, which loads the foreign resource named system, and the clpfd module, which loads the foreign resources named clpfd and random.

    By not listing foreign resources when running spld, we avoid the risk of omitting a required resource.