Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Link against minimal/unversioned msvcrt.dll for Windows binaries #2355

Closed
mqudsi opened this issue Mar 1, 2018 · 11 comments
Closed

Link against minimal/unversioned msvcrt.dll for Windows binaries #2355

mqudsi opened this issue Mar 1, 2018 · 11 comments

Comments

@mqudsi
Copy link

mqudsi commented Mar 1, 2018

Given rust's very minimal VC runtime usage on Windows, this is a proposal to have rust's default Windows toolchain link against the unversioned msvcrt.dll that has shipped with all versions of Windows rather than the toolchain-specific Visual C++ runtime (msvcrtXX.dll). This will eliminate completely any dependence on a specific toolchain/dll on end-user systems and allow Win32 binaries generated via rust to be deployed more portably and with greater ease across all Windows platforms.

Some background:

msvcrt.dll is not intended for use by user applications as it does not have a stable API and Microsoft makes no guarantee as to the availability or the behavior of any particular methods it exposes, as such, Microsoft does not ship a msvcrt.lib for dynamically linking against msvcrt.dll - instead, it advises that developers either statically link their binaries against msvcrtXX.lib tied to a specific release of the Visual C runtime (updated with each Visual Studio release) or link against that same dll dynamically and distribute a copy of said DLL with the resulting binary (as was the norm in the early 2000s) or distribute a copy of the VC runtime installer and execute that as needed during the deployment phase.

Since rust only uses very minimal functionality from the runtime library (allocation, basic string functions, etc) I believe we should be able to limit ourselves to the surface area of the msvcrt api that has been around since at least Windows XP and hasn't changed (for example, many of Microsoft's own single-binary tools target this version of msvcrt to provide universal binary functionality without the hassle of dependency management or a complicated setup routine).

I have open sourced a script to generate a msvcrt.lib file from the publicly exposed APIs found in any msvcrt.dll, this can be used to generate a (freely redistributable, but no need to redistribute it) the msvcrt.lib library stub that can be used by the MSVC compiler to become aware of the APIs exposed by msvcrt.dll and to link against them dynamically (without needing to LoadLibrary etc at runtime): msvcrt.lib (readme forthcoming)


FWIW, at NeoSmart Technologies we've been linking against msvcrt.dll for many years now with a variety of applications for the most basic CRT requirements (basically, standard C functions) and we haven't had any issues or complaints. Binaries produced many years back on Windows XP still run without problem on the latest Windows 10 builds, and applications built today on Windows 10 run on Windows XP just fine.

@Diggsey
Copy link
Contributor

Diggsey commented Mar 14, 2018

If you want to do this you can use the -gnu target already. It doesn't make sense for the -msvc target to link to this DLL, as it's explicitly not part of the MSVC toolchain and not supported. Rust programs do not exist in isolation - they are often linked with C/C++ code, so either you'll end up with multiple C runtimes linked to your application, or the C/C++ code may be unexpectedly linked to this very old version of the runtime causing linker errors, or worse, instability.

Difficulties when deploying can be solved by either statically linking, or by using the universal CRT, a version-less CRT that is up-to-date, supported by the MSVC toolchain, and is a built-in windows component.

@mqudsi
Copy link
Author

mqudsi commented Mar 14, 2018

The universal crt is very nice, but unfortunately it is restricted to Windows 10 and up. Some older versions of Windows can run apps linking against the universal crt, but only after installing the redistributable, which defeats the purpose of using it.

@steffengy
Copy link

If you're using msvcrt.dll that's just as relying on undefined behavior in e.g. C,
it works until it doesn't.
I think Microsoft is pretty clear on communicating that this is a terrible idea:

The msvcrt.dll is now a "known DLL," meaning that it is a system component owned and built by Windows. It is intended for future use only by system-level components.

https://msdn.microsoft.com/en-us/library/abx4dbyh(v=vs.120).aspx

Although MSVCRT.DLL has been an operating system DLL for a long time, and has been documented as off-limits to applications, there are still a lot of people who treat it as a C runtime delivery channel, and those programs create a lot of grief for the product team.

https://blogs.msdn.microsoft.com/oldnewthing/20140411-00/?p=1273

@mqudsi
Copy link
Author

mqudsi commented Mar 14, 2018

You're not saying anything I didn't already say in my first post. I listed all these caveats upfront, I am neither unaware about them nor attempting to hide them.

I wouldn't advise using mscvcrt.dll directly for most anyone. But if you are careful and you know what you are doing (and presumably people working on a cross-platform compiler would qualify as such), a judgement call can be made. This is a tool in an arsenal, and hopefully it won't be used by anyone to whom the expression "if all you have is a hammer, everything looks like a nail" would apply.

It all depends on how much rust depends on the CRT for. You do yourself and others a disfavor if scaremongering people into thinking the signatures for memcpy or strcmp and co. will ever change. Microsoft's policy is that they're free to break compatibility. But they're not going to do change the essential building blocks, even if thousands of other APIs are added or modified. Look at strcpy. Despite its many faults, Microsoft did not dare touch it, and even in the versioned CRT, strcpy_s was introduced instead.

Many of these functions are either formal or de facto standards, either universally or in the Windows world.

Again, it all depends on how much rust relies on the CRT for. If rust is using it for simd operations and advanced intrinsics, then I would be against linking against the unversioned msvcrt.dll. But the guidelines that apply to your common developer are less a "must" and more of a "recommendation" when you are working on low-level applications or writing your own runtime library.

Using the GNU target, the versioned MSVCRT, or the Universal CRT are complete non-starters in this discussion. What would have been a helpful alternative suggestion would have been to compile the rust runtime against the userspace DDK, directly using the NT kernel APIs exposed to userland that msvcrt.dll is written against in the first place. Which is also an option I'd be in favor of and happy to permanently abandon this suggestion if interest in doing that were expressed.

@steffengy
Copy link

I just wanted to provide some references for a clarified position on msvcrt.dll.

Many of these functions are either formal or de facto standards, either universally or in the Windows world.

Some are pretty safe sure, but a single one that isn't, is enough that everything falls apart.
Software shouldn't rely on luck, versioning and guarantees are there for a reason, we aren't in the 70s anymore.

directly using the NT kernel APIs exposed to userland that msvcrt.dll is written against in the first place

Assuming you mean kernel32 and such (and not direct NT-syscalls), sure one could do that, but it's work not providing much added value for the common user and someone has to look into it and do it.
(from a compatibility point with other MSVC dll's and such it may cause more issues than it solves)

You can already link the CRT statically, if you really do not want to ship it after all, is there any usecase that this is not enough/suboptimal for?

@Centril
Copy link
Contributor

Centril commented Oct 9, 2018

cc @retep998 for expertise.

@retep998
Copy link
Member

retep998 commented Oct 9, 2018

I am opposed to trying to link to msvcrt.dll with the -msvc toolchain.

  • It would create massive incompatibility issues whenever you try to statically link to any C or C++ code.
  • Not relying on redistributables is already achievable through statically linking the CRT.
  • Rust would have to ship its own import library for linking to msvcrt.dll.
  • Microsoft themselves tells you not to do this.

There are no upsides to this change, and the downsides would make life hell for programmers not understanding why their program is getting linker errors or crashing at runtime due to CRT incompatibilities.

Also, Rust does not currently prevent you from choosing to use your custom msvcrt.lib so you already can do what you want to do without having to mess with the default experience for most Rust users on Windows.

@Centril
Copy link
Contributor

Centril commented Oct 9, 2018

Alright, given @retep998's review I'll elect to close this issue at this time; if you think more discussion is necessary, feel free to reraise the issue on http://internals.rust-lang.org/.

@Centril Centril closed this as completed Oct 9, 2018
@mingkuang-Chuyu
Copy link

mingkuang-Chuyu commented Jun 23, 2019

https://github.com/Chuyu-Team/VC-LTL/releases

VC-LTL is an open source CRT library based on the MS VCRT.
You can use rust + VC-LTL, shared to msvcrt.dll and optimize the application file size.

@comex
Copy link

comex commented Jun 25, 2019

That repo has quite a lot of files starting with

// Copyright (c) Microsoft Corporation. All rights reserved.

...

@xspeed1989
Copy link

VC-LTL is compatible with rust

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants