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

Gracefully handle super-long linker command lines #41190

Closed
alexcrichton opened this issue Apr 10, 2017 · 11 comments
Closed

Gracefully handle super-long linker command lines #41190

alexcrichton opened this issue Apr 10, 2017 · 11 comments
Labels
A-linkage Area: linking into static, shared libraries and binaries C-enhancement Category: An issue proposing an enhancement or a PR with one. E-help-wanted Call for participation: Help is requested to fix this issue.

Comments

@alexcrichton
Copy link
Member

The compiler should gracefully handle invocations of the linker which would otherwise blow the system limits. I've heard reports of this happening on both Unix and Windows, so this is a cross-platform concern.

My preference of how to implement this would be:

  • Linkers typically support this method via passing arguments as @file where file is a path on the filesystem that contains a bunch of options.
  • Short linker invocations should not use @file syntax for debuggability
  • The compiler automatically switches to @file when the command line gets too big.
  • rustc has some arbitrary limit for bytes it'll pass as arguments to Command, likely well below the platform specific limits

I don't know the precise syntax of these files, unfortunately, but I'm sure google does somewhere!

@jsgf
Copy link
Contributor

jsgf commented Apr 10, 2017

The trouble is that if rustc is generating linker lines that are too long for exec (or the Windows equiv), then the chances are it's also getting a command line that is similarly long. Therefore rustc also needs to accept @args as well as generate it.

Are there cases where rustc will generate a linker line that's not proportional to its own command line (setting aside issues around -C link-arg[s])?

@jsgf
Copy link
Contributor

jsgf commented Apr 10, 2017

BTW, the @ argfile syntax is pretty simple: it's basically whitespace separated with normal "" \-esc quoting rules. Commonly, args are separated by \n for readability. args files can recursively include other args files. https://sourceware.org/binutils/docs/ld/Options.html#Options

I believe MacOS's linker adds complications in that it can only be flags, not input files - but it supports a second file containing input filenames (which makes intermingling flags and files awkward), with a slightly different format (one filename per line, no quoting rules).

@alexcrichton
Copy link
Member Author

Yes I think that @-syntax for rustc itself may be best in a separate bug for now to bikeshed syntax, etc. The linker is invoked with a command line of size O(size of dependency graph) where the compiler is O(number immediate dependencies), so I think this is far more likely to be a problem internally than invoking the compiler (to start out with at lesat)

@nagisa
Copy link
Member

nagisa commented Apr 10, 2017

Some notes:

  1. @file should not be removed for failed linker invocations.
  2. rustc should attempt to put @file into some ramfs if there’s anything like that.

@jsgf
Copy link
Contributor

jsgf commented Apr 10, 2017

@alexcrichton:

The linker is invoked with a command line of size O(size of dependency graph) where the compiler is O(number immediate dependencies),

Well, the rustc line needs to have a -Ldependency= option for each node in the dependency graph, but if they tend to be in the same directory then they can be collapsed together, so it becomes O(number-of-dirs-in-dep-graph) - which works for cargo, but not for buck because every dep tends to be in its own directory.

@nagisa:

@file should not be removed for failed linker invocations.

I'm not sure what this means. Do you mean that the arg @file is used literally if file doesn't exist?

@nagisa
Copy link
Member

nagisa commented Apr 10, 2017

no I mean it should not remove the file, so you could look at the args when linking fails.

@alexcrichton
Copy link
Member Author

@jsgf ah yes, that is a good point.

@retep998
Copy link
Member

retep998 commented Apr 11, 2017

For Windows the limit for a command line is a hard 32,768 wchars. Fortunately for Windows, the way that we flatten the command line for CreateProcess for Command is identical to the format of link's command files, so we can just reuse that code and it'll work.

rustc should attempt to put @file into some ramfs if there’s anything like that.

@nagisa Just open the file on Windows with FILE_ATTRIBUTE_TEMPORARY and Windows will delay writing it to disk so long as memory is available.

@retep998
Copy link
Member

Related issues: #40384 #39644

@cengiz-io
Copy link
Contributor

cengiz-io commented May 30, 2017

I know we're currently looking into this but this is causing so much pain for me right now. I'll try moving my rust source folder to a shorter path.

I hope it gets fixed very soon.

😭

Can we perhaps assign some labels and look for potential takers?

@alexcrichton alexcrichton added A-linkage Area: linking into static, shared libraries and binaries E-help-wanted Call for participation: Help is requested to fix this issue. labels May 30, 2017
@retep998
Copy link
Member

retep998 commented Jun 7, 2017

For whoever is implementing this for msvc, could you also implement deduplication of library input at the same time? cc #38460

@Mark-Simulacrum Mark-Simulacrum added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Jul 27, 2017
alexcrichton added a commit to alexcrichton/rust that referenced this issue Aug 28, 2017
This commit adds logic to the compiler to attempt to handle super long linker
invocations by falling back to the `@`-file syntax if the invoked command is too
large. Each OS has a limit on how many arguments and how large the arguments can
be when spawning a new process, and linkers tend to be one of those programs
that can hit the limit!

The logic implemented here is to unconditionally attempt to spawn a linker and
then if it fails to spawn with an error from the OS that indicates the command
line is too big we attempt a fallback. The fallback is roughly the same for all
linkers where an argument pointing to a file, prepended with `@`, is passed.
This file then contains all the various arguments that we want to pass to the
linker.

Closes rust-lang#41190
alexcrichton added a commit to alexcrichton/rust that referenced this issue Sep 6, 2017
This commit adds logic to the compiler to attempt to handle super long linker
invocations by falling back to the `@`-file syntax if the invoked command is too
large. Each OS has a limit on how many arguments and how large the arguments can
be when spawning a new process, and linkers tend to be one of those programs
that can hit the limit!

The logic implemented here is to unconditionally attempt to spawn a linker and
then if it fails to spawn with an error from the OS that indicates the command
line is too big we attempt a fallback. The fallback is roughly the same for all
linkers where an argument pointing to a file, prepended with `@`, is passed.
This file then contains all the various arguments that we want to pass to the
linker.

Closes rust-lang#41190
bors added a commit that referenced this issue Sep 7, 2017
rustc: Attempt to handle super long linker invocations

This commit adds logic to the compiler to attempt to handle super long linker
invocations by falling back to the `@`-file syntax if the invoked command is too
large. Each OS has a limit on how many arguments and how large the arguments can
be when spawning a new process, and linkers tend to be one of those programs
that can hit the limit!

The logic implemented here is to unconditionally attempt to spawn a linker and
then if it fails to spawn with an error from the OS that indicates the command
line is too big we attempt a fallback. The fallback is roughly the same for all
linkers where an argument pointing to a file, prepended with `@`, is passed.
This file then contains all the various arguments that we want to pass to the
linker.

Closes #41190
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-linkage Area: linking into static, shared libraries and binaries C-enhancement Category: An issue proposing an enhancement or a PR with one. E-help-wanted Call for participation: Help is requested to fix this issue.
Projects
None yet
Development

No branches or pull requests

6 participants