Building and testing Swift packages on Windows using GitHub Actions
Runway handles the release coordination and busywork so you can focus on building great apps. You do the building, we'll do the shipping.
Swift is a great language for writing cross-platform libraries and command-line applications. While Swift is commonly used on Apple platforms and Linux-based operating systems, it is also possible to run Swift programs on Windows.
Having said this, setting up a Windows development environment for Swift on a non-Windows machine can be a bit of a challenge as cross-compilation is highly complex and I didn’t manage to get Docker working locally either.
Thankfully, there is an easy way of setting up a CI/CD pipeline to build and test your Swift packages on Windows using GitHub Actions thanks to an amazing action by Saleem Abdulrasool, the driving force of Swift on Windows.
Building the workflow
Let’s consider we have a Swift package with a single executable target and product and we want to make it available for Windows users.
To do so, we can create a GitHub Actions workflow that runs on every push to the main
branch, builds and tests the package on a Windows machine and uploads the executable as an artefact:
name: Build for Windows
on:
push:
branches:
- main
build-windows-executable:
name: Build Windows Executable
# 1
runs-on: windows-latest
steps:
# 2
- uses: compnerd/gha-setup-swift@main
with:
branch: swift-5.6-release
tag: 5.6-RELEASE
# 3
- uses: actions/checkout@v4
# 4
- run: git config --global core.protectNTFS false
# 5
- run: swift build -c release --static-swift-stdlib --product ReadingTimeCLI
# 6
- run: cp .build\release\ReadingTimeCLI.exe ReadingTimeCLI.exe
# 7
- uses: actions/upload-artifact@v3
with:
name: ReadingTimeCLI-windows.exe
path: ReadingTimeCLI.exe
Let’s break down the workflow above step by step:
- We specify that the workflow should run on the most up-to-date Windows machine available.
- We use the gha-setup-swift action by Saleem Abdulrasool which will make the Swift toolchain available on the machine.
- We check out the repository.
- We disable NTFS protection as it can cause issues when copying files and cloning the repository.
- We build the package using the
swift build
command. We specify the--static-swift-stdlib
flag to statically link the Swift standard library. - We copy the executable from the build folder to the root of the repository. We must remember to use the backslash (
\
) as the path separator as opposed to what we would normally use on Unix systems (/
). - We upload the executable as an artefact using GitHub’s own actions/upload-artifact action so that we can download it later.
You might run into some issues when SPM resolves the package’s dependencies due to the way git works on Windows. For example, git can’t check out files that contain colons
:
in their paths. If you want to learn how you can get around these issues, check out this article on my blog.