Skip to content

Commit 2fa1022

Browse files
authored
Merge pull request #70687 from kubamracek/embedded-docs1
[embedded] Add an initial docs/EmbeddedSwift/UserManual.md
2 parents 4cae998 + 770496b commit 2fa1022

File tree

3 files changed

+343
-0
lines changed

3 files changed

+343
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Embedded Swift -- Status
2+
3+
**⚠️ Embedded Swift is experimental. This document might be out of date with latest development.**
4+
5+
**‼️ Use the latest downloadable 'Trunk Development' snapshot from swift.org to use Embedded Swift. Public releases of Swift do not yet support Embedded Swift.**
6+
7+
For an introduction and motivation into Embedded Swift, please see "[A Vision for Embedded Swift](https://github.com/apple/swift-evolution/blob/main/visions/embedded-swift.md)", a Swift Evolution document highlighting the main goals and approaches.
8+
9+
## Embedded Standard Library Breakdown
10+
11+
This status table describes which of the following standard library features can be used in Embedded Swift:
12+
13+
| **Swift Standard Library Feature** | **Currently Supported In Embedded Swift** |
14+
|---------------------------------------------|-----------------------------------------------------|
15+
| Array (dynamic heap-allocated container) | Yes |
16+
| Array slices | Yes |
17+
| assert, precondition, fatalError | Partial, only StaticStrings can be used as a failure message |
18+
| Bool, Integer types, Float types | Yes |
19+
| Codable, Encodable, Decodable | No |
20+
| Collection + related protocols | Yes |
21+
| Collection algorithms (sort, reverse) | Yes |
22+
| CustomStringConvertible, CustomDebugStringConvertible | No |
23+
| Dictionary (dynamic heap-allocated container) | Yes |
24+
| FixedWidthInteger + related protocols | Yes |
25+
| Hashable, Equatable, Comparable protocols | Yes |
26+
| InputStream, OutputStream | No |
27+
| Integer parsing | No |
28+
| KeyPaths | No |
29+
| Lazy collections | No |
30+
| Mirror | No, intentionally unsupported long-term |
31+
| Objective-C bridging | No, intentionally unsupported long-term |
32+
| Optional | Yes |
33+
| print / debugPrint | Partial (only StaticStrings and integers) |
34+
| Range, ClosedRange, Stride | Yes |
35+
| Result | Yes |
36+
| Set (dynamic heap-allocated container) | Yes |
37+
| SIMD types | Yes |
38+
| StaticString | Yes |
39+
| String (dynamic) | No (work in progress) |
40+
| String Interpolations | No (work in progress) |
41+
| Unicode | No |
42+
| Unsafe\[Mutable\]\[Raw\]\[Buffer\]Pointer | Yes |
43+
| VarArgs | No |
44+
45+
## Non-stdlib Features
46+
47+
This status table describes which of the following Swift features can be used in Embedded Swift:
48+
49+
| **Swift Feature** | **Currently Supported In Embedded Swift** |
50+
|---------------------------------------------|-----------------------------------------------------|
51+
| Swift Concurrency | Partial, experimental (basics of actors and tasks work in single-threaded concurrency mode) |
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Embedded Swift -- Integrating with embedded SDKs
2+
3+
**⚠️ Embedded Swift is experimental. This document might be out of date with latest development.**
4+
5+
**‼️ Use the latest downloadable 'Trunk Development' snapshot from swift.org to use Embedded Swift. Public releases of Swift do not yet support Embedded Swift.**
6+
7+
For an introduction and motivation into Embedded Swift, please see "[A Vision for Embedded Swift](https://github.com/apple/swift-evolution/blob/main/visions/embedded-swift.md)", a Swift Evolution document highlighting the main goals and approaches.
8+
9+
The following document sketches how to integrate Swift code into some popular embedded platforms' SDKs and build systems.
10+
11+
## Integrating with Raspberry Pi Pico (W) build system:
12+
13+
Development for [Raspberry Pi Pico and Pico W](https://www.raspberrypi.com/products/raspberry-pi-pico/) normally uses the [Pico SDK](https://github.com/raspberrypi/pico-sdk) and the vendor provides several [sample projects in the pico-examples repository](https://github.com/raspberrypi/pico-examples). The SDK and sample project setup is described in:
14+
15+
- https://www.raspberrypi.com/documentation/microcontrollers/c_sdk.html#sdk-setup
16+
- https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf
17+
18+
Before trying to use Swift with the Pico SDK, make sure your environment works and can build the provided C/C++ sample projects.
19+
20+
### CMake setup with a bridging header
21+
22+
The Pico SDK is using CMake as its build system, and so the simplest way to integrate with it is to also use CMake to build a Swift firmware application on top of the SDK and the libraries from it. The following describes an example set up of that on a "blinky" example (code that just blinks the built-in LED).
23+
24+
Let's create a directory with a Swift source file, a bridging header, and a CMake definition file:
25+
26+
```
27+
./SwiftPicoBlinky/Main.swift
28+
./SwiftPicoBlinky/BridgingHeader.h
29+
./SwiftPicoBlinky/CMakeLists.txt
30+
```
31+
32+
In `Main.swift`, let's add basic logic to initialize the GPIO port for the Pico's built-in LED, and then turn it on and off in a loop:
33+
34+
```swift
35+
@main
36+
struct Main {
37+
static func main() {
38+
let led = UInt32(PICO_DEFAULT_LED_PIN)
39+
gpio_init(led)
40+
gpio_set_dir(led, /*out*/true)
41+
while true {
42+
gpio_put(led, true)
43+
sleep_ms(250)
44+
gpio_put(led, false)
45+
sleep_ms(250)
46+
}
47+
}
48+
}
49+
```
50+
51+
Notice that we're using functions and variables defined in C in the Pico SDK. For that to be possible, the Swift compiler needs to have access to the C header files that define these functions and variables. The cleanest option would be to define a modulemap, but for simplicity let's just use a bridging header to make declarations visible in Swift without a module. `BridgingHeader.h` should contain:
52+
53+
```c
54+
#pragma once
55+
56+
#include "pico/stdlib.h"
57+
```
58+
59+
Finally, we need to define the application's build rules in CMake that will be using CMake logic from the Pico SDK. The following content of `CMakeLists.txt` shows how to *manually call swiftc, the Swift compiler* instead of using the recently added CMake native support for Swift, so that we can see the full Swift compilation command.
60+
61+
```cmake
62+
cmake_minimum_required(VERSION 3.13)
63+
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
64+
65+
project(swift-blinky)
66+
pico_sdk_init()
67+
execute_process(COMMAND xcrun -f swiftc OUTPUT_VARIABLE SWIFTC OUTPUT_STRIP_TRAILING_WHITESPACE)
68+
69+
add_executable(swift-blinky)
70+
add_custom_command(
71+
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_swiftcode.o
72+
COMMAND
73+
${SWIFTC}
74+
-target armv6m-none-none-eabi -Xcc -mfloat-abi=soft -Xcc -fshort-enums
75+
-Xfrontend -function-sections -enable-experimental-feature Embedded -wmo -parse-as-library
76+
$$\( echo '$<TARGET_PROPERTY:swift-blinky,INCLUDE_DIRECTORIES>' | tr '\;' '\\n' | sed -e 's/\\\(.*\\\)/-Xcc -I\\1/g' \)
77+
$$\( echo '${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES}' | tr ' ' '\\n' | sed -e 's/\\\(.*\\\)/-Xcc -I\\1/g' \)
78+
-import-bridging-header ${CMAKE_CURRENT_LIST_DIR}/BridgingHeader.h
79+
${CMAKE_CURRENT_LIST_DIR}/Main.swift
80+
-c -o ${CMAKE_CURRENT_BINARY_DIR}/_swiftcode.o
81+
DEPENDS
82+
${CMAKE_CURRENT_LIST_DIR}/BridgingHeader.h
83+
${CMAKE_CURRENT_LIST_DIR}/Main.swift
84+
)
85+
add_custom_target(swift-blinky-swiftcode DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_swiftcode.o)
86+
87+
target_link_libraries(swift-blinky
88+
pico_stdlib hardware_uart hardware_gpio
89+
${CMAKE_CURRENT_BINARY_DIR}/_swiftcode.o
90+
)
91+
add_dependencies(swift-blinky swift-blinky-swiftcode)
92+
pico_add_extra_outputs(swift-blinky)
93+
```
94+
95+
With these three files, we can now configure and build a Swift firmware for the Pico:
96+
97+
```bash
98+
$ export TOOLCHAINS=org.swift.59202401301a
99+
$ export PICO_BOARD=pico
100+
$ export PICO_SDK_PATH=<path_to_pico_sdk>
101+
$ export PICO_TOOLCHAIN_PATH=<path_to_arm_toolchain>
102+
$ ls -al
103+
-rw-r--r-- 1 kuba staff 39B Feb 2 22:08 BridgingHeader.h
104+
-rw-r--r-- 1 kuba staff 1.3K Feb 2 22:08 CMakeLists.txt
105+
-rw-r--r-- 1 kuba staff 262B Feb 2 22:08 Main.swift
106+
$ mkdir build
107+
$ cd build
108+
$ cmake -S ../ -B . -G Ninja
109+
$ ninja -v
110+
```
111+
112+
This should produce several build artifacts in the `build/` subdirectory, include `swift-blinky.uf2`, which can be directly uploaded to the Pico by copying it into the fake Mass Storage Volume that the device presents when plugged over USB in BOOTSEL mode.

0 commit comments

Comments
 (0)