feat: add godotengine.godot-cpp 0.0.1 (import godot_cpp) - #144
Merged
Conversation
Sunrisepeak
marked this pull request as ready for review
August 3, 2026 20:35
Sunrisepeak
force-pushed
the
feat/godotengine-godot-cpp-module
branch
from
August 3, 2026 20:36
05bff3a to
ef3780e
Compare
Form A registration of mcpplibs/godot-cpp-m: the C++23 module layer over
godot-cpp's unchanged API. `import godot_cpp;` re-exports the whole public
`godot` namespace, so a file that opened with a stack of
The index stays light: the 1022-TU source build lives in compat.godot-cpp
and the module layer lives in its own repo, so this side carries only the
descriptor -- the same split ffmpeg/opencv use.
Module name is one segment, `godot_cpp`, matching the library and the
reserved for packages exposing several submodules (opencv.cv, ffmpeg.av).
Two things the module deliberately does not carry, both upstream's shape
rather than a wrapper choice:
* MACROS -- GDCLASS, GDREGISTER_CLASS, GDVIRTUAL_*, D_METHOD, memnew and
the ERR_* family. A named module cannot export them, and GDExtension
code is written in them, so the package ships <godot-cpp-m/macros.h> to
include next to the import. godot-cpp's headers are in the module's
global module fragment, so both spellings denote the same entities.
* HashMap/HashSet and their default hashers, which reach
hash_murmur3_one_float/double -- `static` functions declaring an unnamed
union. Exposing a TU-local TYPE from a module interface is a hard error,
not the -Wexpose-global-module-tu-local warning.
The member consumes the package the way a user would and asserts the same
numbers tests/examples/godot-cpp asserts through headers, so a divergence
means the re-export changed behaviour.
Note on ordering: this member declares [indices] godotengine, and a
member-level table REPLACES the root's, so the transitive compat.godot-cpp
resolves from the PUBLISHED index -- the constraint ffmpeg-module documents.
It therefore only goes green after the compat.godot-cpp PR merges and
publish-artifact reruns. Simulating a published index locally does not work:
mcpp refreshes on a resolution miss and wipes the injected state.
The workspace jobs never refreshed the published index. The snapshot in play
is whatever the pinned mcpp release vendored -- the Download step `cp -a`s the
release's registry/ over ~/.mcpp/registry, on top of the restored cache -- so
it is by construction older than main, and it never moves, because the cache
is saved with that same stale copy inside it.
This stayed invisible because mcpp DOES refresh on a miss for a direct
dependency, and because every member so far resolved its packages either from
this checkout or from compat packages that have been in the index far longer
than any snapshot. tests/examples/godot-cpp-module is the first member to
depend on a package added in the same cycle THROUGH a Form-A package -- a
transitive dependency, which is the path with no refresh -- and it failed with
error: dependency 'compat.godot-cpp': no package found ...
index: local index 160c389 (never refreshed)
on all three platforms, minutes after `Publish Index Artifact` had already
republished an index that contained it. Reproduced locally against a snapshot
of the same age, and `mcpp index update` alone turns that run green:
test result ok. 1 passed; 0 failed; finished in 72.94s
Two changes that only make sense together. The version becomes 4.5.0 rather than 0.0.1: a module layer that only re-exports an API has no version of its own worth inventing, and what a consumer needs from the number is which Godot they are targeting -- the same version compat.godot-cpp carries. That is exactly what makes the short name matter. This package and its own compat.godot-cpp dependency are always resolved together, and mcpp's installed-package lookup matches on (name, version) WITHOUT the namespace. With both named `godot-cpp` at 4.5.0, resolving this one lands on compat's unpacked directory: error: dependency 'godotengine.godot-cpp': index entry has no `mcpp = ...` field, and no mcpp.toml was found at <verdir>/mcpp.toml or <verdir>/*/mcpp.toml and it is cache-order dependent, so a clean runner passes and a warm one fails. Reproduced with a namespace unrelated to either package: leave a single <anything>-x-godot-cpp/4.5.0 in the store and the resolution goes to it; remove it and the same descriptor installs and builds fine. The store DIRECTORIES are namespaced (ns-x-name) -- the lookup is not. `godot-cpp-m` sidesteps it, keeps the version tracking upstream, and matches the repository name. `import godot_cpp;` is unchanged. Verified both ways with the CI-pinned mcpp 2026.8.3.3: cold store (both packages downloaded, 27.80s) and warm store with compat-x-godot-cpp and godotengine-x-godot-cpp-m side by side (3.52s) -- the state that previously failed. Both `test result ok`.
Second version of the module layer, tracking upstream one for one as
compat.godot-cpp's do: 10.0.0-rc1 binds Godot 4.6, 4.5.0 binds Godot 4.5.
Getting there needed a shim on the package side. godot-cpp declares
hash_murmur3_one_float/_double `static`, and each declares an unnamed union
in its body -- a class with no linkage inside a TU-local function. With 10.x
the module interface exposes those functions (reachable from many inline
bodies) and GCC rejects it outright:
error: 'uint32_t godot::hash_murmur3_one_float(float, uint32_t)' exposes
TU-local entity 'union ...::<unnamed>'
-Wno-expose-global-module-tu-local, -fpermissive and -Wno-error= all leave it
standing, and exporting less does not converge -- a single engine class is
enough to trigger it. The package now generates a shim: upstream's header with
`static` dropped from those two, scoped to its own include path, so
compat.godot-cpp still compiles upstream's copy untouched. With it the export
surface actually GREW (1818 names) because nothing has to be held back any
more -- HashMap, HashSet, AHashMap and PairHash re-export normally.
The new member asserts the version through TYPES rather than
GODOT_VERSION_MAJOR/_MINOR: those are macros, and a module cannot export
macros. EditorDock and AHashMap exist in 4.6 and not in 4.5, which also
doubles as proof the shim did its job.
Verified with the CI-pinned mcpp 2026.8.3.3:
godot-cpp-module -> ok (1 passed)
godot-cpp-module-v10 -> version=true ... ok (1 passed)
Sunrisepeak
force-pushed
the
feat/godotengine-godot-cpp-module
branch
from
August 4, 2026 04:57
7371423 to
f9bded9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Registers
mcpplibs/godot-cpp-m0.0.1 asgodotengine.godot-cpp— the C++23 module layer over godot-cpp's unchanged API:Form A: the index carries the descriptor, nothing else. The 1022-TU source build stays in
compat.godot-cpp(#143) and the module layer lives in its own repo — the same splitffmpeg/opencvuse, and what keeps this index from growing a second full godot-cpp build.Module name
One segment,
godot_cpp— matching the library and the#include <godot_cpp/...>root users already type. The dotted spelling is reserved here for packages that expose several submodules (opencv.cv,ffmpeg.av); this one has a single interface unit.The wrapper is generated, not curated
godot-cpp's public surface is ~1750 names — every engine class, every builtin Variant type, the global enums and their enumerators (so
godot::OKandgodot::ERR_FILE_NOT_FOUNDstill spell the same),godot::Math, the templates — and it moves with every Godot release. Sosrc/godot_cpp.cppmis produced by a brace/namespace-aware scan of the headers (tools/gen_module_cppm.pyin the package repo) and checked by the compiler.Two things it deliberately does not carry
Both are upstream's shape, not a wrapper choice:
Macros.
GDCLASS,GDREGISTER_CLASS,GDVIRTUAL_*,D_METHOD,memnew/memdelete, theERR_*family — a named module cannot export macros, and GDExtension code is written in them. The package ships<godot-cpp-m/macros.h>to include next to the import, the same answerffmpeg-mgives:godot-cpp's headers sit in the module's global module fragment, so both spellings denote the same entities and mixing them is well-formed. The package's own
tests/godot_cpp_macros.cppis exactly this shape.HashMap/HashSetand their default hashers (7 names). Their inline bodies reachhash_murmur3_one_float/double, which arestaticand declare an unnamed union in their bodies. An unnamed union type is TU-local, and exposing a TU-local type from a module interface is a hard error — not the-Wexpose-global-module-tu-localwarning. Found by bisecting the 1759 exports, not by guessing. They are godot-cpp's internal container plumbing (extension code usesDictionary/Array/TypedArray) and remain reachable through the headers.Mirrors
github.com/mcpplibs/godot-cpp-m/archive/refs/tags/v0.0.1.tar.gzgitcode.com/mcpp-res/godot-cpp/releases/download/v0.0.1/godot-cpp-m-0.0.1.tar.gzsha256
5145f1e539b4b42bdb4064a2df0dcb54ffac4d70f88edc42f38bf2304a37a344, hashed twice from GitHub and re-downloaded from GitCode — byte-identical. The archive carries no symlinks (checked, for the Windows leg).Test member
tests/examples/godot-cpp-module/consumes the package the way a user would and asserts the same numberstests/examples/godot-cppasserts through headers — that member is the header spelling of this one, so a divergence means the re-export changed behaviour. Both halves can fail: the Variant math is defined incompat.godot-cpp'ssrc/variant/*.cpp(so it only resolves if that dependency linked), andNode/Node2D/Node::PROCESS_MODE_*/godot::OKexist only in the pre-generatedgen/tree.Verification so far
In the package repo, against
compat.godot-cppresolved from the #143 checkout:That example is also what caught
compat.godot-cppmissing-fPIC— now fixed in #143.Lint here is clean (
mcpp xpkg parse, mirror table, package name, cross-package refs) and the CN url returns 200.Ordering
This member declares
[indices] godotengine, and a member-level table replaces the root's rather than merging — so the transitivecompat.godot-cppresolves from the published index. That is the constrainttests/examples/ffmpeg-moduledocuments, and it meansworkspace (*)here stays red until #143 merges andpublish-artifactrepublishes the index.Simulating a published index locally does not substitute for that: mcpp refreshes the index on a resolution miss and wipes the injected state, so the real gate is CI after the merge.
Design notes:
.agents/docs/2026-08-04-add-godot-cpp-plan.md§6.