Skip to content

[godot] Fix various issues with GDExtension on Apple platforms#2768

Merged
badlogic merged 1 commit intoEsotericSoftware:4.2from
mihe:apple-fixes
May 5, 2025
Merged

[godot] Fix various issues with GDExtension on Apple platforms#2768
badlogic merged 1 commit intoEsotericSoftware:4.2from
mihe:apple-fixes

Conversation

@mihe
Copy link
Contributor

@mihe mihe commented Feb 27, 2025

Forgive the issue(s) and PR rolled into one, but there are a number of issues with the GDExtension builds for Apple platforms currently, which this PR tries to address.

I realize there's a lot to unpack here. This all started out as trying to figure out why the iOS builds weren't working when using the spine-godot GDExtension, and very much snowballed from there, unfortunately.

macOS

  • When exporting a macOS build, you're currently shown a warning informing you that there was no Info.plist present in this extension and that one was generated automatically instead.
    • Godot tries to accommodate for extensions that are distributed as just raw shared libraries (as opposed to Framework bundles) and automatically bundle them into Framework bundles, along with a generated Resources/Info.plist, which serves as a manifest of sorts. However, this should ideally be done by the extension author instead.
    • To resolve this, I've included generation of an Info.plist (using SCons env.Substfile) that matches the format that Godot itself uses, just as a starting point.
  • The template_debug and template_release binaries were added into the same Framework bundles, which isn't correct, as the Framework bundles are effectively what are meant to be the shared libraries, so needs to host one binary per bundle instead.
    • To resolve this, I changed the output paths for macos builds to result in a 1-to-1 mapping of Framework bundles and binaries.
  • The [libraries] entries for macOS in the *.gdextension file were referencing the binaries within the Framework bundles, which isn't entirely correct, for the reasons mentioned above, and also needed to be changed to accommodate for the Info.plist, which otherwise wouldn't be found on export.
    • To resolve this, I changed the [libraries] entries to reference the Framework bundles instead.
  • This is more nitpicky, but the builds for macOS, found in spine-godot/build/build-extension.sh, were manually building for both arm64 and x86_64 and combining them into universal binaries with lipo. This is already done for you by the default arch=universal.
    • To resolve this, I removed all the macos-specific building and just let it rely on the default case instead.

iOS

  • As mentioned, the iOS builds didn't seem to work at all, as the iOS builds were being built as shared libraries (as seen here) but then renamed to be static library *.a files (as seen here) and put into XCFramework bundles, which can't be linked against when Xcode builds the app.
    • The approach of using XCFramework to begin with (which I believe I suggested to @badlogic a few months back) is somewhat flawed (as it turns out) as you must also build and bundle an XCFramework of godot-cpp, to satisfy that link-time dependency, and then declare that dependency as part of your *.gdextension file (like this). However, this means that if you as the end-user rely on multiple GDExtensions, you'll almost certainly end up with collisions and/or binary incompatibilities between their different godot-cpp libraries, which can't be resolved without building every GDExtension from source and modifying them to reference the same godot-cpp XCFramework.
    • It is however technically possible to build multiple regular Framework bundles instead, one that targets simulator builds and one that doesn't, and then use the simulator feature tag in the *.gdextension file to load the appropriate one, similar to how threaded and non-threaded web builds are loaded.
    • But... The iOS simulator builds in Godot are being phased out due to fundamental incompatibilities between the iOS simulator and the Vulkan and Metal renderers, and just generally not being great for use with games, which means that not only are any benefits of XCFramework bundles over regular Framework bundles more or less gone, but the argument for distributing simulation binaries at all is somewhat questionable.
    • So, to resolve this, I've changed the iOS builds to produce regular Framework bundles instead that only target device builds of Godot, and not simulator builds.
  • As a result of using regular Framework bundles, you need to provide an install_name (a search path) to the linker, otherwise you'll get a dynamic linker error at runtime when you try to launch an iOS app that uses the extension.
    • Godot does this for you automatically (seen here) using the install_name_tool found on macOS, in the case where you only distribute *.dylib files for iOS.
    • To resolve this, I've added -Wl,-install_name,@rpath/... as linker arguments when building, which achieves the same effect as what Godot does with install_name_tool.
    • Note that this is done for macos builds as well, but I don't believe it's necessary there, but doesn't seem to cause any problems either way.
  • As a result of using regular Framework bundles, there needs to be an Info.plist alongside the binary, same as with macOS, so I added generation of that for iOS as well, which matches the format that Godot generates for you when you only distribute *.dylib files for iOS.

General

  • This technically applies to all platforms, but the *.gdextension file was using absolute resource paths when referencing the different libraries, which isn't strictly necessary, and restricts where the end-user can put the GDExtension in their project. It's possible to use relative paths instead.
    • To resolve this, I changed all the paths to be relative to the *.gdextension file instead.

I've tested all this with both the 4.2 branch of godot-cpp, as well as the 4.3 branch, and both seemed to work when used with Godot 4.4-rc2. However, when rebasing in some of the later changes to spine-runtimes 4.2 branch (5d23a7d...268d0e8) the 4.2 branch of godot-cpp started crashing as soon as you start the editor.

@badlogic
Copy link
Collaborator

badlogic commented May 5, 2025

@mihe thank you so much for this work! All your issue resolutions make sense. For the Info.plist files, we'll stick to the minimal format you've added to this PR. I'll think about how we best derive the version string.

However, when rebasing in some of the later changes to spine-runtimes 4.2 branch (5d23a7d...268d0e8) the 4.2 branch of godot-cpp started crashing as soon as you start the editor.

I will investigate. I'm aware of the editor crashing on exit, but have not seen it crash on start-up.

@badlogic badlogic merged commit 15b96b3 into EsotericSoftware:4.2 May 5, 2025
@badlogic
Copy link
Collaborator

badlogic commented May 5, 2025

I've now tested this on both macOS and iOS, works as intended. I have added a simple mechanism that fetches the major.minor from the git branch name to be included in the Info.plist, which will work for our infra, but might not work in forks.

I can still see the crash on editor exit, but I can not reproduce a crash on start-up as you reported. If you could open an issue with repro steps I'd be much obliged.

@mihe mihe deleted the apple-fixes branch May 5, 2025 15:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants