-
Notifications
You must be signed in to change notification settings - Fork 2
user_impl_workflow
This page explains where you implement your extension, how the generated CMake project is intended to be used, and how the workflow differs by target/platform.
extgen generates a multi-platform CMake project, but the extension logic itself is always your responsibility and lives inside the src/ folder (plus target-specific glue for some platforms).
✅ Key idea: extgen generates the bridge + build system, you implement the feature code.
After running extgen, your folder usually looks like:
-
code_gen/→ generated bridge code (do not hand-edit) -
cmake/→ helper scripts (packaging, xcframework, etc.) -
src/✅ → your implementation lives here-
src/CMakeLists.txt✅ → you control which files build per platform -
src/native/,src/ios/,src/tvos/, etc. ✅ → your platform implementations
-
-
third_party/→ optional integration point for SDKs / libraries
The workflow is:
- Edit GMIDL → defines the public API
- Run extgen → regenerates bindings + project
- Implement platform behavior in
src/ - Build via CMake presets (or via IDE toolchains)
The root CMakeLists.txt provides platform classification booleans like:
set(EXTGEN_IS_IOS FALSE)
set(EXTGEN_IS_TVOS FALSE)
set(EXTGEN_IS_APPLE_MOBILE FALSE)
set(EXTGEN_IS_PS4 FALSE)
set(EXTGEN_IS_PS5 FALSE)
if(APPLE)
if(CMAKE_OSX_SYSROOT MATCHES "iphone")
set(EXTGEN_IS_IOS TRUE)
set(EXTGEN_IS_APPLE_MOBILE TRUE)
elseif(CMAKE_OSX_SYSROOT MATCHES "appletv")
set(EXTGEN_IS_TVOS TRUE)
set(EXTGEN_IS_APPLE_MOBILE TRUE)
endif()
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "ORBIS")
set(EXTGEN_IS_PS4 TRUE)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Prospero")
set(EXTGEN_IS_PS5 TRUE)
endif()You can use these in src/CMakeLists.txt to decide what to compile, which defines to add, and which files belong to each platform.
When building an XCFramework, we must tell the packaging step which public headers to include.
In your src/CMakeLists.txt, extgen places something like:
set(EXT_PUBLIC_HEADERS_IOS
"${CMAKE_SOURCE_DIR}/src/ios/${PROJECT_NAME}_ios.h;${CMAKE_SOURCE_DIR}/code_gen/ios/${PROJECT_NAME}Internal_ios.h"
CACHE STRING "Semicolon-separated list of public headers to embed in the iOS xcframework")
set(EXT_PUBLIC_HEADERS_TVOS
"${CMAKE_SOURCE_DIR}/src/tvos/${PROJECT_NAME}_tvos.h;${CMAKE_SOURCE_DIR}/code_gen/tvos/${PROJECT_NAME}Internal_tvos.h"
CACHE STRING "Semicolon-separated list of public headers to embed in the tvOS xcframework")✅ You must keep this list correct if you change your src/ios or src/tvos layout.
Why this matters:
xcodebuild -create-xcframeworkrequires a headers folder. extgen collects these files into that folder during packaging.
- No C/C++ library build
- Pure Java/Kotlin glue code emitted into the target output folder (default:
../AndroidSource/...)
You implement the platform behavior in the generated Java/Kotlin layer.
A module-named file is generated, for example:
../AndroidSource/Java/<ModuleName>.java
And an internal interface is generated, for example:
../AndroidSource/Java/code_gen/<ModuleName>Interface.java
✅ Your implementation should implement that interface.
- The interface forces your Java/Kotlin implementation to stay in sync with GMIDL
- When you regenerate, compile errors immediately point to missing functions
📝 Tip: Treat the interface as the “contract.” If GMIDL changes, you update your implementation accordingly.
This applies to:
- ✅ Windows
- ✅ macOS
- ✅ Linux
- ✅ Xbox
- ✅ PS4 / PS5
- ✅ Switch
- ✅ Android (JNI mode)
- ✅ iOS/tvOS (Native mode)
In src/, typically organized like:
-
src/native/(shared native implementation) -
src/windows/,src/macos/, etc. (optional splits) -
src/ios/,src/tvos/(platform wrappers if needed)
In src/CMakeLists.txt, you choose which sources compile per platform.
Example pattern:
if(WIN32)
file(GLOB TARGET_SRCS CONFIGURE_DEPENDS "${SRC_DIR}/native/*.cpp" "${SRC_DIR}/windows/*.cpp")
elseif(APPLE)
if(EXTGEN_IS_IOS)
file(GLOB TARGET_SRCS CONFIGURE_DEPENDS "${SRC_DIR}/native/*.cpp" "${SRC_DIR}/ios/*.mm")
elseif(EXTGEN_IS_TVOS)
file(GLOB TARGET_SRCS CONFIGURE_DEPENDS "${SRC_DIR}/native/*.cpp" "${SRC_DIR}/tvos/*.mm")
else()
file(GLOB TARGET_SRCS CONFIGURE_DEPENDS "${SRC_DIR}/native/*.cpp" "${SRC_DIR}/macos/*.mm")
endif()
elseif(ANDROID)
file(GLOB TARGET_SRCS CONFIGURE_DEPENDS "${SRC_DIR}/native/*.cpp")
else()
file(GLOB TARGET_SRCS CONFIGURE_DEPENDS "${SRC_DIR}/native/*.cpp")
endif()
target_sources(${PROJECT_NAME} PRIVATE ${TARGET_SRCS})- Most targets build a shared library
- iOS/tvOS build a static slice that is packaged into an XCFramework
🧩 Tip: If you support many platforms, use one “core” folder (like
src/native/) and keep platform folders thin.
iOS and tvOS development with extgen is designed to:
- ✅ Keep all implementation inside your repository (
src/) - ✅ Allow full Xcode debugging & real-device testing
- ✅ Avoid manual project injection
- ✅ Be repeatable and automation-friendly
The integration into the GameMaker-generated Xcode project is handled automatically via a dedicated CMake build target.
Generate bindings and project files from GMIDL:
extgen --config config.jsonRun configure (via preset or manually). This prepares the extension project and build targets.
You do not need to manually open or inject anything into Xcode.
From GameMaker:
- Build for iOS/tvOS
- Enable Suppress Run
This generates the Xcode project for the game.
In your CMake configuration (or preset), set:
# =============================================================================
# GameMaker iOS integration (optional)
# =============================================================================
set(EXT_GM_XCODEPROJ_OVERRIDE
"~/GameMakerStudio2/GM_IOS/YourGame/YourGame/YourGame.xcodeproj"
CACHE FILEPATH "" FORCE)
set(EXT_GM_APP_TARGET_OVERRIDE "" CACHE STRING "" FORCE)| Variable | Purpose |
|---|---|
EXT_GM_XCODEPROJ_OVERRIDE |
Path to the GameMaker-generated .xcodeproj
|
EXT_GM_APP_TARGET_OVERRIDE |
Optional override for the app target name |
Because EXT_GM_XCODEPROJ_OVERRIDE is a FILEPATH, CMake automatically:
- Expands
~ - Normalizes the path
- Validates it properly in GUIs and presets
Instead of manually injecting the extension project into Xcode, run:
cmake --build <build-folder> --target integrate_gamemakerThis target automatically:
- Adds the extension project to the GameMaker Xcode project
- Creates required project references
- Adds the static library dependency
- Links it into the correct GameMaker target
- Safely handles repeated runs (idempotent)
No Xcode UI steps required.
Now open the GameMaker-generated .xcodeproj or workspace.
Your extension is already integrated.
You can:
- Build for device or simulator
- Debug on real hardware
- Use full Xcode tooling
- Edit extension source directly from the injected reference
The integration adds a project reference, not copied files.
That means:
- Editing code inside Xcode edits your real extension source
- No duplicated files
- No manual syncing required
- Clean Git history
Switching between device/simulator is simply a configuration change.
-
Edit GMIDL
-
Run
extgen -
Implement logic in
src/ -
Export from GameMaker (Suppress Run)
-
Run:
cmake --build <build-folder> --target integrate_gamemaker
-
Open Xcode and build/debug normally
If you re-export from GameMaker, simply re-run the integration target.
When ready for distribution:
cmake --build <build-folder> --target package_ios_xcframework
cmake --build <build-folder> --target package_tvos_xcframeworkThis produces:
<ExtensionName>.xcframework- A zipped distribution artifact (if configured)
- No manual Xcode project editing
- Deterministic and repeatable
- CI-friendly
- Safe to re-run after every GameMaker export
- Single source of truth for extension code
- Works cleanly for teams
| Target Type | Where You Implement | What You Build |
|---|---|---|
| Android (Java/Kotlin) | Android output folder (../AndroidSource/...) |
No native lib |
| Desktop + Consoles + JNI |
src/ via CMakeLists |
Shared library |
| iOS/tvOS Native mode |
src/ + XCFramework packaging |
XCFramework |
| iOS/tvOS ObjC/Swift modes |
src/ + Xcode dev workflow |
XCFramework (final) |
- ✅ Keep core logic platform-agnostic (
src/native/) - ✅ Use platform folders only for wrappers/entry points
- ✅ Keep
src/CMakeLists.txtclean and explicit - ✅ Always maintain the XCFramework public header list for Apple targets
- ✅ Regenerate often — treat “compile errors after regeneration” as your update checklist
GameMaker 2026