Building Swift toolchain against prebuilt LLVM binaries (under Linux)

Is building of the Swift toolchain currently supported against prebuilt binary distributions of LLVM, instead of the source repository?

Builds of LLVM, at least as initiated by the Swift build process, are massive undertakings. The overall results, whether because of lack of selectivity for final targets, or because of the nature of the LLVM project, are sized around 60Gb. The repository itself requires several gigabytes.

An issue of perhaps more widespread consequences follows from the nature of Linux distributions and their packaging systems. Currently, no means are apparent to construct a distribution-based package adding the Swift toolchain to a Linux system. Prepackaged binary distributions of the toolchain for Linux integrate their own copies of LLVM. In a very basic attempt at developing a distribution package, such copies would conflict with those supplied by the packages directly supplying LLVM. Through a more advanced case, in which the conflicts would be averted by workarounds in selecting file locations, the installed size of the toolchain would be significantly bloated in comparison to one integrating with a preexisting installation of LLVM, shared across the system, including with other tools utilizing LLVM.

Therefore, it would be strongly advantageous if it were possible to undertake the following:

  1. Begin with a Linux system with LLVM already installed through distribution packages.
  2. Create a local copy of the source repository of Swift.
  3. Build the Swift toolchain against the system binaries (accompanied by any required header files) for LLVM.
  4. Package the particular build results as distribution package that depends on the LLVM package, without including in itself LLVM.

Is any support available for such build cases, as extend beyond the basic case of building the Swift toolchain in tandem to building LLVM from source?

No, it is not, as the Swift compiler is built against a periodic fork of upstream LLVM that applies Swift-specific patches, not the stock LLVM that comes in linux distros.

This seems excessive: are you building unoptimized with debug info? Obviously, release builds would not build with either and are much smaller.

This is mostly true, but several linux distros have made small modifications and got it to work. I would not say that they're "significantly bloated," as the Swift toolchain does not ship with most LLVM binaries - I only count 18 included below, plus the compiler-rt binaries in usr/lib/clang/, out of the many more LLVM usually includes:

> ls -l swift-DEVELOPMENT-SNAPSHOT-2026-03-01-a-ubi9/usr/lib
total 816276
drwxr-xr-x.  3 finagolfin finagolfin      4096 Mar  1 12:30 clang
lrwxrwxrwx.  1 finagolfin finagolfin        16 Mar  1 12:30 libclang.so -> libclang.so.21.0
lrwxrwxrwx.  1 finagolfin finagolfin        18 Mar  1 12:30 libclang.so.21.0 -> libclang.so.21.0.0
-rwxr-xr-x.  1 finagolfin finagolfin 156664280 Mar  1 12:29 libclang.so.21.0.0
lrwxrwxrwx.  1 finagolfin finagolfin        21 Mar  1 12:30 libIndexStore.so -> libIndexStore.so.21.0
-rwxr-xr-x.  1 finagolfin finagolfin   3203984 Mar  1 12:28 libIndexStore.so.21.0
lrwxrwxrwx.  1 finagolfin finagolfin        15 Mar  1 13:22 liblldb.so -> liblldb.so.21.0
lrwxrwxrwx.  1 finagolfin finagolfin        17 Mar  1 13:22 liblldb.so.21.0 -> liblldb.so.21.0.0
-rwxr-xr-x.  1 finagolfin finagolfin 278834600 Mar  1 13:19 liblldb.so.21.0.0
lrwxrwxrwx.  1 finagolfin finagolfin        14 Mar  1 12:30 libLTO.so -> libLTO.so.21.0
-rwxr-xr-x.  1 finagolfin finagolfin 114932128 Mar  1 12:29 libLTO.so.21.0
-rwxr-xr-x.  1 finagolfin finagolfin 271589584 Mar  1 13:02 libsourcekitdInProc.so
-rwxr-xr-x.  1 finagolfin finagolfin    529520 Mar  1 12:30 libswiftDemangle.so
-rwxr-xr-x.  1 finagolfin finagolfin   3461728 Mar  1 15:37 libSwiftSourceKitClientPlugin.so
-rwxr-xr-x.  1 finagolfin finagolfin   6614688 Mar  1 15:37 libSwiftSourceKitPlugin.so
drwxr-xr-x. 19 finagolfin finagolfin      4096 Mar  1 14:31 swift
drwxr-xr-x. 11 finagolfin finagolfin      4096 Mar  1 13:32 swift_static
> ls -l swift-DEVELOPMENT-SNAPSHOT-2026-03-01-a-ubi9/usr/bin
total 1705584
lrwxrwxrwx. 1 finagolfin finagolfin        34 Mar  1 12:30 aarch64-swift-linux-musl-clang++.cfg -> aarch64-swift-linux-musl-clang.cfg
-rw-r--r--. 1 finagolfin finagolfin       131 Mar  1 12:30 aarch64-swift-linux-musl-clang.cfg
lrwxrwxrwx. 1 finagolfin finagolfin         8 Mar  1 12:30 clang -> clang-21
lrwxrwxrwx. 1 finagolfin finagolfin         5 Mar  1 12:30 clang++ -> clang
-rwxr-xr-x. 1 finagolfin finagolfin 210099400 Mar  1 12:23 clang-21
lrwxrwxrwx. 1 finagolfin finagolfin         5 Mar  1 12:30 clang-cache -> clang
lrwxrwxrwx. 1 finagolfin finagolfin         5 Mar  1 12:30 clang-cl -> clang
lrwxrwxrwx. 1 finagolfin finagolfin         5 Mar  1 12:30 clang-cpp -> clang
-rwxr-xr-x. 1 finagolfin finagolfin  93196808 Mar  1 12:30 clangd
-rwxr-xr-x. 1 finagolfin finagolfin  71651680 Mar  1 15:45 docc
lrwxrwxrwx. 1 finagolfin finagolfin         3 Mar  1 12:30 ld64.lld -> lld
lrwxrwxrwx. 1 finagolfin finagolfin         3 Mar  1 12:30 ld.lld -> lld
-rwxr-xr-x. 1 finagolfin finagolfin 130537448 Mar  1 12:23 lld
-rwxr-xr-x. 1 finagolfin finagolfin    784960 Mar  1 13:20 lldb
-rwxr-xr-x. 1 finagolfin finagolfin    168648 Mar  1 12:55 lldb-argdumper
-rwxr-xr-x. 1 finagolfin finagolfin   2123376 Mar  1 13:20 lldb-dap
-rwxr-xr-x. 1 finagolfin finagolfin 187059472 Mar  1 13:19 lldb-server
lrwxrwxrwx. 1 finagolfin finagolfin         3 Mar  1 12:30 lld-link -> lld
-rwxr-xr-x. 1 finagolfin finagolfin  27138752 Mar  1 12:23 llvm-ar
-rwxr-xr-x. 1 finagolfin finagolfin   8429400 Mar  1 12:24 llvm-cov
-rwxr-xr-x. 1 finagolfin finagolfin  28448416 Mar  1 12:23 llvm-nm
-rwxr-xr-x. 1 finagolfin finagolfin   8176992 Mar  1 12:23 llvm-objcopy
-rwxr-xr-x. 1 finagolfin finagolfin  29639024 Mar  1 12:23 llvm-objdump
-rwxr-xr-x. 1 finagolfin finagolfin   9845936 Mar  1 12:24 llvm-profdata
lrwxrwxrwx. 1 finagolfin finagolfin         7 Mar  1 12:30 llvm-ranlib -> llvm-ar
-rwxr-xr-x. 1 finagolfin finagolfin   9447616 Mar  1 12:24 llvm-symbolizer
-rwxr-xr-x. 1 finagolfin finagolfin    198688 Mar  1 13:27 plutil
-rwxr-xr-x. 1 finagolfin finagolfin     17336 Mar  1 12:56 repl_swift
drwxr-xr-x. 2 finagolfin finagolfin      4096 Mar  1 13:22 sdk-module-lists
-rwxr-xr-x. 1 finagolfin finagolfin 237495448 Mar  1 15:36 sourcekit-lsp
lrwxrwxrwx. 1 finagolfin finagolfin        12 Mar  1 13:22 swift -> swift-driver
-rwxr-xr-x. 1 finagolfin finagolfin     11862 Mar  1 12:05 swift-api-checker.py
lrwxrwxrwx. 1 finagolfin finagolfin        14 Mar  1 13:22 swift-api-digester -> swift-frontend
lrwxrwxrwx. 1 finagolfin finagolfin        14 Mar  1 13:22 swift-autolink-extract -> swift-frontend
lrwxrwxrwx. 1 finagolfin finagolfin        13 Mar  1 14:31 swift-build -> swift-package
-rwxr-xr-x. 1 finagolfin finagolfin  36029984 Mar  1 15:58 swift-build-sdk-interfaces
-rwxr-xr-x. 1 finagolfin finagolfin   1562216 Mar  1 13:33 swift-build-tool
lrwxrwxrwx. 1 finagolfin finagolfin        12 Mar  1 13:22 swiftc -> swift-driver
lrwxrwxrwx. 1 finagolfin finagolfin        14 Mar  1 13:22 swift-cache-tool -> swift-frontend
lrwxrwxrwx. 1 finagolfin finagolfin        14 Mar  1 13:22 swiftc-legacy-driver -> swift-frontend
-rwxr-xr-x. 1 finagolfin finagolfin   2162096 Mar  1 12:30 swift-demangle
-rwxr-xr-x. 1 finagolfin finagolfin  36021136 Mar  1 15:58 swift-driver
lrwxrwxrwx. 1 finagolfin finagolfin        13 Mar  1 14:31 swift-experimental-sdk -> swift-package
-rwxr-xr-x. 1 finagolfin finagolfin  53532464 Mar  1 15:23 swift-format
-rwxr-xr-x. 1 finagolfin finagolfin 269487448 Mar  1 12:59 swift-frontend
-rwxr-xr-x. 1 finagolfin finagolfin   9431192 Mar  1 15:56 swift-help
lrwxrwxrwx. 1 finagolfin finagolfin        14 Mar  1 13:22 swift-legacy-driver -> swift-frontend
-rwxr-xr-x. 1 finagolfin finagolfin 254401560 Mar  1 14:31 swift-package
lrwxrwxrwx. 1 finagolfin finagolfin        13 Mar  1 14:31 swift-package-collection -> swift-package
lrwxrwxrwx. 1 finagolfin finagolfin        13 Mar  1 14:31 swift-package-registry -> swift-package
-rwxr-xr-x. 1 finagolfin finagolfin     18520 Mar  1 13:02 swift-plugin-server
lrwxrwxrwx. 1 finagolfin finagolfin        13 Mar  1 14:31 swift-run -> swift-package
lrwxrwxrwx. 1 finagolfin finagolfin        13 Mar  1 14:31 swift-sdk -> swift-package
lrwxrwxrwx. 1 finagolfin finagolfin        14 Mar  1 13:22 swift-symbolgraph-extract -> swift-frontend
lrwxrwxrwx. 1 finagolfin finagolfin        14 Mar  1 13:22 swift-synthesize-interface -> swift-frontend
lrwxrwxrwx. 1 finagolfin finagolfin        13 Mar  1 14:31 swift-test -> swift-package
-rwxr-xr-x. 1 finagolfin finagolfin  29322264 Mar  1 14:34 wasmkit
lrwxrwxrwx. 1 finagolfin finagolfin         3 Mar  1 12:30 wasm-ld -> lld
lrwxrwxrwx. 1 finagolfin finagolfin        33 Mar  1 12:30 x86_64-swift-linux-musl-clang++.cfg -> x86_64-swift-linux-musl-clang.cfg
-rw-r--r--. 1 finagolfin finagolfin       130 Mar  1 12:30 x86_64-swift-linux-musl-clang.cfg

None, as the Swift compiler likely would not work without the LLVM patches, and Swift's version of lldb definitely doesn't.

I suggest you take a look at popular packaging scripts like Fedora's in my last link and follow their lead instead.

Are LLVM maintainers receptive to eventual integration of the main project with the submitted patches? Why is LLVM in its general design not compatible with the Swift language, considering that a design objective of LLVM is independence of the high-level programming language from the details of generating target-specific compiled binaries?

I followed advice to invoke the following command, because it was vastly more straightforward than other instructions that were available:

$ utils/build-script --release-debuginfo

I would appreciate advice for an equally straightforward process not resulting in the bloat of debug information.

I have analyzed the binaries distributed for Ubuntu. Almost the entirety of the downloadable archive consists of binaries, dominantly shared libraries, for Clang or LLDB.

Concerning installation on Linux, a complicating factor is collision with binaries from the main distributions of the same parent projects. For example, a system may host an installation of the main LLVM project alongside the Swift toolchain. The problems in relation to such collisions include both the possibility of identical filenames supplied by different packages, and redundancy in functionality of large libraries or executables.

Patches are continually being upstreamed and there was talk of getting it all in eventually, so no patching would be required, but I don't know how realistic that is.

I suspect the Swift authors push LLVM more than other languages, which sometimes also maintain their own patches.

Run utils/build-script --help to see the available flags, and look at utils/build-presets.ini to see common flags used, particularly on the CI used to generate release toolchains. I use the flags -RA for release builds, which means release with no assertions or debug info.

As I showed above, that is not the case: most of it is Swift-specific binaries, like swift-frontend, the Swift compiler itself. You are right that the clang/lldb binaries take up a significant minority of space also, but they do not dominate.

Yes, that is a well-known result that has been extensively discussed here and on GitHub and is easily worked around, as in the Fedora install I suggested you look at.

AFAIU there are at least a few people who maintain both upstream and downstream at the same time, so it's not a primary concern.

One thing to keep in mind is that there's no fixed set of patches to be upstreamed, it's always a moving target. LLVM and Swift release cycles are not exactly aligned. Even if for a given Swift release a set of patches is fully upstreamed (if that's even possible, because patch review is also not aligned with release cycles), new patches are likely to appear downstream in the meantime.

As an example, Swift 6.3 and main branch are not developed against main branch of upstream LLVM and Clang, they target upstream 21.x branch. APIs and SPIs of both projects are a moving target. Not locking LLVM and Clang to a release branch within Swift would introduce an incredible amount of churn, as a commit to main branch of Clang, LLVM, or LLDB would easily break main branch of Swift. Targeting an upstream release branch reduces that churn and breakage risk.

The design objective of LLVM seems to be general and complete coverage of high-level programming languages. It is concerning that a lack of convergence may represent overall limitations of LLVM, perhaps prompting reflection over the compatibility of the two projects.

I reviewed both, but remain confused about a set of flags that prompts the most basic build of of the local working copy of the project. Flags limited to -RA was not successful.

Do you have any concrete recommendations for easily interpreting the relevant points of the sources you mention?

After more complete analysis, I agree with the characterization of a "significant minority".

The larger issue remains, that binaries in the Swift distributions occupy the same locations as binaries from the main distribution of parent projects, without allocating themselves into separate spaces. It may be argued that Swift distributions should be organized such as to assign different locations, if not also alternative base file names, for the files representing parent projects modified from their mainstream versions.

Whether or not distribution-specific packages have incorporated solutions, as various workarounds undoubtedly may be utilized, the problem ought to be addressed at the level of the official precompiled binaries offered directly by the Swift project.

The referenced discussion is massive, and touches on many different concerns.

Would you mind identifying the point (e.g. via a link to one or more specific comments) where the particular issue is introduced or resolved in the discussion?

To be clear, I am particularly referring to the issue of multiple packages providing files with colliding names and locations, yet incompatible or conflicting functionality.

I understand the problems about instability across releases of LLVM.

I suppose the solution is first to integrate new patches with a target release, and then further to merge the resulting branch with a more recent release or development branch.

Nah, any software project grows in new directions, and I imagine that the Swift devs, who often are or were LLVM devs, keep adding new LLVM features, which they may then upstream.

First off, I never asked the question you attribute to me, so I ask that you carefully remove any AI slop you are using.

Using -RA alone should work, as I show in a container here, so you'll have to be more specific about what didn't work for you.

I suggest you skim that thread till you find the relevant comments, as there is a detailed discussion of packaging there, but the best approach is to actually look at the Fedora packaging script I pointed you at twice above.

I simply misplaced the paragraph in relation to the quote formatting. There is no need for expressing animus. I am not using any AI tools. I have edited the earlier post to correct the error.

I encountered some unexpected and unrelated problems shortly after posting my original questions. I am trying to keep the discussion alive, and regret that I am not investing the full attention you feel is deserved.

I apologize.

The option seems to introduce a dependency for a component called swift-driver. I can try to integrate it into the build environment. The build method I described earlier apparently does not feature the same dependency.

The basic fact is that for someone lacking familiarity with many of the background issues, history, and tools, the available instructions tend to seem quite opaque. It is certainly helpful to receive tips for isolating the relevant information from the general sources.

I am looking for an earlier reference as you claim to have provided, but it happens that I find none.

Regardless, I will review the script.

No, pretty much all options we discussed here will require building swift-driver in some way. Don't hesitate to paste your build logs to gist.github.com or some site like that and link them here if you are unable to build.

The problem is those instructions are quite detailed, including linking to exact distro package lists we install before building, and extensively used, so it is unlikely that you would go wrong if you simply followed them carefully, though certainly possible.

I mentioned the Fedora build scripts twice and linked you to a repology.org webpage that links to Swift build scripts for several linux distros, including Fedora. I went to that page myself now to get this Fedora build script link for you.

I understand, but it would be instructive to be offered an explanation for the reason the particular component is required in such cases despite being unneeded in my original build process (even though the process seems to be an inappropriate choice for other reasons).

I will review the document.

I will also note that the title is misleading in relation to the general objective, and that the location somewhat obscure. Referencing the document as relevant is constructive, but not so is faulting someone unfamiliar with the ecosystem for not already having found the document.

It had been my conclusion, following a genuine attempt to find thorough documentation for the build process, that no such document has been provided.

Regardless, following my initial review of the document, it does appear that the recommended invocation of the build script, is not different from the one I mentioned originally.

It is helpful that you have the insight and knowledge to connect the relevant pieces, but again, not helpful is faulting someone for not following all of the connections you have not clarified explicitly.

Regardless, I will review the suggested sources.

1 Like

It suffices most of the time to say the component is pretty much required, so if you want to know why, you'll have to ask.

In this case, swift-driver is a new implementation of the part of the Swift compiler that handles CLI arguments, written in Swift, but the old version, written in C++, has been kept around. Generally, build-script will make sure swift-driver is built, but it will fall back to the old one if not.

Yep, that's why I assumed you had already seen that doc, but not followed it carefully.

I told you in my first response:

then followed up with

What information was missing for you to click on that link, then follow the Fedora links I explicitly mentioned?

The Fedora script maintains the original file tree, and installs symbolic links for the user-facing executable utilities.

This solution is obviously the most straightforward, but I was hoping a cleaner solution was possible.

The script was useful for providing the specific set of utilities that have been designated as user facing, and therefore, should be accessible through the system path.

Incidentally, based on tests with the precompiled distribution for Ubuntu, symbolic links are not adequate, in such a case, because of breakage locating resources such as linked libraries. Shell wrapper scripts were required instead.

I have not yet had an opportunity to read through the entire conversation on Github, however.

These wrappers were added by @SteveM in the official Ubuntu package or by you locally?

@SteveM asked several questions about packaging for Debian/Ubuntu and got many answers from several members of the Swift team, so I thought you may find that thread useful too. I suggest you skim it for matters that you want to know about also.

An archived distribution of binaries for Ubuntu is provided directly by the Swift developers.

I have augmented it with wrappers while attempting to develop a more automated and comprehensive solution for installing Swift on an Ubuntu system.