Skip to content

Commit 54d735e

Browse files
Update to the latest info
1 parent e720f2f commit 54d735e

File tree

6 files changed

+137
-109
lines changed

6 files changed

+137
-109
lines changed

src/examples/exporting-function.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Exporting function for host environment
22

3+
## Swift 5.10 or earlier
4+
35
You can expose a Swift function for host environment using special attribute and linker option.
46

57
```swift
@@ -59,3 +61,26 @@ console.log("2 + 3 = " + addFn(2, 3))
5961
```
6062

6163
If you use SwiftPM package, you can omit linker flag using clang's `__atribute__`. Please see [swiftwasm/JavaScriptKit#91](https://github.com/swiftwasm/JavaScriptKit/pull/91/files) for more detail info
64+
65+
## Swift 6.0 or later
66+
67+
If you use Swift 6.0 or later, you can use `@_expose(wasm, "add")` and omit the `--export` linker flag.
68+
69+
```swift
70+
// File name: lib.swift
71+
@_expose(wasm, "add")
72+
@_cdecl("add") // This is still required to call the function with C ABI
73+
func add(_ lhs: Int, _ rhs: Int) -> Int {
74+
return lhs + rhs
75+
}
76+
```
77+
78+
Then you can compile the Swift code with the following command without `--export` linker flag.
79+
80+
```bash
81+
$ swiftc \
82+
-target wasm32-unknown-wasi \
83+
-parse-as-library \
84+
lib.swift -o lib.wasm \
85+
-Xclang-linker -mexec-model=reactor
86+
```

src/examples/importing-function.md

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Importing a function from host environments
22

3+
## Swift 5.10 or earlier
4+
35
You can import a function from your host environment using the integration of Swift Package Manager
46
with C targets. Firstly, you should declare a signature for your function in a C header with an
57
appropriate `__import_name__` attribute:
@@ -14,15 +16,14 @@ Move this C header to a separate target, we'll call it `HostFunction` in this ex
1416
`Package.swift` manifest for your WebAssembly app would look like this:
1517
1618
```swift
17-
// swift-tools-version:5.3
18-
// The swift-tools-version declares the minimum version of Swift required to build this package.
19+
// swift-tools-version:5.9
1920
import PackageDescription
2021
2122
let package = Package(
22-
name: "SwiftWasmApp",
23+
name: "Example",
2324
targets: [
2425
.target(name: "HostFunction", dependencies: []),
25-
.target(name: "SwiftWasmApp", dependencies: ["HostFunction"]),
26+
.executableTarget(name: "Example", dependencies: ["HostFunction"]),
2627
]
2728
)
2829
```
@@ -43,41 +44,24 @@ Note that we use `env` as default import module name. You can specify the module
4344
like `__attribute__((__import_module__("env"),__import_name__("add")))`.
4445

4546
```javascript
46-
const WASI = require("@wasmer/wasi").WASI;
47-
const WasmFs = require("@wasmer/wasmfs").WasmFs;
48-
49-
const promisify = require("util").promisify;
50-
const fs = require("fs");
51-
const readFile = promisify(fs.readFile);
47+
// File name: main.mjs
48+
import { WASI, File, OpenFile, ConsoleStdout } from "@bjorn3/browser_wasi_shim";
49+
import fs from "fs/promises";
5250

5351
const main = async () => {
54-
const wasmFs = new WasmFs();
55-
// Output stdout and stderr to console
56-
const originalWriteSync = wasmFs.fs.writeSync;
57-
wasmFs.fs.writeSync = (fd, buffer, offset, length, position) => {
58-
const text = new TextDecoder("utf-8").decode(buffer);
59-
switch (fd) {
60-
case 1:
61-
console.log(text);
62-
break;
63-
case 2:
64-
console.error(text);
65-
break;
66-
}
67-
return originalWriteSync(fd, buffer, offset, length, position);
68-
};
6952

7053
// Instantiate a new WASI Instance
71-
let wasi = new WASI({
72-
args: [],
73-
env: {},
74-
bindings: {
75-
...WASI.defaultBindings,
76-
fs: wasmFs.fs,
77-
},
78-
});
79-
80-
const wasmBinary = await readFile("lib.wasm");
54+
// See https://github.com/bjorn3/browser_wasi_shim/ for more detail about constructor options
55+
let wasi = new WASI([], [],
56+
[
57+
new OpenFile(new File([])), // stdin
58+
ConsoleStdout.lineBuffered(msg => console.log(`[WASI stdout] ${msg}`)),
59+
ConsoleStdout.lineBuffered(msg => console.warn(`[WASI stderr] ${msg}`)),
60+
],
61+
{ debug: false }
62+
);
63+
64+
const wasmBinary = await fs.readFile(".build/wasm32-unknown-wasi/debug/Example.wasm");
8165

8266
// Instantiate the WebAssembly file
8367
let { instance } = await WebAssembly.instantiate(wasmBinary, {
@@ -99,3 +83,28 @@ an integration with an imported host function.
9983

10084
A more streamlined way to import host functions will be implemented in the future version of the
10185
SwiftWasm toolchain.
86+
87+
88+
## Swift 6.0 or later
89+
90+
If you are using Swift 6.0 or later, you can use experimental `@_extern(wasm)` attribute
91+
92+
Swift 6.0 introduces a new attribute `@_extern(wasm)` to import a function from the host environment.
93+
To use this experimental feature, you need to enable it in your SwiftPM manifest file:
94+
95+
```swift
96+
.executableTarget(
97+
name: "Example",
98+
swiftSettings: [
99+
.enableExperimentalFeature("Extern")
100+
]),
101+
```
102+
103+
Then, you can import a function from the host environment as follows without using C headers:
104+
105+
```swift
106+
@_extern(wasm, module: "env", name: "add")
107+
func add(_ a: Int, _ b: Int) -> Int
108+
109+
print(add(2, 2))
110+
```

src/getting-started/hello-world.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ $ swiftc -target wasm32-unknown-wasi hello.swift -o hello.wasm
1818

1919
## 3. Run the produced binary on WebAssembly runtime
2020

21-
You can the run the produced binary with [wasmer](https://wasmer.io/) (or other WebAssembly runtime):
21+
You can the run the produced binary with [wasmtime](https://wasmtime.dev/) (or other WebAssembly runtime):
2222

2323
```sh
24-
$ wasmer hello.wasm
24+
$ wasmtime hello.wasm
2525
```
2626

2727
The produced binary depends on WASI which is an interface of system call for WebAssembly.
28-
So you need to use WASI supported runtime and when you run the binary on browser, you need WASI polyfill library like [@wasmer/wasi](https://github.com/wasmerio/wasmer-js/tree/master/packages/wasi).
28+
So you need to use WASI supported runtime and when you run the binary on browser, you need WASI polyfill library like [@bjorn3/browser_wasi_shim](https://github.com/bjorn3/browser_wasi_shim).

src/getting-started/porting.md

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import WASILibc
3232
### Limitations
3333

3434
WebAssembly and [WASI](https://wasi.dev/) provide a constrained environment, which currently does
35-
not directly support multi-threading, or filesystem access in the browser. Thus, you should not
35+
not directly support multi-threading. Thus, you should not
3636
expect these APIs to work when importing `WASILibc`. Please be aware of these limitations when
3737
porting your code, which also has an impact on what [can be supported in the Swift
3838
Foundation](#swift-foundation-and-dispatch) at the moment.
@@ -44,32 +44,34 @@ SwiftWasm, but in a limited capacity. The main reason is that [the Dispatch core
4444
library](https://swift.org/core-libraries/#libdispatch) is unavailable due to [the lack of
4545
standardized multi-threading support](https://github.com/swiftwasm/swift/issues/1887) in WebAssembly
4646
and SwiftWasm itself. Many Foundation APIs rely on the presence of Dispatch under the hood,
47-
specifically file system access and threading helpers. A few other types are unavailable in browsers
48-
or aren't standardized in WASI hosts, such as support for sockets and low-level networking, or
49-
support for time zone files, and they had to be disabled. These types are therefore absent in
50-
SwiftWasm Foundation:
47+
specifically threading helpers. A few other types are unavailable in browsers
48+
or aren't standardized in WASI hosts, such as support for sockets and low-level networking,
49+
and they had to be disabled. These types are therefore absent in SwiftWasm Foundation:
5150

52-
* `FoundationNetworking` types, such as `URLSession` and related APIs
53-
* `FileManager`
54-
* `Host`
55-
* `Notification`
56-
* `NotificationQueue`
57-
* `NSKeyedArchiver`
58-
* `NSKeyedArchiverHelpers`
59-
* `NSKeyedCoderOldStyleArray`
60-
* `NSKeyedUnarchiver`
61-
* `NSNotification`
62-
* `NSSpecialValue`
63-
* `Port`
64-
* `PortMessage`
65-
* `Process`
66-
* `ProcessInfo` (Partially available since 5.7)
67-
* `PropertyListEncoder`
68-
* `RunLoop`
69-
* `Stream`
70-
* `Thread`
71-
* `Timer`
72-
* `UserDefaults`
51+
| Type or module | Status |
52+
|----------------|--------|
53+
| `FoundationNetworking` | ❌ Unavailable |
54+
| `FileManager` | ✅ Available after 6.0 |
55+
| `Host` | ✅ Partially available after 6.0 |
56+
| `Notification` | ✅ Available after 6.0 |
57+
| `NotificationQueue` | ❌ Unavailable |
58+
| `NSKeyedArchiver` | ✅ Available after 6.0 |
59+
| `NSKeyedArchiverHelpers` | ✅ Available after 6.0 |
60+
| `NSKeyedCoderOldStyleArray` | ✅ Available after 6.0 |
61+
| `NSKeyedUnarchiver` | ✅ Available after 6.0 |
62+
| `NSNotification` | ✅ Available after 6.0 |
63+
| `NSSpecialValue` | ✅ Available after 6.0 |
64+
| `Port` | ✅ Available after 6.0 |
65+
| `PortMessage` | ✅ Available after 6.0 |
66+
| `Process` | ❌ Unavailable |
67+
| `ProcessInfo` | ✅ Partially available after 5.7 |
68+
| `PropertyListEncoder` | ✅ Available after 6.0 |
69+
| `RunLoop` | ❌ Unavailable |
70+
| `Stream` | ✅ Partially available after 6.0 |
71+
| `SocketPort` | ❌ Unavailable |
72+
| `Thread` | ❌ Unavailable |
73+
| `Timer` | ❌ Unavailable |
74+
| `UserDefaults` | ✅ Available after 6.0 |
7375

7476
Related functions and properties on other types are also absent or disabled. We would like to make
7577
them available in the future as soon as possible, and [we invite you to

src/getting-started/swift-package.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,12 @@ You can also use SwiftPM for managing packages in the same way as other platform
66
## 1. Create a package from template
77

88
```sh
9-
$ swift package init --type executable
10-
Creating executable package: hello
9+
$ swift package init --type executable --name Example
10+
Creating executable package: Example
1111
Creating Package.swift
12-
Creating README.md
1312
Creating .gitignore
1413
Creating Sources/
15-
Creating Sources/hello/main.swift
16-
Creating Tests/
17-
Creating Tests/LinuxMain.swift
18-
Creating Tests/helloTests/
19-
Creating Tests/helloTests/helloTests.swift
20-
Creating Tests/helloTests/XCTestManifests.swift
14+
Creating Sources/main.swift
2115
```
2216

2317
## 2. Build the Project into a WebAssembly binary
@@ -28,11 +22,19 @@ You need to pass `--triple` option, which indicates that you are building for th
2822
$ swift build --triple wasm32-unknown-wasi
2923
```
3024

25+
<!--
26+
If [you installed Swift SDK instead of the whole toolchain](./setup.md#experimental-swift-sdk), you need to use the following command:
27+
28+
```sh
29+
$ swift build --experimental-swift-sdk <SDK name>
30+
```
31+
-->
32+
3133
## 3. Run the produced binary
3234

33-
Just as in the [previous section](./hello-world.md), you can run the produced binary with the `wasmer` WebAssembly runtime.
35+
Just as in the [previous section](./hello-world.md), you can run the produced binary with WebAssembly runtimes like `wasmtime`.
3436

3537
```sh
36-
$ wasmer ./.build/debug/hello-swiftwasm.wasm
38+
$ wasmtime ./.build/wasm32-unknown-wasi/debug/Example.wasm
3739
Hello, world!
3840
```

src/getting-started/testing.md

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,45 +12,37 @@ Let's assume you have a `SwiftWasmLibrary` target in your project that you'd lik
1212
would probably look like this:
1313

1414
```swift
15-
// swift-tools-version:5.3
16-
// The swift-tools-version declares the minimum version of Swift required to build this package.
15+
// swift-tools-version: 5.9
1716

1817
import PackageDescription
1918

2019
let package = Package(
21-
name: "HelloSwiftWasm",
22-
products: [
23-
.executable(name: "SwiftWasmApp", targets: ["SwiftWasmApp"]),
24-
],
25-
targets: [
26-
// Targets are the basic building blocks of a package. A target can define a module or a test
27-
// suite. Targets can depend on other targets in this package, and on products in packages which
28-
// this package depends on.
29-
.target(
30-
name: "SwiftWasmApp",
31-
dependencies: ["SwiftWasmLibrary"],
32-
),
33-
.target(name: "SwiftWasmLibrary"),
34-
.testTarget(name: "SwiftWasmTests", dependencies: ["SwiftWasmLibrary"]),
35-
]
20+
name: "Example",
21+
products: [
22+
.library(name: "Example", targets: ["Example"]),
23+
],
24+
targets: [
25+
.target(name: "Example"),
26+
.testTarget(name: "ExampleTests", dependencies: ["Example"]),
27+
]
3628
)
3729
```
3830

39-
Now you should make sure there's `Tests/SwiftWasmTests` subdirectory in your project.
40-
If you don't have any files in it yet, create `SwiftWasmTests.swift` in it:
31+
Now you should make sure there's `Tests/ExampleTests` subdirectory in your project.
32+
If you don't have any files in it yet, create `ExampleTests.swift` in it:
4133

4234
```swift
43-
import SwiftWasmLibrary
35+
import Example
4436
import XCTest
4537

46-
final class SwiftWasmTests: XCTestCase {
38+
final class ExampleTests: XCTestCase {
4739
func testTrivial() {
4840
XCTAssertEqual(text, "Hello, world")
4941
}
5042
}
5143
```
5244

53-
This code assumes that your `SwiftWasmLibrary` defines some `text` with `"Hello, world"` value
45+
This code assumes that your `Example` defines some `text` with `"Hello, world"` value
5446
for this test to pass. Your test functions should all start with `test`, please see [XCTest
5547
documentation](https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods)
5648
for more details.
@@ -64,17 +56,9 @@ are not available in test suites compiled with SwiftWasm. If you have an existin
6456
porting to WebAssembly, you should use `#if os(WASI)` directives to exclude places where you use
6557
these APIs from compilation.
6658

67-
## Building and running the test suite with `carton`
68-
69-
If you use [`carton`](https://carton.dev) to develop and build your app, as described in [our guide
70-
for browser apps](./browser-app.md), just run `carton test` in the
71-
root directory of your package. This will automatically build the test suite and run it with
72-
[Wasmer](https://wasmer.io/) for you.
73-
7459
## Building and running the test suite with `SwiftPM`
7560

76-
If you manage your SwiftWasm toolchain without `carton` (as shown in [the "Setup" section](./setup.md)),
77-
you can build your test suite by running this command in your terminal:
61+
You can build your test suite by running this command in your terminal:
7862

7963
```sh
8064
$ swift build --build-tests --triple wasm32-unknown-wasi
@@ -84,12 +68,18 @@ If you're used to running `swift test` to run test suites for other Swift platfo
8468
warn you that this won't work. `swift test` doesn't know what WebAssembly environment you'd like to
8569
use to run your tests. Because of this building tests and running them are two separate steps when
8670
using `SwiftPM`. After your tests are built, you can use a WASI-compatible host such as
87-
[Wasmer](https://wasmer.io/) to run the test bundle:
71+
[wasmtime](https://wasmtime.dev/) to run the test bundle:
8872

8973
```sh
90-
$ wasmer .build/debug/HelloSwiftWasmPackageTests.xctest
74+
$ wasmtime .build/wasm32-unknown-wasi/debug/ExamplePackageTests.wasm
9175
```
9276

9377
As you can see, the produced test binary starts with the name of your package followed by
94-
`PackageTests.xctest`. It is located in the `.build/debug` subdirectory, or in the `.build/release`
78+
`PackageTests.wasm`. It is located in the `.build/debug` subdirectory, or in the `.build/release`
9579
subdirectory when you build in release mode.
80+
81+
## Building and running the test suite with `carton`
82+
83+
If you use [`carton`](https://carton.dev) to develop and build your app, as described in [our guide
84+
for browser apps](./browser-app.md), just run `carton test` in the
85+
root directory of your package. This will automatically build the test suite and run it with a WASI runtime for you.

0 commit comments

Comments
 (0)