How to Build & Customize Your Own Swift Compiler!

Pedro RojasPedro Rojas
6 min read

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:

  1. 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.

  2. 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).

  3. 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! 😅

  4. RAM is also important. I’m assuming you use macOS. Make sure you have at least 8 GB (16 GB recommended).

  5. 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:

  1. Latest version of Xcode. It will install and provide a lot of useful resources for compilation and execution.

  2. 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 scripts

  • For ninja and sccache, 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

0
Subscribe to my newsletter

Read articles from Pedro Rojas directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Pedro Rojas
Pedro Rojas