Hi all,
tl;dr we're making some changes to the way Embedded Swift interacts with the platform and it will require small changes to existing Embedded Swift programs to continue to link properly.
In our discussions with various people using Embedded Swift, one of the issues we keep hearing about is that it's hard to tell exactly what functions you need to provide to get Embedded Swift to run on top of your platform. There is a documented set of external dependencies, but it's a somewhat ad hoc set of requirements (posix_memalign, free, arc4random_buf, _swift_getExclusivityTLS, etc.) that effectively assume a C library underneath.
We've been working on a Platform Abstraction Layer (PAL) that makes the set of requirements on the platform more deliberate and explicit. The PAL is described by a single C header swift/EmbeddedPlatform.h that provides declarations for a set of _swift_* functions that a platform must supply to support Embedded Swift. The C header makes it easy to bind to existing platform C libraries. The declared functions can be implemented in either C or in Embedded Swift (via @c @implementation), whatever makes the most sense. The implementations should then be linked in with the final Embedded Swift binary.
The functions in the PAL currently fall into a few different categories, e.g.:
- Memory allocation
- Standard output
- Error reporting
- Random hash seeding
- Random number generation
- Mutexes
- Thread-local storage
If you're running on a POSIX-y system, or really anything with a libc, there are straightforward implementations of these functions on top of that functionality. To help with these cases, we've created some "mix-in" static libraries that implement the PAL. For example:
swiftEmbeddedPlatformPOSIXlibrary provides implementations for all of the non-concurrency-related PAL entrypoints on top of POSIX.swiftEmbeddedPlatformSingleThreadedprovides single-threaded implementations of the TLS and mutex-related entrypointsswiftEmbeddedPlatformMultiThreadedPOSIXprovides multi-threaded implementations of the TLS and mutex-related entrypoints on top of pthreads
@BoisyPitre has provided a guide for porting Embedded Swift to a new platform that describes the specific functions, and the header itself has its own documentation.
One of the goals here is that all of the Embedded Swift libraries in the toolchain will only require these functions from the platform, and nothing more---everything else is built on top of them. So we've sought to minimize dependencies where we can, and will continue to try to keep the PAL as small as is reasonable. There have been some nice second-order effects. For example, we now send all Swift-introduced allocation and deallocation through the PAL, so it's possible to completely separate the Embedded Swift heap from the C heap.
We expect the PAL to grow a bit more. For example, there's an open pull request to put clock functions into the PAL, and reseat the concurrency library's clock handling on top of them. Expect more in this area for concurrency specifically.
The PAL needs to be enabled when the standard library is built, so it's a global flag. My intent is to enable the PAL on main shortly, at which point Embedded Swift programs will need to link in one of the platform layers or define the appropriate _swift_* functions to continue to link. Sorry for the inconvenience this will cause, but it's important that we move toward this world with well-defined, minimal requirements from the platform.
Doug