Skip to content

Commit 2b37be6

Browse files
Improve Integrate with Zephyr doc (#153)
- Update architectures and flags for Zephyr guide - Added back picolibc include dir, added more info - Add more information on linking customizations - Change title of IntegrateWithZephyr doc
1 parent 38b5af0 commit 2b37be6

File tree

1 file changed

+95
-7
lines changed

1 file changed

+95
-7
lines changed

Sources/EmbeddedSwift/Documentation.docc/SDKSupport/IntegrateWithZephyr.md

Lines changed: 95 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1-
# Integrating with Zephyr
1+
# Zephyr RTOS SDK
22

33
Integrating Swift with Zephyr RTOS for embedded systems development
44

5+
[Zephyr](https://www.zephyrproject.org/) is an open-source RTOS for embedded systems that is sponsored by the Linux Foundation. Since it depends on CMake primarily for its build system, it can easily be integrated to be used with Embedded Swift.
6+
57
The following document outlines how to setup a Swift to Zephyr project for an emulated ARM Cortex M0, explaining a few key concepts along the way. For a complete working example on real hardware, however, refer to the [nrfx-blink-sdk](https://github.com/swiftlang/swift-embedded-examples/tree/main/nrfx-blink-sdk) project that is compatible with nRF or other boards.
68

79
> Note: Embedded Swift is experimental. Public releases of Swift do not support Embedded Swift, yet. See <doc:InstallEmbeddedSwift> for details.
810
9-
## Zephyr Target Architecture Compatibility
11+
## Target Architecture Compatibility
1012

1113
Zephyr [supports quite a few target architectures](https://docs.zephyrproject.org/latest/introduction/index.html), but not all are supported by Embedded Swift. Please refer to the following table for an overview of Zephyr-supported architectures that are supported by Swift, along with the correct target triple to use:
1214

1315
| Architecture | Details | Swift Triple |
1416
|--------------|---------------------|-------------------------|
15-
| ARMv6-M | Cortex M0, M1, M3 | armv6m-none-none-eabi |
16-
| ARMv7-M | Cortex M4, M7 | armv7em-none-none-eabi |
17+
| ARMv6-M | Cortex M0, M0+, M1 | armv6m-none-none-eabi |
18+
| ARMv7-M | Cortex M3 | armv7-none-none-eabi |
19+
| ARMv7-EM | Cortex M4/M4F, M7 | armv7em-none-none-eabi |
1720
| ARMv8-M | Cortex M23-85 | aarch64-none-none-elf |
1821
| Intel | 32-bit (i686) | i686-unknown-none-elf |
1922
| Intel | 64-bit (x86_64) | x86_64-unknown-none-elf |
@@ -134,7 +137,7 @@ Next, set the compiler target to the arch you are building for. For this example
134137
set(CMAKE_Swift_COMPILER_TARGET armv6m-none-none-eabi)
135138
```
136139

137-
After setting the target triple, some additional additional Swift compiler flags need to be defined:
140+
After setting the target triple, some additional additional Swift compiler flags need to be defined.
138141

139142
```cmake
140143
# Set global Swift compiler flags
@@ -145,15 +148,26 @@ add_compile_options(
145148
# Enable function sections to enable dead code stripping on elf
146149
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xfrontend -function-sections>"
147150
151+
# Use software floating point operations matching GCC
152+
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xcc -mfloat-abi=soft>"
153+
154+
# Use compacted C enums matching GCC
155+
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xcc -fshort-enums>"
156+
148157
# Disable PIC
149158
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xcc -fno-pic>"
150159
151160
# Disable PIE
152161
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xcc -fno-pie>"
162+
163+
# Add Libc include paths
164+
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xcc -I -Xcc ${ZEPHYR_SDK_INSTALL_DIR}/arm-zephyr-eabi/picolibc/include>"
153165
)
154166
```
155167

156-
There are quite a few other Zephyr flags that must also be imported in order to get Zephyr include paths and flags such `-mcpu`, `-mfloat-abi`, and so on:
168+
- NOTE: The `-mfloat-abi=soft` flag may need to change to `-mfloat-abi=hard` for ARM CPUs that support hard-float, such as the Cortex-M4F and Cortex-M7. This and the `-fshort-enums` flags are not required for non-ARM architectures such as Intel and RISC-V.
169+
170+
There are quite a few other Zephyr flags that can also be imported (optional) in order to get Zephyr include paths and flags such `-mcpu`, `mthumb`, `-mabi`, and so on:
157171

158172
```cmake
159173
# Import TOOLCHAIN_C_FLAGS from Zephyr as -Xcc flags
@@ -289,7 +303,8 @@ manifest:
289303
- cmsis # required by the ARM port
290304
```
291305
292-
It is recommended to set the `revision` to a tagged version of Zephyr instead of always getting the main revision, which could have changing APIs.
306+
- It is recommended to set the `revision` to a tagged version of Zephyr instead of always getting the main revision, which could have changing APIs.
307+
- Also, please note that depending on what architecture you are targeting, you may need to add more/different targets to the `name-allowlist`, which is useful to get needed dependencies when compiling a project from a CI. See the [Zephyr workflow from swift-embedded-examples](https://github.com/swiftlang/swift-embedded-examples/blob/main/.github/workflows/build-zephyr.yml) for an example of setting up a CI for Zephyr.
293308

294309
Next, set the `ZEPHYR_BASE` environment variable to tell `west` where the Zephyr workspace is located:
295310

@@ -335,3 +350,76 @@ ninja: no work to do.
335350
```
336351

337352
The `-r jlink` param is needed for this example to use the J-Link tools instead of using `nrfjprog`, which is the default for this board and also [deprecated](https://www.nordicsemi.com/Products/Development-tools/nRF-Command-Line-Tools).
353+
354+
## Customizing the Linker
355+
356+
The default linker configuration for building a Zephyr project from CMake works well for simple projects, but it can be customized as needed. The following sections show off some useful ways to customize linking Zephyr projects for Swift.
357+
358+
### Stripping Out Unused Sections
359+
360+
When compiling Swift to Zephyr projects, you may see some warnings about orphaned sections from the linker, like `.swift_modhash`:
361+
362+
```console
363+
~/zephyr-sdk-0.17.0/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd: warning: orphan section `.swift_modhash' from `app/libapp.a(Main.swift.obj)' being placed in section `.swift_modhash'
364+
[135/135] Linking C executable zephyr/zephyr.elf
365+
~/zephyr-sdk-0.17.0/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd: warning: orphan section `.swift_modhash' from `app/libapp.a(Main.swift.obj)' being placed in section `.swift_modhash
366+
```
367+
368+
These types of warnings can be suppressed by passing a custom linker script to Zephyr that discards the sections, especially if they are not needed. For example, a script called `sections.ld` can be created at the root of the project with the following contents:
369+
370+
```ld
371+
/DISCARD/ : { *(.swift_modhash*) }
372+
/DISCARD/ : { *(.ARM.attributes*) *(.ARM.exidx) }
373+
```
374+
375+
Then, in `CMakeLists.txt`, add the following line:
376+
377+
```cmake
378+
# Remove unused sections
379+
zephyr_linker_sources(SECTIONS "sections.ld")
380+
```
381+
382+
This can also help to reduce the size of the output elf/binary since unused sections are stripped out. Be careful what sections you strip out, however, as some sections may be required.
383+
384+
### Linking Swift Libraries
385+
386+
This example adds the `swiftUnicodeDataTables` library from Swift to be linked into the Zephyr project. This is useful for linking unicode symbols when using strings. See <doc:Strings> for more information on this.
387+
388+
In order to add additional linker params, the CMake `target_link_libraries` invocation can be used against `zephyr_pre0` and `zephyr_final`, like this:
389+
390+
```cmake
391+
# The code is using a String as a Dictionary key and thus require linking with libswiftUnicodeDataTables.a
392+
# We compute the path where this file reside, taking into accout how the toolchain is referenced (Swiftly or TOOLCHAINS env variable).
393+
find_program(SWIFTLY "swiftly")
394+
IF(SWIFTLY)
395+
execute_process(COMMAND swiftly use --print-location OUTPUT_VARIABLE toolchain_path)
396+
cmake_path(SET additional_lib_path NORMALIZE "${toolchain_path}/usr/lib/swift/embedded/${CMAKE_Swift_COMPILER_TARGET}")
397+
ELSE()
398+
get_filename_component(compiler_bin_dir ${CMAKE_Swift_COMPILER} DIRECTORY)
399+
cmake_path(SET additional_lib_path NORMALIZE "${compiler_bin_dir}/../lib/swift/embedded/${CMAKE_Swift_COMPILER_TARGET}")
400+
ENDIF()
401+
402+
target_link_directories(zephyr_pre0 PRIVATE "${additional_lib_path}")
403+
target_link_libraries(zephyr_pre0
404+
-Wl,--whole-archive
405+
swiftUnicodeDataTables
406+
-Wl,--no-whole-archive
407+
)
408+
409+
target_link_directories(zephyr_final PRIVATE "${additional_lib_path}")
410+
target_link_libraries(zephyr_final
411+
-Wl,--whole-archive
412+
swiftUnicodeDataTables
413+
-Wl,--no-whole-archive
414+
)
415+
```
416+
417+
Extra code is required to find the right paths where the `swiftUnicodeDataTables.a` file is located, depending on how Swift is installed.
418+
419+
When this is built, depending on the target architecture, warnings may then be printed about 32-bit enums, like this:
420+
421+
```console
422+
~/zephyr-sdk-0.17.0/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd: warning: ~/.local/share/swiftly/toolchains/6.1.0/usr/lib/swift/embedded/armv6m-none-none-eabi/libswiftUnicodeDataTables.a(UnicodeWord.cpp.o) uses 32-bit enums yet the output is to use variable-size enums; use of enum values across objects may fail
423+
```
424+
425+
To suppress these, simply add `-Wl,--no-enum-size-warning` to the `target_link_libraries` invocations.

0 commit comments

Comments
 (0)