Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .agents/docs/2026-10-24-runnable-template-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# 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.

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.
8 changes: 8 additions & 0 deletions .agents/docs/2026-10-25-unified-mwrap-checkpoint.md
Original file line number Diff line number Diff line change
@@ -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.
36 changes: 23 additions & 13 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Expand All @@ -55,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: |
Expand Down Expand Up @@ -116,28 +122,32 @@ 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
- name: Run tests
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.
- 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
if: runner.os == 'Linux'
shell: bash
working-directory: examples/summator
env:
MCPP_INDEX_MIRROR: GLOBAL
run: '"$MCPP" build'
run: '"$MCPP" build --strict'

- name: Verify the Windows Godot entry point and export boundary
if: runner.os == 'Windows'
shell: bash
run: python3 tools/check_extension_exports.py
49 changes: 49 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -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[@]}"
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
target/
.mcpp/
.xlings/
__pycache__/
mcpp.lock
gcm.cache/
compile_commands.json
2 changes: 1 addition & 1 deletion .xlings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"workspace": {
"xim:mcpp": "2026.8.3.3"
"xim:mcpp": "2026.10.24.1"
}
}
152 changes: 30 additions & 122 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,152 +1,60 @@
# 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"`.
> godot-cpp 10.0.0-rc1 as C++23 modules, preserving godot:: APIs.

```cpp
import std;
import godot_cpp;
**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)

int main() {
godot::Vector2 v{3, 4};
std::println("{}", v.length()); // 5 — the same godot-cpp you already know, no #include
}
```
[![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

- **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.
> More Modules API -> [Usage and API](docs/usage.md)

## Install

```sh
mcpp new godot_math --template mcpplibs.mwrap.godot_cpp@10.0.0-rc1
cd godot_math
mcpp run
```

```toml
[dependencies]
godot-cpp-m = "10.0.0-rc1" # Godot 4.6; use "4.5.0" for Godot 4.5
mcpplibs.mwrap.godot_cpp = "10.0.0-rc1"
```

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 <godot-cpp-m/macros.h>
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.
Use `.macros` for version mappings. For GDCLASS, D_METHOD and memory/control macros, include
`<mwrap/godot_cpp/macros.hpp>` before `import mcpplibs.mwrap.godot_cpp;`.

## 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 ...::<unnamed>'
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.
A generated linkage adapter keeps upstream template bodies usable by named modules. [Details](docs/usage.md)

## 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
```cpp
import mcpplibs.mwrap.godot_cpp;
int main() { return godot::Vector2(3, 4).length() == 5 ? 0 : 1; }
```

## Regenerating the module

`src/godot_cpp.cppm` is generated, not hand-written. After a `compat.godot-cpp`
version bump:
The default template uses standalone math. [Summator](examples/summator) builds a shared GDExtension; loading needs a matching engine.

```sh
python3 tools/gen_module_cppm.py --shim-out include/godot_cpp/templates/hashfuncs.hpp \
<godot-cpp-checkout-with-gen/> > src/godot_cpp.cppm
mcpp test
```
## Regenerating the module

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.
Use `tools/gen_module_cppm.py` with the exact compat.godot-cpp source and generated headers; see [usage](docs/usage.md).

## 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.
`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.

## License

MIT for the module layer. Upstream godot-cpp is MIT as well.
[MIT](LICENSE); compat.godot-cpp carries upstream sources, generated bindings and notices.
Loading
Loading