A barebones Godot 4 project with a Swift GDExtension, powered by SwiftGodot.
Repo root vs Godot project folder
Run make commands from this repo root, where the Makefile lives. Open GodotProject/ in Godot; it is the Godot project folder inside the larger SwiftGodot template repo.
Create a new project
Use the scaffold script from this template repo:
scripts/create_project.sh --name MySwiftProject --dest ../MySwiftProject
cd ../MySwiftProject
make
make verify
open MySwiftProject.xcodeprojIn Xcode, select the shared MySwiftProject-Godot scheme and press Cmd-R to build the Swift extension, prepare a debug-signed Godot copy, and run the Godot project under Xcode's debugger.
If Xcode completion, symbol search, or option-click docs look incomplete after a fresh checkout, select the MySwiftProject Swift package scheme and build it once, then switch back to MySwiftProject-Godot.
See TEMPLATE_USAGE.md for more scaffold options, including creating a project from an explicit local template path or git URL.
Xcode project layout
godot-swift/
├── MyExtension.xcodeproj # Xcode wrapper plus Swift package reference
├── .gitignore # Ignored Swift, Godot, Xcode, and profiling output
└── SwiftExtension/ # Swift Package (your extension code)
├── Package.swift
└── Sources/MyExtension/
└── MyExtension.swift # SpinningCube demo node
GodotProject/ still exists on disk and is the folder you open in Godot, but it is intentionally not listed in the Xcode navigator. Generated projects keep the same .gitignore, so SwiftPM build folders, copied dylibs, Godot editor caches, Xcode user state, .DS_Store, and *.profraw profiling files stay out of source control. The Xcode project intentionally focuses on the Swift package, tests, scripts, and docs; edit Godot scenes and project files from Godot itself.
Requirements
- Godot 4.6 has been verified with this project. SwiftGodot's upstream README currently describes Godot 4.4 support, so prefer the version recorded in
GodotProject/project.godotunless you are intentionally testing another Godot release. - Xcode / Swift toolchain. This repo was verified with Swift 6.3.1, while the extension package itself declares Swift tools 5.9.
Build and run this project
1. Build the Swift extension
make # debug build # or make release # optimised build
This compiles the Swift package and copies libMyExtension.dylib into GodotProject/bin/.
The build also copies SwiftGodot's runtime dylib, libSwiftGodot.dylib, which libMyExtension.dylib loads at runtime.
Build output is quiet by default; use make VERBOSE=1 to show the full SwiftPM output.
The first build can still take a while because SwiftPM compiles SwiftGodot, SwiftSyntax, macros, and generated Godot bindings. Generated projects do not copy .build; SwiftPM will reuse its normal dependency caches where it safely can.
The Makefile uses SWIFT_BIN to pick a Swift CLI, preferring ~/Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin/swift or Swiftly's ~/.swiftly/bin/swift when available. Run make toolchain to see the selected compiler, or pass SWIFT_BIN=/path/to/swift if needed.
After building, you can verify that the copied dylibs and GDExtension metadata agree:
make verify
make verify also checks GodotProject/.godot/extension_list.cfg, which is intentionally kept in the repo so Godot loads MyExtension.gdextension from a clean checkout. Other .godot editor/cache files remain ignored.
make doctor is also available as an alias for make verify.
To list the available Makefile commands:
make helpTo remove only the copied dylibs from GodotProject/bin/ without clearing SwiftPM's build cache:
make clean-bin
To open the project with the default macOS Godot app path:
make open
If Godot is installed somewhere else, pass its executable path:
make open GODOT_BIN=/path/to/Godot
Xcode workflow
Open MyExtension.xcodeproj in Xcode. The project references SwiftExtension/ as a local Swift package so Xcode has a real SwiftPM graph for indexing, completion, symbol search, and option-click documentation.
Use the shared MyExtension-Godot scheme for running the game:
- Cmd-B runs the external build target, which invokes
make debug verify. - Cmd-R builds, runs
make prepare-xcode-run, and launches the Godot project through Xcode's LLDB launcher. - Cmd-U runs the native
MyExtensionTestsXCTest target without running the Godot Makefile target first.
After a fresh checkout, package reset, or DerivedData clear, select the MyExtension Swift package scheme and build it once. That lets Xcode run SwiftGodot's package plugins and generate the API surface SourceKit needs for indexing. Then switch back to MyExtension-Godot for normal Godot debugging.
make prepare-xcode-run copies /Applications/Godot.app into /private/tmp/MyExtension-Godot.app, signs that copy with godot-debug.entitlements, and links /private/tmp/MyExtension-GodotProject back to this repo's GodotProject/. The normal /Applications/Godot.app remains untouched.
The shared Xcode scheme uses those stable /private/tmp paths because Xcode's LLDB launcher does not reliably expand project-relative paths in the executable field.
The external target deliberately keeps the Makefile as the source of truth for the Swift toolchain instead of inheriting Xcode's build environment.
2. Open the Godot project
Open GodotProject/ in Godot 4. Godot will automatically load MyExtension.gdextension and register the SpinningCube node type.
3. Use your Swift node
In any 3D scene, add a child node and search for SpinningCube — it will appear under Node3D. It will create a spinning box at runtime.
Adding your own Swift nodes
- Create a new Swift file under
SwiftExtension/Sources/MyExtension/. - Annotate your class with
@Godotand subclass a Godot base type. - Add the new type to the
#initSwiftExtensioncall inMyExtension.swift. - Run
make, optionally runmake verify, and restart/reload the Godot editor.
Rebuilding without restarting Godot
Use Project > Reload Current Project in the Godot editor after running make to pick up the updated library.
Debugging in Xcode
Xcode can attach its debugger to a running Godot process so you can set Swift breakpoints in your extension. The Makefile also includes terminal LLDB helpers if you prefer a command-line debugger.
One-time setup: re-sign Godot
The official Godot binary is signed without the com.apple.security.get-task-allow entitlement, which macOS requires before an external debugger can attach. The Xcode workflow's make prepare-xcode-run target signs a copied Godot app under /private/tmp/, so you usually do not need to modify /Applications/Godot.app.
If you prefer to attach Xcode to your normal installed Godot app, re-sign it once with an ad-hoc signature that includes that entitlement:
# Clear any Gatekeeper quarantine flags first xattr -cr /Applications/Godot.app # Re-sign with the debug entitlement codesign \ --sign - \ --entitlements godot-debug.entitlements \ --force \ --deep \ /Applications/Godot.app
The godot-debug.entitlements file in the repo root contains the required entitlement. You will need to repeat this step after every Godot update.
Fix incomplete indexing in Xcode
Xcode's indexer needs to build the local Swift package scheme before it can fully resolve SwiftGodot's generated API:
- Open
MyExtension.xcodeproj. - Select the
MyExtensionSwift package scheme. - Build with Cmd-B.
- Open the Issue Navigator (Cmd-5). At the bottom you may see a prompt to Trust & Enable the SwiftGodot macro/plugin. Click it; Xcode may ask you to do this twice.
- Switch back to the
MyExtension-Godotscheme for Godot debugging.
Once the package scheme has built, symbol search, completion, option-click docs, and "Cannot find X in scope" errors should settle down.
Running tests in Xcode
Use Cmd-U on the MyExtension-Godot scheme to run the native MyExtensionTests XCTest target. That target links the local Swift package product and uses the same test sources as make test, but the Godot Makefile target is intentionally disabled for the Test action so Xcode does not build or launch Godot just to run unit tests.
From the terminal, you can run the same Swift package tests with:
make testAttaching to a running game
- Run
maketo build the debug.dylib. - Open
GodotProject/in Godot and press Run (F5). - In Xcode, open
MyExtension.xcodeproj. - Set any breakpoints you want in your Swift source files.
- In the menu bar choose Debug › Attach to Process by PID or Name…, type
Godot, and click Attach.
Xcode will attach to the Godot process and stop at your Swift breakpoints.
Debugging with LLDB from Make
For command-line debugging, you can launch Godot under LLDB:
make debug-run
At the LLDB prompt, type:
run
Or attach LLDB to an already-running Godot process:
make debug-attach
Use either make debug-run or make debug-attach, not both. debug-run launches Godot under LLDB from the start; debug-attach attaches to a Godot process you already started.
make debug-attach builds first, verifies the copied dylibs, and then runs lldb -n Godot. If your Godot process uses a different name, pass it with GODOT_PROCESS:
make debug-attach GODOT_PROCESS=Godot
These targets use terminal LLDB, not Xcode's GUI debugger. Breakpoints set in Xcode do not automatically carry over to terminal LLDB. To use Xcode breakpoints in Xcode, use Debug > Attach to Process by PID or Name... as described above.
Project notes
See PROJECT_CONTEXT.md for the current debugging notes, known setup decisions, and fixes discovered while getting this project running. See TEMPLATE_USAGE.md for instructions on using this repo as a starter for a new SwiftGodot project.