I try to build a minimal relocatable build of SWI Prolog 9.0.4 on Linux, which contains only a few needed packages. I found the STATIC_EXTENSIONS switch to create only one executable, but the linking of swipl fails with following error:
[ 48%] Linking C executable swipl
/usr/bin/ld: libswipl.a(pl-cstack.c.o): in function `print_trace.part.0':
pl-cstack.c:(.text+0xb7): undefined reference to `dladdr'
So if STATIC_EXTENSIONS is TRUE, the configuration defines that libdl is not needed, which is obviously not the case. So, I need to activate the switch HAVE_LIBDL manually to get the linkage working.
Thanks. Seems to depend whether you link to the static or dynamic glibc. I’ve added an #ifdef. Also added a bit simpler way for explicit packages, e.g.
make -DSTATIC_EXTENSIONS=ON -DINSTALL_DOCUMENTATION=OFF -DSWIPL_PACKAGE_LIST="clib;plunit" -G Ninja ..
The SWIPL_PACKAGE_LIST option is not documented properly in CMAKE.md and on the website. It mentions a switch SWIPL_PACKAGES=List, but it should be SWIPL_PACKAGE_LIST=List, I think.
If STATIC_EXTENSIONS is switched on, the installed executable will contain a RUNPATH entry to <install-path>/lib/swipl/lib/x86_64-linux, although there are no shared libraries to load on that path.
Hmm. Weird. It creates static libraries and then links an executable from the main program and the static libraries. Why would cmake add a RUNPATH? As far as I can tell, the cmake scripts of Prolog do not mention RUNPATH.
The problem can be circumvented by adding “another” -lws2_32 to the end of the command. I guess the order of the libraries matters, and a proper fix would be to add ws2_32.lib to the libraries for package/clib.
Edit: It seems possible to fix this problem by changing the order of the socket libraries under WIN32, no idea why this is relevant:
Hmm. Weird. It creates static libraries and then links an executable from the main program and the static libraries. Why would cmake add a RUNPATH? As far as I can tell, the cmake scripts of Prolog do not mention RUNPATH.
I think it is because of the explicit setting of set(CMAKE_INSTALL_RPATH "${SWIPL_ABS_INSTALL_ARCH_LIB}") in cmake/Install.cmake. I don’t know why it is set twice in this file. Once unconditionally and a second time if the lib path is not in the “cmake platform implicit link directories”.
I also do not know, why cmake creates RUNPATH entries instead of RPATH entries. Perhaps it uses RUNPATH as soon as it is available on that platform.
I guess you should disable these tests. As there is no dynamic loading, the extension interface is not relevant anyway and including its tests surely is not.
I don’t know. It should not try to build packages/cpp anyway with -DSWIPL_PACKAGES_X=OFF. The static extensions isn’t worked out well. It is mostly there to support extensions for the WASM version. Eventually it should disable the stuff that is not compatible with it.
As a temporary workaround, I just cleared the content of cmake/Install.cmake to get rid of the RUNPATH entry. But this is of course not the general solution.
I pushed f817bbb7d3989c72a2101014338443cd14728f75 which skips all the RPATH stuff if the core is not build as a shared object. I think that is fine. Remains hard to access though. There are so many build targets and configurations that it is nearly impossible to validate all of these
I don’t know if that is correct. SWIPL_SHARED_LIB / SWIPL_STATIC_LIB only has an influence to the libswipl.*, isn’t it? So the packages are still shared libraries, which need to be found by the swipl executable using RPATH. So the correct condition would be NOT STATIC_EXTENSIONS, I think.
But CMAKE_INSTALL_RPATH_USE_LINK_PATH perhaps also need to be set anyways to get RPATH for external libraries not in the standard paths.
I think it is Without libswipl.so/dylib/…, you can only use foreign extensions on ELF based systems as ELF is the only binary format that uses a process wide global dynamic symbol table to resolve the PL_* functions ((X)COFF resolves against other shared objects). So, not ELF and no shared kernel means no extensions. Using ELF, we can have extensions, but these are resolved against the process’ symbol table and we do not need to find libswipl for that.
So far I do not see a configuration where this fails (but, there are many …)
cmake -DSWIPL_SHARED_LIB=OFF -DSWIPL_STATIC_LIB=ON ..
ninja
src/swipl
?- use_module(library(archive)).
use_module(library(archive)).
ERROR: Exported procedure archive:archive_set_header_property/2 is not defined
ERROR: Exported procedure archive:archive_open_entry/2 is not defined
ERROR: Exported procedure archive:archive_next_header/2 is not defined
ERROR: Exported procedure archive:archive_close/1 is not defined
Do I understand correctly that this can’t be fixed (for the reasons stated above)? In other words, under Windows, static lib means static extensions, too.
Yes. The only binary format I know about that can resolve undefined symbols against the main executable is ELF (and only when compiled with -rdynamic on gcc). Windows and MacOS use COFF based executables. On the many Unix descendants you find several binary formats, among which ELF (e.g., Linux). COFF is more specific in where symbols need to be found, which reduces the likelihood of surprises but this makes it also less flexible.
Except when trying to create a single file executable with no or only system shared object dependencies there is these days no reason not compile the core into a shared object.