Remove Zig's internal depedency on shell32.dll
and ole32.dll
#18091
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is mostly a proof-of-concept. Contributes towards #1840 although that's not the primary motivation.
Motivation
viri on Discord posted this article when we were talking about command line parsing and reasons for avoiding CommandLineToArgvW:
https://randomascii.wordpress.com/2018/12/03/a-not-called-function-can-cause-a-5x-slowdown/
The post details a considerable slowdown on process initialization whenever a process depends on
shell32.dll
(orole32.dll
by extension since it depends onshell32.dll
), even if none of the shell32/ole32 functions are called during the runtime of the program. This is due toshell32.dll
bringing ingdi32.dll
and causing some GDI-related initialization at process startup.This PR
This PR removes all dependencies on shell32/ole32 from Zig code, and removes
std.os.windows.shell32
/std.os.windows.ole32
entirely from the standard library.shell32.SHGetKnownFolderPath
This function was used to get the local app data directory in
std.fs.getAppDataDir
. This PR removes theSHGetKnownFolderPath
usage and instead just uses the environment variableLOCALAPPDATA
. This is not a perfect solution, asSHGetKnownFolderPath
does some complicated acrobatics with registry/user profile stuff.If this PR is merged, then a follow-up issue will be created for a proper
SHGetKnownFolderPath
reimplementation (or maybe a properSHGetKnownFolderPath
implementation could be a blocker for this PR). This would likely be based on Wine's.ole32
COM-related stuffThese functions were used in
windows_sdk.zig
to get Visual Studio installation instances via ISetupConfiguration. As noted in #16594 (comment) and #16594 (comment), the COM stuff under-the-hood was actually just reading.json
files from aMicrosoft\VisualStudio\Packages\_Instances
directory in%PROGRAMDATA%
.So,
windows_sdk.zig
now just reads those.json
files directly instead of going through the COM interface. If you're interested, here's a full log from Procmon of what all would happen during the previous COM-based implementation:https://gist.github.com/squeek502/2aa0b9498c5552fa887b1556291f8745
If you'd like to test the
zig libc
of this PR to make sure it still works on your setup, you can run this build oflibc_only.exe
:libc_only-20231123.zip
The encouraging results
No
shell32.dll
/ole32.dll
in a build of the compiler without LLVM:Compilers built without LLVM, printing the
--help
text:libc_only.exe
as detailed here:The dashed hopes
Unfortunately,
LLVMSupport.lib
has its own dependencies onshell32
'sSHGetKnownFolderPath
/SHFileOperationW
andole32
'sCoTaskMemFree
:which means that when building Zig with LLVM enabled, we inherit those dependencies and the slow process initialization returns, even if the
shell32
/ole32
functions aren't called. So, there's no actual gain in process initialization at all in status-quo Zig.The meager reality
The new
windows_sdk.zig
is faster than the previous implementation, but not too much (these are ReleaseFast compilers built with LLVM enabled):The path forward
Eventually, #16270 will come into play and Zig's lack of dependency on
shell32.dll
/ole32.dll
will become meaningful, so investment in shedding these dependencies should be worthwhile in the long run.In the meantime, there is a potential avenue to explore with regards to
-delayload
which is what LLVM uses to avoid the process initialization cost of theshell32
/ole32
dependency. I haven't put much effort into investigating this or if/how it could be utilized by Zig, but it might be possible. My naive attempt at building LLVM from source with MSVC and then building Zig with that didn't seem to get the-delayload
to carry over, but again I didn't look too closely/try much of anything.