From 5548a42e9859110d82286878b552de24b081d94a Mon Sep 17 00:00:00 2001 From: Kharkunov Eugene Date: Wed, 4 Nov 2026 12:38:41 +0200 Subject: [PATCH 1/9] Add manual for Swift sources in native extensions Describes how to put .swift files into the src folder of an extension for iOS and macOS, call them from Objective-C++ through the generated -Swift.h header, use a bridging header and Swift packages from Swift, and set the swiftFlags of the ext.manifest. --- docs/en/en.json | 4 + docs/en/manuals/extensions-ext-manifests.md | 1 + docs/en/manuals/extensions-swift.md | 176 ++++++++++++++++++++ docs/en/manuals/extensions.md | 2 +- 4 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 docs/en/manuals/extensions-swift.md diff --git a/docs/en/en.json b/docs/en/en.json index ef17ae0a..393dfe74 100644 --- a/docs/en/en.json +++ b/docs/en/en.json @@ -2074,6 +2074,10 @@ "path": "/manuals/extensions-spm", "name": "Swift Package Manager dependencies" }, + { + "path": "/manuals/extensions-swift", + "name": "Swift in native extensions" + }, { "path": "/manuals/extensions-script-api", "name": "Adding auto-complete definition" diff --git a/docs/en/manuals/extensions-ext-manifests.md b/docs/en/manuals/extensions-ext-manifests.md index ae15267e..77656775 100644 --- a/docs/en/manuals/extensions-ext-manifests.md +++ b/docs/en/manuals/extensions-ext-manifests.md @@ -67,6 +67,7 @@ Allowed keys are for platform specific compile flags are: * `linkFlags` - Flags that should be passed to the linker * `libs` - Additional libraries to include when linking * `defines` - Defines to set when building +* `swiftFlags` - Flags that should be passed to the Swift compiler (iOS and macOS). Only a fixed set of flags is allowed, see [Swift in native extensions](/manuals/extensions-swift#compiler-options). * `aaptExtraPackages` - Extra package name that should be generated (Android) * `aaptExcludePackages` - Regexp (or exact names) of packages to exclude (Android) * `aaptExcludeResourceDirs` - Regexp (or exact names) of resource directories to exclude (Android) diff --git a/docs/en/manuals/extensions-swift.md b/docs/en/manuals/extensions-swift.md new file mode 100644 index 00000000..0031bfff --- /dev/null +++ b/docs/en/manuals/extensions-swift.md @@ -0,0 +1,176 @@ +--- +title: Using Swift in iOS and macOS native extensions +brief: This manual explains how to write the code of a native extension in Swift for iOS and macOS builds. +--- + +# Swift in native extensions + +Many Apple APIs, such as StoreKit 2 or CryptoKit, are only available from Swift. A native extension can include its own Swift source files next to its Objective-C++ files. The build server compiles them together with the rest of the extension and links the result into the engine. This is separate from [Swift packages](/manuals/extensions-spm) and [CocoaPods](/manuals/extensions-cocoapods), which provide ready-made dependencies. + +Swift code is compiled for macOS (`arm64` and `x86_64`) and for iOS (devices and the simulator). Swift files are ignored when building for other platforms. + + +## Adding Swift sources + +Put the `.swift` files in the `src` folder of the extension, next to the C++ and Objective-C++ files: + +``` +myextension/ +├── ext.manifest +└── src/ + ├── myextension.mm + └── Greeter.swift +``` + +Swift files in `commonsrc` or `pluginsrc` are not supported and fail the build. + +All Swift files of an extension are compiled together as one Swift module. The name of the module is the `name` from `ext.manifest`, where every character other than a letter, a digit or an underscore is replaced with `_` (`My-Extension` becomes `My_Extension`). The Swift language mode is Swift 5. + + +## Calling Swift from Objective-C++ + +The entry point of an extension is still a C++ function registered with `DM_DECLARE_EXTENSION`, so an extension needs at least one `.cpp` or `.mm` file. Swift is called from this file through the generated `-Swift.h` header. + +Only classes, protocols and methods marked with `@objc` are visible from Objective-C. Mark the classes `public` and derive them from `NSObject`: + +`src/Greeter.swift`: + +```swift +import Foundation + +@objc(MyExtensionGreeter) +public class Greeter: NSObject { + @objc public func message() -> String { + return "Hello from Swift" + } +} +``` + +`src/myextension.mm`: + +```cpp +#include + +#if defined(DM_PLATFORM_IOS) || defined(DM_PLATFORM_OSX) +#import +#import "MyExtension-Swift.h" +#endif + +static dmExtension::Result AppInitializeMyExtension(dmExtension::AppParams* params) +{ +#if defined(DM_PLATFORM_IOS) || defined(DM_PLATFORM_OSX) + MyExtensionGreeter* greeter = [[MyExtensionGreeter alloc] init]; + dmLogInfo("%s", [[greeter message] UTF8String]); +#endif + return dmExtension::RESULT_OK; +} + +DM_DECLARE_EXTENSION(MyExtension, "MyExtension", AppInitializeMyExtension, 0, 0, 0, 0, 0) +``` + +* The generated header imports `Foundation`. Types from other frameworks are only forward declared in it. Import the header of the framework (for example `UIKit`) in the `.mm` file before you call methods that use those types. +* `throws` functions are exposed as methods with an `NSError **` parameter, and `async` functions as methods with a completion handler. +* Swift-only features, such as generics, enums with associated values and structs, are not visible from Objective-C. Wrap them in an `@objc` class. +* Guard the include with `DM_PLATFORM_IOS` or `DM_PLATFORM_OSX`, as the header only exists when building for these platforms. + + +## Calling Objective-C from Swift + +To use Objective-C or C declarations from Swift, add a bridging header named `-Bridging-Header.h` to the `src` folder, for example `src/MyExtension-Bridging-Header.h`: + +```cpp +#import "mynative.h" +``` + +If the header exists, it is imported into the Swift module automatically. Headers it includes are searched in the `include` folder of the extension and in the folders added with `-I` in `swiftFlags` (see below). + +Apple frameworks, such as `Foundation`, `UIKit` or `StoreKit`, are imported from Swift with a normal `import`. The frameworks listed in `frameworks` and `weakFrameworks` of the `ext.manifest` are linked as usual. Most system frameworks are linked automatically when the Swift code imports them. + + +## Using Swift packages from Swift + +The products of the [Swift packages](/manuals/extensions-spm) that the extension declares in `SwiftPackages.json` are available to its Swift code. Import the module in a Swift file: + +```swift +import Foundation +import Sentry + +@objc(MyExtensionCrashReporter) +public class CrashReporter: NSObject { + @objc public func start(dsn: String) { + SentrySDK.start { options in + options.dsn = dsn + } + } +} +``` + +The Objective-C headers of a package can be imported in the bridging header, in the same way as from an `.mm` file: + +`src/MyExtension-Bridging-Header.h`: + +```cpp +#import +``` + +Declare the package in the `SwiftPackages.json` of the extension that uses it. The build server builds the packages first and then the Swift code of the extension. CocoaPods dependencies are not yet available from Swift code, use them from the Objective-C++ file. + + +## Compiler options + +Options for the Swift compiler are set in the `ext.manifest` file, in the same `context` as the options for the C++ compiler: + +```yaml +name: MyExtension + +platforms: + ios: + context: + defines: ["MY_DEFINE"] + swiftFlags: ["-strict-concurrency=complete", "-I", "include"] + osx: + context: + defines: ["MY_DEFINE"] +``` + +* `defines` - The defines set for C++ are passed to Swift as conditional compilation names, so `#if MY_DEFINE` works in Swift. The value of a define, such as `MY_DEFINE=1`, is dropped, as Swift only supports names. +* `swiftFlags` - Additional flags for the Swift compiler. Each flag and each value is a separate list item. The flags are filtered by an allow list, and all other flags fail the build with an `Invalid flag - 'swiftFlags'` error. The allowed flags are: + * `-enable-upcoming-feature ` - Enable an upcoming language feature, for example `["-enable-upcoming-feature", "ExistentialAny"]`. + * `-strict-concurrency=minimal|targeted|complete` + * `-enforce-exclusivity=checked|unchecked` + * `-O`, `-Osize` and `-Onone` - The optimization level. The default is `-O`. + * `-suppress-warnings` + * `-I ` and `-F ` - Add a folder that is searched for headers and modules, or for frameworks. The flag and its path are two separate list items, and the path is relative to the extension folder and must stay inside of it. + +The `swiftFlags` of the `ios` platform apply to both devices and the simulator. A build server that predates Swift support rejects the `swiftFlags` key with a `Manifest context variable unsupported` error, and the project then fails to build until the Defold version and the build server are updated. + + +## Minimum OS versions + +The Swift runtime is not included in the application. It is loaded from the operating system, and the Swift code is built for the minimum iOS and macOS versions the engine supports. Use an `#available` check before calling APIs that are newer than that. + + +## Limitations + +* An extension still needs a C++ or Objective-C++ file with `DM_DECLARE_EXTENSION`. Swift code cannot yet register the extension or call the Defold SDK (`dmsdk`) itself. A build with only `.swift` files fails to link with an undefined symbol error named after the extension. +* Swift code can use [Swift packages](/manuals/extensions-spm), but not CocoaPods dependencies. Use pods from the Objective-C++ file and pass what is needed to the Swift code. +* Only the Swift 5 language mode is supported. C++ interoperability is not enabled. +* Swift sources are supported by Defold versions that include this feature. A build server with an older SDK fails with a `Swift sources are not supported by this Defold SDK version` error. + + +## Troubleshooting + +`no such module 'Name'` +: The module is not a product of a package declared in a `SwiftPackages.json`. Check that `products` lists a product that provides the module, as described in the [Swift Package Manager manual](/manuals/extensions-spm). + +`Swift sources are only supported in the 'src' folder` +: Move the `.swift` files into the `src` folder of the extension. + +`'MyExtension-Swift.h' file not found` +: The module name is built from `name` in `ext.manifest`. Check the name in the `#import` line, and that the class is marked `public` and `@objc`. + +`Undefined symbols ... _MyExtension` +: The extension has no `DM_DECLARE_EXTENSION`. Add a `.mm` file that registers the extension as described above. + +`Invalid flag - 'swiftFlags'` +: The flag is not on the allow list. Remove it or use one of the listed flags. diff --git a/docs/en/manuals/extensions.md b/docs/en/manuals/extensions.md index 9b897906..fc4b9126 100644 --- a/docs/en/manuals/extensions.md +++ b/docs/en/manuals/extensions.md @@ -50,7 +50,7 @@ To create a new extension, create a folder in the project root. This folder will : The extension folder _must_ contain an *ext.manifest* file. This file is a configuration file with flags and defines used when building a single extension. File format definition can be found in the [Extension Manifest manual](https://defold.com/manuals/extensions-ext-manifests/). *src* -: This folder should contain all source code files. +: This folder should contain all source code files. Swift files (`.swift`) for iOS and macOS also go here, see [Swift in native extensions](/manuals/extensions-swift). *include* : This optional folder contains any include files. From 7c291315b08eec96e22c67b54bd00d5e3c412dd0 Mon Sep 17 00:00:00 2001 From: Kharkunov Eugene Date: Wed, 4 Nov 2026 12:59:38 +0200 Subject: [PATCH 2/9] Document the Swift include and framework path keys The paths are set with additionalSwiftIncludePaths and additionalFrameworkSearchPaths in the extension manifest instead of -I and -F in swiftFlags. --- docs/en/manuals/extensions-ext-manifests.md | 1 + docs/en/manuals/extensions-swift.md | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/en/manuals/extensions-ext-manifests.md b/docs/en/manuals/extensions-ext-manifests.md index 77656775..6b2c0216 100644 --- a/docs/en/manuals/extensions-ext-manifests.md +++ b/docs/en/manuals/extensions-ext-manifests.md @@ -68,6 +68,7 @@ Allowed keys are for platform specific compile flags are: * `libs` - Additional libraries to include when linking * `defines` - Defines to set when building * `swiftFlags` - Flags that should be passed to the Swift compiler (iOS and macOS). Only a fixed set of flags is allowed, see [Swift in native extensions](/manuals/extensions-swift#compiler-options). +* `additionalSwiftIncludePaths`, `additionalFrameworkSearchPaths` - Folders in the extension that the Swift compiler searches for headers, modules and frameworks (iOS and macOS), see [Swift in native extensions](/manuals/extensions-swift#compiler-options). * `aaptExtraPackages` - Extra package name that should be generated (Android) * `aaptExcludePackages` - Regexp (or exact names) of packages to exclude (Android) * `aaptExcludeResourceDirs` - Regexp (or exact names) of resource directories to exclude (Android) diff --git a/docs/en/manuals/extensions-swift.md b/docs/en/manuals/extensions-swift.md index 0031bfff..3a446fee 100644 --- a/docs/en/manuals/extensions-swift.md +++ b/docs/en/manuals/extensions-swift.md @@ -82,7 +82,7 @@ To use Objective-C or C declarations from Swift, add a bridging header named `` and `-F ` - Add a folder that is searched for headers and modules, or for frameworks. The flag and its path are two separate list items, and the path is relative to the extension folder and must stay inside of it. +* `additionalSwiftIncludePaths` - Folders that the Swift compiler searches for headers and modules, in addition to the `include` folder of the extension. +* `additionalFrameworkSearchPaths` - Folders that the Swift compiler searches for frameworks, in addition to the `lib/` folder of the extension. -The `swiftFlags` of the `ios` platform apply to both devices and the simulator. A build server that predates Swift support rejects the `swiftFlags` key with a `Manifest context variable unsupported` error, and the project then fails to build until the Defold version and the build server are updated. +The paths are relative to the extension folder, must stay inside of it, and may only contain letters, digits and `._+-/`. + +The Swift keys of the `ios` platform apply to both devices and the simulator. A build server that predates Swift support rejects them with a `Manifest context variable unsupported` error, and the project then fails to build until the Defold version and the build server are updated. ## Minimum OS versions From 095e66978c8c3c6b04da7e8a8d62da1a8bfc76b4 Mon Sep 17 00:00:00 2001 From: Kharkunov Eugene Date: Wed, 4 Nov 2026 14:05:34 +0200 Subject: [PATCH 3/9] Describe additionalFrameworkSearchPaths as a general key --- docs/en/manuals/extensions-ext-manifests.md | 3 ++- docs/en/manuals/extensions-swift.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/en/manuals/extensions-ext-manifests.md b/docs/en/manuals/extensions-ext-manifests.md index 6b2c0216..017037bc 100644 --- a/docs/en/manuals/extensions-ext-manifests.md +++ b/docs/en/manuals/extensions-ext-manifests.md @@ -68,7 +68,8 @@ Allowed keys are for platform specific compile flags are: * `libs` - Additional libraries to include when linking * `defines` - Defines to set when building * `swiftFlags` - Flags that should be passed to the Swift compiler (iOS and macOS). Only a fixed set of flags is allowed, see [Swift in native extensions](/manuals/extensions-swift#compiler-options). -* `additionalSwiftIncludePaths`, `additionalFrameworkSearchPaths` - Folders in the extension that the Swift compiler searches for headers, modules and frameworks (iOS and macOS), see [Swift in native extensions](/manuals/extensions-swift#compiler-options). +* `additionalSwiftIncludePaths` - Folders in the extension that the Swift compiler searches for headers and modules (iOS and macOS), see [Swift in native extensions](/manuals/extensions-swift#compiler-options). +* `additionalFrameworkSearchPaths` - Folders in the extension that are searched for frameworks when compiling and linking the extension (iOS and macOS), see [Swift in native extensions](/manuals/extensions-swift#compiler-options). * `aaptExtraPackages` - Extra package name that should be generated (Android) * `aaptExcludePackages` - Regexp (or exact names) of packages to exclude (Android) * `aaptExcludeResourceDirs` - Regexp (or exact names) of resource directories to exclude (Android) diff --git a/docs/en/manuals/extensions-swift.md b/docs/en/manuals/extensions-swift.md index 3a446fee..bb228c8d 100644 --- a/docs/en/manuals/extensions-swift.md +++ b/docs/en/manuals/extensions-swift.md @@ -143,7 +143,7 @@ platforms: * `-O`, `-Osize` and `-Onone` - The optimization level. The default is `-O`. * `-suppress-warnings` * `additionalSwiftIncludePaths` - Folders that the Swift compiler searches for headers and modules, in addition to the `include` folder of the extension. -* `additionalFrameworkSearchPaths` - Folders that the Swift compiler searches for frameworks, in addition to the `lib/` folder of the extension. +* `additionalFrameworkSearchPaths` - Folders that are searched for frameworks, in addition to the `lib/` folder of the extension. This is not specific to Swift: the folders are used by the Swift compiler, by the C++ and Objective-C++ compiler for the sources of the extension, and by the linker. The paths are relative to the extension folder, must stay inside of it, and may only contain letters, digits and `._+-/`. From 54cef65e74b395eb5937276ac4638452818e1807 Mon Sep 17 00:00:00 2001 From: Kharkunov Eugene Date: Wed, 4 Nov 2026 16:28:15 +0200 Subject: [PATCH 4/9] Describe the Swift runtime libraries for older minimum OS versions --- docs/en/manuals/extensions-swift.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/en/manuals/extensions-swift.md b/docs/en/manuals/extensions-swift.md index bb228c8d..1a72f2ab 100644 --- a/docs/en/manuals/extensions-swift.md +++ b/docs/en/manuals/extensions-swift.md @@ -152,7 +152,11 @@ The Swift keys of the `ios` platform apply to both devices and the simulator. A ## Minimum OS versions -The Swift runtime is not included in the application. It is loaded from the operating system, and the Swift code is built for the minimum iOS and macOS versions the engine supports. Use an `#available` check before calling APIs that are newer than that. +The Swift runtime is part of iOS 12.2 and later and of macOS 10.14.4 and later. The Swift code is built for the minimum iOS and macOS versions that the engine supports, and the application uses the Swift runtime of the operating system. Use an `#available` check before calling APIs that are newer than the minimum version. + +A few parts of the runtime are part of the operating system only from a later version. For example, Swift concurrency (`async`, `await` and `Task`) is part of iOS 15 and macOS 12, and `Span` is part of iOS 26 and macOS 26. If the minimum version is older and your Swift code uses such a feature, the application needs an extra library to run on those devices. You don't have to do anything for this: the build server finds the libraries that the engine uses, as Xcode does, and adds them to the application. On iOS they are placed in the `Frameworks` folder of the application and are signed together with the rest of its code. + +The minimum versions are set by the Defold version and the build server, not by the project. ## Limitations @@ -179,3 +183,6 @@ The Swift runtime is not included in the application. It is loaded from the oper `Invalid flag - 'swiftFlags'` : The flag is not on the allow list. Remove it or use one of the listed flags. + +`Swift sources are not supported for this minimum OS version` +: The build targets an iOS or macOS version older than iOS 12.2 or macOS 10.14.4, which have no Swift runtime. Use a Defold version with a newer minimum OS version, or remove the Swift sources. From d8053cff278804da7572ae98ed4474d794b5da95 Mon Sep 17 00:00:00 2001 From: Kharkunov Eugene Date: Wed, 4 Nov 2026 16:32:12 +0200 Subject: [PATCH 5/9] Leave Span out of the list of back-deployed Swift features --- docs/en/manuals/extensions-swift.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/manuals/extensions-swift.md b/docs/en/manuals/extensions-swift.md index 1a72f2ab..9378b7ee 100644 --- a/docs/en/manuals/extensions-swift.md +++ b/docs/en/manuals/extensions-swift.md @@ -154,7 +154,7 @@ The Swift keys of the `ios` platform apply to both devices and the simulator. A The Swift runtime is part of iOS 12.2 and later and of macOS 10.14.4 and later. The Swift code is built for the minimum iOS and macOS versions that the engine supports, and the application uses the Swift runtime of the operating system. Use an `#available` check before calling APIs that are newer than the minimum version. -A few parts of the runtime are part of the operating system only from a later version. For example, Swift concurrency (`async`, `await` and `Task`) is part of iOS 15 and macOS 12, and `Span` is part of iOS 26 and macOS 26. If the minimum version is older and your Swift code uses such a feature, the application needs an extra library to run on those devices. You don't have to do anything for this: the build server finds the libraries that the engine uses, as Xcode does, and adds them to the application. On iOS they are placed in the `Frameworks` folder of the application and are signed together with the rest of its code. +A few parts of the runtime are part of the operating system only from a later version. For example, Swift concurrency (`async`, `await` and `Task`) is part of iOS 15 and macOS 12. If the minimum version is older and your Swift code uses such a feature, the application needs an extra library to run on those devices. You don't have to do anything for this: the build server finds the libraries that the engine uses, as Xcode does, and adds them to the application. On iOS they are placed in the `Frameworks` folder of the application and are signed together with the rest of its code. The minimum versions are set by the Defold version and the build server, not by the project. From 3d8af48a5d77ef3fe4bdc3b49b6b4b8071460892 Mon Sep 17 00:00:00 2001 From: Kharkunov Eugene Date: Wed, 4 Nov 2026 20:50:15 +0200 Subject: [PATCH 6/9] Correct the Swift manual on minimum versions, module names and other platforms The minimum version can be raised by a package, the module name must differ from the imported modules, an extension with only .mm and .swift files doesn't build for other platforms, and the library artifact has no Swift. Also list both errors for swiftFlags values and separate the troubleshooting entries. --- docs/en/manuals/extensions-swift.md | 31 ++++++++++++++++++----------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/docs/en/manuals/extensions-swift.md b/docs/en/manuals/extensions-swift.md index 9378b7ee..7c69e939 100644 --- a/docs/en/manuals/extensions-swift.md +++ b/docs/en/manuals/extensions-swift.md @@ -22,10 +22,12 @@ myextension/ └── Greeter.swift ``` -Swift files in `commonsrc` or `pluginsrc` are not supported and fail the build. +Keep all Swift files in `src`. A macOS or iOS build fails if it finds a Swift file in `commonsrc` or `pluginsrc`. All Swift files of an extension are compiled together as one Swift module. The name of the module is the `name` from `ext.manifest`, where every character other than a letter, a digit or an underscore is replaced with `_` (`My-Extension` becomes `My_Extension`). The Swift language mode is Swift 5. +The name of the module must differ from the modules that the code imports. An extension named `StoreKit` can't `import StoreKit`, as the compiler takes the import for the module itself. + ## Calling Swift from Objective-C++ @@ -50,18 +52,13 @@ public class Greeter: NSObject { ```cpp #include - -#if defined(DM_PLATFORM_IOS) || defined(DM_PLATFORM_OSX) #import #import "MyExtension-Swift.h" -#endif static dmExtension::Result AppInitializeMyExtension(dmExtension::AppParams* params) { -#if defined(DM_PLATFORM_IOS) || defined(DM_PLATFORM_OSX) MyExtensionGreeter* greeter = [[MyExtensionGreeter alloc] init]; dmLogInfo("%s", [[greeter message] UTF8String]); -#endif return dmExtension::RESULT_OK; } @@ -71,7 +68,7 @@ DM_DECLARE_EXTENSION(MyExtension, "MyExtension", AppInitializeMyExtension, 0, 0, * The generated header imports `Foundation`. Types from other frameworks are only forward declared in it. Import the header of the framework (for example `UIKit`) in the `.mm` file before you call methods that use those types. * `throws` functions are exposed as methods with an `NSError **` parameter, and `async` functions as methods with a completion handler. * Swift-only features, such as generics, enums with associated values and structs, are not visible from Objective-C. Wrap them in an `@objc` class. -* Guard the include with `DM_PLATFORM_IOS` or `DM_PLATFORM_OSX`, as the header only exists when building for these platforms. +* `.mm` files are only compiled for iOS and macOS, so an extension with only `.mm` and `.swift` files fails on other platforms with `Extension has no source!`. To also build the extension for other platforms, put `DM_DECLARE_EXTENSION` in a `.cpp` file and call the `.mm` file from it inside a `DM_PLATFORM_IOS` or `DM_PLATFORM_OSX` guard. ## Calling Objective-C from Swift @@ -113,7 +110,7 @@ The Objective-C headers of a package can be imported in the bridging header, in #import ``` -Declare the package in the `SwiftPackages.json` of the extension that uses it. The build server builds the packages first and then the Swift code of the extension. CocoaPods dependencies are not yet available from Swift code, use them from the Objective-C++ file. +Declare the package in the `SwiftPackages.json` of the extension that uses it. The build server builds the packages first and then the Swift code of the extension. If a package needs a newer OS than the minimum version of the engine, set it as `minVersion` in the `SwiftPackages.json`, and the Swift code of the extension is built for that version too. CocoaPods dependencies are not yet available from Swift code, use them from the Objective-C++ file. ## Compiler options @@ -136,7 +133,7 @@ platforms: ``` * `defines` - The defines set for C++ are passed to Swift as conditional compilation names, so `#if MY_DEFINE` works in Swift. The value of a define, such as `MY_DEFINE=1`, is dropped, as Swift only supports names. -* `swiftFlags` - Additional flags for the Swift compiler. Each flag and each value is a separate list item. The flags are filtered by an allow list, and all other flags fail the build with an `Invalid flag - 'swiftFlags'` error. The allowed flags are: +* `swiftFlags` - Additional flags for the Swift compiler. Each flag and each value is a separate list item. The flags are filtered by an allow list, and all other flags fail the build with an `Invalid flag - 'swiftFlags'` error. A value with whitespace, a backslash or template syntax, or one that names a response file, fails with an `invalid 'swiftFlags' value` error instead. The allowed flags are: * `-enable-upcoming-feature ` - Enable an upcoming language feature, for example `["-enable-upcoming-feature", "ExistentialAny"]`. * `-strict-concurrency=minimal|targeted|complete` * `-enforce-exclusivity=checked|unchecked` @@ -152,11 +149,11 @@ The Swift keys of the `ios` platform apply to both devices and the simulator. A ## Minimum OS versions -The Swift runtime is part of iOS 12.2 and later and of macOS 10.14.4 and later. The Swift code is built for the minimum iOS and macOS versions that the engine supports, and the application uses the Swift runtime of the operating system. Use an `#available` check before calling APIs that are newer than the minimum version. +The Swift runtime is part of iOS 12.2 and later and of macOS 10.14.4 and later. The Swift code is built for the minimum iOS or macOS version of the build, and the application uses the Swift runtime of the operating system. Use an `#available` check before calling APIs that are newer than the minimum version. A few parts of the runtime are part of the operating system only from a later version. For example, Swift concurrency (`async`, `await` and `Task`) is part of iOS 15 and macOS 12. If the minimum version is older and your Swift code uses such a feature, the application needs an extra library to run on those devices. You don't have to do anything for this: the build server finds the libraries that the engine uses, as Xcode does, and adds them to the application. On iOS they are placed in the `Frameworks` folder of the application and are signed together with the rest of its code. -The minimum versions are set by the Defold version and the build server, not by the project. +The minimum version of a build is the one that the engine supports, which is set by the Defold version and the build server. A `minVersion` in a `SwiftPackages.json` raises it for the packages, the Swift code and the link of the engine, as described in the [Swift Package Manager manual](/manuals/extensions-spm). It can't be lowered. ## Limitations @@ -165,6 +162,7 @@ The minimum versions are set by the Defold version and the build server, not by * Swift code can use [Swift packages](/manuals/extensions-spm), but not CocoaPods dependencies. Use pods from the Objective-C++ file and pass what is needed to the Swift code. * Only the Swift 5 language mode is supported. C++ interoperability is not enabled. * Swift sources are supported by Defold versions that include this feature. A build server with an older SDK fails with a `Swift sources are not supported by this Defold SDK version` error. +* Swift sources are not compiled when building the `library` artifact (`--build-artifacts library` in [Bob](/manuals/bob)), so an Objective-C++ file that imports `-Swift.h` fails to compile there. ## Troubleshooting @@ -176,7 +174,13 @@ The minimum versions are set by the Defold version and the build server, not by : Move the `.swift` files into the `src` folder of the extension. `'MyExtension-Swift.h' file not found` -: The module name is built from `name` in `ext.manifest`. Check the name in the `#import` line, and that the class is marked `public` and `@objc`. +: The module name is built from `name` in `ext.manifest`. Check the name in the `#import` line. + +`unknown type name 'MyExtensionGreeter'` +: The class is missing from the generated header. Check that it is marked `public` and `@objc`, derives from `NSObject`, and that the `.mm` file uses the name from `@objc(...)`. + +`cannot find 'AppStore' in scope` together with `file 'A.swift' is part of module 'StoreKit'; ignoring import` +: The extension has the same name as a module it imports. Rename the extension in `ext.manifest`. `Undefined symbols ... _MyExtension` : The extension has no `DM_DECLARE_EXTENSION`. Add a `.mm` file that registers the extension as described above. @@ -184,5 +188,8 @@ The minimum versions are set by the Defold version and the build server, not by `Invalid flag - 'swiftFlags'` : The flag is not on the allow list. Remove it or use one of the listed flags. +`invalid 'swiftFlags' value` +: The value has whitespace, a backslash or template syntax, or names a response file. Put each flag and each value in its own list item. + `Swift sources are not supported for this minimum OS version` : The build targets an iOS or macOS version older than iOS 12.2 or macOS 10.14.4, which have no Swift runtime. Use a Defold version with a newer minimum OS version, or remove the Swift sources. From 64b3fcae3ddd42512573b78fbf75984c1f78d602 Mon Sep 17 00:00:00 2001 From: Kharkunov Eugene Date: Thu, 5 Nov 2026 12:58:14 +0200 Subject: [PATCH 7/9] Describe CocoaPods dependencies from Swift code as not supported --- docs/en/manuals/extensions-swift.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/manuals/extensions-swift.md b/docs/en/manuals/extensions-swift.md index 7c69e939..9cd527cf 100644 --- a/docs/en/manuals/extensions-swift.md +++ b/docs/en/manuals/extensions-swift.md @@ -110,7 +110,7 @@ The Objective-C headers of a package can be imported in the bridging header, in #import ``` -Declare the package in the `SwiftPackages.json` of the extension that uses it. The build server builds the packages first and then the Swift code of the extension. If a package needs a newer OS than the minimum version of the engine, set it as `minVersion` in the `SwiftPackages.json`, and the Swift code of the extension is built for that version too. CocoaPods dependencies are not yet available from Swift code, use them from the Objective-C++ file. +Declare the package in the `SwiftPackages.json` of the extension that uses it. The build server builds the packages first and then the Swift code of the extension. If a package needs a newer OS than the minimum version of the engine, set it as `minVersion` in the `SwiftPackages.json`, and the Swift code of the extension is built for that version too. Using CocoaPods dependencies from Swift code is not supported. Use them from the Objective-C++ file and pass what is needed to the Swift code. ## Compiler options @@ -159,7 +159,7 @@ The minimum version of a build is the one that the engine supports, which is set ## Limitations * An extension still needs a C++ or Objective-C++ file with `DM_DECLARE_EXTENSION`. Swift code cannot yet register the extension or call the Defold SDK (`dmsdk`) itself. A build with only `.swift` files fails to link with an undefined symbol error named after the extension. -* Swift code can use [Swift packages](/manuals/extensions-spm), but not CocoaPods dependencies. Use pods from the Objective-C++ file and pass what is needed to the Swift code. +* Using CocoaPods dependencies from Swift code is not supported. Use them from the Objective-C++ file and pass what is needed to the Swift code. * Only the Swift 5 language mode is supported. C++ interoperability is not enabled. * Swift sources are supported by Defold versions that include this feature. A build server with an older SDK fails with a `Swift sources are not supported by this Defold SDK version` error. * Swift sources are not compiled when building the `library` artifact (`--build-artifacts library` in [Bob](/manuals/bob)), so an Objective-C++ file that imports `-Swift.h` fails to compile there. From da3a3a0bc8724f35884276d18e213fad09de5a8d Mon Sep 17 00:00:00 2001 From: Kharkunov Eugene Date: Fri, 6 Nov 2026 15:26:46 +0200 Subject: [PATCH 8/9] Correct the Swift manual on runtime libraries and package module maps --- docs/en/manuals/extensions-swift.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/en/manuals/extensions-swift.md b/docs/en/manuals/extensions-swift.md index 9cd527cf..d06463b4 100644 --- a/docs/en/manuals/extensions-swift.md +++ b/docs/en/manuals/extensions-swift.md @@ -149,9 +149,9 @@ The Swift keys of the `ios` platform apply to both devices and the simulator. A ## Minimum OS versions -The Swift runtime is part of iOS 12.2 and later and of macOS 10.14.4 and later. The Swift code is built for the minimum iOS or macOS version of the build, and the application uses the Swift runtime of the operating system. Use an `#available` check before calling APIs that are newer than the minimum version. +The Swift runtime is part of every iOS and macOS version that Defold supports. The Swift code is built for the minimum iOS or macOS version of the build, and the application uses the Swift runtime of the operating system. Use an `#available` check before calling APIs that are newer than the minimum version. -A few parts of the runtime are part of the operating system only from a later version. For example, Swift concurrency (`async`, `await` and `Task`) is part of iOS 15 and macOS 12. If the minimum version is older and your Swift code uses such a feature, the application needs an extra library to run on those devices. You don't have to do anything for this: the build server finds the libraries that the engine uses, as Xcode does, and adds them to the application. On iOS they are placed in the `Frameworks` folder of the application and are signed together with the rest of its code. +A few parts of the runtime are part of the operating system only from a later version. For example, `MutableSpan` and related types are part of iOS 26 and macOS 26. If the minimum version is older and your Swift code or a dynamic framework of a package uses such a feature, the application may need an extra library to run on those devices. You don't have to do anything for this: the build server finds the libraries that the engine and the dynamic libraries embedded with it use, as Xcode does, and adds them to the application. On iOS they are placed in the `Frameworks` folder of the application and are signed together with the rest of its code. The minimum version of a build is the one that the engine supports, which is set by the Defold version and the build server. A `minVersion` in a `SwiftPackages.json` raises it for the packages, the Swift code and the link of the engine, as described in the [Swift Package Manager manual](/manuals/extensions-spm). It can't be lowered. @@ -160,6 +160,7 @@ The minimum version of a build is the one that the engine supports, which is set * An extension still needs a C++ or Objective-C++ file with `DM_DECLARE_EXTENSION`. Swift code cannot yet register the extension or call the Defold SDK (`dmsdk`) itself. A build with only `.swift` files fails to link with an undefined symbol error named after the extension. * Using CocoaPods dependencies from Swift code is not supported. Use them from the Objective-C++ file and pass what is needed to the Swift code. +* A target of a Swift package with its own `module.modulemap` can't be imported from Swift code, and neither can a Swift target that depends on one. The build fails with a `no such module` or `missing required module` error. * Only the Swift 5 language mode is supported. C++ interoperability is not enabled. * Swift sources are supported by Defold versions that include this feature. A build server with an older SDK fails with a `Swift sources are not supported by this Defold SDK version` error. * Swift sources are not compiled when building the `library` artifact (`--build-artifacts library` in [Bob](/manuals/bob)), so an Objective-C++ file that imports `-Swift.h` fails to compile there. @@ -190,6 +191,3 @@ The minimum version of a build is the one that the engine supports, which is set `invalid 'swiftFlags' value` : The value has whitespace, a backslash or template syntax, or names a response file. Put each flag and each value in its own list item. - -`Swift sources are not supported for this minimum OS version` -: The build targets an iOS or macOS version older than iOS 12.2 or macOS 10.14.4, which have no Swift runtime. Use a Defold version with a newer minimum OS version, or remove the Swift sources. From 1b932413344937a057b3338943c7781dbb24c75d Mon Sep 17 00:00:00 2001 From: Kharkunov Eugene Date: Fri, 6 Nov 2026 15:29:17 +0200 Subject: [PATCH 9/9] Mention package module maps in the Swift troubleshooting list --- docs/en/manuals/extensions-swift.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/manuals/extensions-swift.md b/docs/en/manuals/extensions-swift.md index d06463b4..861ea8cf 100644 --- a/docs/en/manuals/extensions-swift.md +++ b/docs/en/manuals/extensions-swift.md @@ -169,7 +169,7 @@ The minimum version of a build is the one that the engine supports, which is set ## Troubleshooting `no such module 'Name'` -: The module is not a product of a package declared in a `SwiftPackages.json`. Check that `products` lists a product that provides the module, as described in the [Swift Package Manager manual](/manuals/extensions-spm). +: The module is not a product of a package declared in a `SwiftPackages.json`. Check that `products` lists a product that provides the module, as described in the [Swift Package Manager manual](/manuals/extensions-spm). A target with its own `module.modulemap` also gives this error, as listed in the limitations above. `Swift sources are only supported in the 'src' folder` : Move the `.swift` files into the `src` folder of the extension.