-
Notifications
You must be signed in to change notification settings - Fork 33
Home
JPL is a set of Java classes and C functions providing a bidirectional interface between Java and Prolog. JPL uses the Java Native Interface (JNI) to connect to a Prolog engine through the Prolog Foreign Language Interface (FLI). JPL is not a pure Java implementation of Prolog; it makes extensive use of native implementations of Prolog on supported platforms.
This is the projct Wiki with information to support development of JPL. This Wiki may provide more information than the basic one in documentation Developing JPL.
For understanding JPL and using it in your embedded application please refer to JPL Documentation page.
For development of JPL, we follow The GitHub Standard Fork & Pull Request Workflow.
:toc:
First, let us make sure we have all the necessary libraries and tools to compile the system:
sudo apt-get install \
build-essential autoconf curl chrpath pkg-config \
ncurses-dev libreadline-dev libedit-dev \
libunwind-dev \
libgmp-dev \
libssl-dev \
unixodbc-dev \
zlib1g-dev libarchive-dev \
libossp-uuid-dev \
libxext-dev libice-dev libjpeg-dev libxinerama-dev libxft-dev \
libxpm-dev libxt-dev \
libdb-dev \
libpcre3-dev \
libyaml-dev \
openjdk-11-jdk junit \
make ninja-build \
cmake
Since we want to get JPL it is mandatory to have:
-
openjdk-11-jdk
or any package that can providejava
and the compilerjavac
. (Runjavac -version
to test). -
junit
, for running Java unit testing.
As explained in fnogatz
's swivm repo, if you want to reduce resources, the following packages are optional:
-
libreadline-dev
andlibedit-devl
: Without, you do not have history feature in SWIPL interpreter. -
unixodbc-dev
: Without, you have no ODBC database connectivity (e.g., MySQL) -
libssl-dev
: Without, you have no SSL (and HTTPS) support. -
libgmp-dev
: Without, you lack unbounded integer support, rational numbers, good random number generators, etc. -
libarchive-dev
: Without, you can not unpack and install add-ons. -
libpcre3-dev
: Without, you have no regular expression support (library(pcre)). -
libyaml-dev
: Without, you have no YAML support (library(yaml)).
There are several environmnet variables that play some role in running SWIPL with JPL:
-
SWI_HOME_DIR
: to find the root dir of SWIPL install to be used. -
LD_LIBRARY_PATH
(dynamic linker search path):- to find native libraries, including
libjpl.so
andlibswipl.so
; - to find the JVM shared objects (
libjvm.so
) when calling Java from Prolog, as explained here.
- to find native libraries, including
-
CLASSPATH
: to find thejpl.jar
file implementing the JPL Java API. -
LD_PRELOAD
: to pre-load certain libraries (e.g.,libswipl.so
). -
JAVA_HOME
: to find the Java compiler and JNI when compiling JPL.
Find more information on ach in JPL doc here.
Here is a run on cloning, configuring, compiling, testing, and installing:
git clone https://github.com/SWI-Prolog/swipl-devel.git
cd swipl-devel
git submodule update --init
# Avoid conflicts with existing SWI installs (e.g., Ubuntu distribution)
unset LD_LIBRARY_PATH LD_PRELOAD SWI_HOME_DIR
mkdir build
cd build
# via make
cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr/local/swipl-git -DINSTALL_DOCUMENTATION=OFF ..
make -j 8
# via ninja (faster)
cmake -G Ninja -DCMAKE_INSTALL_PREFIX:PATH=/usr/local/swipl-git -DINSTALL_DOCUMENTATION=OFF ..
ninja
ctest -j 8 # run all tests (-j makes it faster!)
sudo make install
/usr/local/swipl-git/bin/swipl
Notes:
- The
unset
step is important if you have a distribution version installed in the system. See this issue if you getCould not find system resources
FATAL ERROR. - If there are other versions installed (e.g., distribution version) you need to make sure you are running the one you want; and you may need to setup
SWI_HOME_DIR
andLD_LIBRARY_PATH
if the Prolog is embedded into C/Java so that the right version is used. See discussion above on how to keep many SWI versions and how to use these environment variables. - SWI provides a script to activate the current install under the
build/
dir of CMAKE or the local install. Please refer to script../scripts/swipl-activate
in the CMAKE documentation of SWI.- Note this will create three
swipl
symbolic links in$HOME/bin
that you would need to delete if you want to use another install (e.g., the distribution one). So may not be the best way to work on, I prefer to work with the Linux alternative framework as described above.
- Note this will create three
From build/
directory (where CMAKE compiled SWIPL):
/usr/bin/env "SWI_HOME_DIR=home" "SWIPL_BOOT_FILE=home/boot.prc" src/swipl
Start relevant commits with [A-Z]+
: such that they become entries in the changelog.
The frequent tags are FIXED
, ADDED
and MODIFIED
, but anything matching the regex above is copied to the changelog.
For example, "ADDED: Rational number support
".
As of April 2020 most tests have been ported to JUNIT4.
- The set of JUNIT test class are in package
org.jpl7.junit
, but there is a test suitorg.jpl7.JPLTestSuite
to wrap them all. - There are also standalone tests in
org.jpl7.standalone.*
- Each of these testing classes can be run individually and are not part of the test suite.
IMPORTANT: All unit test cases are sub-classes of org.jpl7.junit.JPLTest
, which provides a method setUpClass
to initialize the Prolog engine with the correct SWIPL in the source development tree. Such class will gather a few environment variables that point to the development tree of SWIPL. While those variables are already set by CMAKE, if one wants to develop and run the tests within an IDE and outside CMAKE for the Java component, one has to set those variables (see below for more details).
There are 3 ways one can run the unit testing (or an application that wants to use the development SWI+JPL):
Using CMAKE from anywhere in the build/
structure:
ctest -V -R jpl:prolog_in_java
ctest -V -R jpl:java_in_prolog
In CLI, the tests needs to be run from build/package/jpl
.
This is the command to run the prolog_in_java
test (which uses SWIPL plunit and a test_lib
script defined in packages/cmake/PrologPackage.cmake
to collect all test_xxx.pl
unit testing files):
ssardina@Thinkpad-X1 jpl]$ /usr/bin/env "CLASSPATH=src/main/java/jpl.jar" "SWI_HOME_DIR=../../home" "SWIPL_BOOT_FILE=../../home/boot.prc" java "-Djava.library.path=." "-classpath" "/usr/share/java/junit4.jar:src/main/java/jpl.jar:src/test/java/jpltest.jar" org.jpl7.junit.Test_Atom
JUnit version 4.12
.Starting test: testAtomToString1 (Test_Atom)
.Starting test: testAtomToString2 (Test_Atom)
.Starting test: testAtomToString3 (Test_Atom)
.Starting test: testAtomEquality1 (Test_Atom)
.Starting test: testAtomEquality2 (Test_Atom)
.Starting test: testAtomIdentity (Test_Atom)
.Starting test: testAtom1 (Test_Atom)
.Starting test: testAtomHasFunctorWrongName (Test_Atom)
.Starting test: testAtomHasFunctorNameZero (Test_Atom)
.Starting test: testAtomArity (Test_Atom)
.Starting test: testAtomName1 (Test_Atom)
.Starting test: testAtomName2 (Test_Atom)
.Starting test: testAtomName3 (Test_Atom)
.Starting test: testAtomHasFunctorWrongArity (Test_Atom)
Time: 0.044
OK (14 tests)
and this is the one for testing java_in_prolog
(remember, always from build/package/jpl
):
[ssardina@Thinkpad-X1 jpl]$ /home/ssardina/git/soft/prolog/swipl-devel.git/build/src/swipl "-p" "foreign=:/home/ssardina/git/soft/prolog/swipl-devel.git/build/packages/plunit" "-f" "none" "--no-packs" "-s" "/home/ssardina/git/soft/prolog/swipl-devel.git/packages/jpl/test_jpl.pl" "-g" "test_jpl" "-t" "halt"
% PL-Unit: jpl .......................................................................................... done
% 3 tests are blocked:
% /home/ssardina/git/soft/prolog/swipl-devel.git/packages/jpl/test_jpl.pl:610:
test method_static_echo_float_4: we do not yet widen unbounded integers to floats or doubles
% /home/ssardina/git/soft/prolog/swipl-devel.git/packages/jpl/test_jpl.pl:914:
test set_field_static_shadow_1: we do not yet resolve same-named shadowed fields
% /home/ssardina/git/soft/prolog/swipl-devel.git/packages/jpl/test_jpl.pl:1193:
test throw_java_exception_1: part of the error term is nondeterministic: we need to match with _
% 90 tests passed
You can also run the Java-side unit testing (or any embedded application) inside an IDE (e.g., IntelliJ), which one would probably be using to develop JPL.
It is usually convenient to develop the Java side of JPL within and IDE. As an example, we will be using IntelliJ, but the same ideas should apply for other IDEs (e.g., ECLIPSE).
The project in the IDE will be under <swi-devel>/package/jpl
which is "outside" of the binary generated by CMAKE under <swi-devel>/build
.
As of May 2020, the JPL is a Maven project, so this already simplifies many things. However, one still needs to do a few things to make sure the Java being developed accesses the correct SWI development under the CMAKE binary dir <swi-devel>/build
, including the compiled libjpl.so
library.
So, to run, for example, unit testing classes for Java-calls-Prolog within the IDE:
-
Compile SWI-Prolog using CMAKE, to compile not only SWI itself but also the C code of JPL
<swi-devel>/project/jpl/src/c/jpl.c
which will yield library<swi-devel>/build/packages/jpl/libjpl.so
. -
Create a JUnit Run on some of the testing classes, like
org.jpl7.junit.Test_Atom
. -
Edit the working directory of the JUnit Run created to be
<swi-devel>/packages/jpl
.- Note this is the source code dir of JPL, not the folder within the
build/
directory used in step 1.
- Note this is the source code dir of JPL, not the folder within the
-
Edit the environment variables of the JUnit Run created to make sure it is using the current development of SWIPL compiled in step 1::
```bash LD_LIBRARY_PATH=../../build/packages/jpl; SWI_HOME_DIR=../../build/home; SWIPL_BOOT_FILE=../../build/home/boot.prc; LD_PRELOAD=../../build/src/libswipl.so ```
Notes:
- The
LD_PRELOAD
variable should not be necessary for the tests. - If the tests includes some Prolog code using some Java class in the JPL Java API, then one will need to setup an artifact to produce
jpl.jar
file, say the target dir for the project isout/
and also modify theCLASSPATH
environment variable in the runner. This is needed because some Prolog test files will look for Java classes in that JAR and you want to use the one being developed within the IDE rather than the last generated by CMAKE (which could be old and don't reflect the changes did inside the IDE yet). - To get all the warnings add
-Xlint
to the "Additional commands line parameters" to the Java Compiler (Settings / Build / Compiler / Java Compiler). Check javac options.
cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr/local/swipl-git -DINSTALL_DOCUMENTATION=OFF ..
make -C packages/jpl clean ; make -j 8
ctest -V -R jpl:prolog_in_java
src/swipl -x home/boot.prc -f none --home=home/ --no-signals
For JPL to be included in the compilation, CMAKE has to be able to find Java and JNI:
- Found JNI: /usr/lib/jvm/java-11-openjdk-amd64/lib/libjawt.so
-- JNI_INCLUDE_DIRS=/usr/lib/jvm/java-11-openjdk-amd64/include;/usr/lib/jvm/java-11-openjdk-amd64/include/linux;/usr/lib/jvm/java-11-openjdk-amd64/include
-- JNI_LIBRARIES=/usr/lib/jvm/java-11-openjdk-amd64/lib/libjawt.so;/usr/lib/jvm/java-11-openjdk-amd64/lib/server/libjvm.so
-- Found Java: /usr/bin/java (found version "11.0.7") found components: Development
While Java can be found if it is installed, finding JNI requires having JAVA_HOME
set:
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64/
When loading JPL module in Prolog:
?- use_module(library(jpl)).
ERROR: /usr/lib/swi-prolog/library/jpl.pl:4243:
'$open_shared_object'/3: libjvm.so: cannot open shared object file: No such file or directory
ERROR: /usr/lib/swi-prolog/library/jpl.pl:4243:
/usr/lib/swi-prolog/library/jpl.pl:4243: Initialization goal raised exception:
library `java' does not exist (Please add directory holding libjava.so to $LD_LIBRARY_PATH)
ERROR: Exported procedure jpl:jpl_c_lib_version/1 is not defined
true.
Do a locate libjvm.so
to find where it is and add the path to LD_LIBRARY_PATH
so that library can be found:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/jvm/java-8-oracle/jre/lib/amd64/server/
or for OpenJDK
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/jvm/java-11-openjdk-amd64/lib/server/
System is unable to find the SWI Prolog framework, including failing to find library libswipl.so
.
Set-up:
-
SWI_HOME_DIR
: the location where SWI-Prolog is installed.- In Ubuntu distribution:
/usr/lib/swi-prolog/
- In local install for example:
/usr/local/swipl/lib/swipl/
- In Ubuntu distribution:
-
SWIPL_BOOT_FILE
: location of the.prc
booting file.- In Ubuntu distribution:
/usr/lib/swi-prolog/boot64.prc
- In local install for example:
/usr/local/swipl/lib/swipl/
- In Ubuntu distribution:
You need to tell the system to pre-load SWI main library:
export LD_PRELOAD=/home/ssardina/git/soft/prolog/swipl-devel.git/build/src/libswipl.so
Check this post and what is preloading?
Check this post.
This is resovled by loading libswipl.so
before by setting LD_PRELOAD
as above.
Some Prolog file is not able to find jpl.jar
that it needs to call some class. We need to setup CLASSPATH to point to JPL:
export CLASSPATH=</path/to/build>/packages/jpl/src/java/jpl.jar
That is the JAR file that CMAKE produces and the Prolog test code needs to be able to find it.
JPL is released under the terms of the Simplified BSD License. See LICENSE file.