Building VTK#
One command builds a VTK wheel from source:
pyvista-build vtk
It works on Linux, macOS, and Windows and follows the official Building Python wheels instructions, with the options PyVista’s own CI uses. A first build takes from minutes to over an hour and needs several GB of disk.
The wheel is built for, and installed into, the active virtual environment, else
.venvin the current directory, else the Python running the command.--python PATHpicks another interpreter.It says where the build goes and asks once before starting, then builds with those defaults straight through. Anything missing that it would install is listed before that question, which covers it too.
--yesanswers it in advance.Every command is printed as it runs. Its output shows as one line that updates as it runs, with the time elapsed.
--verbose(-v) prints all of the output and the environment variables each command sets.
--interactive walks through the build one step at a time:
Each step shows its settings, says what it is about to do and where, and waits for a yes.
Enter accepts the default,
ngoes through the settings one by one, and the same flags the command line takes change one in place.
pyvista-build vtk --interactive
pyvista-build --help lists every flag. The result is a wheel, so once
installed (manually or with --install) PyVista picks it up like the
stock one.
The Steps#
Every build runs the same eight steps, in this order. Each one prints what it
is about to do, and --interactive waits for a yes before it runs. See the
dry run for sample output for each step.
1. Tools#
Ensure the tools the build needs are available.
Checks
git,cmake,ninja, a C++ compiler, the wheel repair tool, andpatchelfon Linux before anything is downloaded. See Tooling for what each one does.Lists everything the build would install, each item with where it goes:
cmake,ninja, the repair tool, andpatchelfon Linux when missing or too old,setuptoolsandwheel, and the finished wheel with--install.Starting the build covers that whole list.
--interactiveasks again at this step, and--yesanswers in advance. Without a terminal and without--yesthe command stops instead of installing.The compiler has to compile and link a one-line program. A missing or broken one stops with instructions for your operating system, such as an Xcode and Command Line Tools pair that no longer match after a macOS update. On Windows, Visual Studio’s build environment is imported automatically.
A compiler cache (
ccacheorsccache) is used when one is onPATH.--compiler-cache nonebuilds without one.When the cloned source asks for other
cmakeorninjaversions than the ones checked, as on a firstcvistabuild, those are checked again after step 2.
2. Source#
Get the VTK source to build.
Clones VTK into
./vtk-build/srcat the release tag PyVista supports.--refpicks another tag, branch, or commit.--build-dirputs everything somewhere else.--source DIRbuilds a checkout you already have.An existing checkout is reused as is, local edits included.
With
--interactivethe clone prompt also takes a fork’s git URL or the path of another checkout, and an existing checkout is confirmed before it is reused. Answering with a git URL there deletes it, after one more confirmation, and clones the fork in its place.A build tree configured from one checkout cannot build another, so switching checkouts asks before deleting the build tree.
--cleanor another--build-diravoids the question.
3. Build options#
Choose which modules and options to build.
On top of the modules every build has, the modules to build are organized into named groups. The default set matches the stock wheel plus what PyVista’s CI enables:
rendering: OpenGL rendering, widgets, charts, and textio: extra readers and writers (scene import, Exodus, Xdmf2)web: web export modules used by trame and the Jupyter backendsmatplotlib: Matplotlib-rendered math text and labelsparallel: DIY2-based parallel filtersserialization: object serialization and.pyistub filesheadless(Linux, off by default): no X, rendering through EGL or OSMesa, see Off-Screen Plotting GPU Support
Options:
--withand--withoutadd or drop groups,--minimalkeeps only the required ones.--opt smp=VALUEpicks the threading backend for SMP-enabled filters:Sequential(the default, as in the PyPI wheels),STDThread,OpenMP, orTBB, which needs TBB installed.At the prompt,
nasks about each group in turn, and the command-line flags work there as well.
pyvista-build vtk --without web,matplotlib
pyvista-build vtk --minimal --with rendering
pyvista-build vtk --opt smp=STDThread
4. Configure#
Generate the build tree with CMake.
Shows the build type, compiler cache, version suffix, and extra CMake cache entries, then runs
cmake.--build-type,--compiler-cache,--version-suffix, and-Dchange one directly. At the prompt,nasks about each in turn.Every command is printed in full before it runs.
5. Build#
Compile VTK.
Runs
cmake --buildwith Ninja and logs the full output tovtk-build/build.log.Uses one compile job per CPU core, at most one per 2 GB of memory, since each job can take that much.
--jobssets the number instead.When a command fails, its last lines of output are printed and the build stops. The log has the complete compiler output.
6. Wheel#
Package the build as a wheel.
Runs
setup.py bdist_wheelin the build tree.
7. Repair#
Make the wheel installable outside the build tree.
Bundles the libraries the wheel links against and sets its platform tag, so it installs outside the build tree and on other machines.
A manifest’s
[repair]table can ask for the bundled libraries to be stripped and pass extra arguments to the repair tool.A rerun reuses the repaired wheel when the built wheel’s contents have not changed.
--no-repairskips the step.
8. Install#
Install the wheel into the target environment.
--installinstalls the wheel into the target environment, which starting the build covers. Without it,--interactiveoffers to, and otherwise the wheel’s path and thepipcommand are printed.The wheel replaces the installed
vtk.pip install --force-reinstall vtkgoes back to the stock one.
Scripted Use#
Without --interactive the command asks once before it starts, and
that answer covers installing anything that is missing. Without a
terminal it stops at that question, so pass --yes in CI and scripts,
and --verbose so the job log shows every command in full and every
line of output. --dry-run
prints the commands, and the install list, without running anything.
For a backend whose manifest lives only in
its source tree, such as cvista, --dry-run needs an existing
checkout and stops without one. Optional steps keep their own switches, so
--no-repair skips the repair step and --install installs the
wheel at the end.
pyvista-build vtk --ref master --build-type RelWithDebInfo --jobs 8 --yes
pyvista-build vtk --dry-run
A backend that always builds the same way in CI keeps those flags in a
[defaults.<name>] table of its manifest, and the command line names
the set. A backend whose ci set holds --yes, --source . and
its build options runs its job as:
pyvista-build cvista --defaults ci
Flags given after the name still win, so --defaults ci --jobs 4 builds
the set with four jobs. Manifest Reference describes the table.
Developer Loop#
The build tree is kept between runs. Edit files under vtk-build/src
and run pyvista-build vtk again: configure is skipped unless the
options changed, ninja rebuilds what the edit touched and a new
wheel is written. --reconfigure forces cmake to run again,
--clean deletes the build tree first, and -D KEY=VALUE passes
any CMake cache entry straight through:
pyvista-build vtk --build-type Debug -D VTK_ENABLE_LOGGING=OFF
--ref leaves a checkout
that is already at that commit as it is, edits included, and otherwise
checks the commit out, which needs a checkout without local edits.
--update fetches first, then checks out --ref, or the release
tag when --ref is not given, and always needs a checkout without
local edits:
pyvista-build vtk --update --ref master
CI Workflows#
A CI job builds from scratch every time, so a compiler cache is what keeps it short: a warm cache turns a build of hours into minutes.
Pass
--yesand--verbose, as in Scripted Use.pip install pyvista-build[tools]installs every tool the build gets from PyPI up front, so the tools step has nothing left to install.The build uses
ccacheorsccache, whichever is onPATH. Installccacheon Linux and macOS (apt-get install ccache,brew install ccache) and set upsccacheon Windows, where MSVC needs it (mozilla-actions/sccache-action).--cache-dirputs the cache in a directory the job can save and restore between runs. Save it at the end of the job and restore it at the start, one cache per operating system: object files from one do not help another.The cache tools read their own environment variables, and the command passes every
CCACHE_*andSCCACHE_*setting through to the build and into the manylinux container except the host paths:CCACHE_DIRbecomes the mounted cache andCCACHE_BASEDIR,CCACHE_CONFIGPATH,CCACHE_LOGFILEandSCCACHE_DIRstay on the host.FORCE_COLOR,NO_COLOR,TERMandCOLUMNSgo in as well, so the container’s output is colored and wrapped like the host’s, and so does every variable the manifest’s[manylinux] envnames. SetFORCE_COLOR=1in a job to keep the colors in its log.CCACHE_MAXSIZE=1GorSCCACHE_CACHE_SIZE=1Gis the one worth setting in a job: the defaults are 5 GB and 10 GB, a full VTK build fits in 1 GB, and the cache is uploaded and downloaded on every run. A developer machine needs no cap.The command already keys
ccacheentries on the compiler’s version string rather than its binary’s timestamp (CCACHE_COMPILERCHECK) and on paths relative to the build (CCACHE_BASEDIR), and leaves the__DATE__and__TIME__macros, the locale variables and the defines of precompiled headers out of the hash (CCACHE_SLOPPINESS), so a runner image update that ships the same compiler, or a job that checks out elsewhere, keeps the cache valid. Each variable set in the environment beforehand wins over these defaults.On Linux add
--manylinuxfor a wheel that installs on other machines; the container installsccacheitself and uses the same directory.After the build, one line says how many of this run’s compilations hit and missed the cache, followed by the cumulative statistics. On GitHub Actions both go to the job summary (
GITHUB_STEP_SUMMARY), from inside the container as well.
pyvista-build vtk --yes --verbose --cache-dir compiler-cache
This repository’s own workflow does this on all three operating systems, keeping the cache as a workflow artifact. A full hit rate finishes in about 10 minutes on Linux, 25 on macOS, and 35 on Windows.
Other Backends#
The same command builds any VTK backend whose source tree carries a
pyvista-build.toml manifest. That file declares the groups and
options the backend offers, its tool requirements, per-platform CMake
init caches, and the extra commands it needs; stock VTK’s manifest ships
with pyvista-build. cvista, the
community fork, is known by name. A fork of VTK is built as vtk from
its URL, using the manifest
in its tree when it has one and the shipped one otherwise. A --url the
existing checkout in the build directory was not cloned from stops the
build, so give a fork its own --build-dir:
pyvista-build cvista
pyvista-build vtk --url https://github.com/me/vtk.git --ref my-branch --build-dir vtk-fork-build
Manifest Reference lists every key a manifest can set, for a fork that wants its own groups, options or hooks.
A backend built this way is selected like any other installed one:
automatically for cvista, or explicitly through
PYVISTA_VTK_BACKEND.
Off-Screen Plotting GPU Support#
The stock Linux wheels already render off-screen without an X server: VTK picks EGL for GPU rendering, or OSMesa for software rendering, at run time. To build a wheel that does not link against X at all:
pyvista-build vtk --with headless
Such a wheel cannot open on-screen windows, so use it only where you
save static images or stream the render window to another computer
with a display (for example, using
pyvista.set_jupyter_backend('server') and JupyterLab).
Portable Linux Wheels#
A wheel built on Linux is tagged for the glibc of the machine that
built it and may not install elsewhere. To share one, build it inside a
manylinux container, as PyVista’s
own CI does.
--manylinuxbuilds a Linux wheel only. It runs the build in a container through Docker, so Docker is needed for this flag and for nothing else.Without
--manylinuxno Docker is involved on any operating system, and macOS and Windows wheels are always built that way.A macOS or Windows machine can still run
--manylinuxto produce a Linux wheel, which it then cannot install.
Docker must be installed and running first:
Linux: install Docker Engine for your distribution, then add yourself to the
dockergroup (sudo usermod -aG docker $USER) and log in again so nosudois needed.macOS: install Docker Desktop for Mac (or
brew install --cask docker) and start it.Windows: install Docker Desktop for Windows with the WSL 2 backend and start it.
docker run --rm hello-world confirms it works. Then:
pyvista-build vtk --manylinux
What happens:
The image matches your machine’s architecture (
manylinux_2_28_x86_64ormanylinux_2_28_aarch64) and carries the same Python version as the one running the command.--manylinux-imagepicks another image.The source is cloned or updated on your machine first.
The container installs VTK’s build dependencies and this package’s requirements, mounts the
pyvista-buildyou are running read-only, and runs the remaining steps with the source and./vtk-buildmounted.The repair step runs
auditwheelthere with--platset to the image’s policy (itsAUDITWHEEL_PLAT), which gives the wheel the image’s tag and puts it invtk-build/wheelhouse.Files written by the container are handed back to your user, even when the build fails.
On a Linux host the install step runs afterwards. On macOS and Windows the wheel is only written, since it is for Linux.
Caches and limits:
The container installs
ccacheand keeps its cache between runs invtk-build/compiler-cache, or in--cache-diror$CCACHE_DIRwhen set.--compiler-cache noneskips it.sccacheis not available there.pipkeeps its cache invtk-build/pip-cache.A build tree configured inside the container cannot be continued outside it.
Tooling#
What the command looks for and offers to install. The tools extra
(pip install pyvista-build[tools]) installs every PyPI one up front,
here or in CI:
git clones the source and checks out the requested tag, branch, or commit. Never installed by the command.
CMake configures the build: it reads VTK’s
CMakeLists.txtand the options chosen, finds the compiler and Python, and writes the build files. Installed withpipwhen missing.Ninja is the build tool that CMake generates files for; it runs the compiler across all cores and only rebuilds what changed. Installed with
pipwhen missing.A C++ compiler: GCC or Clang on Linux, Xcode’s command-line tools on macOS (
xcode-select --install), Visual Studio with the Desktop development with C++ workload on Windows. Never installed by the command. A missing one stops with the instructions for your operating system.Development headers on Linux for Python, OpenGL, and X11:
sudo apt install python3-dev libgl1-mesa-dev libx11-dev libxcursor-devon Debian and Ubuntu, orsudo dnf install python3-devel mesa-libGL-devel libX11-devel libXcursor-develon Fedora. The tool check cannot see them, so a missing one stopscmakeinstead.ccache and sccache are compiler caches: they store each object file keyed by its inputs, so rebuilding after an edit or a reconfigure compiles again only what changed.
ccacheis the usual choice on Linux and macOS;sccacheis the one that supports MSVC on Windows. The build uses whichever is onPATH, and--compiler-cache noneturns it off.Wheel repair tools copy the shared libraries a wheel depends on into the wheel itself and set the platform tag, so it installs on other machines: auditwheel on Linux, which also needs patchelf, delocate on macOS, and delvewheel on Windows. Installed with
pipwhen missing.setuptools and wheel are the Python packages that
setup.py bdist_wheelneeds to package the build tree. Installed withpipwhen missing.Docker runs the manylinux container for
--manylinux. Never installed by the command.
Building by Hand#
pyvista-build vtk --dry-run prints the exact cmake and
setup.py commands, which is the quickest way to get a starting point
for a manual build. The essential configuration is:
git clone https://gitlab.kitware.com/vtk/vtk.git
cmake -S vtk -B vtk/build -GNinja \
-DCMAKE_BUILD_TYPE=Release \
-DVTK_WHEEL_BUILD=ON \
-DVTK_WRAP_PYTHON=ON \
-DVTK_BUILD_TESTING=OFF \
-DVTK_BUILD_DOCUMENTATION=OFF \
-DVTK_BUILD_EXAMPLES=OFF \
-DPython3_EXECUTABLE=$(which python)
cmake --build vtk/build --parallel
cd vtk/build && python setup.py bdist_wheel
The wheel is written to vtk/build/dist.