Bug 19760 – Windows 10 -m64 undocumented dependency on MSVC ++ Redistributable when linking with LLD

Status
NEW
Severity
critical
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Windows
Creation time
2019-03-25T01:54:55Z
Last change time
2024-12-13T19:02:38Z
Assigned to
No Owner
Creator
Jonathan Marler
Moved to GitHub: dmd#19544 →

Attachments

IDFilenameSummaryContent-TypeSize
1739verbose-dmd.txtVerbse DMD Outputtext/plain6412

Comments

Comment #0 by johnnymarler — 2019-03-25T01:54:55Z
Created attachment 1739 Verbse DMD Output --- hello.d import std.stdio; void main() { writeln("Hello!"); } > dmd -m64 hello.d > hello A windows pops up with: hello.exe - System Error The code execution cannot proceed because msvcr100.dll was not found. Reinstalling the program may fix this problem. Note that I do not have Visual Studio installed on this computer. The compiler is using lld-link.exe to link. I've attached the verbose compiler output as well.
Comment #1 by johnnymarler — 2019-03-25T02:19:45Z
I manually fixed the issue on my laptop by reading this thread: https://www.faqforge.com/windows/fix-the-program-cant-start-because-msvcr100-dll-is-missing-from-your-computer-error-on-windows/ It had me download and install this: https://www.microsoft.com/en-us/download/details.aspx?id=14632 So...the problem is that the DMD installation includes: dmd2\windows\lib64\mingw\msvcrt100.lib However, the msvcrt100.dll isn't necessarilly installed on the host system. So...dmd and/or lld-link should not be linking against ".lib" files when their ".dll" counterparts are not installed on the system. DMD should not be providing msvcrt100.lib to lld-link unless the dll is installed. The correct full solution may involve changes to both dmd and lld-link (LLVM's linker).
Comment #2 by b2.temp — 2019-03-25T07:48:32Z
I don't think this is an issue, at least certainly not critical. The error message is clear and once you have setup the right dynamic library the "problem" goes away. > However, the msvcrt100.dll isn't necessarilly installed on the host system. So...dmd and/or lld-link should not be linking against ".lib" files when their ".dll" counterparts are not installed on the system. But the reasoning is not good. the system where is linked the program is not necessarily the one that will run the program. And most importantly : you can definitely compile the program.
Comment #3 by johnnymarler — 2019-03-25T10:31:39Z
I have to respectfully disagree with you on the severity of this issue. This issue means that out of the box, any 64-bit executable compiled by dmd is broken. To run D any D program, the user now has to install this extra package and the only way for the end user to fix it is to Google this missing dll issue and figure out they need to download an extra package from microsoft. This issue affects all 64-bit programs compiled by dmd and only manifests at "load time". In my mind this is the epitome of critical issues. Because this library is not installed by default on windows machines, dmd should not be forcing every executable to have this load-time dependency. It should be compiling against a static version of the library by default, and allow the option to link against the dynamic one. Then the developer can choose when to depend on this extra package, and by doing so can protect their end user by checking that this dependency exists when their software is installed.
Comment #4 by kinke — 2019-03-25T10:38:57Z
> It should be compiling against a static version of the library by default Well, I wish it was that simple, but nope, Microsoft does not permit a 3rd party to ship with their static libs. So both DMD's and LDC's libraries are import libraries for their DLLs and based themselves on the MinGW definitions. [DMD's -m32 on Windows uses the DigitalMars C runtime, so that's different.]
Comment #5 by johnnymarler — 2019-03-25T10:48:12Z
Actually it appears Microsoft expects software installers to install their own msvcrt*.dlls (see wiki https://en.m.wikipedia.org/wiki/Microsoft_Windows_library_files) However that doesn't address the issue. Unless the dll is installed by default on all windows systems (i.e. kernel32.dll), dmd should not be forcing a runtime dependency on it.
Comment #6 by kinke — 2019-03-25T19:27:30Z
> Unless the dll is installed by default on all windows systems (i.e. kernel32.dll), dmd should not be forcing a runtime dependency on it. That's a Windows DLL, not to be confused with their C(++) runtime. I don't know if there's any MSVC runtime preinstalled on Windows, and if so, which version(s) (depending on the Windows versions). I do know that the 2015+ runtime is required to cover druntime properly (C99 additions + some relevant fixes). It's the same old story, nobody cares that one needs gcc/clang + binutils on Posix (for linking *and* the libs), but if a bunch of (easily redistributable) DLLs are required for running generated programs on Windows due to the restrictive MS license preventing to simply ship with their static libs, people complain - no offence intended, just an observation. Also note that Visual Studio defaults to /MD (dynamic runtime, i.e., these DLLs). So generated binaries also depend on those DLLs (but newer ones, vc100 is VS 2010).
Comment #7 by johnnymarler — 2019-03-25T21:04:52Z
> That's a Windows DLL, not to be confused with their C(++) runtime. Yes, not sure what your point is though. I was saying that DMD shouldn't add runtime dependencies that are not installed on all windows machines. msvcr100.dll is not installed on all machines. It is installed with Visual Studio or by the user manually downloading and installing a standalone version. > I don't know if there's any MSVC runtime preinstalled on Windows, and if so, which version(s) (depending on the Windows versions). I do know that the 2015+ runtime is required to cover druntime properly (C99 additions + some relevant fixes). Been reading about this and it looks like different compilers for different languages also run into this problem. https://gitlab.haskell.org/ghc/ghc/issues/14537 https://github.com/rust-lang/rfcs/issues/2355 It looks like there are different approaches being taken. > It's the same old story, nobody cares that one needs gcc/clang + binutils on Posix (for linking *and* the libs), but if a bunch of (easily redistributable) DLLs are required for running generated programs on Windows due to the restrictive MS license preventing to simply ship with their static libs, people complain - no offence intended, just an observation. If I compiled a "hello world" program on one linux machine and it wouldn't run on another linux machine without installing extra software that doesn't come out of the box, then I would certainly have a problem with that. That's what we're seeing here in the windows 10 case. If msvcr100.dll was installed on all machines by default then this wouldn't be an issue, but it isn't. It looks like msvcrt.dll (a different version) is always installed, however, Microsoft doesn't make any guarantees as to it's API. So you're taking a risk either way. > Also note that Visual Studio defaults to /MD (dynamic runtime, i.e., these DLLs). So generated binaries also depend on those DLLs (but newer ones, vc100 is VS 2010). Like I said in the issue, the machine this occurred on was one that didn't have visual studio installed. It's using the LLVM linker. If you installed the right version of visual studio then you would't run into this issue because it would have installed msvcr100.dll. However, requiring everyone to install visual studio to run programs compiled with "dmd -m64" is not a solution. In the end, the situation is that anyone running windows 10 who hasn't installed visual studio, will run into this error if they compile 64-bit code with dmd. Having a new user download dmd, compile their program and find out they can't run it is a very bad first impression. To solve this, we need to remove the dependency on msvcr100.dll, and switch to using a static library by default. If a program wants to use msvcr100.dll, they can explicitly configure that and make sure to include that dll in their software installer.
Comment #8 by kinke — 2019-03-25T23:13:50Z
> It looks like msvcrt.dll (a different version) is always installed If it is indeed preinstalled, that's the version from 2002-2003 IIRC. E.g., missing a whole lot of C99 math functions (but maybe not much more than the 2010 runtime). > If you installed the right version of visual studio then you would't run into this issue because it would have installed msvcr100.dll. However, requiring everyone to install visual studio to run programs compiled with "dmd -m64" is not a solution. You don't need full-blown Visual Studio (let alone the ancient 2010 one), you need the runtime redistributable of the matching version; for DMD v10 (VS 2010), for LDC v14 (VS 2015). But what I meant was that anyone compiling a C++ program with Visual Studio's default settings will also yield a binary depending on the runtime DLLs, just like DMD. That's of course no problem for the dev himself, but if he is to redistribute that program. > To solve this, we need to remove the dependency on msvcr100.dll, and switch to using a static library by default. Feel free not to trust me, but I had a look at their license, as shipping with static libs would have made the lives of some people around here much easier. Or are you suggesting to port the DigitalMars C runtime to 64-bits? Note that the MinGW runtime is no alternative, it is itself based on the Microsoft DLLs (yep, the MSVC ones, not just the Windows ones). A practical solution (well, the only really I can think of) would be checking the availability of those DLLs in the installer.
Comment #9 by dfj1esp02 — 2019-03-26T16:06:00Z
(In reply to kinke from comment #8) > Or are you suggesting to port the DigitalMars C runtime to 64-bits? Or musl :)
Comment #10 by johnnymarler — 2019-03-26T16:47:55Z
> Feel free not to trust me, but I had a look at their license, as shipping with static libs would have made the lives of some people around here much easier. > Or are you suggesting to port the DigitalMars C runtime to 64-bits? Note that the MinGW runtime is no alternative, it is itself based on the Microsoft DLLs (yep, the MSVC ones, not just the Windows ones). I'm not sure what the right solution is yet. It looks like different compilers are using different approaches. I think I've read that LIBCMT is a static version of MSVCRT.dll, but I can't confirm, and even if it is, there may be licensing issues like you point out. Maybe we could use msvcrt.dll (the unversioned one) for stuff that we're sure will never change and supplement it with another static library to fill in the holes. Maybe we chose another implementation that we can ship a static library of (DMC/MUSL). I'm not sure what the right solution is here. > A practical solution (well, the only really I can think of) would be checking the availability of those DLLs in the installer. This only works if you are creating an executable that you are shipping with an installer.
Comment #11 by kinke — 2019-03-26T18:16:55Z
> I think I've read that LIBCMT is a static version of MSVCRT.dll, but I can't confirm I can; also see the -mscrtlib cmdline switch. > Maybe we chose another implementation that we can ship a static library of (DMC/MUSL). Musl on Windows? I just mentioned alternative runtimes for completeness; even if somebody wanted to go through all that trouble, incl. adapting druntime, there'd be still one big drawback: if you want to mix D and C(++) code and use the same heap etc., you have to make sure both parts use the same runtime. So any non-MSVC runtime on Windows would be an exotic and as such bad choice, just like the DigitalMars C runtime and Optlink are (being phased out with -m32mscoff/-m64 by default). > This only works if you are creating an executable that you are shipping with an installer. I was talking about the DMD installer itself - checking if the libs or a Visual C++ (dev) installation is found, just so that the dev himself can run generated binaries without surprises. When redistributing you own Windows programs, you have two options - either bundle your software with the MS DLLs, like most C++ software does, or install Visual Studio or the Build Tools and link against the static runtime to prevent those runtime dependencies. The latter is clearly not an option for hobbyist devs; you surely remember all the threads of Windows users complaining about the Visual C++ dependency for linking.
Comment #12 by r.sagitario — 2019-03-26T18:44:55Z
I'm with kinke on this. We must not distribute the static MS libs, and the dynamic libs need to be installed (usually through the distributable installers). Didn't the installer warn you that no VC runtime was found and even proposed to install the VC2010 redistributables for you?
Comment #13 by johnnymarler — 2019-03-26T18:59:44Z
> Didn't the installer warn you that no VC runtime was found and even proposed to install the VC2010 redistributables for you? I'm talking about the the case where you build hello world on one windows machine, then run it on another. Are you saying that it's ok that you can't run simple binaries on other machines without putting them inside an installer and including the MSVC C++ Redistribuable runtime in your installer? And if that's the case, I haven't seen any documentation saying that all executables compiled by DMD need to be packaged with an installer and need to come with the Microsoft redistributable runtime.
Comment #14 by kinke — 2019-03-26T19:48:11Z
> Are you saying that it's ok that you can't run simple binaries on other machines without putting them inside an installer and including the MSVC C++ Redistribuable runtime in your installer? It sadly can't be avoided (and the only one to blame being Microsoft) for as long as druntime and Phobos depend on a C runtime, unless the dev installs Visual Studio or the Build Tools. Alternatively, just mentioning the MSVC runtime as prerequisite on the web or in some README might be enough in some cases. C# apps come with a .NET framework dependency, Java with JRE, and C(++)/D/Rust/... usually with the MSVC runtime (https://stackoverflow.com/questions/52153676/what-is-the-requirements-for-running-a-rust-compiled-program-on-another-windows). My Windows system with a moderate number of installed programs currently has 15 installed MSVC runtime versions (2005-2017, incl. different subversions). For LDC, I wrote this in an attempt to clarify that dependency: https://github.com/ldc-developers/ldc/blob/8f81d0797b7cb4bc44aeb6565366a8d31945b8c4/packaging/README.txt#L10-L18
Comment #15 by dfj1esp02 — 2019-03-28T11:38:23Z
(In reply to kinke from comment #11) > Musl on Windows? I just mentioned alternative runtimes for completeness; > even if somebody wanted to go through all that trouble, incl. adapting > druntime, there'd be still one big drawback: if you want to mix D and C(++) > code and use the same heap etc., you have to make sure both parts use the > same runtime. Technically there's Universal CRT. If the problem is only with math functions, I suppose those can be separately taken from musl, should be standalone. If you use C/C++ code, you either compiled it and then have visual studio, or not and you again have the problem of the same runtime.
Comment #16 by kinke — 2019-03-28T13:07:00Z
(In reply to anonymous4 from comment #15) > (In reply to kinke from comment #11) > > Musl on Windows? I just mentioned alternative runtimes for completeness; > > even if somebody wanted to go through all that trouble, incl. adapting > > druntime, there'd be still one big drawback: if you want to mix D and C(++) > > code and use the same heap etc., you have to make sure both parts use the > > same runtime. > > Technically there's Universal CRT. > If the problem is only with math functions, I suppose those can be > separately taken from musl, should be standalone. Please just trust my and Rainer's judgement on this, we have been deeply involved with all this. Universal CRT is one part of the newer MS runtimes since 2015 (and so used when linking against recent MS msvcrt.lib or libcmt.lib). It doesn't solve anything for us (as it isn't preinstalled on older Windows; not sure if it's preinstalled on Win10), except making the runtime installation somewhat harder (requires a reboot IIRC). The problem isn't only with math functions (e.g., no hex float parsing, buggy snprintf in older MS runtimes...). And in contrast to all/most? other x86(_64) runtimes, Microsoft chose 64-bit double precision for `long double`, so printf etc. from other runtimes won't work out of the box. And for LDC, we use the Visual C++ EH personality function (which for example is not part of the Universal CRT). > If you use C/C++ code, you either compiled it and then have visual studio, > or not and you again have the problem of the same runtime. I'm not sure I get what you mean. But the MS runtime is not just used by the MS compiler, but also by MinGW-gcc and the Intel compiler, and those are, I guess, at least a thousand times more popular than all the other C(++) compilers on Windows combined. If you meant that you need a runtime *version* compatible with the C(++) code, then yes, you either need an older Visual Studio compatible with that version, or you might get away with selecting one of the many runtime versions LDC ships with (all dynamic ones from VS 2002-2015) via `-mscrtlib`.
Comment #17 by dfj1esp02 — 2019-03-28T15:00:34Z
(In reply to kinke from comment #16) > Universal CRT is one part of the newer MS runtimes since 2015 (and so used > when linking against recent MS msvcrt.lib or libcmt.lib). It doesn't solve > anything for us (as it isn't preinstalled on older Windows; not sure if it's > preinstalled on Win10) It's delivered as system update to everything post XP. > The problem isn't only with math functions (e.g., no hex float parsing, > buggy snprintf in older MS runtimes...). These two must be standalone too. UCRT has standard snprintf, then there's a problem if some code actually relies on the buggy one. > And in contrast to all/most? other > x86(_64) runtimes, Microsoft chose 64-bit double precision for `long > double`, so printf etc. from other runtimes won't work out of the box. AFAIK, musl doesn't predefine fp precision and relies on declared precision definitions. Options: 1. keep using 100 or ms static lib 2. full static musl with ported malloc, stdio, personality, startup etc. 3. use ucrt and ported personality
Comment #18 by kinke — 2019-03-28T16:06:41Z
(In reply to anonymous4 from comment #17) > 2. full static musl with ported malloc, stdio, personality, startup etc. Won't work when mixing with C(++) code and you want a shared C runtime. Which shouldn't be an extremely exotic use case (D plugin as DLL). > 3. use ucrt and ported personality Won't work if you want to catch D exceptions from C++, something that's in principle doable with LDC for more than 3 years already (https://github.com/ldc-developers/dmd-testsuite/pull/15). Anyway, I'm out of this discussion, I think I made my points.
Comment #19 by johnnymarler — 2019-03-28T16:17:08Z
>> 2. full static musl with ported malloc, stdio, personality, startup etc. >Won't work when mixing with C(++) code and you want a shared C runtime. Which shouldn't be an extremely exotic use case (D plugin as DLL). You're straw manning. We're not talking about dropping support for msvcrt.dll, we're talking about making the default a static library. The developer can still opt-in to link against msvcrXX.dll, which they would when their software is going to be deployed with an installer or if they need to interoperate with C++ binaries. And by the way, DMD is currently only compatible with C++ programs that link against msvcr100.dll, a small subset of the versions of msvcrXX.dll. The fact that DMD binaries on windows are only compatible with a small subset of C++ binaries is a fact that should not be hidden from the developer. By making it "opt-in" rather than defaulting to one specific-version, you're making it easier for developers because now they know what their binaries are compatible with. > Anyway, I'm out of this discussion, I think I made my points. The main point I've gotten from you is that you think it's ok for simple programs compiled with DMD to not work on other's computers by default. Right now this is a fundamental disagreement between us that makes all your other points moot.
Comment #20 by johnnymarler — 2019-03-28T16:29:32Z
Another idea to mitigate this problem. Having a runtime dependency on a dll that is not intalled on Windows machines by default could be OK if we could fail with a message prompting user to install the Microsoft C++ Redistributable package. This could be done by loading the msvcr100.dll dynamically inside druntime rather than having the windows loader do it. This would also give us the ability to choose between multiple versions if we wanted to support that. Then in the case where it can't find the DLL, we could put up an error message or error window a message like: "This binary requires the Microsoft Visual C++ 2010 Redistributable package. Please install it to continue."
Comment #21 by kinke — 2019-03-28T18:05:55Z
(In reply to Jonathan Marler from comment #19) > The main point I've gotten from you is that you think it's ok for simple > programs compiled with DMD to not work on other's computers by default. Yep, totally my point, besides that being apparently no big deal (let alone critical issue rendering a compiler 'totally broken') for the comparatively huge Visual C++, Rust and MinGW user base. And with an absolutely trivial solution - just install Visual Studio and use the static libs (I think that's the default setting for DMD too, for LDC it definitely is), then your users won't need the redistributable. And that seems to be the crux - some Windows guys seem totally opposed to the idea of having to install the 'official system toolchain' for professional development, while having to install Xcode on Mac (also required for linking in general, not just to have the ability of linking the C runtime statically) is somehow far less considered a PITA. > This could be done by loading the msvcr100.dll dynamically inside druntime That'd be too late; druntime's _d_run_main (IIRC) is called from C main (emitted by the compiler), which is called by the C runtime, as that's where the actual entry point is. I wish Microsoft had added something similar as convenience ages ago - if the binary requires one of their runtime DLLs, offer the option to download & install it automatically for them, but they apparently don't find it that critical or rather shift the burden to the software packagers.
Comment #22 by brocolis — 2019-03-28T18:11:10Z
I think this is a doc issue. A possible 'fix' in https://dlang.org/dmd-windows.html: "In order to run programs built with -m64 the end users must first install <link to>MS DLLs</link> in their computers" The developers should then warn their users whenever they want.
Comment #23 by r.sagitario — 2019-03-28T22:15:49Z
>Then in the case where it can't find the DLL, we could put up an error > message or error window a message like: > "This binary requires the Microsoft Visual C++ 2010 Redistributable > package. Please install it to continue." This is possible with delayed loaded DLLs. An error could be issued at startup as in https://docs.microsoft.com/en-us/cpp/build/reference/loading-all-imports-for-a-delay-loaded-dll?view=vs-2017 The downside is that the necessary lib implementing this functionality (delayimp.lib) comes with VC only, so you can also just use the static libraries to begin with. > I think this is a doc issue. I agree, lets improve the documentation and move on.
Comment #24 by johnnymarler — 2019-03-29T05:34:38Z
>> The main point I've gotten from you is that you think it's ok for simple >> programs compiled with DMD to not work on other's computers by default. > Yep, totally my point, besides that being apparently no big deal (let alone critical issue rendering a compiler 'totally broken') for the comparatively huge Visual C++, Rust and MinGW user base. And with an absolutely trivial solution - just install Visual Studio and use the static libs (I think that's the default setting for DMD too, for LDC it definitely is), then your users won't need the redistributable. > And that seems to be the crux - some Windows guys seem totally opposed to the idea of having to install the 'official system toolchain' for professional development, while having to install Xcode on Mac (also required for linking in general, not just to have the ability of linking the C runtime statically) is somehow far less considered a PITA. Ah I see I've misunderstood. I wasn't aware that you could statically link using the MSVC tools. This is a much better state, at least there's a path to be able to build executables that will run on any reasonably recent windows system. In that case updating the dmd windows documentation about using the LLD linker is good enough for me. Still not ideal, but acceptable. >> This could be done by loading the msvcr100.dll dynamically inside druntime >That'd be too late; druntime's _d_run_main (IIRC) is called from C main (emitted by the compiler), which is called by the C runtime, as that's where the actual entry point is. Gotcha. So if we wanted to do that we would also need to also emit the entry point or link against a static library with an entry point implementation.
Comment #25 by dfj1esp02 — 2019-03-29T08:37:02Z
(In reply to brocolis from comment #22) > "In order to run programs built with -m64 the end users must first install > <link to>MS DLLs</link> in their computers" Normally the dll is just placed in the same folder with the executable, applications on windows are self contained this way.
Comment #26 by r.sagitario — 2019-03-29T09:52:11Z
Given that the MS-DLLs are redistributable, we could also just add them to the dmd installation. You can then copy them with your built executable to another computer without having to go through full installation of the VC distributables. Using the VC2010 DLLs has the advantage that later versions don't make it that easy because they require proper manifests.
Comment #27 by kinke — 2019-03-29T19:09:00Z
(In reply to Jonathan Marler from comment #24) > In that case updating the dmd windows documentation about > using the LLD linker is good enough for me. Wrt. docs, they should mention that it is specific to -m32mscoff/-m64 *and* the shipped-with MinGW libs, i.e., only if no Visual Studio is installed. LLD as linker is usable just fine with the MS libs (and in fact way faster than the MS linker - see the -link-internally speedup in https://github.com/ldc-developers/ldc/issues/2964#issuecomment-454533092). (In reply to Rainer Schuetze from comment #26) > Using the VC2010 DLLs has the advantage that later versions don't make it > that easy because they require proper manifests. But I guess the UCRT is more likely already installed nowadays. I don't know whether DMD requires vcruntime etc. on top like LDC. The question of default MSVC runtime version for DMD is also relevant for https://github.com/dlang/installer/pull/346.
Comment #28 by ibuclaw — 2022-12-27T17:09:14Z
*** Issue 21867 has been marked as a duplicate of this issue. ***
Comment #29 by ibuclaw — 2022-12-27T17:10:36Z
*** Issue 22525 has been marked as a duplicate of this issue. ***
Comment #30 by robert.schadek — 2024-12-13T19:02:38Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/19544 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB