Skip to content

user_impl_workflow

DiasFranciscoA edited this page Feb 12, 2026 · 8 revisions

Implementation 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.


📁 Project Layout (What You Own vs What extgen Owns)

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:

  1. Edit GMIDL → defines the public API
  2. Run extgen → regenerates bindings + project
  3. Implement platform behavior in src/
  4. Build via CMake presets (or via IDE toolchains)

🧠 Platform Detection Helpers (CMake)

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.


🍏 iOS / tvOS XCFramework Headers (Required)

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-xcframework requires a headers folder. extgen collects these files into that folder during packaging.


✅ Workflow by Target


🤖 Android (Java & Kotlin modes)

What gets generated

  • No C/C++ library build
  • Pure Java/Kotlin glue code emitted into the target output folder (default: ../AndroidSource/...)

What you implement

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.

Why this is good

  • 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.


🖥️ Native Targets (Desktop + Consoles + JNI + Apple Native)

This applies to:

  • ✅ Windows
  • ✅ macOS
  • ✅ Linux
  • ✅ Xbox
  • ✅ PS4 / PS5
  • ✅ Switch
  • ✅ Android (JNI mode)
  • ✅ iOS/tvOS (Native mode)

Where you implement

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)

What you change

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})

Build output behavior

  • 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 / tvOS (ObjC and Swift modes) — Recommended Dev Workflow

This is the most “IDE-assisted” workflow because you often want:

  • Xcode autocomplete & debugging
  • Real-device testing
  • A workflow that builds inside the GameMaker iOS pipeline

This approach keeps everything editable in VS Code, but testable in Xcode.


✅ Recommended Workflow (macOS)

1) Run extgen

Generate the project from GMIDL:

extgen --config config.json

2) Configure CMake (do not build)

Use your preset and run configure only.

This generates an Xcode project for the extension (or other Apple project files depending on your setup).

3) Build your GameMaker iOS project (suppress run)

From GameMaker, build iOS with “Suppress Run” enabled.

✅ This generates the Xcode workspace/project for the game.

4) Open the GameMaker-generated Xcode workspace

You should now be in Xcode with the game project.

5) Add the extgen extension Xcode project into the workspace

In Xcode:

  • Right click the workspace / project navigator
  • Add Files to…
  • Select the Xcode project generated by extgen for your extension

✅ Now your extension project is visible alongside the game.

6) Link the extension library into the game target

In Xcode:

  • Select the game target
  • Go to General
  • Under Frameworks, Libraries, and Embedded Content
  • Click +
  • Add your extension static library target

✅ Now the game links your extension during iOS builds.


🔥 Why this workflow is ideal

  • You can iterate rapidly using Xcode + real device debugging
  • Your extension sources remain in your repo and are editable in VS Code
  • When you’re done, you can still use extgen + CMake to package the final XCFramework

📦 Final Packaging (XCFramework)

Once the implementation is done:

  • Run the CMake build preset that triggers:

    • package_ios_xcframework
    • package_tvos_xcframework

This produces the final .xcframework (and zip if configured).


✅ Summary Table

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)

🧠 Best Practices

  • ✅ Keep core logic platform-agnostic (src/native/)
  • ✅ Use platform folders only for wrappers/entry points
  • ✅ Keep src/CMakeLists.txt clean and explicit
  • ✅ Always maintain the XCFramework public header list for Apple targets
  • ✅ Regenerate often — treat “compile errors after regeneration” as your update checklist

Clone this wiki locally