Swift on Windows Status

I would like to know which is the current status of Swift on Windows and some real-world usage.

I have been trying the binaries distributed through here and it seems it is in a usable state. Also this repo includes the patches required by Foundation to work on Windows but they have not been added to the official repo.

I have some questions I would like to ask to the community:

  • What is the current build status of Swift on Windows? Is there any site where Swift 4.1/4.2 binaries are distributed?
  • What is the state of Swift Foundation on Windows?
  • Could we add a Community-Hosted CI for Windows? Is Apple willing to add Windows as an official supported platform with CI nodes?
  • What is the status of Swift PM on Windows? One of the main problems I found out trying to use the distribution from swiftforwindows.github.io is that Swift PM is not available so building any complex project is very difficult.
7 Likes

My knowledge is a few months out of date, and @compnerd is really the expert on this, but here's the situation last time I looked:

Those binaries are usable if you're fine to only be targeting MinGW or Cygwin, but not if you're wanting to target Windows natively. Personally, I think that if you're only wanting to try out Swift on Windows running Ubuntu through WSL is the way to do it, and for distribution native is really required.

Those patches, as far as I'm aware, are again targeting MinGW/Cygwin and not native Windows. For my usage, I hacked together support for the Foundation methods that I needed – eventually some of those changes could hopefully be merged in to the main Foundation repository, although I didn't write them in a way that would be merged as-is.

Not to my knowledge. While you can build it yourself, building it from source will mean you end up with a dynamically linked standard library, and there are (were?) some issues in representing various bits of type metadata that meant anything more complex than a print statement failed to link. You can also build the standard library with DLLImport disabled (there's a few places around the code where you need to turn it off) and then link with duplicate symbols – I've still got the invocations around somewhere.

I'm sure that no-one is opposed to a community-hosted CI for Windows – it's just a matter of time, effort, and money in making that happen. I obviously can't speak for Apple, but I would guess that having community-hosted CI would be a necessary step before they'd consider adopting it as an official supported platform.

What I did here is use SwiftPM from WSL (Ubuntu on Windows) and cross-compiled the binaries – I had to add a couple of minor patches to SwiftPM to get that to work, but otherwise it's a fairly good solution.

If you have some time to devote to this, I can share my process and any other useful information. I think the biggest obstacle to Swift on Windows so far has been that anyone who's likely to care about it – anyone in the Swift community – probably doesn't use Windows as their primary platform, and so it's hard to test things or keep them up to date. With that said, a number of us are interested in deploying to Windows, so I hope that once there's a little less friction in getting to the stage where you can build an application (i.e. once the problems are missing methods in Foundation rather than strange compiler issues) the project will gain some momentum.

3 Likes

Same problem probably exists for Swift on Android too. I think getting the SPM to work is more important than getting Foundation to work since you can build a complex project without Foundation, but not without the SPM

3 Likes

I also think in addition to SPM you will need a cross platform IDE that uses SPM, something that is competitive with Android Studio.

1 Like

I'd actually lean the other way. Many applications and libraries depend on Foundation to run, but SwiftPM can be used to cross-compile for other platforms. Eventually being able to run SwiftPM natively on Windows would be ideal, but it doesn't block building and running apps targeting Windows, whereas not having the functionality provided by Foundation does block a number of existing applications and libraries. In the meantime, using SwiftPM through Ubuntu for Windows to target native Windows binaries works fairly well.

SPM can crosscompile to windows? i did not know that

1 Like

It seems like Kotlin native is already usable / will be used for iOS development (in addition to Android) before Swift can be used to comfortably develop on Android which may drive the former’s adoption quite fast.

6 Likes

Very interesting, I hope to see this merged upstream eventually!

Thank you. Yes, any information about that would be much appreciated. I have tried to build some tools on Windows with swiftc but it can get very complex easily if you have multiple modules and dependencies.

(Also, I will take a look to this script from your project. Very interesting stuff.)

I spent some time looking into this today and trying to get things working. It looks like the status of things hasn't changed much: static linking still works and dynamic linking is an issue.

With regards to dynamic linking, we're waiting on Full Type Metadata On Windows - #9 by Joe_Groff, which is a little beyond my ability to fix. @compnerd, do you have any updates on how that's going? Alternatively, @Joe_Groff – you suggested a possible implementation for this; is it likely to be a major change, or is it a small change that happens to be tricky in how it interacts with other systems? If either of you were able to help implement those changes it would be a major step forward for Swift's usability on Windows, and would help lower the bar for other people to contribute to the port.

In terms of actually getting non-trivial Swift programs working on Windows: here are the notes I took for my process. They were mainly written for my own reference, so I'm happy to elaborate on any parts that don't make sense. My process is focused on cross-compiling to Windows from Ubuntu on Windows.

The interesting part is really getting the Swift libraries built for Windows - swiftCore.lib, swiftOnoneSupport.lib etc. Once that's done, those libraries can be copied to lib/swift_static/windows/x86_64 on any Swift installation and used to cross-compile to Windows.

I wrote up some steps for getting my environment set up.

My Notes

  • Download Ubuntu for Windows
  • Install Swift dependencies via apt, including a recent version of clang.
  • export UCRTVersion=10.0.17134.0 (or whatever the current version is)
  • export UniversalCRTSdkDir="/mnt/c/swift-source/Windows Kits/10"
  • export VCToolsInstallDir="/mnt/c/swift-source/VCToolsInstallDir"
  • Modify configure_sdk_windows in CMakeLists.txt within the swift root source folder to remove Windows archs other than x86_64.
  • Rename kernel32.Lib in the VCToolsInstallDir/lib/x64 folder to kernel32.lib, and other files as appropriate.
  • For static linking:
    • Go to Visibility.h in stdlib/public/SwiftShims and comment out __declspec(dllimport); do the same in Platform.h for SwiftDemangle and SwiftRemoteMirror.
    • In Linking.cpp, always return false from useDllStorage().

64-bit build invocation:

utils/build-script -R --no-assertions --build-swift-static-stdlib --extra-cmake-options=-DCMAKE_AR="/usr/bin/llvm-ar",-DCMAKE_RANLIB="/usr/bin/llvm-ranlib",-DSWIFT_SDKS="LINUX;WINDOWS",-DSWIFT_WINDOWS_ICU_I18N_INCLUDE="/mnt/c/swift-source/windows-icu/include",-DSWIFT_WINDOWS_ICU_UC_INCLUDE="/mnt/c/swift-source/windows-icu/include",-DSWIFT_WINDOWS_ICU_I18N="/mnt/c/swift-source/windows-icu/lib64/icuin.lib",-DSWIFT_WINDOWS_ICU_UC="/mnt/c/swift-source/windows-icu/lib64/icuuc.lib"
/usr/bin/cmake --build /mnt/c/swift-source/build/Ninja-Release/swift-linux-x86_64 -- -j20 swift-stdlib-windows-x86_64

Build Swift (ignoring the last failures of the dynamically linked core libs). Run the build commands a few times and stop when it keeps hitting the same point.

Then, rename lib(...).a files in lib/swift-static/windows/x86_64 to (...).lib.

Possibly generate a new swiftCore.lib by linking the generated one statically with libicuuc and libicuin – otherwise icuuc.lib and icuin.lib always need to be passed as libraries in the linker arguments.

Need to use a modified version of lld-link (patch open here) that allows multiple definitions - build from source and pass /force:multiple as a linker argument to it to continue linking when multiple definitions are encountered.

To Build Swift code:

Make sure INCLUDE and LIB environment variables are set, mirroring those set in Windows' Developer Tools Command Prompt with VsDevCmd -arch=amd64.

Run build command, assuming a single main.swift file:

swiftc -static-stdlib -target x86_64-unknown-windows-msvc -use-ld=lld -Xlinker /LIBPATH:/mnt/c/swift-source/Windows Kits/10/Lib/10.0.17134.0/um/x64 main.swift -Xlinker /mnt/c/swift-source/windows-icu/lib64/icuuc.lib  -Xlinker /mnt/c/swift-source/windows-icu/lib64/icuin.lib -v -o SwiftTest.exe

For Swift Packages

You can see the build script I use here, but the main interesting part is the destination.json file passed as --destination to the Swift Package Manager. I did have to make a couple of changes to SwiftPM to get it to recognise Windows as a supported platform – I'll see if I can get those upstreamed in the near future.

9 Likes

I believe @compnerd already made the changes I suggested. I don't know how much is left regarding addressing the issues with cross-DLL data references, but in general it shouldn't be too complicated to deal with them; the compiler mainly needs not to optimize by sharing data structures with the runtime, instead emitting copies of the data structures in question.

Those changes haven’t been made as far as I can tell: $SBoWV is still missing during linking, and furthermore @compnerd doesn’t seem to appear during the recent-ish commit history to GenMeta.cpp or GenValueWitnesses.cpp. I think he may have fixed the protocol descriptor issue, though; previously, there were also missing references to protocol descriptors during linking.

Ah, that could be. IIRC he also added code to suppress prefab value witness table sharing for value types, but maybe we still don't have a solution for the class reference value witness tables, which would explain why $SBoWV (the value witness table for Builtin.NativeObject and thereby all class types) is still missing.

Thinking about it more, classes require one-time instantiation any way, and with @John_McCall and @Slava_Pestov's ongoing work on class resilience, many class metadata objects are emitted as true-const instantiation patterns rather than directly as metadata objects. That may give us an opportunity to have the value witness table for class types filled in at instantiation time, avoiding the need for the direct reference or to redundantly generate a value witness table in every object file.

4 Likes

Yeah, we should be set up well after this work to fully initialize class metadata at runtime if we want. It's a bit of a shame to do so for totally static types, but there are classes we always have to do it for, so it's not the worst thing.

Yeah, and referencing data symbols across DLLs on Windows requires some kind of post-load initialization anyway, and lazy initialization might be slightly preferable to the static constructor that would typically happen in code generated by MSVC.

Time to necromance this thread :mage:

So, what needs to be done to get the class metadata initialized at runtime? The $sBoWV references are the last item that remain from getting the libdispatch SDK overlay building for Windows! I think that with some guidance, I might be able to get this completed which would bring the Windows build into a much better shape.

@Joe_Groff, @John_McCall - some guidance would greatly appreciated.

6 Likes

The simplest thing would be to just force all class types into the in-place-but-non-trivial metadata initialization path. Ultimately the right way to get that to happen is to make ClassLayoutBuilder::doesMetadataRequireInitialization return true.

EDIT: I originally said "false", but that's obviously wrong.

1 Like

Bleh, hacking the compiler to always return true doesn't seem to be sufficient. That changes 1 of the 3 references in the swift SDK from direct to the import.

Well, that might not be the only reason we emit a reference to the VWT, or we might be emitting a reference in some cases even though we're going to call the runtime.

For example, these references are from code and so should be fine, but arguably EmitTypeLayoutRef::hasVisibileValueWitnessTable should ignore the special-case builtin types on PE/COFF.