Skip to content

Add article on porting Embedded Swift to a new platform - #231

Merged
DrPitre merged 4 commits into
mainfrom
porting-to-new-platforms-article
Aug 18, 2026
Merged

DrPitre merged 4 commits into
mainfrom
porting-to-new-platforms-article

Conversation

@DrPitre

@DrPitre DrPitre commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds a new DocC article, PortingToNewPlatforms.md, documenting the Embedded Swift Platform Abstraction Layer (EmbeddedPlatform.h) and the runtime entry points a platform must provide (allocation, console output, randomness, mutexes, exclusivity checking, exit).
  • Points readers at the ready-made shims in stdlib/public/EmbeddedPlatform (POSIX, single-threaded, multi-threaded POSIX/Darwin) that they can reuse or copy as a starting point.
  • Links the new article from the landing page's "SDK support" section, alongside IntegratingWithPlatforms and Baremetal.

Test plan

  • Verified every function name, signature, and flag mentioned (_swift_allocate, _swift_mutex_init, EMBEDDED_SWIFT_MUTEX_NUM_WORDS, swift_getPlatformLayerVersion, etc.) against the current upstream swiftlang/swift source.
  • Confirmed the <doc:STM32BaremetalGuide> cross-reference resolves under main's Examples/ layout.
  • Build the DocC bundle locally and confirm the new article renders and appears under SDK support.

Documents the Embedded Swift Platform Abstraction Layer (EmbeddedPlatform.h)
and the entry points a platform must provide, with pointers to the
ready-made shims in swiftlang/swift's stdlib/public/EmbeddedPlatform.
The five "Provide ..." sections were nested as H3 under "Provide memory
allocation" (H2), making them look like its subsections instead of
sibling entry points. Also fixes "Proivde" -> "Provide".

@heckj heckj left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great to me overall - Only real feedback was that it wasn't clear to me what a user needs to do with the implementations and how to wrap that into something broader, but it's also not something I've tried to do before - so maybe it's more obvious to folks who are wrangling Embedded and board bring ups.


## Overview

<doc:IntegratingWithPlatforms> and <doc:Baremetal> describe how to connect Swift code to an *existing* SDK, or how to write the startup code and register access for a *specific* board. This article is about the layer underneath both of those: the small number of low-level functions that the Embedded Swift compiler and standard library call into whenever a program uses a feature that needs help from the outside world, such as allocating memory, calling `print()`, or creating a `Mutex`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I read through this, I wasn't sure if this meant the article was about doing things that get you to an SDK (prerequisites) and there's more to building an SDK than is detailed here, or if this porting guide is effectively "how to create a beta SDK for your personal use" kind of thing.

Some of this is my own lack of understanding of what you need to use an arbitrary board - do you need an SDK, or is that more of a "hardened convenience" around these bare "gotta have" technical capabilities?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's meant for people bringing Embedded Swift to a new platform (e.g. microprocessor or operating system environment). Granted, it something that probably doesn't happen often, but having an article like this demonstrates that we want people to consider expanding the Embedded Swift ecosystem.


## Provide mutexes

`_swift_mutex_init`, `_swift_mutex_destroy`, `_swift_mutex_lock`, `_swift_mutex_unlock`, and `_swift_mutex_tryLock` are only needed if you use `Synchronization.Mutex`. The caller allocates the storage for you — at least `EMBEDDED_SWIFT_MUTEX_NUM_WORDS` pointer-sized words (8 by default; override with `-Xcc -DEMBEDDED_SWIFT_MUTEX_NUM_WORDS=<n>` if your mutex representation needs more) — and hands it to `_swift_mutex_init` along with `.checked` and/or `.recursive` flags to opt into misuse diagnostics and reentrant locking.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A small update, this PR moved back to having separate function definitions for recursive threads.

void _swift_mutexRecursive_init(void * EMBEDDED_SWIFT_NONNULL mutex,
                                swift_mutex_flags_t flags);
void _swift_mutexRecursive_destroy(void * EMBEDDED_SWIFT_NONNULL mutex);
void _swift_mutexRecursive_lock(void * EMBEDDED_SWIFT_NONNULL mutex);
void _swift_mutexRecursive_unlock(void * EMBEDDED_SWIFT_NONNULL mutex);

FWIW, Synchronization.Mutex doesn’t expose recursive locking. The recursive mutex functions are currently used internally by Concurrency, so perhaps they can be left out of this section and introduced later when discussing Concurrency support.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I like documenting both recursive and non-recursive in the same place still, with a note that it's the non-recursive one needed for Synchronization.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I verified against the current EmbeddedPlatform.h and confirmed _swift_mutexRecursive_init/destroy/lock/unlock are back as a separate function family with their own EMBEDDED_SWIFT_MUTEX_RECURSIVE_NUM_WORDS sizing. So I removed the incorrect .recursive flag and documented both families.

@DougGregor DougGregor left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for writing this! I have a couple of "flow" comments, and we've tuned a few things in the platform abstraction layer since you started.


## Provide randomness

`_swift_generateRandom` feeds `SystemRandomNumberGenerator`, the default source used by `shuffle()` and friends. `_swift_generateRandomHashSeed` seeds the hashing used by `Set` and `Dictionary`; it doesn't need to be cryptographically secure, and can even return a fixed value if you want deterministic hashing. Both can typically forward to a hardware RNG or `arc4random_buf` where available.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_swift_generateRandom is only needed if you use SystemRandomNumberGenerator. It might be worth calling that out explicitly. I also recommend splitting this into two paragraphs: one for this entrypoint, and the other for hashing, because they're different uses.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I split into two paragraphs: one for _swift_generateRandom with an explicit call-out that it's only needed for SystemRandomNumberGenerator, and a separate one for _swift_generateRandomHashSeed covering Set/Dictionary hashing.


## Provide mutexes

`_swift_mutex_init`, `_swift_mutex_destroy`, `_swift_mutex_lock`, `_swift_mutex_unlock`, and `_swift_mutex_tryLock` are only needed if you use `Synchronization.Mutex`. The caller allocates the storage for you — at least `EMBEDDED_SWIFT_MUTEX_NUM_WORDS` pointer-sized words (8 by default; override with `-Xcc -DEMBEDDED_SWIFT_MUTEX_NUM_WORDS=<n>` if your mutex representation needs more) — and hands it to `_swift_mutex_init` along with `.checked` and/or `.recursive` flags to opt into misuse diagnostics and reentrant locking.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I like documenting both recursive and non-recursive in the same place still, with a note that it's the non-recursive one needed for Synchronization.


## Provide exclusivity checking

`_swift_getExclusivityTLS` and `_swift_setExclusivityTLS` are only needed when the compiler is built with `-enforce-exclusivity=checked`. They store and retrieve a single pointer per thread of execution. On a single-threaded platform this is just a global variable; on a multi-threaded platform it needs real thread-local storage.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These entrypoints have been subsumed by _swift_tls_* entrypoints.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with documenting both families in the same "Provide mutexes" section, as you suggested, with non-recursive first with a note that Synchronization.Mutex only needs that family, then the recursive family with a note that it's currently only used internally by Concurrency.

I replaced the exclusivity section with "Provide thread-local storage," covering the current _swift_tls_init/_swift_tls_get/_swift_tls_set entry points, SWIFT_TLS_KEY_COUNT, and _swift_thread_isMain

Comment on lines +59 to +61
## Implement entry points in C or in Swift

You can implement any of these functions in C. Define a function matching the declaration in `EmbeddedPlatform.h` and link it into your firmware, the same way you would provide any other C symbol the linker asks for.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this section belongs toward the beginning, because it lays out how you implement the functions that are described by most of the document.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved this section up, right after "Reuse the built-in shims" and before the per-feature breakdown.

Comment on lines +78 to +81
## Reuse the built-in shims

Because every entry point is just a function with a specified signature, you rarely need to write all of them from scratch. The Swift repository ships several ready-made shims under [`stdlib/public/EmbeddedPlatform`](https://github.com/swiftlang/swift/tree/main/stdlib/public/EmbeddedPlatform) that you can use directly (where your toolchain provides prebuilt libraries for your target) or copy as a starting point:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this part about the built-in shims belongs way at the beginning, before we discuss how to implement your own. If you're doing Embedded Swift on a POSIX-y platform. If you're single-threaded, against the provided swiftEmbeddedPlatformPOSIX and then choose between the single- and multi-threaded versions. We can show some link lines and paths to where to find them in the toolchain, because for some folks, this is all you need.

It's only if you don't have a POSIX-y platform that you need the rest of this document.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. I moved this section to the front, right after the Overview, and reworded it to lead with the POSIX case: link swiftEmbeddedPlatformPOSIX plus a threading shim (single- or multi-threaded) and you're generally done. I also added the actual library product names (swiftEmbeddedPlatformPOSIX, etc.) and an example link-line so it's actionable without reading the rest of the article. The per-feature sections that follow are now clearly for platforms that don't fit one of these shims.

Boisy Pitre and others added 2 commits August 17, 2026 14:15
- Move the shim/implementation-mechanics sections before the
  per-feature deep dive, since most POSIX-y platforms only need the
  former.
- Clarify in the overview that this article is for platforms lacking
  these entry points entirely, not for consuming an existing SDK.
- Split the randomness section into RNG vs. hash-seed paragraphs and
  call out the SystemRandomNumberGenerator dependency explicitly.
- Document the non-recursive and recursive mutex function families
  together, dropping the removed .recursive flag, and note that
  Synchronization.Mutex only needs the non-recursive family.
- Replace the removed _swift_getExclusivityTLS/_swift_setExclusivityTLS
  section with a "Provide thread-local storage" section describing the
  current _swift_tls_* entry points and _swift_thread_isMain.

@DougGregor DougGregor left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the revisions, this looks good to me!

@DrPitre
DrPitre merged commit 04f3e7e into main Aug 18, 2026
33 of 36 checks passed
@DrPitre
DrPitre deleted the porting-to-new-platforms-article branch August 18, 2026 21:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants