Much of SWI-Prolog builds conditionally. For example, regex support is built only when the pcre library is detected by cmake. This gets us a maximally useful SWI-Prolog for a particular system.
A downside is that it is not immediately obvious what will actually be built without knowing what packages your build environment provides, and how these influence the SWI-Prolog build.
I would like to explicitly enable, say, the pcre package, and have cmake fail if it lacks required dependencies to do this, rather than just disable the pcre package if the pcre library is not found. This does not seem to be possible.
Iām pretty unfamiliar with cmake. Is there some way to do what I want? More broadly, is there some way to build a standard SWI-Prolog distribution containing all the things youād expect for a desktop install, which will fail the build if anything is missing rather than silently turning off features?
[edit]
One way is to enable INSTALL_TESTS, call check_installation, and see if any warnings come up. But this can only be done after the build has already run.
My concern is actually packaging, as Iām trying to make some improvements to the current package definition in Nix.
I can study the build system and make sure that the required packages are present in the dependencies. But this is fragile. A next version of SWI-Prolog might introduce a new package that needs a new dependency, or existing dependency requirements might change, and when the packaged SWI-Prolog version is updated to the latest upstream source, there would be no immediate way of knowing that standard features were automatically disabled.
Much better to just say what I want and have the build system (or something else) validate that that is what Iāll get.
cmake itself has find_package() where you can add āREQUIREDā to make it fail if the dependency is not found. So, in theory we could add some flag, e.g. SWIPL_PACKAGES_REQUIRED (better name) and use this to add the REQUIRED keyword to all find_package() calls where we need to drop some feature if the package is not found.
Traditionally, SWI-Prolog provides check_installation/0 which analyses the system for available features and whether or not all foreign libraries can be loaded. So, you can run
./src/swipl -g check_installation -t halt
That might be enough? Possibly we need some flags/options to avoid warnings that do not satisfy this usage. For example, is lacking tcmalloc an issue or not? It improves memory management on Linux systems for certain multi-threaded workloads (notally web servers) because the default Linux malloc does a poor job here. check_installation/0 also warns of the executable is not (first) on $PATH or if the userās environment contains old config files.
The nice thing about check_installation is that it is lightweight and can be run on the not-yet-installed system as well as on the installed system, where it also verifies that the shared objects expected from the OS can actually be loaded.
There actually is a SWIPL_PACKAGES_PCRE build option, which is on by default.
But this doesnāt work as an override. Setting that explicitly to ON while not providing pcre in the build environment will still just build SWI-Prolog without pcre.
I like this solution. If you like, I could look into seeing if I can modify the build system for this. One problem I saw (at least in the places I looked) is that packages donāt really set anything to say they are being included, but maybe thatās just me misunderstanding cmake right now.
It is workable, and would make sure no dependency mistakes crept into packaging. I think it makes a lot of sense to run this as a post-build check. It would indeed have to be filtered for differences that are accounted for by the packaging explicitly wanting a different kind of output (excluding X/qt for example). Flags for that could work. So could a grep from the output of check_installation.
Still, failing early when explicitly requested features cannot be built would be nice. If the SWI-Prolog build cannot directly do failure on missing dependencies, Iām thinking of providing some pre-check script to fail the build early for cases I know will not work (but potentially not catching everything), then running check_installation after the build.
Go ahead. I think you only need to define some cmake variable that you add to the argument list of all find_package() calls that remove features. Note that that is not always trivial. E.g., for ssl we are happy with OpenSSL and LibreSSL. Lacking GMP we use the bundled LibBF, is this that a requirement? XPCE has a bunch of dependencies, several of which are non-fatal. I agree this is the best option for packagers.
That would be nice in general. As is we get warnings on explicitly disabled features. That is still nice to evaluate the suitability of a given swipl instance for what you are trying to do, but not to check whether this installation satisfies the intend of the packager. It probably needs two modes or two predicates. Possibly we can leave data from CMake in some file to make check_installation/0 aware of the intended packages?
In terminusdb we use gmp to communicate big numbers across fli boundaries. So there itās actually pretty important to know for sure things built with GMP, and we didnāt somehow get libBF instead.
As an extra installable file which is imported at runtime?
Possibly. It gets messy otherwise though. I am not aware that one can distinguish explicitly set options from default options in CMake. Hopefully Iām wrong.
I see. It is a little shaky as SWI-Prolog redefines the allocation hooks of GMP (but tries to not affect foreign code by calling the default hooks when used not as part of Prologās arithmetic). In Janus (the Python binding) and the WASM version I uses (hexadecimal) strings for bigints and rational numbers.
That would be the idea yes. We could also create library(check_installation) from some check_installation.pl.in using CMake. I think both are fine with me.
Another simple possibility for this PCRE2 option, is to simply force it on within swi-prolog. Who would complain, i.e. who has a good reason in 2024 for compiling swi-prolog without pcre2?
Itās probably not very common, but there are still constrained systems where you may want to build the smallest swipl you can, ditching any unnecessary dependencies. Being able to turn off things in the build that pull in dependencies you donāt need for a functioning (albeit less-featureful) swipl is great.
This is especially the case in very specific deployment scenarios, where you use swi-prolog for a single application only, rather than using it as a more general purpose prolog environment. For example, a prolog http service running on a server, or a swi-prolog embedded in a larger application.
If given the option, why would you go for a version that has support for all these features that your application doesnāt even depend on, but which nevertheless pull in extra dependencies?
Not everyone will care about doing such specific tuning for their deployments, but I appreciate that the option is there.
All packages of other peopleās software have this as a potential problem - I donāt think thereās a convenient cure, and updating packages as/when necessary is just the tedious housekeeping that comes with evolving software.
It can be mitigated by sensible defaults in the appās build system - e.g. if PCRE is expected to be intended by around 98% of the users, then the building script could intentionally fail unless e.g. -DENABLE_PCRE2=OFF is specified.
If you have a container that doesnāt have PCRE, you can build swipl without that dependency.
Cmake looks for the dependency in the āglobalā environment. For example, findPCRE.cmake has the line find_path(PCRE_INCLUDE_DIR NAMES pcre2.h), which on my system resolves to /usr/include/pcre2.h and which dpkg -S tells me is part of package libpcre2-dev:amd64; if you donāt want to build with PCRE, then you would need to do the equivalent of apt remove libpcre2-dev.
[The actual situation is a bit more complicated; thereās also a check for whether packages/pcre is present, which is another way of controlling what gets built; packages/pcre can be left out by simply not including that submodule.]
Sure, thereās probably no way to just make the build system automatically maintain a package, Iām not expecting that much. Package maintenance requires that someone occasionally updates what a package looks like, beyond merely refreshing the imported source, to get with the times.
I just want builds to fail when an enabled feature cannot be built, so builds break loudly rather than disable features silently.
The question here is not āhow do I build SWI-Prolog without pcreā. I know how to do that. The question is, how do we build SWI-Prolog with pcre (or any other feature, or a standard set of features), and have the build fail if itās not there?
Also features should (and are) just disableable by setting a flag, rather than modifying the build environment.
This is pretty much what we are looking for. It is rather ugly though. Possibly the dirty stuff can be centralized in a function on cmake/PackageSelection.cmake? I think this route is good, so Iām happy to apply this if it can be implemented more or less elegantly.
I still think it would be good to have an option that says āall features that rely on dependencies should be present, except those that are explicitly disabledā.
Iām afraid I have other priorities for the next couple of months ā¦
We might also be able to use tri-state options instead of two-state (boolean) options: [CMake] How to handle options with more than two possible values?
So the basic idea is to just have a string option instead, and have an AUTO (or maybe UNSET?) variant in addition to ON and OFF.