The state of WinUI and Swift

Until recently, I successfully used swift-winui, which allows me to build simple GUI utilities in Swift running on Windows 11.

Everything compiled and ran fine with Swift 6.0.3. However, since Swift 6.1, my projects no longer compile with linker errors such as:

lld-link: error: too many exported symbols (got 67393, max 65535)

It seems that the swift-win-ui library (DLL) exports too many symbols. How can this suddenly happen with Swift 6.1 without me having added anything to the Swift projection of swift-winui ?

Also, more broadly, are there any advancements or a roadmap for a next-generation swift-winui that takes advantage of the advances in Swift (6.1 and soon 6.2) over the past year and removes known limitations ?

Swift WinUI is such an interesting project and I hope it's not on hiatus.

1 Like

Changes to the language and SPM can do this. The underlying issue here is the lack of support for libraries in SPM. All the symbols are marked for DLL export, but then used in a static library. The export table associates an ordinal with each entry, which is a uint16, limiting the export table to 16K.

The most immediately viable workaround would be to switch to CMake to build as that allows proper handling for static and dynamic linking.

Do you have anything specific in mind? I don’t know if we have any concrete plans to that end currently (CC: @stevenbrix )

I am still able to build an according project in release mode with Swift 6.1.

My naive answer to this is: If this is the issue, then libraries should be supported in SPM...

This might be helpful:

I just recently migrated my swift-winrt repos from SPM to CMake (for several reasons, the symbol limit being one), and also consolidated them into a monorepo along the way: GitHub - ktraunmueller/winrt-monorepo: Monorepo containing all (previously stand-alone) swift-winrt repos

Note: I am not a CMake expert in any way, take my build setup with a grain of salt

Thank you for the link. How do you use a library to be compiled via SPM with this repo?

EDIT: Means: Do you have a simple example how this then works together? Thanks.

I've also migrated the build setup for my (closed-source, sorry) Windows app from SPM to CMake, so for me it's now CMake all the way. The static libraries produced by the projects in the monorepo are linked (along with other static libraries) into a monolithic Windows .exe.

1 Like

I can build in release mode using 6.1 too. The lld-link error is related to debug mode.
I hope Apple can work with TBC to fix SwiftPM and resolve this limitation.
No fun having to learn and switch to CMake.

1 Like

The Browser Company uses CMake to build its software :slightly_smiling_face:

Well, let's say it would be nice if SPM would suffice here, and whoever helps making that a reality, thanks :slight_smile:

SPM isn't the only build system for building Swift code. I found CMake quite unapproachable and intimidating at first, but with a lot of help from ChatGPT, I migrated from SPM to CMake in a very short amount of time. I think it's a great build system, and it's nice to have this choice.

FWIW, I'd love to learn more about what's happening in SwiftPM with this. I made changes in 6.1 to cut down the number of symbols exported by executables where we regularly hit the limit. DLLs in theory should have built the same as in 6.0. That leads me to wonder if there are just more symbols exported by the compiler in 6.1. I'm also curious how this is working in CMake if you're choosing DLLs there. Seems that would run into the same problems?

Underlying all this is my desire to make sure people aren't forced to abandon SwiftPM for CMake. If you run into any issues I'd love to see issues raised so we can investigate and make SwiftPM better.

1 Like

Just to clarify my use case, I want to avoid dlls if possible. My general preference with the build system is to trim down shipped binary size as much as possible, which means to go static library (stripping out anything that the app doesn't need). I can't recall why I configured SPM to build the libraries as dlls, it seemed like the only viable option for Windows when I started out porting my app to Windows.

CMake doesn't run into this issue as it properly can isolate the static and dynamic builds and then properly controls the flags that it needs to apply to control the exported symbol set according to the build time. This is the long standing issue where the build engine in SPM is forcing us to build all the targets in a single style, building all targets for dynamic linking and then re-use the objects (as object libraries rather than proper libraries) for static linking.

Having all targets be built twice (once for static linking, once for dynamic linking), creating the static or dynamic library, and then allowing control over linkage in-between targets and products should allow use of SPM.

This work would still leave many of the other sharp edges of SPM, e.g. the inability to inject arbitrary commands at various points in the build, the inability to use RBE, the inability to inject a compiler launcher (e.g. sccache), the inability to dynamically query the host environment at build time (e.g. check_function_exists), and most importantly, the inability to deal with tools like the resource compiler, message compiler, etc.

If you don't have DLLs then everything is built static in SwiftPM 6.1.

On Windows that is. I didn't change the other platforms.

We're definitely looking at that for the integration with Swift Build to support this use case. It will require changes to build each module into it's own directory so we can pick and choose when constructing the include and link paths.

1 Like