Category Archives: Swift

swiftformat, Decent Swift Syntax, and Sublime Text

If you’re writing Swift code for iOS you’re most likely going to be doing so in Xcode. If you’re coding Swift to run on the server, you might want to check out an editor like Sublime Text. In this post we’ll show you how to use Sublime, the Decent Swift Syntax package and swiftformat together to write some nicely formatted Swift code.

Sublime Text

Installing Sublime is as easy as heading over to the Sublime Text website and clicking the download button appropriate for your platform. In this post we’ll be using macOS.

Once you’ve installed Sublime Text create a new file with File – New and then go to its Tools menu and select Command Palette. A search field will open. Start typing ‘package’ and select Package Control: Install Package.

The search field will change again to list available packages to install. Find and install Decent Swift Syntax. You’ll notice from here that files ending in .swift will be inferred as containing the Swift language, and Decent Swift Syntax will go to work.

swiftformat

The Decent Swift Syntax package relies on swiftformat to do the heavy lifting of reformatting your Swift code. To install it you will want to use brew: brew install swiftformat

Two Spaces and a Gotcha

With the end of the spaces vs. tabs war, the new battlefront formed was whether to indent two spaces or four. Anyone with sense knows that the answer is two spaces, so at the top of your Swift file you can add // swiftformat:options --indent 2 in order to tell swiftformat to format your code accordingly.

Now here is an interesting gotcha we you may find when writing closures. Let’s say our closure function signature is something like:

And we’re writing some code that supplies the closure, like:

If this is all you wrote and saved your code swiftformat would happily replace status and error because they were unused arguments. Out of habit I save files often so it came as a bit of a surprise when my arguments started disappearing. Although swiftformat has an stripunusedargs option, it doesn’t appear to permit you to turn it off.

Swift on Linux In 2021

It has been nearly 6 years since Apple first open sourced the Swift language and brought it to Linux. In that time we’ve seen the rise (and sometimes fall) of server-side frameworks such as Zewo, Kitura, and Vapor as well as porting Swift to SBC devices such as the Raspberry Pi and Beaglebone.

I recently checked in with some folks in the Swift ARM community to find out if there was an easy way to install the latest version of Swift on Ubuntu. FutureJones pointed me to a Debian-based repository he’s been working on at Swiftlang.xyz. A nicely put together repo, Swiftlang.xyz supports multiple flavors of Debian and Ubuntu OSes as well as both x86 and ARM architectures! I’ve installed Swift 5.4 and the upcoming 5.6 release with great success.

Using https://swiftlang.xyz/public/ is a piece of cake with an installer script to configure your apt repository list automatically. arkansas below is an Ubuntu VM running on Apple Silicon with Parallels.

Type curl -s https://swiftlang.xyz/install.sh | sudo bash to get started.

I want to use Swift 5.6 so I’ll select option 2 which will include the dev repository in my apt sources.

Now it’s time to install Swift through the provided swiftlang package. apt-get install swiftlang is all it takes.

Once installed let’s kick the tires a bit. First, typing swift in the terminal will bring up the REPL:

To really test things out let’s hit a REST API and destructure the response. For this we’ll use ReqRes and just grab a user with GET https://reqres.in/api/users/2.

And now, some code!

Swift 4 titleized String Extension

Swift 4.2

Rails provides the titleize inflector (capitalizes all the words in a string), and I needed one for Swift too. The code snippet below adds a computed property to the String class and follows these rules:

  • The first letter of the first word of the string is capitalized
  • The first letter of the remaining words in the string are capitalized, except those that are considered “small words”

Create a file in your Xcode project named String+Titleized.swift and paste in the following String extension:

Configure SMALL_WORDS to your liking. In this example I was titleizing Spanish phrases, so my SMALL_WORDS contains various definite articles and conjunctions. An example of the usage and output:

Note: This post is a Swift 4.2 version of this one written in Swift 2.

Building Swift 3.0 on an ARMv7 System

Swift 3.0 Swift 3.0 Swift 3.0

Editor’s Note: This post supersedes our other posts on building Swift 3.0 for the BeagleBone Black or Raspberry Pi 3 as it utilizes the repository’s hosted by the Swift ARM organization.

To get started with building Swift 3.0 natively on an ARMv7 you’re going to need:

  • a suitably powerful ARMv7 system; we have used the BeagleBoard X15 with build times of about 4 hours and Raspberry Pi 3 for initial build times of 6 hours
  • high-speed IO on either a USB3 flash drive or a UHS-I/class 10 microSD card with a capacity of 16GB or greater (I like the Patriot EP Series for the price combined with relatively high write speeds)
  • one of the supported Ubuntu releases such as Ubuntu Xenial 16.04
  • Patience

Install Build Prerequisites

Compiling Swift requires a number of prerequisites. Get them in one fell swoop with:

# sudo apt-get install -y git cmake ninja-build clang uuid-dev libicu-dev icu-devtools libbsd-dev libedit-dev libxml2-dev libsqlite3-dev swig libpython-dev libncurses5-dev pkg-config autoconf libtool systemtap-sdt-dev libcurl4-openssl-dev

Add Some Swap

You will need at a minimum 2G of RAM on an ARMv7 system to build Swift. If you are working with the Pi3 you will want to add some swap to double up from the base 1G.

# cd /var/cache
# sudo mkdir swap
# cd swap
# sudo fallocate -l 1G 1G.swap
# sudo mkswap 1G.swap
Setting up swapspace version 1, size = 1024 MiB (1073737728 bytes)
no label, UUID=184d002a-2f15-4b23-8360-8e792badc6a2
# sudo chmod 600 1G.swap
# sudo swapon 1G.swap

Using build-swift

build-swift is our Github repository that has several helper scripts to make life a little easier building Swift on ARM.

# git clone https://github.com/swift-arm/build-swift
# cd build-swift

By default build-swift will check out to the swift-3.0 branch.

The contained scripts (located in the scripts directory) are pretty simple:

  • get.sh – Downloads all of the required repositories for building Swift; these repositories are from the Swift ARM organization and have been patched specifically for building ARMv7
  • update.sh – Updates all of your local repositories with the latest on Github
  • package.sh – Runs the Swift build-script
  • clean.sh – Deletes the build artifacts
  • distclean.sh – Deletes both the build artifacts and the deletes the repositories

I suggest you look at each shell script and walk through the logic before executing. They are straightforward but it’s worth the time understanding what they are doing.

Let’s Do This

Remember to make sure you have:

  • installed all of the prerequisite packages
  • have plenty of RAM available on your system (2G minimum)
  • cloned build-swift from Github

Now, clone all of the required repositories:

# cd build-swift
# ./scripts/get.sh

On a high-speed SD card this step took about 15 minutes to download and write everything.

Now, compile. The Swift on ARM team uses Jenkins to run this in a headless build job, but if you use nohup to ensure your compile continues even if the terminal detaches you should be fine:

# nohup ./scripts/package.sh > swiftbuild.log&

To watch the output of the build use tail -F swiftbuild.log.

Now, be prepared to wait! A clean build of Swift on a Raspberry Pi 3 can take upwards of 6 hours. The reward is well worth it, however, and that is a swift.tar.gz bundle that can be installed on either a Raspberry Pi 2 or Pi 3 running Ubuntu Xenial (do not try to install this on a Raspbian machine, you will be sorry). I like to install Swift in /opt/swift/ like so:

# cd /opt
# mkdir -p swift/swift-3.0
# cd swift/swift-3.0
# tar -xzvf /path/to/swift.tar.gz

You can then set your PATH with export PATH=/opt/swift/swift-3.0/usr/bin:$PATH. To properly use swiftc and swift build you will also need to run the following commands:

sudo apt-get install -y libicu-dev
sudo apt-get install -y clang-3.6
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-3.6 100
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-3.6 100

Getting Help

If you are having trouble compiling feel free to join our swift-arm Slack.

Working with MySQL Databases using Swift 3.0

If you’ve read our other Swift articles you’ll know that we’re big proponents of Swift on the server. Today we’ll keep with that theme by looking at working with MySQL databases with Vapor’s MySQL wrapper.

Warning: This is not a tutorial on MySQL or SQL. If you aren’t familiar with either there are plenty of tutorials out there. We’re going to focus specifically on working with MySQL with Swift 3.0 on Linux.

Getting Started

We chose MySQL 5.7 on an Ubuntu 16.04 system for this tutorial. MySQL 5.7 introduces a number of new features, one of which is the ability to store JSON data in a more efficient manner, as well as provide capabilities to select within the JSON data. More on this later. Since MySQL 5.7 is the default MySQL on Ubuntu 16.04 we’ll go with it as our OS.

If you don’t have Swift installed you can use our apt-get repo. See this post for instructions on setting it up. As of late September 2016 Apple also began building snapshots for Ubuntu 16.04. See Swift.org for more details.

Set up our database

Our database will be called swift_test, and it should be manipulated with a MySQL user swift whose password is swiftpass. If you’ve worked with MySQL for any period of time you are probably already chanting GRANT ALL ON swift_test.* and so on. So let’s set that up:

# sudo mysql
...
mysql> create user swift;
Query OK, 0 rows affected (0.00 sec)

mysql> create database swift_test;
Query OK, 1 row affected (0.00 sec)

mysql> grant all on swift_test.* to 'swift'@'localhost' identified by 'swiftpass';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql> quit
Bye

Create a Swift Package

On to the code! Let’s create a package.

# mkdir swift_mysql
# swift package init --type executable

Update your Package.swift to look like:

Second, we’re going to be using a few helper routines to fill in some random data in our database. Create a file in the Sources directory called utils.swift and add the following:

Vapor MySQL

On to the real code, our main.swift file which will use the Vapor MySQL module.

Connecting to the Database

Add the following to Sources/main.swift:

Here we are setting up our database handle mysql. The initializer Database(host:String, user:String, password:String, database:String) is straightforward. The statement try mysql.execute("SELECT @@version") is a test to ensure we connected properly and can communicate with the database.

If our do block succeeds with no errors we can proceed to interacting with our database!

Ints and Strings

All of the calls made to MySQL will be through the execute(_:String) method. Note that this is different from using an abstraction API that provides methods like .create(table:String, ...) or .insert(table:String, .... execute takes raw SQL and passes it down through the MySQL connector.

Querying for results also uses the execute(_:String) method, but now we treat the result of the call as an array of [String:Node]. The keys of the dictionary are the column names returned.

The Node type here is a Vapor data structure that is used for converting amongst different representations. You can read more about it here. When using it with MySQL we take advantage of the Node properties int, string, object to convert from its agnostic representation to a Swift type. Thus, let bar = result["bar"]?.int gives us an Int.

Moving On

Now let’s look at a more advanced example with creating a table that contains MySQL DATE, POINT, and JSON datatypes.

Our table is called samples.

To insert a date into the database using a SQL statement we will need to appropriately format it:

Now let’s create a POINT as a Swift tuple:

Finally, we want to utilize MySQL 5.7’s new JSON datatype, and moreover we’ll use the Jay package in Swift to quickly create a JSON-string from a Swift [String:Any] dictionary.

Hint: You do not have to explicitly call out Jay as a dependency in the Package.swift file because it is included transitively by the MySQL package.

We now want to convert this to a String suitable for giving to MySQL:

Now we have our date, point, and JSON string (sample), let’s insert the data into the samples table:

Note we did use a bit of a trick with the POINT in that \(point) will expand in our string to (37.20262, -112.98785), thus the full string will be POINT(37.20262, -112.98785) which is what MySQL will expect. The entire statement string looks like:

Retrieving Results

Warning! As of this writing (September 22, 2016), there is a bug in Vapor MySQL 1.0.0 that crashes on reading a POINT datatype, so we’ll have to make do and not use SELECT * below. We’ve filed this issue against Vapor MySQL and will update the post once the issue is fixed.

In the example below we’re going to take advantage of MySQL 5.7’s ability to include JSON data in the SELECT ... WHERE clauses. Here we are looking for those samples where the speed field of the JSON data in the sample is greater than 80.

A couple of notes here. The JSON_EXTRACT function is used to return data from a JSON document, selected from the parts of the document matched by the path arguments. In our case here we want to extract the value at the path $.speed from the sample column. To extract the longitude value from our JSON document we would use the path $.gps.longitude.

To iterate over our results we use the for result in results construct in Swift, and then the if let construct to validate our result data. First, use let sample = result["sample"]?.object to get a dictionary that is built from the MySQL JSON document. This is key here! The Vapor MySQL library does not return back a String object that needs to be handed to a JSON parser; that work is already done for you, so you can begin accessing the sample dictionary directly.

The remaining lets give us our speed, temperature, and created_at. Note that created_at is a MySQL DATETIME which will read in as a String. To convert to a Date in Swift you will need to use a DateFormatter with .date(from:String).

Get the Code!

If you want to get started with less typing, check out the code from Github. Build everything with swift build, but before running the executable remember that you have to have the database, user, and grants already configured.

Handling Dates with Swift 3.0

Swift 3.0

When you take on a goal as ambitious as the Great Renaming it is a challenge to ensure that all of the reference documentation is updated. As of September 20, 2016, for example, the DateFormatter documentation contains inconsistencies and references to Swift 2.3-style APIs. As time passes this will undoubtedly be corrected, but in the meantime here are a few examples for formatting dates with the Date and DateFormatter.

The current example in the above-reference documentation is:

In Swift 3.0 this changes to:

Notice that .mediumStyle is dropped in favor of .medium. This is in line with simplified naming; we know that the type is of DateFormatter.Style so there is no reason to repeat the word Style. The same applies for .none as opposed to .noStyle.

Now, let’s look at the changes to setting the formatter’s locale:

Again, we see the simplification from Locale(localeIdentifier:) to Locale(identifier:). Less typing and to the point. Likewise the stringFromDate method of the DateFormatter has been streamlined to string(from:), which if you use the entire signature is string(from:Date). See the pattern?

Moving on to creating a Date from a String representation, the Apple documentation has this example:

Applying the principle of reducing verbiage and unnecessary words we arrive at:

The TimeZone initializer drops an extraneous three characters (for), and as expected the dateFromString method becomes date(from:).

Rules of Thumb

It should be apparent that the general rule of thumb when transitioning from Swift 2 to Swift 3 is to remove superfluous words. If you were used to writing formatter.timeStyle = .fullStyle before, get used to writing formatter.timeStyle = .full. If you see someTypeFromAnotherType() it’s likely been replaced with someType(from:AnotherType).

Speaking from experience, after working with Swift 3 for several months now, going back to Swift 2 feels overly verbose, and this is coming from someone who actually likes verbose languages. Once you get the hang of it you’ll be embracing Hemingway and eschewing Tolstoy.

Happy Swifting!

Notifications and userInfo with Swift 3.0

Xcode 8.0 Swift 3.0

Xcode 9.3 Swift 4.1

Editor’s Note: This is one of our most popular posts, so I wanted to take a moment and verify that the Swift 3.0 code presented below is still accurate with Swift 4.1. I’m happy to say it still is, so enjoy posting Notifications with userInfo in Swift 4!

Swift 3.0 has brought a number of changes to the Swift language, including the Great Renaming which brought about the end of the NS prefix on Foundation classes. NSThread is now simply Thread. NSData becomes Data. You get the idea.

That means we need to provide an update on using NSNotificationCenter, sorry, NotificationCenter with userInfo. Things have definitely changed between Swift 2 and Swift 3.

The technique for obtaining the default NotificationCenter has changed, and can now be done with let nc = NotificationCenter.default. In addition the model of using selectors has changed to specifying a block or funtion to execute when the notificaiton is received.

For example, in Swift 2 we would write:

whereas Swift 3 code would look like this:

In this example we’re instructing the notification center to deliver MyNotification notifications to the catchNotification function which has a signature of (Notification) -> Void. Alternatively we could use a trailing closure:

Post It!

Now, let’s look at posting (sending) a notification. The postNotificationName method in Swift 2.0 has been replaced with post in Swift 3.0.

The userInfo now takes [AnyHashable:Any]? as an argument, which we provide as a dictionary literal in Swift. Note that the userInfo values don’t need to be homogeneous (that’s where the Any comes in); we are sending along a String and a Date.

Handling Notifications

The guard construct serves as a good method to unwrap and verify that the expected data is in the userInfo.

To verify that the guard works properly switch out the Date() in the call to post with a String or some other object. You should see No userInfo found in notification printed to the console.

Example Source

You can try out the code above with a simple iOS project. Create a new Single View Application and replace the contents of ViewController.swift with the following:

A few notes here:

  • Notification “names” are no longer strings, but are of type Notification.Name, hence why we declare let myNotification = Notification.Name(rawValue:"MyNotification"). This allows us to use myNotification anywhere a Notification.Name is expected, i.e., the NotificationCenter.addObserver and NotificationCenter.post functions.
  • We chose to have a separate func for catchNotification here rather than utilizing a trailing closure.

And that’s it! Simple and effective.

error: invalid inferred toolchain

Invalid inferred toolchain? What?!

You’ve installed swiftenv on your shiny new Ubuntu system, obtained one of the Apple releases with swiftenv install, but when you run swift build you get error: invalid inferred toolchain. That’s no good.

Fortunately the fix is simple, you need to install clang:

sudo apt-get install clang-3.6
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-3.6 100
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-3.6 100

In this example we’re using clang-3.6 but any version 3.6 or higher should be fine.

MQTT Last Will and Testament

This is another post in a series on writing MQTT clients using Swift on Linux.

In this post we’ll look at the MQTT Last Will and Testament message. Essentially the LWT message is predefined by a client connecting to the broker. In the event the client abnormally disconnects, the broker will then broadcast the LWT to any subscribers of the LWT message topic.

For example, let’s say you are building a chat application where each client connects to a broker and then subscribes to the topic /chat/hottub. Messages then published to /chat/hottub are received by all of the subscribers. A simple but effective way to join a “chat room” (i.e., MQTT topic).

When a client leaves the chat under normal conditions we might expect a message like “Joe has left /chat/hottub.” This would be easy to do; when the user types /exit then publish an appropriate message and then terminate the client. If a client abnormally disconnects (loss of network, client crash, etc.), then what was given to the broker as the Last Will and Testament message is used instead.

Here’s how we set up the Last Will message for our MQTT client:

willMessage is a MQTTWill property of the MQTT class. MQTTWill is constructed with a topic and message. In our example here the topic will be our chat channel /chat/hottub, and the message will be a JSON string that contains our client’s ID and a simple Abnormal Disconnect string.

Get the Code

We’ve been building Swift 3.0 directly from the latest in the Apple repositories and continually upgrade our code. To use these examples you’ll need to install Swift 3.0 from our apt-get repository.

An example of our MQTT HotTub is in GitHub.

# git clone https://github.com/iachievedit/MQTTHotTub
# cd MQTTHotTub
# swift build

To test things out you’ll want to run the MQTTHotTub twice, so open a second terminal.

1__clear_____build_debug_MQTTHotTub__ssh__and_9__clear_____build_debug_MQTTHotTub__ssh_

Run the clients with .build/debug/MQTTHotTub.

Prisencolinensinainciusol

Our MQTTHotTub client simulates a chat of gibberish. Each published message is delivered as JSON:

{"client":"octxktfo", "message":"Gyxswhz nsoxfnj gz."}
{"client":"ajyhyjic", "message":"Cmr w bzwubzv mwfhtklz."}

When a client receives a message that it did not send it gets filtered out:

Remember, if we are listening to messages published to a given topic, and we publish to that topic, the client will also receive that message back as an echo. This is the purpose of filtering with cid != clientId.

You can see each client logging what they are receiving from other clients:

Received "Wlfu zrqyj tady obxnjl lupihobi nph oapplt nyidmja." from octxktfo
Received "Cmr w bzwubzv mwfhtklz." from ajyhyjic

Now, CTRL-C one of the clients, and notice what is received by the remaining client(s):

Received "Abnormal Disconnect" from octxktfo
Abnormal Disconnect
Abnormal Disconnect

This is the MQTT Last Will and Testament message in action; the aborted client had no opportunity to broadcast that it was unavailable so instead the broker sent out the client’s Last Will on the /chat/hottub topic:

{"client":"\(clientId)","message":"Abnormal Disconnect"}

Do I Need to Have a Last Will?

Need is a strong word, and the answer is no, your MQTT client does not need to supply a Last Will message. There are plenty of additional examples that provide guidance on when you might want to use one.

What’s Next?

We’re continuing to work hard on our MQTT implementation for Swift on Linux. With Last Will and Testament now working our attention will turn to implementing secure MQTT connections (MQTT SSL). Stay tuned!

Compiling Open Source Swift Foundation

I recently came across an issue with the NSThread implementation in open source Swift Foundation. I wouldn’t have ever found the issue if it hadn’t been for trying to run this code on a Raspberry Pi 3:

Our expectation here is that we will be creating and destroying a thread every second. Unfortunately, after approximately 230 threads the system resources had been exhausted and no more threads would actually start. In the end, as you can see from SR-1908, the solution was to initialize threads with system scope and a state of detached:

Philippe Hausler proposed the solution in SR-1908, and since I had a Raspberry Pi 3 to test it out on I took on the task of implementing and testing it.

Building Only Foundation

If you read the Getting Started documentation for Open Source Foundation it’s pretty clear that you need to first build Swift, clang, and llvm. If I were working on a tricked out server with plenty of CPU and fast disk, I wouldn’t mind. On a Raspberry Pi 3 though, as much of an improvement it is over its older siblings, it is still a little slow. I could also look into cross-compiling Swift, but haven’t yet rustled up the time to figure that out (and if you’ve ever worked with cross-compile environments you know it takes a good amount of time to get set up).

What we need is the ability to take advantage of an existing build tree and compile Foundation by itself. It turns out you can, otherwise, we wouldn’t have a blog post on this now would we?

Here’s what you’re going to need to do this (regardless of whether you run this on an x86 server or an ARM computer like a BeagleBone or Raspberry Pi):

  • a fully built swiftc, typically found in build/buildbot_linux/swift-linux-armv7/bin
  • a fully built swift, also in the build/buildbot_linux/swift-linux-armv7/bin directory
  • a fully built clang (the one built from the open source repositories), found in build/buildbot_linux/llvm-linux-armv7/bin directory

I’m looking to provide a “toolchain” of sorts with all of these already compiled, but for now you’ll have to build your own first. Then you will be able to build Foundation on its own.

Now, let’s look at how you use this to test something out on Foundation. Notice that we are cloning our own fork of swift-corelibs-foundation. This is important if you’re planning on issuing pull requests back into the upstream repository (i.e., Apple’s repository).

# git clone https://github.com/iachievedit/swift-corelibs-foundation
# export PREBUILT_ROOT=/root/workspace/Swift-3.0-Pi3-ARM-Incremental/build/buildbot_linux/
# SWIFTC=$PREBUILT_ROOT/swift-linux-armv7/bin/swiftc \
CLANG=$PREBUILT_ROOT/llvm-linux-armv7/bin/clang      \
SWIFT=$PREBUILT_ROOT/swift-linux-armv7/bin/swift     \
SDKROOT=$PREBUILT_ROOT/swift-linux-armv7             \
BUILD_DIR=build ./configure Debug
# /usr/bin/ninja
...
[290/290] Link: build/Foundation/libFoundation.so

First, we set an environment variable PREBUILT_ROOT to where our prebuilt Swift and associated tools are. This is used in the next step which, if you strip away the environment variables is ./configure Debug (you can use Release here as well). But, we need the environment variables SWIFTC, CLANG, SWIFT, and SDKROOT to point the configure script to our “toolchain.” Finally, the BUILD_DIR environment variable sets where all of the intermediate artifacts and final output (libFoundation.so) will be placed.

Note: I shouldn’t have to say this but somtimes you’d be surprised by what gets left in the comments. Your PREBUILT_ROOT is the location of your preexisting toolchain. Don’t expect to find anything on your system at /root/workspace/Swift-3.0-Pi3-ARM-Incremental!

Finally, /usr/bin/ninja runs our build. Once complete you should have a libFoundation.so shared library in your build/Foundation/ directory. To test it with an existing installation of Swift just copy libFoundation.so over to $YOUR_SWIFT_ROOT/usr/lib/swift/linux/libFoundation.so.

Running testcases

You can also run the Foundation test suite by adding a -DXCTEST_BUILD_DIR parameter to ./configure

# export PREBUILT_ROOT=/root/workspace/Swift-3.0-Pi3-ARM-Incremental/build/buildbot_linux/
# SWIFTC=$PREBUILT_ROOT/swift-linux-armv7/bin/swiftc \
CLANG=$PREBUILT_ROOT/llvm-linux-armv7/bin/clang      \
SWIFT=$PREBUILT_ROOT/swift-linux-armv7/bin/swift     \
SDKROOT=$PREBUILT_ROOT/swift-linux-armv7             \
BUILD_DIR=build ./configure Debug                    \
-DXCTEST_BUILD_DIR=$PREBUILT_ROOT/xctest-linux-armv7
# /usr/bin/ninja test
[4/4] Building Tests
**** RUNNING TESTS ****
execute:
LD_LIBRARY_PATH= build/TestFoundation/TestFoundation
**** DEBUGGING TESTS ****
execute:
LD_LIBRARY_PATH= lldb build/TestFoundation/TestFoundation

Running the tests requires LD_LIBRARY_PATH to be supplied with two paths: one to the libXCTest.so shared library, as well as the path to the “library under test”. We accomplish this as follows, assuming that our libFoundation.so is in ./build/Foundation, which would it would be if we were following the steps above.

# LD_LIBRARY_PATH=./build/Foundation:$PREBUILT_ROOT/xctest-linux-armv7 ./build/TestFoundation/TestFoundation
...
Test Suite 'All tests' passed at 03:16:45.315
     Executed 483 tests, with 0 failures (0 unexpected) in 37.621 (37.621) seconds

Closing Thoughts

I need to stress here that to use this technique you do need a preexisting “build toolchain” that has a Swift, clang, and llvm. Moreover, the further time passes from when your toolchain was last built to when you try to build Foundation on its own, the higher the risk that your Foundation relies on language features that weren’t present when you built your toolchain. However, if you decide to embark on working with Foundation, build your full Swift toolchain first and save the build directory to employ the technique described above.

Good luck!