[RFC] Update Windows Build Toolchain
Open, NormalPublic

Description

Motivation

We currently use mingw-w64 GCC 7.3.0 from the mingw-builds toolchain on the Binary Factory, which has quite old mingw-w64 headers and also an old GCC.

An update of the Windows build toolchain is needed for these dependencies.

Scope

This only concerns the build toolchain used on the KDE Binary Factory, and subsequently also other developers and contributors who use the prebuilt dependencies from the Binary Factory. Anyone can still build the dependencies and Krita on Windows with any supported toolchains.

Choice of Toolchain

Available Candidates

[mingw-builds]: https://github.com/niXman/mingw-builds
[mingw-builds-release]: https://github.com/niXman/mingw-builds-binaries/releases
[llvm-mingw]: https://github.com/mstorsjo/llvm-mingw

Exclusion of MSVC

Amyspark had found several codegen performance regressions with MSVC in the past, therefore we cannot consider using it for releases until these issues have been resolved.

msvcrt vs ucrt

msvcrt.dll was the C standard library from before and up to Microsoft Visual C++ 6.0. Since then, newer versions of Visual C++ used versioned DLLs (e.g. msvcr70.dll). Modern versions of Windows still include msvcrt.dll for use by system components and for compatibility with old programs compiled against Visual C++ 6.0. Officially, linking to msvcrt.dll is *not* supported, but since Microsoft is unlikely to break old programs it will likely still work for the foreseeable future.

Since msvcrt is stuck at Visual C++ 6.0, mingw-w64 provides its own replacement functions to replace some of the non-compliant parts in it.

Universal CRT (ucrt) is Microsoft's new C standard library which ships as part of Windows starting from Windows 10, and installable on Windows 7 through Windows 8.1. It conforms more closely to ISO C99 than the old msvcrt. Visual Studio started using it since VS2015. Mingw-w64 added support for ucrt but it needs to be enabled when building the toolchain.

I believe ucrt should be preferred. Mingw-w64's ucrt support is a bit young, but I am not too worried about that. Our embedded Python already requires ucrt, so we are not adding a new dependency.

Toolchains using ucrt:

  • llvm-mingw
  • MSYS2 UCRT64
  • MSYS2 CLANG64

libstdc++ vs libc++

libstdc++ is the GNU C++ Library, while libc++ is the C++ standard library implementation by LLVM developers. libc++ is quite a bit younger, but it has been the default C++ standard library for macOS, FreeBSD and Android for some time, so it has also been widely used. In any case, neither is really native to Windows, so I don't think either one of them has an edge over the other.

I've seen comments that claim libc++ performs worse than libstdc++, but I have not found any recent benchmarks that can prove or disprove this. Since we mostly use Qt's library classes over C++ standard library classes, I am willing to guess this would not affect Krita very much.

Toolchains using libstdc++:

  • mingw-builds
  • MSYS MINGW64
  • MSYS UCRT64

Toolchains using libc++:

  • llvm-mingw
  • MSYS CLANG64

Build Times

There isn't much of a noticeable difference in compile time between GCC and Clang on Windows. However, link time with lld from LLVM is an order of magnitude faster than GNU ld, which is quite noticeable when rebuilding only a small number of object files in the kritaui library.

Toolchains using lld:

  • llvm-mingw
  • MSYS CLANG64

Note: GCC-based toolchains *can* use lld but it requires some manual setup.

Problems with MSYS2

Rolling Release

MSYS2 is a rolling release, which means it is difficult to pin the packages to specific versions. We may create an archive of the MSYS2 environment and use that as a "stable" toolchain, but this archive will not be easily reproducible with the exact versions of packages.

Included Shared Libraries

MSYS2 comes with certain libraries included or available as packages (gettext and OpenSSL for example), which is helpful in some way, because some libraries does not provide a native CMake build system (which we currently work around by either using prebuilt binaries or adapting the CMake build system from vcpkg). This however also ties shared libraries together with the toolchain. If we choose to deliver the toolchain as an archive, whenever we want to update these libraries we will need to update the whole toolchain.

Miscellaneous Considerations

  • mingw-w64 GCC is known to have a codegen bug that breaks the upstream ANGLE build, though we may patch it regardless of which toolchain is chosen for the Binary Factory. (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104862, https://bugs.chromium.org/p/angleproject/issues/detail?id=7179)
  • The official Rust compiler may have issues working with llvm-based and/or ucrt-based mingw-w64 toolchains. (https://github.com/rust-lang/rust/issues/72241)
    • Note however we do *not* actually require Rust. The only dependency that needs Rust is Rav1e, which is optional and not actually used on the Binary Factory for Windows and macOS. (They use libaom instead.)
  • llvm-mingw supports cross-compiling for Windows aarch64 (MSVC can too, but mingw-builds or GCC can't), though we will need to adjust our build system for that to happen and I don't plan to do it soon.
  • llvm-mingw and MSYS CLANG64 supports ASAN, though for best effect one needs to also build all deps locally with ASAN, so not really a concern with the Binary Factory, unless we also want to make nightly builds with ASAN.
  • llvm-mingw supports producing .pdb debugging symbols which may allow us to get better crash reports for the Microsoft Store release. I don't really know how that works though and it also requires changing parts of the build process.

Suggestion (personal opinion)

To be clear, I am partial towards a purpose-built standalone toolchain so my suggestion is biased. Considering the extra work needed to manage a MSYS2 build environment or toolchain (manual dependency updates) and the lack of tagged stable releases, I would not recommend using MSYS2 for the Binary Factory. This leaves mingw-builds and llvm-mingw. I am in favour of moving to ucrt instead of msvcrt. Therefore I would recommend switching to llvm-mingw.

Action Plan

alvinhochun updated the task description. (Show Details)Apr 19 2022, 8:16 AM
alvinhochun updated the task description. (Show Details)Apr 26 2022, 7:33 AM

I approve of the move, it'll bring superb performance improvements for very little cost. It's also got a great suite of checks and sanitizers.

Only drawback I can imagine of is that at present, Visual Studio Code doesn't support debugging with LLDB, and the extension that does has a broken console handler: https://github.com/vadimcn/vscode-lldb/issues/400

But I already use MSVC for my own builds, so while unrepresentative of our CI situation, it's a further sanity check.

I use gdb to debug the llvm build, because lldb doesn't yet know how to read the split debug info (I always test with the packaged build instead of running from the install prefix directly).

I also run from the terminal and have to debug krita.com instead of krita.exe, otherwise Ctrl+C does not break into the debugger. Never actually tried launching the debugger for Krita from vscode...

alvinhochun triaged this task as Normal priority.
alvinhochun added subscribers: bcooksley, rempt.

Okay, Halla gave the approval on IRC. Dmitry won't be around for a while but in MR !1372 he agreed to switching to Clang so I think he should be fine with this too. We can start the transition after Halla has finished making the 5.0.6 release this week.

@bcooksley We will need https://github.com/mstorsjo/llvm-mingw/releases/download/20220323/llvm-mingw-20220323-ucrt-x86_64.zip to be extracted to C:/MingW/ (so that the Clang is available at C:/MingW/llvm-mingw-20220323-ucrt-x86_64/bin/clang-14.exe). This can be done ahead of time. Then I will make the MR to update the binary factory pipeline when we are ready to make the switch. Do you have any concerns with this? Shall I make a sysadmin ticket?

Being unfamiliar with the whole world of MingW/MSys2 - is there any reason that particular build of LLVM is being targeted and why we're not sourcing Clang via MSys2?

@bcooksley because MSYS2 is a rolling release distribution, and IIRC from our IRC conversations, you and Dmitry weren't comfortable with the idea of not having a pinned version.

I see - is there a better way of doing this rather than a zip file from a Github repository that does not appear to be affiliated with the main MSys2 project?
(I'm not sure about MSys2's package manager, but most let you specify the version to install/work with)

It is possible to build or cross-compile the whole toolchain ourselves with the scripts in https://github.com/mstorsjo/llvm-mingw, but I'd rather not do that... Note that MSYS2 is "only" an environment that provides some GNU tools and compiler toolchains based on mingw-w64. The current mingw-builds toolchain we use isn't affiliated with MSYS2 either. Obviously the different parties cooperate with mingw-w64 but neither are the official mingw-w64 toolchain and mingw-w64 does not make an official toolchain. So we either work with prebuilt toolchains, or compile everything manually.

MSYS2 is a rolling release, like Arch Linux (very much, it even uses pacman as the package manager), so you really can't pin package versions unless you archive them somewhere (or you can build them from source, but the compiler you use to build them won't be pinned either).

Meh, that is really quite the terrible situation, no wonder why MSVC is generally considered to be the only supported compiler on Windows...

alvinhochun updated the task description. (Show Details)May 7 2022, 9:41 AM
alvinhochun updated the task description. (Show Details)May 21 2022, 12:18 PM

I've now deployed the LLVM Windows toolchain to C:\MingW-LLVM\ on both Binary Factory builders.
We cannot use C:\MingW\ as it is in use by the existing MingW toolchains.