Trying to cross-compile LLVM runtimes to Windows

I've tried building libc++ for Windows on Linux by setting clang-cl as
the compiler and lld-link as the linker, but I immediately hit
roadblocks. The first issue seems to be the fact that CMake appears to
ignore the value of CMAKE_RC_COMPILER variable and hardcodes "rc" as
the resource compiler. This got resolved in upstream 12 days ago
(https://github.com/Kitware/CMake/commit/bd9bfc644954a48b1bf7ea18fc260a1231840671)

I managed to workaround this issue by symlinking llvm-rc as rc.
However, that's not sufficient because CMake uses following invocation
(https://github.com/Kitware/CMake/blob/master/Source/cmcmd.cxx#L1815):

rc /foCMakeFiles/cmTC_2c376.dir/manifest.res
CMakeFiles/cmTC_2c376.dir/manifest.rc

llvm-rc option parses requires /fo option argument to be separate.
I've modified the flag to support both joined and separate value which
helped getting past that error, but I immediately hit another error:
https://reviews.llvm.org/P8113

The problem seems to be that the .rc file generated by CMake contains
an absolute path to the resource, but llvm-rc expects the path to be
always relative. However, I couldn't fine any documentation that would
explain whether that's a requirement and it's CMake's fault or whether
llvm-rc should be handling absolute paths as well. Is anyone familiar
with Windows resource file semantics?

All of these errors seem to suggest that this cross-compiling for
Windows with Clang using CMake isn't a well explored area. Has anyone
had more success with cross-compiling LLVM runtimes (libc++,
compiler-rt) to Windows?

I've tried building libc++ for Windows on Linux by setting clang-cl as
the compiler and lld-link as the linker, but I immediately hit
roadblocks. The first issue seems to be the fact that CMake appears to
ignore the value of CMAKE_RC_COMPILER variable and hardcodes "rc" as
the resource compiler. This got resolved in upstream 12 days ago
(https://github.com/Kitware/CMake/commit/bd9bfc644954a48b1bf7ea18fc260a1231840671)

I managed to workaround this issue by symlinking llvm-rc as rc.
However, that's not sufficient because CMake uses following invocation
(https://github.com/Kitware/CMake/blob/master/Source/cmcmd.cxx#L1815):

rc /foCMakeFiles/cmTC_2c376.dir/manifest.res
CMakeFiles/cmTC_2c376.dir/manifest.rc

llvm-rc option parses requires /fo option argument to be separate.
I've modified the flag to support both joined and separate value which
helped getting past that error,

Please send that patch for review (add me, zturner, amccarth and thakis as reviewers) - it's probably useful irrespective of the other issues you're running into.

but I immediately hit another error: https://reviews.llvm.org/P8113

The problem seems to be that the .rc file generated by CMake contains
an absolute path to the resource, but llvm-rc expects the path to be
always relative. However, I couldn't fine any documentation that would
explain whether that's a requirement and it's CMake's fault or whether
llvm-rc should be handling absolute paths as well. Is anyone familiar
with Windows resource file semantics?

As the existing cmake behaviour works with rc.exe, llvm-rc should adapt to handle it as well.

It seems like we look in the INCLUDE environment for files included in resource files, but as that assert points out, doing that doesn't makse sense if the file name looked for actually turns out to be an absolute path. I'd just add an "if (!path::is_absolute(FileName))" before the FindInEnvPath call.

All of these errors seem to suggest that this cross-compiling for
Windows with Clang using CMake isn't a well explored area. Has anyone
had more success with cross-compiling LLVM runtimes (libc++,
compiler-rt) to Windows?

I do this, successfully - see https://github.com/mstorsjo/llvm-mingw (as Jean-Michaël already linked). I do this in a mingw setup though, so cmake doesn't use llvm-rc directly, but instead I wrap llvm-rc in a GNU windres like frontend, that takes care of preprocessing (in case there are #include etc) and option handling (wrangling options from GNU windres style to what llvm-rc expects).

It's definitely not a well-explored area though - as build-compiler-rt.sh and build-libcxx.sh in my repo shows, I go through quite a bit of manual fiddling to get it all to build in a bootstrap setup. There might be opportunities for simplifying all of it somewhat, but this setup works for me at least.

// Martin

We cross-compile clang and compiler-rt for Windows on Linux. For clang, we use LLVM’s WinMsvc toolchain file (https://reviews.llvm.org/diffusion/L/browse/llvm/trunk/cmake/platforms/WinMsvc.cmake). We add /manifest:no to our link flags in that toolchain file, which prevents cmake from attempting to do any mt or rc calls IIRC. I don’t know if not embedding a manifest is an acceptable workaround for your use case, but it works for us. For compiler-rt, we have this weird setup (for historic reasons) where we build for Windows with an msvc triple but using the gcc-style driver, which I think ends up saving us from CMake’s rc calls (though we then need some other CMake shenanigans to make lld-link happy). I wouldn’t recommend going that route, but even with clang-cl the /manifest:no might save you?