Context
A few weeks ago, I announced that I had managed to package Swift 5.10.1 for Gentoo using the official binaries built for Fedora 39. Fortuitous timing, of course, because as of a few days ago, Gentoo officially no longer supports the gold
linker as being effectively abandoned upstream. Gentoo has used ld
/lld
as its default linker (depending on profile) for years while allowing you to install gold
if you want, but packages can now no longer rely on gold
. This is a problem, because all of the prebuilt Swift binaries currently built for Linux default to using gold
, since it's readily available on those systems, and means that I'll need to transition over to source builds of Swift in order to keep packaging it.
In order to do this, I need to:
- Build the Swift project using
lld
on Linux in such a way that, - The built Swift defaults to also using
lld
I haven't gotten to explore (2) yet, though, because I cannot get the Swift project to build using lld
.
(For reference, the latest Gentoo profile uses Clang + LLVM 17 systemwide)
What I've Tried
The base build-script
invocation I'm currently using is
./utils/build-script \
--verbose-build \
--release \
--swift-install-components='autolink-driver;compiler;clang-resource-dir-symlink;libexec;stdlib;swift-remote-mirror;sdk-overlay;static-mirror-lib;toolchain-tools;license;sourcekit-inproc' \
--llvm-install-components='llvm-ar;llvm-cov;llvm-profdata;IndexStore;clang;clang-resource-headers;compiler-rt;clangd;lld;LTO;clang-features-file' \
--llbuild --skip-test-llbuild \
--swiftpm --skip-test-swiftpm \
--swift-driver --skip-test-swift-driver \
--xctest --skip-build-xctest \
--libicu --skip-test-libicu \
--swiftdocc --skip-test-swiftdocc \
--lldb --skip-test-lldb \
--foundation --skip-test-foundation \
--libdispatch --skip-test-libdispatch \
--indexstore-db --skip-test-indexstore-db \
--sourcekit-lsp --skip-test-sourcekit-lsp \
--bootstrapping=bootstrapping \
--skip-early-swift-driver --skip-early-swiftsyntax
Most of these flags are pulled directly from the presets.ini
for the Linux buildbot, with bootstrapping enabled (and since the system doesn't have a Swift installation, we have to bootstrap and skip the early Swift driver and Swift Syntax; I don't know what the bootstrapping story will be for Swift 6, but one thing at a time).
-
If I run this invocation, the project manages to build LLVM and cmark before failing to build Swift due to trying to link using
-fuse-ld=gold
-
If I add
--extra-cmake-options="-DSWIFT_USE_LINKER=lld"
to force the usage oflld
, the project manages to build LLVM and cmark, before failing to build Swift due to missing symbols in Swift- It appears from searching around that
lld
behavior differs for ELF around--gc-sections
, and the missing symbols are due to them being GC'd out by default
- It appears from searching around that
-
If I add
--extra-cmake-options="-DSWIFT_USE_LINKER=lld" --extra-swift-args="^.*\$;-Xlinker\;-z\;-Xlinker\;nostart-stop-gc"
, the project manages to build LLVM, cmark, Swift, and a few other dependencies before another one down the road fails to build due to-fuse-ld=gold
-
It seems that all dependencies respect the
LLVM_USE_LINKER
setting (including Swift), so if I try--extra-cmake-options="-DLLVM_USE_LINKER=lld" --extra-swift-args="^.*\$;-Xlinker\;-z\;-Xlinker\;nostart-stop-gc"
, LLVM itself doesn't build due to undefined symbols:FAILED: lib/libIndexStore.so.15git : && /usr/lib/llvm/17/bin/clang++ --target=x86_64-unknown-linux-gnu -fPIC -Wno-unknown-warning-option -Werror=unguarded-availability-new -fno-stack-protector -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-class-memaccess -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wno-comment -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -Wno-nested-anon-types -O3 -DNDEBUG -Wl,-z,defs -Wl,-z,nodelete -fuse-ld=lld -Wl,--color-diagnostics -Wl,--version-script,"/home/itai/Development/swift-project/build/Ninja-ReleaseAssert/llvm-linux-x86_64/tools/clang/tools/IndexStore/IndexStore.exports" -shared -Wl,-soname,libIndexStore.so.15git -o lib/libIndexStore.so.15git tools/clang/tools/IndexStore/CMakeFiles/IndexStore.dir/IndexStore.cpp.o -Wl,-rpath,"\$ORIGIN/../lib:" lib/libclangIndex.a lib/libclangIndexDataStore.a lib/libLLVMSupport.a lib/libclangIndex.a lib/libclangFormat.a lib/libclangToolingInclusions.a lib/libclangFrontend.a lib/libclangDriver.a lib/libLLVMWindowsDriver.a lib/libclangParse.a lib/libclangCAS.a lib/libLLVMOption.a lib/libLLVMRemoteCachingService.a lib/libLLVMCAS.a lib/libLLVMRemoteNullService.a lib/libclangSerialization.a lib/libclangSema.a lib/libclangAPINotes.a lib/libclangEdit.a lib/libclangAnalysis.a lib/libclangASTMatchers.a lib/libclangAST.a lib/libLLVMFrontendOpenMP.a lib/libLLVMScalarOpts.a lib/libLLVMAggressiveInstCombine.a lib/libLLVMInstCombine.a lib/libLLVMTransformUtils.a lib/libLLVMAnalysis.a lib/libLLVMProfileData.a lib/libLLVMSymbolize.a lib/libLLVMDebugInfoPDB.a lib/libLLVMDebugInfoMSF.a lib/libLLVMDebugInfoDWARF.a lib/libLLVMObject.a lib/libLLVMMCParser.a lib/libLLVMMC.a lib/libLLVMDebugInfoCodeView.a lib/libLLVMIRReader.a lib/libLLVMAsmParser.a lib/libLLVMTextAPI.a lib/libclangSupport.a lib/libclangToolingCore.a lib/libclangRewrite.a lib/libclangLex.a lib/libclangBasic.a lib/libLLVMBitReader.a lib/libLLVMCore.a lib/libLLVMBinaryFormat.a lib/libLLVMRemarks.a lib/libLLVMBitstreamReader.a lib/libclangDirectoryWatcher.a lib/libLLVMSupport.a -lrt -ldl -lm /usr/lib64/libz.so /usr/lib64/libzstd.so /usr/lib64/libtinfo.so lib/libLLVMDemangle.a && : ld.lld: error: version script assignment of 'LLVM_15' to symbol 'indexstore_store_units_apply' failed: symbol not defined ld.lld: error: version script assignment of 'LLVM_15' to symbol 'indexstore_store_set_unit_event_handler' failed: symbol not defined ld.lld: error: version script assignment of 'LLVM_15' to symbol 'indexstore_occurrence_relations_apply' failed: symbol not defined ld.lld: error: version script assignment of 'LLVM_15' to symbol 'indexstore_record_reader_search_symbols' failed: symbol not defined ld.lld: error: version script assignment of 'LLVM_15' to symbol 'indexstore_record_reader_symbols_apply' failed: symbol not defined ld.lld: error: version script assignment of 'LLVM_15' to symbol 'indexstore_record_reader_occurrences_apply' failed: symbol not defined ld.lld: error: version script assignment of 'LLVM_15' to symbol 'indexstore_record_reader_occurrences_in_line_range_apply' failed: symbol not defined ld.lld: error: version script assignment of 'LLVM_15' to symbol 'indexstore_record_reader_occurrences_of_symbols_apply' failed: symbol not defined ld.lld: error: version script assignment of 'LLVM_15' to symbol 'indexstore_unit_reader_dependencies_apply' failed: symbol not defined ld.lld: error: version script assignment of 'LLVM_15' to symbol 'indexstore_unit_reader_includes_apply' failed: symbol not defined clang++: error: linker command failed with exit code 1 (use -v to see invocation)
It seems that the build script for LLVM toggles some setting when
LLVM_USE_LINKER
is explicitly set, because it useslld
just fine when I don't set that -
I've also tried using
--extra-cmake-options="-DLLVM_USE_LINKER=lld,-DLLVM_NO_DEAD_STRIP:BOOL=TRUE"
because--gc-sections
is disabled whenLLVM_NO_DEAD_STRIP
isn't set, but this doesn't appear to be the the issue -
I've also tried removing
--indexstore-db --skip-test-indexstore-db
but it doesn't make a difference, as expected -
I've also tried, in conjunction with the above, pulling a page from
docs/OpenBSD.md
and adding--skip-build-clang-tools-extra --skip-build-compiler-rt --llvm-targets-to-build=host
just in case it made a difference, but no dice
Is there a way to reliably build the Swift project on Linux with lld
?
I'm not sure whether this is a supported configuration at all, or whether I should expect this to work. I could try somehow setting LLVM_USE_LINKER=lld
for all dependencies other than LLVM itself, but I'm not sure that's a better solution than having consistent flags for compilation everywhere.
Are there any other flags or toggles I should be setting or trying to get things up and running? Thanks!