Windows GNU/MingW and MSVC binary C ABI compatibility guarantees

This question is a bit of a follow-up to the recent Cross-compiling for Windows: What is the difference between `-gnu` and `-msvc`?

How binary compatible are the -windows-gnu and -windows-msvc C ABIs, in theory and in practice?

Imagine I want to compile an executable for x86_64-windows-gnu. I have a library compiled for x86_64-windows-msvc (either by Zig or MSVC or some other compiler). Will I be able to link my executable with the library when

  1. the library is static (.lib or .a)
  2. the library is shared (.dll) and I’m linking implicitly
  3. the library is shared and I’m linking explicitly using LoadLibrary?

Is the same true if the situations are reversed, i.e. I’m compiling for MSVC and linking with a library compiled for GNU/MingW?

I’m having a lot of trouble finding any conclusive answers to this question on the web. Some seem to claim the ABIs are incompatible, others imply the incompatibility mainly applies to C++ specifics and not the C ABI, and Andrew has claimed that the C ABIs are binary compatible in the past.

I did some quick experiments of my own and tried compiling an executable and a DLL for -windows-gnu and linking them (both implicitly and explicitly), and then swapped out the compiled DLL for a different one compiled for -windows-msvc. The executable found and linked with the MSVC DLL just fine at runtime, which suggests that they are compatible, but I’m not sure if that was a fluke or something that is guaranteed to always work.

Does this compatibility hold true for static libraries as well?

I also know that some details differ between x86_64-windows-gnu and x86_64-windows-msvc, such as the size of C long double being 80 bits under the former and 64 under the latter, which suggests that only a subset of features are binary compatible. Are there any other differences that affect binary compatibility?

1 Like

Which MSVCRT? (MicroSoft Visual C RunTime)

With each Visual Studio, Microsoft used to release a new msvcrt library. For example msvc120.dll was version 12 of msvcrt, used by Visual Studio 2013. Your application had to distribute the mscvrt library with an installer.

uCRT (Universal C RunTime)

Universal CRT is a Windows component, included in Windows 10 or later and in Windows Server 2016 or later. There is no ucrt installer for these operating systems, because the library is a system component that is included and maintained with Windows Update. There are installers for older versions of Windows (even for Windows XP).

Visual Studio 2015 and later versions of Visual Studio all use Universal CRT.

Since universal crt is a windows component, Microsoft recommends dynamic linking to the universal crt library.

MinGW-w64

The version of mingw included with zig, can use universal crt: mingw-w64/mingw-w64-doc/howto-build/ucrt-vs-msvcrt.txt at master · mingw-w64/mingw-w64 · GitHub

The zig mingw update instructions configures mingw include files to use universal crt (--with-default-msvcrt=ucrt).
build update-mingw runs tools/update_mingw.zig to copy the implementation (I haven’t check if the library configuration is correct, but I believe it is).

Conclusion

Zig ming-w64 is compatible with universal crt.
You can mix dll’s that use universal crt but you cannot mix dlls that link to the older msvcrt.

What about C++?

For C++ you must have the same C++ library and the same exception (unwind) library for all of your code and libraries.
The best way is to build everything from source.
One binary only dll forces you to use a specific library, two or more binary only dll’s and if they use different libraries means that the game is over.
Note that these are C++ problems, since there is no C++ ABI, zig can do nothing to solve these problems.

3 Likes

For C++ msys2 have some differences on MinGW:

  • sys: mingw64, env: x86_64 => msvcrt + libstdc++ (legacy)
  • sys: ucrt64, env: ucrt-x86_64 => ucrt + libstdc++
  • sys: clang64, env: clang-x86_64 => ucrt + libc++ (like zig)