Skip to content

provide a way of overriding the MinGW library path #68887

Closed

Description

@tanriol

The recently landed #67429 introduced a heuristic to search for the system MinGW libraries relative to the cross-gcc (used as linker) itself. However, there are systems that do not follow this pattern. For example, on my Gentoo system:

  • /usr/bin/x86_64-w64-mingw32-gcc is a symlink to /usr/x86_64-pc-linux-gnu/x86_64-w64-mingw32/gcc-bin/9.2.0/x86_64-w64-mingw32-gcc
  • /usr/x86_64-w64-mingw32/usr/lib/ is the directory with the actual libraries in the /usr/x86_64-w64-mingw32 sysroot

It would be useful to have a way of overriding the heuristics and informing rustc about the correct library path manually. In the current configuration even RUSTFLAGS="-L /usr/x86_64-w64-mingw32/usr/lib/" does not help because the rustc-provided libraries have higher priority.

Activity

  1. added
    A-linkageArea: linking into static, shared libraries and binaries
    C-feature-requestCategory: A feature request, i.e: not implemented / a PR.
    O-windows-gnuToolchain: GNU, Operating system: Windows
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Feb 6, 2020
  2. mati865 commented on Feb 7, 2020

    @mati865
    Member

    cc @alexcrichton
    My comment in the PR:

    Maybe it'd be possible to reuse one of Cargo configuration fields or add new one to specify path of system libraries.

  3. alexcrichton commented on Feb 7, 2020

    @alexcrichton
    Member

    My hope is that this would be of far lesser urgency than #67429 because this only affects the startup object files which ideally change far less in the gcc toolchain than the rest of the toolchain. The main issue was that we'd prefer our own import libraries and such, which really was only effective if they came from the same toolchain as the host toolchain, which they rarely did.

  4. mati865 commented on Feb 7, 2020

    @mati865
    Member

    It'd be nice to have Rust's MinGW follow latest MinGW release but it's not backwards compatible: https://www.diffchecker.com/mjMudsm6
    Although it's worth mentioning the last breaking change to the CRT happened 2 years ago. This means using newer MinGW would already increase amount of systems where it just works.

    How does *-linux-gnu target work in regard of CRT? It doesn't ship startup objects unlike *-linux-musl and *-windows-gnu targets.

  5. alexcrichton commented on Feb 7, 2020

    @alexcrichton
    Member

    The toolchain used for MinGW has historically been "whatever is on the builders", so it's not strictly kept in sync with something or intentionally held back. It should be updateable at any time!

    The non-MinGW targets all rely on the linker to pull in the CRT. None of them work without a preinstalled toolchain, though, whereas one of the purposes of the MinGW toolchain is to work without a preinstalled toolchain.

  6. mati865 commented on Feb 8, 2020

    @mati865
    Member

    @alexcrichton there is another case of nonstandard path. 😔
    This time on Windows when MinGW is installed through Chocolatey #68872 (comment)

    I'll check if it is using symlink which we follow but I'm at a loss.
    Chocolatey install wrappers so there is really no way to get location of original executable.

  7. alexcrichton commented on Feb 10, 2020

    @alexcrichton
    Member

    Sorry I don't know of a great way to fix things, I know very little about MinGW myself.

  8. rivy commented on Feb 15, 2020

    @rivy

    @mati865 , On AppVeyor CI (which uses a choco install of mingw), while testing, I used the relative path "..\lib\mingw\tools\install\mingw64" from the wrapper to the main directory of the install. I believe that should be a relatively stable path. It should be at least testable.

  9. rivy commented on Feb 15, 2020

    @rivy

    @mati865 ,

    After a bit of googling and stackoverflow search, I found a second, more robust, though more complicated/slower, method of finding the installation main directory (ref: SE). Using the --shimgen-noop option to gcc returns a reference to the true installation path (see path to executable).

    C:>"c:\ProgramData\chocolatey\bin\gcc.exe" --shimgen-noop
    [shim]: Set up Shim to run with the following parameters:
      path to executable: c:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin\gcc.exe
      working directory: C:\ProgramData\chocolatey\bin
      is gui? False
      wait for exit? True
      command (optional):
    [shim]: Command line '"c:\ProgramData\chocolatey\bin\gcc.exe"  --shimgen-noop'
    [shim]: Current process '"c:\ProgramData\chocolatey\bin\gcc.exe"'
    [shim]: Command line after removing process '  --shimgen-noop'
    [shim]: Arguments after removing shimgen args - ''
    [shim]: Arguments are ''

    I hope that's helpful.

  10. mati865 commented on Feb 15, 2020

    @mati865
    Member

    @rivy Rust could get library path from gcc itself but calling executables on Windows is slow.
    I was about to add Chocolatey structure as one of the paths (and fix Cygwin as well) but there was a lot going on for me this week.

  11. rivy commented on Feb 17, 2020

    @rivy

    @mati865 , yep, I think using the "usual" relative path (ie, "..\lib\mingw\tools\install\mingw64") would be the better choice. I guess you could fall back to parsing the gcc --shimgen-noop output, but that's a lot of effort for a low percentage occurrence.

    I do want to say thanks for your efforts on this problem.

  12. tanriol commented on Feb 17, 2020

    @tanriol
    ContributorAuthor

    Still, how about a fallback to some config item or environment variable so that it can be made work on unsupported layouts too without rebuilding rustc?

  13. 25 remaining items

  14. saurik commented on Jul 2, 2020

    @saurik

    -Z link-self-contained=no worked so well--for both 64-bit and 32-bit--that I was even able to use clang as a wrapper for the linker instead of having to directly specify mingw's ld! \o/ I guess the question I have now is: if the user is specifying LINKER, shouldn't link-self-contained default to no? (I'm assuming the idea of having this self-contained environment in the first place is to avoid people having to bring their own install of MinGW, and so one is being shipped with rustc?) If you have an overridden LINKER, it seems like the probability that the libraries that come with rustc will be exactly compatible is "slim" (and so I'd expect "user brought their own linker, but wants to roll the die with the rustc embedded libraries" to be the corner case scenario that should require a flag override, not "user brought their own linker and thereby probably the linker works"; I didn't bring this up before because I had assumed there was some reason all these flags had to be passed manually, and thereby the paths needed to be known, but now seeing that "just call the linker" was an option from the beginning it seems like it should be the default in cases when the user provided the linker).

  15. mati865 commented on Jul 2, 2020

    @mati865
    Member

    @saurik the plan is to always disable self contained mode when cross compiling and on Windows when the linker location is outside of Rust sysroot.

    To do it properly we need to stabilise link-self-contained first but that requires MCP.
    There is open MCP already for what #72999 did and if it's not approved all the changes made so far will be probably reverted: rust-lang/compiler-team#310

  16. mati865 commented on Jul 16, 2020

    @mati865
    Member

    Status update:
    MCP was seconded and since the beta was cut I've opened #74410 to completely ignore shipped CRT objects when cross compiling.

  17. saurik commented on Jul 16, 2020

    @saurik

    @mati865 To verify, by "cross compiling" here we mean "when the user is using a toolchain that isn't the system default toolchain (and thereby has provided their own LINKER)", not "when the user happens to be compiling for a host/target architecture that is different from the build/host architecture" (to use x/y as gnu/cargo naming)? (Like, if I am on Win32 compiling for Win32, many people would not call that "cross compiling"--though I can see an argument that it is, and it is obvious to see that when one considers one things like "I am on Linux and am compiling a binary for Linux but I am on a system with glibc 2.23 and need the resulting binary to run on a system with glibc 2.17 and so I have a sysroot for an old version of CentOS that is my host/target system while a very recent build of Ubuntu is my build/host system": in some sense I am "cross compiling" from Ubuntu bionic to CentOS 7--but if I am specifying the linker and thereby have a sysroot I would need to not have these shipped objects injected no matter the architectures involved. I mostly ask this question as I ran into a really annoying bug in Cargo rust-lang/cargo#8147 wherein it incorrectly makes assumptions about toolchains based on architecture.)

  18. mati865 commented on Jul 16, 2020

    @mati865
    Member

    @saurik that's a good point. Until link-self-contained option is stabilised and heuristic for automatic external linker detection is added, it's expected when user provides own linker self-contained mode makes no sense. Do you want to open PR yourself?

  19. saurik commented on Jul 16, 2020

    @saurik

    @mati865 FWIW, "it's expected when user provides own linker self-contained mode makes no sense" is what I agree with / want, so if you are saying that will be the behavior I have no issue? My belief is just that "self contained mode" is the "narrow" (even if very common) case that only makes sense if the user is using the rust-provided linker (and that that has nothing to do with "cross compiling").

  20. mati865 commented on Jul 16, 2020

    @mati865
    Member

    My proposal for now:

    • -Z link-self-contained=yes/no takes precedence over anything else, it will become stable -C flag at some point
    • host != target: self-contained mode is disabled
    • user manually specified the linker: for now just disable self-contained mode, later this will change to "is external linker available in the PATH?"

    Would you like to implement and open PR for "user manually specified the linker: for now just disable self-contained mode" (since it's your idea) or want me to do it?

  21. saurik commented on Jul 17, 2020

    @saurik

    My proposal would be:

    • if LINKER is set, then use that linker and assume it isn't self-contained (as the user should not even know where that linker is located to specify it manually... and if they do, honestly, I bet they are doing something epic and want all the magic behavior to go away);

    • otherwise if target is a platform for which rust ships a self-contained toolchain (I know of Win32 and Linux+musl or whatever) then use self-contained toolchain;

    • otherwise (if the user didn't specify LINKER and is expecting rust to just guess at a linker, but rust also doesn't ship its own preferable linker) if the user has a useful-looking linker on their path then use that linker without self-contained and hope (really hard) that it works well enough to make a useful binary (and if the user wants this linker over the default preferable self-contained one they should specify it manually with LINKER, which would throw them into the earlier case);

    • otherwise, throw an error to the user telling them they need to provide a linker.

    I don't see why host != target is relevant at all... :(. But, I will note that as I have said in passing a couple times, I am making an assumption about what this self-contained mode is even for and who is using it: my assumption is that this is essentially a compete toolchain with sysroot/libraries that ships with rust so the compiler can do builds for a handful of platforms that are common targets for which the user is unlikely to have a toolchain installed on their current computer, such as for non-standard libc on Linux, Win32, or maybe emscripten or something. If so, I would expect this to be purely a "fallback" option that would always be available for these targets regardless of the host and the tooling for which might cause "unwelcome" command line arguments if the user manually specified LINKER to use a linker they brought, and which would cause mix-and-march issues--like we are seeing in these various ones I have run into--were you to attempt to use the rust libraries with a linker that came from someone else, no matter where that linker is located... like, my confusion on the use case here is so strong I honestly don't see why you would have this as a -C flag: either you are using the self-container linker or you aren't, and there doesn't seem like there should be any grey area where we have to ask the user.

    Is the issue that rust isn't shipping a linker, and is only shipping the libraries? If so, I feel like that just needs to be fixed, as otherwise that is going to just keep causing problems forever; like, there is simply no forward compatibility guarantee for libraries: even on macOS old linkers can't link against new libraries as the load commands at the head of the binary are extended with new features every year. A linker and a sysroot aren't exactly glued together, but there is at least a loose level of coupling between them and it isn't safe to just mix and match them: either don't ship libraries and expect the user to bring them or ship a full toolchain.

    My confusion with PATH might be that I don't know if you are saying this is for linkers found on the path by rust without LINKER or linkers found on the path that were manually specified with LINKER. In the former case I see the relevance, but then "later" is strange as both rules are relevant, as custom linkers are often--but not always--not on your path and adding them to the path to be found might not work a seat the name might be strange. In the latter case, I am just really confused as most of my time on this issue I was actually using the system copy of MinGW that I installed from homebrew/Ubuntu: I only switched to an off-PATH linker at the very end when I "could" (as I happen to prefer using an off-path copy of clang from the Android SDK as a wrapper for the on-PATH copy of mingw-ld... but I could just as easily be using the distribution's default install of clang and maybe even lld instead of mingw and now everything is both on path and strange); but even to the extent to which my toolchain is off-PATH today doesn't mean I might not be setting my PATH differently tomorrow (and sometimes I do this) so that weird folder is on my path.

    Taking a further step back, once I saw how the command line being passed to my linker was complete "vanilla" and it worked, I don't even understand what this option does: why not pass the vanilla options to your own self-contained linker? If the paths are internally wrong on that linker and it can't find it's sysroot, why not fix that in the self-contained linker? I would expect the self-contained linker to work just like my linker does, and my linker "just works". Why does the rust self contained linker fail to "just work" in a way that requires the crt objects to be manually passed in?

    (As for a PR, I am not in a position to test this without some maybe-hopefully-minimal instruction. I would be willing to accept said instruction, and maybe that will mean you get more patches out of me in the future ;P, but I just don't know what all I need to recompile to make this kind of change or then how to use that alternative copy: I have been "using" the rust toolchain, but I have so far not developed on it myself. Note that I continue to be willing to provide some compensation for you doing changes--assuming you agree with them, of course--in addition to paying for your time on this already that I might have caused, as me doing my job to pay you to do these tasks probably is arguably efficient for the world than me doing this directly; but again: if there is some minimal-investment-to-you way to tell me what I need to rebuild to make a change and test it, given that I seem to be resourceful enough to understand how to use the tooling itself and have been a maintainer of compilers in the past, I am definitely willing to do that and maybe seeing what I am suggesting manifested concretely will make more sense, or the process of me editing the code will help me understand the use case and thereby come up with a more reasonable suggestion for what to change.)

  22. mati865 commented on Jul 17, 2020

    @mati865
    Member

    I'll get to that wall of text later 😉.
    For now I'll address only

    I don't see why host != target is relevant at all...

    For MinGW the linker is shipped only when it's the host compiler and is preferred over external linkers in the PATH. So we assume that if user overridden the linker they don't want self contained mode.
    However when cross compiling users don't need to specify the linker because it will be taken from the PATH. Hence self contained mode is disabled entirely.

  23. mati865 commented on Jul 30, 2020

    @mati865
    Member

    @saurik Apologies, I was quite busy recently.

    The change itself is trivial and comes to adding condition that check if linker option is none, similarly to:
    #74410

    There is a (big) catch however, testing this change is complicated. You have to modify https://github.com/mati865/rust/blob/08990e5c7554d4d6a0440debc2edc99c8e9565c8/src/librustc_codegen_ssa/back/link.rs#L1017 to always return None, then copy and paste few lines in CI config to create dist archive for windows-gnu.
    Finally you need to run it on Windows machine with MinGW compiler added to the PATH and test that:

    • if -C linker=gcc was not specified rustc picks CRT objects from the sysroot
    • if -C linker=gcc was specified rustc picks CRT objects from the MinGW in the system
  24. added a commit that references this issue on Aug 10, 2020
  25. added a commit that references this issue on Sep 3, 2020
  26. mati865 commented on Sep 3, 2020

    @mati865
    Member

    -C link-self-contained has been stabilised in nightly and MinGW detection was reworked in the next nightly.

    If somebody still encounters the issue with tomorrow's nightly, please open new report.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-linkageArea: linking into static, shared libraries and binariesC-feature-requestCategory: A feature request, i.e: not implemented / a PR.O-windows-gnuToolchain: GNU, Operating system: WindowsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions