Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ideas to improve windows header files and libc #9998

Open
marler8997 opened this issue Oct 21, 2021 · 54 comments
Open

ideas to improve windows header files and libc #9998

marler8997 opened this issue Oct 21, 2021 · 54 comments
Labels
os-windows proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Milestone

Comments

@marler8997
Copy link
Contributor

marler8997 commented Oct 21, 2021

Here's what MinGW provides for Zig:

  • C/C++ headers for the win32 APIs (means we can compile C/C++ code without depending on Visual Studio)
  • An implementation of libc for Windows

(Let me know if I'm missing something here)

The problems I've been having with MinGW

  • it seems to have alot of bugs (this may not be accurate, just my limited experience)
  • it's difficult to contribute to (patches over email, non-responsive, can take months to integrate changes)
  • MinGW's goals don't always align with Zig's, so sometimes it doesn't make sense for them to fix things that Zig needs
  • IMO, it's not "compatible enough" with MSVC so most projects need to add explicit support for MinGW. MinGW doesn't care to be more compatible and is OK with projects needing to put in work to support it alongside MSVC.

Every software has bugs, but MinGW's main problem here is that it's difficult, time consuming and slow to fix them. I think if this wasn't the case, I would have no issue continuing to use MinGW and submitting patches.

So what can we do? A big chunk of work is going to be getting C/C++ headers for the win32 APIs. Because Microsoft has released the https://github.com/microsoft/win32metadata project, and we are already using it to generate Zig bindings, we can enhance that project to generate C/C++ headers as well. I anticipate the initial work to support this would be just a few weeks.

That leaves us with the 2nd chunk of work, an implementation of libc for Windows. This work is already planned (#2879). With this it may be feasible to drop MinGW with work that's already planned and leveraging existing tools.

Thoughts, concerns?

P.S. Long term goal here is to completely replace the need for Visual Studio using this proposal and #8973

@SpexGuy
Copy link
Contributor

SpexGuy commented Oct 22, 2021

There are at least a couple other things mingw provides:

  1. .def files listing symbols in win32 dll files so that we can link with them
  2. build support via zig c++ for libraries that support mingw as a target

The first is something we could probably generate from the win32 metadata, but there may be hidden dragons in 2. Particularly, C libraries that assume that windows && !MSVC means mingw, and use mingw-specific header declarations.

@marler8997
Copy link
Contributor Author

Yeah def files are trivial to generate with win32metadata. I didn't really consider C++, there could definitely be some gotchas there.

@michal-z
Copy link
Contributor

michal-z commented Oct 22, 2021

@marler8997 Wouldn't it be easier to maintain our own fork of Mingw-w64?

Unfortunately https://github.com/microsoft/win32metadata also has bugs. Currently there are some critical errors for some DX APIs.

Also, looking at: https://github.com/mingw-w64/mingw-w64/commits/master it seems that development is pretty active. Have you tried reporting issues there?

@andrewrk andrewrk added os-windows proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. labels Oct 22, 2021
@andrewrk andrewrk added this to the 0.10.0 milestone Oct 22, 2021
@andrewrk andrewrk changed the title Drop MinGW Drop MinGW-w64 Oct 22, 2021
@andrewrk
Copy link
Member

This is quite an ambitious and interesting topic. I like the energy. Let's go over all the pieces here individually; there is a lot to consider.

it seems to have alot of bugs

Can you elaborate on this? Seems like you have some insight that I am not privy to.

it's difficult to contribute to (patches over email, non-responsive, can take months to integrate changes)

I share your preference for more "modern" systems for patches than email. However, if I'm being honest, it can take months for Zig pull requests to get merged too, sometimes. We have a few open since May of this year and that's on me, I really need to spend the time to figure it out and get those PRs merged or reviewed or otherwise addressed. But point being, can we do better than MinGW on this one metric? Maybe not.

I've also had some really pleasant interactions with Martin Storsjö when I asked for help on the MinGW-w64 on IRC. I do think that upstream is willing to work with us, and I personally see that relationship as valuable. This particular point, I do not see as compelling. However...

MinGW's goals don't always align with Zig's, so sometimes it doesn't make sense for them to fix things that Zig needs

I'm pretty sure I agree with you, but I'm curious what in particular you are considering.

IMO, it's not "compatible enough" with MSVC so most projects need to add explicit support for MinGW. MinGW doesn't care to be more compatible and is OK with projects needing to put in work to support it alongside MSVC.

I'm also curious to hear more details about this. I've used mingw-w64 in the past for various projects, and found its binary compatibility with MSVC to be flawless. Maybe I just got "lucky" but either way, it would help to have some more information on this axis to help move this issue along.

Every software has bugs, but MinGW's main problem here is that it's difficult, time consuming and slow to fix them. I think if this wasn't the case, I would have no issue continuing to use MinGW and submitting patches.

So, I'm actually finding myself kind of disagreeing with your reasoning here, but agreeing with your conclusion regardless. Idea being that if we can fulfill the Windows target features, as you listed them (implementation of libc for windows, .def files for windows, C/C++ headers for windows), without depending on this third party project, that would be an improvement.

Let's address each use case independently:

implementation of libc for windows

Indeed, there is a plan to do this already: #2879

Even if we stick with mingw-w64, the plan is to reduce the number of files that we depend on. For example, at the very least, all the math functions could be common and shared between all of zig's libc targets.

Even if this issue were not accepted, any progress towards replacing components of mingw-w64 libc with zig libc files would be welcome.

.def files for windows

Yeah def files are trivial to generate with win32metadata.

Neat! That's good to know.

C/C++ headers for windows

Because Microsoft has released the https://github.com/microsoft/win32metadata project, and we are already using it to generate Zig bindings, we can enhance that project to generate C/C++ headers as well. I anticipate the initial work to support this would be just a few weeks.

This is a cool idea - I hadn't considered that this is possible. Do you think it has a realistic chance of working, in the sense that it could generate a viable windows.h file that would be compatible with existing software? It might be worth doing a proof-of-concept for this to explore whether this is feasible.

@michal-z's point is important:

Unfortunately https://github.com/microsoft/win32metadata also has bugs. Currently there are some critical errors for some DX APIs.

That's good to know. One of the benefits mingw-w64 provides is that it has people using it and curating fixes to stuff like this. So we would be taking on that labor burden if we tried to do it with win32metadata ourselves. It could still be done, but that's something to consider. If win32metadata has bugs, that can be worked around, by us having "patch" data on top of it, that applies before lowering win32metadata to .h file(s). This is similar to the strategy that we do with tools/update_cpu_features.zig which applies some adjustments on top of LLVM's CPU features table data.

Conclusion

Seems like we should start with migrating logic from mingw-w64 to zig libc and then re-evaluate after that.

P.S. Long term goal here is to completely replace the need for Visual Studio using this proposal and #8973

Does the existing mingw-w64 integrations not already solve this problem? If not, can we list some explicit problems with status quo?

Anyway, seems like we have some stuff to explore. My goals are:

  • Making it practical to add C libraries as a dependency of a zig project even when cross compiling
    • .h file compatibility is not strictly required but an important consideration
  • Simplify the options needed to choose a target and improve the defaults
  • Improving the quality of generated machine code when using various targets
  • Reducing the maintenance burden of tracking third party projects and/or changing target data over time
  • Improving the robustness of zig-provided software such as libc for various targets
  • Increasing the contributor-friendliness of these components
  • Making zig more autonomous and less dependent on third party projects

I think I forgot a couple points, but hopefully this is enough to keep the issue moving forward.

@marler8997
Copy link
Contributor Author

marler8997 commented Oct 22, 2021

Andrew thanks for taking the time to respond with all your thoughts. I think we're mostly in agreement here. I think I'm going to go ahead with enhancing my zigwin32gen project to generate C/C++ headers first. This will be an easy (and fun) task for me that will give us alot of information about the feasibility of decreasing dependence on MinGW, and getting an idea of what benefits may come from it as well. In simple terms, this task is generating all the files in lib/libc/include/any-windows-any.

Below you'll find some of my thoughts and experiences. Since I think we're already in agreement, it doesn't seem necessary but I've included it anyway since you asked for it.

Thoughts and Experiences (unnecessary reading)

The "seems to have alot of bugs" statement comes from trying to use "zig cc" on various projects and getting header file errors from the mingw headers. For example I've come across this one a few times:

2021-08-04T11:54:57.4224911Z /snap/zig/3678/lib/libc/mingw/secapi/vsprintf_s.c:39:10: warning: implicit declaration of function '__ms_vsnprintf' is invalid in C99 [-Wimplicit-function-declaration]
2021-08-04T11:54:57.4225714Z   return __ms_vsnprintf (_DstBuf, _Size, _Format, _ArgList);

I'm guessing a portion of the errors I've seen over time were because of "zig cc" and not mingw itself. It just "seems" to me that it tends to have bugs for simple things that it shouldn't have, non-complicated use cases. Note that my use of the word "seems" here is intentional and comes from my limited experience. But even if mingw isn't all that buggy, Zig's usage of it (manual inclusion of particular files) is, and its usage is brittle since it's not supported by MinGW. I don't think MinGW is going to put in effort into supporting Zig's use case (and why would they) so this "bugginess" which results from the combination of Zig is the reality of our situation.

There's a lot of work left to do on the Zig windows toolchain, and when I see a problem with mingw itself, I know it's going to take along time to fix. For example, I submitted a 2-line change to fix how they were including a particular header. This change was needed in order to allow projects to have header files named "rpc.h", something which MSVC allows. One particular developer was against the change (an example of not caring much about MSVC compatibility), but Martin said the change was "ok" but it was in a header file shared with Wine, so Martin asked another contributor to forward the discussion to them. It's now been 6 weeks since then and the change hasn't been merged and there's been no follow up on whether the discussion was forwarded to Wine. I pinged them 3 days ago so maybe I'll hear back soon. If I was submitting a change like this to Zig, I wouldn't be scratching my head as to what's going on 6 weeks later.

I'll also point out that fixes to MinGW are dependent on the mingw release schedule. This could be mitigated with a pre-release patch system, but I'm weighing that work against what it would take to release or decrease dependence on mingw.

Marler(me): MinGW's goals don't always align with Zig's, so sometimes it doesn't make sense for them to fix things that Zig needs

Andrew: I'm pretty sure I agree with you, but I'm curious what in particular you are considering.

I should explain my motivation here. For some reason, the idea that Zig could be a replacement for Visual Studio is what excites me. My goal is to get Zig to become a drop-in replacement for msvc in as many projects as possible. I think dependence on MinGW is going to hold us back here. MinGW seems to have lower aspirations. For example, when I submitted a patch to fix an issue with some WSA inline function, rather than try to match what MSVC was doing which would have resulted in the most compatible solution, they were more concerned about modifying their headers and potentially breaking projects that depended on mingw's alternative behavior. I think this is a valid approach for MinGW to have, but I don't think it's the right approach for Zig. If we want to be a drop-in replacement, then compatibility with MSVC would be more important than supporting projects who have become dependent on our particular toolchain idiosyncrasies.

@marler8997
Copy link
Contributor Author

@michal-z

Wouldn't it be easier to maintain our own fork of Mingw-w64?

Short term definitely. Long term, almost certainly not. Long term we should already have a common libc we can leverage, and zigwin32gen/win32metadata can also be leveraged for most everything else. I'm not sure about libc++, but we could still leverage MinGW for that if we were so inclined.

Unfortunately https://github.com/microsoft/win32metadata also has bugs. Currently there are some critical errors for some DX APIs.

True, but they're "usually" quick to fix them and when we don't want to wait for them, I've already got systems in place to patch them.

Patching data like win32metadata is easier than patching a codebase like MinGW.

@y0shir
Copy link

y0shir commented Oct 29, 2021

That doesn't mean dropping optional compatibility with MinGW? Just because microsoft compiler is the "dominant" one doesn't mean that there isn't many great projects that depend on MinGW in some form.

@slimsag
Copy link
Contributor

slimsag commented Dec 5, 2021

@marler8997

I am discovering mingw-w64 headers are missing key updates to the Direct3D 12 headers, and the latest D3D12 headers from the Windows SDK are incompatible with mingw-w64's COM definitions etc. so I cannot intermix them. This is preventing me from building Dawn / WebGPU on Windows.

I saw your project above and I found your genc PR marlersoft/zigwin32gen#10 but I am curious how far along this work is, and if you still plan to work on it further?

@andrewrk
Copy link
Member

andrewrk commented Dec 5, 2021

@slimsag can you check mingw-w64 master branch and see if those headers are present and have the desired updates?

git clone git://git.code.sf.net/p/mingw-w64/mingw-w64

List of changed files:

 mingw-w64-crt/Makefile.am                          |   357 +-
 mingw-w64-crt/Makefile.in                          | 35120 ++++++++-----------
 mingw-w64-crt/configure                            |    65 +
 mingw-w64-crt/configure.ac                         |    31 +
 mingw-w64-crt/crt/charmax.c                        |     2 +-
 mingw-w64-crt/crt/crtdll.c                         |     4 +-
 mingw-w64-crt/crt/crtexe.c                         |    30 +-
 mingw-w64-crt/crt/mingw_helpers.c                  |     2 +-
 mingw-w64-crt/crt/pseudo-reloc.c                   |    21 +-
 mingw-w64-crt/crt/tlssup.c                         |     6 +-
 mingw-w64-crt/gdtoa/strtopx.c                      |    14 +
 ...-0.def => api-ms-win-crt-convert-l1-1-0.def.in} |     8 +-
 .../lib-common/api-ms-win-crt-math-l1-1-0.def.in   |     2 +-
 mingw-w64-crt/lib-common/computecore.def           |    63 +
 mingw-w64-crt/lib-common/computenetwork.def        |    61 +
 mingw-w64-crt/lib-common/computestorage.def        |    19 +
 mingw-w64-crt/lib-common/crtdll.mri                |     5 +
 mingw-w64-crt/lib-common/msvcr100.mri              |     5 +
 mingw-w64-crt/lib-common/msvcr110.mri              |     5 +
 mingw-w64-crt/lib-common/msvcr120.mri              |     5 +
 mingw-w64-crt/lib-common/msvcr120_app.mri          |     6 +
 mingw-w64-crt/lib-common/msvcr120d.mri             |     5 +
 mingw-w64-crt/lib-common/msvcr80.mri               |     5 +
 mingw-w64-crt/lib-common/msvcr80_64.mri            |     6 +
 mingw-w64-crt/lib-common/msvcr90.mri               |     5 +
 mingw-w64-crt/lib-common/msvcr90d.mri              |     5 +
 mingw-w64-crt/lib-common/msvcrt-os.mri             |     6 +
 mingw-w64-crt/lib-common/mswsock.def               |     2 +
 mingw-w64-crt/lib-common/ntdll.def.in              |    60 +
 mingw-w64-crt/lib-common/ntquery.def               |    17 +
 mingw-w64-crt/lib-common/query.def                 |    17 +
 mingw-w64-crt/lib-common/tbs.def                   |     3 +
 mingw-w64-crt/lib-common/ucrtbase.def.in           |     8 +-
 mingw-w64-crt/lib-common/ucrtbase.mri              |     5 +
 mingw-w64-crt/lib-common/ws2_32.def.in             |     1 +
 mingw-w64-crt/lib32/Makefile.am                    |     3 +
 mingw-w64-crt/lib32/authz.def                      |    36 +-
 mingw-w64-crt/lib32/fontsub.def                    |     4 +
 mingw-w64-crt/lib32/ksuser.def                     |    11 +-
 mingw-w64-crt/lib32/mswsock.def                    |    46 +-
 mingw-w64-crt/lib32/ntdll.def                      |    55 +
 mingw-w64-crt/lib32/ntquery.def                    |    17 +
 mingw-w64-crt/lib32/query.def                      |    17 +
 mingw-w64-crt/lib32/tbs.def                        |    15 +
 mingw-w64-crt/lib32/user32.def                     |   191 +-
 mingw-w64-crt/lib32/ws2_32.def                     |    14 +
 mingw-w64-crt/lib64/Makefile.am                    |     4 +
 mingw-w64-crt/lib64/query.def                      |  1447 -
 mingw-w64-crt/lib64/winhvplatform.def              |    37 +
 mingw-w64-crt/libarm32/Makefile.am                 |     1 +
 mingw-w64-crt/libarm32/query.def                   |    51 -
 mingw-w64-crt/libarm64/Makefile.am                 |     5 +
 mingw-w64-crt/libsrc/activeds-uuid.c               |    15 +-
 mingw-w64-crt/libsrc/bits.c                        |    17 +
 mingw-w64-crt/libsrc/ksuser.c                      |     1 +
 mingw-w64-crt/math/cephes_emath.c                  |  1283 -
 mingw-w64-crt/math/cephes_emath.h                  |   719 -
 mingw-w64-crt/math/x86/asinh.c                     |    55 +-
 mingw-w64-crt/math/x86/asinhf.c                    |    17 +-
 mingw-w64-crt/math/x86/asinhl.c                    |    15 +-
 mingw-w64-crt/math/x86/atanh.c                     |     2 +-
 mingw-w64-crt/math/x86/atanhf.c                    |     2 +-
 mingw-w64-crt/math/x86/atanhl.c                    |     2 +-
 mingw-w64-crt/misc/longjmp.S                       |     3 +
 mingw-w64-crt/misc/mingw_wcstod.c                  |    18 +-
 mingw-w64-crt/misc/mingw_wcstold.c                 |    96 +-
 mingw-w64-crt/misc/setjmp.S                        |     2 +
 mingw-w64-crt/misc/strtold.c                       |   398 -
 mingw-w64-crt/misc/wcstold.c                       |    64 +-
 mingw-w64-crt/stdio/mingw_pformat.c                |  1886 +-
 mingw-w64-crt/stdio/strtof.c                       |    18 +-
 mingw-w64-crt/stdio/ucrt_vfscanf.c                 |     2 +-
 mingw-w64-headers/Makefile.am                      |    10 +
 mingw-w64-headers/Makefile.in                      |    10 +
 mingw-w64-headers/crt/_mingw.h.in                  |     6 +-
 mingw-w64-headers/crt/_mingw_mac.h                 |     4 +-
 mingw-w64-headers/crt/corecrt.h                    |     5 -
 mingw-w64-headers/crt/ctype.h                      |     2 +-
 mingw-w64-headers/crt/intrin.h                     |     4 +
 mingw-w64-headers/crt/locale.h                     |     6 +
 mingw-w64-headers/crt/setjmp.h                     |     8 +-
 mingw-w64-headers/crt/wchar.h                      |     2 +-
 mingw-w64-headers/ddk/include/ddk/ata.h            |  1732 +
 mingw-w64-headers/ddk/include/ddk/ntifs.h          |     2 +
 mingw-w64-headers/ddk/include/ddk/wdm.h            |  1144 +-
 mingw-w64-headers/include/activation.h             |     2 +-
 mingw-w64-headers/include/activaut.h               |     2 +-
 mingw-w64-headers/include/activdbg.h               |     2 +-
 mingw-w64-headers/include/activdbg100.h            |     2 +-
 mingw-w64-headers/include/activprof.h              |     2 +-
 mingw-w64-headers/include/activscp.h               |     2 +-
 mingw-w64-headers/include/adhoc.h                  |     2 +-
 mingw-w64-headers/include/afunix.h                 |    19 +
 mingw-w64-headers/include/alg.h                    |     2 +-
 mingw-w64-headers/include/amstream.h               |     2 +-
 mingw-w64-headers/include/amvideo.h                |     2 +-
 mingw-w64-headers/include/asyncinfo.h              |     2 +-
 mingw-w64-headers/include/audioclient.h            |     2 +-
 mingw-w64-headers/include/audioendpoints.h         |     2 +-
 mingw-w64-headers/include/audiopolicy.h            |     2 +-
 mingw-w64-headers/include/austream.h               |     2 +-
 mingw-w64-headers/include/bdaiface.h               |     2 +-
 mingw-w64-headers/include/bits.h                   |  1540 +-
 mingw-w64-headers/include/bits.idl                 |   418 +
 mingw-w64-headers/include/bits1_5.h                |   589 +-
 mingw-w64-headers/include/bits1_5.idl              |   109 +
 mingw-w64-headers/include/bits2_0.h                |   815 +-
 mingw-w64-headers/include/bits2_0.idl              |   100 +
 mingw-w64-headers/include/bits2_5.h                |   270 +
 mingw-w64-headers/include/bits2_5.idl              |   102 +
 mingw-w64-headers/include/bits3_0.h                |   704 +
 mingw-w64-headers/include/bits3_0.idl              |    71 +
 mingw-w64-headers/include/bits5_0.h                |   581 +
 mingw-w64-headers/include/bits5_0.idl              |    59 +
 mingw-w64-headers/include/comadmin.h               |     2 +-
 mingw-w64-headers/include/comcat.h                 |     2 +-
 mingw-w64-headers/include/commoncontrols.h         |     2 +-
 mingw-w64-headers/include/computecore.h            |    82 +
 mingw-w64-headers/include/computedefs.h            |   119 +
 mingw-w64-headers/include/computenetwork.h         |   142 +
 mingw-w64-headers/include/computestorage.h         |    40 +
 mingw-w64-headers/include/control.h                |     2 +-
 mingw-w64-headers/include/ctfutb.h                 |     2 +-
 mingw-w64-headers/include/d3d10.h                  |     2 +-
 mingw-w64-headers/include/d3d10_1.h                |     2 +-
 mingw-w64-headers/include/d3d10effect.h            |     4 +-
 mingw-w64-headers/include/d3d10sdklayers.h         |     2 +-
 mingw-w64-headers/include/d3d11.h                  |     2 +-
 mingw-w64-headers/include/d3d11_1.h                |     2 +-
 mingw-w64-headers/include/d3d11_2.h                |     2 +-
 mingw-w64-headers/include/d3d11_3.h                |     2 +-
 mingw-w64-headers/include/d3d11_4.h                |     2 +-
 mingw-w64-headers/include/d3d11on12.h              |     2 +-
 mingw-w64-headers/include/d3d11sdklayers.h         |     2 +-
 mingw-w64-headers/include/d3d12.h                  |     2 +-
 mingw-w64-headers/include/d3d12sdklayers.h         |     2 +-
 mingw-w64-headers/include/d3d12shader.h            |     2 +-
 mingw-w64-headers/include/d3dcommon.h              |     2 +-
 mingw-w64-headers/include/dbgprop.h                |     2 +-
 mingw-w64-headers/include/dcommon.h                |     2 +-
 mingw-w64-headers/include/dcompanimation.h         |     2 +-
 mingw-w64-headers/include/ddstream.h               |     2 +-
 mingw-w64-headers/include/devicetopology.h         |     2 +-
 mingw-w64-headers/include/dimm.h                   |     2 +-
 mingw-w64-headers/include/dinput.h                 |     4 +-
 mingw-w64-headers/include/dinputd.h                |     2 +-
 mingw-w64-headers/include/directmanipulation.h     |     2 +-
 mingw-w64-headers/include/dispex.h                 |     2 +-
 mingw-w64-headers/include/dmodshow.h               |     2 +-
 mingw-w64-headers/include/docobj.h                 |     2 +-
 mingw-w64-headers/include/docobjectservice.h       |     2 +-
 mingw-w64-headers/include/documenttarget.h         |     2 +-
 mingw-w64-headers/include/downloadmgr.h            |     2 +-
 mingw-w64-headers/include/drmexternals.h           |     2 +-
 mingw-w64-headers/include/dsound.h                 |    12 +-
 mingw-w64-headers/include/dvdif.h                  |     2 +-
 mingw-w64-headers/include/dwrite.h                 |     2 +-
 mingw-w64-headers/include/dwrite_1.h               |     2 +-
 mingw-w64-headers/include/dwrite_2.h               |     2 +-
 mingw-w64-headers/include/dwrite_3.h               |     2 +-
 mingw-w64-headers/include/dxgi.h                   |     2 +-
 mingw-w64-headers/include/dxgi1_2.h                |     2 +-
 mingw-w64-headers/include/dxgi1_3.h                |     2 +-
 mingw-w64-headers/include/dxgi1_4.h                |     2 +-
 mingw-w64-headers/include/dxgi1_5.h                |     2 +-
 mingw-w64-headers/include/dxgi1_6.h                |     2 +-
 mingw-w64-headers/include/dxgicommon.h             |     2 +-
 mingw-w64-headers/include/dxgidebug.h              |     2 +-
 mingw-w64-headers/include/dxgiformat.h             |     2 +-
 mingw-w64-headers/include/dxgitype.h               |     2 +-
 mingw-w64-headers/include/dxva.h                   |   269 +
 mingw-w64-headers/include/dxva2api.h               |     2 +-
 mingw-w64-headers/include/dxvahd.h                 |     2 +-
 mingw-w64-headers/include/endpointvolume.h         |     2 +-
 mingw-w64-headers/include/eventtoken.h             |     2 +-
 mingw-w64-headers/include/evr.h                    |     2 +-
 mingw-w64-headers/include/evr9.h                   |   411 +-
 mingw-w64-headers/include/evr9.idl                 |   125 +
 mingw-w64-headers/include/exdisp.h                 |     2 +-
 mingw-w64-headers/include/filter.h                 |     2 +-
 mingw-w64-headers/include/fontsub.h                |    64 +
 mingw-w64-headers/include/fsrm.h                   |     2 +-
 mingw-w64-headers/include/fsrmenums.h              |     2 +-
 mingw-w64-headers/include/fsrmquota.h              |     2 +-
 mingw-w64-headers/include/fsrmreports.h            |     2 +-
 mingw-w64-headers/include/fsrmscreen.h             |     2 +-
 mingw-w64-headers/include/fusion.h                 |     2 +-
 mingw-w64-headers/include/fwptypes.h               |     2 +-
 mingw-w64-headers/include/hstring.h                |     2 +-
 mingw-w64-headers/include/icftypes.h               |     2 +-
 mingw-w64-headers/include/icodecapi.h              |     2 +-
 mingw-w64-headers/include/iketypes.h               |     2 +-
 mingw-w64-headers/include/inputscope.h             |     2 +-
 mingw-w64-headers/include/inspectable.h            |     2 +-
 mingw-w64-headers/include/ioringapi.h              |   140 +
 mingw-w64-headers/include/locationapi.h            |     2 +-
 mingw-w64-headers/include/mediaobj.h               |     2 +-
 mingw-w64-headers/include/medparam.h               |     2 +-
 mingw-w64-headers/include/mfapi.h                  |    64 +-
 mingw-w64-headers/include/mfidl.h                  |   542 +-
 mingw-w64-headers/include/mfidl.idl                |    56 +-
 mingw-w64-headers/include/mfobjects.h              |     2 +-
 mingw-w64-headers/include/mfplay.h                 |     2 +-
 mingw-w64-headers/include/mfreadwrite.h            |     2 +-
 mingw-w64-headers/include/mftransform.h            |     2 +-
 mingw-w64-headers/include/mmdeviceapi.h            |     2 +-
 mingw-w64-headers/include/mmreg.h                  |     6 +
 mingw-w64-headers/include/mmstream.h               |     2 +-
 mingw-w64-headers/include/mscoree.h                |     2 +-
 mingw-w64-headers/include/msctf.h                  |     2 +-
 mingw-w64-headers/include/mshtmhst.h               |     2 +-
 mingw-w64-headers/include/mshtml.h                 |     2 +-
 mingw-w64-headers/include/msinkaut.h               |     2 +-
 mingw-w64-headers/include/msinkaut_i.c             |     2 +-
 mingw-w64-headers/include/msopc.h                  |     2 +-
 mingw-w64-headers/include/mstcpip.h                |   241 +-
 mingw-w64-headers/include/msxml.h                  |     2 +-
 mingw-w64-headers/include/napcertrelyingparty.h    |     2 +-
 mingw-w64-headers/include/napcommon.h              |     2 +-
 mingw-w64-headers/include/napenforcementclient.h   |     2 +-
 mingw-w64-headers/include/napmanagement.h          |     2 +-
 mingw-w64-headers/include/napprotocol.h            |     2 +-
 mingw-w64-headers/include/napservermanagement.h    |     2 +-
 mingw-w64-headers/include/napsystemhealthagent.h   |     2 +-
 .../include/napsystemhealthvalidator.h             |     2 +-
 mingw-w64-headers/include/naptypes.h               |     2 +-
 mingw-w64-headers/include/netcfgn.h                |     2 +-
 mingw-w64-headers/include/netcfgx.h                |     2 +-
 mingw-w64-headers/include/netfw.h                  |     2 +-
 mingw-w64-headers/include/netlistmgr.h             |     2 +-
 mingw-w64-headers/include/ntdddisk.h               |     6 +
 mingw-w64-headers/include/ntioring_x.h             |    54 +
 mingw-w64-headers/include/ntsecapi.h               |  1147 +-
 mingw-w64-headers/include/ntstatus.h               |     1 +
 mingw-w64-headers/include/nvme.h                   |  2835 ++
 mingw-w64-headers/include/oaidl.h                  |     2 +-
 mingw-w64-headers/include/objectarray.h            |     2 +-
 mingw-w64-headers/include/objidl.h                 |     2 +-
 mingw-w64-headers/include/objidlbase.h             |     2 +-
 mingw-w64-headers/include/ocidl.h                  |     2 +-
 mingw-w64-headers/include/oleacc.h                 |     2 +-
 mingw-w64-headers/include/oleidl.h                 |     2 +-
 mingw-w64-headers/include/optary.h                 |     2 +-
 mingw-w64-headers/include/pchannel.h               |    16 +-
 mingw-w64-headers/include/portabledevicetypes.h    |     2 +-
 mingw-w64-headers/include/processthreadsapi.h      |    97 +
 .../include/proofofpossessioncookieinfo.h          |   173 +
 .../include/proofofpossessioncookieinfo.idl        |    70 +
 mingw-w64-headers/include/propidl.h                |     2 +-
 mingw-w64-headers/include/propsys.h                |     2 +-
 mingw-w64-headers/include/propvarutil.h            |   104 +-
 mingw-w64-headers/include/psdk_inc/_dbg_common.h   |    97 +-
 mingw-w64-headers/include/psdk_inc/_ip_mreq1.h     |     9 +
 mingw-w64-headers/include/psdk_inc/intrin-impl.h   |   119 +
 mingw-w64-headers/include/qedit.h                  |     2 +-
 mingw-w64-headers/include/qnetwork.h               |     2 +-
 mingw-w64-headers/include/rdpencomapi.h            |     2 +-
 mingw-w64-headers/include/regbag.h                 |     2 +-
 mingw-w64-headers/include/relogger.h               |     2 +-
 mingw-w64-headers/include/rtworkq.h                |     2 +-
 mingw-w64-headers/include/sapi51.h                 |     2 +-
 mingw-w64-headers/include/sapi53.h                 |     2 +-
 mingw-w64-headers/include/sapi54.h                 |     2 +-
 mingw-w64-headers/include/sdkddkver.h              |     3 +-
 mingw-w64-headers/include/sensorsapi.h             |     2 +-
 mingw-w64-headers/include/servprov.h               |     2 +-
 mingw-w64-headers/include/shldisp.h                |     2 +-
 mingw-w64-headers/include/shobjidl.h               |     2 +-
 mingw-w64-headers/include/shtypes.h                |     2 +-
 mingw-w64-headers/include/spatialaudioclient.h     |     2 +-
 mingw-w64-headers/include/spellcheck.h             |     2 +-
 mingw-w64-headers/include/strmif.h                 |     2 +-
 .../include/structuredquerycondition.h             |     2 +-
 mingw-w64-headers/include/taskschd.h               |     2 +-
 mingw-w64-headers/include/textstor.h               |     2 +-
 mingw-w64-headers/include/thumbcache.h             |     2 +-
 mingw-w64-headers/include/tlbref.h                 |     2 +-
 mingw-w64-headers/include/tlogstg.h                |     2 +-
 mingw-w64-headers/include/tpcshrd.h                |     2 +-
 mingw-w64-headers/include/tsvirtualchannels.h      |  1060 +
 mingw-w64-headers/include/tsvirtualchannels.idl    |   102 +
 mingw-w64-headers/include/tuner.h                  |     2 +-
 mingw-w64-headers/include/uianimation.h            |     2 +-
 mingw-w64-headers/include/uiautomationclient.h     |   198 +-
 mingw-w64-headers/include/uiautomationclient.idl   |   107 +
 mingw-w64-headers/include/uiautomationcore.h       |   269 +-
 mingw-w64-headers/include/uiautomationcore.idl     |    67 +-
 mingw-w64-headers/include/uiviewsettingsinterop.h  |     2 +-
 mingw-w64-headers/include/unknwn.h                 |     2 +-
 mingw-w64-headers/include/unknwnbase.h             |     2 +-
 mingw-w64-headers/include/urlhist.h                |     2 +-
 mingw-w64-headers/include/urlmon.h                 |     2 +-
 mingw-w64-headers/include/vmr9.h                   |     2 +-
 mingw-w64-headers/include/vss.h                    |     2 +-
 mingw-w64-headers/include/wbemads.h                |     2 +-
 mingw-w64-headers/include/wbemcli.h                |     2 +-
 mingw-w64-headers/include/wbemdisp.h               |     2 +-
 mingw-w64-headers/include/wbemprov.h               |     2 +-
 mingw-w64-headers/include/wbemtran.h               |     2 +-
 mingw-w64-headers/include/wdstptmgmt.h             |     2 +-
 mingw-w64-headers/include/winbase.h                |    17 -
 mingw-w64-headers/include/wincodec.h               |     2 +-
 mingw-w64-headers/include/wincodecsdk.h            |     2 +-
 mingw-w64-headers/include/wincon.h                 |    30 +-
 mingw-w64-headers/include/windns.h                 |   538 +-
 .../include/windows.foundation.collections.h       |     2 +-
 mingw-w64-headers/include/windows.foundation.h     |    74 +-
 .../include/windows.media.speechsynthesis.h        |    16 +-
 .../include/windows.security.cryptography.h        |    16 +-
 mingw-w64-headers/include/windows.storage.h        |    86 +-
 .../include/windows.storage.streams.h              |     2 +-
 mingw-w64-headers/include/windows.system.h         |     2 +-
 .../include/windows.system.threading.h             |    46 +-
 mingw-w64-headers/include/windowscontracts.h       |     2 +-
 mingw-w64-headers/include/winerror.h               |     1 +
 mingw-w64-headers/include/winevt.h                 |    21 +-
 mingw-w64-headers/include/winhvplatform.h          |    37 +
 mingw-w64-headers/include/winhvplatformdefs.h      |   731 +-
 mingw-w64-headers/include/wininet.h                |    98 +-
 mingw-w64-headers/include/winineti.h               |     1 +
 mingw-w64-headers/include/winioctl.h               |   475 +-
 mingw-w64-headers/include/winnt.h                  |   123 +-
 mingw-w64-headers/include/winsock2.h               |     1 +
 mingw-w64-headers/include/winsvc.h                 |   115 +-
 mingw-w64-headers/include/winuser.h                |     5 +-
 mingw-w64-headers/include/wmcodecdsp.h             |     2 +-
 mingw-w64-headers/include/wmcontainer.h            |     2 +-
 mingw-w64-headers/include/wmdrmsdk.h               |     2 +-
 mingw-w64-headers/include/wmp.h                    |     2 +-
 mingw-w64-headers/include/wmprealestate.h          |     2 +-
 mingw-w64-headers/include/wmpservices.h            |     2 +-
 mingw-w64-headers/include/wmsbuffer.h              |   315 +-
 mingw-w64-headers/include/wmsbuffer.idl            |    22 +
 mingw-w64-headers/include/wmsdkidl.h               |   381 +-
 mingw-w64-headers/include/wmsdkidl.idl             |    45 +-
 mingw-w64-headers/include/wmsecure.h               |   472 +
 mingw-w64-headers/include/wmsecure.idl             |    62 +
 mingw-w64-headers/include/wpcapi.h                 |     2 +-
 mingw-w64-headers/include/ws2ipdef.h               |     5 -
 mingw-w64-headers/include/wsdattachment.h          |     2 +-
 mingw-w64-headers/include/wsdbase.h                |     2 +-
 mingw-w64-headers/include/wsdclient.h              |     2 +-
 mingw-w64-headers/include/wsddisco.h               |     2 +-
 mingw-w64-headers/include/wsdhost.h                |     2 +-
 mingw-w64-headers/include/wsdxml.h                 |     2 +-
 mingw-w64-headers/include/wsmandisp.h              |     2 +-
 mingw-w64-headers/include/wtypes.h                 |     2 +-
 mingw-w64-headers/include/wtypesbase.h             |     2 +-
 mingw-w64-headers/include/wuapi.h                  |   159 +-
 mingw-w64-headers/include/wuapi.idl                |    25 +
 mingw-w64-headers/include/xapo.h                   |     2 +-
 mingw-w64-headers/include/xaudio2.h                |     2 +-
 mingw-w64-headers/include/xaudio2fx.h              |     2 +-
 mingw-w64-headers/include/xmllite.h                |     2 +-
 mingw-w64-headers/include/xpsdigitalsignature.h    |     2 +-
 mingw-w64-headers/include/xpsobjectmodel.h         |     2 +-
 mingw-w64-headers/include/xpsobjectmodel_1.h       |     2 +-
 mingw-w64-headers/include/xpsprint.h               |     2 +-
 mingw-w64-headers/include/xpsrassvc.h              |     2 +-
 mingw-w64-headers/wine-import.sh                   |    11 +
 mingw-w64-tools/genpeimg/src/genpeimg.c            |    81 +-
 mingw-w64-tools/genpeimg/src/img.h                 |     3 +-
 mingw-w64-tools/genpeimg/src/img_pe.c              |    21 +-
 mingw-w64-tools/widl/VERSION                       |     2 +-
 mingw-w64-tools/widl/configure                     |    20 +-
 mingw-w64-tools/widl/include/winbase.h             |     7 +-
 mingw-w64-tools/widl/include/winerror.h            |    24 +
 mingw-w64-tools/widl/include/winnt.h               |  1229 +-
 mingw-w64-tools/widl/src/header.c                  |    24 +-
 mingw-w64-tools/widl/src/widl.c                    |   105 +-
 370 files changed, 36845 insertions(+), 28703 deletions(-)

@slimsag
Copy link
Contributor

slimsag commented Dec 5, 2021

@andrewrk Yeah, this was the first thing I checked actually. Unfortunately, latest mingw-w64 headers do not fix this. I will see about filing issues upstream on mingw-w64

Here are some concrete examples of what I've found to be missing in the latest upstream mingw-w64-headers compared to the headers shipped with e.g. a recent Windows SDK (10.0.19041.0):

  • Windows SDK d3d12sdklayers.h defines ID3D12SharingContract, mingw-w64 headers do not.
  • Windows SDK d3d12.h defines ID3D12GraphicsCommandList4, mingw-w64 headers do not.
  • dxcapi.h (which appears to be a very popular / official DirectX library not shipped with the Windows SDK or MinGW) utilizes the _Maybenull_ and __in_ecount_opt macro definitions, both are defined in Windows SDK sal.h but not in mingw-w64 sal.h.
  • UWP headers - such as windows.ui.xaml.media.dxinterop.h - are also entirely missing in mingw-w64

I suspect that there are many more definitions than just these missing

@michal-z
Copy link
Contributor

michal-z commented Dec 5, 2021

Please note that latest DirectX 12 headers from Microsoft are here: https://github.com/microsoft/DirectX-Headers (those are standalone and MIT licensed).

DirectX 12 headers that come with Windows SDK have problems with functions that return structure by value (when compiled as C code).

mingw-w64 should use headers from Microsoft git repo if possible.

@michal-z
Copy link
Contributor

michal-z commented Dec 5, 2021

d3d12.h that comes with mingw-w64 (https://github.com/mingw-w64/mingw-w64/blob/master/mingw-w64-headers/include/d3d12.h) is very old (latest header provides ID3D12Device8 the one that come with mingw-w64 provides only ID3D12Device1).

@slimsag I think that your best bet is to take headers from https://github.com/microsoft/DirectX-Headers and put them into Dawn source tree.

@slimsag
Copy link
Contributor

slimsag commented Dec 5, 2021

@michal-z The primary problem isn't that the d3d12.h is outdated, I can workaround that by including updated d3d headers as you noted. The big problem is those last two bullet points I mentioned:

  • dxcapi.h (which appears to be a very popular / official DirectX library not shipped with the Windows SDK or MinGW) utilizes the _Maybenull_ and __in_ecount_opt macro definitions, both are defined in Windows SDK sal.h but not in mingw-w64 sal.h.
  • UWP headers - such as windows.ui.xaml.media.dxinterop.h - are also entirely missing in mingw-w64

These are direct dependencies of Dawn and the mingw-w64 headers are incompatible with them.

@andrewrk
Copy link
Member

andrewrk commented Dec 5, 2021

Note that we can carry patches to our mingw-w64 headers in the zig repo as long as the patches have been accepted upstream as well.

@michal-z
Copy link
Contributor

michal-z commented Dec 5, 2021

@slimsag Regarding macro definitions, I think you can do something like:

#define _Maybenull_
#define __in_ecount_opt(x)

in dxcapi.h.

But, yeah, UWP headers are problematic.

@andrewrk
Copy link
Member

andrewrk commented Dec 6, 2021

Got one piece of info from #mingw-w64 on OFTC:

<jon_y> andrewrk: directx headers are from Wine
<jon_y> you can contribute changes to sal.h

@slimsag
Copy link
Contributor

slimsag commented Dec 17, 2021

Lengthy write-up incoming, hoping this is useful to whoever else stumbles across this issue and attempts to solve it. After spending ~2 weeks on this, I don't feel I've made much progress and feel a bit ill at how large of a problem I now realize this may be for Zig w.r.t. cross compiling for Windows.

Hopefully some of this information is useful for us finding a long-term solution to this. It feels a bit like I've traveled inside a broken Fukushima reactor and back again, I'm planning to find some band-aids for myself and I probably won't dive back in again for now.

Here goes..

Windows header file sources

Authoritative sources for Windows API headers

We can find these in two places:

  1. The IDL files that Microsoft releases as part of the Windows SDK, which are redistributed under an MIT license here: https://github.com/microsoft/win32metadata/tree/master/generation/WinSDK/RecompiledIdlHeaders
    • But note the authoritative source is actually the Windows source code inside of Microsoft, the win32metadata repository merely has a script which copies them from the Windows SDK into the repo.
    • https://github.com/microsoft/DirectX-Headers similarly is a redistributed copy, Microsoft allows constributions to this repository to .h and .idl files, but ultimately they periodically synchronize the changes in this repository with the IDL files in the Windows internal repository and regenerate the .h files from the .idl sources found in the Windows SDK.
  2. Wine, they have a hand crafted (emphasis on that) recreation of Microsoft's IDL files. They're not the same at all as the IDL sources Microsoft distributes due to licensing concerns in the past.

MinGW-w64 may have some other headers (sal.h?) which it does not acquire from Wine, I didn't investigate this, but I strongly suspect almost all headers mingw-w64 distributes are generated from Wine's IDL files. Could be wrong though.

Non-authoritative sources for Windows API headers

  • Any .h file you find is actually generated from the IDL file from either Windows SDK or Wine. .h files are never the authoritative source.
  • https://github.com/microsoft/DirectX-Headers for example redistributes the IDL files and Microsoft employees periodically push commits to this repository which synchronize the IDL files from the Windows SDK with the IDL files distributed in this repository. The header files are generated using the MIDL compiler distributed with Visual Studio.
  • mingw-w64 pulls various headers from Wine's implementation, which generates them from their own hand-crafted IDL files.

Using IDL files

How IDL -> .h happens

There exist two IDL compilers which parse .idl files and generate .h files from them:

  1. MIDL, Microsoft IDL compiler, distributed with Visual Studio. Closed source.
  2. WIDL, Wine IDL compiler, found in tools/widl of the Wine source code.

IDL files are actually incredibly similar to the C header files themselves, what the generator does is quite minimal translation of syntax (but more on this below.)

Incompatibilities

Any header compiled with Microsoft's MIDL compiler, i.e. the .h files in:

Are fundamentally incompatible with mingw-w64 and gcc outright, and fundamentally incompatible with clang/zig when targeting a GNU ABI.

Header files generated using the Wine WIDL compiler (those distributed by Zig, those distributed by mingw-w64, and those in the Wine repository) are compatible with with all compilers (more on this below.)

Atrocities of COM / win32 headers

The COM calling convention differs from the C calling convention, in specific msvc has undocumented behavior in which aggregates are returned by pointer using a hidden 2nd parameter in COM C/C++ functions and methods. Clang and Zig emulate this undocumented msvc behavior when targetting msvc ABI, but not gnu ABI.

the IDL files distributed by Microsoft have attributes which denote which COM methods require a hidden parameter in order to store the return value.

How this is handled is where Wine and Microsoft headers differ greatly. When it comes to the C definitions, they are identical. For example Wine and Microsoft headers both define:

      D3D12_CPU_DESCRIPTOR_HANDLE *( STDMETHODCALLTYPE *GetCPUDescriptorHandleForHeapStart )( 
          ID3D12DescriptorHeap * This,
          D3D12_CPU_DESCRIPTOR_HANDLE * RetVal);

However, when it comes to C++ definitions Microsoft defines just:

virtual D3D12_CPU_DESCRIPTOR_HANDLE STDMETHODCALLTYPE GetCPUDescriptorHandleForHeapStart( void) = 0;

Despite what is written above, msvc and msvc-emulating compilers detect that the return value of this function is an aggregate and inject a second parameter (the return pointer.)

Wine on the other hand defines this same C++ virtual method as:

#ifdef WIDL_EXPLICIT_AGGREGATE_RETURNS
    virtual D3D12_CPU_DESCRIPTOR_HANDLE* STDMETHODCALLTYPE GetCPUDescriptorHandleForHeapStart(D3D12_CPU_DESCRIPTOR_HANDLE *__ret) = 0;
    D3D12_CPU_DESCRIPTOR_HANDLE STDMETHODCALLTYPE GetCPUDescriptorHandleForHeapStart()
    {
        D3D12_CPU_DESCRIPTOR_HANDLE __ret;
        return *GetCPUDescriptorHandleForHeapStart(&__ret);
    }
#else
    // We crash here!
    virtual D3D12_CPU_DESCRIPTOR_HANDLE STDMETHODCALLTYPE GetCPUDescriptorHandleForHeapStart() = 0;
#endif

When WIDL_EXPLICIT_AGGREGATE_RETURNS is defined, the headers are compatible with gcc, mingw-w64, and clang (when targetting gnu ABI.) Otherwise, the definition matches that found in the Microsoft headers and the headers become fundamentally broken for non-msvc-emulating compilers.

Relevant links:

Today, GCC/MinGW-w64 still cannot emulate msvc's COM calling convention behavior. Only clang can: llvm/llvm-project@85a0f8f#diff-48f9c7403ada1feaf517d77cd12f97c5bd239d6247190543d74b463c7da242ccR1058 (here you can see the ARM logic they use to detect an aggregate requiring a hidden return-by-paramete, which is much more complex than just "uses the COM calling convention".)

@marler32 and @michal-z ran into this for example in microsoft/win32metadata#636 and thought the Microsoft header definitions may be wrong, unfortunately not - msvc just has undocumented behavior of injecting a hidden parameter. Microsoft actually cannot alter the header definitions to match C calling convention, as msvc would still inject the secret parameter.

Me and @Andoryuuta found only one single semi-official reference to this undocumented behavior in msvc, as almost a footnote of this Raymond Chen article in 2014: https://devblogs.microsoft.com/oldnewthing/20040114-00/?p=41053

"The return value is placed in rax. If the return value is larger than 64 bits, then a secret first parameter is passed which contains the address where the return value should be stored. "

The harsh reality of all of this is that any Zig project which includes Microsoft headers and uses the default GNU ABI will compile just fine, but get a segfault when they invoke a COM method returning an aggregate as the hidden return parameter will be null.

Additionally, it means any C++ project compiled with Zig or MinGW that does not explicitly define WIDL_EXPLICIT_AGGREGATE_RETURNS themselves will find the same segfault. Truly horrific.

Failed approaches I investigated

The headers distributed in win32metadata are not sufficient

@andrewrk suggested we might be able to drop the GNU ABI support and only support msvc ABI. On that note, I checked to see if we can just use the .h headers distributed in https://github.com/microsoft/win32metadata/tree/master/generation/WinSDK/RecompiledIdlHeaders (which are MSVC compatible) and only use clang's msvc-emulating ABI target

The problem with this approach is that win32metadata is not complete: the headers included in this repository are generated by the Microsoft MIDL compiler distributed with Visual Studio and because of this they have a dependency on vcruntime.h and all the other headers distributed as part of Visual Studio, which are not open source.

  1. Even if we had a way to include those headers legally, it seems our libcxx is incompatible with those headers (at least when I tried swapping our any-windows-any headers dir for all of those): https://gist.github.com/slimsag/da3a5ffbba121289917eae5c49c5365a - I am not smart enough to resolve this.
  2. For cross-compilation, we still have no msvc runtime libraries we can redistribute. We need to depend on mingw/wine for libraries still, I'm unsure if we will run into more incompatibilities here. For example, I have seen indications MinGW-w64 and clang both may emit __mingw prefix'd references when invoking COM methods in gnu ABI targets.

Could we run the Wine WIDL compiler on Microsoft's IDL files?

Another thought I had was: what if we could merely run Wine's WIDL compiler on Microsoft's IDL files? Effectively giving us super-up-to-date headers for MinGW-w64 that could theoretically even be used by MinGW and Wine themselves.

I ran quite far with this experiment, and I believe it may be possible however I ran into two hurdles:

  1. The IDL files in https://github.com/microsoft/win32metadata/tree/master/generation/WinSDK/RecompiledIdlHeaders depend on what seems to be just two files not distributed as OSS: stdole32.tlb and stdole2.tlb which you can see are used via importlib here. Maybe we could get Microsoft to distribute these under a permissive license? Unsure.
  2. The Wine WIDL compiler does not support a whole litany of more modern syntax features that the Microsoft IDL files use. I have categorized these here but basically I think we'd either be looking at writing our own IDL compiler (which I think would not be too hard) or contributing some major changes to Wine's.

This was the approach I got furthest with. In fact, with relatively few patches I was able to use the WIDL compiler to compile most of the DirectX headers from Microsoft. I have not tested these yet, but I suspect they'll work and be compatible with MinGW/clang/zig with GNU ABIs using the WIDL_EXPLICIT_AGGREGATE_RETURNS definition hack. See recent commits in https://github.com/slimsag/win32metadata (21277d9f9c8860c75c9aee7319fe51d67a1301b7 and before)

Can we stick with wine/mingw-w64 headers and contribute to them?

This is the path of least effort, and what we're currently doing. I will say however that after what I have found here.. I feel quite confident the Wine headers are currently, and I suspect will remain for quite some time, very outdated.

Unfortunately, merging win32metadata IDL file changes into Wine's IDL files would be extremely non-trivial, too, because Wine's are hand-crafted much in the same way Microsoft's are - they differ quite a lot in syntax, ordering of definitions, and even which files symbols are defined in sometimes. Attempting to merge the two would be a seriously tedious undertaking.

@andrewrk
Copy link
Member

andrewrk commented Dec 18, 2021

Thank you for this really, really helpful writeup.

Could we run the Wine WIDL compiler on Microsoft's IDL files?

Despite your apparent emotional defeat, my take on this is that you successfully pioneered the way forward, and I think the Zig project can carry the torch from here. 🔥

@michal-z
Copy link
Contributor

michal-z commented Dec 18, 2021

This looks like handcrafted, Wine-based IDL with latest interfaces (up to ID3D12Device9), maybe we could use this one?
https://github.com/HansKristian-Work/vkd3d-proton/blob/master/include/vkd3d_d3d12.idl

This is basically nice and clean IDL without Microsoft specific annotations and it is also up to date. I think we should run Wine WIDL compiler on this.

@slimsag
Copy link
Contributor

slimsag commented Dec 18, 2021

@michal-z Ah, yes, I forgot to mention vk3d-proton. I did look into this as well. I do believe they are compatible with Wine's WIDL. However, they are actually quite stripped down and do not include D3D11 or prior, only good if you care about D3D12 (which in my case is a problem as Dawn also supports D3D11)

It also doesn't solve the larger issue of mingw-w64 headers being quite out of date, I think that is worth solving.

As for a temporary workaround: it's a good solution, also note I did manage to get the WIDL compiler to build the full latest d3d headers with minor patches - buried in my message above:

In fact, with relatively few patches I was able to use the WIDL compiler to compile most of the DirectX headers from Microsoft. I have not tested these yet, but I suspect they'll work and be compatible with MinGW/clang/zig with GNU ABIs using the WIDL_EXPLICIT_AGGREGATE_RETURNS definition hack. See recent commits in https://github.com/slimsag/win32metadata (21277d9f9c8860c75c9aee7319fe51d67a1301b7 and before)

@michal-z
Copy link
Contributor

@slimsag Using d3d11.idl from Wine and latest d3d12.idl from Proton should work, right? This would give us headers to build Dawn I suppose.

@slimsag
Copy link
Contributor

slimsag commented Dec 18, 2021

@michal-z The workaround I quoted above (should, I think / hope) give us headers to build Dawn, I just haven't tested it yet.

But no, mixing the Wine and Proton headers does not generally work. Multiple reasons for this: (1) proton headers strip out non-d3d12 things from files shared between d3d12/d3d11, e.g. in dxgibase, d3dcommon, etc. (2) proton headers use vk3d_ prefix (easy to fix) but also in constant names, etc. (3) proton headers redeclare some symbols, e.g. vkd3d_unknown.idl redeclares a subset of what is in the upstream unknwn.idl and unknwnbase.idl which leads to conflicts.

Basically if you want to do that, you need to manually port/copy over the portions of Proton's headers that you want into the Wine headers which is non-trivial (but slightly easier than copying from Windows SDK IDL -> Wine IDL, you don't have to remove annotations etc.)

@smourier
Copy link

Note the "secret first parameter" trick is officially documented here in the "x64 calling convention return values": https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#return-values

A scalar return value that can fit into 64 bits, including the __m64 type, is returned through RAX. Non-scalar types including floats, doubles, and vector types such as __m128, __m128i, __m128d are returned in XMM0. The state of unused bits in the value returned in RAX or XMM0 is undefined.

User-defined types can be returned by value from global functions and static member functions. To return a user-defined type by value in RAX, it must have a length of 1, 2, 4, 8, 16, 32, or 64 bits. It must also have no user-defined constructor, destructor, or copy assignment operator. It can have no private or protected non-static data members, and no non-static data members of reference type. It can't have base classes or virtual functions. And, it can only have data members that also meet these requirements. (This definition is essentially the same as a C++03 POD type. Because the definition has changed in the C++11 standard, we don't recommend using std::is_pod for this test.) Otherwise, the caller must allocate memory for the return value and pass a pointer to it as the first argument. The remaining arguments are then shifted one argument to the right. The same pointer must be returned by the callee in RAX.

@EvineDev
Copy link

EvineDev commented Dec 18, 2021

Extending from the x64 calling convention, there is 2 new rules in returning an struct / class from a method.

  1. Class / Struct of 8 bytes or less are always returned by pointer. Primitive types <= 8 bytes are still returned in registers.
  2. The Class / Struct this pointer takes precedence over the return object pointer. So you'll get this in rcx and return_pointer in rdx

Now, this is news to me. It's clearly not documented on the msdn page on calling conventions. And I don't see any reason for these changes to the abi.

I made a godbolt snippet where I explored the issue: https://godbolt.org/z/1xE6YnEnx

  1. fn_ret_obj returns in registers as the abi guide describes.
  2. fn_ret_int returns in registers as the abi guide describes.
  3. method_ret_obj returns by pointer. In contrast from what you would expect.
  4. method_ret_int returns in registers. This is what you would expect with a natural extension to the abi.

@michal-z
Copy link
Contributor

michal-z commented Dec 18, 2021

Agner Fog explains calling conventions in detail here: https://www.agner.org/optimize/calling_conventions.pdf
See:
Section 7.1 Passing and returning objects
Table 7. Methods for returning structure, class and union objects

All possible cases are described in above document.

@EvineDev
Copy link

A lot great information there, but I don't see it describing returning a simple structure, class or union from a method.

If I follow Table 7, I would expect returning a 4 byte struct from a method to do so via registers. But in my godbolt link the object is returned by pointer. See the method_ret_obj disassembly.

@mstorsjo
Copy link

My interpretation of both of these sources is that:

  1. Wine's WIDL implementation: determining if the return value should be via pointer is as simple as looking at whether or not the IDL type definition is a struct, union, coclass, interface, or runtimeclass. I couldn't tell you why Wine does not have special handling for the case of aarch64 here (maybe because it's dealing with IDL files and not C++ code, so this is unnecessary? Alternatively it could be a real bug with Wine on aarch64)

I'd guess that nobody has exercised those corners of Wine on aarch64 yet. But also, I think in practice, the difference between being non-POD or C++14 aggregate only is visible in more corner cases (not exactly familiar with the details of what constitutes a C++14 aggregate though). If you look at the same Godbolt testcase as above, but for aarch64 targets, you get the same difference for the method_ret_obj function: https://godbolt.org/z/fKjzGWceq

  1. Clang's implementation: Specifically of note is that whether or not the return value should be via pointer is dependent upon: (a) whether the return type is POD (non-aarch64) OR (b) whether the return type is a C++14 'aggregate' (aarch64 only) OR (c) is a C++ instance method.

I think this one is the correct one, but I don't know exactly in which cases the distinction differs.

But a much bigger issue regarding arm/aarch64, is that WIDL_EXPLICIT_AGGREGATE_RETURNS isn't enabled in mingw-w64 headers right now, but based on what I see right now, it really should.

Do you happen to have a minimal C++ standalone testcase that sets up a COM object and calls such a method, that I could try out for arm/aarch64 targets?

@slimsag
Copy link
Contributor

slimsag commented Dec 18, 2021

But a much bigger issue regarding arm/aarch64, is that WIDL_EXPLICIT_AGGREGATE_RETURNS isn't enabled in mingw-w64 headers right now, but based on what I see right now, it really should.

Yup! I think Zig (in GNU mode only) and MinGW-w64 should both be defining this by default, as it stands out of the box programs will compile but then segfault.

Do you happen to have a minimal C++ standalone testcase that sets up a COM object and calls such a method, that I could try out for arm/aarch64 targets?

Unfortunately not, what I have currently is quite entangled in a mess of other stuff. We will need to create such a minimal testcase from scratch.

@slimsag
Copy link
Contributor

slimsag commented Dec 18, 2021

Hmm, I don't think there's anything in Clang automatically emitting references to _mingw* anything unless it was present in the source?

Seems you're right! I think I got confused here.

@mstorsjo
Copy link

But a much bigger issue regarding arm/aarch64, is that WIDL_EXPLICIT_AGGREGATE_RETURNS isn't enabled in mingw-w64 headers right now, but based on what I see right now, it really should.

Yup! I think Zig (in GNU mode only) and MinGW-w64 should both be defining this by default, as it stands out of the box programs will compile but then segfault.

Indeed. Not sure if Zig is defining this manually (or whether it should), as mingw-w64 headers already do define it automatically where they think it's relevant: https://github.com/mingw-w64/mingw-w64/blob/master/mingw-w64-headers/crt/_mingw_mac.h#L356-L361
(But based on the reading of specs above, this workaround should be enabled everywhere in GNU mode, regardless of architecture.)

@slimsag
Copy link
Contributor

slimsag commented Dec 18, 2021

That's strange; I am pretty confident I ran into this with Zig in GNU mode, compiling C++ on an x86_64 platform - maybe that header was not getting included for me somehow. I'll see if I can debug further.

@mstorsjo
Copy link

That's strange; I am pretty confident I ran into this with Zig in GNU mode, compiling C++ on an x86_64 platform - maybe that header was not getting included for me somehow. I'll see if I can debug further.

Hmm, I think most of the mingw-w64 provided headers would end up pulling in those base headers. I guess it's plausible that it was missed if testing something specific to the IDL generated headers though - or if Zig just does something different. (Or if I'm misreading the headers somehow, and that define isn't normally defined? A minimal buildable and runnable testcase would be awesome here.)

@andrewrk
Copy link
Member

andrewrk commented Dec 18, 2021

To clarify Zig's end goal regarding libc, our goal is to provide static libc for Windows, with no dependency on msvcrt.dll and no dependency on UCRT either.

But a much bigger issue regarding arm/aarch64, is that WIDL_EXPLICIT_AGGREGATE_RETURNS isn't enabled in mingw-w64 headers right now, but based on what I see right now, it really should.

#10360

Edit: ah, I see that the mingw-w64 headers are intended to define this with preprocessor defines; let's explore sending a patch to mingw-w64 before merging this workaround.

@slimsag
Copy link
Contributor

slimsag commented Dec 18, 2021

I think my memory may be wrong about encountering this with Zig in a GNU target, sorry. I'd assume for now there is no issue with the WIDL_EXPLICIT_AGGREGATE_RETURNS define, and I'll report back if I can repro.

@mstorsjo
Copy link

To clarify Zig's end goal regarding libc, our goal is to provide static libc for Windows, with no dependency on msvcrt.dll and no depedency on UCRT either.

That's a quite nice goal in itself (and presumably worthwhile for static binaries on all platforms).

Are you planning to provide standalone C headers for this libc then too, or just rely on the platform's existing headers (mingw-w64 or UCRT, musl, etc)? I presume the latter. For math functions, it should be quite straightforward I think.

For things like printf etc, it's less straightforward though, to provide a cross-platform libc implementation. If potential future MSVC header compatibility is a target, the UCRT headers only have printf as an inline function calling e.g. __stdio_common_vfprintf, so if you want your libc to be usable with UCRT headers, that's the function you'd need to provide.

@andrewrk
Copy link
Member

andrewrk commented Dec 18, 2021

Ideally:

  • UCRT headers so that it could be used as a drop-in and already existing libraries will compile without problems
  • MSVC ABI

And then yep, we would just provide __stdio_common_vfprintf for Windows targets and whatever other special things are required to make it work. Of course we would want to share as much common implementations as possible, and as you noted this would be the most straightforward for math functions, but it would also be perfectly fine to have some Windows-specific code (and some Linux-specific code too).

I also wouldn't be against maintaining a patchset against UCRT headers if there were some improvements that could be made. The benefits of such patches would be weighed against the maintenance burden.

@PathogenDavid
Copy link

Hello all, I stumbled across this issue from it being posted on Hacker News.

Another source of the Windows SDK that I've not seen mentioned in this thread is the Microsoft.Windows.SDK.CPP NuGet package.

You can download the package directly using the link on the right, .nupkg files are just zip files in disguise so just unzip it with whatever. Note that the import libraires are found in separate architecture-specific packages such as Microsoft.Windows.SDK.CPP.x64.

These packages are unfortunately not permissively licensed so distribution might be problematic, but maybe Zig could just automatically download them as needed? If the main goal is to avoid having developers install Visual Studio or the Visual Studio Build Tools this is probably the closest you could get to an official solution.

(Apologies if I've misunderstood the goals here. I've not actually even had a chance to use Zig yet so I definitely don't have a great idea of what its needs are 😅)

@jbkempf
Copy link

jbkempf commented Dec 19, 2021

Now regarding headers, WinSDK generally has been non-redistributable

I have to emphase this. The Windows SDK is very far from being MIT or redistributable; both headers and IDLs are copyrighted heavily.

The Win32metadata gives a tool to generate, but if you look at the headers generated, they are not at all MIT.

@iainnicol
Copy link

The Windows SDK is very far from being MIT or redistributable

Very true. However, as @mstorsjo and I independently discovered, .h and .idl files are checked into the MIT licenced win32metadata repo, and these files are incredibly similar to those in the Windows SDK.

I have to politely but strongly disagree with mstorsjo here: I think it's very clear the files are MIT licenced, given the licence notice on the repo, but why draw unnecessary attention, in case corporate changes it mind?

It's also worth noting Microsoft plans to (but has not yet) open source most of vcruntime/vcstartup (minus some proprietary intel intrinsics). This is as part of their open source STL project. Also, the the cppwinrt files are MIT licenced, in the actual Windows SDK itself. Together these facts mean we could, in theory, put together a large subset of the Windows SDK, that's free software and MSVC-ABI compatible.

@jbkempf
Copy link

jbkempf commented Dec 19, 2021

However, as @mstorsjo and I independently discovered, .h and .idl files are checked into the MIT licenced win32metadata repo, and these files are incredibly similar to those in the Windows SDK.

I don’t think this is correct. The main license of the repo might be MIT but the files are not.

Examples:

The main project of win32metadata is the tooling to process the files, which is what the MIT is about.

I think it's very clear the files are MIT licenced

It's very clear they are not. See "all right reserved"

@mstorsjo
Copy link

The Windows SDK is very far from being MIT or redistributable

Very true. However, as @mstorsjo and I independently discovered, .h and .idl files are checked into the MIT licenced win32metadata repo, and these files are incredibly similar to those in the Windows SDK.

I have to politely but strongly disagree with mstorsjo here: I think it's very clear the files are MIT licenced, given the licence notice on the repo, but why draw unnecessary attention, in case corporate changes it mind?

Keep in mind that it's totally possible to have a mixture of licenses within one repo (e.g. BSD/MIT/LGPL/whatever). And these files very specifically say "All rights reserved", not "distributable according to the toplevel license file".

Given the unclear situation, I wouldn't start relying on this until the situation is clarified. And if it's a case where this is more or less accidental and they could realize their mistake and change their mind, then we definitely shouldn't rely on that.

@iainnicol
Copy link

iainnicol commented Dec 19, 2021

I don’t think this is correct. The main license of the repo might be MIT but the files are not.

Good examples. But the question is, when there's a contradiction, what takes precedence?

It's very clear they are not. See "all right reserved"

I'll note “All rights reserved” is also used with the BSD licences. It doesn't mean there can't be a separate permissive licence.

if it's a case where this is more or less accidental and they could realize their mistake and change their mind, then we definitely shouldn't rely on that.

On the other hand, if these files have been validly permissively licenced, that can't be undone.

I should probably clarify: I appreciate the points yous are making. I'm not saying it's 100% clear cut, more that it's arguable. I can also see why you'd prefer something was 100% clear, not just arguable. I also wonder what legal counsel would say. Regardless, hopefully there is some positive clarity.

@jbkempf
Copy link

jbkempf commented Dec 19, 2021

In case of conflict, of course the information of the file prevails.

This has always been the case in all Open Source distributions compliance.

All rights reserved is pretty clear, not arguable…

On the other hand, if these files have been validly permissively licenced, that can't be undone.

Copyright and authorships are valid whatever the license header say. Those rights are unalienable, by default.

Else I could take any file from anyone and slap a MIT header on it…

@PathogenDavid
Copy link

@89z cl.exe is not a part of the Windows SDK, it's a part of the MSVC toolchain. If you're looking for a foss alternative to the toolchain you can use the clang-cl and lld-link. Or if you're wanting the MSVC toolchain without Visual Studio you can install Build Tools for Visual Studio.

@PathogenDavid
Copy link

@89z You're definitely not understanding what this thread is about:

Here's what MinGW provides for Zig:

* C/C++ headers for the win32 APIs (means we can compile C/C++ code without depending on Visual Studio)

* An implementation of libc for Windows

MinGW provides both a GNU-based toolchain and an alternative SDK for building Windows software. Zig is using MinGW-w64, which represents only the latter. Those NuGet packages are the Microsoft-official equivalent of MinGW-w64.

@PathogenDavid
Copy link

@89z No idea, at a glance it looks like they're using lld. Either way it's not the subject of this thread.

@nektro
Copy link
Contributor

nektro commented Aug 17, 2022

windows linker is provided by llvm (and soon self hosted compiler) not mingw

@mirh
Copy link

mirh commented Jun 20, 2023

FWIW mingw did some major headers update in the last year or so (possibly even surpassing the mach sdk)

@gan-lin
Copy link

gan-lin commented Oct 9, 2024

Here are what I know:

For C:

  1. UCRT is redistributable (without debugging symbols): https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-170 , which means it can be included freely in any project;
  2. Part of UCRT is open sourced (under MIT license): https://www.nuget.org/packages/Microsoft.Windows.SDK.CRTSource

For C++:

  1. Microsoft standard C++ library (MSSTL) is open sourced: https://github.com/microsoft/STL
  2. Win32 API interface is published as a winmd file, and from it we can generate headers: https://github.com/microsoft/win32metadata (there are discussions above, but according to Where is an MIT-licensed Windows.Win32.winmd file? microsoft/win32metadata#1488 , it seems to be MIT licensed.)

I compared the files from "open sourced UCRT part" and UCRT in Windows SDK:

  • The headers are almost identical so it can be used interchange;
  • Suppose that each obj file is compiled from a cpp file, then I compared source code files in open sourced UCRT with obj files in libucrt.lib: most files are there; math functions (<math.h> and <complex.h>, or, libm) and a few compiler-generated functions (CFG?) are missing.

So I think it is possible to use the open sourced UCRT with the redistributable to form a build environment. But I'm not familiar to the problems about ABI.

@gan-lin
Copy link

gan-lin commented Oct 13, 2024

However, I found that vcruntime.h (#included by corecrt.h) may not be open sourced or redistributable. This has already been listed by zig libc. I've not considered before, and I wonder whether there is a solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
os-windows proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Projects
None yet
Development

No branches or pull requests

16 participants