apple / swift-cmake-examples

Apache License 2.0
99 stars 9 forks source link

Build under Windows #13

Open pultar opened 2 months ago

pultar commented 2 months ago

Hi, I wanted to build the example projects under Windows 11, Swift 5.10, installation of the toolchain via WinGet following instructions on swift.org.

Swift version 5.10 (swift-5.10-RELEASE)
Target: x86_64-unknown-windows-msvc

When I want to build 3_bidirectional_cxx_interop using

cmake -S . -B build -GNinja
cmake --build build

I get:

-- The CXX compiler identification is Clang 16.0.0 with GNU-like command-line
-- The Swift compiler identification is Apple 5.10
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Users/fpultar/AppData/Local/Programs/Swift/Toolchains/5.10.0+Asserts/usr/bin/clang++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Check for working Swift compiler: C:/Users/fpultar/AppData/Local/Programs/Swift/Toolchains/5.10.0+Asserts/usr/bin/swiftc.exe
-- Check for working Swift compiler: C:/Users/fpultar/AppData/Local/Programs/Swift/Toolchains/5.10.0+Asserts/usr/bin/swiftc.exe - works
-- Configuring done (4.6s)
-- Generating done (0.0s)
-- Build files have been written to: C:/Users/fpultar/source/repos/test-fxp/swift-cmake-examples/3_bidirectional_cxx_interop/build

and

[4/6] Linking Swift static library lib\fibonacci\fibonacci.lib
FAILED: lib/fibonacci/fibonacci.lib lib/fibonacci/CMakeFiles/fibonacci.dir/fibonacci.swift.obj lib/fibonacci/SwiftFibonacci.swiftmodule
C:\Windows\system32\cmd.exe /C "cd . && C:\Users\fpultar\AppData\Local\Programs\Swift\Toolchains\5.10.0+Asserts\usr\bin\swiftc.exe -j 32 -num-threads 32 -emit-library -static -o lib\fibonacci\fibonacci.lib -module-name SwiftFibonacci -module-link-name fibonacci -emit-module -emit-module-path lib\fibonacci\SwiftFibonacci.swiftmodule -emit-dependencies  -Onone -g -incremental -libc MDd -cxx-interoperability-mode=default -output-file-map lib\fibonacci\CMakeFiles\fibonacci.dir\Debug\output-file-map.json -I C:/Users/fpultar/source/repos/test-fxp/swift-cmake-examples/3_bidirectional_cxx_interop/include -I C:/Users/fpultar/source/repos/test-fxp/swift-cmake-examples/3_bidirectional_cxx_interop/build/lib/fibonacci/include C:\Users\fpultar\source\repos\test-fxp\swift-cmake-examples\3_bidirectional_cxx_interop\lib\fibonacci\fibonacci.swift lib\fibonacci\CMakeFiles\fibonacci.dir\fibonacci.cpp.obj    && cd ."
error: unableToFind(tool: "link")
ninja: build stopped: subcommand failed.

I get similar errors for 2_executable_library.

Forcing building shared libraries (cmake -S . -B build -GNinja -DBUILD_SHARED_LIBS=TRUE) resolves the problem for 2_executable_library but 3_bidirectional_cxx_interop fails with:

[4/6] Linking Swift shared library lib\fibonacci\fibonacci.dll
FAILED: lib/fibonacci/fibonacci.dll lib/fibonacci/CMakeFiles/fibonacci.dir/fibonacci.swift.obj lib/fibonacci/SwiftFibonacci.swiftmodule lib/fibonacci/fibonacci.lib
C:\Windows\system32\cmd.exe /C "cd . && C:\Users\fpultar\AppData\Local\Programs\Swift\Toolchains\5.10.0+Asserts\usr\bin\swiftc.exe -j 32 -num-threads 32 -emit-library -o lib\fibonacci\fibonacci.dll -module-name SwiftFibonacci -module-link-name fibonacci -emit-module -emit-module-path lib\fibonacci\SwiftFibonacci.swiftmodule -emit-dependencies -Dfibonacci_EXPORTS -Onone -g -incremental -libc MDd -cxx-interoperability-mode=default -output-file-map lib\fibonacci\CMakeFiles\fibonacci.dir\Debug\output-file-map.json -I C:/Users/fpultar/source/repos/test-fxp/swift-cmake-examples/3_bidirectional_cxx_interop/include -I C:/Users/fpultar/source/repos/test-fxp/swift-cmake-examples/3_bidirectional_cxx_interop/build/lib/fibonacci/include C:\Users\fpultar\source\repos\test-fxp\swift-cmake-examples\3_bidirectional_cxx_interop\lib\fibonacci\fibonacci.swift lib\fibonacci\CMakeFiles\fibonacci.dir\fibonacci.cpp.obj C:\Users\fpultar\AppData\Local\Programs\Swift\Platforms\5.10.0\Windows.platform\Developer\SDKs\Windows.sdk\/usr/lib/swift/windows/x86_64/swiftrt.obj   -Xlinker -implib:lib\fibonacci\fibonacci.lib -L C:/Users/fpultar/AppData/Local/Programs/Swift/Toolchains/5.10.0+Asserts/usr/lib/swift/windows   -L C:/Users/fpultar/AppData/Local/Programs/Swift/Toolchains/5.10.0+Asserts/usr/lib/swift/windows/x86_64  && cd ."
error: link command failed with exit code 1319 (use -v to see invocation)
fibonacci.cpp.obj : error LNK2038: mismatch detected for '_ITERATOR_DEBUG_LEVEL': value '2' doesn't match value '0' in swiftrt.obj
fibonacci.cpp.obj : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MDd_DynamicDebug' doesn't match value 'MD_DynamicRelease' in swiftrt.obj
C:\Users\fpultar\AppData\Local\Programs\Swift\Platforms\5.10.0\Windows.platform\Developer\SDKs\Windows.sdk\\usr\lib\swift\windows\x86_64\swiftrt.obj : warning LNK4042: object specified more than once; extras ignored
   Creating library lib\fibonacci\fibonacci.lib and object lib\fibonacci\fibonacci.exp
LINK : warning LNK4098: defaultlib 'msvcrtd.lib' conflicts with use of other libs; use /NODEFAULTLIB:library
lib\fibonacci\fibonacci.dll : fatal error LNK1319: 2 mismatches detected
clang: error: linker command failed with exit code 1319 (use -v to see invocation)
error: fatalError
ninja: build stopped: subcommand failed.

Do you have any suggestions what could be the issue? I understand that these examples should all work under Windows so I am assuming something might be off with my dev setup.

Best, Felix

compnerd commented 2 months ago

error: unableToFind(tool: "link")

This indicates that link.exe was not found in Path. Are you running from within a VS Developer Command Prompt? If not, the MSVC tools required (link.exe) are not in the Path and so the toolchain cannot locate it. Since this is the CMake examples repository, I am assuming that you are building with just CMake. As such, you could work around this by doing -D CMAKE_Swift_FLAGS="-use-ld=lld" to ensure that LLD is always used over the default (link.exe) to link products.

LINK : warning LNK4098: defaultlib 'msvcrtd.lib' conflicts with use of other libs; use /NODEFAULTLIB:library

This indicates that you are building in debug mode. Unfortunately, there is no current support for building with a debug C runtime as the Swift runtime requires the release mode C runtime. You can workaround this by always building in Release or RelWithDebInfo configurations.

@etcwilde - should we perhaps set CMAKE_MSVC_RUNTIME_LIBRARY to MultiThreaded always to allow building the rest of the project in debug mode?

pultar commented 2 months ago

Thanks for your quick answer!

If I start from C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio 2022\Visual Studio Tools\Developer Command Prompt for VS 2022 or C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio 2022\Visual Studio Tools\Developer PowerShell for VS 2022, I get:

 cmake -S . -B build -GNinja -DCMAKE_BUILD_TYPE=Release
-- The Swift compiler identification is Apple 5.10
-- Check for working Swift compiler: C:/Users/fpultar/AppData/Local/Programs/Swift/Toolchains/5.10.0+Asserts/usr/bin/swiftc.exe
-- Check for working Swift compiler: C:/Users/fpultar/AppData/Local/Programs/Swift/Toolchains/5.10.0+Asserts/usr/bin/swiftc.exe - broken
CMake Error at C:/Program Files/CMake/share/cmake-3.29/Modules/CMakeTestSwiftCompiler.cmake:40 (message):
  The Swift compiler

    "C:/Users/fpultar/AppData/Local/Programs/Swift/Toolchains/5.10.0+Asserts/usr/bin/swiftc.exe"

  is not able to compile a simple test program.

  It fails with the following output:

    Change Dir: 'C:/Users/fpultar/source/repos/test-fxp/swift-cmake-examples/2_executable_library/build/CMakeFiles/CMakeScratch/TryCompile-6my756'

    Run Build Command(s): C:/Users/fpultar/AppData/Local/Microsoft/WinGet/Links/ninja.exe -v cmTC_789a8
    [1/2] C:\Users\fpultar\AppData\Local\Programs\Swift\Toolchains\5.10.0+Asserts\usr\bin\swiftc.exe -j 32 -num-threads 32 -c  -module-name cmTC_789a8 -incremental -output-file-map CMakeFiles\cmTC_789a8.dir\\output-file-map.json  C:\Users\fpultar\source\repos\test-fxp\swift-cmake-examples\2_executable_library\build\CMakeFiles\CMakeScratch\TryCompile-6my756\main.swift
    [2/2] C:\Windows\system32\cmd.exe /C "cd . && C:\Users\fpultar\AppData\Local\Programs\Swift\Toolchains\5.10.0+Asserts\usr\bin\swiftc.exe -j 32 -num-threads 32 -emit-executable -o cmTC_789a8.exe  CMakeFiles\cmTC_789a8.dir\main.swift.obj    && cd ."
    FAILED: cmTC_789a8.exe
    C:\Windows\system32\cmd.exe /C "cd . && C:\Users\fpultar\AppData\Local\Programs\Swift\Toolchains\5.10.0+Asserts\usr\bin\swiftc.exe -j 32 -num-threads 32 -emit-executable -o cmTC_789a8.exe  CMakeFiles\cmTC_789a8.dir\main.swift.obj    && cd ."
       Creating library cmTC_789a8.lib and object cmTC_789a8.exp
    LINK : error LNK2001: unresolved external symbol mainCRTStartup
    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\lib\x86\msvcrt.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'
    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\lib\x86\msvcprt.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'
    cmTC_789a8.exe : fatal error LNK1120: 1 unresolved externals
    clang: error: linker command failed with exit code 1120 (use -v to see invocation)
    ninja: build stopped: subcommand failed.

  CMake will not be able to correctly generate this project.
Call Stack (most recent call first):
  CMakeLists.txt:9 (project)

I have a 64-bit CPU and OS:

Processor   AMD Ryzen 9 7950X 16-Core Processor               4.50 GHz
Installed RAM   192 GB (191 GB usable)
System type 64-bit operating system, x64-based processor
compnerd commented 2 months ago

You need to use the Native Tools Developer Command Prompt. I believe that the command prompt you are using sets up the environment for 32-bit compilation, not 64-bit. The Windows toolchain defaults to 64-bit compilation, and 32-bit is known to still contain issues :(.

    LINK : error LNK2001: unresolved external symbol mainCRTStartup
    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\lib\x86\msvcrt.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'
    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\lib\x86\msvcprt.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'

Does seem to match the hypothesis above.

etcwilde commented 2 months ago

should we perhaps set CMAKE_MSVC_RUNTIME_LIBRARY to MultiThreaded always to allow building the rest of the project in debug mode?

Yeah, I think that makes sense. Is there a drawback to that approach?

compnerd commented 2 months ago

should we perhaps set CMAKE_MSVC_RUNTIME_LIBRARY to MultiThreaded always to allow building the rest of the project in debug mode?

Yeah, I think that makes sense. Is there a drawback to that approach?

The only drawback that I can think of is future robustness. If we do end up supporting a debug C runtime build of the Swift runtime, it would allow us to support a MultiThreadedDebug variant as well. At the very least, we should be prepared for some day supporting a static variant so that we could do a fully statically linked binary on Windows if desired (even if strongly discouraged by Microsoft).

pultar commented 2 months ago

It works with the native command prompt using this command:

cmake -S . -B build -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Release -GNinja
cmake --build build

It was necessary to explicitly tell cmake to use clang as MSVC was used otherwise.

The other use case I had in mind was compiling the project on a Mac and a Parallels Windows installation. Following your guidance, I came up with this configure command from the x64_Native_Prompt:

cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_SYSTEM_PROCESSOR=AMD64 -DCMAKE_SYSTEM_NAME=Windows
cmake --build build

I suppose that's the logic in InitializeSwift.cmake?

Does it make sense to document these details somewhere in this repo? I am sure it is just my inexperience developing for Windows but that could also be true for other people coming from macOS / Linux.

It's honestly amazing that all these things now also work on Windows. Seems like it can really expand the scope of Swift for cross-platform development!

compnerd commented 2 months ago

It was necessary to explicitly tell cmake to use clang as MSVC was used otherwise.

Oh, right - if you want to use link, then you need to tell it to use clang and clang++ for the C/C++ compiler.

Does it make sense to document these details somewhere in this repo? I am sure it is just my inexperience developing for Windows but that could also be true for other people coming from macOS / Linux.

I think it makes sense to document these details, but I'm not certain about the location to document it. Perhaps @etcwilde has some thoughts.

It's honestly amazing that all these things now also work on Windows. Seems like it can really expand the scope of Swift for cross-platform development!

I'm happy that you are excited about this - looking forward to see what you build :)

afabri commented 2 months ago

This indicates that you are building in debug mode. Unfortunately, there is no current support for building with a debug C runtime as the Swift runtime requires the release mode C runtime. You can workaround this by always building in Release or RelWithDebInfo configurations

Is the "always Release" also true for macOS ? I ask because I have a branch where I fill arrays from the C++ side in order to create a sparse matrix and call a solver from the Accelerate library. It does build but crashes.

compnerd commented 2 months ago

Is the "always Release" also true for macOS ? I ask because I have a branch where I fill arrays from the C++ side in order to create a sparse matrix and call a solver from the Accelerate library. It does build but crashes.

No, the thing is that Microsoft does not have a stable ABI for the C runtime, and you must match that when you build the various components. For performance and redistribution reasons, we build the runtime with the release C runtime, which then requires that we build all client code with the same runtime model.