How to Build & Customize Your Own Swift Compiler!

Table of contents

In this article, I'll show you how to modify and compile your own version of Swift. This means diving into the actual Swift language codebase.
As you may know, Swift is an open-source language, which means anyone can contribute and experiment with it.
I was working on a video about how random numbers are generated in Swift. I needed to debug Swift's source code to understand the process better, but I quickly realized it wasn't as easy as I had hoped 😬. To make it even more challenging, there isn't much documentation available to help.
That's why I'm making this article: to share my experience of downloading the source code, modifying it, and compiling a custom version of Swift. My goal is to make the process as easy to understand as possible.
Before we dive in, I want to clarify a few important things:
I’m not an expert in this. The steps I’ll show you may not be the most optimal, but they worked for me. You’ll also need to adjust some settings on your local machine, so proceed carefully and read the entire article before trying it yourself.
This is for local experimentation only. If you’re looking to contribute to the Swift repo regularly, that would require additional knowledge, which is beyond the scope of this article (see references at the end).
Compiling Swift requires a lot of disk space. It’s recommended to have at least 150 GB. Trust me, I learned this the hard way after running out of storage multiple times! 😅
RAM is also important. I’m assuming you use macOS. Make sure you have at least 8 GB (16 GB recommended).
Lastly, this article is intentionally short to get straight to the point. If you are looking for a detailed explanation of all the steps below, I recommend watching my video (https://youtu.be/Rg3wsgNygYA) where I explain everything in detail.
All right, let’s get started!
Step 1: Download Swift
Clone Swift’s repo in your computer:
mkdir swift-source
cd swift-source
git clone https://github.com/swiftlang/swift.git #you can clone it by SSH as well
I recommend you to keep all your swift work in a dedicated folder. In my case, it would be “swift-source”.
Step 2: Download Utility Repos
Next, let’s run the following command:
swift/utils/update-checkout --clone
it will automatically clone and configure all the necessary repositories required to build Swift, for example LLVM and CLang to support compilation, Core libraries such as Foundation and Grand Central Dispatch, and many more tools.
Step 3: Install Dependencies
Now we will have to download the following dependencies:
Latest version of Xcode. It will install and provide a lot of useful resources for compilation and execution.
Install the following dependencies through command line using
brew
:
brew install cmake ninja sccache
Step 4: Check Dependencies
Review if the dependencies were installed correctly using —-version
command:
cmake --version
should print 3.24.2 or higher.python3 --version
should be at least 3.6. Python is essential for running the build scriptsFor
ninja
andsccache
, just make sure--version
command works correctly.Lastly, If your mac is running on Apple Sillicon, ensure all the installed dependencies are built for arm64. You can check this by using the command: “
file $(which <>YOUR_DEPENDENCY)
”, for example:file $(which python3)
should shows “arm64”, otherwise Swift won’t compile.
Step 5: Edit Swift Standard Library
Swift code contains a lot of pieces, like the compiler, parser and many more things, but to get started. For this demo, I will make a small update in the String
struct from the Swift Standard Library.
To do that, let’s find String.swift
file from this path:
swift→stdlib→public→core
Let’s proceed to open String.swift
using VSCode
, not Xcode
. This will be our IDE to work through the rest of the article.
If you want to learn why I didn’t use Xcode, please watch my video for more details.
Make a Room and insert this extension:
extension String {
public var swiftAndTips: String {
print("Subscribe to @swiftandtips on Youtube!")
return self
}
}
I’m happy adding this message, but feel free to write whatever you want. Now save the file, and it’s time to build our “custom” library.
Step 6: Building Custom Swift
Let’s run build-script in the terminal:
swift/utils/build-script --skip-build-benchmarks \\
--swift-darwin-supported-archs "$(uname -m)" \\
--release-debuginfo --swift-disable-dead-stripping \\
--bootstrapping=hosttools --sccache
This command will build your new version of Swift by generating a custom Swift toolchain with optimizations, debug information, and assertions, using Ninja as the build system.
Once this command starts running, it's a good time to make a coffee ☕️, read a book 📖, or perhaps watch my videos on YouTube 😉. On my machine with an M1 Max and 32 GB of RAM, this building process takes about 2 hours! So you may expect more or less time depending on your configuration.
Once this build process is complete, you’ll have a new folder under swift-source/build/Ninja-RelWithDebInfoAssert
with all the binaries to compile and execute a custom version of Swift, yay!
If you got any build issue, please take a look to this troubleshooting page: https://github.com/swiftlang/swift/blob/main/docs/HowToGuides/GettingStarted.md#troubleshooting-build-issues
Step 7: Create a Demo “app”
To keep it simple, I will create a single swift file called “RandomDemo.swift” and I will add the following code calling the new swiftAndTips property that I created earlier:
let message = "Hello, Swift!"
print(message.swiftAndTips)
You can save this file anywhere, but in my case, I’m saving it inside of swift-source
folder.
Step 8: Compiling the Demo File
Now it’s time to compile the file. But first let’s compile it using the default Swift version from Xcode. To do that, open the terminal and use the following command:
xcrun swiftc RandomDemo.swift
If you press enter, you should expect an error, because swiftAndTips doesn’t exist in the Standard Library:
Now let’s change the compiler from the one we generate with build-script. replace swiftc from the one in this folder:
xcrun build/Ninja-RelWithDebInfoAssert/swift-macosx-arm64/bin/swiftc Demo.swift
This time, we should see any issue! 🎉
Great! It’s finally time to run the executable. Let’s run it using ./ command:
./RandomDemo
Aaaaaand….. wait what??:
Step 9: Set The Dynamic Linker Library Path
One last step is to set DYLD_LIBRARY_PATH
the custom library compiled by Ninja using the following command:
export DYLD_LIBRARY_PATH=/<FULL_PATH_TO_SWIFT_PROJECT>/build/Ninja-RelWithDebInfoAssert/swift-macosx-arm64/lib/swift/macosx
I'm leaving out many important details about this linking process. If you haven't watched my video yet, now is a good time to do so.
Type echo $DYLD_LIBRARY_PATH
and you should see this location set:
Finally, try again ./Random.swift
and see the results:
Congratulation, You have learned how to configure and run your own custom version of Swift! 🥳
Wrap up
In this article, I shared my experience with debugging and setting up a custom version of Swift. I realize there's much more to learn if you want to fully contribute to Swift. If you're interested, I highly recommend checking out the links in the next section.
Also, let me know if you want to learn more about developing and contributing to the Swift language. I'll be happy to help you!
That’s all for me! Remember, my name is Pitt and this… this is swiftandtips.com! Thanks for reading and have a great day! ❤️
References
My video: https://youtu.be/Rg3wsgNygYA
https://github.com/swiftlang/swift/blob/main/docs/HowToGuides/GettingStarted.md
https://forums.swift.org/t/link-against-custom-built-swift-stdlib/55765
https://github.com/swiftlang/swift/blob/main/docs/HowToGuides/GettingStarted.md#next-steps
https://github.com/swiftlang/swift/blob/main/docs/HowToGuides/FirstPullRequest.md
Subscribe to my newsletter
Read articles from Pedro Rojas directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
