digitalmars.D - [Proposal] Switch to the Universal CRT on Windows.
- Adam Wilson (38/38) Jun 30 I recently got hit by a rather esoteric bug that looked like a
- Adam Wilson (11/18) Jun 30 It was noted to me by ADR on Discord that we could keep the
- Dennis (15/17) Jul 01 I'm in favor, but can I say that this shows how much of a
- Denis Feklushkin (9/20) Jul 01 I also agree with this, for the reason that libc slows down
- Guillaume Piolat (7/13) Jul 02 I'm not sure if it's easy to implement and maintain fopen for
- Denis Feklushkin (6/12) Jul 03 Seems this isn't used in the druntime.
- Adam Wilson (14/20) Jul 02 There is a technical argument for leaving `libc` behind as well.
- Richard (Rikki) Andrew Cattermole (4/26) Jul 02 This is sounding far too platform specific, and will make it so it
- Adam Wilson (6/11) Jul 02 And how do you avoid making it platform specific? The reason I
- Richard (Rikki) Andrew Cattermole (9/23) Jul 02 Simple, you won't be doing these things in it.
- Adam Wilson (9/10) Jul 04 That is nothing like what I proposed last year or what we have
- Richard (Rikki) Andrew Cattermole (5/17) Jul 04 Indeed.
- Walter Bright (1/1) Jul 03 https://github.com/dlang/dmd/pull/23351
- Walter Bright (2/3) Jul 03 This should be picked up by chkformat.d ?
- Walter Bright (2/4) Jul 03 I agree. fopen() is not used in dmd.
- Kagamin (24/28) Jul 16 ```
- Lance Bachmeier (5/7) Jul 01 It's 2026 so I agree. I don't do much with Windows beyond my work
- Adam Wilson (79/86) Jul 07 I thought it would be good to post an update on this work since
- Richard (Rikki) Andrew Cattermole (2/2) Jul 07 Very well done!
- Walter Bright (4/4) Jul 07 Here's a note of genuine appreciation for your efforts from me!
- Adam Wilson (10/15) Jul 07 You're welcome!
- Walter Bright (2/19) Jul 07
I recently got hit by a rather esoteric bug that looked like a real bug, but was actually not a bug, but also kind of a bug. Specifically, on Windows the printf `%zd` format would fail with a Segfault. The simple fix was to delete `%zd` and use `%d` with a cast to a fixed size int type. But it was the wrong fix. The actual root cause is that I was running `build.d` and `build.d` decided to use the 13 year old MSVCR120.dll, which does not support `%zd` printf formats. Despite the fact that I have the most modern C++ build tools and SDK's that you can get installed on my machine. (I work on Windows for a living, to my enduring shame) The result is that we ship a fallback CRT that doesn't even support building the compiler itself. Egg, meet face. The solution is pretty straight-forward. Use the Universal CRT for everything on Windows. And it turns out that there is another reason to abandon everything but UCRT. MINGW64 is now deprecated in favor of UCRT. (See blog post [here](https://www.msys2.org/news/#2026-03-15-deprecating-the-m ngw64-environment)) Therefore, we will be required to make this change at some point in the near future because MinGW is forcing us too. Moving to UCRT will also allow us to deprecate and eventually remove the giant bag of hacks that is our MINGW64 support. Anybody not using Windows 10 or greater will need to install the UCRT as a minimum from [here](https://support.microsoft.com/en-us/topic/update-for-universal-c-runtime-in-windows-322bf30f-4735-bb94-3949-49f5c49f4732). However, I think this is acceptable because our policy is that we only officially support the versions of Windows that Microsoft does for ESU, which means Win10 22H2 (until October 2028) or Win11. And since UCRT has been back-ported to older systems by Microsoft itself, it's an easy problem to handle for people deploying D-code. Note for Walter: You will need at least the 2015 Build Tools on Win7, which you can get [here](https://www.microsoft.com/en-us/download/details.aspx?id=48159). Or if you want something a little newer, the VS2017 build tools are [here](https://aka.ms/vs/15/release/vs_buildtools.exe). I have posted a PR [here](https://github.com/dlang/dmd/pull/23345). This PR deprecates (but still allows) the msvcr120 fallback path as well as updating various detection routines to include the latest versions of VS and deprecate anything prior to VS2015. If no WinSDK or VS installation is detected then the compiler throws an error.
Jun 30
On Wednesday, 1 July 2026 at 01:24:05 UTC, Adam Wilson wrote:I have posted a PR [here](https://github.com/dlang/dmd/pull/23345). This PR deprecates (but still allows) the msvcr120 fallback path as well as updating various detection routines to include the latest versions of VS and deprecate anything prior to VS2015. If no WinSDK or VS installation is detected then the compiler throws an error.It was noted to me by ADR on Discord that we could keep the ability to build without the WinSDK/VS if we included the appropriate UCRT library files from MinGW and updated `lld-link.exe`. We might want to consider including more than just the UCRT library files from MinGW so we can support building projects that need more than the UCRT without requiring the WinSDK. Although, I would note that this is a bigger shift into a policy of shipping our own complete development environment, with the attendant overhead of making sure that environment is up-to-date.
Jun 30
On Wednesday, 1 July 2026 at 01:24:05 UTC, Adam Wilson wrote:The solution is pretty straight-forward. Use the Universal CRT for everything on Windows.I'm in favor, but can I say that this shows how much of a nuisance depending on libc is? Walter often says how printf is the most debugged function ever so we should leverage that in dmd, but here we are getting bitten by libc nonsense yet again. Between that, its [unsafe interface](https://github.com/dlang/dmd/pull/13987), stupid [global locale system](https://github.com/dlang/dmd/blob/cfae207a4dfa38bdc67b28986e263365adc577c3/compiler/src/dmd/r ot/port.d#L93-L104) and [random breakages](https://bugzilla-archive.dlang.org/bugs/23846/), are we really better off than if we just wrote our own D function to interpolate numbers in strings? In my own code I avoid libc as much as I can, using `CreateFileW` instead of `fopen` for example. Only a few essentials like memcpy and memset remain since LDC sometimes emits calls to that even when you don't write them yourself. At least those are simple and deterministic: I haven't found a libc yet that implements them visibly different than the rest.
Jul 01
On Wednesday, 1 July 2026 at 12:37:22 UTC, Dennis wrote:On Wednesday, 1 July 2026 at 01:24:05 UTC, Adam Wilson wrote:I also agree with this, for the reason that libc slows down porting to systems where it is not present. Maybe we need to get together somewhere and discuss it? My proposal was outlined [here](https://forum.dlang.org/post/mssdrzylsdqmpcnvakar forum.dlang.org): "druntime should not import core.stdc" Let the druntime use these functions through wrapper functions or aliases. There will be only about 10 of them in total, I think: malloc/free, some sync methods...The solution is pretty straight-forward. Use the Universal CRT for everything on Windows.I'm in favor, but can I say that this shows how much of a nuisance depending on libc is? Walter often says how printf is the most debugged function ever so we should leverage that in dmd, but here we are getting bitten by libc nonsense yet again. Between that, its [unsafe interface](https://github.com/dlang/dmd/pull/13987), stupid [global locale system](https://github.com/dlang/dmd/blob/cfae207a4dfa38bdc67b28986e263365adc577c3/compiler/src/dmd/r ot/port.d#L93-L104) and [random breakages](https://bugzilla-archive.dlang.org/bugs/23846/), are we really better off than if we just wrote our own D function to interpolate numbers in strings?
Jul 01
On Wednesday, 1 July 2026 at 12:37:22 UTC, Dennis wrote:In my own code I avoid libc as much as I can, using `CreateFileW` instead of `fopen` for example. Only a few essentials like memcpy and memset remain since LDC sometimes emits calls to that even when you don't write them yourself. At least those are simple and deterministic: I haven't found a libc yet that implements them visibly different than the rest.I'm not sure if it's easy to implement and maintain fopen for many systems. At least the libc is maintained by others. Other small challenges involves: emitting and parsing floating-point correctly. And the transcendental functions, that are not especially better in Phobos than in libc.
Jul 02
On Thursday, 2 July 2026 at 16:32:06 UTC, Guillaume Piolat wrote:I'm not sure if it's easy to implement and maintain fopen for many systems. At least the libc is maintained by others.It can be "implemented" by bypassing alias to libc's `fopen`Other small challenges involves: emitting and parsing floating-point correctly.Seems this isn't used in the druntime.And the transcendental functions, that are not especially better in Phobos than in libc.And the Phobos problem is a Phobos problem, essentially unrelated to the compiler and druntime. It will even be possible to disable some of its parts for which there will be no implementations.
Jul 03
On Wednesday, 1 July 2026 at 12:37:22 UTC, Dennis wrote:In my own code I avoid libc as much as I can, using `CreateFileW` instead of `fopen` for example. Only a few essentials like memcpy and memset remain since LDC sometimes emits calls to that even when you don't write them yourself. At least those are simple and deterministic: I haven't found a libc yet that implements them visibly different than the rest.There is a technical argument for leaving `libc` behind as well. Specifically if you want to do anything with async operations you're going to have to use the API's specific to that platform. For example: Linux has `io_uring` where Windows has I/O Completion Ports. `libc` stops working as a universal system interface when you need to do async work, which means that anywhere we might want to support an async interface, we'll need to use something other than `libc`. Another example is terminal colors. Windows has `SetConsoleTextAttribute()` where `libc` is the only choice on Linux. Which means we really should be abstracting away `libc`. IMO, BaseD is going to become that abstraction.
Jul 02
On 03/07/2026 5:14 PM, Adam Wilson wrote:On Wednesday, 1 July 2026 at 12:37:22 UTC, Dennis wrote:This is sounding far too platform specific, and will make it so it cannot be the base most library for D. This is what druntime is for.In my own code I avoid libc as much as I can, using `CreateFileW` instead of `fopen` for example. Only a few essentials like memcpy and memset remain since LDC sometimes emits calls to that even when you don't write them yourself. At least those are simple and deterministic: I haven't found a libc yet that implements them visibly different than the rest.There is a technical argument for leaving `libc` behind as well. Specifically if you want to do anything with async operations you're going to have to use the API's specific to that platform. For example: Linux has `io_uring` where Windows has I/O Completion Ports. `libc` stops working as a universal system interface when you need to do async work, which means that anywhere we might want to support an async interface, we'll need to use something other than `libc`. Another example is terminal colors. Windows has `SetConsoleTextAttribute()` where `libc` is the only choice on Linux. Which means we really should be abstracting away `libc`. IMO, BaseD is going to become that abstraction.
Jul 02
On Friday, 3 July 2026 at 05:18:38 UTC, Richard (Rikki) Andrew Cattermole wrote:On 03/07/2026 5:14 PM, Adam Wilson wrote:And how do you avoid making it platform specific? The reason I ask is that DRT does not yet exist in BaseD code. DRT would be after it in the build chain (BaseD->DRT->Phobos). So everything you write is going to be platform specific.IMO, BaseD is going to become that abstraction.This is sounding far too platform specific, and will make it so it cannot be the base most library for D. This is what druntime is for.
Jul 02
On 03/07/2026 5:57 PM, Adam Wilson wrote:On Friday, 3 July 2026 at 05:18:38 UTC, Richard (Rikki) Andrew Cattermole wrote:Simple, you won't be doing these things in it. They belong much further up the dependency graph. Based can only really do simple stuff like bit manipulation, memory copying byte by byte. Trying to expand the scope of it beyond this is just going to lead to massive problems both with binary sizes, as in 64k limit and make porting extremely difficult to even get off the ground. The scope is basically the same as compiler-rt builtins.On 03/07/2026 5:14 PM, Adam Wilson wrote:And how do you avoid making it platform specific? The reason I ask is that DRT does not yet exist in BaseD code. DRT would be after it in the build chain (BaseD->DRT->Phobos). So everything you write is going to be platform specific.IMO, BaseD is going to become that abstraction.This is sounding far too platform specific, and will make it so it cannot be the base most library for D. This is what druntime is for.
Jul 02
On Friday, 3 July 2026 at 06:08:39 UTC, Richard (Rikki) Andrew Cattermole wrote:The scope is basically the same as compiler-rt builtins.That is nothing like what I proposed last year or what we have discussed since then. The idea for BaseD has always been a trimmed-down no-gc standard library for projects that need it. That means basic terminal I/O, data structures, etc. If your goal for BaseD is limited "things the compiler needs to link successfully" then we have fundamentally different views on the topic.
Jul 04
On 05/07/2026 4:50 PM, Adam Wilson wrote:On Friday, 3 July 2026 at 06:08:39 UTC, Richard (Rikki) Andrew Cattermole wrote:Indeed. The biggest difference is I know for a fact that what you want as-is is going to be a nightmare to fix. It will appear to work, right up until we can't do a release anymore.The scope is basically the same as compiler-rt builtins.That is nothing like what I proposed last year or what we have discussed since then. The idea for BaseD has always been a trimmed-down no-gc standard library for projects that need it. That means basic terminal I/O, data structures, etc. If your goal for BaseD is limited "things the compiler needs to link successfully" then we have fundamentally different views on the topic.
Jul 04
On 7/1/2026 5:37 AM, Dennis wrote:its [unsafe interface](https://github.com/dlang/dmd/pull/13987)This should be picked up by chkformat.d ?
Jul 03
On 7/1/2026 5:37 AM, Dennis wrote:In my own code I avoid libc as much as I can, using `CreateFileW` instead of `fopen` for example.I agree. fopen() is not used in dmd.
Jul 03
On Wednesday, 1 July 2026 at 12:37:22 UTC, Dennis wrote:In my own code I avoid libc as much as I can, using `CreateFileW` instead of `fopen` for example. Only a few essentials like memcpy and memset remain since LDC sometimes emits calls to that even when you don't write them yourself.``` extern(C): void* memset(void* dest, int c, size_t count) { RtlFillMemory(dest,count,cast(ubyte)c); return dest; } int memcmp(in char* b1, in char* b2, size_t count) { foreach(i;0..count)if(b1[i]!=b2[i])return b1[i]-b2[i]; return 0; } void* memmove(void* dst, in void* src, size_t count) { RtlMoveMemory(dst,src,count); return dst; } void* memcpy(void* dst, in void* src, size_t count) { return memmove(dst,src,count); } ``` Not sure how slow is this `memcmp` though.
Jul 16
On Wednesday, 1 July 2026 at 01:24:05 UTC, Adam Wilson wrote:The solution is pretty straight-forward. Use the Universal CRT for everything on Windows.It's 2026 so I agree. I don't do much with Windows beyond my work with R (much of it being interoperability with D), but they changed to UCRT years ago, and it made everything easier. Windows was a nightmare for R before the change.
Jul 01
On Wednesday, 1 July 2026 at 01:24:05 UTC, Adam Wilson wrote:I have posted a PR [here](https://github.com/dlang/dmd/pull/23345). This PR deprecates (but still allows) the msvcr120 fallback path as well as updating various detection routines to include the latest versions of VS and deprecate anything prior to VS2015. If no WinSDK or VS installation is detected then the compiler throws an error.I thought it would be good to post an update on this work since it turned into quite the adventure. The good news is that UCRT is now the default for all build paths in DMD on Windows. Including the MinGW build path. the `-mscrtlib` option is retained so that you can specify different variants of the CRT in Windows. You can also use it to specify older versions of the MSCVRT if you need to. However, while I was working on this PR, I ran into a number of "begats". The first was that the the nightly builds were broken, which prevented me from doing end-to-end testing of the UCRT support. So I fixed that with a liberal application of Opus 4.8. I even upgraded the script to upload the builds that succeeded even if one or more individual platform builds failed. The reason I made *that* change is because The FreeBSD build had been broken since April 8th. JMD kindly tracked down the actual brokenness in the FreeBSD build and fixed it in the DMD repo, then showed me the rest of the places where the fix would need to applied. While there was some help from Gemini to update the scripts to account for system level changes by GitHub, most of this work was by hand. Finally, I've also updated the Visual Studio / Build Tools detection logic in the Windows Installer to detect newer versions of the VS (which has irritated me for a while). We also made a change to the installer to be architecture sensitive. If you are still on a 32-bit machine, the options to install VS2026 (64-bit only) will be disabled and an option to install the VS2019 Build Tools (last 32-bit release) will be enabled. The reverse is true on 64-bit machines. These changes will be live in tomorrows nightly build. The reason I went to all of this trouble is that originally I was working on a PR to add some new features to the CodeView debugging symbol emitter on Windows to add some new types of information that have been made available since the last major update. And during testing of these changes `build.d` decided that it couldn't find the UCRT libraries so defaulted to the ancient MSVCR120 library that shipped with MinGW. Which incidentally segfaults when you try to use the `%zd` format in `printf`. Walter has since decided to remove `%zd` from DMD, but even so, upgrading to UCRT will be a major improvement in interoperability and security for D on Windows. The new CodeView data includes some nice quality-of-life improvements. 1. Complete Stack Frame information. Enables the debugger to more accurately traverse the stack. 2. UDT location information. The debugger will now be able to locate the source code for UDT's and navigate to them when you're stepping through code. 3. Environment info. Language and Compiler version info to inform the debugger to use the D dialect. Also include the original build path to the source file to help the debugger locate the source file on disk. 4. File content hashes. Now the debugger can detect when a file has change and inform you that the code your are debugging does not match what the debugger is seeing. While none of these changes are going to change your life, I think you'll find them to make the debugging experience a bit smoother. While the compiler may get all the attention and effort, the infrastructure we use to deliver D to other programmers has a strong "first impression" effect on how they perceive us. Broken nightlies, an installer that can't find the latest version of Visual Studio, outdated versions of the CRT libraries. All of these boring non-glamorous details reflect poorly on us. Which gets to another point. Part of the reason that these things are neglected is because the are difficult to work with and get absolutely no recognition when they work correctly but everybody notices when they don't. I think this is one area where the application of LLM's can be significantly beneficial to D. I didn't know anything about NSIS scripts or GitHub Actions before I started this project, but after watching the LLM do it's work, I do know more about those things, and how we use them in D (although some of our build system is literal madness). I was able to get done in a week what would've easily taken me a month or more to work out by hand. I firmly believe that D's "curb appeal" matters quite a bit, and hopefully the time that Rainer, JMD, Rikki, Nic, and I spent this week on improving that curb appeal will pay dividends in the future. That you to all you fantastic gentlemen for you help this past week!
Jul 07
Very well done! This stuff is never fun.
Jul 07
Here's a note of genuine appreciation for your efforts from me! BTW, I just downloaded dmd.2.112.0.osx.tar.xz for OSX, the official latest release, from https://dlang.org/download.html. Running its dmd yields: Segmentation fault: 11
Jul 07
On Tuesday, 7 July 2026 at 22:32:04 UTC, Walter Bright wrote:Here's a note of genuine appreciation for your efforts from me! BTW, I just downloaded dmd.2.112.0.osx.tar.xz for OSX, the official latest release, from https://dlang.org/download.html. Running its dmd yields: Segmentation fault: 11You're welcome! That is ... not a good look. I think this was fixed in master here: https://github.com/dlang/dmd/issues/21410 and released in 2.112.1. But I have to ask, why haven't we built a binary installer for 2.112.1 yet? I would have that we'd have shipped that by now. I know that the full release process is complex. Is this something that we could apply LLM's too and get the full release process automated?
Jul 07
On 7/7/2026 5:37 PM, Adam Wilson wrote:On Tuesday, 7 July 2026 at 22:32:04 UTC, Walter Bright wrote:If it was fixed it's not on the download page.Here's a note of genuine appreciation for your efforts from me! BTW, I just downloaded dmd.2.112.0.osx.tar.xz for OSX, the official latest release, from https://dlang.org/download.html. Running its dmd yields: Segmentation fault: 11You're welcome! That is ... not a good look. I think this was fixed in master here: https://github.com/dlang/dmd/issues/21410 and released in 2.112.1.But I have to ask, why haven't we built a binary installer for 2.112.1 yet? I would have that we'd have shipped that by now. I know that the full release process is complex. Is this something that we could apply LLM's too and get the full release process automated?
Jul 07









Adam Wilson <flyboynw gmail.com> 