Skip to content

Instantly share code, notes, and snippets.

@troughton
Last active April 5, 2019 15:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save troughton/3aeb46992647c083aaf3c201800e46f5 to your computer and use it in GitHub Desktop.
Save troughton/3aeb46992647c083aaf3c201800e46f5 to your computer and use it in GitHub Desktop.
Swift Cross-Compilation on Windows 10

Cross-compiling Swift for Windows through the Linux Subsystem for Windows

This tutorial will walk you through the process of compiling your own native programs for Windows using the Ubuntu on Windows. While the development environment and Swift compiler used here will be the standard toolchain for Linux, you'll also be able to cross-compile programs that run natively on Windows like any other executable.

Required Environment

This tutorial assumes a computer running an up-to-date 64-bit version of Windows 10 (at the time of writing, the Fall Creators' Update was the most recent build).

You'll also need Visual Studio 2017; the Community Edition is sufficient, since we'll only be using the SDKs that come with it and some command line tools.

In the Visual Studio Installer (which should itself be installed on your computer alongside Visual Studio), make sure that you select the tools for C++ development. In particular, this tutorial is tested against the 10.0.10586 Windows 10 SDK, although it may also work with more recent versions. Installing the SDKs can be done by modifying an existing Visual Studio install.

Installing Ubuntu on Windows

Microsoft provides instructions for installing the Linux subystem for Windows. This tutorial assumes that you're using Ubuntu, although other Linux variants may work; furthermore, it assumes that you are using Ubuntu 16.04 LTS, which, at the time of writing, is the version provided through the Microsoft Store.

If you're using a version of Ubuntu earlier than 16.04, you may need to update or amend these instructions as appropriate.

Ubuntu dependencies

Once Ubuntu is installed and you have Bash open, you can start installing the dependencies. We'll be using all of the same ones needed to build Swift normally along with a few extras.

Note that every command below that starts with sudo will give root access to what comes after it. You'll need it for these commands, but if you're ever unsure, try the command without sudo first and don't run as root if you don't trust the command.

Firstly, let's make sure that apt is up to date. You'll need the password that you created when you installed Ubuntu.

sudo apt-get update

Then, let's install the Swift dependencies. At the time of writing, these are:

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

However, always use the Swift README as the authoritative source.

We're going to have to install a few more dependencies such as a recent version of Clang; I used version 5.0.1. To do this, we'll need to add the LLVM apt repositories as sources.

To do this, you'll need to first edit the /etc/apt/sources.list file with a text editor. I happen to use vim (sudo apt-get install vim) for these purposes; as one alternative, nano is easier to use but had display issues at the time of writing. I'll be assuming you're using vim for the remainder of this section.

Open the file as root:

sudo vim /etc/apt/sources.list

and hit I on the keyboard to enter insert mode. At the bottom of the file, paste in the deb and deb-src lines for your version of Ubuntu, which you can find at http://apt.llvm.org. For instance, to use Clang 5.0, add the following lines to the bottom of your file:

deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-5.0 main
deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-5.0 main

Exit out of insert mode by pressing the esc key, and then save out the file and exit by typing :wq.

Back in the terminal, you now need to add the keys for the LLVM repository. Scroll down to the Install section of the LLVM apt page matching the version of Clang you chose and copy and paste the line starting with wget into your terminal.

wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -

You can now run sudo apt-get update again. Finally, we're ready to install recent versions of Clang and LLD.

sudo apt-get install clang-5.0 lld-5.0

To make it so that when you use clang on the terminal it always uses this new version, we need to update the symlinks. First, remove the existing symlinks:

sudo rm /usr/bin/clang
sudo rm /usr/bin/clang++
sudo rm /usr/bin/clang-cl

And then create new links to point to the new versions of Clang and LLD.

sudo ln -s /usr/bin/clang-5.0 /usr/bin/clang
sudo ln -s /usr/bin/clang-5.0 /usr/bin/clang++
sudo ln -s /usr/bin/clang-5.0 /usr/bin/clang-cl
sudo ln -s /usr/bin/lld-5.0 /usr/bin/lld
sudo ln -s /usr/bin/lld-5.0 /usr/bin/lld-link

Cloning Swift

While we'll be working in Bash for most of this, I recommend cloning the Swift sources onto the Windows file system so you can easily access it. For instance, I cloned the sources to my C drive:

cd /mnt/c

Note that all your Windows files can be found under /mnt/{drive letter}.

From there, follow the instructions in the Swift README under the section "Getting Sources for Swift and Related Projects". If you started in the root of the C drive, if you run ls /mnt/c/swift-source you should see swift, llvm, clang, and other assorted projects there.

Installing ICU

We're going to leave Bash for a little while and set up some other dependencies. Firstly, Swift relies on ICU; I used version 59. We're going to need a Windows build; you can download one from http://site.icu-project.org/download/59; scroll down and select the "Windows (x86 64-bit) Visual Studio 2015" binaries. Once you've downloaded and extracted the zip, move the directory into your swift-source directory. I renamed it to windows-icu, which is how I'll refer to it from now on.

If you run ls /mnt/c/swift-source from Bash again you should see windows-icu in the list; if you ls /mnt/c/swift-source/windows-icu you should see include, bin64, and lib64 subdirectories.

Setting up the Visual C and UCRT SDKs

(tip: the Tab key should auto-complete the current directory or file name you're typing in Bash)

You'll also need to copy the visualc.modulemap and ucrt.modulemap files from swift/stdlib/public/Platform (where swift is the path you cloned the Swift repository into) into the include directories of their respective SDKs and then rename them to module.modulemap.

For instance, depending on your versions, visualc.modulemap might become:

C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.11.25503\include\module.modulemap

and ucrt.modulemap might become:

C:\Program Files (x86)\Windows Kits\10\Include\10.0.10586.0\ucrt\module.modulemap
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment