Remove Zig's internal depedency on shell32.dll and ole32.dll#18091
Remove Zig's internal depedency on shell32.dll and ole32.dll#18091andrewrk merged 4 commits intoziglang:masterfrom
shell32.dll and ole32.dll#18091Conversation
Removes the dependency on shell32.dll. This is a stop gap solution until a proper SHGetKnownFolderPath Zig implementation is written
Removes the dependency on ole32.dll
7635496 to
0bc4ee1
Compare
|
Excellent work! I love the dramatic, insightful writeup. |
|
@squeek502 it might be worth adding a little CI check that zig doesn't depend on shell32.dll again? Otherwise this is likely to accidentally regress with some refactor |
Note that the compiler still depends on shell32 when built with LLVM enabled, so I think this would be better to do once the version of the compiler that actually gets shipped stops depending on shell32. Within |
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.dllby 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.dllbringing ingdi32.dlland 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.ole32entirely from the standard library.shell32.SHGetKnownFolderPathThis function was used to get the local app data directory in
std.fs.getAppDataDir. This PR removes theSHGetKnownFolderPathusage and instead just uses the environment variableLOCALAPPDATA. This is not a perfect solution, asSHGetKnownFolderPathdoes some complicated acrobatics with registry/user profile stuff.If this PR is merged, then a follow-up issue will be created for a proper
SHGetKnownFolderPathreimplementation (or maybe a properSHGetKnownFolderPathimplementation could be a blocker for this PR). This would likely be based on Wine's.ole32COM-related stuffThese functions were used in
windows_sdk.zigto 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.jsonfiles from aMicrosoft\VisualStudio\Packages\_Instancesdirectory in%PROGRAMDATA%.So,
windows_sdk.zignow just reads those.jsonfiles 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 libcof 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.dllin a build of the compiler without LLVM:Compilers built without LLVM, printing the
--helptext:libc_only.exeas detailed here:The dashed hopes
Unfortunately,
LLVMSupport.libhas its own dependencies onshell32'sSHGetKnownFolderPath/SHFileOperationWandole32'sCoTaskMemFree:which means that when building Zig with LLVM enabled, we inherit those dependencies and the slow process initialization returns, even if the
shell32/ole32functions 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.zigis 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.dllwill 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
-delayloadwhich is what LLVM uses to avoid the process initialization cost of theshell32/ole32dependency. 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-delayloadto carry over, but again I didn't look too closely/try much of anything.