Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin to generate gdextension files. #577

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

samdeane
Copy link
Contributor

@samdeane samdeane commented Oct 17, 2024

This is a proof-of-concept plugin which will generate a .gdextension file for a GodotScript extension.

See #130 for more details.

Motivation

Maintaining the .gdextension file is a bit fiddly. The syntax is obscure and exactly which architectures to fill in for each platform isn't clear.

Also, the current recommended approach of copying the built swift libraries into place inside the bin/ folder is repetitive and error-prone.

It is relatively easy to recompile the library but forget to copy the new version into place. The solution is typically to automate this step, but that requires each user to build some extra tooling to perform this copy whenever they trigger a build.

The .gdextension format supports using a relative or absolute path to a library, which can be outside the root folder of the Godot project. Doing this allows you to specify the actual build location once in the extension file. As long as recompiling the extension puts it into the same place, it will always be picked up next time you run.

A plugin can solve this problem by writing the correct entries in the .gdextension file for you. The exact entries it writes can be based on the platform you are building for. The entries can be written as paths relative to the Godot project root, allowing you to commit the file to source control as long as you can ensure that the libraries are built into the same relative location on each machine (which is quite achievable).

Usage

To use this, cd to your extension root and run:

swift package make-extension --allow-writing-to-package-directory

It will iterate through all library targets.

For each target, it looks for a file <target-name>.gdextension at the root of the package folder. If there isn't one, it makes one from a template.

It then performs a debug build of that target, works out where the build artefacts are, and fills their location into the .gdextension file.

To use this extension file, you sym-link it into your Godot project's bin/ folder.

Limitations

The generated/updated file has a fixed location currently, but it could be specified as a parameter.

We use the plugin host api to perform a build to work out the build location, which is slow. Ideally we could just do something like swift build --show-bin-path but this requires actually shelling out, and it will only work for SPM.
Using the Package API will hopefully report the correct information for Xcode when invoked from there
(update: I've just discovered that Xcode doesn't support the relevant part of the plugin host api anyway 🤦).

The .gdextension file parser is crude. It preserves section order, but not key order, and it doesn't understand multi-line entries, comments, etc, etc. This would need improving, but that probably requires implementing a full parser that mirrors the one in config_file.cpp in the Godot source. We might be able to link into SwiftGodot and use the actual implementation of ConfigFile, but I'm not sure if that will work without additional context.

Alternatives Considered

Build Plugin

A build plugin could create a .gdextension file automatically. This would be preferable to a command plugin in that it would always be invoked as part of the build process, regardless of the IDE or build tool you were using (Xcode, VSCode, swift command line, etc). It would always know the build context (platform, architecture, configuration), and so could update the appropriate entries.

To allow custom entries in the file, the plugin could take another file as input, using the same format, add in or rewrite keys pointing to the libraries, then write it out as a .gdextension file.

To use this you would add this line to your plugin target in your Package.swift:

            plugins: [.plugin(name: "ExtensionBuilderPlugin", package: "SwiftGodot")]

And add an input file (say YourPlugin.gdswift) to your sources. The plugin would process the input file, add in entries for the built libraries, and output it into the resource bundle of the built library.

Limitations

I tried this approach, but there are problems.

The main one is that the sandboxing of build plugins is extreme. They can only create temporary files that become inputs to the build.

This means that the only way to locate the generated .gdextension file is for it to be written into the resource bundle for the built library.

This works fine, but is of limited use since telling Godot where to find the resource bundle is essentially the same problem as telling it where to find the compiled libraries.

@@ -2,6 +2,7 @@
.godot/
.DS_Store
/.build
/.index-build
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swift's VSCode plugin has a background indexing option, which creates this folder.

Package.swift Outdated
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm running swift-format locally, so the whitespace is a bit messed up.
The actual non-whitespace changes are minimal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant