I do not have a ready.made answer as I have never tried this but this question:
Building a shared library using gcc on Linux and MinGW on Windows
seems to touch on the problem:
I'm having trouble with generating a build setup that allows shared
libraries to be built in both Linux and Windows using gcc and MinGW,
respectively. In Linux, a shared library doesn't have to resolve all
dependencies at compile time; whereas, this appears to the case in
Windows.
That being said, the manual says at Linking Foreign Modules that there is a special linking tool:
This section discusses the functionality of the (autoload)
library(shlib)
, providing an interface to manage shared libraries.
We describe the procedure for using a foreign resource (DLL in Windows
and shared object in Unix) called mylib
.
First, one must assemble the resource and make it compatible to
SWI-Prolog. The details for this vary between platforms. The
swipl-ld(1)
utility can be used to deal with this in a portable
manner. The typical commandline is:
swipl-ld -o mylib file.{c,o,cc,C} ...
Make sure that one of the files provides a global
function install_mylib()
that initialises the module using calls
to PL_register_foreign()
. Here is a simple example file mylib.c
,
which creates a Windows MessageBox: ...
However, it seems that you need to add the option -shared
which is not given above!
The manual for swipl-ld
is here
but is given in the context of building a standalone executable based on
swipl
libraries and additional C-code, which is is different.
swipl-ld
is indeed in the distribution, in the bin
directory.
Note that you need a "module stub" to introduce the foreign functions to the swipl runtime. Like so:

Testing whether it works
On Linux
Just a short test, but on Linux (I will have to reactive my Windows machine a bit later)
In directory /home/rost/compilec
:
C-code file mylib.c
#include <SWI-Prolog.h>
#include <stdio.h>
static foreign_t
pl_say_hello(term_t to)
{ char *a;
if ( PL_get_atom_chars(to, &a)) {
printf("Hello, %s\n",a);
PL_succeed;
}
else {
PL_fail;
}
}
install_t
install_mylib()
{ PL_register_foreign("say_hello", 1, pl_say_hello, 0);
}
Prolog file mylib.pl
declaring a "stub module":
:- module(mylib, [ say_hello/1 ]).
:- use_foreign_library(foreign(mylib)).
After the above have been created, build a shared library using
swipl-ld
by compiling mylib.c
:
$ swipl-ld -v -shared -o mylib mylib.c
Output is:
eval `swipl --dump-runtime-variables`
PLBASE="/usr/local/logic/swipl/lib/swipl"
PLARCH="x86_64-linux"
PLSOEXT="so"
PLLIBDIR="/usr/local/logic/swipl/lib/swipl/lib/x86_64-linux"
PLLIB="-lswipl"
PLTHREADS="yes"
/usr/bin/cc -c -fPIC -D_REENTRANT -D__SWI_PROLOG__ -I/usr/local/logic/swipl/lib/swipl/include -o mylib.o mylib.c
/usr/bin/cc -o mylib.so -shared -Wl,-rpath=/usr/local/logic/swipl/lib/swipl/lib/x86_64-linux mylib.o -L/usr/local/logic/swipl/lib/swipl/lib/x86_64-linux -lswipl
rm mylib.o
cc
happens to be gcc version 10.2.1
(run cc -v
to see that)
Now start swipl
and call the provided predicate.
On the Prolog Toplevel (i.e. the Prolog command line), first extend the search path for foreign libraries:
?- assertz(file_search_path(foreign,'/home/rost/compilec')).
true.
Consult the "stub module":
?- [mylib].
true.
Then call the predicate in question:
?- say_hello('World').
Hello, World
true.
On Windows
(More precisely, on Windows 10. Awkward to work with.)
Get SWI-Prolog
I have installed SWI-Prolog using the installer available at Download SWI-Prolog stable versions, namely SWI-Prolog 8.2.4-1 for Microsoft Windows (64 bit)
.
After installation has been performed, the SWI-Prolog file tree can be found in C:\Program Files\swipl
and the bin
subdirectory indeed contains all we all.
Get MinGW
Now get MinGW. This being 64-bit Windows, so we will get the 64-bit version (which supplants the 32-bit version, and is also being maintained by another team).
Downloads can be found at this page.
Download the MinGW64-builds.
Sidenote
I also tried Win-builds but no luck, the win-builds installer fails trying to download packages because the SHA-3 checksum do not match. Maybe it's too old?
End of sidenote
Clicking on MinGW64-builds. will redirect us to Sourceforge (ah, nsotalgia!) and will dump an installer into the Downloads
directory. It passes the antivirus, ESet Antivirus says that it has good confidence in this executable, and computing the SHA-256 checksum then googling it brings good results. Excellent.
So run the installer. I filled in the mysterious settings that it requests as follows:
Version 8.1.0 - Latest MingW version
Architecture - Proposes "i686" (why), switch to "x86_64"
Threads - "posix" or "win32"? Let's take "posix"
Exception - "seh", why not, this seems to be the modern exception format
Build revision 0 - Ok I guess
(For SEH vs SLJ exception format, see this question)
After then download of packages & installation finishes, you end up with a lot of tools in
C:\Program Files\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin
Now we can build our DLL. Open the "Command Prompt" window:
> set PATH=C:\Program Files\swipl\bin;C:\Program Files\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;%PATH%
> cd (to where the mylib.c and mylib.pl files reside)
> swipl-ld -v -shared -o mylib mylib.c
We see:
eval `swipl.exe --dump-runtime-variables`
PLBASE="c:/program files/swipl"
PLARCH="x64-win64"
PLSOEXT="dll"
PLLIBDIR="c:/program files/swipl/bin"
PLLIB="-lswipl"
PLTHREADS="yes"
gcc.exe -c -D_REENTRANT -D__WINDOWS__ -D_WINDOWS -D__SWI_PROLOG__ -I"c:/program files/swipl/include" -o mylib.obj mylib.c
gcc.exe -o mylib.dll -shared mylib.obj -L"c:/program files/swipl/bin" -lswipl
rm mylib.obj
and the file mylib.dll
has been successfully created.
Sidenote:
If you check it out on Linux, file
says that this is a PE/COFF file:
$ file mylib.dll
mylib.dll: PE32+ executable (DLL) (console) x86-64, for MS Windows
nm(1)
works on the DLL (sweet!) and lists the exported procedure:
$ nm mylib.dll | grep say
000000006e5813b0 t pl_say_hello
Well, that DLL file is just a serialized structure like any other,
End of sidenote
Can swipl
use it the DLL? Yes it can!
Start swipl
. Suppose we have the mylib.dll
in directory C:\Users\francisbacon\Documents\Compiling
:
1 ?-
assertz(file_search_path(foreign,'C:/Users/francisbacon/Documents/Compiling')).
true.
2 ?-
[mylib].
true.
3 ?-
say_hello('World').
Hello, World
true.