Skip to content

Commit 8be26f8

Browse files
Add initial WIP IntegrateWithZephyr document
1 parent 7e1f25f commit 8be26f8

File tree

3 files changed

+154
-1
lines changed

3 files changed

+154
-1
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.DS_Store
22
**/.DS_Store
3-
*/.build
3+
.build/
44
*/build
55
*/sdkconfig
66
*/sdkconfig.old

Sources/EmbeddedSwift/Documentation.docc/Documentation.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ The malloc/calloc/free APIs are expected to be provided by the platform. The Swi
190190
### SDK Support
191191

192192
- <doc:IntegrateWithPico>
193+
- <doc:IntegrateWithZephyr>
193194

194195
### Language Details
195196

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# Integrating with Zephyr
2+
3+
**⚠️ Embedded Swift is experimental. This document might be out of date with latest development.**
4+
5+
For an introduction and motivation into Embedded Swift, please see "[A Vision for Embedded Swift](https://github.com/swiftlang/swift-evolution/blob/main/visions/embedded-swift.md)", a Swift Evolution document highlighting the main goals and approaches.
6+
7+
Refer to the [nrfx-blink-sdk](../../../../nrfx-blink-sdk/) project for a complete working "blinky" example that can be used as a starting point. However, for a formal introduction to setting up a Swift Zephyr project and explanations into the various options, continue reading this document.
8+
9+
## Zephyr Setup
10+
11+
Before setting up a Swift project that works with Zephyr, you need to setup dependencies and a Zephyr workspace as per the [Getting Started Guide](https://docs.zephyrproject.org/latest/develop/getting_started/index.html). Regardless of your platform (macOS or Linux), ensure that you can build the blinky example without errors before starting with Swift integration:
12+
13+
```bash
14+
cd ~/zephyrproject/zephyr
15+
west build -p always -b <your-board-name> samples/basic/blinky
16+
```
17+
18+
By default, the `main` revision of the Zephyr sources are checked out when calling `west init`, which contains pre-release and development changes that may cause instability and changing APIs that are not desirable. To checkout a specific release version of Zephyr, use the following commands:
19+
20+
```bash
21+
cd ~/zephyrproject/zephyr
22+
git checkout v4.1.0
23+
west update
24+
west packages pip --install
25+
26+
# For older versions of Zephyr (pre 4.1.0), use:
27+
pip install -r ~/zephyrproject/zephyr/scripts/requirements.txt
28+
```
29+
30+
Refer to the [Zephyr Releases](https://docs.zephyrproject.org/latest/releases/index.html) page for more information on current and LTS releases.
31+
32+
## Project Setup
33+
34+
Once Zephyr is setup, the next step is to setup a project with a bridging header, `CMakeLists.txt`, `Main.swift`, and `prj.conf`:
35+
36+
```plain
37+
SwiftZephyrProject/BridgingHeader.h
38+
SwiftZephyrProject/CMakeLists.txt
39+
SwiftZephyrProject/Main.swift
40+
SwiftZephyrProject/prj.conf
41+
```
42+
43+
These are the minimum required files in order to build a Zephyr project. For example, `prj.conf` is required even if it is empty, or the project will not build.
44+
45+
Inside of `BridgingHeader.h`, add the following content as a minimum:
46+
47+
```c
48+
#pragma once
49+
50+
#include <autoconf.h>
51+
```
52+
53+
The `Main.swift` file must contain a `static func main()` as follows:
54+
55+
```swift
56+
@main
57+
struct Main {
58+
static func main() {
59+
// code
60+
}
61+
}
62+
```
63+
64+
### CMakeLists.txt Setup
65+
66+
The `CMakeLists.txt` setup is more involved and complex since target, compilation flags, and library linking must be specified for Swift. First, some initial setup and flags:
67+
68+
```cmake
69+
cmake_minimum_required(VERSION 3.29)
70+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
71+
72+
# Use the armv7em-none-none-eabi target triple for Swift
73+
set(CMAKE_Swift_COMPILER_TARGET armv7em-none-none-eabi)
74+
# Enable "wmo" as needed by Embedded Swift
75+
set(CMAKE_Swift_COMPILATION_MODE wholemodule)
76+
# FIXME: Skip checking if the compiler works
77+
set(CMAKE_Swift_COMPILER_WORKS true)
78+
79+
# Create a new project called "SwiftZephyrProject" and enable "Swift" as a supported language
80+
project(SwiftZephyrProject Swift)
81+
```
82+
83+
The following flags have been curated to work well with `armv7em-none-none-eabi` target with `swiftc`. Some flags may need to change depending on the chosen target:
84+
85+
```cmake
86+
# Set global Swift compiler flags
87+
add_compile_options(
88+
# Enable Embedded Swift
89+
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature Embedded>"
90+
91+
# Enable function sections to enable dead code stripping on elf
92+
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xfrontend -function-sections>"
93+
94+
# Use software floating point operations matching GCC
95+
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xcc -mfloat-abi=soft>"
96+
97+
# Use compacted C enums matching GCC
98+
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xcc -fshort-enums>"
99+
100+
# Disable PIC
101+
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xcc -fno-pic>"
102+
103+
# Add Libc include paths
104+
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xcc -I -Xcc ${ZEPHYR_SDK_INSTALL_DIR}/arm-zephyr-eabi/picolibc/include>"
105+
)
106+
```
107+
108+
The following block will automatically grab Zephyr compilation flags (such as `-D__ZEPHYR__=1` and `-DKERNEL`) and set them as Swift compiler definitions. This is required to successfully build Swift code that works with Zephyr:
109+
110+
```cmake
111+
# Add definitions from Zephyr to -Xcc flags
112+
get_target_property(ZEPHYR_DEFINES zephyr_interface INTERFACE_COMPILE_DEFINITIONS)
113+
if(ZEPHYR_DEFINES)
114+
foreach(flag ${ZEPHYR_DEFINES})
115+
# Ignore expressions like "$<SOMETHING>"
116+
string(FIND "${flag}" "$<" start_of_expression)
117+
if(NOT start_of_expression EQUAL -1)
118+
continue()
119+
endif()
120+
121+
add_compile_options("$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xcc -D${flag}>")
122+
endforeach()
123+
endif()
124+
```
125+
126+
Finally, setup targets, libraries, and additional compile options:
127+
128+
```cmake
129+
# The Swift code providing "main" needs to be in an OBJECT library (instead of STATIC library) to make sure it actually gets linker.
130+
# A STATIC library would get dropped from linking because Zephyr provides a default weak empty main definition.
131+
add_library(app_swift OBJECT Main.swift)
132+
133+
add_dependencies(app_swift syscall_list_h_target)
134+
target_compile_options(app_swift PRIVATE
135+
-parse-as-library
136+
137+
-Osize
138+
139+
-Xfrontend -disable-stack-protector
140+
141+
# FIXME: add dependency on BridgingHeader.h
142+
-import-bridging-header ${CMAKE_CURRENT_LIST_DIR}/BridgingHeader.h
143+
)
144+
145+
# Copy include paths from C target to Swift target
146+
target_include_directories(app_swift PRIVATE
147+
"$<TARGET_PROPERTY:app,INCLUDE_DIRECTORIES>"
148+
)
149+
150+
# Link the Swift target into the primary target
151+
target_link_libraries(app PRIVATE app_swift)
152+
```

0 commit comments

Comments
 (0)