As part of the Kotlin Build Tools team at JetBrains, we’ve been exploring how to integrate Kotlin/Native directly into Swift Build. Swift Build is the build execution system used by Xcode and Swift Package Manager (SwiftPM) across Swift, Objective-C, C/C++, and other components of the Apple toolchain.
Our prototype extends Swift Build with initial support for the Kotlin/Native compiler, kotlinc-native, allowing Swift Build to compile Kotlin targets and expose the resulting artifacts to Swift targets as dependencies. This enables Swift targets to import and use Kotlin code, much like how Swift can import Objective-C code in Xcode or SwiftPM.
The Kotlin/Native compiler takes Kotlin sources and produces Kotlin/Native libraries, .klib intermediate artifacts. When Kotlin targets depend on one another, their corresponding .klib files are passed through the build graph, so that each Kotlin target can see and use its dependencies during compilation.
When a Swift target depends on one or more Kotlin targets, Swift Build collects all relevant .klib files and invokes the Kotlin/Native compiler again to translate them into a single .framework file. It contains headers and binaries that Swift code can import, enabling cross-language integration.
The prototype supports:
- Detecting Kotlin sources in a target.
- Compiling them into
.kliblibraries. - Passing
.kliboutputs through Kotlin-to-Kotlin dependencies. - Generating a single
.frameworkfile that Swift can import and link against.
Kotlin Multiplatform (KMP) libraries are most commonly built with Gradle. To support SwiftPM build and distribution, we convert such KMP libraries into SwiftPM-compatible packages with a custom Gradle task that generates a Sources layout and a Package.swift manifest containing the required Kotlin/Native compiler options.
Quickstart
We have already implemented some SwiftPM packages and an Xcode project. Some of the SwiftPM packages are even converted from KMP projects. Please see the following examples and run the commands given to open the projects in Xcode using Swift Build with Kotlin integration:
- Git clone the repo : kotlin-swift-build.
- Setup the Kotlin/Native Toolchain, check the Kotlin/Native toolchain section.
- Change directory to clone repo root.
Here are some samples; you can run the commands from repository root:
// to open in Xcode
swift package --disable-sandbox launch-xcode --project-path KotlinSamples/SwiftPackage
// to build directly from terminal
swift package --disable-sandbox run-xcodebuild -- \
-workspace KotlinSamples/SwiftPackage/.swiftpm/xcode/package.xcworkspace \
-scheme SwiftPackage \
-configuration Debug \
-destination 'platform=macOS' \
KOTLINC_NATIVE_PATH="<YourAbsolutePathToKotlinCNativeExecutable>" \
build
// to open in Xcode
swift package --disable-sandbox launch-xcode --project-path KotlinSamples/ConversionSample
// to build directly from terminal
swift package --disable-sandbox run-xcodebuild -- \
-workspace KotlinSamples/ConversionSample/.swiftpm/xcode/package.xcworkspace \
-scheme ConversionSample \
-configuration Debug \
-destination 'platform=macOS' \
KOTLINC_NATIVE_PATH="<YourAbsolutePathToKotlinCNativeExecutable>" \
build
// to open in Xcode
swift package --disable-sandbox launch-xcode --project-path KotlinSamples/KotlinSwiftXCodeProject
// to build directly from terminal
swift package --disable-sandbox run-xcodebuild -- \
-project KotlinSamples/KotlinSwiftXCodeProject/KotlinSwiftXCodeProject.xcodeproj \
-scheme swiftConsumer \
KOTLINC_NATIVE_PATH="<YourAbsolutePathToKotlinCNativeExecutable>" \
build
// to open in Xcode
swift package --disable-sandbox launch-xcode --project-path KotlinSamples/kotlin-nsurl-session
// to build directly from terminal
swift package --disable-sandbox run-xcodebuild -- \
-workspace KotlinSamples/kotlin-nsurl-session/.swiftpm/xcode/package.xcworkspace \
-scheme kotlin_nsurl_session \
-configuration Debug \
-destination 'platform=macOS' \
KOTLINC_NATIVE_PATH="<YourAbsolutePathToKotlinCNativeExecutable>" \
build
Prototype implementation
NOTE: The current implementation supports only single-target-triple builds. Building for multiple architectures will result in a “Duplicate Task” exception.
Let’s review the structure of the prototype and highlight open integration points.
You can also check out our fork of Swift Build, including all the changes, at kotlin-swift-build.
To learn more about the added tools and changes, you can also check the open merge request.
Configuring the Kotlin/Native Toolchain
A built-in macro is introduced:
KOTLINC_NATIVE_PATH
KOTLINC_NATIVE_PATH is evaluated via:
MacroEvaluationScope.evaluateAsString(BuiltinMacros.KOTLINC_NATIVE_PATH)
This value is currently hard-coded and should eventually be detected dynamically.
Compiling Kotlin targets
A new KlibCompilerSpec task compiles all .kt files in a target into a .klib artifact. For Xcode-defined targets, this works out of the box. You can add .kt files to the Kotlin target and write Kotlin code as you would in any IDE. This distinction is important because the same workflow does not work out of the box in a SwiftPM setup.
Kotlin-to-Kotlin Dependency Resolution and .klib Propagation
When Kotlin targets depend on one another, Swift Build must ensure that the compiled Kotlin outputs (.klib files) are passed through the build graph, allowing each Kotlin target to see and use APIs of its dependencies during compilation.
In our prototype, each Kotlin target declares its generated .klib as the output of the KlibCompilerSpec task. During the compilation of another Kotlin target, Swift Build examines the target’s dependencies, identifies which of them are Kotlin targets, reconstructs the expected output locations of their .klib files, and supplies these .klib files as inputs to the dependent target’s Kotlin/Native compilation.
This mechanism ensures that Kotlin dependencies are available to the Kotlin/Native compiler exactly when needed. The resulting .klib files are also used during framework generation, where Swift Build invokes the Kotlin/Native compiler again to produce the final .framework file imported by Swift code.
Support for Kotlin compilation in SwiftPM
SwiftPM does not pass source files directly to the build system. Instead, it converts them into a Package Intermediate Format (PIF), which Xcode and Swift Build use to construct the build graph. During this conversion, SwiftPM classifies files strictly by known language extensions, such as .swift or .c/.cpp. However, it has no concept of .kt files, as a result:
.ktfiles never appear in the target’s source list.- Swift Build never receives them as inputs.
- Kotlin-specific tool specs cannot see or compile them.
Since PIF is the only source description that Swift Build receives from SwiftPM, Kotlin sources must appear under a recognized extension to be propagated through the pipeline.
To make SwiftPM include Kotlin sources in its PIF, we represent Kotlin source files in the package as .kt.swift files:
<file>.kt → <file>.kt.swift
This causes SwiftPM to treat these files as Swift sources and include them in the PIF. Once they reach Swift Build:
- They are routed to
SwiftCompilerthanks to the.swift-like extension. SwiftCompilerfilters them out, preventing Swift compilation.- The files are restored to their original
.ktform insideTARGET_TEMP_DIR. KlibCompilerSpecreceives the restored.ktfiles and compiles them as Kotlin sources.
This workaround enables Kotlin compilation within the existing SwiftPM → PIF → Swift Build pipeline. However, it’s not ideal, as it relies on SwiftPM misclassifying Kotlin sources as Swift files. Proper support would require SwiftPM to:
- Recognize
.ktas a valid source type. - Expose Kotlin sources through the PIF model directly.
Suppressing linker tasks for Kotlin targets
Kotlin targets are not linked using the standard Swift/C/C++ linker pipeline. Kotlin-to-Kotlin linkage is performed by the Kotlin/Native compiler itself using .klib inputs, while a generated .framework performs Swift-to-Kotlin linkage.
For pure Kotlin targets, the regular Swift/C/C++ linkers are not applicable. On Apple platforms, Swift and C/C++ targets are linked by ld the platform linker, which relies on search paths, system frameworks, and auto-linking metadata. Kotlin/Native instead expects a dedicated invocation of the Kotlin/Native compiler with an explicit list of .klib files and does not participate in this platform linker model. To avoid producing incorrect or redundant link actions for Kotlin targets, SourcesTaskProducer.generateTasks returns early when .kt sources are detected, suppressing the creation of Swift/C/C++ linker tasks for those targets.
For Swift targets that depend on Kotlin targets, we still use the standard Swift linker, but adjust the link file list so that it does not try to link individual Kotlin targets or their outputs directly. Instead of adding per-target Kotlin artifacts to the link file list, we later add a single generated .framework (produced by the Kotlin-specific tooling) and let the Swift linker link against that framework only.
Generating .framework automatically
Let’s see how the unified framework is produced and wired into the Swift target.
To make Kotlin code usable from Swift, Kotlin targets are packaged into a .framework. This is performed by a dedicated tool spec, Klib2FrameworkTool, using the following command:
kotlinc-native -p framework
NOTE: Current implementation supports only a single KotlinWorld.framework per final executable or dynamic product. A single Swift target may aggregate any number of Kotlin targets into one KotlinWorld.
In Xcode projects, if multiple dynamic targets (for example, frameworks or executables) that depend on Kotlin targets are built as part of the same build graph, Swift Build will attempt to generate more than one KotlinWorld framework. This is currently not supported.
The same limitation applies to SwiftPM-based builds. If multiple executable or dynamic library products depending on Kotlin targets are built in the same build, multiple KotlinWorld frameworks would be generated and this can end up:
- Failing the build, for example, with multiple commands producing the
KotlinWorld.framework. - Succeeding with inconsistent symbol mappings due to global Kotlin/Native name translation.
The Klib2FrameworkTool spec:
- Collects all Kotlin dependencies of the Swift target.
- Resolves the
.kliboutputs of those dependencies. - Invokes the Kotlin/Native compiler with the complete set of
.klibinputs, producing a unifiedKotlinWorld.framework.
Although Klib2FrameworkTool receives both direct and transitive Kotlin dependencies during framework generation, the Swift target is only intended to be exposed to the APIs of its direct Kotlin dependencies. The generated framework internally contains all Kotlin dependencies, but Swift imports only what is made visible through those direct Kotlin targets. This design behaves correctly for Xcode-defined targets.
However, when building SwiftPM packages, we observed that dependency flattening occurs at the PIF level. For the following chain:
S (SwiftTarget) → K1 (KotlinTarget) → K2 (KotlinTarget)
The PIF produced by swift package dump-pif lists both K1 and K2 as dependencies of S, even though S declares only K1 as a direct dependency in Package.swift. In effect, SwiftPM surfaces transitive Kotlin dependencies as if they were direct dependencies of the Swift target.
This behaviour is clearly visible in the PIF. The Swift product dependencies and its frameworks build phase include entries for both K1 and K2. Consequently, Swift Build treats all reachable Kotlin targets in the dependency graph as direct inputs to the Swift target.
Due to this flattening, our framework-generation logic must currently expose the APIs of transitive Kotlin dependencies when running under SwiftPM as well, even though semantically, only the direct Kotlin dependency should have been visible to the Swift target.
Phase 1. Compilation with SwiftCompiler
Swift Build runs Klib2FrameworkTool with:
omitBinary = true
In this mode, the Kotlin/Native compiler generates headers, module maps etc. but no binary.
This is primarily a performance optimization. Machine code generation is the most expensive stage of the Kotlin/Native compilation pipeline and is unnecessary for the consuming Swift code.
The generated framework is added to the Swift compiler’s search paths so the Swift target can import:
import KotlinWorld
Phase 2. Linking with LdLinkerSpec
Later in the build graph, Swift Build invokes Klib2FrameworkTool again, this time with the full binary generation enabled. The Kotlin/Native compiler performs hermetic linkage over all the collected .klib files and produces a final fully linked KotlinWorld.framework file containing the compiled Kotlin binaries.
This framework is then passed to the ld platform linker as a standard framework dependency, and the Swift target links against it.
Converting Kotlin to SwiftPM with a Gradle task
A Gradle task transforms a KMP module into a SwiftPM package by:
- Generating
Sources/<module>/<sourceSet>/withkt.swiftsymlinks. - Computing the Kotlin/Native compiler configuration derived from:
- Source sets
- Fragment definitions and refinements relationships (
-Xfragments,-Xfragment-refines, and so on)
In Gradle, Kotlin/Native compiler arguments and the source sets are target-specific and depend on the active Apple target, for example, ios_simulator_arm64 or macos_arm64. To reproduce the same compilation model under SwiftPM, these arguments are serialized into Package.swift file, so that Swift Build can reconstruct the correct Kotlin/Native invocation per architecture.
Instead of embedding a single flat compiler string, the conversion task emits a structured representation via cSettings:
cSettings: [
.define("KOTLINC_NATIVE_ARCH_ARGS", to: "{ ... }"), // JSON: kotlinc-native Target -> fragment flags
.define("KOTLINC_NATIVE_ARCH_SOURCES", to: "{ ... }"), // JSON: source -> allowed kotlinc-native targets
.define("KOTLINC_NATIVE_COMMON_ARGS", to: "[ ... ]") // JSON: shared compiler flags
]
In kotlin-swift-build, KlibCompilerSpec reads these values from GCC_PREPROCESSOR_DEFINITIONS and:
- Determines the active Kotlin/Native target from the current build environment.
- Selects the corresponding entry from
KOTLINC_NATIVE_ARCH_ARGS. - Appends
KOTLINC_NATIVE_COMMON_ARGS. - Filters source inputs using
KOTLINC_NATIVE_ARCH_SOURCESwhen necessary. - Forwards the reconstructed argument set to
kotlinc-native.
This approach preserves Kotlin Multiplatform’s target-specific compilation semantics while maintaining deterministic Package.swift.
Here are some examples that we converted:
How to use
Set up the environment
1. Clone our Swift Build prototype
Clone our modified implementation of Swift Build:
git clone https://github.com/Kotlin/kotlin-swift-build
2. Kotlin/Native toolchain
2.1 Provision Kotlin/Native (kotlinc-native) with Gradle (How to get Kotlin/Native toolchain)
The recommended way to provision the Kotlin/Native compiler for Swift Build is to use the Gradle task provided by the Kotlin samples in this repository. This ensures that a compatible Kotlin/Native distribution is downloaded and installed locally.
// Navigate to the kotlin-swift-build repository root
cd <path-to-kotlin-swift-build>
// Navigate to a Kotlin sample that provides Gradle setup
cd KotlinSamples/ConversionSample
// Download and prepare the Kotlin/Native distribution
./gradlew commonizeNativeDistribution
After the task completes, return to the repository root and verify that the Kotlin/Native distribution was installed:
// Navigate back to repository fork
cd <path-to-kotlin-swift-build>
// List all installed Kotlin/Native distributions
ls -ld "$HOME/.konan/kotlin-native-prebuilt-"*
This command will print one or more directories such as:
~/.konan/kotlin-native-prebuilt-macos-aarch64-2.2.21
~/.konan/kotlin-native-prebuilt-macos-x86_64-2.2.21
Note the paths aside for the next step where you override KOTLINC_NATIVE_PATH.
When overriding KOTLINC_NATIVE_PATH, point it to the kotlinc-native executable, eg. it should look like following:
KOTLINC_NATIVE_PATH = ~/.konan/kotlin-native-prebuilt-macos-aarch64-2.2.21/bin/kotlinc-native
2.2 Providing Kotlin/Native toolchain into Swift Build (How to make Swift Build consume Kotlin/Native toolchain)
There are two alternative ways to provide a Kotlin/Native toolchain to Swift Build.
Option 1. Use the expected default path (no code changes required)
Install Kotlin/Native 2.2.21 under the path assumed by the built-in macros:
$HOME/.konan/kotlin-native-prebuilt-macos-aarch64-2.2.21/bin/kotlinc-native
Option 2. Override KOTLINC_NATIVE_PATH
Static Override in macro table
You may provide custom toolchain locations by defining the macros manually in Swift Build.
To do this, navigate to kotlin-swift-build/Sources/SWBCore/Settings/Settings.swift and update the getKotlinCNativeSettingsTable() function:
func getKotlinCNativeSettingsTable() -> MacroValueAssignmentTable{
var kotlinCNativeTable = MacroValueAssignmentTable(namespace: core.specRegistry.internalMacroNamespace)
kotlinCNativeTable.push(
BuiltinMacros.KOTLINC_NATIVE_PATH,
Static{BuiltinMacros.namespace.parseString("$(HOME)/.konan/kotlin-native-prebuilt-macos-aarch64-2.2.21/bin/kotlinc-native")
})
return kotlinCNativeTable
}
Swift Build will resolve KOTLINC_NATIVE_PATH from this macro table for all Kotlin-related specs.
Dynamic Override
When building Xcode projects through Swift Build, the macros can also be overridden via build settings passed to the run-xcodebuild command plugin.
// For Xcode projects
swift package --disable-sandbox run-xcodebuild -- \
-project <YourProject>.xcodeproj \
-scheme <YourScheme> \
KOTLINC_NATIVE_PATH="<YourAbsolutePathToKotlinCNativeExecutable>" \
build
// For SwiftPM packages
swift package --disable-sandbox run-xcodebuild -- \
-workspace <YourPackage>/.swiftpm/xcode/package.xcworkspace \
-scheme SwiftPackage \
-configuration Debug \
-destination 'platform=macOS' \
KOTLINC_NATIVE_PATH="<YourAbsolutePathToKotlinCNativeExecutable>" \
build
Run Xcode with the modified Build System
You can test the modified Swift Build directly in Xcode. In the root directory of the kotlin-swift-build, run:
swift package --disable-sandbox launch-xcode
This launches the currently selected Xcode.app with the modified Swift Build instance instead of the Build System Service.
Building a Xcode Project
- Open an existing Xcode project.
- Add a new Framework target for your Kotlin code.
- Add
.ktfiles directly (do not use the.kt.swiftworkaround used for SwiftPM). - Navigate to Project Navigator → Your Kotlin Framework Target → Build Phases → Compile Sources and add your
.ktfiles. - Select the Swift target that should depend on Kotlin. Go to Build Phases → Target Dependencies and add your Kotlin framework target.
- In your Swift target, import the generated framework:
import KotlinWorld - Call Kotlin APIs as needed and build the Swift target. You will see the Kotlin-related compiler and framework logs in the build output.
Build a SwiftPM Project
- Create a new SwiftPM package or open an existing one.
- Under
Sources, create directories for the Kotlin targets, for example:Sources/ ├── KotlinTarget1/ //import KotlinTarget2 code in KotlinTarget1 ├── KotlinTarget2/ - Inside these directories, create Kotlin files using the
.kt.swiftextension, for example,MyFile.kt.swift. - Define the Kotlin target in
Package.swiftfile:// Package.swift targets: [ .target( name: "KotlinTarget2", path: "Sources/KotlinTarget2" ), .target( name: "KotlinTarget1", path: "Sources/KotlinTarget1", dependencies: [ .target(name: "KotlinTarget2") ], ), ] - Add the Kotlin target as a dependency of a Swift target:
// Package.swift targets: [ .target( name: "KotlinTarget2", path: "Sources/KotlinTarget2" ), .target( name: "KotlinTarget1", path: "Sources/KotlinTarget1", dependencies: [ .target(name: "KotlinTarget2") ], ), .target( name: "SwiftTarget", dependencies: [ .target(name: "KotlinTarget") //transitively depends on KotlinTarget2 ], path: "Sources/SwiftTarget" ) ]
NOTE: SwiftPM builds flatten dependencies within a package. For example, in the SwiftTarget → KotlinTarget1 → KotlinTarget2 chain, SwiftPM surfaces both KotlinTarget1 and KotlinTarget2 as direct dependencies of SwiftTarget.
- In the Swift target, import the Kotlin framework
KotlinWorld.framework:import KotlinWorld - Call Kotlin-exposed APIs from Swift.
- (Optional) You can also create a macOS Swift executable, depend on the Kotlin target, and run it to validate end-to-end behavior.
- (Optional) Use a remote SwiftPM Kotlin dependency:
- Add the remote dependency in your
Package.swift:// Package.swift dependencies: [ .package( url: "https://github.com/abdulowork/kotlinx-io-fork-for-swift-build", exact: "0.9.0-swiftpm-SNAPSHOT.3" ) ] -
- Import and use
KotlinWorld:
- Import and use
// main.swift import KotlinWorld let buf = Buffer() // from kotlinx-io-fork-for-swift-build buf.writeInt(int: 64) ... - Add the remote dependency in your
Open Questions and Suggested Improvements
The current implementation of our Swift Build prototype leaves room for improvement and raises some integration questions.
Kotlin/Native Code Generation Model vs Target-Based Build
SwiftPM and Xcode target models, as used for Swift and Objective-C, assume that each target or package (the producer) compiles and emits its own machine code artifact, which is later consumed and linked by downstream targets. The producer does not need to know who will consume its output.
Kotlin/Native differs from this model. In the current integration, machine code can only be generated once all consumers of Kotlin code are known, because Kotlin/Native performs final code generation and linkage across the full dependency set. As a result, machine code is effectively produced at the consumer level rather than by individual Kotlin targets.
This raises an open design question for Swift Build:
- What is the right way to model Kotlin/Native compilation in Swift Build?
Toolchain Resolution
The current implementation relies on hard-coded KOTLINC_NATIVE_PATH.
In contrast to Swift, Kotlin/Native toolchains are not typically discovered from local installations. In the Kotlin ecosystem, the Kotlin version determines the compiler distribution, which is then downloaded and cached automatically (for example, by Gradle).
Open questions here are:
- How does Swift Build discover the Swift compiler toolchain?
- Is there an established mechanism for registering or discovering third-party compilers?
- Does Swift Build support resolving, downloading, and caching external toolchains based on a declared version rather than discovering preinstalled ones?
- Are there existing examples of version-driven toolchain resolution for non-Swift compilers (for example Android NDK support)?
Overriding KOTLINC_NATIVE_PATH in SwiftPM Contexts
Within Xcode projects, the developer can override toolchain-related build settings, such as providing a custom KOTLINC_NATIVE_PATH through Xcode Build Settings.
For SwiftPM packages, such overrides are also possible when building via xcodebuild, by passing build settings on the command line, for example:
xcodebuild -scheme SwiftPMProduct KOTLINC_NATIVE_PATH=/custom/path/to/kotlinc-native
However, there is currently no way to express these overrides in Package.swift itself.
This raises the question of whether it’s feasible for SwiftPM to allow passing such overrides through the Package manifest, for example:
//Package.swift
.kotlinCNativeToolchain(
version: "2.2.21",
path: "/custom/path/to/kotlinc-native"
)
Inclusion of .kt files into Kotlin to SwiftPM conversion
The workaround of defining Kotlin sources as .kt.swift files, so that SwiftPM emits them into the PIF, is suboptimal. Open questions here are:
- Can SwiftPM be extended to pass
.ktfiles directly to the build system without the.kt.swiftworkaround? - Is there an extension point in SwiftPM for defining new source types?
Custom Kotlin-Specific Settings in Package.swift
A natural extension would be allowing SwiftPM to define new configuration domains, similar to cSettings.
An open question here is whether SwiftPM can define keys for custom settings.
For example, for kmpSettings they could be:
//Package.swift
.target(
name: "KMPTarget",
kmpSettings: [
.define("-Xfragments", to: "..."),
.define("-Xfragment-refines", to: "..."),
.define("-Xfragment-sources", to: "...")
]
)
- If yes, what might be the best way to do it? And how could these settings be fetched from Swift Build?
- If not, what would be your suggestion?
A higher-level KMP DSL in Package.swift
In Gradle, Kotlin Multiplatform avoids raw compiler options by exposing structured concepts such as commonMain, iosMain, macosMain through dependsOn refinement rules.
From these, Gradle automatically derives:
- Fragment relationships
- Compilation order
- All required
-Xfragment*options - Library wiring
This reduces developer overhead and eliminates a major source of configuration errors.
A similar higher-level DSL in SwiftPM would remove the need for long, fragile compiler options and make KMP usage significantly easier.
For example, a basic SwiftPM DSL could look like:
//Package.swift
.kmpTarget(
name: "KMPTarget",
sourceSets: [
.common("Sources/KMPTarget/commonMain"),
.ios("Sources/KMPTarget/iosMain"),
.macOS("Sources/KMPTarget/macosMain")
]
)
Such a DSL would allow SwiftPM to:
- Model KMP source sets and refinements directly.
- Derive all fragment options automatically.
- Pass structured metadata to Swift Build rather than opaque strings.
- Simplify the KMP → SwiftPM conversion.
Open questions here are:
- Can SwiftPM support a new DSL domain (for example,
kmpTarget) for modeling source sets and refinements? - What mechanism would allow Package.swift to define these settings, manifest extension?
Using a Custom SwiftPM and Swift Build Together
Both .kt inclusion and fragment flag propagation require enhancements to SwiftPM.
This raises a broader question of whether it’s feasible to integrate a custom SwiftPM with a custom Swift Build inside Xcode.
Swift Build Plugins
We are also evaluating whether parts of this integration could be re-implemented as a Swift Build plugin. Open questions here are:
- What is the recommended approach for implementing third-party compiler integrations using Swift Build plugins?
- Are there known limitations that would prevent Kotlin/Native from being integrated solely through plugins?
