Skip to content

Building vgl

Jeremiah van Oosten edited this page Oct 19, 2026 · 3 revisions

Building vgl

This page explains how to build vgl from source: what you need installed, how to clone the repository, the CMake presets, every VGL_* CMake option, where each dependency comes from, static and shared builds, builds without exceptions and RTTI, running the tests, and notes for Windows, Linux and macOS. For consuming a built or packaged vgl from your own project, see Installing vgl. Builds for browsers and phones have pages of their own: Web builds and Mobile platforms.

This page describes vgl 1.0. To use vgl without building it, see Installing vgl: release archives, vcpkg and Conan.

Requirements

Tool Version Notes
CMake 3.24 or later 3.25 or later to use CMakePresets.json (preset schema version 6, workflow presets)
C++ compiler C++20 A current MSVC, GCC, Clang or Apple Clang, the Android NDK's Clang, or Emscripten. CI uses the compilers of the windows-2025, ubuntu-24.04 and macos-15 runners
C compiler C99 vgl compiles stb_image and Zstandard as C; the C API headers are C99
Ninja any recent Used by the Linux, macOS, Android, iOS and Emscripten presets (Ninja Multi-Config)
Network access at configure time Only for dependencies that are not installed (see Dependencies); turn VGL_FETCH_DEPENDENCIES off to forbid downloads

Optional, depending on what you build:

  • Windows SDK fxc for the Direct3D 11 backend, which compiles its HLSL at build time. It ships with the Windows SDK that Visual Studio installs. If CMake cannot find it, the backend is skipped with a warning.
  • libcurl for the defaults module's HTTP reader (VGL_DEFAULTS_HTTP), or network access to let CMake download and build curl.
  • GDAL 3.7 or later for the baker (VGL_BUILD_BAKER). It is never downloaded.
  • Ogre 14 for the Ogre backend (VGL_BACKEND_OGRE), or network access to let CMake download and build Ogre 14.6.1.
  • X11 and Wayland development headers on Linux, when CMake downloads GLFW for the samples.

The library itself uses only the C and C++ standard libraries (design document, section 4). The runtime dependencies are stb_image and Zstandard, both compiled into vgl when they are downloaded.

Cloning

git clone https://github.com/3dgep/vgl.git
cd vgl

The repository has one submodule, wiki, which is this GitHub wiki checked out next to the code so that its pages can be edited alongside it. It is not needed to build vgl, and a plain git clone (without --recurse-submodules) is all you need. Contributors who edit the wiki fetch it with git submodule update --init wiki.

The sample data in samples/data (about 30 MB of small packs baked by vgl's baker) is part of the repository as ordinary files, so the samples and tests work offline after the clone.

Quick start

Without presets, any generator works:

cmake -S . -B build
cmake --build build --config Release
ctest --test-dir build -C Release

With presets, a workflow preset configures, builds and tests in one step:

cmake --list-presets=all
cmake --workflow --preset windows-msvc-static-release   # on Windows
cmake --workflow --preset linux-gcc-static-release      # on Linux
cmake --workflow --preset macos-clang-static-release    # on macOS

Presets

CMakePresets.json has the configurations CI builds. Every configure preset writes its build tree to build/<preset> and installs to install/<preset>, exports compile_commands.json, and turns VGL_WARNINGS_AS_ERRORS on. The multi-config generators put executables and DLLs in build/<preset>/bin/<Config>, for example build/linux-gcc-static/bin/Release/vgl-headless.

Presets are only listed on the host they apply to (a condition on the host system, or on an environment variable for the cross builds).

Configure presets

Preset Host Generator What it sets
windows-msvc-static Windows Newest Visual Studio BUILD_SHARED_LIBS=OFF
windows-msvc-shared Windows Newest Visual Studio BUILD_SHARED_LIBS=ON, VGL_DEFAULTS_HTTP=ON
windows-msvc-noexcept Windows Newest Visual Studio VGL_DISABLE_EXCEPTIONS=ON
windows-msvc-baker Windows Newest Visual Studio Static, VGL_BUILD_BAKER=ON, VGL_DEFAULTS_HTTP=ON, CMAKE_PREFIX_PATH=$env{CONDA_PREFIX}/Library (activate the conda-forge environment first)
linux-gcc-static Linux Ninja Multi-Config GCC, BUILD_SHARED_LIBS=OFF
linux-gcc-shared Linux Ninja Multi-Config GCC, BUILD_SHARED_LIBS=ON, VGL_DEFAULTS_HTTP=ON
linux-gcc-noexcept Linux Ninja Multi-Config GCC, VGL_DISABLE_EXCEPTIONS=ON
linux-gcc-baker Linux Ninja Multi-Config GCC, static, VGL_BUILD_BAKER=ON, VGL_DEFAULTS_HTTP=ON
linux-clang-static Linux Ninja Multi-Config Clang, BUILD_SHARED_LIBS=OFF
linux-clang-shared Linux Ninja Multi-Config Clang, BUILD_SHARED_LIBS=ON, VGL_DEFAULTS_HTTP=ON
linux-clang-noexcept Linux Ninja Multi-Config Clang, VGL_DISABLE_EXCEPTIONS=ON
macos-clang-static macOS Ninja Multi-Config Apple Clang, BUILD_SHARED_LIBS=OFF
macos-clang-shared macOS Ninja Multi-Config Apple Clang, BUILD_SHARED_LIBS=ON
android-arm64 any, with ANDROID_NDK set Ninja Multi-Config NDK toolchain, arm64-v8a, API 24, static; see Mobile platforms
ios-arm64 macOS Ninja Multi-Config iOS arm64, deployment target 15.0, static; see Mobile platforms
emscripten any, with EMSDK set Ninja Multi-Config Emscripten toolchain, static, -pthread, VGL_DEFAULTS_HTTP=ON; see Web builds

Build, test and workflow presets

Each configure preset has build and test presets named <preset>-debug and <preset>-release (the baker presets and the cross builds have -release only), and a workflow preset of the same name that runs configure, build and test in order. The Android and iOS workflows configure and build only, since their tests need a device, emulator or simulator.

# Configure once, then build and test separately.
cmake --preset linux-clang-shared
cmake --build --preset linux-clang-shared-release
ctest --preset linux-clang-shared-release

# Or all in one.
cmake --workflow --preset linux-clang-shared-release

The test presets show the output of failing tests and fail if no tests were found.

CMake options

vgl's options all start with VGL_. Options that default to "top level" are on when vgl is the top-level project and off when it is added to another project with add_subdirectory or FetchContent, so that embedding vgl builds only the library.

Components

Option Default Meaning
BUILD_SHARED_LIBS OFF Standard CMake option: build vgl, vgl-defaults, vgl-gl and vgl-d3d11 as shared libraries. The Ogre backend is always static
VGL_BUILD_DEFAULTS ON Build the defaults module, vgl::defaults: a thread pool, a file reader, a disk cache and, with VGL_DEFAULTS_HTTP, an HTTP reader. The samples need it (Defaults module)
VGL_DEFAULTS_HTTP OFF Give the defaults module an HTTP reader. Natively it uses libcurl (installed, or downloaded); with Emscripten it uses the browser's fetch and needs no library. Without it, vgl_http_reader_create returns VGL_RESULT_NOT_SUPPORTED
VGL_BACKEND_GL ON Build the OpenGL 3.3 / OpenGL ES 3.0 backend, vgl::gl (OpenGL backend)
VGL_BACKEND_D3D11 ON on Windows Build the Direct3D 11 backend, vgl::d3d11 (Direct3D 11 backend). Not available elsewhere; skipped with a warning if fxc is not found
VGL_BACKEND_OGRE OFF Build the Ogre backend, vgl::ogre, for classic Ogre 14 (Ogre backend)
VGL_BUILD_BAKER OFF Build the baking tool vgl-bake (needs GDAL 3.7 or later) (Baker)
VGL_BUILD_SAMPLES top level Build the samples (Samples)
VGL_BUILD_TESTS top level Build the tests
VGL_INSTALL top level Generate install rules, the CMake package and the pkg-config files (Installing vgl)

Library rules and strictness

Option Default Meaning
VGL_DISABLE_EXCEPTIONS OFF Build the library targets without exceptions and RTTI (see below)
VGL_WARNINGS_AS_ERRORS OFF Treat compiler warnings as errors (/WX or -Werror). Every preset turns it on

Dependency options

Option Default Meaning
VGL_FETCH_DEPENDENCIES ON Download, at a pinned version with a checked hash, each dependency that is not installed. Off, a missing runtime dependency is a configure error, and parts that need a missing optional one (Ogre, GLFW, Dear ImGui) are skipped
VGL_ZSTD_PROVIDER AUTO Where Zstandard comes from: AUTO (installed, else downloaded), SYSTEM (installed only; an error if none is found) or BUNDLED (always downloaded and compiled into vgl)

Tests that need extra software

Option Default Meaning
VGL_TEST_GL OFF Add the checks of the OpenGL, pure-C and Ogre samples as tests (gl, gl_es, gl_c, ogre_gl, ogre_d3d11). They need a display and an OpenGL driver; CI runs them under Xvfb with Mesa
VGL_TEST_BROWSER OFF Emscripten builds only: add the browser test, which serves the OpenGL sample's page with Caddy and checks it in headless Chrome. VGL_CHROME and VGL_CADDY name the programs if they are not on the path

Dependencies

Each dependency is looked for as an installed package first (system packages, vcpkg, conda or anything on CMAKE_PREFIX_PATH), and otherwise downloaded with FetchContent at a pinned version with a checked hash, unless VGL_FETCH_DEPENDENCIES is off. The configure output says which was used, in lines that start with vgl:.

Dependency Used by Installed package Download
Zstandard Runtime (decompression), baker (compression) find_package(zstd 1.4 CONFIG) 1.5.7, compiled into vgl with hidden symbols, no assembly, no multithreading
stb_image Runtime (JPEG and PNG imagery tiles) stb_image.h found with find_path (for example Debian's libstb-dev or vcpkg's stb) 2.30 at a pinned commit, compiled into vgl
libcurl Defaults module's HTTP reader (VGL_DEFAULTS_HTTP), vgl-bake check find_package(CURL) curl 8.11.1, static, HTTP and HTTPS only, on Schannel (Windows), Secure Transport (Apple) or OpenSSL (elsewhere)
Ogre Ogre backend and sample (VGL_BACKEND_OGRE) find_package(OGRE 14 CONFIG), through OGRE_DIR or CMAKE_PREFIX_PATH 14.6.1, static, with only the OpenGL 3+ render system (and Direct3D 11 on Windows), RTSS, Bites, the overlay with Dear ImGui and the stb codec
GDAL Baker only find_package(GDAL 3.7) Never downloaded
nlohmann/json Baker only find_package(nlohmann_json 3.10 CONFIG) 3.11.3 (headers)
GLFW OpenGL, pure-C and Ogre samples find_package(glfw3 3.3 CONFIG) 3.4, static. With Emscripten, its GLFW port is used instead
Dear ImGui Interactive samples' overlay Never looked for 1.92.9b; without VGL_FETCH_DEPENDENCIES, the OpenGL and Direct3D 11 samples are skipped

Notes:

  • Zstandard. With an installed Zstandard, a static vgl passes the dependency on to its consumers (find_dependency(zstd CONFIG) in the package, Requires.private: libzstd in vgl.pc). A downloaded one is compiled in, and consumers need nothing. Use VGL_ZSTD_PROVIDER=BUNDLED for self-contained binaries (the release archives and the cross-build presets do) and SYSTEM for package managers that must not download anything.
  • libcurl. A downloaded curl is linked into vgl-defaults and not installed. An installed static vgl-defaults with the HTTP reader therefore needs an installed libcurl, which its CMake package finds with find_dependency(CURL). On Linux, install libcurl4-openssl-dev (Debian, Ubuntu) to avoid building curl.
  • Ogre. Building Ogre the first time takes a while. A downloaded Ogre is part of vgl's build tree and is not installed, so vgl::ogre is installed only when vgl was built against an installed Ogre (Installing vgl).
  • GDAL. On Linux, install it from the system packages (libgdal-dev); on Windows, from conda-forge with the environment in tools/baker/environment.yml. See Baker and the baker's README.
  • Offline builds. Install Zstandard and stb_image (and libcurl, GLFW, Ogre as needed), then configure with -DVGL_FETCH_DEPENDENCIES=OFF. The interactive samples need Dear ImGui, which is only ever downloaded, so they are skipped; the headless sample still builds.

Static and shared libraries

vgl builds as a static library by default, and as a shared one with BUILD_SHARED_LIBS=ON. The core, the defaults module and the OpenGL and Direct3D 11 backends follow that setting; the Ogre backend is always static, so that it shares the host's Ogre instead of holding a second copy of Ogre's singletons.

A shared vgl exports only the C API (symbols are hidden by default, VGL_API marks the exports). The macro VGL_SHARED tells the headers that the library is shared: on Windows the declarations become __declspec(dllimport), elsewhere they get default visibility. Consumers get it automatically:

  • through CMake, vgl::vgl carries VGL_SHARED in its interface compile definitions;
  • through pkg-config, vgl.pc has -DVGL_SHARED in its Cflags;
  • through Conan, the package defines it for shared builds.

If you link a shared vgl without any of those, define VGL_SHARED yourself before including any vgl header. Never define it for a static vgl.

Things to know about each kind:

  • Static vgl is C++, so a C program that links it with the C linker also needs the C++ runtime. On Linux the vgl target links stdc++ and m for you, and vgl.pc lists them in Libs.private (use pkg-config --static). Apple's and Android's toolchains link libc++ themselves.
  • Shared vgl on Windows puts vgl.dll, vgl-defaults.dll, vgl-gl.dll and vgl-d3d11.dll next to the executables in a top-level build (build/<preset>/bin/<Config>). Your own executables need the DLLs next to them; see Installing vgl.
  • The library version is 1.0.0, with SOVERSION 1: the C ABI stays compatible within a major version, so the shared libraries are libvgl.so.1 and libvgl.1.dylib. (Before 1.0, the SOVERSION was the major and minor version.)

Building without exceptions and RTTI

vgl never lets an exception cross the API boundary, and its library targets build without exceptions and RTTI when VGL_DISABLE_EXCEPTIONS is on (the *-noexcept presets). This is for engines that compile everything with exceptions off.

cmake -S . -B build-noexcept -DVGL_DISABLE_EXCEPTIONS=ON
cmake --build build-noexcept --config Release

What it changes:

  • vgl, vgl-defaults, vgl-gl and vgl-d3d11 are compiled with /EHs-c- /GR- and _HAS_EXCEPTIONS=0 on MSVC, or -fno-exceptions -fno-rtti on GCC and Clang.
  • The tests, samples and the baker may still use exceptions; they are not affected.
  • The Ogre backend keeps exceptions, because Ogre throws. It catches them at its interface, so nothing escapes into the host.
  • The header-only C++ wrapper reports errors with vgl::expected (std::expected where the standard library has it, otherwise a minimal substitute that never throws), so it works in code built without exceptions too (C++ wrapper).

Running the tests

Tests are built when VGL_BUILD_TESTS is on (the default at the top level). Run them with CTest, naming the configuration for multi-config generators. The Release tests are about four times faster than Debug:

ctest --test-dir build/windows-msvc-static -C Release --output-on-failure
# or with a test preset
ctest --preset windows-msvc-static-release
# a subset, by name
ctest --preset windows-msvc-static-release -R "geodesy|tiling"
Test What it covers Built when
foundation, common, geodesy, tiling, selection, mesh, image, pack, context, render Internal unit tests (geodesy against GeographicLib reference values) Always
defaults Thread pool, file reader, disk cache VGL_BUILD_DEFAULTS
http HTTP reader against a small server on the loopback address VGL_DEFAULTS_HTTP, not Emscripten
api_c, api_cpp The C headers compile as C99 and the C++ wrapper as C++20, and both link against the library Always
headless The headless sample's --check on samples/data: loading, selection and frames without a GPU VGL_BUILD_SAMPLES
d3d11 The Direct3D 11 sample's check, offscreen, on the hardware device or WARP Windows, VGL_BUILD_SAMPLES
gl, gl_es, gl_c, ogre_gl, ogre_d3d11 Sample checks that need a display VGL_TEST_GL
baker, host_check Baker on synthetic surfaces; vgl-bake check against a local server (needs libcurl) VGL_BUILD_BAKER
browser The web page in headless Chrome Emscripten, VGL_TEST_BROWSER

On Linux without a GPU, the OpenGL checks run on Mesa's software renderer under a virtual X server, as CI does:

sudo apt-get install xvfb libgl1-mesa-dri libglx-mesa0 libegl-mesa0
cmake --preset linux-gcc-shared -DVGL_TEST_GL=ON
cmake --build --preset linux-gcc-shared-release
LIBGL_ALWAYS_SOFTWARE=1 xvfb-run -a ctest --test-dir build/linux-gcc-shared -C Release --output-on-failure

The samples' checks expect the sample set in samples/data, which their tests name explicitly.

Platform notes

Windows

  • Visual Studio with the "Desktop development with C++" workload, which includes the Windows SDK (for fxc) and CMake. The Windows presets leave the generator out, so CMake uses the newest installed Visual Studio. Ninja works too, from a developer command prompt.

  • The Direct3D 11 backend targets feature level 11_0 and links only d3d11.lib. Its sample and test use WARP, the software rasterizer every Windows machine has, when there is no GPU.

  • A static library from MSVC links only into builds with the same runtime (Debug or Release); build the configuration you link, or use a shared build.

  • The baker on Windows takes GDAL from conda-forge. Create and activate the environment, so that CONDA_PREFIX is set, then use the baker preset:

    micromamba create -p D:\vgl-env -f tools\baker\environment.yml
    micromamba activate D:\vgl-env
    cmake --workflow --preset windows-msvc-baker-release

    Keep that environment off PATH for ordinary builds: a re-configure can otherwise pick up its packages (such as its Zstandard DLL), and executables then fail to start.

Linux

  • The presets use Ninja Multi-Config with GCC (linux-gcc-*) or Clang (linux-clang-*).

  • The packages CI installs on Ubuntu 24.04 cover everything except the baker:

    sudo apt-get install ninja-build libzstd-dev libcurl4-openssl-dev \
        libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libwayland-dev libxkbcommon-dev

    The X11 and Wayland headers are for the GLFW that CMake downloads for the samples; with an installed GLFW (libglfw3-dev) they are not needed. For the baker add libgdal-dev and nlohmann-json3-dev, and use linux-gcc-baker.

  • The minimum target is the glibc of Ubuntu 22.04, on x86_64 and aarch64 (design document, section 4).

macOS

  • Install the Xcode command line tools and Ninja (brew install ninja), then use macos-clang-static or macos-clang-shared.

  • The OpenGL backend runs on Apple's OpenGL 4.1 core profile. Apple ships no clip control, so the logarithmic depth convention applies. The Direct3D 11 backend is not built. The Ogre backend is not supported on macOS in version 1 (Ogre's Metal render system follows, as milestone M3b).

  • The supported minimum is macOS 11, as universal binaries (arm64 and x86_64). The macOS presets set CMAKE_OSX_ARCHITECTURES to arm64;x86_64 and CMAKE_OSX_DEPLOYMENT_TARGET to 11.0, and compile Zstandard in (VGL_ZSTD_PROVIDER=BUNDLED), since a universal build needs every library it links as a universal binary and Homebrew's have one architecture only. To build for the host's architecture alone, override the variable:

    cmake --preset macos-clang-static -DCMAKE_OSX_ARCHITECTURES=arm64
    cmake --build --preset macos-clang-static-release

    The HTTP reader links libcurl, so a universal build with VGL_DEFAULTS_HTTP needs a universal libcurl (or the downloaded one); this is not checked in CI.

Embedding the source tree

vgl can be built as part of your own CMake project with add_subdirectory or FetchContent. Tests, samples and install rules are then off by default, and the targets vgl::vgl, vgl::defaults, vgl::gl, vgl::d3d11 and vgl::ogre are available under the same names as in the installed package. See Installing vgl for an example.

See also

Clone this wiki locally