How to use JPL in alpine container from java service

I am trying to run a new java service in a docker container that talks to a prolog engine via JPL. My goal would be to load a *.pl file into the Prolog engine with some custom rules I’ve written, and interact with it from Java, asking questions.

I’ve done the following, it doesn’t work, and I think I’m going about this slightly wrong.

  1. I built version 9.3.5 of SWI-Prolog project packages-jpl from github using a maven install command. I didn’t run any CMAKE commands, I wasn’t sure where to start. I suspect there may need to be a jpl.so file included in this jar somehow and I don’t know how to create it.

  2. I create an alpine container by taking the java 21 corretto container and installing the swi-prolog apk package version 9.3.5 from the edge test apk respository. A swi prolog home is created in /usr/lib/swipl but there is no jpl.so file created

  3. I copied my jpl.jar file into /usr/lib/swipl, although I don’t think I need it in there, since I copy an executable jar file with the jpl.jar inside of it and it is found on the classpath

  4. I base my environment variables in the container on this: JPL - Initializing the Prolog engine

  5. I get a linking error at runtime when I try to JPL.init() in my java code, which I think is due to not being able to find jpl.so because it does not exist

  6. I find references to you having an alpine container working with JPL here, but I cannot find the container. Does it exist? Can I use it? SWI-Prolog issue 102 references making an alpine container but I cannot find the Dockerfile or the container.

  7. I can’t use these commands in alpine to build, as some of those C library dependencies do not exist in alpine: JPL - Setting up SWIPL & JPL for development

(I’ve read thread here on the discourse site “how-to-build-a-docker-image-with-swipl-and-jpl” which seems related, but hasn’t gotten me to where I need to go. )

Practically the only way to build such an image is to create a Dockerfile that includes the desired JDK and build Prolog from source based on that. The official Docker library is for Debian, but should give a good starting point. It is mostly a matter of replacing the dependencies, adding a JDK as dependency. You need to remove
-DSWIPL_PACKAGES_JAVA=OFF and you can probably strip a lot of stuff that you do not need.

The biggest challenge is finding the proper dependencies. Alpine ports have existed (do exist?). I vaguely recall that Alpine comes with a fairly restricted C library that has caused some problems in the past. I think these are resolved, but I am not sure.

If you find stuff, please share here!

You find the Docker library Dockerfiles at GitHub - SWI-Prolog/docker-swipl: Docker images for SWI-Prolog

edit: And the Alpine package build at APKBUILD « swi-prolog « testing - aports - Alpine packages build scripts

1 Like

Thank you. I decided to switch to Debian in my container, and am trying to build the whole SWI Prolog stack including the JAVA.
Thank you for the tips. I decided to switch to Debian. I’m not wedded to Alpine.

I’ve very successfully built the SWI-PROLOG stack without the JNI prolog build at this point. Removing -DSWIPL_PACKAGES_JAVA=OFF did not trigger the java stack to build, though, as far as I can tell.

Using your container as a base ( GitHub - SWI-Prolog/docker-swipl: Docker images for SWI-Prolog) I am sitting in the /tmp/src/swipl-$version/packages/jpl directory. How do I build?

  1. I think I need to run cmake in some way to create the jpl.so file, but I am not having luck at guessing the right arguments. Can you tell me?
  2. Should I be running the mvn package command ? I have done this successfully to build the JAR file, but it does not produce a jpl.so file.

My current attempt at building, which does not add all the dependencies I think I need to make jpl work:

   && cd swipl-$SWIPL_VER/build \
     && cmake -DCMAKE_BUILD_TYPE=RELEASE \
 	       -DCMAKE_INSTALL_PREFIX=/usr \
 	       -G Ninja \
           ..; \
     ninja; \
     ninja install; \

Just found these errors in the build output, and working to address…

-- Could NOT find JNI (missing: JAVA_AWT_LIBRARY JAVA_JVM_LIBRARY JAVA_INCLUDE_PATH JAVA_INCLUDE_PATH2 JAVA_AWT_INCLUDE_PATH) 
-- Could NOT find Java (missing: Java_JAVA_EXECUTABLE Java_JAVAC_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVADOC_EXECUTABLE Development) 

All you need to do is to add these dependencies to the apt-get install line

default-jdk junit4

Thank you, that was it!

So, I was able to build this container and a jpl.jar file. However, it turns out that java 21 cannot run code compiled with jdk 1.7. Java has made the decision to stop being reverse compatible that far back. I think it will work with Java 17, though, and am building from there.

Still, in case it might be useful to someone else, here is my containerfile. It’s based off your 9.3.2 tag.

FROM <my container Debian + Java 17>

ARG SWIPL_VER=9.3.2
ARG SWIPL_TAR=swipl-${SWIPL_VER}.tar.gz
COPY ./${SWIPL_TAR} /tmp/

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    libtcmalloc-minimal4 \
    libarchive13 \
    libyaml-0-2 \
    libgmp10 \
    libossp-uuid16 \
    libssl1.1 \
    ca-certificates \
    libdb5.3 \
    libpcre2-8-0 \
    libedit2 \
    libgeos-3.9.0 \
    libspatialindex6 \
    unixodbc \
    odbc-postgresql \
    tdsodbc \
    libmariadbclient-dev-compat \
    libsqlite3-0 \
    libserd-0-0 \
    python3 \
    libpython3.9 \
    libraptor2-0 && \
    dpkgArch="$(dpkg --print-architecture)" && \
    rm -rf /var/lib/apt/lists/*
ENV LANG C.UTF-8
RUN set -eux; \
    BUILD_DEPS='make cmake ninja-build gcc g++ git pkg-config m4 libtool automake autoconf libarchive-dev libgmp-dev libossp-uuid-dev libpcre2-dev libreadline-dev libedit-dev libssl-dev zlib1g-dev libdb-dev unixodbc-dev libsqlite3-dev libserd-dev libraptor2-dev  libyaml-dev libgeos++-dev libspatialindex-dev libpython3-dev libgoogle-perftools-dev default-jdk junit4'; \
    dpkgArch="$(dpkg --print-architecture)"; \
    apt-get update; apt-get install -y --no-install-recommends $BUILD_DEPS; rm -rf /var/lib/apt/lists/*; \
    mkdir /tmp/src; \
    cd /tmp/src; \
    cp /tmp/${SWIPL_TAR} . ; \
    tar -xzf ${SWIPL_TAR}; \
    mkdir swipl-$SWIPL_VER/build; \
    cd swipl-$SWIPL_VER/build; \
    cmake -DCMAKE_BUILD_TYPE=RELEASE \
	  -DCMAKE_INSTALL_PREFIX=/usr \
	  -G Ninja \
          ..; \
    ninja; \
    ninja install; \
    rm -rf /tmp/src; \
    mkdir -p /usr/share/swi-prolog/pack; \
    apt-get purge -y --auto-remove $BUILD_DEPS

Just change default-jdk to the latest JDK that will work for you. In the end you’ll probably have to modernise your code anyway though. That is how it works in IT. You can sometimes stay a little behind, but at some point it gets tedious as the old dependency no longer works on a still supported OS, etc. …

What is the most recent JVM you have tried out your JPL code with? My existing system runs on Java 21.

I don’t know. JPL is pretty Java version agnostic. It is old, so old JDKs should work fine. Deprecation warnings for the latest JDK that ship with various Linux, MacOS and Windows have been handled. Just try the version you need and run the tests (run ctest -R java in the build directory after building SWI-Prolog).

  Cheers --- Jan

Hello,
I was able to get things working in JAVA 17. I intend to come back to this later, once the core of my system is working. I think I found some issues compiling with various versions of corretto java that I would like to share/learn about. But it will probably be about a week before I can get back to it.
Thank you, Chris