Next: Exceptions from C, Previous: Train Example, Up: Mixing C and Prolog Examples [Contents][Index]
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.6.0/sicstus-4.6.0/bin $ cp /usr/local/sicstus4.6.0/lib/libsprt4-6-0.so sp-4.6.0/ $ cp /usr/local/sicstus4.6.0/lib/sicstus-4.6.0/bin/sprt.sav \ sp-4.6.0/sicstus-4.6.0/bin/sprt.sav
The resulting folder contents can be seen by running the find
command:
$ find . -print . ./sp-4.6.0 ./sp-4.6.0/libsprt4-6-0.so ./sp-4.6.0/sicstus-4.6.0 ./sp-4.6.0/sicstus-4.6.0/bin ./sp-4.6.0/sicstus-4.6.0/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.6.0 target $ find target/ -print target/ target/myfiles target/myfiles/b.so target/main.sav target/main.exe target/sp-4.6.0 target/sp-4.6.0/sicstus-4.6.0 target/sp-4.6.0/sicstus-4.6.0/bin target/sp-4.6.0/sicstus-4.6.0/bin/sprt.sav target/sp-4.6.0/libsprt4-6-0.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.6.0/sicstus-4.6.0/library $ cp /usr/local/sicstus4.6.0/lib/sicstus-4.6.0/library/SU_messages.po \ sp-4.6.0/sicstus-4.6.0/library/ $ cp /usr/local/sicstus4.6.0/lib/sicstus-4.6.0/bin/spds.sav \ sp-4.6.0/sicstus-4.6.0/bin/ $ cp /usr/local/sicstus4.6.0/lib/sicstus-4.6.0/library/license.pl \ sp-4.6.0/sicstus-4.6.0/library/
As before, the resulting folder contents can be seen by running the
find
command:
$ find . -print . ./sp-4.6.0 ./sp-4.6.0/libsprt4-6-0.so ./sp-4.6.0/sicstus-4.6.0 ./sp-4.6.0/sicstus-4.6.0/library ./sp-4.6.0/sicstus-4.6.0/library/SU_messages.po ./sp-4.6.0/sicstus-4.6.0/library/license.pl ./sp-4.6.0/sicstus-4.6.0/bin ./sp-4.6.0/sicstus-4.6.0/bin/spds.sav ./sp-4.6.0/sicstus-4.6.0/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
.