6.8.2 Building for a Target Machine

The following example shows how to build an application with a dynamically loaded foreign resource in such a way that it can be deployed into an arbitrary folder on a target system that does not have SICStus installed. The example is run on Linux but it would be very similar on other platforms.

The example consists of three source files, one toplevel file (main.pl) which in turn loads a module-file (b.pl). The latter also loads a foreign resource (b.c).

The initial directory structure, and the contents of the source files can be seen from the following transcript:

$ find build/
build/
build/myfiles
build/myfiles/main.pl
build/myfiles/b.pl
build/myfiles/b.c
$ cat build/myfiles/main.pl
:- module(main, [main/0]).

:- use_module(b,
              [b_foreign/1]).

main :-
  b_foreign(X),
  write(X), nl.

user:runtime_entry(start) :-
  main.

$ cat build/myfiles/b.pl
:- module(b, [b_foreign/1]).

foreign(b_foreign_c, b_foreign([-string])).

foreign_resource(b, [
        b_foreign_c]).

:- load_foreign_resource(b).

$ cat build/myfiles/b.c
#include <sicstus/sicstus.h>
/* b_glue.h is generated by splfr from the foreign/[2,3] facts. 
   Always include the glue header in your foreign resource code.
*/
#include "b_glue.h"

char const * SPCDECL b_foreign_c(void)
{
  return "Hello World!";
}

The following transcript shows how the foreign resource and the SICStus runtime executable is built:

$ cd build/myfiles/
$ splfr b.pl b.c
$ cd ..
$ sicstus --nologo
% optional step for embedding source info in saved-state.
| ?- set_prolog_flag(source_info, on).
yes
% source_info
| ?- compile('myfiles/main.pl').
% compiling …/build/myfiles/main.pl...
%  module main imported into user
%  compiling …/build/myfiles/b.pl...
%   module b imported into main
%   loading foreign resource …/build/myfiles/b.so in module b
%  compiled …/build/myfiles/b.pl in module b, 0 msec 3104 bytes
% compiled …/build/myfiles/main.pl in module main, 0 msec 5344 bytes
yes
% source_info
| ?- save_program('main.sav').
% …/build/main.sav created in 20 msec
yes
% source_info
| ?- halt.
$ spld '$SP_APP_DIR/main.sav' -o main.exe
Created "main.exe"

(instead of creating main.exe you could use the generic runtime system sprt.exe provided as part of the installation (see Generic Runtime Systems)).

Please note: it is important that main.sav be saved to a folder that is the “root” of the folder tree. The folder in which the saved-state is created (…/build/ above) is treated specially by save_program/[1,2] and by restore/1. This special handling ensures that myfiles/b.so will be found relative to the location of main.sav when main.sav is restored on the target system. See Saving for details.

Next, the necessary runtime files must be copied from the SICStus installation:

$ mkdir -p sp-4.4.1/sicstus-4.4.1/bin
$ cp /usr/local/sicstus4.4.1/lib/libsprt4-4-1.so sp-4.4.1/
$ cp /usr/local/sicstus4.4.1/lib/sicstus-4.4.1/bin/sprt.sav \
     sp-4.4.1/sicstus-4.4.1/bin/sprt.sav

The resulting folder contents can be seen by running the find command:

$ find . -print
.
./sp-4.4.1
./sp-4.4.1/libsprt4-4-1.so
./sp-4.4.1/sicstus-4.4.1
./sp-4.4.1/sicstus-4.4.1/bin
./sp-4.4.1/sicstus-4.4.1/bin/sprt.sav
./myfiles
./myfiles/b.so
./myfiles/main.pl
./myfiles/b.pl
./myfiles/b.c
./main.sav
./main.exe

It is possible to run the program from its current location:

$ ./main.exe
Hello World!

The folder build/myfiles/ contains some files that do not need to be present on the target machine, i.e. the source files. The following transcript shows how a new folder, target/, is created that contains only the files that need to be present on the target system.

$ cd ..
$ mkdir target
$ mkdir target/myfiles
$ cp build/main.sav target
$ cp build/main.exe target
$ cp build/myfiles/b.so target/myfiles/
$ cp -R build/sp-4.4.1 target
$ find target/ -print
target/
target/myfiles
target/myfiles/b.so
target/main.sav
target/main.exe
target/sp-4.4.1
target/sp-4.4.1/sicstus-4.4.1
target/sp-4.4.1/sicstus-4.4.1/bin
target/sp-4.4.1/sicstus-4.4.1/bin/sprt.sav
target/sp-4.4.1/libsprt4-4-1.so
$ target/main.exe
Hello World!

Note that target/myfiles/b.so was found since its location relative the directory containing the saved-state (main.sav) is the same on the target system as on the build system.

The folder target/ can now be moved to some other system and target/main.exe will not depend on any files of the build machine.

As a final example, the following transcripts show how the runtime system can be debugged on the build machine. It is possible to do this on the target system as well, if the necessary files are made available. See Debugging Runtime Systems for more information.

First, the development system files and the license file must be made available:

$ mkdir sp-4.4.1/sicstus-4.4.1/library
$ cp /usr/local/sicstus4.4.1/lib/sicstus-4.4.1/library/SU_messages.po \
     sp-4.4.1/sicstus-4.4.1/library/
$ cp /usr/local/sicstus4.4.1/lib/sicstus-4.4.1/bin/spds.sav \
     sp-4.4.1/sicstus-4.4.1/bin/
$ cp /usr/local/sicstus4.4.1/lib/sicstus-4.4.1/library/license.pl \
     sp-4.4.1/sicstus-4.4.1/library/

As before, the resulting folder contents can be seen by running the find command:

$ find . -print
.
./sp-4.4.1
./sp-4.4.1/libsprt4-4-1.so
./sp-4.4.1/sicstus-4.4.1
./sp-4.4.1/sicstus-4.4.1/library
./sp-4.4.1/sicstus-4.4.1/library/SU_messages.po
./sp-4.4.1/sicstus-4.4.1/library/license.pl
./sp-4.4.1/sicstus-4.4.1/bin
./sp-4.4.1/sicstus-4.4.1/bin/spds.sav
./sp-4.4.1/sicstus-4.4.1/bin/sprt.sav
./myfiles
./myfiles/b.so
./myfiles/main.pl
./myfiles/b.pl
./myfiles/b.c
./main.sav
./main.exe
$

To tell the runtime system to start a development system. you can set the SP_USE_DEVSYS environment variable as shown below. You could also set SP_ATTACH_SPIDER and debug in the SICStus IDE (see Debugging Runtime Systems).

$ SP_USE_DEVSYS=yes
$ export SP_USE_DEVSYS
$ ./main.exe
% The debugger will first creep -- showing everything (trace)
        1      1 Call: restore('$SP_APP_DIR/main.sav') ? RET
% restoring …/build/main.sav...
% …/build/main.sav restored in 10 msec 5600 bytes
        1      1 Exit: restore('$SP_APP_DIR/main.sav') ? RET
        2      1 Call: runtime_entry(start) ? RET
in scope of a goal at line 12 in …/build/myfiles/main.pl
        3      2 Call: main:main ? RET
in scope of a goal at line 7 in …/build/myfiles/main.pl
        4      3 Call: main:b_foreign(_2056) ? RET
in scope of a goal at line 7 in …/build/myfiles/main.pl
        4      3 Exit: main:b_foreign('Hello World!') ? v
Local variables (hit RET to return to debugger)
X = 'Hello World!' ? RET
in scope of a goal at line 7 in …/build/myfiles/main.pl
        4      3 Exit: main:b_foreign('Hello World!') ? n
Hello World!
$ 

Please note: source info is available, since we used set_prolog_flag(source_info, on) before we compiled main.pl and created the saved-state main.sav.



Send feedback on this subject.