Build & Publish
This page is for developers who want to use OpenNest from source or contribute to it. It covers the toolchains, how to build the two native C++ engines and the three managed plug-ins (Grasshopper 1, the Rhino command, and Grasshopper 2), how to load the result into Rhino, and how publishing + docs deploy.
1. Prerequisites
| Tool | Version | Used for |
|---|---|---|
| CMake | 3.20+ | Configuring/building the native engines |
| MSVC | Visual Studio 2022 (Windows) | Compiling the C++ DLLs on Windows |
| Clang | default toolchain (macOS) | Compiling the C++ dylibs on macOS |
| .NET SDK | 8.0.x | Building all three managed plug-ins |
Note
Use the .NET 8.0.x SDK even though most targets are net7.0 / net48 — that's what CI uses, and the Rhino-9 command + Grasshopper 2 targets are net8.0. Building the net48 target on Windows works because the projects set EnableWindowsTargeting=true.
Both engines are fully self-contained — no external dependencies. Clipper2 and a minimal Boost.Polygon subset are vendored in src/opennest_cpp.
2. Repository layout
| Folder | Builds / contains |
|---|---|
src/opennest_cpp |
nfp_nest.dll — NFP/SVGnest GA engine. Vendored Clipper2 (static) + a minimal Boost.Polygon subset. C++17. The C ABI is in src/capi/nfp_nest_capi.{h,cpp}. |
src/nest_physics_cpp |
nest_physics.dll — physics/overlap-relaxation (collision) solver. Header-only, threads only, no external deps. C++20. C ABI in nest_physics_capi.{h,cpp}. |
src/opennest_2 |
opennest_2.gha — the C# Grasshopper 1 plug-in (components) + the shared nesting/nest_geo/nest_sheets logic the other managed projects reuse. |
src/opennest_commands |
opennest_commands.rhp — the Rhino command plug-in (OpenNest command). Reuses opennest_2 via a project reference. |
src/opennest_gh2 |
opennest_gh2.rhp — the Grasshopper 2 plug-in (Rhino 9 WIP only). Built against the Rhino-9 GH2 SDK. |
tools/ |
gen_example_docs.py (generates the C++/C# example pages) + pack_examples.py (zips the per-language download projects). |
examples/downloads/{cpp,csharp,python} |
Self-contained, runnable example projects (one per API example) that are zipped into docs/api/*/downloads/. |
docs/ |
MkDocs Material source. overrides/ holds the header template override (inline section tabs). |
grasshopper_plugin/ |
Committed Yak manifests + .yak binaries per platform (opennest_win/, opennest_mac/). |
.github/ |
CI workflows (publish.yml, docs.yml), PR/issue templates. |
The C++ engine is the single source of truth
The Python package compas_nest does not keep its own copy of the engine — it vendors this repo as a git submodule and compiles src/opennest_cpp + src/nest_physics_cpp directly. Updating compas_nest to a new engine is just bumping that submodule, so the C++ here is the one source both packages build from.
3. Build the native engines
Each engine is its own standalone CMake project, so configure and build them one folder at a time. Both produce a self-contained shared library (no lib prefix, to match the P/Invoke names).
Self-contained DLLs
Every engine links the static MSVC runtime (/MT) on Windows (and -static-libgcc -static-libstdc++ under GCC), so the resulting DLL/dylib has no external runtime dependency and loads in Rhino without the VC++ redistributable.
Windows (MSVC, x64)
# nfp_nest.dll -> src/opennest_cpp/build/Release/nfp_nest.dll
cmake -S src/opennest_cpp -B src/opennest_cpp/build -A x64
cmake --build src/opennest_cpp/build --config Release
# nest_physics.dll -> src/nest_physics_cpp/build/Release/nest_physics.dll
cmake -S src/nest_physics_cpp -B src/nest_physics_cpp/build -A x64
cmake --build src/nest_physics_cpp/build --config Release
macOS (Clang)
Drop -A x64. To match CI's universal build, pass the OSX arch flag (both engines need it explicitly):
cmake -S src/opennest_cpp -B src/opennest_cpp/build -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
cmake --build src/opennest_cpp/build --config Release
cmake -S src/nest_physics_cpp -B src/nest_physics_cpp/build -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
cmake --build src/nest_physics_cpp/build --config Release
Optional flags
nfp_nest vendors a minimal Boost.Polygon at src/opennest_cpp/third_party/boost_min; override it with -DBOOST_MIN_INCLUDE_DIR=<dir> to point at a full Boost install. nest_physics can additionally build a standalone CLI with -DNEST_PHYSICS_BUILD_CLI=ON.
4. Build the managed plug-ins
All three are built with the .NET 8.0.x SDK:
dotnet build src/opennest_2/opennest_2.csproj -c Release # GH1 components (.gha)
dotnet build src/opennest_commands/opennest_commands.csproj -c Release # Rhino command (.rhp)
dotnet build src/opennest_gh2/opennest_gh2.csproj -c Release # Grasshopper 2 (.rhp, Rhino 9)
| Project | Output | Target frameworks | Loaded by |
|---|---|---|---|
opennest_2 |
opennest_2.gha |
net7.0-windows, net7.0, net48 |
Grasshopper 1 (Rhino 7/8, and classic GH in Rhino 9) |
opennest_commands |
opennest_commands.rhp |
net8.0-windows, net8.0, net7.0-windows, net7.0, net48 |
Rhino's command line (the net8/RhinoCommon-9 flavor is what loads on Rhino 9) |
opennest_gh2 |
opennest_gh2.rhp |
net8.0-windows, net8.0 |
Grasshopper 2 (Rhino 9 WIP only), against the R9 GH2 SDK |
A PostBuild target copies each native engine library next to the .gha (guarded by Exists(...), so a missing source is silently skipped):
| Native lib | Windows source | macOS source |
|---|---|---|
nest_physics |
nest_physics.dll (staged next to the csproj) |
../nest_physics_cpp/build/nest_physics.dylib |
nfp_nest |
../opennest_cpp/build/Release/nfp_nest.dll |
../opennest_cpp/build/nfp_nest.dylib |
nest_physics.dll is copied from a different place
On Windows, nest_physics.dll is copied from the project root next to the csproj — not from a build/Release/ folder like nfp_nest. After building nest_physics, stage its DLL there yourself; otherwise the Exists(...) guard skips it and the physics P/Invoke fails at runtime.
5. Run it locally
Users — Rhino Package Manager
Run _PackageManager, search OpenNest, install. The Package Manager picks the distribution matching your Rhino (it installs on Rhino 8 and 9), delivering the Grasshopper 1 components and the OpenNest Rhino command. No build required.
Grasshopper 2 (Rhino 9 WIP) — manual load
GH2 is not auto-registered (a Yak-registered GH2 .rhp crashes Rhino's plug-in manager). The package drops the GH2 files in a grasshopper2/ subfolder; you load opennest_gh2.rhp by hand inside Grasshopper 2. See the Grasshopper 2 page for the walkthrough.
Developers — load your local build
Close Rhino, then copy the built .gha + the native DLLs into the Grasshopper Libraries folder (%AppData%\Grasshopper\Libraries), and the .rhps where Rhino/GH2 expect them.
Quit Rhino fully before refreshing
Rhino file-locks the loaded .gha/.rhp and native DLLs while running, so a rebuild cannot overwrite the installed copy. Close Rhino completely before copying a new build in, then restart.
6. How publishing works
Publishing is automated by the Build & Publish (Windows + macOS → Yak) workflow (.github/workflows/publish.yml).
- Trigger: every push to
mainauto-publishes a new version. A manual Actions → Run workflow is also available, with abumpinput (minor/patch/major). - Version auto-bump: the canonical version is
grasshopper_plugin/opennest_win/manifest.yml; the base is the max of that and the live Yak version, bumped to a 4-partX.Y.Z.0string in both manifests. - Build matrix: the
macjob builds the engines as universal (x86_64;arm64) dylibs; thewindowsjob (needs: mac) builds the Windows x64 DLLs + all three plug-ins, then assembles four Yak distributions of one package on the Windows runner. - Four distributions, one package: the same
OpenNestversion ships asrh8_0-win,rh8_0-mac(net7 / RhinoCommon-8 command) andrh9_0-win,rh9_0-mac(net8 / RhinoCommon-9 command). The Package Manager installs the one matching the running Rhino — so GH1 + the command auto-install on Rhino 8 and 9, Windows and macOS. - Grasshopper 2 rides along, never auto-loaded:
opennest_gh2.rhpis staged into each package'sgrasshopper2/subfolder (a plain download), so Rhino's plug-in manager never registers it — the user loads it manually in GH2 (Rhino 9 only). - Release + tag: the run commits the bumped manifests + refreshed
.yakbinaries, tagsv<version>, and creates a GitHub Release with the.yakfiles attached. The Yak push is skipped whenYAK_TOKENis absent; everything else still runs. [skip ci]guard: the bot's release commit ends with[skip ci], so its own commit tomaindoesn't re-trigger the run.
git pull after every push to main
CI pushes a release commit (version bump + refreshed packages) back to main, so your local main falls behind after each push. Run git pull --rebase before your next push.
7. Maintainer setup
- Workflow permissions — Settings → Actions → General → Read and write permissions (both workflows need
contents: write). YAK_TOKENsecret — Settings → Secrets and variables → Actions. Generate withyak login --ci. Without it the run still builds, bumps, tags, and releases — only the Yak push is skipped. Yak tokens expire; re-runyak login --ciif pushes start being skipped.- Pages source — Settings → Pages → Source = Deploy from a branch, branch =
gh-pages.
8. How the docs deploy
The Docs workflow (.github/workflows/docs.yml) builds and deploys this site.
- Trigger: push to
maintouchingdocs/**,mkdocs.yml, or the workflow (alsoworkflow_dispatch). - What it does: on
ubuntu-latest, installsmkdocs-materialand runsmkdocs gh-deploy --force --no-history, force-pushing a single-commitgh-pagesbranch that GitHub Pages serves. - Example pages are generated: the C++/C# example pages + the per-language download zips are produced by
tools/gen_example_docs.pyandtools/pack_examples.py— run them after changing an example underexamples/downloads/.
The published site is at https://petrasvestartas.github.io/OpenNest/.
9. Contributing
- Work on a feature/fix branch (or a fork).
- Open a pull request using
.github/PULL_REQUEST_TEMPLATE.md: builds locally (native engines from source + the.gha), tested in Rhino with real geometry, docs updated if behavior/inputs/options changed, and no prebuilt binaries committed (CI builds from source). - File issues with the templates in
.github/ISSUE_TEMPLATE/(attach a.gh/.ghxor.3dmfor bugs).
Note
Don't commit built binaries — CI builds everything from source and publishes on merge to main.
OpenNest is released under the MIT License (2019–2026 Petras Vestartas).