Reducing the size of SwiftGodot #741
Replies: 2 comments
-
|
I have now a proof-of-concept that follows up on the work in So the solution was to split thing up in physical directories, each one with their own Package.swift to prevent Swift's build system from attempting the above. Here are the steps: Baseline
For each module
Re-export the API at the toplevel
Entry Point
Update Code Generator
The only downside is that making whole-sale changes that used to be limited to the toplevel Package.swift are now spread out to ten different places. |
Beta Was this translation helpful? Give feedback.
-
|
The core split has now been merged |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hello folks,
TLDR: New
barebone-splitbransh introduces a new SwiftPM targets that brings the bare minimum of SwiftGodot (the new "SwiftGodotRuntime") to at 1.5MB in release mode when statically linking or 3.8Mb as a dynamic library.I could use your help, let me know if this version works for you or if this causes any problems, below are more details.
Background
SwiftGodot today is a large library as it surfaces strongly typed APIs for the entire Godot API surface and it is available either as a dynamic library (which is quick during development as you do not need to relink) or static library (which is great for deployment as you an remove unnecessary code).
The API surface is problematic in terms of build time and library size. Today, the library in debug mode would produce extensions that would be about 23 megs in size when statically linked or a dynamic library that is 113 megs in size and I have been exploring a few options to trim it.
The above are debug build results which are about 2x the size of a release build.
I have experimented with various options to reduce the size and wanted to give folks an update on the investigations and where I think we are going.
Linker Reduction Efforts
This relates to SwiftGodot in its current form, my effort was to try to find a way to reduce the size of a plugin that links with SwiftGodot's static library as much as possible.
I am aware that there is a problem with "Linking too much" into SwiftGodot due to keeping a dictionary with all known types. It turns out that this is not strictly necessary and can be solved (as shown in 38aade8 - this patch contained both this change and other changes, so I had to revert the change, as the
getBindingsize optimization that was bundled into that change was not complete, revert took place in e937884)This particular direction reduces the library's Debug build from 23 megs to 18 megs. Some of the additional code that is kept around I believe is an oversight in Swift that is probably easy to fix (they are flagging all the types as 'keep around', which brings all the virtual methods, which ends up bringing a lot of additional unnecessary code). You can see the discussion here: https://forums.swift.org/t/how-do-i-put-my-swift-libraries-on-a-diet/82785 and in particular: https://forums.swift.org/t/why-nominal-type-descriptors-are-always-marked-no-dead-strip/77252/13
That should further bring down static builds from 18megs to something smaller.
Reducing SwiftGodot itself
I have attempted two separate approaches:
Using Swift Package traits to request a specific profile of SwiftGodot (branch
traits-sizes), while this works, the support in Xcode for it is not great today.Splitting SwiftGodot into multiple libraries.
Using Package Traits
I stopped working on the traits approach about a month ago, but I could take it back up.
Splitting SwiftGodot into Multiple Libraries
The SwiftGodot split looked a lot more promising, the idea was to split SwiftGodot into pieces:
The branch
splitcontains the above implementation, and it looks great on paper, but it has one problem: SwiftPM sadly decides that if you have a dependency on another library, that it will make a copy of the entire library into the new library. This means that SwiftGodot2D that depends on SwiftGodotRuntime and SwiftGodotCore gets a copy of those two, and so does SwiftGodot3D. This is sort of ok, until you try to use both SwiftGodot2D and SwiftGodog3D, as each of them will have their own copies of shared functions and shared data to talk to Godot.This is a known problem in SwiftPM, you can see a discussion on the subject and I am not sure how to proceed until that is fixed (You can see how to crash Xcode and SwiftPM in the
split-crashbranch).Simple SwiftGodotRuntime split
Given the above roadblock, but also the desire to help people that want to use SwiftGodot not for its rich API support of Godot, but merely to interoperate with Apple's APIs and Godot, I have created a smaller effort that rather than having the beautiful split above, it provides two libraries: SwiftGodotRuntime like the above that you can use if you merely want to interop with Godot and SwiftGodot (as it stands today).
The above produces a libSwiftGodot.dylib that is 8.9 megs in size in debug mode and 3.7 megs in size in release mode and the build time if you merely depend on it is quite good.
The above lives in the
barebone-splitbranch and I would love for people to test if this works for them, in particular if they use the full versionSwiftGodot- to make sure I did not regress anything accidentally.To use this, make sure that you reference the
barebone-splitbranch:And if you just want to use the core binding, reference the
SwiftGodotRuntimepackage, like this:For static builds, use:
The static build is where I could use your help, I am using a flag called "-conditional-runtime-records" that disables the forced inclusion of types that are not referenced, this brings the size from 8.9 megs down to 2.6 megs in debug mode and from 3.9megs to 1.5 megs
A sample project shows how to statically link to get a small binary.
Next Steps
There are a few things worth exploring:
split-crash) which would give us the nice dynamic library split during development.barebone-splitBeta Was this translation helpful? Give feedback.
All reactions