#!/usr/bin/env bash ############################################################################# ## ## This script creates a XVM logtalk.pl file with the Logtalk compiler and ## runtime and optionally an application.pl file with a Logtalk application ## ## Last updated on October 31, 2024 ## ## This file is part of Logtalk ## SPDX-FileCopyrightText: 1998-2024 Paulo Moura ## SPDX-License-Identifier: Apache-2.0 ## ## Licensed under the Apache License, Version 2.0 (the "License"); ## you may not use this file except in compliance with the License. ## You may obtain a copy of the License at ## ## http://www.apache.org/licenses/LICENSE-2.0 ## ## Unless required by applicable law or agreed to in writing, software ## distributed under the License is distributed on an "AS IS" BASIS, ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## See the License for the specific language governing permissions and ## limitations under the License. ## ############################################################################# print_version() { echo "$(basename "$0") 0.12" exit 0 } if ! [ "$LOGTALKHOME" ]; then echo "The environment variable LOGTALKHOME should be defined first, pointing" echo "to your Logtalk installation directory!" echo "Trying the default locations for the Logtalk installation..." if [ -d "/usr/local/share/logtalk" ]; then LOGTALKHOME=/usr/local/share/logtalk echo "... using Logtalk installation found at /usr/local/share/logtalk" elif [ -d "/usr/share/logtalk" ]; then LOGTALKHOME=/usr/share/logtalk echo "... using Logtalk installation found at /usr/share/logtalk" elif [ -d "/opt/local/share/logtalk" ]; then LOGTALKHOME=/opt/local/share/logtalk echo "... using Logtalk installation found at /opt/local/share/logtalk" elif [ -d "/opt/share/logtalk" ]; then LOGTALKHOME=/opt/share/logtalk echo "... using Logtalk installation found at /opt/share/logtalk" elif [ -d "$HOME/share/logtalk" ]; then LOGTALKHOME="$HOME/share/logtalk" echo "... using Logtalk installation found at $HOME/share/logtalk" elif [ -f "$( cd "$( dirname "$0" )" && pwd )/../core/core.pl" ]; then LOGTALKHOME="$( cd "$( dirname "$0" )" && pwd )/.." echo "... using Logtalk installation found at $( cd "$( dirname "$0" )" && pwd )/.." else echo "... unable to locate Logtalk installation directory!" >&2 echo exit 1 fi echo export LOGTALKHOME=$LOGTALKHOME elif ! [ -d "$LOGTALKHOME" ]; then echo "The environment variable LOGTALKHOME points to a non-existing directory!" >&2 echo "Its current value is: $LOGTALKHOME" >&2 echo "The variable must be set to your Logtalk installation directory!" >&2 echo exit 1 fi if ! [ "$LOGTALKUSER" ]; then echo "The environment variable LOGTALKUSER should be defined first, pointing" echo "to your Logtalk user directory!" echo "Trying the default location for the Logtalk user directory..." echo export LOGTALKUSER=$HOME/logtalk fi if [ -d "$LOGTALKUSER" ]; then if ! [ -f "$LOGTALKUSER/VERSION.txt" ]; then echo "Cannot find version information in the Logtalk user directory at $LOGTALKUSER!" echo "Creating an up-to-date Logtalk user directory..." logtalk_user_setup else system_version=$(cat "$LOGTALKHOME/VERSION.txt") user_version=$(cat "$LOGTALKUSER/VERSION.txt") if [ "$user_version" \< "$system_version" ]; then echo "Logtalk user directory at $LOGTALKUSER is outdated: " echo " $user_version < $system_version" echo "Creating an up-to-date Logtalk user directory..." logtalk_user_setup fi fi else echo "Cannot find \$LOGTALKUSER directory! Creating a new Logtalk user directory" echo "by running the \"logtalk_user_setup\" shell script:" logtalk_user_setup fi # default values directory="$(pwd -P)" temporary="" paths="$LOGTALKHOME/paths/paths.pl" settings="$LOGTALKHOME/scripts/embedding/settings-embedding-sample.lgt" compile="false" foreign="false" goal="true" encrypt="false" usage_help() { echo echo "This script creates a XVM logtalk.pl file with the Logtalk compiler/runtime" echo "and an optional application.pl file from an application source code given" echo "its loader file. When embedding an application, this script also creates a" echo "loader.pl file for loading all generated Prolog and foreign library files," echo "optionally calling a startup goal." echo echo "Usage:" echo " $(basename "$0") [-c] [-d directory] [-t tmpdir] [-p paths] [-s settings] [-l loader] [-g goal] [-f] [-x]" echo " $(basename "$0") -v" echo " $(basename "$0") -h" echo echo "Optional arguments:" echo " -c compile library alias paths in paths and settings files" echo " -d directory for generated Prolog files (absolute path; default is current directory)" echo " -t temporary directory for intermediate files (absolute path; default is an auto-created directory)" echo " -p library paths file (absolute path; default is $paths)" echo " -s settings file (absolute path or 'none'; default is $settings)" echo " -l loader file for the application (absolute path)" echo " -g startup goal for the application in canonical syntax (default is $goal)" echo " -f copy foreign library files loaded by the application" echo " -x encrypt the generated logtalk.pl and application.pl files" echo " -v print version of $(basename "$0")" echo " -h help" echo } while getopts "cd:t:p:s:l:g:fxvh" option do case $option in c) compile="true";; d) d_arg="$OPTARG";; t) t_arg="$OPTARG";; p) p_arg="$OPTARG";; s) s_arg="$OPTARG";; l) l_arg="$OPTARG";; g) g_arg="$OPTARG";; f) foreign="true";; x) encrypt="true";; v) print_version;; h) usage_help; exit;; *) usage_help; exit;; esac done if [ "$d_arg" != "" ] ; then directory="$d_arg" fi if [ "$t_arg" != "" ] ; then temporary="$t_arg" fi if [ "$p_arg" != "" ] ; then if [ -f "$p_arg" ] ; then paths="$p_arg" else echo "The $p_arg library paths file does not exist!" >&2 exit 1 fi fi if [ "$s_arg" != "" ] && [ "$s_arg" != "none" ] ; then if [ -f "$s_arg" ] ; then settings="$s_arg" else echo "The $s_arg settings file does not exist!" >&2 exit 1 fi elif [ "$s_arg" == "none" ] ; then settings="none" fi if [ "$l_arg" != "" ] ; then if [ -f "$l_arg" ] ; then loader="$l_arg" else echo "The $l_arg loader file does not exist!" >&2 exit 1 fi else loader="" fi if [ "$g_arg" != "" ] ; then goal="$g_arg" fi mkdir -p "$directory" if [ "$temporary" != "" ] ; then mkdir -p "$temporary" else temporary=$(mktemp -d) fi if [[ ! "$temporary" || ! -d "$temporary" ]]; then echo "Could not create temporary directory!" exit 1 fi cd "$temporary" || exit 1 operating_system=$(uname -s) if [ "${operating_system:0:10}" == "MINGW32_NT" ] || [ "${operating_system:0:10}" == "MINGW64_NT" ] ; then # assume that we're running on Windows using the Git for Windows bash shell extension='.sh' elif [ "$LOGTALKHOME" != "" ] && [ "$LOGTALKUSER" != "" ] && [ "$LOGTALKHOME" == "$LOGTALKUSER" ] ; then # assume that we're running Logtalk without using the installer scripts extension='.sh' else extension='' fi # use GNU sed if available instead of BSD sed if gsed --version >/dev/null 2>&1 ; then sed="gsed" else sed="sed" fi cp "$LOGTALKHOME/adapters/xvm.pl" . cp "$LOGTALKHOME/core/core.pl" . xvmlgt$extension --goal "logtalk_compile([core(expanding),core(monitoring),core(forwarding),core(user),core(logtalk),core(core_messages)],[optimize(on),scratch_directory('$temporary')]),halt." if [ "$compile" = "true" ] ; then xvmlgt$extension --goal "logtalk_load(expand_library_alias_paths(loader)),logtalk_compile('$paths',[hook(expand_library_alias_paths),scratch_directory('$temporary')]),halt." else cp "$paths" "$temporary/paths_lgt.pl" fi if [ "$settings" != "" ] && [ "$settings" != "none" ] ; then if [ "$compile" = "true" ] ; then xvmlgt$extension --goal "logtalk_load(expand_library_alias_paths(loader)),logtalk_compile('$settings',[hook(expand_library_alias_paths),optimize(on),scratch_directory('$temporary')]),halt." else xvmlgt$extension --goal "logtalk_compile('$settings',[optimize(on),scratch_directory('$temporary')]),halt." fi $sed -i "s/settings_file, allow/settings_file, deny/" xvm.pl cat \ xvm.pl \ paths*.pl \ expanding*_lgt.pl \ monitoring*_lgt.pl \ forwarding*_lgt.pl \ user*_lgt.pl \ logtalk*_lgt.pl \ core_messages*_lgt.pl \ settings*.pl \ core.pl \ > "$directory"/logtalk.pl else cat \ xvm.pl \ paths*.pl \ expanding*_lgt.pl \ monitoring*_lgt.pl \ forwarding*_lgt.pl \ user*_lgt.pl \ logtalk*_lgt.pl \ core_messages*_lgt.pl \ core.pl \ > "$directory"/logtalk.pl fi if [ "$loader" != "" ] ; then mkdir -p "$temporary/application" cd "$temporary/application" || exit 1 if [ "$foreign" = "true" ] ; then xvmpl --goal "consult('$directory/logtalk'),set_logtalk_flag(clean,off),set_logtalk_flag(scratch_directory,'$temporary/application'),logtalk_load('$loader'),forall((current_plugin(PlugIn),plugin_property(PlugIn,file(File))),(decompose_file_name(File,_,Basename),atom_concat('$directory/',Basename,Copy),copy_file(File,Copy))),halt." else xvmpl --goal "consult('$directory/logtalk'),set_logtalk_flag(clean,off),set_logtalk_flag(scratch_directory,'$temporary/application'),logtalk_load('$loader'),halt." fi cat "$(ls -rt ./*.pl)" > "$directory"/application.pl if [ "$encrypt" = "true" ] ; then xvmpl --goal "encrypt_program('$directory/logtalk.pl'),halt." xvmpl --goal "encrypt_program('$directory/application.pl'),halt." rm "$directory"/logtalk.pl rm "$directory"/application.pl fi if [ "$foreign" = "true" ] ; then xvmpl --goal "consult('$directory/logtalk'),set_logtalk_flag(report,off),logtalk_load('$loader'),open('$directory/loader.pl',append,Stream),forall((current_plugin(PlugIn),plugin_property(PlugIn,file(File))),(decompose_file_name(File,_,Basename,_),format(Stream,'\tload_foreign_library(~q),~n',[Basename]))),close(Stream),halt." fi echo ":- initialization((" > "$directory"/loader.pl echo " consult(logtalk)," >> "$directory"/loader.pl if [ "$goal" = "true" ] ; then echo " consult(application)" >> "$directory"/loader.pl else echo " consult(application)," >> "$directory"/loader.pl echo " $goal" >> "$directory"/loader.pl fi echo "))." >> "$directory"/loader.pl if [ "$encrypt" = "true" ] ; then xvmpl --goal "encrypt_program('$directory/loader.pl'),halt." rm "$directory"/loader.pl fi fi function cleanup { rm -rf "$temporary" } # register cleanup function to be called on EXIT signal trap cleanup EXIT