Cannot compile Swift code that uses Foundation with CMake and `-static-stdlib`

I’m trying to use CMake to build a Swift program, because SwiftPM using C++ libraries with SwiftPM on Windows seems more difficult, but I’m running into trouble.

# CMakeLists.txt
cmake_minimum_required(VERSION 3.29)
project(broken LANGUAGES Swift)

add_executable(broken Main.swift)
target_compile_options(broken PRIVATE -static-stdlib)
target_link_options(broken PRIVATE -static-stdlib)
// Main.swift
import Foundation

Bundle.main
mkdir build && cmake -G Ninja .. && ninja

results in loads of linker errors:
Linker Errors - Pastebin.com (piped to head –bytes 256KiB because of pastebin.com limits)

This doesn’t occur when using SwiftPM, is this a known issue with -static-stdlib?

Shouldn’t that be -static-swift-stdlib?

Don’t think so:

$ swiftc --help
...
  -static-executable      Statically link the executable
  -static-stdlib          Statically link the Swift standard library
  -static                 Make this module statically linkable and make the output of -emit-library a static library.
...
1 Like

+ SwiftPM passes -static-stdlib when called with --static-swift-stdlib.

Are you compiling on Windows? I copied your example exactly on Linux and did not experience any problems. Maybe @compnerd could speak to this if you’re on Windows…

The log indicates that the build is for Linux. It appears as though CoreFoundation is missing. This is odd because we have at least two ways to indicate the dependency: either the extension we use in swift (swift-autolink-extract) or the response file we inject for static linking. I would be recommend investigating that linker invocation and why neither of those are triggering the link dependency.

Did you do so with CMake/ninja or just by manually passing in the source file yourself?

@needlesslygrim, as Saleem says, something is going wrong when linking. I tried running basically the same command in one line, swiftc -v Main.swift -static-stdlib, and didn't have an issue. However, if you examine the output there, you will see a bunch of Swift runtime libraries automatically added:

-l_FoundationCShims -l_FoundationCollections -lswiftSwiftOnoneSupport -lswiftCore -lswift_Concurrency -lswift_StringProcessing -lswift_RegexParser -lswiftSynchronization -lswiftGlibc -lBlocksRuntime -ldispatch -lswiftDispatch -l_FoundationICU -lCoreFoundation -lFoundation -lFoundationEssentials -lFoundationInternationalization

My guess is that CMake's Swift support either doesn't properly work with the Swift compiler's support for linking against the static stdlib, so CMake sets up ninja to separately compile your code then link it and loses that linker info, or the way you are configuring it is unexpected. Maybe @etcwilde, who added some Swift support to CMake, can chime in.

When I originally added the support for Swift in CMake there wasn't anything specific for the static standard library. The reason for that is that the support for it is pretty much entirely on the driver side, the user simply passes in -static-stdlib. This mirrors how C++ is handled: -static-stdlibc++. Neither of these are explicitly added into CMake, it is a user controllable behaviour with the standard CMAKE_Swift_FLAGS or CMAKE_CXX_FLAGS property.

I do wonder if we accidentally broke this configuration with recent refactorings. It would be interesting to know if CMAKE_Swift_FLAGS vs CMAKE_EXE_LINKER_FLAGS makes a difference. But, really, this is difficult to judge without the actual linker invocation.

If it worked before, that may be the case. It is easy to reproduce his linker error, as CMake is configuring Swift to build that object file first, then link it separately, so I'm able to reproduce his error manually by doing something similar, ie swiftc -c Main.swift && swiftc Main.o -static-stdlib. I notice now that if I change it to add -static-stdlib to the first command too, it works, so maybe the target_compile_options doesn't work for Swift with certain versions of CMake?

@needlesslygrim, please check if that compile flag is passed in with ninja -v and if not, let us know which version of CMake isn't doing that, as Jesse said your config worked for him.

Sorry for the slow reply. Unfortunately, the behaviour is extremely odd. I just ran ninja -v again to test, and it failed running this command:
/home/needlesslygrim/.local/share/swiftly/bin/swiftc -j 16 -num-threads 16 -emit-executable -o broken CMakeFiles/broken.dir/Main.swift.o -static-stdlib

However, I then ran ninja clean and ninja -v, and it works???

A screenshot of my terminal session:

Additionally, it seems to be working on my Desktop as well now (although I was using the Fedora repo version of Swft there and update in between so that could be the reason). I guess this is solved then?

I do wonder if the Fedora repo version was the issue then. I have tried to use it before and run into some strange behaviors myself, before just switching to Swiftly and using the rhel-ubi9 tool chain.