Foreign C mylib.so not found at runtime

I’m using: SWI-Prolog version linux gentoo 9.39.9-r1

I want the code to:
While running as standalone elf executable, lookup and load a C library which is installed in a “~/lib/prolog” directory in my home.

But what I’m getting is:
The executable cannot load the C library: Existence_error(source_sink,“lib.so”).
Whereas, it works nice when executed from the interactive swipl.
I tried various file_search_path/2 solutions, to no avail.

My code looks like this:

% lib/lib.pl
:- module(lib, [cpred/0]).

:- use_foreign_library("lib.so").
/* lib/lib.c */
#include <stdio.h>
#include <SWI-Prolog.h>

install_t install(void);

foreign_t cpred(void) {
  puts("works");
  PL_succeed;
}

install_t install(void) {
  PL_register_foreign("cpred", 0, cpred, 0);
}
% exe/exe.pl
:- use_module(library(lib)).

:- initialization(main, main).

main :-
    cpred.
% ~/.config/swi-prolog/init.pl
file_search_path(library, '/home/mala/lib/prolog').
file_search_path(foreign, '/home/mala/lib/prolog').

Compilation and installation of lib:

$ cd lib
$ swipl-ld -shared -o lib.so lib.c
$ cp lib.so lib.pl ~/lib/prolog/

Compilation of exe:

$ cd exe
$ swipl -o exe -p library=~/lib/prolog --stand-alone -c exe.pl

Run (does not work):

$ ./exe
ERROR: /home/mala/lib/prolog/lib.pl:5: Initialization goal raised exception:
ERROR: source_sink `"lib.so"' does not exist
ERROR: In:
ERROR:   [19] throw(error(existence_error(source_sink,"lib.so"),_256))
ERROR:   [17] shlib:load_foreign_library("lib.so",lib,[]) at /usr/lib/swipl/library/shlib.pl:398

Run of the exe.pl source from the swipl toplevel (works):

$ swipl
?- [exe].
true.

?- main.
works
true.

That only searches in the local directory. Use

:- use_foreign_library(foreign(lib)).

That will use the file search path foreign. You can choose any other name as long as you have matching file_search_path/2 clauses.

Better avoid using the extension. The search is done using the extension for shared objects for the target platform.

Thanks for your swift answer.

That triggers a compilation-time error:

ERROR: /home/mala/lib/prolog/lib.pl:5:
ERROR:    /home/mala/lib/prolog/lib.pl:5: Initialization goal raised exception:
ERROR:    open_shared_object/3: lib: cannot open shared object file: No such file or directory

I also tried with “lib.so”, and I get a slightly different compile-time error:

ERROR: /home/mala/lib/prolog/lib.pl:5:
ERROR:    /home/mala/lib/prolog/lib.pl:5: Initialization goal raised exception:
ERROR:    source_sink `foreign("lib.so")' does not exist

The shared object is also loaded when the Prolog file is being compiled, so you must ensure it can be found at compile and at runtime.

But, the compilation normally does not load your init.pl file …

It seems a bit strange to create an exe and demand lib.so to be in your personal library. Maybe use --foreign=save? That includes lib.so in the created executable.

Note that you can set the Prolog flag verbose_file_search to true to see where Prolog is searching for a file.

Useful info: that sent me on the right path.

I was only setting the library path with -p library=~/lib/prolog in my swipl -c command; adding -p foreign=~/lib/prolog solved it all. I need both, one for lib.pl and the other for lib.so, voilà.

I like dynamic loading of libraries; and during development I act as an unprivileged user, so I don’t install libraries in /usr/local/lib or something like that.

I just mimic the system tree (bin/, include/, lib/, share/, etc.) in my home for the installation phase; then once the stuff is ready, packaging it for system-wide installation is a breeze…

So, just for reference, my Makefile for compiling a foreign library:

PREFIX = $(HOME)
LIBDIR = $(PREFIX)/lib/prolog

SRC = lib.pl
LIB = $(SRC)

CSRC = lib.c
CLIB = $(CSRC:.c=.so)

.PHONY: all
all: $(CLIB)

$(CLIB): $(CSRC)
        swipl-ld -shared -o $@ $^

.PHONY: install
install: $(LIB) $(CLIB)
        install -D -t $(LIBDIR) $^

The one for the application using the library:

PREFIX = $(HOME)
BINDIR = $(PREFIX)/bin
LIBDIR = $(PREFIX)/lib/prolog

SRC = exe.pl
EXE = $(firstword $(SRC:.pl=))

.PHONY: all
all: $(EXE)

$(EXE): $(SRC)
        swipl -o $@ -p library=$(LIBDIR) -p foreign=$(LIBDIR) --stand-alone -c $<

.PHONY: install
install: $(EXE)
        install -D -t $(BINDIR) $^

Thanks again.