On the other hand, it's a bit weird that Darling requires a kernel module. Given the name (darling-mach) I guess it's doing something to make Linux look more like XNU, but it's surprising that the Darling team has to do that within Linux itself (given that Wine is apparently able to make Linux look like NT in userspace).
Not sure it's the underlying reason, but for a long while Go would use raw syscalls on Darwin, which is something that Windows has explicitly sabotaged for ages. It's a lot easier to trap a library call from userspace than a syscall.
Their Linux kernel module does seem to be XNU based, but it feels like poor design / a rushed job to run it as a Linux kernel module instead of isolating it in userspace.
Rushed job? We've been at this for almost 8 years. We tried doing this without a kernel module for several years, but it just wasn't feasible.
You see, people think XNU is just another kernel, but it's very different from Linux or the Windows kernel. The only reason why we need a kernel module is Mach IPC. But this IPC is so critical and omni-present that a user-space process cannot even do a sleep() without using it. Even event loops in every GUI application use Mach IPC on the lowest level.
There is no way of implementing the full semantics of this IPC mechanism without a help from the kernel. For example, Mach IPC involves making direct memory copies between processes.
So even if we decided to take the "wineserver" approach, which would set us back by several years, the result would be super slow and not very compatible.
Also the userspace on macOS is quite different from other operating systems, which is why it's all taking us so long. MacOS is a bloated system with a huge number of layers sitting between the UI toolkit and the windowing server.
Imagine creating Wine from scratch. How much functionality would you need to implement to provide the correct behavior for a super-simple native GUI application? Probably just USER32, GDI32 and KERNEL32 would do. On MacOS, this is AppKit, QuartzCore, Foundation, CoreFoundation, libobjc and libSystem (which includes huge components such as libdispatch and emulating complex APIs such as kqueue).
FYI: The reason why we don't emulate raw syscalls is because this is not possible from kernel modules, unless you resort to techniques that could easily destabilize the whole system.
While I agree with your overall point (and agree that it's unfair to characterize the hard work y'all have been doing as a "rushed job")...
> How much functionality would you need to implement to provide the correct behavior for a super-simple native GUI application? Probably just USER32, GDI32 and KERNEL32 would do. On MacOS, this is AppKit, QuartzCore, Foundation, CoreFoundation, libobjc and libSystem (which includes huge components such as libdispatch and emulating complex APIs such as kqueue).
I don't think "number of APIs" is the reasonable benchmark for how difficult it might be to get a GUI application up and running. It's totally possible that macOS might more eagerly split out functionality into different systems while Windows combines that same functionality into relatively few. I don't know how true that is, but it'd be interesting to compare based on the depth of those libraries rather than just the quantity.
And from what I understand about Wine, all three of those Windows libraries are incredibly complex and convoluted, and even to this day have gaps in their Wine equivalents. Assuming macOS' greater quantity of necessary libraries add up to the same degree of API surface to be reimplemented, what y'all are doing is impressive, to say the least (and sure, Wine's more usable right now, but Wine also had a decade or two of a head start).