From 1b5d9739a193b3a9877eff257b349716a189f0a3 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 24 Oct 2026 10:59:18 +0900 Subject: [PATCH 1/8] feat: add runnable math template and current mcpp library contract --- .../docs/2026-10-24-runnable-template-plan.md | 11 ++ .github/workflows/ci.yml | 28 ++-- .xlings.json | 2 +- README.md | 154 +++--------------- docs/usage.md | 153 +++++++++++++++++ examples/summator/mcpp.toml | 4 +- examples/summator/summator.gdextension | 2 +- mcpp.toml | 6 +- templates/math/mcpp.toml.in | 6 + templates/math/src/main.cpp.in | 11 ++ templates/math/template.toml | 4 + tools/test_template.py | 83 ++++++++++ 12 files changed, 314 insertions(+), 150 deletions(-) create mode 100644 .agents/docs/2026-10-24-runnable-template-plan.md create mode 100644 docs/usage.md create mode 100644 templates/math/mcpp.toml.in create mode 100644 templates/math/src/main.cpp.in create mode 100644 templates/math/template.toml create mode 100644 tools/test_template.py diff --git a/.agents/docs/2026-10-24-runnable-template-plan.md b/.agents/docs/2026-10-24-runnable-template-plan.md new file mode 100644 index 0000000..1c19db0 --- /dev/null +++ b/.agents/docs/2026-10-24-runnable-template-plan.md @@ -0,0 +1,11 @@ +# godot-cpp-m runnable template checkpoint + +Latest main b19f8247338b564057d363878ef39ed16dc07c58 was cloned from the organization repository. Keep the existing godotengine.godot-cpp-m package and import godot_cpp API. Candidate 10.0.0-rc1.1 appends one wrapper revision to SDK 10.0.0-rc1 (Godot 4.6); the SDK is unchanged. No merge, tag or release is authorized here. + +The default math template uses the full self.name dependency key and runs vector/cross-product/color checks without an engine. Existing engine objects and GDCLASS registration still need a Godot process loading the extension. The README has 42 lines and links details in docs/usage.md. The manifest explicitly names src/godot_cpp.cppm as its library entry, avoiding the current client's missing-interface packaging advisory. The summator extension now declares the matching Godot 4.6 minimum and native CI builds its shared-library shape on all three platforms; actual engine loading is not claimed. + +The client pin and .xlings.json use mcpp 2026.10.24.1. Local LLVM 23.1.3 and GCC 16.1.0 strict module/macro suites both pass two binaries. Actual default mcpp new + strict build + run passes with both compilers, printing vector length 5 and cross product (0,0,1), with a real out-of-line color result checked. The explicit library-entry recheck passes. The Linux LLVM summator shared library strictly builds; engine loading and native Windows/macOS verification remain pending. The extension has no C++ module entry of its own and the client's associated advisory is not a missing wrapper interface. + +All local heavy checks run serially under mwrap-tests.slice (16 logical CPUs, 32 GiB max on this 32-CPU/62-GiB host), taskset 0-15 and MCPP_JOBS=6. Resource-supervised checks stop their own process group below 6 GiB free disk or 20% available host memory. Completed task diagnostic directories were removed after checking active process references; source logs and immutable archives remain. + +Before release readiness: native source/template CI must pass, and the exact immutable archive must be registered and consumed by index tests. No mcpp engine sources are changed. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a650e7..5894767 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ env: # Keep in sync with mcpp-index's .github/workflows/validate.yml MCPP_VERSION: # this package is consumed from that index, so it should be exercised with # the client that index pins. - MCPP_VERSION: "2026.8.3.3" + MCPP_VERSION: "2026.10.24.1" jobs: build: @@ -30,18 +30,21 @@ jobs: matrix: include: - platform: linux + toolchain: gcc@16.1.0 os: ubuntu-latest suffix: linux-x86_64 ext: tar.gz mcpp: bin/mcpp xlings: registry/bin/xlings - platform: macos + toolchain: llvm@23.1.3 os: macos-15 suffix: macosx-arm64 ext: tar.gz mcpp: bin/mcpp xlings: registry/bin/xlings - platform: windows + toolchain: llvm@23.1.3 os: windows-latest suffix: windows-x86_64 ext: zip @@ -116,7 +119,7 @@ jobs: shell: bash env: MCPP_INDEX_MIRROR: GLOBAL - run: '"$MCPP" build' + run: '"$MCPP" build --strict' # tests/godot_cpp_module.cpp -- the import surface # tests/godot_cpp_macros.cpp -- GDCLASS next to the import @@ -124,20 +127,19 @@ jobs: shell: bash env: MCPP_INDEX_MIRROR: GLOBAL - run: '"$MCPP" test' + run: '"$MCPP" test --strict' - # A real GDExtension shared library -- the shape this package exists for, - # and what caught the missing -fPIC in compat.godot-cpp. - # - # Linux only, and not by choice: mcpp refuses `kind = "shared"` off ELF -- - # "PE consumers need an import library and Mach-O needs install-name - # handling; neither is modelled yet, so mcpp refuses rather than producing - # an artifact nothing has ever verified." The library layer itself is - # still built and tested on all three above. + # Verify the native shared-library shape on every supported platform. + # Loading this library still requires a matching Godot process. - name: Build the summator GDExtension example - if: runner.os == 'Linux' shell: bash working-directory: examples/summator env: MCPP_INDEX_MIRROR: GLOBAL - run: '"$MCPP" build' + run: '"$MCPP" build --strict' + + - name: Actual default scaffold, strict build and standalone math + shell: bash + env: + MCPP_INDEX_MIRROR: GLOBAL + run: python3 tools/test_template.py --mcpp "$MCPP" --toolchain "${{ matrix.toolchain }}" diff --git a/.xlings.json b/.xlings.json index 7b8dcf9..1a87e82 100644 --- a/.xlings.json +++ b/.xlings.json @@ -1,5 +1,5 @@ { "workspace": { - "xim:mcpp": "2026.8.3.3" + "xim:mcpp": "2026.10.24.1" } } diff --git a/README.md b/README.md index 6649556..87f7c8a 100644 --- a/README.md +++ b/README.md @@ -1,152 +1,42 @@ # godot-cpp-m -> godot-cpp as a C++23 module for mcpp — the same API, reached with `import godot_cpp;`. -> -> Targets **Godot 4.6** (`compat.godot-cpp` 10.0.0-rc1). For Godot 4.5, use `godot-cpp-m = "4.5.0"`. +The godot-cpp **10.0.0-rc1** API through C++23 modules. Keep upstream `godot::` types and names. -```cpp -import std; -import godot_cpp; +## Quick start -int main() { - godot::Vector2 v{3, 4}; - std::println("{}", v.length()); // 5 — the same godot-cpp you already know, no #include -} +Use mcpp **2026.10.24.1**. Version **10.0.0-rc1.1** is a wrapper candidate until its index entry is published. + +```sh +mcpp new godot-math --template godotengine.godot-cpp-m@10.0.0-rc1.1 +cd godot-math +mcpp run ``` -- **Nothing forked, nothing reimplemented.** Upstream's sources and its - pre-generated GDExtension bindings arrive through the - [`compat.godot-cpp`](https://github.com/mcpplibs/mcpp-index) index package, - which compiles all 1022 translation units directly — no SCons, no CMake, and - no Python anywhere in the build. This repository is only the module layer. -- **The whole `godot` namespace is re-exported**, generated from the headers - rather than curated by hand: ~1750 names, every engine class, every builtin - Variant type, the global enums *and their enumerators* (so `godot::OK` and - `godot::ERR_FILE_NOT_FOUND` still spell the same), `godot::Math`, the - templates. -- **Macros keep working too**, through an optional side header — see below. +The default template runs vector and color math without a Godot process. -## Install +## Existing projects ```toml [dependencies] -godot-cpp-m = "10.0.0-rc1" # Godot 4.6; use "4.5.0" for Godot 4.5 +"godotengine.godot-cpp-m" = "10.0.0-rc1.1" ``` -The version tracks upstream godot-cpp, which is also the version -`compat.godot-cpp` carries: - -| package version | upstream tag | engine | -|---|---|---| -| `10.0.0-rc1` | `10.0.0-rc1` | Godot 4.6 | -| `4.5.0` | `godot-4.5-stable` | Godot 4.5 | - -## Macros - -C++ named modules cannot export macros, and GDExtension code is written in -them: `GDCLASS`, `GDREGISTER_CLASS`, `GDVIRTUAL_*`, `D_METHOD`, -`memnew`/`memdelete`, the `ERR_*` family. A translation unit that registers -classes includes the side header next to the import: - ```cpp -#include import godot_cpp; - -using namespace godot; - -class Player : public Node2D { - GDCLASS(Player, Node2D) -protected: - static void _bind_methods() { - ClassDB::bind_method(D_METHOD("get_speed"), &Player::get_speed); - } -public: - void _process(double delta) override { /* ... */ } - double get_speed() const { return speed; } -private: - double speed = 1.0; -}; -``` - -The headers it pulls in denote the same global-module entities the module -re-exports (they sit in the module's global module fragment), so mixing the -include and the import this way is well-formed. `tests/godot_cpp_macros.cpp` -covers exactly this shape. Any other upstream header can be included the same -way — they are all on the include path. - -## The hashfuncs shim - -`include/godot_cpp/templates/hashfuncs.hpp` is generated, and it is what makes -the whole `godot` namespace exportable at all. - -godot-cpp declares `hash_murmur3_one_float` / `_double` `static`, and each -declares an unnamed union inside its body. A local class has no linkage, and -`static` makes the enclosing function TU-local, so once the module interface -exposes it — which it does, reachable from many inline bodies — GCC rejects the -module outright: - -``` -error: 'uint32_t godot::hash_murmur3_one_float(float, uint32_t)' exposes - TU-local entity 'union ...::' -note: ... is also TU-local but has been exposed elsewhere -``` - -That is a hard error, not the `-Wexpose-global-module-tu-local` warning: -`-Wno-...`, `-fpermissive` and `-Wno-error=` all leave it standing. Exporting -less does not help either — with 10.x a single engine class is enough to -trigger it. - -The shim is upstream's header with `static` dropped from those two functions -and nothing else changed. This package's `include/` precedes the dependency's -on the command line, so only this package's translation units see it; -`compat.godot-cpp` keeps compiling upstream's copy untouched. The bodies are -identical — the sole difference is linkage, internal to inline — and the -generator refuses to run if either declaration stops matching exactly once. - -With it in place nothing has to be held back: `HashMap`, `HashSet`, `AHashMap`, -`Pair`, the hashers and the rest of `templates/` all re-export normally. - -## Example - -`examples/summator/` is a complete GDExtension — registered class, bound -methods, entry point — built as the shared library Godot loads, written with -`import godot_cpp;`: - -```sh -cd examples/summator && mcpp build -# then drop the library + summator.gdextension into a Godot 4.5 project -``` - -## Regenerating the module - -`src/godot_cpp.cppm` is generated, not hand-written. After a `compat.godot-cpp` -version bump: - -```sh -python3 tools/gen_module_cppm.py --shim-out include/godot_cpp/templates/hashfuncs.hpp \ - > src/godot_cpp.cppm -mcpp test +int main() { + return godot::Vector2(3, 4).length() == 5 ? 0 : 1; +} ``` -The checkout has to be one that has already run upstream's -`binding_generator.py` — which is exactly what the `compat.godot-cpp` archive -contains, so unpacking that is the simplest source. - -## Tests - -```sh -mcpp test -``` +## Scope -- `tests/godot_cpp_module.cpp` — the module surface: Variant math whose - definitions live in the library's `.cpp` files (so it can only pass if the - library really linked), plus generated engine classes and global enums. -- `tests/godot_cpp_macros.cpp` — the macro surface: a `GDCLASS` subclass with a - bound method and an overridden engine virtual, next to the import. +The pinned godot-cpp release targets Godot 4.6. Linux, macOS and Windows use the +same module API; the generated bindings are supplied by `compat.godot-cpp`. -Neither runs engine code: anything routed through the `gdextension_interface_*` -function pointers needs a Godot process that has loaded the extension. +Engine objects and registration need a Godot process loading a GDExtension. +For `GDCLASS`, `D_METHOD` and other macros, include `` before imports. +The [summator example](examples/summator) shows the extension structure; the default template exercises standalone math. -## License +## Documentation -MIT for the module layer. Upstream godot-cpp is MIT as well. +[Usage and adaptation details](docs/usage.md) · [Examples](examples) · [MIT](LICENSE) diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 0000000..41ecd24 --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,153 @@ +# godot-cpp-m + +> godot-cpp as a C++23 module for mcpp — the same API, reached with `import godot_cpp;`. +> +> Targets **Godot 4.6** (`compat.godot-cpp` 10.0.0-rc1). For Godot 4.5, use `godot-cpp-m = "4.5.0"`. + +```cpp +import std; +import godot_cpp; + +int main() { + godot::Vector2 v{3, 4}; + std::println("{}", v.length()); // 5 — the same godot-cpp you already know, no #include +} +``` + +- **Nothing forked, nothing reimplemented.** Upstream's sources and its + pre-generated GDExtension bindings arrive through the + [`compat.godot-cpp`](https://github.com/mcpplibs/mcpp-index) index package, + which compiles all 1022 translation units directly — no SCons, no CMake, and + no Python anywhere in the build. This repository is only the module layer. +- **The whole `godot` namespace is re-exported**, generated from the headers + rather than curated by hand: ~1750 names, every engine class, every builtin + Variant type, the global enums *and their enumerators* (so `godot::OK` and + `godot::ERR_FILE_NOT_FOUND` still spell the same), `godot::Math`, the + templates. +- **Macros keep working too**, through an optional side header — see below. + +## Install + +```toml +[dependencies] +"godotengine.godot-cpp-m" = "10.0.0-rc1.1" # Godot 4.6; use "4.5.0" for Godot 4.5 +``` + +The version tracks upstream godot-cpp. A numeric wrapper revision may follow +the upstream version: candidate `10.0.0-rc1.1` still uses SDK `10.0.0-rc1`. +The historical upstream mapping is: + +| package version | upstream tag | engine | +|---|---|---| +| `10.0.0-rc1` | `10.0.0-rc1` | Godot 4.6 | +| `4.5.0` | `godot-4.5-stable` | Godot 4.5 | + +## Macros + +C++ named modules cannot export macros, and GDExtension code is written in +them: `GDCLASS`, `GDREGISTER_CLASS`, `GDVIRTUAL_*`, `D_METHOD`, +`memnew`/`memdelete`, the `ERR_*` family. A translation unit that registers +classes includes the side header next to the import: + +```cpp +#include +import godot_cpp; + +using namespace godot; + +class Player : public Node2D { + GDCLASS(Player, Node2D) +protected: + static void _bind_methods() { + ClassDB::bind_method(D_METHOD("get_speed"), &Player::get_speed); + } +public: + void _process(double delta) override { /* ... */ } + double get_speed() const { return speed; } +private: + double speed = 1.0; +}; +``` + +The headers it pulls in denote the same global-module entities the module +re-exports (they sit in the module's global module fragment), so mixing the +include and the import this way is well-formed. `tests/godot_cpp_macros.cpp` +covers exactly this shape. Any other upstream header can be included the same +way — they are all on the include path. + +## The hashfuncs shim + +`include/godot_cpp/templates/hashfuncs.hpp` is generated, and it is what makes +the whole `godot` namespace exportable at all. + +godot-cpp declares `hash_murmur3_one_float` / `_double` `static`, and each +declares an unnamed union inside its body. A local class has no linkage, and +`static` makes the enclosing function TU-local, so once the module interface +exposes it — which it does, reachable from many inline bodies — GCC rejects the +module outright: + +``` +error: 'uint32_t godot::hash_murmur3_one_float(float, uint32_t)' exposes + TU-local entity 'union ...::' +note: ... is also TU-local but has been exposed elsewhere +``` + +That is a hard error, not the `-Wexpose-global-module-tu-local` warning: +`-Wno-...`, `-fpermissive` and `-Wno-error=` all leave it standing. Exporting +less does not help either — with 10.x a single engine class is enough to +trigger it. + +The shim is upstream's header with `static` dropped from those two functions +and nothing else changed. This package's `include/` precedes the dependency's +on the command line, so only this package's translation units see it; +`compat.godot-cpp` keeps compiling upstream's copy untouched. The bodies are +identical — the sole difference is linkage, internal to inline — and the +generator refuses to run if either declaration stops matching exactly once. + +With it in place nothing has to be held back: `HashMap`, `HashSet`, `AHashMap`, +`Pair`, the hashers and the rest of `templates/` all re-export normally. + +## Example + +`examples/summator/` is a complete GDExtension — registered class, bound +methods, entry point — built as the shared library Godot loads, written with +`import godot_cpp;`: + +```sh +cd examples/summator && mcpp build +# then drop the library + summator.gdextension into a matching Godot 4.6 project +``` + +## Regenerating the module + +`src/godot_cpp.cppm` is generated, not hand-written. After a `compat.godot-cpp` +version bump: + +```sh +python3 tools/gen_module_cppm.py --shim-out include/godot_cpp/templates/hashfuncs.hpp \ + > src/godot_cpp.cppm +mcpp test +``` + +The checkout has to be one that has already run upstream's +`binding_generator.py` — which is exactly what the `compat.godot-cpp` archive +contains, so unpacking that is the simplest source. + +## Tests + +```sh +mcpp test +``` + +- `tests/godot_cpp_module.cpp` — the module surface: Variant math whose + definitions live in the library's `.cpp` files (so it can only pass if the + library really linked), plus generated engine classes and global enums. +- `tests/godot_cpp_macros.cpp` — the macro surface: a `GDCLASS` subclass with a + bound method and an overridden engine virtual, next to the import. + +Neither runs engine code: anything routed through the `gdextension_interface_*` +function pointers needs a Godot process that has loaded the extension. + +## License + +MIT for the module layer. Upstream godot-cpp is MIT as well. diff --git a/examples/summator/mcpp.toml b/examples/summator/mcpp.toml index 9d05da7..649a0b3 100644 --- a/examples/summator/mcpp.toml +++ b/examples/summator/mcpp.toml @@ -4,11 +4,11 @@ # # mcpp build # # then point summator.gdextension at the produced library and drop both -# # into a Godot 4.5 project +# # into a matching Godot 4.6 project [package] name = "summator" version = "0.1.0" -description = "Minimal Godot 4.5 GDExtension written with import godot_cpp;" +description = "Minimal Godot 4.6 GDExtension written with import godot_cpp;" license = "MIT" [targets.summator] diff --git a/examples/summator/summator.gdextension b/examples/summator/summator.gdextension index f0eb6ee..39b4ac1 100644 --- a/examples/summator/summator.gdextension +++ b/examples/summator/summator.gdextension @@ -1,6 +1,6 @@ [configuration] entry_symbol = "summator_library_init" -compatibility_minimum = "4.5" +compatibility_minimum = "4.6" [libraries] linux.debug.x86_64 = "res://bin/libsummator.so" diff --git a/mcpp.toml b/mcpp.toml index 1f302ab..53ee3eb 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -16,8 +16,9 @@ # /*/mcpp.toml". Distinct short names sidestep it, and `-m` matches # the repository name. [package] +namespace = "godotengine" name = "godot-cpp-m" -version = "10.0.0-rc1" +version = "10.0.0-rc1.1" description = "godot-cpp as a C++23 module (import godot_cpp;) on top of the compat.godot-cpp source build" license = "MIT" repo = "https://github.com/mcpplibs/godot-cpp-m" @@ -26,6 +27,9 @@ platforms = ["linux", "macos", "windows"] [targets.godot-cpp-m] kind = "lib" +[lib] +path = "src/godot_cpp.cppm" + [build] sources = ["src/**/*.cppm"] include_dirs = ["include"] diff --git a/templates/math/mcpp.toml.in b/templates/math/mcpp.toml.in new file mode 100644 index 0000000..00381f1 --- /dev/null +++ b/templates/math/mcpp.toml.in @@ -0,0 +1,6 @@ +[package] +name = "{{project.name}}" +version = "0.1.0" + +[dependencies] +"{{self.name}}" = "{{self.version}}" diff --git a/templates/math/src/main.cpp.in b/templates/math/src/main.cpp.in new file mode 100644 index 0000000..b4956f0 --- /dev/null +++ b/templates/math/src/main.cpp.in @@ -0,0 +1,11 @@ +import std; +import godot_cpp; + +int main() { + const godot::Vector2 vector(3, 4); + const godot::Vector3 cross = godot::Vector3(1, 0, 0).cross(godot::Vector3(0, 1, 0)); + if (std::abs(vector.length() - 5.0) > 1e-5 || cross != godot::Vector3(0, 0, 1)) return 1; + if (godot::Color(1, 0, 0, 1).to_rgba32() != 0xff0000ffu) return 2; + std::println("godot-cpp: vector length {}, cross product ({}, {}, {})", vector.length(), cross.x, cross.y, cross.z); + return 0; +} diff --git a/templates/math/template.toml b/templates/math/template.toml new file mode 100644 index 0000000..32d1be9 --- /dev/null +++ b/templates/math/template.toml @@ -0,0 +1,4 @@ +[template] +description = "Run godot-cpp vector and color math through modules without a Godot process" +default = true +post_message = "Run `mcpp run` to execute standalone godot-cpp vector and color math. Engine classes need a loaded GDExtension." diff --git a/tools/test_template.py b/tools/test_template.py new file mode 100644 index 0000000..81ea805 --- /dev/null +++ b/tools/test_template.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +"""Render an installed candidate's default mcpp template, then build and run it.""" +import argparse +import json +import os +from pathlib import Path +import shutil +import subprocess +import tempfile +import tomllib + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--mcpp", default="mcpp") + parser.add_argument("--namespace", help="index namespace for legacy manifests without package.namespace") + parser.add_argument("--toolchain", default="llvm@23.1.3") + parser.add_argument("--template", help="named template; omit for the package default") + parser.add_argument("--run-arg", action="append", default=[]) + parser.add_argument("--index", type=Path, help="candidate SDK/wrapper index for unpublished feature dependencies") + args = parser.parse_args() + root = Path(__file__).resolve().parents[1] + metadata = tomllib.loads((root / "mcpp.toml").read_text())["package"] + namespace = metadata.get("namespace", args.namespace) + assert namespace, "Supply the published index namespace for this legacy manifest" + name, version = metadata["name"], metadata["version"] + identity = namespace + "." + name + with tempfile.TemporaryDirectory(prefix=name + "-template-") as directory: + temporary = Path(directory) + home = temporary / "home" + package = home / "registry/data/xpkgs" / (namespace + "-x-" + name) / version / (name + "-" + version) + shutil.copytree(root, package, ignore=shutil.ignore_patterns( + ".git", "target", ".mcpp", ".xlings", ".candidate-index", "__pycache__", "mcpp.lock", "compile_commands.json", "mcpp-2026.*")) + index = home / "indices/mcpplibs/pkgs/mwrap" + index.mkdir(parents=True) + entry = '{url="https://example.invalid/candidate.tar.gz",sha256="fixture"}' + descriptor = ('package={spec="1",namespace=' + json.dumps(namespace) + ',name=' + json.dumps(name) + + ',description="Installed template fixture",type="package",mcpp="mcpp.toml",xpm={') + descriptor += ",".join(platform + "={[" + json.dumps(version) + "]=" + entry + "}" + for platform in ("linux", "macosx", "windows")) + "}}\n" + (index / (identity + ".lua")).write_text(descriptor) + env = dict(os.environ, MCPP_HOME=str(home)) + selector = identity + "@" + version + for command in ([args.mcpp, "new", "--list-templates", selector], + [args.mcpp, "new", "quickstart", "--template", selector + (":" + args.template if args.template else "")]): + print("+", " ".join(command), flush=True) + subprocess.run(command, cwd=temporary, env=env, check=True) + project = temporary / "quickstart" + manifest = project / "mcpp.toml" + text = manifest.read_text() + dependency = tomllib.loads(text)["dependencies"][identity] + options = {"version": dependency} if isinstance(dependency, str) else dependency + assert options["version"] == version, options + replacement = '{ path = ' + json.dumps(package.as_posix()) + if options.get("features"): + replacement += ', features = ' + json.dumps(options["features"]) + replacement += ' }' + lines = text.splitlines() + matches = [i for i, line in enumerate(lines) if line.startswith(json.dumps(identity) + " =")] + assert len(matches) == 1, "Expected exactly one qualified dependency from self.name" + lines[matches[0]] = json.dumps(identity) + " = " + replacement + manifest.write_text("\n".join(lines) + "\n") + if args.index: + candidate_index = args.index.resolve() + subprocess.run([os.sys.executable, str(candidate_index / "tests/prepare_mwrap_indices.py")], + cwd=candidate_index, check=True) + with manifest.open("a") as out: + out.write("\n[indices]\n") + for namespace in ("compat", "mcpplibs.mwrap"): + view = candidate_index / "tests/mwrap/.indices" / namespace + out.write(json.dumps(namespace) + ' = { path = ' + json.dumps(view.as_posix()) + ' }\n') + command = [args.mcpp, "build", "--toolchain", args.toolchain, "--strict"] + print("+", " ".join(command), flush=True) + subprocess.run(command, cwd=project, check=True) + command = [args.mcpp, "run", "--toolchain", args.toolchain] + if args.run_arg: + command += ["--", *args.run_arg] + print("+", " ".join(command), flush=True) + subprocess.run(command, cwd=project, check=True) + + +if __name__ == "__main__": + main() From 40f72d5533a9bc29b17e62ae8a6c84b3dc593071 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 24 Oct 2026 11:20:51 +0900 Subject: [PATCH 2/8] fix: export the declared Godot entry without scanning SDK objects --- .../docs/2026-10-24-runnable-template-plan.md | 2 ++ .github/workflows/ci.yml | 13 +++++++++---- .gitignore | 2 ++ examples/summator/mcpp.toml | 3 +++ tools/check_extension_exports.py | 18 ++++++++++++++++++ 5 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 tools/check_extension_exports.py diff --git a/.agents/docs/2026-10-24-runnable-template-plan.md b/.agents/docs/2026-10-24-runnable-template-plan.md index 1c19db0..7209162 100644 --- a/.agents/docs/2026-10-24-runnable-template-plan.md +++ b/.agents/docs/2026-10-24-runnable-template-plan.md @@ -9,3 +9,5 @@ The client pin and .xlings.json use mcpp 2026.10.24.1. Local LLVM 23.1.3 and GCC All local heavy checks run serially under mwrap-tests.slice (16 logical CPUs, 32 GiB max on this 32-CPU/62-GiB host), taskset 0-15 and MCPP_JOBS=6. Resource-supervised checks stop their own process group below 6 GiB free disk or 20% available host memory. Completed task diagnostic directories were removed after checking active process references; source logs and immutable archives remain. Before release readiness: native source/template CI must pass, and the exact immutable archive must be registered and consumed by index tests. No mcpp engine sources are changed. + +On 1b5d973, Linux/macOS native wrapper, template and shared-extension jobs passed. Windows passed wrapper build/tests, then automatic COFF export discovery for the shared example exceeded CreateProcess's 32,768-byte command limit (86,489 bytes for the SDK object list). The extension already declares its GDE_EXPORT C entry point, so windows_auto_export=false correctly leaves PE exports to those source declarations. This uses the documented current manifest capability and avoids exporting the whole SDK; no engine edit or strict-mode exception is needed. The default template now precedes the extension check so an unrelated example failure cannot hide its result. Native Windows revalidation is still required. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5894767..8cd26e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -129,6 +129,12 @@ jobs: MCPP_INDEX_MIRROR: GLOBAL run: '"$MCPP" test --strict' + - name: Actual default scaffold, strict build and standalone math + shell: bash + env: + MCPP_INDEX_MIRROR: GLOBAL + run: python3 tools/test_template.py --mcpp "$MCPP" --toolchain "${{ matrix.toolchain }}" + # Verify the native shared-library shape on every supported platform. # Loading this library still requires a matching Godot process. - name: Build the summator GDExtension example @@ -138,8 +144,7 @@ jobs: MCPP_INDEX_MIRROR: GLOBAL run: '"$MCPP" build --strict' - - name: Actual default scaffold, strict build and standalone math + - name: Verify the Windows Godot entry point and export boundary + if: runner.os == 'Windows' shell: bash - env: - MCPP_INDEX_MIRROR: GLOBAL - run: python3 tools/test_template.py --mcpp "$MCPP" --toolchain "${{ matrix.toolchain }}" + run: python3 tools/check_extension_exports.py diff --git a/.gitignore b/.gitignore index 0bce1a1..d6c1dcb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ target/ .mcpp/ +.xlings/ +__pycache__/ mcpp.lock gcm.cache/ compile_commands.json diff --git a/examples/summator/mcpp.toml b/examples/summator/mcpp.toml index 649a0b3..062a19b 100644 --- a/examples/summator/mcpp.toml +++ b/examples/summator/mcpp.toml @@ -13,6 +13,9 @@ license = "MIT" [targets.summator] kind = "shared" +# Godot loads the GDE_EXPORT C entry point; it does not import the SDK's C++ +# symbols. Avoid scanning all 1,000+ SDK objects for automatic PE exports. +windows_auto_export = false [dependencies] godot-cpp-m = { path = "../.." } diff --git a/tools/check_extension_exports.py b/tools/check_extension_exports.py new file mode 100644 index 0000000..4c1046c --- /dev/null +++ b/tools/check_extension_exports.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +"""Check the built Windows extension publishes its declared Godot C entry only.""" +import json +from pathlib import Path +import re +import subprocess + +root = Path(__file__).resolve().parents[1] / "examples/summator" +commands = json.loads((root / "compile_commands.json").read_text(encoding="utf-8")) +entry = next(item for item in commands if Path(item["file"]).name == "summator.cpp") +reader = Path(entry["arguments"][0]).with_name("llvm-readobj.exe") +assert reader.is_file(), reader +binaries = list((root / "target").rglob("summator.dll")) +assert len(binaries) == 1, binaries +output = subprocess.check_output([str(reader), "--coff-exports", str(binaries[0])], text=True) +names = set(re.findall(r"^\s*Name:\s*(\S+)\s*$", output, re.M)) +assert names == {"summator_library_init"}, output +print("Verified the sole Windows extension export: summator_library_init") From ec79e387b3d96853ba06e421ebff85d986fa3070 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:09:59 +0900 Subject: [PATCH 3/8] feat: unify mwrap identity and upstream-aligned first release --- .../2026-10-25-unified-mwrap-checkpoint.md | 8 +++ .github/workflows/ci.yml | 3 ++ .github/workflows/release.yml | 49 +++++++++++++++++ README.md | 53 +++++++++++-------- README.zh.md | 51 ++++++++++++++++++ docs/usage.md | 12 ++--- examples/summator/mcpp.toml | 6 +-- examples/summator/src/summator.cpp | 4 +- include/godot-cpp-m/macros.h | 4 +- include/mwrap/godot_cpp/macros.hpp | 2 + mcpp.toml | 31 ++++------- src/godot_cpp.cppm | 6 ++- src/macros.cppm | 22 ++++++++ templates/math/src/main.cpp.in | 2 +- tests/godot_cpp_macros.cpp | 4 +- tests/godot_cpp_module.cpp | 4 +- tests/macros.cpp | 3 ++ tools/check_mwrap_release.py | 33 ++++++++++++ tools/gen_module_cppm.py | 5 +- 19 files changed, 236 insertions(+), 66 deletions(-) create mode 100644 .agents/docs/2026-10-25-unified-mwrap-checkpoint.md create mode 100644 .github/workflows/release.yml create mode 100644 README.zh.md create mode 100644 include/mwrap/godot_cpp/macros.hpp create mode 100644 src/macros.cppm create mode 100644 tests/macros.cpp create mode 100644 tools/check_mwrap_release.py diff --git a/.agents/docs/2026-10-25-unified-mwrap-checkpoint.md b/.agents/docs/2026-10-25-unified-mwrap-checkpoint.md new file mode 100644 index 0000000..e3a3659 --- /dev/null +++ b/.agents/docs/2026-10-25-unified-mwrap-checkpoint.md @@ -0,0 +1,8 @@ +# Unified mwrap first release + +Package/module: `mcpplibs.mwrap.godot_cpp`; upstream version: `10.0.0-rc1`. + +This checkpoint migrates wrapper identity while retaining upstream API names and SDK sources. +Default README is English with a mandatory Chinese counterpart; original section order is preserved. +Validation and release evidence are recorded in the PR and the index ecosystem ledger. +No old release tag or source resource is rewritten. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8cd26e8..dc17bf2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,6 +58,9 @@ jobs: # repeat run rebuilds little. Keyed off the tracked inputs only -- # `git ls-files -s` reads the index, so build output can never enter the # hash the way a hashFiles() glob would. + - name: Mwrap identity and bilingual README contract + run: python3 tools/check_mwrap_release.py + - name: Compute registry cache key shell: bash run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..f0c6447 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,49 @@ +name: Release +on: + push: + tags: ["mwrap-*"] +permissions: + contents: read +jobs: + publish: + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: write + actions: read + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Check tag, upstream version and bilingual entry pages + run: python3 tools/check_mwrap_release.py --tag "$GITHUB_REF_NAME" + - name: Require successful source CI at this exact commit + env: + GH_TOKEN: ${{ github.token }} + shell: bash + run: | + set -euo pipefail + result=$(gh run list --repo "$GITHUB_REPOSITORY" --workflow ci.yml --commit "$GITHUB_SHA" --limit 1 --json status,conclusion --jq '.[0] | .status == "completed" and .conclusion == "success"') + test "$result" = true || { echo 'No successful source CI at the tag commit'; exit 1; } + - name: Build immutable source asset and publish + env: + GH_TOKEN: ${{ github.token }} + shell: bash + run: | + set -euo pipefail + version="${GITHUB_REF_NAME#mwrap-}" + repo="${GITHUB_REPOSITORY#*/}" + asset="${repo}-${version}.tar.gz" + git archive --format=tar.gz --prefix="${repo}-${version}/" "$GITHUB_SHA" > "$RUNNER_TEMP/$asset" + (cd "$RUNNER_TEMP" && sha256sum "$asset" > "$asset.sha256") + if gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then + echo 'Release already exists; refusing to change immutable assets'; exit 1 + fi + extra=() + if [[ "$version" == *-rc* ]]; then extra+=(--prerelease); fi + gh release create "$GITHUB_REF_NAME" "$RUNNER_TEMP/$asset" "$RUNNER_TEMP/$asset.sha256" \ + --repo "$GITHUB_REPOSITORY" --verify-tag --title "$repo $version" \ + --notes "Module wrapper for upstream $version. New mwrap package identities become installable after mcpp-index publication; see the bilingual README for the tested support scope." "${extra[@]}" diff --git a/README.md b/README.md index 87f7c8a..38b1c05 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,51 @@ # godot-cpp-m -The godot-cpp **10.0.0-rc1** API through C++23 modules. Keep upstream `godot::` types and names. +> godot-cpp 10.0.0-rc1 as C++23 modules, preserving godot:: APIs. -## Quick start +**English** · [简体中文](README.zh.md) -Use mcpp **2026.10.24.1**. Version **10.0.0-rc1.1** is a wrapper candidate until its index entry is published. +Use mcpp **2026.10.24.1**. The new mwrap identity becomes installable after index publication. + +## Install ```sh -mcpp new godot-math --template godotengine.godot-cpp-m@10.0.0-rc1.1 -cd godot-math +mcpp new godot_math --template mcpplibs.mwrap.godot_cpp@10.0.0-rc1 +cd godot_math mcpp run ``` -The default template runs vector and color math without a Godot process. - -## Existing projects - ```toml [dependencies] -"godotengine.godot-cpp-m" = "10.0.0-rc1.1" +mcpplibs.mwrap.godot_cpp = "10.0.0-rc1" ``` +## Macros + +Use `.macros` for version mappings. For GDCLASS, D_METHOD and memory/control macros, include +`` before `import mcpplibs.mwrap.godot_cpp;`. + +## The hashfuncs shim + +A generated linkage adapter keeps upstream template bodies usable by named modules. [Details](docs/usage.md) + +## Example + ```cpp -import godot_cpp; -int main() { - return godot::Vector2(3, 4).length() == 5 ? 0 : 1; -} +import mcpplibs.mwrap.godot_cpp; +int main() { return godot::Vector2(3, 4).length() == 5 ? 0 : 1; } ``` -## Scope +The default template uses standalone math. [Summator](examples/summator) builds a shared GDExtension; loading needs a matching engine. + +## Regenerating the module + +Use `tools/gen_module_cppm.py` with the exact compat.godot-cpp source and generated headers; see [usage](docs/usage.md). -The pinned godot-cpp release targets Godot 4.6. Linux, macOS and Windows use the -same module API; the generated bindings are supplied by `compat.godot-cpp`. +## Tests -Engine objects and registration need a Godot process loading a GDExtension. -For `GDCLASS`, `D_METHOD` and other macros, include `` before imports. -The [summator example](examples/summator) shows the extension structure; the default template exercises standalone math. +`mcpp test` covers module/math and textual macros; CI also builds the extension on Linux/macOS/Windows. +This is a prerelease binding, not certification of engine loading. -## Documentation +## License -[Usage and adaptation details](docs/usage.md) · [Examples](examples) · [MIT](LICENSE) +[MIT](LICENSE); compat.godot-cpp carries upstream sources, generated bindings and notices. diff --git a/README.zh.md b/README.zh.md new file mode 100644 index 0000000..4187786 --- /dev/null +++ b/README.zh.md @@ -0,0 +1,51 @@ +# godot-cpp-m + +> godot-cpp 10.0.0-rc1 的 C++23 模块封装,保留 godot:: API。 + +[English](README.md) · **简体中文** + +使用 mcpp **2026.10.24.1**。新 mwrap 身份在索引发布后可直接安装。 + +## 安装 + +```sh +mcpp new godot_math --template mcpplibs.mwrap.godot_cpp@10.0.0-rc1 +cd godot_math +mcpp run +``` + +```toml +[dependencies] +mcpplibs.mwrap.godot_cpp = "10.0.0-rc1" +``` + +## 宏 + +版本映射使用 `.macros`;GDCLASS、D_METHOD 与内存/控制宏在 import 前包含 +``,再 `import mcpplibs.mwrap.godot_cpp;`。 + +## hashfuncs 适配 + +生成的链接属性适配使上游模板实现可用于命名模块;见[详情](docs/usage.md)。 + +## 示例 + +```cpp +import mcpplibs.mwrap.godot_cpp; +int main() { return godot::Vector2(3, 4).length() == 5 ? 0 : 1; } +``` + +默认模板使用独立数学 API;[Summator](examples/summator) 构建共享扩展,加载需要匹配的引擎。 + +## 重新生成模块 + +用精确版本 compat.godot-cpp 源码及生成头运行 `tools/gen_module_cppm.py`;见[使用](docs/usage.md)。 + +## 测试 + +`mcpp test` 覆盖模块、数学与文本宏;CI 还在 Linux/macOS/Windows 构建扩展。 +这是预发布绑定,不代表引擎实际加载认证。 + +## 许可证 + +[MIT](LICENSE);compat.godot-cpp 提供上游源码、生成绑定及通知。 diff --git a/docs/usage.md b/docs/usage.md index 41ecd24..3b459a2 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -1,12 +1,12 @@ # godot-cpp-m -> godot-cpp as a C++23 module for mcpp — the same API, reached with `import godot_cpp;`. +> godot-cpp as a C++23 module for mcpp — the same API, reached with `import mcpplibs.mwrap.godot_cpp;`. > > Targets **Godot 4.6** (`compat.godot-cpp` 10.0.0-rc1). For Godot 4.5, use `godot-cpp-m = "4.5.0"`. ```cpp import std; -import godot_cpp; +import mcpplibs.mwrap.godot_cpp; int main() { godot::Vector2 v{3, 4}; @@ -30,11 +30,11 @@ int main() { ```toml [dependencies] -"godotengine.godot-cpp-m" = "10.0.0-rc1.1" # Godot 4.6; use "4.5.0" for Godot 4.5 +"mcpplibs.mwrap.godot_cpp" = "10.0.0-rc1" # Godot 4.6; use "4.5.0" for Godot 4.5 ``` The version tracks upstream godot-cpp. A numeric wrapper revision may follow -the upstream version: candidate `10.0.0-rc1.1` still uses SDK `10.0.0-rc1`. +the upstream version: candidate `10.0.0-rc1` still uses SDK `10.0.0-rc1`. The historical upstream mapping is: | package version | upstream tag | engine | @@ -51,7 +51,7 @@ classes includes the side header next to the import: ```cpp #include -import godot_cpp; +import mcpplibs.mwrap.godot_cpp; using namespace godot; @@ -111,7 +111,7 @@ With it in place nothing has to be held back: `HashMap`, `HashSet`, `AHashMap`, `examples/summator/` is a complete GDExtension — registered class, bound methods, entry point — built as the shared library Godot loads, written with -`import godot_cpp;`: +`import mcpplibs.mwrap.godot_cpp;`: ```sh cd examples/summator && mcpp build diff --git a/examples/summator/mcpp.toml b/examples/summator/mcpp.toml index 062a19b..208ad93 100644 --- a/examples/summator/mcpp.toml +++ b/examples/summator/mcpp.toml @@ -1,5 +1,5 @@ # A real GDExtension, built as the shared library Godot loads -- the shape -# godot-cpp actually ships in. Written against `import godot_cpp;` with the +# godot-cpp actually ships in. Written against `import mcpplibs.mwrap.godot_cpp;` with the # side header for the registration macros. # # mcpp build @@ -8,7 +8,7 @@ [package] name = "summator" version = "0.1.0" -description = "Minimal Godot 4.6 GDExtension written with import godot_cpp;" +description = "Minimal Godot 4.6 GDExtension written with import mcpplibs.mwrap.godot_cpp;" license = "MIT" [targets.summator] @@ -18,4 +18,4 @@ kind = "shared" windows_auto_export = false [dependencies] -godot-cpp-m = { path = "../.." } +"mcpplibs.mwrap.godot_cpp" = { path = "../.." } diff --git a/examples/summator/src/summator.cpp b/examples/summator/src/summator.cpp index 821eef9..b367e83 100644 --- a/examples/summator/src/summator.cpp +++ b/examples/summator/src/summator.cpp @@ -1,5 +1,5 @@ // A complete Godot 4.5 GDExtension -- registered class, bound methods, -// entry point -- written with `import godot_cpp;`. +// entry point -- written with `import mcpplibs.mwrap.godot_cpp;`. // // Compare with upstream's C++ version of the same example: the only // difference is the first three lines. Everything below is ordinary @@ -7,7 +7,7 @@ #include // GDCLASS, GDREGISTER_CLASS, D_METHOD, the entry-point plumbing -import godot_cpp; +import mcpplibs.mwrap.godot_cpp; using namespace godot; diff --git a/include/godot-cpp-m/macros.h b/include/godot-cpp-m/macros.h index fbc01bb..8fb90dd 100644 --- a/include/godot-cpp-m/macros.h +++ b/include/godot-cpp-m/macros.h @@ -1,14 +1,14 @@ // godot-cpp-m/macros.h -- optional side header for godot-cpp's preprocessor surface. // // C++ named modules cannot export MACROS. Everything with linkage comes from -// `import godot_cpp;`; the macro spellings that GDExtension code is written in +// `import mcpplibs.mwrap.godot_cpp;`; the macro spellings that GDExtension code is written in // -- GDCLASS, GDREGISTER_CLASS, GDVIRTUAL_*, D_METHOD, memnew/memdelete, the // ERR_* family, VARIANT_ENUM_CAST -- are preprocessor constructs, so a // translation unit that registers classes textually includes THIS header next // to the import: // // #include -// import godot_cpp; +// import mcpplibs.mwrap.godot_cpp; // // class Player : public godot::Node2D { // GDCLASS(Player, Node2D) diff --git a/include/mwrap/godot_cpp/macros.hpp b/include/mwrap/godot_cpp/macros.hpp new file mode 100644 index 0000000..b0afcb0 --- /dev/null +++ b/include/mwrap/godot_cpp/macros.hpp @@ -0,0 +1,2 @@ +#pragma once +#include diff --git a/mcpp.toml b/mcpp.toml index 53ee3eb..25156d6 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -1,30 +1,14 @@ -# godot-cpp-m -- godot-cpp as a C++23 module. -# -# This package is ONLY the module layer. Upstream's sources and its -# pre-generated GDExtension bindings arrive through the compat.godot-cpp index -# package, which compiles them (1022 TUs) as an ordinary mcpp source package. -# The version TRACKS UPSTREAM: 4.5.0 is the godot-cpp / Godot release this -# wraps, the same version compat.godot-cpp carries. A module layer that only -# re-exports an API has no version of its own worth inventing -- what a -# consumer needs to know from the version is which Godot it targets. -# -# The NAME is `godot-cpp-m`, not `godot-cpp`, and that is load-bearing: 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 -- two packages sharing both would have this one -# resolve to the other's unpacked directory and fail with "no mcpp.toml at -# /*/mcpp.toml". Distinct short names sidestep it, and `-m` matches -# the repository name. +# Module wrapper; upstream API preserved. Policy: mcpp-index/docs/mwrap.md. [package] -namespace = "godotengine" -name = "godot-cpp-m" -version = "10.0.0-rc1.1" -description = "godot-cpp as a C++23 module (import godot_cpp;) on top of the compat.godot-cpp source build" +namespace = "mcpplibs.mwrap" +name = "godot_cpp" +version = "10.0.0-rc1" +description = "godot-cpp as a C++23 module (import mcpplibs.mwrap.godot_cpp;) on top of the compat.godot-cpp source build" license = "MIT" repo = "https://github.com/mcpplibs/godot-cpp-m" platforms = ["linux", "macos", "windows"] -[targets.godot-cpp-m] +[targets.godot_cpp] kind = "lib" [lib] @@ -46,3 +30,6 @@ cxxflags = ["-Wno-expose-global-module-tu-local"] [dependencies] # Upstream tree + pre-generated bindings + the whole source build recipe. compat.godot-cpp = "10.0.0-rc1" + +[package.metadata.mwrap] +upstream-version = "10.0.0-rc1" diff --git a/src/godot_cpp.cppm b/src/godot_cpp.cppm index bf46e1a..8564284 100644 --- a/src/godot_cpp.cppm +++ b/src/godot_cpp.cppm @@ -9,7 +9,7 @@ // #include // godot::Node *n = ...; // -// says `import godot_cpp;` instead and is otherwise unchanged. Macros are the one +// says `import mcpplibs.mwrap.godot_cpp;` instead and is otherwise unchanged. Macros are the one // thing a module cannot carry (GDCLASS, GDREGISTER_CLASS, memnew, ERR_*, // GDVIRTUAL_*): a TU that registers classes still includes the header that // defines them. @@ -1147,7 +1147,7 @@ module; #include #include -export module godot_cpp; +export module mcpplibs.mwrap.godot_cpp; export namespace godot { using ::godot::EditorPlugin; @@ -2976,3 +2976,5 @@ export namespace godot::helpers { using ::godot::helpers::append_all; } + +export import mcpplibs.mwrap.godot_cpp.macros; diff --git a/src/macros.cppm b/src/macros.cppm new file mode 100644 index 0000000..32bf57d --- /dev/null +++ b/src/macros.cppm @@ -0,0 +1,22 @@ +module; +#include +namespace mwrap_godot_cpp_capture { +inline constexpr auto value_GODOT_VERSION_MAJOR = GODOT_VERSION_MAJOR; +inline constexpr auto value_GODOT_VERSION_MINOR = GODOT_VERSION_MINOR; +inline constexpr auto value_GODOT_VERSION_PATCH = GODOT_VERSION_PATCH; +inline constexpr auto value_GODOT_VERSION_STATUS = GODOT_VERSION_STATUS; +} +#undef GODOT_VERSION_MAJOR +#undef GODOT_VERSION_MINOR +#undef GODOT_VERSION_PATCH +#undef GODOT_VERSION_STATUS + +export module mcpplibs.mwrap.godot_cpp.macros; + +export namespace mcpplibs::mwrap::godot_cpp::macros { +inline constexpr auto GODOT_VERSION_MAJOR = mwrap_godot_cpp_capture::value_GODOT_VERSION_MAJOR; +inline constexpr auto GODOT_VERSION_MINOR = mwrap_godot_cpp_capture::value_GODOT_VERSION_MINOR; +inline constexpr auto GODOT_VERSION_PATCH = mwrap_godot_cpp_capture::value_GODOT_VERSION_PATCH; +inline constexpr auto GODOT_VERSION_STATUS = mwrap_godot_cpp_capture::value_GODOT_VERSION_STATUS; + +} diff --git a/templates/math/src/main.cpp.in b/templates/math/src/main.cpp.in index b4956f0..477475f 100644 --- a/templates/math/src/main.cpp.in +++ b/templates/math/src/main.cpp.in @@ -1,5 +1,5 @@ import std; -import godot_cpp; +import mcpplibs.mwrap.godot_cpp; int main() { const godot::Vector2 vector(3, 4); diff --git a/tests/godot_cpp_macros.cpp b/tests/godot_cpp_macros.cpp index ff43a98..457d932 100644 --- a/tests/godot_cpp_macros.cpp +++ b/tests/godot_cpp_macros.cpp @@ -1,6 +1,6 @@ // The macro half of the contract: a real GDExtension class declaration -- // GDCLASS, a bound method, an overridden engine virtual -- written next to -// `import godot_cpp;`, with only the side header included. +// `import mcpplibs.mwrap.godot_cpp;`, with only the side header included. // // This is the case a named module cannot cover on its own, so it gets its own // test: it proves that textually including godot-cpp's headers alongside the @@ -18,7 +18,7 @@ #include import std; -import godot_cpp; +import mcpplibs.mwrap.godot_cpp; using namespace godot; diff --git a/tests/godot_cpp_module.cpp b/tests/godot_cpp_module.cpp index 231e9d2..843c975 100644 --- a/tests/godot_cpp_module.cpp +++ b/tests/godot_cpp_module.cpp @@ -1,5 +1,5 @@ // Behavioral test for the `godot_cpp` module: the same godot-cpp API as -// always, reached with `import godot_cpp;` and no #include at all. +// always, reached with `import mcpplibs.mwrap.godot_cpp;` and no #include at all. // // The assertions mirror the compat.godot-cpp test on purpose -- if the module // re-export changed behaviour, these are the numbers that would move. @@ -8,7 +8,7 @@ // class registration) is out of scope for a standalone binary. import std; -import godot_cpp; +import mcpplibs.mwrap.godot_cpp; namespace { diff --git a/tests/macros.cpp b/tests/macros.cpp new file mode 100644 index 0000000..f2d230d --- /dev/null +++ b/tests/macros.cpp @@ -0,0 +1,3 @@ +import mcpplibs.mwrap.godot_cpp.macros; +namespace macros = mcpplibs::mwrap::godot_cpp::macros; +int main() { static_assert(macros::GODOT_VERSION_MAJOR >= 4); return 0; } diff --git a/tools/check_mwrap_release.py b/tools/check_mwrap_release.py new file mode 100644 index 0000000..4dde1a9 --- /dev/null +++ b/tools/check_mwrap_release.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +"""Check the immutable mwrap release coordinate and bilingual entry pages.""" +import argparse +from pathlib import Path +import re +import tomllib + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--tag', help='release tag; omitted during PR checks') + args = parser.parse_args() + root = Path(__file__).resolve().parents[1] + package = tomllib.loads((root / 'mcpp.toml').read_text())['package'] + assert package['namespace'] == 'mcpplibs.mwrap', package + assert re.fullmatch(r'[A-Za-z_][A-Za-z_0-9]*', package['name']), package['name'] + upstream = package['metadata']['mwrap']['upstream-version'] + version = package['version'] + assert version == upstream or re.fullmatch(re.escape(upstream) + r'\.[1-9][0-9]*', version), (version, upstream) + if args.tag: + assert args.tag == 'mwrap-' + version, (args.tag, version) + identity = package['namespace'] + '.' + package['name'] + for name, other in [('README.md', 'README.zh.md'), ('README.zh.md', 'README.md')]: + text = (root / name).read_text() + assert len(text.splitlines()) <= 100, name + assert '](' + other + ')' in '\n'.join(text.splitlines()[:12]), name + assert identity in text and version in text, name + assert text.count('```') % 2 == 0, name + print(identity + '@' + version) + + +if __name__ == '__main__': + main() diff --git a/tools/gen_module_cppm.py b/tools/gen_module_cppm.py index 3b36b02..fc8d0df 100644 --- a/tools/gen_module_cppm.py +++ b/tools/gen_module_cppm.py @@ -363,7 +363,7 @@ def match_brace(text: str, start: int) -> int: // #include // godot::Node *n = ...; // -// says `import godot_cpp;` instead and is otherwise unchanged. Macros are the one +// says `import mcpplibs.mwrap.godot_cpp;` instead and is otherwise unchanged. Macros are the one // thing a module cannot carry (GDCLASS, GDREGISTER_CLASS, memnew, ERR_*, // GDVIRTUAL_*): a TU that registers classes still includes the header that // defines them. @@ -371,7 +371,7 @@ def match_brace(text: str, start: int) -> int: {includes} -export module godot_cpp; +export module mcpplibs.mwrap.godot_cpp; """ @@ -477,6 +477,7 @@ def main(argv: list[str]) -> int: out.append(f"using ::{ns}::{name};\n") out.append("}\n\n") + out.append("export import mcpplibs.mwrap.godot_cpp.macros;\n") sys.stdout.write("".join(out)) return 0 From eb86be94dc1f68bbade9d5ec7dcd4646cc937ac3 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:11:17 +0900 Subject: [PATCH 4/8] fix: place macro module imports before exported declarations --- src/godot_cpp.cppm | 2 +- tools/gen_module_cppm.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/godot_cpp.cppm b/src/godot_cpp.cppm index 8564284..35fbac5 100644 --- a/src/godot_cpp.cppm +++ b/src/godot_cpp.cppm @@ -1148,6 +1148,7 @@ module; #include export module mcpplibs.mwrap.godot_cpp; +export import mcpplibs.mwrap.godot_cpp.macros; export namespace godot { using ::godot::EditorPlugin; @@ -2977,4 +2978,3 @@ using ::godot::helpers::append_all; } -export import mcpplibs.mwrap.godot_cpp.macros; diff --git a/tools/gen_module_cppm.py b/tools/gen_module_cppm.py index fc8d0df..fb63143 100644 --- a/tools/gen_module_cppm.py +++ b/tools/gen_module_cppm.py @@ -372,6 +372,7 @@ def match_brace(text: str, start: int) -> int: {includes} export module mcpplibs.mwrap.godot_cpp; +export import mcpplibs.mwrap.godot_cpp.macros; """ @@ -477,7 +478,6 @@ def main(argv: list[str]) -> int: out.append(f"using ::{ns}::{name};\n") out.append("}\n\n") - out.append("export import mcpplibs.mwrap.godot_cpp.macros;\n") sys.stdout.write("".join(out)) return 0 From 4f6f0628b4df94f940ef7e0bdcde3f5df104b03a Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:13:32 +0900 Subject: [PATCH 5/8] fix(ci): read bilingual metadata explicitly as UTF-8 --- tools/check_mwrap_release.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/check_mwrap_release.py b/tools/check_mwrap_release.py index 4dde1a9..9222469 100644 --- a/tools/check_mwrap_release.py +++ b/tools/check_mwrap_release.py @@ -11,7 +11,7 @@ def main(): parser.add_argument('--tag', help='release tag; omitted during PR checks') args = parser.parse_args() root = Path(__file__).resolve().parents[1] - package = tomllib.loads((root / 'mcpp.toml').read_text())['package'] + package = tomllib.loads((root / 'mcpp.toml').read_text(encoding="utf-8"))['package'] assert package['namespace'] == 'mcpplibs.mwrap', package assert re.fullmatch(r'[A-Za-z_][A-Za-z_0-9]*', package['name']), package['name'] upstream = package['metadata']['mwrap']['upstream-version'] @@ -21,7 +21,7 @@ def main(): assert args.tag == 'mwrap-' + version, (args.tag, version) identity = package['namespace'] + '.' + package['name'] for name, other in [('README.md', 'README.zh.md'), ('README.zh.md', 'README.md')]: - text = (root / name).read_text() + text = (root / name).read_text(encoding="utf-8") assert len(text.splitlines()) <= 100, name assert '](' + other + ')' in '\n'.join(text.splitlines()[:12]), name assert identity in text and version in text, name From 7824150898d97dd2331b50dc4f6a7bdf5c51001e Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:31:51 +0900 Subject: [PATCH 6/8] docs: apply concise bilingual mwrap README layout --- README.md | 2 +- README.zh.md | 2 +- tools/check_mwrap_release.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 38b1c05..6e05fce 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ **English** · [简体中文](README.zh.md) -Use mcpp **2026.10.24.1**. The new mwrap identity becomes installable after index publication. +Upstream: [godotengine/godot-cpp](https://github.com/godotengine/godot-cpp) ## Install diff --git a/README.zh.md b/README.zh.md index 4187786..9158490 100644 --- a/README.zh.md +++ b/README.zh.md @@ -4,7 +4,7 @@ [English](README.md) · **简体中文** -使用 mcpp **2026.10.24.1**。新 mwrap 身份在索引发布后可直接安装。 +上游仓库:[godotengine/godot-cpp](https://github.com/godotengine/godot-cpp) ## 安装 diff --git a/tools/check_mwrap_release.py b/tools/check_mwrap_release.py index 9222469..227fd8d 100644 --- a/tools/check_mwrap_release.py +++ b/tools/check_mwrap_release.py @@ -22,7 +22,7 @@ def main(): identity = package['namespace'] + '.' + package['name'] for name, other in [('README.md', 'README.zh.md'), ('README.zh.md', 'README.md')]: text = (root / name).read_text(encoding="utf-8") - assert len(text.splitlines()) <= 100, name + assert len(text.splitlines()) <= 150, name assert '](' + other + ')' in '\n'.join(text.splitlines()[:12]), name assert identity in text and version in text, name assert text.count('```') % 2 == 0, name From aa56fc47357906c5822a64f49c96674410e609c7 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:36:30 +0900 Subject: [PATCH 7/8] docs: standardize navigation and introductory layout --- README.md | 6 ++++-- README.zh.md | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6e05fce..e1217ce 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,11 @@ > godot-cpp 10.0.0-rc1 as C++23 modules, preserving godot:: APIs. -**English** · [简体中文](README.zh.md) +**English** · [简体中文](README.zh.md) · Upstream: [godotengine/godot-cpp](https://github.com/godotengine/godot-cpp) · [Releases](https://github.com/mcpplibs/godot-cpp-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) -Upstream: [godotengine/godot-cpp](https://github.com/godotengine/godot-cpp) +[![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23) +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +[![CI](https://github.com/mcpplibs/godot-cpp-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/godot-cpp-m/actions/workflows/ci.yml) ## Install diff --git a/README.zh.md b/README.zh.md index 9158490..ee886d1 100644 --- a/README.zh.md +++ b/README.zh.md @@ -2,9 +2,11 @@ > godot-cpp 10.0.0-rc1 的 C++23 模块封装,保留 godot:: API。 -[English](README.md) · **简体中文** +[English](README.md) · **简体中文** · 上游:[godotengine/godot-cpp](https://github.com/godotengine/godot-cpp) · [Releases](https://github.com/mcpplibs/godot-cpp-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) -上游仓库:[godotengine/godot-cpp](https://github.com/godotengine/godot-cpp) +[![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23) +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +[![CI](https://github.com/mcpplibs/godot-cpp-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/godot-cpp-m/actions/workflows/ci.yml) ## 安装 From daf32149f3ca87a6f8e8f1568913491fac7b353a Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:43:09 +0900 Subject: [PATCH 8/8] docs: lead quickstarts with core module imports and uniform upstream links --- README.md | 9 ++++++++- README.zh.md | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e1217ce..615d782 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,19 @@ > godot-cpp 10.0.0-rc1 as C++23 modules, preserving godot:: APIs. -**English** · [简体中文](README.zh.md) · Upstream: [godotengine/godot-cpp](https://github.com/godotengine/godot-cpp) · [Releases](https://github.com/mcpplibs/godot-cpp-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) +**English** · [简体中文](README.zh.md) · [Upstream](https://github.com/godotengine/godot-cpp) · [Releases](https://github.com/mcpplibs/godot-cpp-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) [![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![CI](https://github.com/mcpplibs/godot-cpp-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/godot-cpp-m/actions/workflows/ci.yml) +## Modules + +- `import mcpplibs.mwrap.godot_cpp;`: godot:: math and GDExtension bindings +- `import mcpplibs.mwrap.godot_cpp.macros;`: Version macro mappings + +> More Modules API -> [Usage and API](docs/usage.md) + ## Install ```sh diff --git a/README.zh.md b/README.zh.md index ee886d1..5f862de 100644 --- a/README.zh.md +++ b/README.zh.md @@ -2,12 +2,19 @@ > godot-cpp 10.0.0-rc1 的 C++23 模块封装,保留 godot:: API。 -[English](README.md) · **简体中文** · 上游:[godotengine/godot-cpp](https://github.com/godotengine/godot-cpp) · [Releases](https://github.com/mcpplibs/godot-cpp-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) +[English](README.md) · **简体中文** · [Upstream](https://github.com/godotengine/godot-cpp) · [Releases](https://github.com/mcpplibs/godot-cpp-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) [![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![CI](https://github.com/mcpplibs/godot-cpp-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/godot-cpp-m/actions/workflows/ci.yml) +## 模块 + +- `import mcpplibs.mwrap.godot_cpp;`: godot:: 数学与 GDExtension 绑定 +- `import mcpplibs.mwrap.godot_cpp.macros;`: 版本宏映射 + +> More Modules API -> [模块与 API](docs/usage.md) + ## 安装 ```sh