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

Keep last redundant linker flag, not first #57018

Merged
merged 7 commits into from
Mar 20, 2019

Conversation

dcreager
Copy link
Contributor

When a library (L1) is passed to the linker multiple times, this is sometimes purposeful: there might be several other libraries in the linker command (L2 and L3) that all depend on L1. You'd end up with a (simplified) linker command that looks like:

-l2 -l1 -l3 -l1

With the previous behavior, when rustc encountered a redundant library, it would keep the first instance, and remove the later ones, resulting in:

-l2 -l1 -l3

This can cause a linker error, because on some platforms (e.g. Linux), the linker will only include symbols from L1 that are needed at the point it's referenced in the command line. So if L3 depends on additional symbols from L1, which aren't needed by L2, the linker won't know to include them, and you'll end up with "undefined symbols" errors.

A better behavior is to keep the last instance of the library:

-l2 -l3 -l1

This ensures that all "downstream" libraries have been included in the linker command before the "upstream" library is referenced.

Fixes #47989

When a library (L1) is passed to the linker multiple times, this is
sometimes purposeful: there might be several other libraries in the
linker command (L2 and L3) that all depend on L1.  You'd end up with a
(simplified) linker command that looks like:

    -l2 -l1 -l3 -l1

With the previous behavior, when rustc encountered a redundant library,
it would keep the first instance, and remove the later ones, resulting
in:

    -l2 -l1 -l3

This can cause a linker error, because on some platforms (e.g. Linux),
the linker will only include symbols from L1 that are needed *at the
point it's referenced in the command line*.  So if L3 depends on
additional symbols from L1, which aren't needed by L2, the linker won't
know to include them, and you'll end up with "undefined symbols" errors.

A better behavior is to keep the *last* instance of the library:

    -l2 -l3 -l1

This ensures that all "downstream" libraries have been included in the
linker command before the "upstream" library is referenced.

Fixes rust-lang#47989
@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @matthewjasper (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Dec 20, 2018
@Dylan-DPC-zz
Copy link

ping from triage @matthewjasper wating for you to review this

@matthewjasper
Copy link
Contributor

r? @alexcrichton

@alexcrichton
Copy link
Member

Thanks for the PR @dcreager!

I'm a little worried about this though in that libraries can change name/link kind via CLI flags, so it seems like the 'kind' of a library could change as we process it silently after this change? I think it sounds right to me to move everything to the end of the command line, but I think we may wish to keep the original warning if the kind is being updated perhaps?

@Dylan-DPC-zz Dylan-DPC-zz added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 24, 2019
@dcreager
Copy link
Contributor Author

Thanks for the feedback Alex! If I'm reading the old code right, we didn't print out the warning before if the kind changed; it was only printed if the second library reference was truly redundant.

@alexcrichton
Copy link
Member

Hm I think perhaps? This is so far out of cache I barely remember what any of this code does. Can you gist a few examples of before/after behavior to help dig into what's changing warning-wise here?

@dcreager
Copy link
Contributor Author

Sure thing! The original problem that this is trying to fix is some linker errors when you have a particular pattern of dependencies in some C/C++ code. I had put together minimal repro in this repo.

On Mac, the linker errors never occur. On Linux, the linker error occurs before this patch, but not after. For both platforms, a "redundant linker flag" warning was printed out before, but not after.

Before (Mac)
$ cargo build
   Compiling cc v1.0.26
   Compiling cc-02-broken v0.1.0 (/Users/dcreager/git/rust-cc-linking/cc-02-broken)
   Compiling cc-01-works-by-accident v0.1.0 (/Users/dcreager/git/rust-cc-linking/cc-01-works-by-accident)                                                                     
warning: redundant linker flag specified for library `c++`

warning: redundant linker flag specified for library `c++`

    Finished dev [unoptimized + debuginfo] target(s) in 3.13s
Before (Linux)
$ cargo build
    Updating crates.io index
  Downloaded cc v1.0.28
   Compiling cc v1.0.28
   Compiling cc-02-broken v0.1.0 (/home/dcreager/git/rust-cc-linking/cc-02-broken)
   Compiling cc-01-works-by-accident v0.1.0 (/home/dcreager/git/rust-cc-linking/cc-01-works-by-accident)
warning: redundant linker flag specified for library `stdc++`

warning: redundant linker flag specified for library `stdc++`

error: linking with `cc` failed: exit code: 1
  |
  = note: "cc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-m64" "-L" "/home/dcreager/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "/home/dcreager/git/rust-cc-linking/target/debug/deps/cc_02_broken-3cc2faff0ce9900d.1kohxk4oy5bpc1tz.rcgu.o" "/home/dcreager/git/rust-cc-linking/target/debug/deps/cc_02_broken-3cc2faff0ce9900d.1kp16pt7op8wd113.rcgu.o" "/home/dcreager/git/rust-cc-linking/target/debug/deps/cc_02_broken-3cc2faff0ce9900d.3l6cjvlvoh2c3so3.rcgu.o" "/home/dcreager/git/rust-cc-linking/target/debug/deps/cc_02_broken-3cc2faff0ce9900d.3nhkg8zoprl8ydjh.rcgu.o" "/home/dcreager/git/rust-cc-linking/target/debug/deps/cc_02_broken-3cc2faff0ce9900d.3sj4jtttlglzuhf6.rcgu.o" "/home/dcreager/git/rust-cc-linking/target/debug/deps/cc_02_broken-3cc2faff0ce9900d.4po5c5g0wu2dwvt4.rcgu.o" "/home/dcreager/git/rust-cc-linking/target/debug/deps/cc_02_broken-3cc2faff0ce9900d.50dua0cq8wfcaoc6.rcgu.o" "-o" "/home/dcreager/git/rust-cc-linking/target/debug/deps/cc_02_broken-3cc2faff0ce9900d" "/home/dcreager/git/rust-cc-linking/target/debug/deps/cc_02_broken-3cc2faff0ce9900d.h8uijmbpxrzuyns.rcgu.o" "-Wl,--gc-sections" "-pie" "-Wl,-zrelro" "-Wl,-znow" "-nodefaultlibs" "-L" "/home/dcreager/git/rust-cc-linking/target/debug/deps" "-L" "/home/dcreager/git/rust-cc-linking/target/debug/build/cc-02-broken-b6be909df134df9e/out" "-L" "/home/dcreager/git/rust-cc-linking/target/debug/build/cc-02-broken-b6be909df134df9e/out" "-L" "/home/dcreager/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "-Wl,--whole-archive" "-lsmall" "-Wl,--no-whole-archive" "-Wl,-Bdynamic" "-lstdc++" "-Wl,-Bstatic" "-Wl,--whole-archive" "-lbig" "-Wl,--no-whole-archive" "-Wl,--start-group" "/home/dcreager/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-296aebc3a1e4ecfc.rlib" "/home/dcreager/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-8cfe07ca425de5e2.rlib" "/home/dcreager/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libbacktrace_sys-8a74789e627c1a40.rlib" "/home/dcreager/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-7e3f00e10075cd58.rlib" "/home/dcreager/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-d3b3d6193d1b05b1.rlib" "/home/dcreager/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-4c47fecb36fc2925.rlib" "/home/dcreager/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-c0c586c7cb2de27a.rlib" "/home/dcreager/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-f1719f3d136282db.rlib" "/home/dcreager/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-b22b3fc53f39823e.rlib" "-Wl,--end-group" "/home/dcreager/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-ec6cc32e99245114.rlib" "-Wl,-Bdynamic" "-ldl" "-lrt" "-lpthread" "-lgcc_s" "-lc" "-lm" "-lrt" "-lpthread" "-lutil" "-lutil"
  = note: /usr/bin/ld: /home/dcreager/git/rust-cc-linking/target/debug/build/cc-02-broken-b6be909df134df9e/out/libbig.a(big.o): in function `big_function':
          /home/dcreager/git/rust-cc-linking/cc-02-broken/src/big.cc:8: undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string()'
          /usr/bin/ld: /home/dcreager/git/rust-cc-linking/cc-02-broken/src/big.cc:12: undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator+=(char const*)'
          /usr/bin/ld: /home/dcreager/git/rust-cc-linking/cc-02-broken/src/big.cc:14: undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator+=(char const*)'
          /usr/bin/ld: /home/dcreager/git/rust-cc-linking/cc-02-broken/src/big.cc:16: undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::size() const'
          /usr/bin/ld: /home/dcreager/git/rust-cc-linking/cc-02-broken/src/big.cc:8: undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
          /usr/bin/ld: /home/dcreager/git/rust-cc-linking/cc-02-broken/src/big.cc:8: undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
          /usr/bin/ld: /home/dcreager/git/rust-cc-linking/target/debug/build/cc-02-broken-b6be909df134df9e/out/libbig.a(big.o):(.data.rel.local.DW.ref.__gxx_personality_v0[DW.ref.__gxx_personality_v0]+0x0): undefined reference to `__gxx_personality_v0'
          collect2: error: ld returned 1 exit status
          

error: aborting due to previous error

error: Could not compile `cc-02-broken`.
warning: build failed, waiting for other jobs to finish...
error: build failed
After (both)
$ cargo +local build
   Compiling cc v1.0.26
   Compiling cc-01-works-by-accident v0.1.0 (/Users/dcreager/git/rust-cc-linking/cc-01-works-by-accident)                                                                     
   Compiling cc-02-broken v0.1.0 (/Users/dcreager/git/rust-cc-linking/cc-02-broken)
    Finished dev [unoptimized + debuginfo] target(s) in 2.77s

I'm not familiar with changing the link type so I don't have any examples of that at my fingertips, but I'll try to put together a minimal example for that, too.

@dcreager
Copy link
Contributor Author

Got a before/after for the "change library kind" behavior:

Before
$ cargo build -p cc-03-change-link-kind
   Compiling cc-03-change-link-kind v0.1.0 (/Users/dcreager/git/rust-cc-linking/cc-03-change-link-kind)                                                                       
    Finished dev [unoptimized + debuginfo] target(s) in 1.02s
After
$ cargo +local build -p cc-03-change-link-kind 
   Compiling cc-03-change-link-kind v0.1.0 (/Users/dcreager/git/rust-cc-linking/cc-03-change-link-kind)
    Finished dev [unoptimized + debuginfo] target(s) in 1.03s

That build script has a flag that updates the kind for the small library, and there is no warning either before or after.

@alexcrichton
Copy link
Member

Ok thanks for the investigation! I'm realizing now I'm completely misreading the code, I thought it warned on changed, but actually it warns on !changed. My bad!

Out of an abundance of caution around linking things I'd like to run this through crater to ensure that we don't have any unexpected breakage. Linkage is always super subtle and really hard to predict what or what won't regress lots. I think this change is right, but would be good to be safe too!

@bors: try

@bors
Copy link
Contributor

bors commented Jan 30, 2019

⌛ Trying commit c56f128 with merge 5ce78cbe7028b830a57eb1611aaf93851a11929e...

@bors
Copy link
Contributor

bors commented Jan 31, 2019

☀️ Test successful - checks-travis
State: approved= try=True

@alexcrichton
Copy link
Member

@craterbot run start=master#d9a2e3b1ccf16c6d43f56f503bd80c1ad137d523 end=try#5ce78cbe7028b830a57eb1611aaf93851a11929e mode=build-only

@craterbot
Copy link
Collaborator

👌 Experiment pr-57018 created and queued.
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 31, 2019
@craterbot
Copy link
Collaborator

🚧 Experiment pr-57018 is now running on agent aws-2.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@dcreager
Copy link
Contributor Author

Out of an abundance of caution around linking things I'd like to run this through crater to ensure that we don't have any unexpected breakage. Linkage is always super subtle and really hard to predict what or what won't regress lots. I think this change is right, but would be good to be safe too!

Absolutely! This will be fun to watch, I’ve never seen crater in action! 😀

@craterbot
Copy link
Collaborator

🚨 Experiment pr-57018 has encountered an error: some threads returned an error
🛠️ If the error is fixed use the retry command.

🆘 Can someone from the infra team check in on this? @rust-lang/infra
ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@pietroalbini
Copy link
Member

Uhhh, wut.

@craterbot retry-report

@craterbot
Copy link
Collaborator

🛠️ Generation of the report for pr-57018 queued again.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@bors
Copy link
Contributor

bors commented Mar 20, 2019

⌛ Testing commit 32d99ef with merge df536c0aabf04d36cbbf74b9c56be787914880f9...

@kennytm
Copy link
Member

kennytm commented Mar 20, 2019

@bors retry

Yield priority for #59298

@bors

This comment has been minimized.

@bors

This comment has been minimized.

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 20, 2019
@Zoxc
Copy link
Contributor

Zoxc commented Mar 20, 2019

@bors treeclosed-

@bors
Copy link
Contributor

bors commented Mar 20, 2019

⌛ Testing commit 32d99ef with merge e961dba88db54067d7534666b440669afdcc8b14...

@bors
Copy link
Contributor

bors commented Mar 20, 2019

💔 Test failed - checks-travis

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Mar 20, 2019
@rust-highfive
Copy link
Collaborator

The job i686-gnu of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
[02:58:56] test [run-make] run-make-fulldeps/pretty-print-to-file ... ok
[02:58:56] test [run-make] run-make-fulldeps/print-cfg ... ok
[02:58:56] test [run-make] run-make-fulldeps/profile ... ok
[02:58:57] test [run-make] run-make-fulldeps/prune-link-args ... ok
[02:58:57] test [run-make] run-make-fulldeps/redundant-libs ... ok
The job exceeded the maximum time limit for jobs, and has been terminated.

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@alexcrichton
Copy link
Member

@bors: retry

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 20, 2019
bors added a commit that referenced this pull request Mar 20, 2019
Keep last redundant linker flag, not first

When a library (L1) is passed to the linker multiple times, this is sometimes purposeful: there might be several other libraries in the linker command (L2 and L3) that all depend on L1.  You'd end up with a (simplified) linker command that looks like:

```
-l2 -l1 -l3 -l1
```

With the previous behavior, when rustc encountered a redundant library, it would keep the first instance, and remove the later ones, resulting in:

```
-l2 -l1 -l3
```

This can cause a linker error, because on some platforms (e.g. Linux), the linker will only include symbols from L1 that are needed *at the point it's referenced in the command line*.  So if L3 depends on additional symbols from L1, which aren't needed by L2, the linker won't know to include them, and you'll end up with "undefined symbols" errors.

A better behavior is to keep the *last* instance of the library:

```
-l2 -l3 -l1
```

This ensures that all "downstream" libraries have been included in the linker command before the "upstream" library is referenced.

Fixes #47989
@bors
Copy link
Contributor

bors commented Mar 20, 2019

⌛ Testing commit 32d99ef with merge 9c499cc...

@bors
Copy link
Contributor

bors commented Mar 20, 2019

☀️ Test successful - checks-travis, status-appveyor
Approved by: alexcrichton
Pushing 9c499cc to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Mar 20, 2019
@bors bors merged commit 32d99ef into rust-lang:master Mar 20, 2019
@rust-highfive
Copy link
Collaborator

📣 Toolstate changed by #57018!

Tested on commit 9c499cc.
Direct link to PR: #57018

🎉 rls on windows: test-fail → test-pass (cc @nrc @Xanewok, @rust-lang/infra).

rust-highfive added a commit to rust-lang-nursery/rust-toolstate that referenced this pull request Mar 20, 2019
Tested on commit rust-lang/rust@9c499cc.
Direct link to PR: <rust-lang/rust#57018>

🎉 rls on windows: test-fail → test-pass (cc @nrc @Xanewok, @rust-lang/infra).
FauxFaux added a commit to FauxFaux/apt-pkg-native-rs that referenced this pull request Apr 13, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants