# Building SWI-Prolog using cmake
As of version 7.7.20, SWI-Prolog ships with `cmake` `CMakeLists.txt`
configuration files that cover the entire project. Builds have been
tested on Ubuntu 16.04, 18.04, 18.10, Fedore 28, MacOSX and cross
compilation for Win32 as well as Win64 using Ubuntu 18.04 as host
system.
The build has been tested with the "Unix Makefiles" and "Ninja"
generators. We use [Ninja](https://ninja-build.org/) as it builds
faster, avoids warning from being cluttered and better facilitates
debugging dependency issues. It can be selected using `cmake -G Ninja
...`, after which the usual `make` _target_ can be replaced by `ninja`
_target_. The examples below all use Ninja. Drop `-G Ninja` to use
classical Unix make.
## Getting cmake
Building SWI-Prolog requires cmake version 3.5 or later (*). Many Linux
systems ship with a cmake package. On MacOS we use the Macport version.
If the shipped cmake version is too old you may wish to download cmake
from https://cmake.org/download/ On Linux systems, installing cmake 3.12
is as simple as:
wget https://cmake.org/files/v3.12/cmake-3.12.0-Linux-x86_64.sh
sudo sh cmake-3.12.0-Linux-x86_64.sh --prefix=/usr/local --exclude-subdir
(*) Tested with 3.5 (Ubuntu Xenial), 3.10 (Ubuntu Bionic), 3.12 (MacOS).
Version 3.5 does not work with the 7.7.20 tar file, but does work with
the current git version.
## Native build
### Getting the source
The source may be downloaded as a tar ball from
http://www.swi-prolog.org or downloaded using git. The git sequence is:
git clone https://github.com/SWI-Prolog/swipl-devel.git
cd swipl-devel
git submodule update --init
If not all modules are needed, one can clone/update particular ones as follows:
git submodule update --init packages/jpl packages/clib packages/sgml
### Building from source
The typical sequence to build SWI-Prolog and install in `/usr/local` is
as follows:
cd swipl-devel
mkdir build
cd build
cmake -G Ninja ..
ninja
ctest -j 8
ninja install
### Upgrading
In most cases the following should update an installed system to the
latest version:
git pull
git submodule update --init
cd build
cmake ..
ninja
ctest -j 8
ninja install
If this fails, one of these measures may be appropriate:
1. run `ninja clean` before `ninja`
2. remove the entire `build` directory and re-create it as above.
Note that the build process makes no modifications outside the
`build` directory.
## Build types
The default build type is `RelWithDebInfo`. Alternatives may be selected
using e.g.,
cmake -DCMAKE_BUILD_TYPE=Debug -G Ninja ..
cmake -DCMAKE_BUILD_TYPE=Release -G Ninja ..
## Install location
To install in a particular location, use `-DCMAKE_INSTALL_PREFIX:PATH=/path/to/install`. For example, this will build SWI to be installed in `/usr/local/swipl-git` and will not include the documentation (see below for other customization options):
cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr/local/swipl-git -DINSTALL_DOCUMENTATION=OFF ..
After `sudo make install`, SWI will be located in `/usr/local/swipl-git`. Next adapt environment variables `SWI_HOME_DIR` and `LD_LIBRARY_PATH` to point to the new compiled and installed SWI system:
export SWI_HOME_DIR=/usr/local/swipl-git/lib/swipl/
export LD_LIBRARY_PATH=/usr/local/swipl-git/lib/swipl/lib/x86_64-linux/:$LD_LIBRARY_PATH
Finally, you can run it:
/usr/local/swipl-git/bin/swipl
_NOTE:_ if there is already an installed SWI (e.g., the one coming with a Linux distribution), running `swipl` will run the new installed system pointed by `SWI_HOME_DIR`.
## Customizing SWI-Prolog
By default the system configures all features. Several cmake _options_
allow for restricting the system.
| Option | Description |
| ----------------------------- | ----------------------------------- |
| `-DMULTI_THREADED=OFF` | Drop support for Prolog threads |
| `-DUSE_SIGNALS=OFF` | Drop signal support |
| `-DUSE_GMP=OFF` | Drop bignum and rational numbers |
| `-DSWIPL_SHARED_LIB=OFF` | Build Prolog kernel as static lib |
| `-DSWIPL_INSTALL_IN_LIB=ON` | Install libswipl.so in <prefix>/lib |
| `-DSWIPL_M32=ON` | Make 32-bit version on 64-bit Linux |
| `-DSWIPL_PACKAGES=OFF` | Only build the core system |
| `-DSWIPL_PACKAGES_BASIC=OFF` | Drop all basic packages |
| `-DSWIPL_PACKAGES_ODBC=OFF` | Drop ODBC and CQL packages |
| `-DSWIPL_PACKAGES_JAVA=OFF` | Drop JPL Java interface |
| `-DSWIPL_PACKAGES_X=OFF` | Drop graphics (xpce) |
| `-DBUILD_TESTING=OFF` | Do not setup for ctest unit tests |
| `-DINSTALL_TESTS=ON` | Add tests to installed system |
| `-DINSTALL_DOCUMENTATION=OFF` | Drop generating the HTML docs |
Note that packages for which the prerequisites cannot be found are
dropped automatically, as are packages for which the sources are not
installed.
## Profile Guided Optimization
When using Ninja and GCC, the system may be build using _Profile Guided
Optimization_ (PGO). This first builds the system instrumented to
collect profile information, then runs a benchmark suite and finally
recompiles it using the benchmark suite output to help (notably) branch
prediction. The performance improvement is about 10 to 20%.
Unfortunately the process is a little hard and the entire system needs
to be recompiled on any change made to it. To build the PGO version, run
the commands below. The `../scripts/pgo-compile.sh` performs the three
steps above using the core system. The final `ninja` builds the
packages and documentation.
cmake -DCMAKE_BUILD_TYPE=Release -G Ninja ..
../scripts/pgo-compile.sh
ninja
To stop using PGO builds in the current build directory run the commands
below. The `pgo-compile.sh -off` restores the normal build flags,
deletes the PGO data and cleans the core system files.
../scripts/pgo-compile.sh --off
ninja
## Cross build
Cross building for Windows using (Ubuntu) linux. Use `README.mingw` to
download and build the dependencies. Next, set these environment
variables:
- `MINGW64_ROOT` must point at the prefix where the dependencies
are for 64-bit Windows.
- `MINGW32_ROOT` must point at the prefix where the dependencies
are for 32-bit Windows.
The cmake toolchain config files (see below) search for Java in
`$HOME/.wine`. Please check these locations.
### 64 bit Windows from Linux
mkdir win64
cd win64
cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/cross/linux_win64.cmake -G Ninja ..
ninja
### 32 bit Windows from Linux
mkdir win32
cd win32
cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/cross/linux_win32.cmake -G Ninja ..
### WASM (Emscripten)
mkdir build.wasm
cd build.wasm
source ~/emsdk/emsdk_env.sh
cmake -DCMAKE_TOOLCHAIN_FILE=$EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DZLIB_LIBRARY=$HOME/zlib-1.2.11/libz.a \
-DZLIB_INCLUDE_DIR=$HOME/zlib-1.2.11 \
-DMULTI_THREADED=OFF \
-DUSE_SIGNALS=OFF \
-DUSE_GMP=OFF \
-DBUILD_SWIPL_LD=OFF \
-DSWIPL_PACKAGES=OFF \
-DINSTALL_DOCUMENTATION=OFF \
-G Ninja ..
### Building a 32-bit version on 64-bit Debian based Linux
Building the 32-bit version on a 64 bit platform can be useful for
testing and creating 32-bit .qlf files or saved states. A fairly
complete system is created using the configuration command below.
cmake -DSWIPL_M32=ON \
-DSWIPL_PACKAGES_JAVA=OFF -DSWIPL_PACKAGES_QT=OFF \
-G Ninja ..
### Cross-building for targets without an emulator
In the above scenarios we have an emulator (Wine, Node.js) that can run
the compiled Prolog system so we can do the Prolog steps of the
installation such as building the boot file, building .qlf files,
library indexes and the documentation. On some systems we do not have a
suitable emulator. Experimental support is provided using the following
steps:
- Build a native Prolog system in a directory, say `native`. This
version must have the same _word-size_ (32 or 64-bits) as the
cross-compiled target. One the core Prolog system (no packages)
is required and the system only needs to be build, i.e., the
_install_ step is allowed but not needed. See above.
- Specify `-DSWIPL_NATIVE_FRIEND=native` for the cross-compilation.
This will cause the above system to be used for the cross
compilation steps.
## Development
When building SWI-Prolog using cmake a complete installation is created
in the cmake _build_ directory. If possible, the files from the source
tree that do not need modification are created as _symbolic links_ to
the real sources. This implies that `src/swipl` can be used as a
complete development environment and library and system predicates can
be edited using edit/1 and friends.
The script `scripts/swi-activate` may be used to create symlinks from
$HOME/bin to the version in the current working directory. It may be
used to activate the system in the build directory or where it is
installed. It is called from the build directory as one of:
../scripts/swipl-activate
../scripts/swipl-activate --installed
Developers may wish to set the environment variable
`SWIPL_INSTALL_PREFIX`, which is used as the default for
`CMAKE_INSTALL_PREFIX`. Moreover, if this variable includes `@builddir@`
this string is replaced with the basename of the current build
directory. This aims at the following scenario:
1. Set e.g. `export SWIPL_INSTALL_PREFIX=$HOME/cmake/@builddir@`
2. Use multiple build directories for debug, different targets or
different configurations. Typically these are called `build.<config>`,
for example `build.single-threaded`.
3. Configure without specifying a `CMAKE_INSTALL_PREFIX`
4. Build, test and install. Optionally use `swipl-activate` to
use this version as default.
### Testing
Tests are registered for use with `ctest`. To run all tests, simply run
this in the build directory. Tests can be run concurrently (`-j 8`
below).
% ctest -j 8
Note that there seem to be few tests. This is misleading. Each ctest
test loads a Prolog file that may run hundreds of tests. If a test
fails, run the command below to get details. Tests are named
_package_:_name_, so `ctest -V -R clib:` runs the tests for the `clib`
package.
% ctest -V -R name
Note that all tests can be executed interactively by loading the test
file and calling the entry point as illustrated. The entry point is
always the base name of the file (without directory and without
extension).
% src/swipl ../src/Tests/core/test_arith.pl
?- test_arith.
% PL-Unit: div ... done
...
## Packaging
### Windows
The windows installer is created from the cross-compiled version using a
Linux native port of the NSIS installer generator. Ensure `makensis` is
installed (`apt-get install nsis`) and run the commands below to in the
build directory create the installer:
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../cmake/cross/linux_win64.cmake -G Ninja ..
ninja
cpack
And, for the 32-bit version:
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../cmake/cross/linux_win32.cmake -G Ninja ..
ninja
cpack
### Debian based Linux systems (.deb or .rpm)
The following commands create swipl-<version>-<nr>.<cpu>.deb/rpm file
with SWI-Prolog to be installed in /usr. The process creates a monolitic
installer for a particular configuration of SWI-Prolog. This is *not*
what is typically used to create packages for distributions. Distro
package maintainers are referred to _Modular packages for Linux_ below.
The prodedure here is intended to create custom Debian packages for
in-house deployment.
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -G Ninja ..
ninja
cpack -G DEB
for generating an RPM, use `cpack -G RPM`. The cmake configure run
selects a default packager depending on the availability of the package
installer `apt` (assuming DEB) or `dnf` (assuming RPM).
#### Modular packages for Linux
Most Linux distributions with to install SWI-Prolog using multiple
packages, notably to reduce dependencies. For example, the xpce package
os normally provided by a package `swi-prolog-x` and the core of
SWI-Prolog as `swi-prolog-nox`. This allows installing `swi-prolog-nox`
on headless servers without installing X11.
Modular installation can be based on cmake _COMPONENTS_. The files for a
particular component can be installed using, for example (not this is a
one-line command):
DESTDIR=$(pwd)/<component> \
cmake -DCMAKE_INSTALL_COMPONENT=<component> \
-P cmake_install.cmake
The defined components are:
| Component | Description |
| -------------------- | ------------------------------------ |
| Core_system | Compiler and core libraries |
| Core_packages | Packages with few dependencies |
| Archive_interface | Libarchive binding |
| Commandline_editors | Readline and libedit interfaces |
| ODBC_interface | ODBC binding |
| BerkeleyDB_interface | BDB interface |
| Perl_regex | PCRE library binding |
| YAML_support | Libyaml binding |
| Java_interface | Java interface (JPL) |
| OpenSSL_interface | Binding to OpenSSL/LibreSSL |
| TIPC_networking | Linux TIPC network support |
| Qt_console | Qt windowed interface |
| Graphics_subsystem | The xpce graphics system (needs X11) |
| Documentation | System HTML documentation |
| Examples | Example files |
See the `debian` subdirectory for the complete set of rules we use to
generate the Ubuntu PPA releases.
### Create a MacOSX Bundle
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_MACOS_BUNDLE=ON -G Ninja ..
ninja
cpack
## Issues
- Provide a FindSWIPL.cmake?
- Problem compiling SWI when another SWI is installed already and you
have environment variables set to facilitate e.g., embedding in Java.
The variable names and possibly conflicting values depend on the OS.
See [issue](https://github.com/SWI-Prolog/swipl-devel/issues/435)