Some of this is covered under the "Goals" section in Evolving SwiftPM Builds with Swift Build, but to give a few more examples of benefits:
-
First class support for cross-compilation - as Jake mentioned in Evolving SwiftPM Builds with Swift Build - #11 by jakepetroules, Swift Build essentially treats every target as a cross compilation target. Baking this constraint into the build system at a low-level has important correctness benefits, and means that support for new platforms can be added in a largely data-driven manner. We've received a PR from @kateinoigakukun already to add WebAssembly support, which I think demonstrates this modularity well: Sign in to GitHub ยท GitHub. As a bonus, I think this is also a major stepping stone towards first-class support for Swift SDKs.
-
A more flexible intermediate representation. Swift Build has very flexible abstractions for defining new build configuration options and product types, for things like compiler and linker settings, libraries, apps, and more. I think there are a lot of opportunities to think about how we could evolve the Package.swift manifest format to take advantage of this flexibility.
-
More dynamic build rules for Swift. Like SwiftPM's current build system, part of Swift Build's planning process involves generating a static graph of tasks. Unlike the current build system however, Swift Build also has the concept of dynamic task graphs which can be spliced into that static task graph, leading to more of a hybrid model. This has enabled us to integrate with the compiler more effectively using tools like the SwiftDriver library to schedule tasks more efficiently and leverage more detailed knowledge of Swift's compilation model to implement optimizations that aren't possible when we treat the compile of each module as a black box. One example of this - Swift Build will prioritize the emission of a target's swiftmodule over the object files. This allows it to begin compiling dependents of that module before the objects are all finished compiling, which can be a major speedup in heavily modularized projects. This category of optimization is much harder to do in SwiftPM's current build system without a substantial rework of how it constructs the build graph. It's also an area with a lot of opportunity for further work, IMO. For example, it lays some of the foundations to begin looking at interleaving build planning with build execution and unlock more gains.
It's hard to draw a precise analogy to other build systems, but I think a good way of thinking about this is:
-
SwiftPM remains the user facing component developers interact. When building, it interacts with Swift Build's build service to lower Package.swift to the PIF intermediate representation, and sends it a build request.
-
Swift Build is responsible for accepting a PIF and a build request, planning a build using the PIF, builtin rules, and user-provided rules.
-
Swift Build then executes that build graph in coordination with LLBuild