This guide describes the steps required for embedding Logtalk and Logtalk applications.
Embedding the compiler and runtime
The Logtalk 3.x compiler and runtime are implemented using both Prolog and Logtalk source files. When embedding Logtalk, usually to generate a new top level interpreter or an executable that includes it, we first need to save the intermediate Prolog files generated by the compilation of the Logtalk source files. An alternative, available in some backend Prolog compilers such as SICStus Prolog, SWI-Prolog, and YAP is to create a saved state after loading Logtalk and a Logtalk application. We explore here the first option.
After starting Logtalk using your favorite backend Prolog compiler, type the query:
| ?- logtalk_compile([ core(expanding), core(monitoring), core(forwarding), core(user), core(logtalk), core(core_messages) ], [ optimize(on), scratch_directory('$HOME/collect') ]).
Assuming, for example, that you’re using a POSIX system and GNU Prolog as the backend compiler, we need to copy the adapter and default paths files to the directory where we’re collecting all the files (
$HOME/collect in our example):
$ cp "$LOGTALKHOME"/adapters/gnu.pl "$HOME"/collect/gnu.pl $ cp "$LOGTALKHOME"/paths/paths_core.pl "$HOME"/collect/paths_core.pl $ cp "$LOGTALKHOME"/core/core.pl "$HOME"/collect/core.pl
Now that we have all the necessary files in one place, its a good idea to take a look to the files in the
integration directory for the chosen backend Prolog compiler and check if some changes to the core files are advised. For example, in the case of GNU Prolog, we can edit the
$HOME/collect/core.pl file and add the line
:- built_in. to the top to give all the predicates implementing the Logtalk compiler and runtime
built-in status. After this step, the details to embed the collected Prolog files that implement Logtalk depend on the backend Prolog compiler.
core.pl files contain initialization goals, the order of embedding of the files is not arbitrary. The initialization goals in the
paths.pl file must be called before the initialization goals in the
core.pl file. But the order that the GNU Prolog compiler calls the initialization goals is operating-system dependent (see its documentation and the
adapters/NOTES.md file for details). Moreover, the files containing the pre-compiled built-in entities,
core_messages_*_lgt.pl must precede, in this order, the
core.pl file. Note that we use regular expressions for the files that contain the pre-compiled built-in entities as their names, depending on the backend Prolog compiler, may include a directory hash, which is used to avoid file names conflicts.
Continuing to use GNU Prolog for our tutorial, we can generate a new top-level executable file by typing (ignore the suspicious predicate warnings about
$ cd "$HOME"/collect $ gplc -o logtalk gnu.pl expanding*_lgt.pl monitoring*_lgt.pl forwarding*_lgt.pl user*_lgt.pl logtalk*_lgt.pl core_messages*_lgt.pl core.pl paths.pl
In this case, the
paths.pl file is listed after the
core.pl file due to
gplc oddly collecting all initialization goals in a stack before calling.
logtalk executable can now be moved to a suitable place or distributed to its users. Note that the executable will still look by default for a
settings.lgt file in the
$LOGTALK_STARTUP_DIRECTORY directory (or the startup directory as returned by the Prolog system when the
LOGTALK_STARTUP_DIRECTORY is not available) and in the
$LOGTALKUSER directory. If necessary, you can turn off loading of settings files by editing the adapter file and changing the value of the
settings_file read-only flag to
Embedding an application
To embed not only Logtalk but also a Logtalk application, we also need to collect the intermediate Prolog files generated by the compilation of the Logtalk source files. Using now SWI-Prolog as an example, assume that we want to generate a single QLF file (SWI-Prolog Quick Load Format file) that includes both Logtalk and our application. The steps are similar (and can be easily automated using e.g. a shell script). Assuming a
loader.lgt file that loads all our application files, we can type the query:
| ?- set_logtalk_flag(source_data, off), set_logtalk_flag(optimize, on), set_logtalk_flag(clean, off), set_logtalk_flag(context_switching_calls, deny), set_logtalk_flag(scratch_directory, '$HOME/collect_app_files'), logtalk_load(loader, [clean(on)]).
Turning off the
source_data flag minimizes the size of the generated code (assuming our application doesn’t require the extended set of source data for reflective computations). Setting the
context_switching_calls flag to
deny ensures that the
<</2 debugging control construct cannot be used to break encapsulation in the final version of our application. As we don’t want to collect an intermediate Prolog file for the loader file itself, we load it using the option
clean(on). This assumes, of course, that the loader files don’t do anything else than loading the application files (as recommended).
Your application may use libraries with their own loader files. If so, these files should be deleted before proceeding:
$ rm -f "$HOME"/collect_app_files/*loader*
Now that we have all necessary application files in the
$HOME/collect_app_files/ directory, we can concatenate them in a single Prolog file (on POSIX system we can use the
cat utility in an automation script), say,
$ cat $(ls -t $HOME/collect_app_files/*.pl) > app_resources.pl
But for the Logtalk own files you cannot use the same trick as the order (show above) is important. Not a problem as there are only nine files to concatenate into, say, a
$ cd "$HOME"/collect $ cp "$LOGTALKHOME"/adapters/swi.pl . $ cp "$LOGTALKHOME"/paths/paths_core.pl . $ cp "$LOGTALKHOME"/core/core.pl . $ cat swi.pl paths_core.pl expanding_*_lgt.pl monitoring_*_lgt.pl forwarding_*_lgt.pl user_*_lgt.pl logtalk_*_lgt.pl core_messages_*_lgt.pl core.pl > logtalk_resources.pl
We just need an intermediate step before generating the
$ cat logtalk_resources.pl ../collect_app_files/app_resources.pl > resources.pl
With all the code in a single file, we can now compiled it into a
$ swipl -q -g "qcompile(resources)" -t halt
These steps are just a guideline. You may want e.g. to add a settings file, set other flags for compiling the final version of your application, define additional library paths, or include required foreign language resources.
Most of the embedding steps described above can easily be automated. For example embedding scripts for selected backend Prolog compilers, see:
For embedding details for specific backend Prolog compilers see those compilers documentation and the following notes: