Building & CMake
Easy3D / Guide / Building & CMake
Easy3D is a normal compiled STATIC CMake library (easy3d, alias easy3d::easy3d), built with C++23 and CMake ≥ 3.20. The one interesting part of the build is how it resolves CNA linkage — this page covers all three modes, every option, and which APIs need CNA linked at runtime.
Why linkage matters at all
CNA's math types (Vector3, Matrix, …) are declared in CNA's headers but defined in CNA's compiled .cpp files. This has two consequences:
- The
easy3dstatic library compiles against CNA's headers alone. - Any executable that actually runs CNA math — constructing a
Vector3, callingCamera3D::GetViewMatrix()— must link theCNAlibrary at final link time.
Building full CNA pulls in heavy dependencies (SHARP_RUNTIME, SDL3, ffmpeg, a graphics backend), so Easy3D keeps its default build free of them and resolves CNA linkage in one of three ways.
The three CNA linkage modes
1. Parent project provides the CNA target (the game path)
If a parent project already defines the CNA target before adding Easy3D — the normal setup for a game that does add_subdirectory(../cna) first — Easy3D detects the existing target and links it automatically. No option needed:
add_subdirectory(../cna cna) # defines the CNA target (+ chosen backend)
add_subdirectory(../easy-3d easy-3d) # detects CNA, links it automatically
add_executable(galaxy_eggbert src/main.cpp)
target_link_libraries(galaxy_eggbert PRIVATE CNA easy3d)
Because the game already selects CNA's backend and options, Easy3D does not need EASY3D_LINK_CNA here — it simply links the CNA target the game created. This is the path games use.
2. Standalone with -DEASY3D_LINK_CNA=ON
When building Easy3D by itself but wanting cameras to actually run (example + full test suite), Easy3D builds CNA itself from EASY3D_CNA_DIR (default ../cna), selecting a graphics backend via EASY3D_CNA_BACKEND (default EASY_GL) and disabling CNA's own demos/tests:
cmake -S . -B build -DEASY3D_LINK_CNA=ON # backend defaults to EASY_GL
cmake --build build
ctest --test-dir build # runs all tests incl. camera, batches, cube_mesh
If there is no CNA CMake project at EASY3D_CNA_DIR, configuration fails with a clear error; fix it with -DEASY3D_CNA_DIR=/path/to/cna.
3. Default: headers only
Otherwise Easy3D compiles against CNA's headers and leaves linking to the consuming application. The default build stays light and self-contained: it produces the easy3d library plus the CNA-free tests, and requires nothing beyond a compiler, CMake, and CNA's headers.
cmake -S . -B build
cmake --build build
ctest --test-dir build # basics + texture_atlas
EASY3D_HAS_CNA_LINK as a PUBLIC compile definition, and the camera example and the camera/batch/cube-mesh tests are built as runnable executables. Your own code can #ifdef EASY3D_HAS_CNA_LINK if it needs to know.CMake options
| Option | Default | Meaning |
|---|---|---|
EASY3D_BUILD_EXAMPLES | ON | Build the examples/ targets (the camera example needs CNA linked). |
EASY3D_BUILD_TESTS | ON | Build the tests/ targets and register them with CTest. |
EASY3D_LINK_CNA | OFF | Standalone only: build CNA from EASY3D_CNA_DIR and link it. Ignored (unnecessary) when a parent project already provides the CNA target. |
EASY3D_CNA_DIR | ../cna | Path to the CNA repository (provides headers under <dir>/include). |
EASY3D_CNA_BACKEND | EASY_GL | CNA graphics backend to enable when Easy3D builds CNA itself: SDL_RENDERER / EASY_GL / BGFX / VULKAN. |
Backend selection notes
CNA requires exactly one graphics backend to be selected; EASY3D_CNA_BACKEND picks which one Easy3D enables when it builds CNA itself (mode 2). On Linux, EASY_GL is the lightest, most-tested choice. The value is ignored in mode 1, where the parent project already chose a backend.
| Value | Backend |
|---|---|
SDL_RENDERER | SDL3's built-in 2D renderer backend. |
EASY_GL | OpenGL backend via easy-gl (default; lightest on Linux). |
BGFX | bgfx backend. |
VULKAN | Vulkan backend. |
Which APIs need CNA linked?
Only code that executes CNA math needs the link. Storing CNA types by value inside Easy3D containers is fine without it — but note that your code constructing a Vector3(x, y, z) to pass in already calls a CNA compiled constructor.
| API | Needs CNA link at runtime? |
|---|---|
VersionString() / VersionNumber() | No — completely CNA-free. |
TextureAtlas (all of it) | No — deliberately CNA-free; deals only in plain pixel rects and UVs. |
Camera3D::GetViewMatrix() / GetProjectionMatrix() | Yes — calls Matrix::CreateLookAt / Matrix::CreatePerspectiveFieldOfView. |
OrbitCamera::ComputePosition() / ApplyTo() | Yes — constructs CNA Vector3 values. |
FollowCamera::Update() / ApplyTo() | Yes — uses CNA Vector3 math (Vector3::Lerp). |
BillboardBatch / CubeBatch / DebugDraw | The classes only store data, but constructing the Vector3/Vector2 values you pass in runs CNA constructors — so in practice, yes. |
AppendCubeMesh() / BuildCubeMesh() | Yes — performs Vector3 arithmetic. |
Microsoft::Xna::Framework::Vector3::Vector3(float, float, float), you are running CNA math without linking CNA. Either link the CNA target in your application, or (standalone) configure with -DEASY3D_LINK_CNA=ON.What the build produces
| Target | Kind | When |
|---|---|---|
easy3d (alias easy3d::easy3d) | Static library | Always. |
easy3d_test_basics, easy3d_test_texture_atlas | Test executables | With EASY3D_BUILD_TESTS=ON (always runnable — CNA-free). |
easy3d_test_camera, easy3d_test_batches, easy3d_test_cube_mesh | Test executables | Only when CNA is linked; otherwise compile-checked as OBJECT libraries (see Testing). |
| Minimal example | Example executable | With EASY3D_BUILD_EXAMPLES=ON and CNA linked (see Minimal Example). |
Include paths
The easy3d target exports its include/ directory as a PUBLIC include path, so consumers just write:
#include <Easy3D/Easy3D.hpp> // umbrella header — everything public
#include <Easy3D/Camera3D.hpp> // or pick individual headers
When CNA is linked, CNA propagates its own PUBLIC include directories (the Microsoft/Xna headers) transitively through easy3d. In the headers-only mode, Easy3D adds EASY3D_CNA_DIR/include to its public include path so CNA headers resolve for consumers too.