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

use debug version of C runtime with MSVC #717

Closed
wants to merge 1 commit into from

Conversation

Be-ing
Copy link
Contributor

@Be-ing Be-ing commented Aug 24, 2022

https://docs.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library

I encountered a link error when linking a Rust library with some C++ built by cc with other C++ code built by CMake because cc wasn't using the debug version of the C runtime.

@dot-asm
Copy link
Contributor

dot-asm commented Aug 27, 2022

On a tangential note, there is a case to be made that when it comes to a library, /MT /Zl flags would be most appropriate. Why is that? Well, what's the difference between /MT and /MD when it comes to the .obj file? Let's say you make a call to a CRT subroutine, for example malloc. If compiled with /MD, the resulting .obj file will have a reference to __imp_malloc, and if compiled with /MT to malloc. Another difference would be a link directive that reflects the chosen option, but you can omit it with /Zl. Now the fun fact. You can link maloc with either CRT, be it static or dynamic, but you can link __imp_malloc only with dynamic. Hence an object file, or collection thereof, compiled with /MT /Zl effectively allows you to leave the decision about which specific CRT library, be it static, dynamic, debug or not, the final application executable object will be linked with to somebody else. To summarize, consider cc.static_crt(true).flag("/Zl");.

Since cc-rs produces specifically libraries for Rust to link with, one can even argue that cc-rs should use /MT /Zl unconditionally. Though I'm not sure how it would play out if you use ATL or MFC... Well, /Zl omits CRT-related link directives, but not others, so it should work...

@Be-ing
Copy link
Contributor Author

Be-ing commented Aug 27, 2022

leave the decision about which specific CRT library, be it static, dynamic, debug or not, the final application executable object will be linked with to somebody else

That would be nice if that works. If you want to experiment with that, go for it. In the meantime this simple change solves my problem.

@dot-asm
Copy link
Contributor

dot-asm commented Aug 27, 2022

It does work for me. And if it doesn't for you, I'd like to hear about it. Would you care to provide more details about the failure? At least who does the final linking, Rust or cl?

@Be-ing
Copy link
Contributor Author

Be-ing commented Aug 27, 2022

I'm not clear what you're asking. I have not tested using /MT /Zl as you proposed. The problem that led to me making this PR is that I ran a debug build with CMake in a project using Corrosion to invoke Cargo to build a Rust staticlib and link it with a C++ executable. That failed to link on Windows.

@dot-asm
Copy link
Contributor

dot-asm commented Aug 27, 2022

I have not tested using /MT /Zl as you proposed.

Then why did you write "That would be nice if that works"? I mean it sounded like it didn't work for you. So I had to ask. It's ok if you don't want to entertain the idea, but then don't make it sound like it didn't work :-)

@Be-ing
Copy link
Contributor Author

Be-ing commented Sep 15, 2022

Ping. I stumbled over this bug again trying to setup a Windows development environment.

@thomcc thomcc added the O-windows Windows targets and toolchains label Oct 26, 2022
@ChrisDenton
Copy link
Member

Hm, while this is certainly the easiest way to fix your specific issue, I'm not sure that this is a good general solution.

This PR may be incorrect for many other use cases. Currently rustc (via libc) hard codes non-debug CRT for all Rust compiled code so it may cause conflicts depending on how it's used.

While I absolutely want to see a solution to the problems with linking the right CRT, I think there is perhaps some design work that needs to be done first.

@Be-ing
Copy link
Contributor Author

Be-ing commented Nov 28, 2022

Since #723 has been closed can this straightforward bug fix be merged?

@dot-asm
Copy link
Contributor

dot-asm commented Nov 28, 2022

Just in case for reference. So that there is understanding of the scope. Since rustc effectively overrides references to C RT left by /M* flag, in cases when C++ is involved, the suggested modification will [currently] result in linking the debug version of C++ RT and non-debug version of C RT. More specifically, when rustc is linking the final executable. Question is if it's a sustainable configuration. One needs to weigh the impact on an average user to figure out if it would qualify as a non-breaking change. In the context one can recognize that a staticlib crate-type provider can solve the problem in the crate's build.rs, by [conditionally] invoking .define( _DEBUG, None) method. In other words, it's not like it's impossible to solve the problem(*) as it stands now. (One can even wonder if crate's build.rs would be a better spot...)

(*) The C++ problem more specifically. As for C-only, I [for one] would still recommend the -MT -Zl approach ;-)

@ChrisDenton
Copy link
Member

straightforward bug fix

I don't think this is a "straight forward bug fix". To be honest, I'm even more nervous about this now than I used to be. Changing the implicit behaviour of cc-rs has been causing issues with various build systems in recent releases.

I do think there should be a way to use debug CRT versions, etc. But this should not be tied to an existing option. Solving one use case does not necessarily justify breaking others. If we can have a solution that doesn't break others then we should do that instead.

@Be-ing
Copy link
Contributor Author

Be-ing commented Jan 29, 2023

Holding up this months old tiny bugfix over vague, unverified concerns is quite frustrating. If you have a better idea, please suggest it or implement it yourself.

@ChrisDenton
Copy link
Member

ChrisDenton commented Jan 29, 2023

The issue is not vague, it's specific. rustc hardcodes non-debug CRT libraries. cc-rs is primarily used to compile static libraries for use in applications compiled by rustc. There are various potential fixes to this.

  • rustc could be changed so that it does not hard code its CRT library (or rustc provides an option to override it).
  • cc-rs could provide a way to force overriding of the CRT library used (rather than doing so implicitly).

@dot-asm
Copy link
Contributor

dot-asm commented Jan 29, 2023

  • cc-rs could provide a way to force overriding of the CRT library used (rather than doing so implicitly).

It's actually possible to override rustc's choice with println!("cargo:rustc-link-lib=msvcrtd");. Well, it's not like it makes rustc give up the attempt to link with non-debug version, it's simply so that rustc-link-lib-s are passed first on the command line to the vendor linker, and that's how they take precedence. Just in case, I would not advocate for having cc-rs play this game [i.e. yes, not doing it implicitly].

@OlivierLDff
Copy link

Hi I'm experimenting rust integration with c++ on windows with msvc, and I find it annoying that the out of the box experience doesn't work to build code in Debug that is built by CMake when some code is also build by cc using the wrong crt library.

From my limited knownledge this PR would be the best to fix the issue implictly for everyone. It only affect the code in Debug mode, so it shouldn't break any behavior in production code.

Another idea would be to add a feature crt-debug to control if -MTd or -MDd is used.

@ChrisDenton
Copy link
Member

This may break production builds that use the debug setting. But even if it only broke some dev builds, that wouldn't be acceptable either.

I'm closing this now as I don't think this approach can be made to work. Other approaches may have a greater chance of success if they're fully opt-in rather than potentially silently enabled. Though long term the proper fix would be to allow rustc to fully support the debug libraries in some way. Then everything can be made to "just work" by default in whatever configuration.

@Be-ing
Copy link
Contributor Author

Be-ing commented Mar 30, 2023

An opt-in solution would not really be a solution because that still leaves debug builds broken unless downstreams are aware of the problem and opt in to the fix.

the proper fix would be to allow rustc to fully support the debug libraries in some way

Could you elaborate?

@ChrisDenton
Copy link
Member

See rust-lang/rust#39016. I have just written a comment outlining a possible way forward and asking rustc compiler if this would be the approach they want.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
O-windows Windows targets and toolchains
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants