building
Building the library
A default build needs a C++17 compiler and CMake 3.20. It takes about twelve seconds on four cores and produces one static library and nothing else. Everything optional is off by default, including the command line tool and the tests.
The short version
# from the unpacked release directory
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
# optional, installs headers + libridgeforge.a + CMake package files
cmake --install build --prefix /usr/local
There is no bootstrap script, no code generation step and nothing fetched while configuring. If your network is down the build still works.
Toolchains
Minimum means it compiles and the test suite passes. Tested means a maintainer runs it before tagging a release.
| Compiler | Minimum | Tested at release | Notes |
|---|---|---|---|
| GCC | 12 | 12, 13, 14 | reference toolchain for benchmarks |
| Clang | 15 | 15, 17, 18 | used for the sanitizer builds |
| MSVC | 19.36 | 19.38 | needs /std:c++17 explicitly |
| Platform | Architecture | State | Notes |
|---|---|---|---|
| Linux | x86-64, arm64 | supported | both run before every tag |
| Windows | x64 | supported | static runtime untested |
| macOS | arm64 | supported | OpenMP needs a separate runtime |
| Other Unix systems | - | unverified | nothing platform specific in the code |
| 32-bit targets | - | unsupported | index arithmetic assumes 64-bit size_t |
CMake options
All options are booleans unless the table says otherwise, and all are prefixed RF_ so they never collide with your own cache variables.
| Option | Default | What it does |
|---|---|---|
RF_BUILD_TOOLS | OFF | builds the rfmesh command line tool; adds about 90 KB to the build output |
RF_BUILD_TESTS | OFF | builds the 411 test cases and registers them with CTest |
RF_BUILD_SHARED | OFF | produces a shared library; symbol visibility is set to hidden except for the public API |
RF_USE_OPENMP | ON | parallelises the quadric pass and the intersection search when a runtime is found; silently off if not |
RF_DOUBLE_PRECISION | OFF | makes rf::Scalar a double; roughly 1.9× memory for positions and 15 % slower collapses |
RF_USE_EXCEPTIONS | OFF | when on, allocation failure propagates instead of returning a status |
RF_ENABLE_ASSERTS | Debug only | internal invariant checks; costs about 30 % on decimation, so keep it off in Release |
RF_INSTALL | ON | generates install rules and the package config; turn off when vendoring |
RF_SANITIZE | empty string | accepts address, undefined or both separated by a semicolon |
RF_DOUBLE_PRECISION changes the layout of every public struct. A program compiled against the single-precision headers and linked against a double-precision library will build, link and then read garbage out of positions. The package config records the setting, so find_package catches it; a hand-written link line does not.
Build types
| Build type | Decimation, 2 M tri, 8 threads | Use it for |
|---|---|---|
Release (-O2) | 4.6 s | everything; this is what the benchmarks use |
RelWithDebInfo | 4.8 s | profiling, crash reports with usable frames |
Debug with asserts | 61 s | reproducing a suspected library bug |
-O3 instead of -O2 | 4.5 s | nothing in particular; the gain is inside the noise |
Do not build with fast-math. The collapse ordering depends on comparing quadric errors that routinely differ in the last two bits, and relaxed floating point makes the output depend on the inliner. The library will still produce a valid mesh, but two builds will disagree about which edges survived, which makes a regression impossible to bisect.
Amalgamation
If CMake is not available, or the project must ship as source, build the single-header form once and carry it along:
cmake -S . -B build -DRF_INSTALL=OFF
cmake --build build --target rf_amalgamate
# writes build/amalgamated/ridgeforge_all.hpp (about 620 KB)
Include it in exactly one translation unit with the implementation macro defined, and include it plainly everywhere else:
// one file in the program, usually ridgeforge_impl.cpp
#define RF_ALL_IMPLEMENTATION
#include "ridgeforge_all.hpp"
The amalgamation is generated from the same sources and runs the same tests, but it cannot express the optional OpenMP path, so it is always single-threaded. For a 2 M triangle decimation that is the difference between 4.6 and 5.9 seconds.
Tests and sanitizers
cmake -S . -B build-test -DRF_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Debug
cmake --build build-test -j && ctest --test-dir build-test --output-on-failure
# 411 tests, about 70 s on four cores; 23 of them are marked slow
ctest --test-dir build-test -LE slow # skip the slow ones
The sanitizer configuration is the one that catches real problems, and it is worth running if you report a crash:
cmake -S . -B build-asan -DRF_BUILD_TESTS=ON \
-DRF_SANITIZE="address;undefined" -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build-asan -j && ctest --test-dir build-asan
Test meshes live in tests/data and are small on purpose: the largest is 180 KB. Four of them are hand-built pathological cases - a zero-area triangle fan, two shells sharing one vertex, a strip with inconsistent winding, and a cube with one face reversed.
When the build fails
| Message | Cause | Fix |
|---|---|---|
undefined reference to rf::io::read | headers found, library not linked | link RidgeForge::ridgeforge, not just the include directory |
'optional' is not a member of 'std' | compiling as C++14 or earlier | set CXX_STANDARD 17 on your target, or /std:c++17 |
omp.h: No such file or directory | detection passed, runtime headers absent | configure with -DRF_USE_OPENMP=OFF |
C2065: '40' near a digit separator | MSVC defaulting to C++14 | add /std:c++17 to the compile options |
static assertion failed: Scalar mismatch | double and single precision headers mixed | rebuild everything with one setting; see the warning above |
CMake cannot find RidgeForgeConfig.cmake | installed with RF_INSTALL=OFF | reinstall with the default, or use add_subdirectory |
If none of these match, the FAQ covers a few more cases, and dev@ridgeforge.dev reaches a maintainer. Include the CMake cache and the exact compiler version; without them the first reply will just ask for them.