-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Choosing which CRT to link to #1684
Conversation
Environment variable sounds like a very hacky solution to a very specific problem. We instead should be solving this problem in general (overriding the libraries which are linked to and the way they’re linked) and less hacky way (line or two in a Cargo.toml or something). I find (thinking about it, if libc linked to |
@nagisa Well...
I don't mind if we use some sort of parameter to cargo somehow instead of an environment variable. I just care that as a result of whatever option it is, build scripts are informed how to build C/C++ code, and rustc will automatically strip out references to the wrong CRT (because we have to for backwards compatibility). |
Yes, it sounds to me like what we should be investigating is a
Same problem exists on linux too.
and
I don’t see how backward compatibility comes into play here. It seems to me that whatever scheme we pick here, we would only ever be forward-incompatible at worst. No rustc/cargo upgrade could break a pinned version of liblibc which does not support linking library statically.
That’s probably the least convincing reason to use environment variables to me. We co-develop cargo along with rustc and libcore/libstd/liblibc and its fully within our power to make cargo support whatever scheme we decide on. |
Well on Windows you don't have both static and dynamic versions of a library with the same name with the only way to differentiate between them being the
@nagisa If we try to link
Then please pick a scheme which supports the following and I'll gladly support it:
|
My two cents, for what it's worth: I am a Windows developer. I do not know how to distribute the CRT without first looking up the procedure because I'm not saying that this is beautiful. In fact I think it's quite ugly. But it makes it possible. With it, I can give exes out to fellow devs without having to play the "Are you missing the runtime?" game. With this, I can build portable apps and conveniently link my large MSVC-only audio library into them. I have a large C++ package with Python bindings, and the static runtime is how I have wheels that just work; put another way, this is part of the "using Rust from other languages" story in my book. If this can be hacked around, I'd love to know how. If it can't, I think that this RFC should be pushed through as quickly as possible, then followed up with one that makes it pretty and possibly more general. The only change I would propose is possibly making the setting a command line argument to Under the right circumstances, I would go to Nightly to get this feature. |
Anyway, right now there's two ways of configuring this that I see which satisfy my requirements stated in my previous message.
If anyone can think of a better way, please say so. If you think one of these options is better, please say so. |
Regarding the specific variable to use, it probably makes sense to use the same resolution methodology in place in gcc-rs for
So, just do the above for |
I would much prefer option 2. I strongly dislike "persistent" environment variables and think they are a terrible way to configure a program: the communication between cargo and a build script is one of the few acceptable uses of environment variables in my mind:
Any time one of those is violated it causes endless problems. Option 2 falls foul only of 1) and to solve that, I don't see why we need dynamically named environment variables if it's only used for communication between cargo and the build script - can't we just have a single |
Perhaps a As someone who uses CMake, I can confirm that the default behavior is On a reread, my previous comment comes across as heavy-handed and possibly a bit hostile. I apologize for that. |
The fact that our MSVC target dynamically links the CRT is basically just a historical accident at this point, and I do personally wish that we linked statically by default specifically in the case of MSVC. This question has also come up before for other targets as well. For example the This also plays into the question of intrusive target configuration in Cargo for the standard library as well for various other codegen options, etc. The compiler and/or Cargo will also need the ability to inform gcc-rs and relevant crates about these options chosen so it can take advantage of it as well, so it's likely that a solution to that problem can be piggy-backed to a solution to this problem. I'm personally pretty wary of codegen options getting selected by environment variables, and I'm also pretty wary of the static/dynamic split on MSVC. If code compiled for a static msvcrt can't be linked against code compiled for a dynamic msvcrt, then how can we compile what we're shipping as part of the If this is the case then I think we'll really need what amounts to an entirely new target and set of artifacts for this. I'd prefer to avoid actually adding a new target, but the question about other forms of codegen configuration may also play into this as well. |
@alexcrichton The choice between If we really want to get technical about it, every single version of the CRT technically is ABI incompatible, because each version is allowed to add remove and change functionality between versions. Just look at Also, if you do want to have separate targets for dynamic vs static CRT, what about debug vs release CRT? Surely someone out there will have a reason for using the debug CRT, so should we add targets for that as well? Does Rust feel like maintaining 8 msvc targets, testing them on buildbot, and distributing artifacts for all of them? |
Oh, something I mentioned on IRC, but ended up not mentioning here (also something borderline unrelated to RFC). Our dependencies on native libraries are very deep in the dependency chain. Executables depend on I feel like that is a big mistake we’re making which also makes solving a bunch of problems hard (swapping out crt, swapping out an allocator, swapping out a panic runtime, etc). We (me and the RFC author) figured out, though, that doing anything about the described issue wouldn’t exactly help much in solving problems described by this RFC¹, but maybe somebody will have any ideas. ¹: Giving build.rs scripts knowledge about CRT being linked to is still hard. |
Could this be handled with a special link attribute to specify linking to the CRT for your current platform? This can then be put in a crate, probably Is the |
@camlorn |
@camlorn Although if we really wanted to be safe, we'd have to ensure that you're not allowed to link in C/C++ code compiled for the wrong CRT version. The only way to check this however is via the
|
@retep998 Currently, my vote is for scanning the linker output and leaving I wish Microsoft had been smarter about this. Too late now, though. |
Given the difficulties with making the flavor of MSVC CRT configurable (and ugliness of using environment variables to control it), I would propose the following:
I think this will address ~99% of motivation of this RFC. The one case this doesn't solve is Windows XP, so devs who need to target it will have to tweak |
@vadimcn I'm not sure how well supported it is to dynamically link the UCRT while statically linking the VC runtime. If we link |
@retep998: Based on what I know, I see no reason why dynamic UCRT + static vcruntime shouldn't work. But I've been wrong before :), so this needs to be tried out. |
@vadimcn This is what happens.
So your idea is kinda broken. |
If I go from the other route and do what I suggested and pass
I think it should be fairly obvious by now that getting |
Oh, and on a somewhat related note, statically linking the CRT is at odds with Rust dylibs. When statically linking the CRT, each binary ( |
In MSC++, code compiled with Also, the static target probably shouldn't support dynamic libraries at all, because on Windows, linking DLLs against static runtime is fraught with peril. The problem is that Windows can't merge symbols during dynamic linking (ELF-based systems can and do), so each DLL linked with use it's own copy of libc, including its own copy of memory allocator. That can be lived with if it is ensured that any resources are always released from the same library they were acquired, but I am not sure if Rust can ensure it will always be the case. Prohibiting dynamic linking in that target is easier and the static mode does not have that much benefit when other This makes the static target for Windows rather similar to the It also means that adding the target is not blocked by rust-lang/rust#27438 because that target simply never needs to emit The |
No, even when linking to the static CRT you still have to deal with other dependencies that can be dynamically linked (such as all the system libraries, kernel32 user32 advapi32 and so on), and so you still need to be able to apply The only legitimate use I see for |
@retep998 Are you still compiling with What you're doing is the reverse (compile as |
@Diggsey I didn't change how any of the code was being compiled, I just passed those linker flags. Right now the entire ecosystem builds code using |
Ok, it will be slightly more complicated than never generating it, but still simpler than full fix of that bug, because the
There are legitimate uses for other kinds of plugins. But the argument is that when you have dylibs, you don't have a single self-contained binary any more anyway, so the main advantage of the static target is gone.
I think initially even those could be disabled. Most DLL plugins need to be compiled against dynamic runtime of the same version as the application that loads them anyway. The main exception that comes to mind is COM modules where the interface does ensure resources are local to each component, but I don't think that can be distributed without installer, so the benefit is not so big there either. |
@jan-hudec It is perfectly acceptable for a DLL to use the static CRT as long as it doesn't share any CRT objects across the DLL boundary. So a
But
We don't have any sort of annotation to say whether to apply
We don't access any system stuff through libc anyway, we only rely on the CRT for math functions and a few memory functions like
I have absolutely no idea what you mean by this. I fail to see how COM is relevant to using the CRT, nor how installers are required for COM. |
There are legitimate uses for |
I think this is starting to highlight a deficiency in Cargo: there is no convenient way to arrange for the distribution of all needed dlls. I can't put them anywhere special, @jan-hudec Basically, the problem is that such a design mandates using MSVC because you need the runtime to manipulate things the app sends you, so forget anything that doesn't use it. I also use static linking of the runtime into DLLs and careful interface design to let my VC++2015 project be safely called by ctypes from Python 2.7 without requiring users to install additional runtimes. In that case, being static or not actually doesn't matter because there's still a version mismatch, so you have to apply the same considerations anyway. My plan was to apply the same approach to my first Rust project. Disabling cdylib would make me very sad, while also locking my current Rust project to MinGW. |
@retep998: FWIW, here's a change to link vcruntime statically. Don't know if this is the most elegant way, but at least stuff works. |
@vadimcn That basically breaks support for older versions of MSVC before the transition to ucrt and vcruntime. You'd need to do it based on the version of MSVC. Also that doesn't fix anything for other compiled C/C++ stuff, only how stuff inside Rust is built with cmake, and even then only when using the old configure system. |
Yep, that's the deal.
gcc crate could to the same.
What's preventing us from porting this to rustbuild? But I agree, this is a pretty fragile approach for not that much benefit over just compiling everything for static linkage and letting the linker fix things up. |
@brson and I have opened an alternative RFC to this which emphasizes environment variables less and focuses on cross-platform support to handle musl as well. |
Team member alexcrichton has proposed to close this. The next step is review by the rest of the tagged teams: No concerns currently listed. See this document for info about what commands tagged team members can give me. |
@rfcbot reviewed |
1 similar comment
@rfcbot reviewed |
All relevant subteam members have reviewed. No concerns remain. |
🔔 This RFC is now entering its week-long final comment period for closing 🔔 |
It has been one week since all blocks to the FCP were resolved. |
rendered
cc @alexcrichton @vadimcn @Diggsey
Related rust-lang/libc#290