How far can i get with Swift WebAssembly in 30 minutes?

i tried to debug this today, by replicating @svanimpe ’s example project as closely as i could.

$ git clone https://github.com/pwsacademy/swiftwasm-examples
$ cd swiftwasm-examples/
$ cd basics/
$ swift run carton bundle --custom-index-page Web/index.html

i was again loudly reminded with a crash and stack trace that carton does not support my Operating System. why Swift performs seppuku when throwing from main is something i fail to understand since Swift 5.9. but that is hardly carton’s fault.

i switched the dependency in Package.swift over to my local fork, and everything went smoothly, Sendable noise notwithstanding.

Swift Concurrency noise
$ swift run carton bundle --custom-index-page Web/index.html
Updating https://github.com/swiftwasm/JavaScriptKit
Updating https://github.com/apple/swift-nio.git
Updating https://github.com/swiftwasm/WasmTransformer
Updating https://github.com/apple/swift-argument-parser.git
Updated https://github.com/swiftwasm/JavaScriptKit (0.24s)
Updated https://github.com/swiftwasm/WasmTransformer (0.27s)
Updated https://github.com/apple/swift-argument-parser.git (0.27s)
Updated https://github.com/apple/swift-nio.git (0.41s)
Computing version for https://github.com/swiftwasm/JavaScriptKit
Computed https://github.com/swiftwasm/JavaScriptKit at 0.21.0 (0.01s)
Computing version for https://github.com/swiftwasm/WasmTransformer
Computed https://github.com/swiftwasm/WasmTransformer at 0.5.0 (0.00s)
Computed https://github.com/swiftwasm/JavaScriptKit at 0.21.0 (0.00s)
Computing version for https://github.com/apple/swift-argument-parser.git
Computed https://github.com/apple/swift-argument-parser.git at 1.3.1 (0.01s)
Computing version for https://github.com/apple/swift-nio.git
Computed https://github.com/apple/swift-nio.git at 2.79.0 (0.01s)
Updating https://github.com/apple/swift-atomics.git
Updating https://github.com/apple/swift-system.git
Updating https://github.com/apple/swift-collections.git
Updated https://github.com/apple/swift-collections.git (0.28s)
Updated https://github.com/apple/swift-atomics.git (0.28s)
Updated https://github.com/apple/swift-system.git (0.28s)
Computing version for https://github.com/apple/swift-system.git
Computed https://github.com/apple/swift-system.git at 1.4.0 (0.00s)
Computing version for https://github.com/apple/swift-atomics.git
Computed https://github.com/apple/swift-atomics.git at 1.2.0 (0.01s)
Computing version for https://github.com/apple/swift-collections.git
Computed https://github.com/apple/swift-collections.git at 1.1.4 (0.01s)
Building for debugging...
/swift/carton/Sources/SwiftToolchain/AsyncFileDownload.swift:36:9: warning: non-final class 'FileDownloadDelegate' cannot conform to 'Sendable'; use '@unchecked Sendable'; this is an error in the Swift 6 language mode
 34 |     public var receivedBytes: Int
 35 |   }
 36 |   class FileDownloadDelegate: NSObject, URLSessionDownloadDelegate {
    |         `- warning: non-final class 'FileDownloadDelegate' cannot conform to 'Sendable'; use '@unchecked Sendable'; this is an error in the Swift 6 language mode
 37 |     let path: String
 38 |     let onTotalBytes: (Int) -> Void

/swift/carton/Sources/SwiftToolchain/AsyncFileDownload.swift:38:9: warning: stored property 'onTotalBytes' of 'Sendable'-conforming class 'FileDownloadDelegate' has non-sendable type '(Int) -> Void'; this is an error in the Swift 6 language mode
 36 |   class FileDownloadDelegate: NSObject, URLSessionDownloadDelegate {
 37 |     let path: String
 38 |     let onTotalBytes: (Int) -> Void
    |         |- warning: stored property 'onTotalBytes' of 'Sendable'-conforming class 'FileDownloadDelegate' has non-sendable type '(Int) -> Void'; this is an error in the Swift 6 language mode
    |         `- note: a function type must be marked '@Sendable' to conform to 'Sendable'
 39 |     let continuation: AsyncThrowingStream<Progress, Error>.Continuation
 40 |     var totalBytesToDownload: Int?

/swift/carton/Sources/SwiftToolchain/AsyncFileDownload.swift:40:9: warning: stored property 'totalBytesToDownload' of 'Sendable'-conforming class 'FileDownloadDelegate' is mutable; this is an error in the Swift 6 language mode
 38 |     let onTotalBytes: (Int) -> Void
 39 |     let continuation: AsyncThrowingStream<Progress, Error>.Continuation
 40 |     var totalBytesToDownload: Int?
    |         `- warning: stored property 'totalBytesToDownload' of 'Sendable'-conforming class 'FileDownloadDelegate' is mutable; this is an error in the Swift 6 language mode
 41 | 
 42 |     init(
/swift/carton/Sources/SwiftToolchain/AsyncFileDownload.swift:36:9: warning: non-final class 'FileDownloadDelegate' cannot conform to 'Sendable'; use '@unchecked Sendable'; this is an error in the Swift 6 language mode
 34 |     public var receivedBytes: Int
 35 |   }
 36 |   class FileDownloadDelegate: NSObject, URLSessionDownloadDelegate {
    |         `- warning: non-final class 'FileDownloadDelegate' cannot conform to 'Sendable'; use '@unchecked Sendable'; this is an error in the Swift 6 language mode
 37 |     let path: String
 38 |     let onTotalBytes: (Int) -> Void

/swift/carton/Sources/SwiftToolchain/AsyncFileDownload.swift:38:9: warning: stored property 'onTotalBytes' of 'Sendable'-conforming class 'FileDownloadDelegate' has non-sendable type '(Int) -> Void'; this is an error in the Swift 6 language mode
 36 |   class FileDownloadDelegate: NSObject, URLSessionDownloadDelegate {
 37 |     let path: String
 38 |     let onTotalBytes: (Int) -> Void
    |         |- warning: stored property 'onTotalBytes' of 'Sendable'-conforming class 'FileDownloadDelegate' has non-sendable type '(Int) -> Void'; this is an error in the Swift 6 language mode
    |         `- note: a function type must be marked '@Sendable' to conform to 'Sendable'
 39 |     let continuation: AsyncThrowingStream<Progress, Error>.Continuation
 40 |     var totalBytesToDownload: Int?

/swift/carton/Sources/SwiftToolchain/AsyncFileDownload.swift:40:9: warning: stored property 'totalBytesToDownload' of 'Sendable'-conforming class 'FileDownloadDelegate' is mutable; this is an error in the Swift 6 language mode
 38 |     let onTotalBytes: (Int) -> Void
 39 |     let continuation: AsyncThrowingStream<Progress, Error>.Continuation
 40 |     var totalBytesToDownload: Int?
    |         `- warning: stored property 'totalBytesToDownload' of 'Sendable'-conforming class 'FileDownloadDelegate' is mutable; this is an error in the Swift 6 language mode
 41 | 
 42 |     init(
[29/29] Linking carton
Build of product 'carton' complete! (2.99s)
- checking Swift compiler path: /home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a/usr/bin/swift
- checking Swift compiler path: /home/ubuntu/.swiftenv/versions/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a/usr/bin/swift
Fetching release assets from https://api.github.com/repos/swiftwasm/swift/releases/tags/swift-wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a
Response contained body, parsing it now...
Response successfully parsed, choosing from this number of assets: 10
Local installation of Swift version wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a not found
Swift toolchain/SDK download URL: https://github.com/swiftwasm/swift/releases/download/swift-wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a/swift-wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a-ubuntu22.04_x86_64.tar.gz
Archive size is 1042 MB
                                                                                                        Downloading the archive
99% [=================================================================================================================================================================================================================---]
saving to /home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a.gz
Download completed successfully
Unpacking the archive: /usr/bin/tar xzf /home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a.gz --strip-components=1 --directory /home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a
Running "/usr/bin/tar" "xzf" "/home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a.gz" "--strip-components=1" "--directory" "/home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a"
- checking Swift compiler path: /home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a/usr/bin/swift
Inferring basic settings...
- swift executable: /home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a/usr/bin/swift
Swift version 6.1-dev (LLVM f4b733c38006ec1, Swift 5c7509bef50dbd7)
Target: x86_64-unknown-linux-gnu
Running "/home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a/usr/bin/swift" "package" "--triple" "wasm32-unknown-wasi" "--scratch-path" "/swift/wasm-test/swiftwasm-examples/basics/.build/carton" "--disable-sandbox" "plugin" "carton-bundle" "--output" "Bundle" "--custom-index-page" "Web/index.html"
Building for debugging...
/swift/carton/Sources/CartonHelpers/Basics/Condition.swift:11:19: warning: '@preconcurrency' attribute on module 'Foundation' has no effect
 9 | */
10 | #if !_runtime(_ObjC)
11 |   @preconcurrency import Foundation
   |                   `- warning: '@preconcurrency' attribute on module 'Foundation' has no effect
12 | #else
13 |   import Foundation

/swift/carton/Sources/CartonHelpers/Basics/FileInfo.swift:12:19: warning: '@preconcurrency' attribute on module 'Foundation' has no effect
10 | 
11 | #if !_runtime(_ObjC)
12 |   @preconcurrency import Foundation
   |                   `- warning: '@preconcurrency' attribute on module 'Foundation' has no effect
13 | #else
14 |   import Foundation
/swift/carton/Sources/CartonHelpers/Basics/Condition.swift:11:19: warning: '@preconcurrency' attribute on module 'Foundation' has no effect
 9 | */
10 | #if !_runtime(_ObjC)
11 |   @preconcurrency import Foundation
   |                   `- warning: '@preconcurrency' attribute on module 'Foundation' has no effect
12 | #else
13 |   import Foundation

/swift/carton/Sources/CartonHelpers/Basics/FileInfo.swift:12:19: warning: '@preconcurrency' attribute on module 'Foundation' has no effect
10 | 
11 | #if !_runtime(_ObjC)
12 |   @preconcurrency import Foundation
   |                   `- warning: '@preconcurrency' attribute on module 'Foundation' has no effect
13 | #else
14 |   import Foundation
/swift/carton/Sources/CartonHelpers/Basics/Process/Process.swift:20:22: warning: using '@_implementationOnly' without enabling library evolution for 'CartonHelpers' may lead to instability during execution
  18 | #endif
  19 | 
  20 | @_implementationOnly import TSCclibc
     |                      `- warning: using '@_implementationOnly' without enabling library evolution for 'CartonHelpers' may lead to instability during execution
  21 | import TSCLibc
  22 | import Dispatch

/swift/carton/Sources/CartonHelpers/Basics/Process/ProcessEnv.swift:72:36: warning: conformance of 'Dictionary<Key, Value>' to protocol 'Sendable' conflicts with that stated in the type's module 'Swift' and will be ignored; there cannot be more than one conformance, even with different conditional bounds
 70 | }
 71 | 
 72 | extension ProcessEnvironmentBlock: Sendable {}
    |                                    `- warning: conformance of 'Dictionary<Key, Value>' to protocol 'Sendable' conflicts with that stated in the type's module 'Swift' and will be ignored; there cannot be more than one conformance, even with different conditional bounds
 73 | 
 74 | /// Provides functionality related a process's environment.

Swift.Dictionary:1:11: note: 'Dictionary<Key, Value>' declares conformance to protocol 'Sendable' here
1 | extension Dictionary : @unchecked Sendable where Key : Sendable, Value : Sendable {
  |           `- note: 'Dictionary<Key, Value>' declares conformance to protocol 'Sendable' here
2 | }
/swift/carton/Sources/CartonHelpers/Basics/Process/ProcessEnv.swift:72:36: warning: conformance of 'Dictionary<Key, Value>' to protocol 'Sendable' conflicts with that stated in the type's module 'Swift' and will be ignored; there cannot be more than one conformance, even with different conditional bounds
 70 | }
 71 | 
 72 | extension ProcessEnvironmentBlock: Sendable {}
    |                                    `- warning: conformance of 'Dictionary<Key, Value>' to protocol 'Sendable' conflicts with that stated in the type's module 'Swift' and will be ignored; there cannot be more than one conformance, even with different conditional bounds
 73 | 
 74 | /// Provides functionality related a process's environment.

Swift.Dictionary:1:11: note: 'Dictionary<Key, Value>' declares conformance to protocol 'Sendable' here
1 | extension Dictionary : @unchecked Sendable where Key : Sendable, Value : Sendable {
  |           `- note: 'Dictionary<Key, Value>' declares conformance to protocol 'Sendable' here
2 | }
/swift/carton/Sources/CartonHelpers/Basics/Process/ProcessEnv.swift:72:36: warning: conformance of 'Dictionary<Key, Value>' to protocol 'Sendable' conflicts with that stated in the type's module 'Swift' and will be ignored; there cannot be more than one conformance, even with different conditional bounds
 70 | }
 71 | 
 72 | extension ProcessEnvironmentBlock: Sendable {}
    |                                    `- warning: conformance of 'Dictionary<Key, Value>' to protocol 'Sendable' conflicts with that stated in the type's module 'Swift' and will be ignored; there cannot be more than one conformance, even with different conditional bounds
 73 | 
 74 | /// Provides functionality related a process's environment.

Swift.Dictionary:1:11: note: 'Dictionary<Key, Value>' declares conformance to protocol 'Sendable' here
1 | extension Dictionary : @unchecked Sendable where Key : Sendable, Value : Sendable {
  |           `- note: 'Dictionary<Key, Value>' declares conformance to protocol 'Sendable' here
2 | }
/swift/carton/Sources/CartonHelpers/Basics/Thread.swift:54:41: warning: converting non-sendable function value to '@Sendable () -> Void' may introduce data races
 52 |         }
 53 | 
 54 |         self.thread = ThreadImpl(block: theTask)
    |                                         `- warning: converting non-sendable function value to '@Sendable () -> Void' may introduce data races
 55 |     }
 56 | 
/swift/carton/Sources/CartonHelpers/Basics/Thread.swift:54:41: warning: converting non-sendable function value to '@Sendable () -> Void' may introduce data races
 52 |         }
 53 | 
 54 |         self.thread = ThreadImpl(block: theTask)
    |                                         `- warning: converting non-sendable function value to '@Sendable () -> Void' may introduce data races
 55 |     }
 56 | 
/swift/carton/Sources/CartonHelpers/Basics/Process/Process.swift:20:22: warning: using '@_implementationOnly' without enabling library evolution for 'CartonHelpers' may lead to instability during execution
  18 | #endif
  19 | 
  20 | @_implementationOnly import TSCclibc
     |                      `- warning: using '@_implementationOnly' without enabling library evolution for 'CartonHelpers' may lead to instability during execution
  21 | import TSCLibc
  22 | import Dispatch
/swift/carton/Sources/CartonHelpers/Basics/Process/Process.swift:20:22: warning: using '@_implementationOnly' without enabling library evolution for 'CartonHelpers' may lead to instability during execution
  18 | #endif
  19 | 
  20 | @_implementationOnly import TSCclibc
     |                      `- warning: using '@_implementationOnly' without enabling library evolution for 'CartonHelpers' may lead to instability during execution
  21 | import TSCLibc
  22 | import Dispatch
[56/56] Linking carton-frontend-slim-tool
Build of product 'carton-frontend-slim' complete! (5.01s)
Building "HelloSwiftWasm"
Building for production...
[0/2] Write swift-version-22C80AB982ED8698.txt
Build of product 'HelloSwiftWasm' complete! (0.86s)
Right after building the main binary size is 8.12 MB

After stripping debug info the main binary size is 5.79 MB


Running wasm-opt -Os --enable-bulk-memory --enable-sign-ext /swift/wasm-test/swiftwasm-examples/basics/Bundle/main.wasm -o /swift/wasm-test/swiftwasm-examples/basics/Bundle/main.wasm
wasm-opt -Os --enable-bulk-memory --enable-sign-ext /swift/wasm-test/swiftwasm-examples/basics/Bundle/main.wasm -o /swift/wasm-test/swiftwasm-examples/basics/Bundle/main.wasm
`wasm-opt` process finished successfully
After stripping debug info the main binary size is 3.71 MB

Copying resources to /swift/wasm-test/swiftwasm-examples/basics/Bundle/JavaScriptKit_JavaScriptKit.resources
Bundle successfully generated at /swift/wasm-test/swiftwasm-examples/basics/Bundle

wow! that’s exactly what i was looking for! now, 3.71 MB uncompressed isn’t nothing, but that is definitely something i can work with :smiley:

now the question becomes: why does this build produce a 3.71 MB binary, but the other one produces a 56 MB binary?

:thinking: what is different about this build?

now i skim through that Concurrency-laden output from earlier, and immediately something sticks out to me.

Build of product 'carton' complete! (2.99s)
- checking Swift compiler path: /home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a/usr/bin/swift
- checking Swift compiler path: /home/ubuntu/.swiftenv/versions/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a/usr/bin/swift
Fetching release assets from https://api.github.com/repos/swiftwasm/swift/releases/tags/swift-wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a
Response contained body, parsing it now...
Response successfully parsed, choosing from this number of assets: 10
Local installation of Swift version wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a not found
Swift toolchain/SDK download URL: https://github.com/swiftwasm/swift/releases/download/swift-wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a/swift-wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a-ubuntu22.04_x86_64.tar.gz
Archive size is 1042 MB
                                                                                                        Downloading the archive
99% [=================================================================================================================================================================================================================---]
saving to /home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a.gz
Download completed successfully
Unpacking the archive: /usr/bin/tar xzf /home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a.gz --strip-components=1 --directory /home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a
Running "/usr/bin/tar" "xzf" "/home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a.gz" "--strip-components=1" "--directory" "/home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a"
- checking Swift compiler path: /home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a/usr/bin/swift
Inferring basic settings...
- swift executable: /home/ubuntu/.carton/sdk/wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a/usr/bin/swift
Swift version 6.1-dev (LLVM f4b733c38006ec1, Swift 5c7509bef50dbd7)

it’s not using a release toolchain, it’s using some random nightly DEVELOPMENT-SNAPSHOT-2024-10-27-a.

that’s “bad”. a lot of libraries crash the compiler when built with nightlies, because the nightlies have compiler assertions enabled. there is often nothing you can do when you have a library that is crashing the compiler. and even if all your libraries build with the nightly, you can forget about using sourcekit-lsp or any other “modern” IDE tools. one lesson this Swiftie learned brutally and repeatedly early in her career is that if you are relying on nightly Swift toolchains, you are going to have a very tough time getting anything done.

but is it really the nightly toolchain that is key to achieving reasonable binary size? let’s find out…

:weary: it’s the .swift-version, stupid

so it looks like carton is using swiftenv, and there is a .swift-version file in the repo that contains the string wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a, so that’s probably where the nightly is coming from.

i try replacing this with 6.0.3-RELEASE, even though i know there is no such thing as swiftwasm 6.0.3. to my surprise, this works, and causes swiftenv to download Swift 6.0.2, which is probably what i would have done too. hooray?

$ swift run carton bundle --custom-index-page Web/index.html
Building for debugging...
[1/1] Write swift-version--75355AAB4E86B17C.txt
Build of product 'carton' complete! (0.27s)
- checking Swift compiler path: /home/ubuntu/.carton/sdk/wasm-6.0.2-RELEASE/usr/bin/swift
- checking Swift compiler path: /home/ubuntu/.swiftenv/versions/wasm-6.0.2-RELEASE/usr/bin/swift
Fetching release assets from https://api.github.com/repos/swiftwasm/swift/releases/tags/swift-wasm-6.0.2-RELEASE
Response contained body, parsing it now...
Response successfully parsed, choosing from this number of assets: 8
Local installation of Swift version wasm-6.0.2-RELEASE not found
Swift toolchain/SDK download URL: https://github.com/swiftwasm/swift/releases/download/swift-wasm-6.0.2-RELEASE/swift-wasm-6.0.2-RELEASE-ubuntu22.04_x86_64.tar.gz
Archive size is 908 MB
                                                                                                        Downloading the archive
99% [=================================================================================================================================================================================================================---]
saving to /home/ubuntu/.carton/sdk/wasm-6.0.2-RELEASE.gz
Download completed successfully
Unpacking the archive: /usr/bin/tar xzf /home/ubuntu/.carton/sdk/wasm-6.0.2-RELEASE.gz --strip-components=1 --directory /home/ubuntu/.carton/sdk/wasm-6.0.2-RELEASE
Running "/usr/bin/tar" "xzf" "/home/ubuntu/.carton/sdk/wasm-6.0.2-RELEASE.gz" "--strip-components=1" "--directory" "/home/ubuntu/.carton/sdk/wasm-6.0.2-RELEASE"
- checking Swift compiler path: /home/ubuntu/.carton/sdk/wasm-6.0.2-RELEASE/usr/bin/swift
Inferring basic settings...
- swift executable: /home/ubuntu/.carton/sdk/wasm-6.0.2-RELEASE/usr/bin/swift
Swift version 6.0.2 (swift-6.0.2-RELEASE)
Build of product 'HelloSwiftWasm' complete! (7.75s)
Right after building the main binary size is 56.56 MB

After stripping debug info the main binary size is 49.95 MB


Running wasm-opt -Os --enable-bulk-memory --enable-sign-ext /swift/wasm-test/swiftwasm-examples/basics/Bundle/main.wasm -o /swift/wasm-test/swiftwasm-examples/basics/Bundle/main.wasm
wasm-opt -Os --enable-bulk-memory --enable-sign-ext /swift/wasm-test/swiftwasm-examples/basics/Bundle/main.wasm -o /swift/wasm-test/swiftwasm-examples/basics/Bundle/main.wasm
`wasm-opt` process finished successfully
After stripping debug info the main binary size is 44.77 MB

Copying resources to /swift/wasm-test/swiftwasm-examples/basics/Bundle/JavaScriptKit_JavaScriptKit.resources
Bundle successfully generated at /swift/wasm-test/swiftwasm-examples/basics/Bundle

…and there it is. the release toolchain cannot produce WebAssembly binaries of reasonable size. only the unstable nightly toolchains can do this.

so i guess the basic tradeoff here is that if you want to do Serious WebAssembly with Swift, you must use nightly toolchains. but we know that we cannot do Serious Development with nightly toolchains, because they cannot compile libraries, and their sourcekit-lsp does not work while editing code. so it seems that Swift on WebAssembly is in a sort of catch-22.

theoretically, we could mitigate this problem by distributing nightlies that are built with noassert, like the release toolchains on Linux, or the Xcode toolchains on macOS. does such a thing exist?

6 Likes