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.