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