Building STP¶
The overview page has the recipe that works from a clean checkout. This page is the detail behind it: what STP depends on, which SAT backend to build against, and the configuration variables worth knowing.
STP is built with CMake, version 3.18 or newer.
CMake is a meta build system that generates build files for other tools
such as make(1), Visual Studio and Xcode. The 3.18 floor comes from the
vendored mimalloc, which is the default allocator; on an older CMake,
configure with -DSTP_ALLOCATOR=system to skip it and use the C
library’s malloc instead.
Dependencies¶
STP relies on flex, bison and python3, plus at least one SAT backend.
Nothing else has to be installed: with -DENABLE_AUTO_DOWNLOAD=ON the
build fetches every library it needs, and lit, which drives the
tests, into a virtual environment of its own.
Configuration fails if no backend is enabled.
On a Debian-like platform most of it comes from the package manager:
sudo apt-get install git build-essential cmake bison flex python3
A python3 interpreter is needed at build time – it generates the AST kind tables – and also for the Python interface and the test suite. git is needed to fetch the dependencies, which are cloned rather than downloaded as archives where their revision is a commit rather than a release.
The SAT backends bring their own dependencies, which are needed only if you
build that backend, and which the scripts/deps script for each one names:
CryptoMiniSat needs GMP (libgmp-dev), MiniSat needs zlib
(zlib1g-dev). Neither is used by STP itself.
STP has no submodules. Everything it does not contain itself is fetched
at a pinned revision, and with -DENABLE_AUTO_DOWNLOAD=ON that needs
nothing installed beforehand.
Most are ExternalProjects: built at build time, installed into
STP_DEP_DIR, and so built once however many build directories are
pointed at the same one. ABC is among them, which matters because it is
920 C files – but it also means every build sharing a dependency
directory shares one ABC, compiled with one set of flags. Its
optimisation level is whichever configuration built it first; its
defines are not left to chance, because STP’s own sources include
ABC’s headers and the two have to agree, so they are recorded in the
directory’s stamp and a mismatch is reported.
-DABC_DIR points at an existing ABC build, which is how to work on
the stp/abc fork – see Source code layout.
mimalloc is the exception: STP configures its build rather than
consuming its output, so it is fetched with CMake’s FetchContent, which
downloads during configuration so that add_subdirectory has
something to descend into. -DFETCHCONTENT_SOURCE_DIR_MIMALLOC
names an existing checkout.
The command-line parser CLI11 and
the header-only floating-point library
SymFPU are headers and nothing
more; CLI11_DIR and SYMFPU_INCLUDE_DIRS name existing copies.
One is not vendored: LibBF, which
converts the real literals in floating-point input –
((_ to_fp 8 24) RNE 1.5). It is required, and there are three ways to
get it, tried in this order:
-DLIBBF_DIR=<path>naming a directory that holdslibbf.hand a builtbflibrary. With it unset,deps/libbfis used if it holds one, which is where an earlier build put itan installed copy, found the way any library is – including one that an earlier build installed into
STP_DEP_DIR(see below)-DENABLE_AUTO_DOWNLOAD=ON, which clones stp/libbf at a pinned commit and builds it as part of this build, with this build’s compiler and flags
Without any of the three, configuration fails and says so. An offline build wants the first.
Upstream LibBF publishes release tarballs and no git repository, which is
what stp/libbf is for. It is laid out like STP’s ABC fork: master
holds the release tarballs verbatim, one commit each, and stp – the
branch the pin names – adds STP’s MSVC portability changes on top. Moving
to a newer release means importing its tarball there and rebasing stp
onto it, then moving the pin here.
SAT backends¶
A query with no solver flag on it goes to the first of these that the build compiled in:
CryptoMiniSat
CaDiCaL
MiniSat
CryptoMiniSat is therefore the default wherever it is linked, and
CaDiCaL is what a stock build solves with. CaDiCaL is also the one
always available: it is enabled when nothing is said, needs no system
library, and the build can produce one itself, so a query is never left
without a solver. CryptoMiniSat is linked whenever it is installed
(-DUSE_CRYPTOMINISAT=AUTO, the default). Either way --cadical,
--cryptominisat or --minisat overrides the order for one run.
The two other values are for builds that would rather not depend on what
the machine has lying around: -DUSE_CRYPTOMINISAT=ON makes a missing
CryptoMiniSat a configuration error, and -DUSE_CRYPTOMINISAT=OFF
never looks for one, which is what pins a build’s set of backends to the
flags that produced it. With -DENABLE_AUTO_DOWNLOAD=ON there is nothing to do: STP clones and
builds stp/cryptominisat at a
pinned commit, as it does for its other dependencies. An installed one is
found and preferred, including one installed into deps/install:
git clone https://github.com/msoos/cryptominisat
cd cryptominisat
mkdir build && cd build
cmake ..
cmake --build . -j$(nproc)
sudo cmake --install .
command -v ldconfig && sudo ldconfig
It is the one dependency STP does not build for you: it reaches the build as a CMake package rather than as a header and a library, and an ExternalProject would write that package only after the configure that has to read it. Install it, or run the script.
CaDiCaL is compiled in by default, is what a build without
CryptoMiniSat solves with, and is worth having on hard bitvector
problems. With
-DENABLE_AUTO_DOWNLOAD=ON there is nothing to do but ask for it;
otherwise an installed CaDiCaL is found the way any library is, or
CADICAL_DIR points at a checkout:
git clone https://github.com/arminbiere/cadical
cd cadical
git checkout rel-3.0.1
./configure -fPIC
make
Then configure STP with -DUSE_CADICAL:BOOL=ON -DCADICAL_DIR:PATH=<path>,
where <path> is the checkout containing src/cadical.hpp and
build/libcadical.a. -fPIC is required, because libcadical.a
is linked into STP’s shared library.
Whichever way it arrives, STP works out which CaDiCaL it has: a checkout
carries a VERSION file, and an installed copy is asked directly, by
compiling and running CaDiCaL::Solver::version(). That decides
whether --cadical-factor can be compiled in, and the answer is
printed at configure time.
CryptoMiniSat stays the default for a build that has it, and CaDiCaL is
the default for one that does not; --cadical, --cryptominisat or
--minisat selects a compiled-in backend at run time. With a
CaDiCaL 3.x build, --cadical-factor controls CaDiCaL’s bounded
variable addition: on – the default – off, or auto, which
enables it only for problems with array operations. auto was the
default until bounded variable addition was measured on bitvector-only
problems and found to pay there too.
CryptoMiniSat and CaDiCaL together¶
Enabling both is supported and needs nothing said about it. It used to:
CryptoMiniSat 5.14 and later fetch, build and install a CaDiCaL of their
own, so its prefix held a libcadical.a, a cadical/cadical.hpp and a
CMake package under the same names STP’s own CaDiCaL uses – which shadowed
STP’s header, captured STP’s lookup, and, when libcryptominisat5 was
static, put two sets of CaDiCaL symbols on one link line. Fitting both
backends in took a shared CryptoMiniSat in a prefix of its own, or giving
up STP’s pinned CaDiCaL for the 2.x copy CryptoMiniSat carried.
STP builds stp/cryptominisat
with -DNOCADICAL=ON, which fetches and installs no CaDiCaL at all, so
none of that arises. -DUSE_CADICAL=ON -DUSE_CRYPTOMINISAT=ON is an
ordinary configure, and the CaDiCaL linked is the one STP pins.
That option is sound because backbone extraction – reached only through
CryptoMiniSat’s backbone simplification token or its
backbone_simpl() API, and in neither default schedule – is the only
thing CryptoMiniSat uses CaDiCaL for, and STP calls neither.
stp --version reports the version of each backend actually linked, so
it is the quickest way to confirm what you ended up with.
MiniSat is optional and off by default; enable it with
-DUSE_MINISAT:BOOL=ON, which also needs zlib – MiniSat reads gzipped
DIMACS and says so in its public headers, so configuration fails without
it. With -DENABLE_AUTO_DOWNLOAD=ON there is nothing else to do: STP
clones and builds stp/minisat at a
pinned commit, which is an updated fork of a MiniSat that has not been
touched upstream since 2010 and no longer compiles as it stands. Your
distribution’s minisat package works too, as does one built by hand:
git clone https://github.com/stp/minisat
cd minisat
mkdir build && cd build
cmake ..
cmake --build . -j$(nproc)
sudo cmake --install .
command -v ldconfig && sudo ldconfig
Every dependency is fetched and built by the build itself under
-DENABLE_AUTO_DOWNLOAD=ON; none of them needs a script beforehand.
Building against non-installed libraries¶
To build STP’s dependencies without installing them, tell CMake where the artefacts are:
-DMINISAT_INCLUDE_DIRS:PATH=<path>and-DMINISAT_LIBDIR:PATH=<path>– the paths tominisat/core/Solver.hand to theminisatlibraries-Dcryptominisat5_DIR:PATH=<path>– the path tocryptominisat5Config.cmake
If the development libraries were not installed, MINISAT_LIBDIR can
be set to minisat’s build directory, and cryptominisat5_DIR to
CryptoMiniSat’s.
Floating-point support¶
Floating-point support is always built, backed by SymFPU. STP carries
four fixes to it that upstream has not taken; they are applied to the
copy the build fetches, so there is nothing to do. An existing clone can
be used instead, via -DSYMFPU_INCLUDE_DIRS=<directory containing the
clone> – that one is taken as-is, so it must already carry those
fixes, which are in cmake/deps-utils/symfpu.
STP solves the SMT-LIB floating-point theory and exposes floating-point
terms through the C, C++ (stp/fp.hpp) and Python APIs. Real literals
under to_fp – ((_ to_fp 8 24) RNE 0.1) – are folded to their
exactly-rounded bits while parsing, in any format and under any of the
five rounding modes. One operation is format-bounded: fp.rem is
refused past roughly binary64-sized formats, because its circuit unrolls
one divide step per representable exponent difference, which for
Float128 would be some 33000 steps deep.
Configuration variables¶
These apply to all generators:
CMAKE_BUILD_TYPE– the build type, e.g. ReleaseCMAKE_INSTALL_PREFIX– the prefix to install under, e.g./usr/localENABLE_ASSERTIONS– build with assertions. Three-valued:ONandOFFare honoured as given, and if it is left unset the build type decides – off forRelease, on for everything else. It used to be a plain on/off flag thatReleaseoverrode unconditionally, so-DENABLE_ASSERTIONS=ON -DCMAKE_BUILD_TYPE=Releasesilently produced a build without them; it now produces an asserting Release buildENABLE_TESTING– enable running the testsENABLE_PYTHON_INTERFACE– build the Python interface (Python 3 only)PYTHON_EXECUTABLE– which Python 3 to use, when more than one is installedSANITIZE– use Clang’s sanitization checks. It sets C++ flags only, and turns on the address and integer sanitizers alongside the undefined one; for the undefined-behaviour build CI runs, which also covers the vendored C, see Running the tests under UndefinedBehaviorSanitizerSTATICCOMPILE– build static libraries and binaries instead of dynamicBUILD_SHARED_LIBS– buildlibstpas a shared library (default ON; forced OFF bySTATICCOMPILE)USE_CRYPTOMINISAT–ONrequires CryptoMiniSat 5.11 or newer and fails configuration if it is missing or older,AUTOuses it when a new enough one happens to be installed, andOFF– the default – never uses it. (It replacesNOCRYPTOMINISATandFORCE_CMS, both of which are still accepted and warn)USE_CADICALandCADICAL_DIR– build the CaDiCaL backend (on by default), optionally against a named checkoutUSE_MINISAT– build the MiniSat backendTUNE_NATIVE– build with-mtune=nativeENABLE_LTO– optimise across translation units, and across STP and the dependencies it compiles. Off by default. On its own it is worth about a percent; most of its value is in what it lets a profile do, and the two are covered together in Link-time and profile-guided optimisationPGOandPGO_DIR–generateoruse, and where the profile lives.scripts/pgo-build.shruns both passes with a training run in between; the same section has the detailWERROR– treat compiler warnings as errorsBUILD_MANPAGE– build and install thestp(1)manpage, which needs help2man. Three-valued:ONrequires help2man and fails configuration without it,OFFnever builds the page, and if it is left unset the page is built when help2man happens to be installed. Packagers who need the page either present or absent for certain should say whichSYMFPU_INCLUDE_DIRS– build against an existing SymFPU clone rather than fetching one (point it at the directory containing the clone)CLI11_DIR– build against an existing CLI11 rather than fetching oneLIBBF_DIR– where to find an already-built LibBFENABLE_AUTO_DOWNLOAD– download and build dependencies that were not found, rather than failing. Off by default: a build that reaches the network should be asked toSTP_DEPS_LOCAL_ONLY– use no dependency from outside the build directory. Off by default. An installed ABC, CaDiCaL, CLI11, LibBF, MiniSat or SymFPU is not looked for and not used; each is built intoSTP_DEP_DIRinstead, which is inside the build directory unless it was pointed elsewhere. Pair it withENABLE_AUTO_DOWNLOADon a cold build directory, or there is nothing left to find and configuration stops –configure.sh --local-depsturns both on.A
-D<X>_DIRnaming a copy is unaffected: that is an answer rather than a search, and the build uses what it was given. LibBF is the one to know about, because thedeps/libbfit falls back on whenLIBBF_DIRsays nothing is a search, and is skipped along with the rest; pass-DLIBBF_DIR=<path>to use a LibBF there anyway. CryptoMiniSat is the exception, being the one dependency STP cannot build: under this option it is used only ifcryptominisat5_DIRnames one, and-DUSE_CRYPTOMINISAT=ONwithout that is a configuration error. A static CryptoMiniSat named that way brings a CaDiCaL of its own, which now meets one this build compiled rather than the same installed copy, so the collision described above is reached where it was not before: use a shared CryptoMiniSat, or-DUSE_CADICAL=OFF.This is narrower than CMake’s own
CMAKE_FIND_USE_CMAKE_SYSTEM_PATH=OFF, and deliberately: the same search also resolves flex, bison, zlib, GMP and python3, none of which STP can build for itself, so disabling it wholesale fails during configuration rather than confining anythingSTP_DEP_DIR– where dependencies this build downloads are installed, and where dependencies are looked for. It defaults to<build>/deps/install, so a build directory is self-contained. Point several build directories at one path and only the first pays to build anything: the rest find what it installed and download nothing, so they do not even needENABLE_AUTO_DOWNLOAD. To fill such a directory ahead of time, configure one build with-DSTP_DEP_DIR=<path> -DENABLE_AUTO_DOWNLOAD=ONand build itsdepstarget, which builds the dependencies and nothing else.Only the installed dependencies are shared. ExternalProject’s own scratch and stamp files stay in the build directory, so two builds sharing a path cannot corrupt each other’s state – though a shared directory does hold one copy of each library, whatever compiled it, and STP warns when the compiler or sanitizer settings that filled it differ from the ones now building against it
STP_ALLOCATOR– which memory allocator thestpbinary uses. STP is allocation-heavy and the C library allocator is a significant bottleneck, so this defaults tomimalloc, which is vendored and built as part of STP. Set it totcmallocto link a system gperftools instead, or tosystemfor plainmalloc– roughly 14% slower, but the lowest peak memory. Only the executables link the allocator;libstpleaves the choice to whatever application embeds it.
There are three ways to set them, in decreasing order of friendliness:
run cmake-gui on the source root instead of cmake, which also
lets you pick the generator; run ccmake, which is the same idea in an
ncurses terminal interface; or pass -D<VARIABLE>=<VALUE> to cmake,
which is best kept for scripts. An already-configured build can be
changed with make edit_cache, which reconfigures and regenerates.
Link-time and profile-guided optimisation¶
Two optimisations that are off by default and want to be turned on together. Neither changes what STP computes; both change how long it takes to compute it.
-DENABLE_LTO=ON optimises across translation units. It reaches the
dependencies as well as STP itself, which is the point: most of a hard
query’s time is not spent in libstp at all. On a ten-second QF_BV
query, CaDiCaL::Internal::propagate() alone is a quarter of the
instructions retired, and CaDiCaL as a whole is most of the rest.
-DPGO=generate then -DPGO=use compiles twice, with a run of the
first build in between to record which branches are taken and which code
is hot. scripts/pgo-build.sh does all of it – configure, build,
train, configure, build:
CC=clang CXX=clang++ ./scripts/pgo-build.sh release --lto --ninja --auto-download
Options it does not recognise go to configure.sh, so the build is
configured as usual. --train=PATH names what to train on, and may be
repeated; it defaults to tests/query-files, the query suite in the
source tree.
What it is worth¶
Measured over 726 SMT-LIB queries (QF_BV, QF_ABV, QF_FP, QF_BVFP,
QF_ABVFP; 20-core Xeon, each configuration run interleaved with the
others on a pinned core, best of three), against the same compiler’s
plain release build:
Configuration |
clang 21 |
gcc 13 |
|---|---|---|
|
-1.0% |
-1.0% |
|
-3.7% |
-1.5% |
both |
-5.4% |
-3.8% |
as the geometric mean of the per-query change, which weights a millisecond query and a ten-second one alike. Summed instead, so that the hard queries dominate, clang with both is 7% faster and gcc with both is 1% faster: gcc’s profile pays off on the front end, where a small query spends its time, and hardly at all inside CaDiCaL’s search, where a large one does.
The split is sharper still on queries that are entirely CaDiCaL. Over 57 of them taking 12 to 123 seconds each, clang with both keeps its 4% – 4.2% on the geometric mean, 4.4% at the median query – and gcc with both has nothing left, at 0.1% on the median query.
Instructions retired fall by more than the time does – 6.2% for gcc with both, over the same queries under callgrind. That gap is the honest shape of the result: PGO removes work, and what remains is increasingly waiting on memory rather than executing.
Training on tests/query-files¶
The default training set is the test suite, which takes about fifteen seconds to run and needs nothing downloaded. It is not a compromise. Trained instead on a disjoint sample of 443 SMT-LIB queries, on 60 deliberately hard ones, or on both corpora together, the same build lands within half a percent of it either way – and which of them is ahead changes with the compiler and with the run. The profile is being used to decide inlining and code layout, and a small query exercises the same code as a large one, just less of it.
Two things do matter more than the training set:
GCC needs
-fprofile-partial-training, which the build passes for it. Without it, code the training run never reached is optimised for size, and a run oftests/query-filesleaves most of CaDiCaL’s search cold. Turning it off cost 0.8% of the 3.8% above.Clang wants the IR instrumentation,
-fprofile-generate, which is what the build uses – not the frontend’s-fprofile-instr-generate, which measured 1.5% worse here.
Which linker¶
With clang, it makes a difference of its own. The same objects, a
bytecode-for-bytecode identical .text and an identical exported
symbol set, linked three ways: through lld the heaviest queries ran about
2% faster than through GNU ld or mold – 2% at the median of the queries
over three seconds, up to 15% on individual ones. That is code layout,
and it is the one part of this that nothing in the source tree controls.
lld is also required rather than merely preferable for the generate
pass. Clang finds its counters through __start___llvm_prf_* symbols
that the linker synthesises; under ThinLTO the sections they refer to do
not exist until the LTO backend has run, and GNU ld decides the symbols
before that, so a target whose inputs are all bytecode – which, with
--testing, several of the unit tests are – fails to link:
undefined reference to `__start___llvm_prf_names'
pgo-build.sh therefore links with lld when the compiler is clang and
ld.lld is installed, unless a linker was named on its command line.
Caveats¶
Both passes have to use the same build directory. GCC names each
.gcdaafter the absolute path of the object file it came from, so a profile collected in one build directory is invisible from another.pgo-build.shreconfigures in place for exactly this reason.The dependencies are rebuilt between the passes, since they are compiled with the profile too.
pgo-build.shtherefore keeps them in the build directory and refuses--dep-dir.ENABLE_LTOrequires thatCCandCXXbe the same compiler at the same version. Without LTO a mismatched pair – which is what a machine whoseccis gcc 15 and whoseg++is gcc 11 has – builds STP quite happily; with it they exchange bytecode, and the build fails at the end withbytecode stream ... generated with LTO version 15.1 instead of the expected 11.3. Configuration checks for this and stops first.A profile is not portable and not reproducible: it belongs to one source tree and one compiler version, and two training runs of the same build do not produce byte-identical binaries. For a build that has to be reproducible, leave
PGOoff.ENABLE_LTOon its own is deterministic.
Working across several worktrees¶
Working on STP usually means several branches alive at once, and a git
worktree each is the pleasant way to hold them: every worktree is a real
checkout with its own build directory, so branches do not disturb each
other and a long build is never invalidated by switching branch.
git worktree add ../my-feature -b my-feature
The catch is that a fresh worktree looks like a fresh machine to the build. None of the dependencies live inside the repository any more, so a naive worktree downloads and rebuilds all of them. Two caches prevent that, and they are separate because the dependencies come in two kinds.
STP_DEP_DIR, described above, holds the ones STP links.
FETCHCONTENT_BASE_DIR holds the ones it compiles:
unordered_dense, mimalloc, googletest and OutputCheck. Share that one
for the download only, and read the note on it below before pointing two
build trees at the same one: FetchContent builds a dependency inside the
base directory too, so sharing it shares more than the download.
Warm both once:
export STP_DEP_DIR=~/.cache/stp/deps # configure.sh honours this
cmake -S . -B warm -G Ninja \
-DSTP_DEP_DIR=$STP_DEP_DIR \
-DFETCHCONTENT_BASE_DIR=~/.cache/stp/fetch \
-DENABLE_AUTO_DOWNLOAD=ON
cmake --build warm --target deps
then in every worktree:
cmake -S . -B build -G Ninja \
-DSTP_DEP_DIR=$STP_DEP_DIR \
-DFETCHCONTENT_BASE_DIR=~/.cache/stp/fetch \
-DENABLE_AUTO_DOWNLOAD=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
ENABLE_AUTO_DOWNLOAD=ON is still wanted even though everything is
already local, because a pinned revision can move under you and this is
what says the build may go and get it. To promise that it will not, leave
it off and pass -DFETCHCONTENT_FULLY_DISCONNECTED=ON instead: CMake
then skips the download and update steps outright, and a moved pin
becomes an error rather than a download. Nothing is re-fetched either
way – against a warm base directory the *-src trees are not touched.
Tests across worktrees¶
ENABLE_TESTING=ON also needs lit, which is not a fetched dependency:
it is pip-installed into a virtual environment inside the build
directory, so it is per-build-tree and none of the above shares it. An
installed lit is used if there is one. Otherwise, when configuring with
FETCHCONTENT_FULLY_DISCONNECTED=ON and no ENABLE_AUTO_DOWNLOAD,
point LIT_TOOL at one – the warm build’s copy will do:
-DLIT_TOOL=$PWD/warm/venv/bin/lit
Doing all of this by hand¶
Nothing above needs a tool: the flags are the whole of it, and they are
written out so that they can be typed, scripted or put in a
CMakeUserPresets.json, whichever suits.
If a shell function is what suits, stp.sh is a set of bash and zsh helpers that apply exactly these flags – one command to warm the caches, one to make a worktree, one to build it. It is a convenience kept alongside STP rather than part of it, and it is not what the rest of this page assumes: everything here works without it, and on the platforms it does not cover.
Building a static library and binary¶
mkdir build && cd build
cmake -DSTATICCOMPILE=ON ..
cmake --build . -j$(nproc)
sudo cmake --install .
command -v ldconfig && sudo ldconfig
Installing¶
make install installs, make uninstall removes. The root of the
installation is CMAKE_INSTALL_PREFIX, set at configure time or
changed later through make edit_cache.
Building on Windows¶
Two toolchains are built and tested: Visual Studio’s cl, and the MSYS2
UCRT64 gcc. Which SAT backend you get follows from which one you pick.
Under MSVC that is MiniSat; under MinGW it is CaDiCaL, whose own
BUILD.md documents a MinGW build. CryptoMiniSat is not built on
Windows at all – upstream supports MinGW there, and STP does not package
it – so both configure with -DUSE_CRYPTOMINISAT=OFF.
Everything else is fetched. -DENABLE_AUTO_DOWNLOAD=ON builds ABC,
LibBF, SymFPU, CLI11 and the SAT backend as part of the build, with its
compiler and its flags, so the toolchain, flex, bison and – for MiniSat
– a zlib are all that has to be installed beforehand.
Both use the Ninja generator rather than the Visual Studio one. Ninja
parallelises by default, where MSBuild without /m builds one project
at a time, and it honours CMAKE_<LANG>_COMPILER_LAUNCHER, which the
Visual Studio generator ignores silently, so a compiler cache does
nothing there. The cost is that Ninja does not locate the MSVC toolchain
for itself: start from an x64 Native Tools developer prompt, or enter
the developer shell first.
The two CI jobs – windows (minisat, MSVC) and
windows (cadical, MinGW) in
.github/workflows/ci.yml
– do exactly what is below, and are the reference if a detail here is
not enough.
Visual Studio¶
flex and bison do not come with Visual Studio.
winflexbison supplies
win_flex.exe and win_bison.exe, which are the names CMake’s
FindFLEX and FindBISON look for on Windows. Put its directory on
PATH and keep the extracted data/ beside the executables, since
bison finds its skeleton files relative to its own path.
MiniSat’s public headers include zlib.h, so a zlib is needed too –
vcpkg’s zlib:x64-windows-static, for one. Name the include directory
and the library file rather than reaching for ZLIB_ROOT: vcpkg
installs that library as zs.lib, which is not one of the names
FindZLIB searches for. What STP resolves is passed on to MiniSat’s
own build, which searches the default paths only, so one setting covers
both.
set ABC_USE_NO_PTHREADS=1
cmake -B build -G Ninja ^
-DCMAKE_BUILD_TYPE=RelWithDebInfo ^
-DENABLE_AUTO_DOWNLOAD=ON ^
-DSTATICCOMPILE=ON ^
-DUSE_MINISAT=ON -DUSE_CRYPTOMINISAT=OFF -DUSE_CADICAL=OFF ^
-DENABLE_PYTHON_INTERFACE=OFF ^
-DZLIB_INCLUDE_DIR=C:/vcpkg/installed/x64-windows-static/include ^
-DZLIB_LIBRARY=C:/vcpkg/installed/x64-windows-static/lib/zs.lib ^
.
cmake --build build
ZLIB_LIBRARY names the .lib itself, and vcpkg has not always
spelled it the same way, so look in that lib\ directory rather than
copying the line verbatim.
ABC_USE_NO_PTHREADS is read by ABC’s makefile while CMake configures.
Without it ABC’s threaded paths are compiled, and they do not build with
cl.
If a compiler cache is pointed at the build, add
-DCMAKE_POLICY_DEFAULT_CMP0141=NEW and
-DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=Embedded. The default /Zi
writes a program database shared by every translation unit, which is
neither cacheable nor safe to write from several compilations at once;
those two move the build onto /Z7.
MinGW (MSYS2 UCRT64)¶
From a UCRT64 shell:
pacman -S --needed bison flex git make \
mingw-w64-ucrt-x86_64-cmake \
mingw-w64-ucrt-x86_64-gcc \
mingw-w64-ucrt-x86_64-ninja
export ABC_USE_NO_PTHREADS=1
export ABC_USE_STDINT_H=1
cmake -B build -G Ninja \
-DENABLE_AUTO_DOWNLOAD=ON \
-DSTATICCOMPILE=ON \
-DUSE_CADICAL=ON -DUSE_CRYPTOMINISAT=OFF \
-DENABLE_PYTHON_INTERFACE=OFF \
.
cmake --build build --parallel "$(nproc)"
ABC_USE_STDINT_H is the one that is easy to miss. ABC’s architecture
probe reads eight-byte pointers as 64-bit Linux and picks an integer type
that is 32 bits wide under LLP64, and the pointer casts in its headers
then do not compile; the variable routes them onto stdint.h instead.
ABC_USE_NO_PTHREADS is as above.
CaDiCaL needs nothing extra here: cmake/FindCaDiCaL.cmake drives its
configure script and builds the library alone, which is what this
toolchain needs it to do.
Common to both¶
Ninja puts the binary at the top of the build tree:
build\stp.exe.-DSTATICCOMPILE=ONproduces anstp.exethat needs nothing beside it. Under MSVC it also moves STP and its dependencies onto the static CRT, so a dependency directory filled by one choice cannot be linked into a build that wants the other. STP records what filledSTP_DEP_DIRand warns when a later build disagrees.The Python interface is off in both jobs and is not exercised on Windows.
Neither job runs the lit suite; both run a handful of queries through the binary they built.
-DENABLE_TESTING=ONis correspondingly less well trodden there.
Testing¶
See Testing.