Skip to content

Send -fno-lto when linker plugin LTO is not requested to avoid having GCC do LTO when using rustc_codegen_gcc - #159924

Merged
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
antoyo:fix/fno-lto
Oct 3, 2026
Merged

rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
antoyo:fix/fno-lto

Conversation

@antoyo

@antoyo antoyo commented Jul 25, 2026 •

Copy link
Copy Markdown
Contributor

@rustbot rustbot added A-run-make Area: port run-make Makefiles to rmake.rs S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jul 25, 2026
@rustbot

rustbot commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

r? @fee1-dead

rustbot has assigned @fee1-dead.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 74 candidates
  • Random selection from 17 candidates

@bjorn3

bjorn3 commented Jul 25, 2026 •

Copy link
Copy Markdown
Member

Thinking about this again, this would cause a compilation failure if there is any C code compiled with -flto, right? Older versions of cc did that whenever rust LTO is enabled even though no LTO between C and Rust happens in that case. Only LTO between Rust crates and separately between C objects. And as it so happens rustc is currently stuck on said older version of the cc crate as disabling LTO for Jemalloc is a perf regression.

@antoyo

antoyo commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

Thinking about this again, this would cause a compilation failure if there is any C code compiled with -flto, right?

You mean objects files that are not fat compiled with GCC?
Is this a case this is currently supported?
That would not work either when using LLD which is the default, no?
I would assume the way to support this would be to explicitly use a linker plugin.
What are your thoughts on this?

@bjorn3

bjorn3 commented Jul 25, 2026

Copy link
Copy Markdown
Member

That would not work either when using LLD which is the default, no?

It should currently work without extra configuration when using Clang as C compiler and either Clang as linker driver or LLD as linker though.

@antoyo

antoyo commented Jul 25, 2026 •

Copy link
Copy Markdown
Contributor Author

It should currently work without extra configuration when using Clang as C compiler and either Clang as linker driver or LLD as linker though.

So, we would need to only emit -fno-lto when gcc is used as the linker, right?
Is there a way to detect this?
If not, would using self.codegen_backend == "gcc" like we did in push_linker_plugin_lto_args be OK?

@fee1-dead

Copy link
Copy Markdown
Member

r? bjorn3

@rustbot rustbot assigned bjorn3 and unassigned fee1-dead Aug 1, 2026
@rust-log-analyzer

This comment has been minimized.

JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Sep 8, 2026
…r=Kobzol

Make `run-make` testsuite work with other codegen backend than LLVM

Needed for rust-lang#159924.

Currently, we always run `run-make` testsuite with the codegen backend rustc was compiled with. However, in CI it's compiled with LLVM, so when we want to test with GCC (with `--test-codegen-backend`), it compiles `rmake.rs` with the GCC backend, but when running the test, it doesn't use the GCC backend since it just calls `rustc`. So to get around that, I now pass the codegen backend through the environment and set it in the `rustc` function of `run_make_support`.

To be noted that for now it's only for the `rustc` function, no other command uses it. Should I extend it right away for all commands (well, likely only `cargo`) or just `rustc` for now is enough?

r? @jieyouxu
Zalathar added a commit to Zalathar/rust that referenced this pull request Sep 9, 2026
…r=Kobzol

Make `run-make` testsuite work with other codegen backend than LLVM

Needed for rust-lang#159924.

Currently, we always run `run-make` testsuite with the codegen backend rustc was compiled with. However, in CI it's compiled with LLVM, so when we want to test with GCC (with `--test-codegen-backend`), it compiles `rmake.rs` with the GCC backend, but when running the test, it doesn't use the GCC backend since it just calls `rustc`. So to get around that, I now pass the codegen backend through the environment and set it in the `rustc` function of `run_make_support`.

To be noted that for now it's only for the `rustc` function, no other command uses it. Should I extend it right away for all commands (well, likely only `cargo`) or just `rustc` for now is enough?

r? @jieyouxu
mu001999 added a commit to mu001999/rust that referenced this pull request Sep 9, 2026
…r=Kobzol

Make `run-make` testsuite work with other codegen backend than LLVM

Needed for rust-lang#159924.

Currently, we always run `run-make` testsuite with the codegen backend rustc was compiled with. However, in CI it's compiled with LLVM, so when we want to test with GCC (with `--test-codegen-backend`), it compiles `rmake.rs` with the GCC backend, but when running the test, it doesn't use the GCC backend since it just calls `rustc`. So to get around that, I now pass the codegen backend through the environment and set it in the `rustc` function of `run_make_support`.

To be noted that for now it's only for the `rustc` function, no other command uses it. Should I extend it right away for all commands (well, likely only `cargo`) or just `rustc` for now is enough?

r? @jieyouxu
rust-bors Bot pushed a commit that referenced this pull request Sep 9, 2026
Rollup merge of #162482 - GuillaumeGomez:run-make-backends, r=Kobzol

Make `run-make` testsuite work with other codegen backend than LLVM

Needed for #159924.

Currently, we always run `run-make` testsuite with the codegen backend rustc was compiled with. However, in CI it's compiled with LLVM, so when we want to test with GCC (with `--test-codegen-backend`), it compiles `rmake.rs` with the GCC backend, but when running the test, it doesn't use the GCC backend since it just calls `rustc`. So to get around that, I now pass the codegen backend through the environment and set it in the `rustc` function of `run_make_support`.

To be noted that for now it's only for the `rustc` function, no other command uses it. Should I extend it right away for all commands (well, likely only `cargo`) or just `rustc` for now is enough?

r? @jieyouxu
@GuillaumeGomez

Copy link
Copy Markdown
Member

#162482 got merged, so after a rebase, this PR should be ready to go.

@rustbot

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

Comment thread tests/run-make/linker-warning/rmake.rs Outdated
@antoyo

antoyo commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

The test now passes.
@bjorn3: This is ready for review.

@mati865

mati865 commented Sep 22, 2026

Copy link
Copy Markdown
Member

Thinking about this again, this would cause a compilation failure if there is any C code compiled with -flto, right?

Yes.

You mean objects files that are not fat compiled with GCC?
Is this a case this is currently supported?

This is the default mode for GCC/Clang and it should work as long as you don't explicitly pass -fno-lto. Fat objects require additional argument to be produced: -ffat-lto-objects.

That would not work either when using LLD which is the default, no?

No, LLD doesn't handle GIMPLE bitcode at all (it doesn't even support the plugins).
I'm not sure if LLD is even a good default for GCC backend.

It should currently work without extra configuration when using Clang as C compiler and either Clang as linker driver or LLD as linker though.

Only when the host Clang version that produced the objects matches LLD version (by default the one shipped with particular Rust version). Also, when using Clang + any linker other than LLD -flto must be provided, otherwise Clang won't add linker plugin.
Since GCC is typically "the default" C/C++ compiler on Linux, in the great majority of the cases this won't work right now.

So, we would need to only emit -fno-lto when gcc is used as the linker, right?

For Clang it will make no difference since (-no)-flto only affects whether the compiler passes the plugin. So, we have:

  • GCC/Clang + LLD - (-no)-flto makes no difference as linker plugins are not used by LLD
  • GCC + non-LLD - implicit GCC LTO plugin can be disabled with -no-flto
  • Clang + non-LLD - no implicit plugin, -no-flto has no effect

Codegen options will likely need to be updated to reflect that: https://doc.rust-lang.org/rustc/codegen-options/index.html#linker-plugin-lto


One thing here I'm failing to understand is why should GCC backend differ from LLVM one here. Since libstd produced by LLVM backend is a fat object, LLD probably does some kind of LTO on it?

@antoyo

antoyo commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor Author

One thing here I'm failing to understand is why should GCC backend differ from LLVM one here.

GCC needs additional files to do LTO (libgccjit.so is not enough) which are not distributed/built in the Rust repo (neither by rustup).

Also, is cg_llvm really automatically doing LTO when building a program that depends on the std because the std is a fat object (even when not asked by the user)?
I'm asking because another reason I wanted this -fno-lto flag being passed is that it makes the compilation time of a simple "Hello, world!" program compiled by cg_gcc go to 30 seconds/1 minute.

@antoyo

antoyo commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

As I understand it, in the LLVM world the embedded bitcode of fat objects is ignored by the linker unless -flto is passed to clang.

Even for Rust? I thought you said otherwise above in this thread.

@mati865

mati865 commented Sep 23, 2026

Copy link
Copy Markdown
Member

Okay, those are pretty compelling arguments for disabling plugin based LTO with GCC backend.

I made small experiment with C code and LLD will only use bitcode from fat objects if given --ffat-lto-objects, which aligns with its --help. So, only when Clang was called with -flto -ffat-lto-objects.

With Rust the situation might be different because Clang puts bitcode in .llvm.lto, whereas rustc puts it in .llvmbc.

@bjorn3

bjorn3 commented Sep 23, 2026

Copy link
Copy Markdown
Member

With Rust the situation might be different because Clang puts bitcode in .llvm.lto, whereas rustc puts it in .llvmbc.

According to https://llvm.org/docs/BitCodeFormat.html#native-object-file-wrapper-format .llvmbc can also be produced by LLVM, but turns out the linker plugin will indeed ignore it. If I understand correctly that would mean -Clinker-plugin-lto would be ignoring the standard library entirely. cc @nikic

@antoyo

antoyo commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

It should currently work without extra configuration when using Clang as C compiler and either Clang as linker driver or LLD as linker though.

Just to make sure I understand, this is not actually the case? Would using clang without -Clinker-plugin-lto do any LTO at all when there are fat objects?

@bjorn3

bjorn3 commented Sep 23, 2026

Copy link
Copy Markdown
Member

I would have expected it to do LTO for C code that is compiled with -flto but without -ffat-lto-objects. I just checked it and it is the case when lld is used, not when any other linker is used with clang.

; echo 'int main() { return 0; }' | clang -flto -x c -c - -o foo.o
; clang foo.o -o foo
foo.o: file not recognized: file format not recognized
clang: error: linker command failed with exit code 1 (use -v to see invocation)
; clang foo.o -o foo -flto
; clang foo.o -o foo -fuse-ld=lld
; ./foo

@antoyo

antoyo commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor Author

I would have expected it to do LTO for C code that is compiled with -flto but without -ffat-lto-objects.

But does Rust send -flto to clang by default?
The difference here is that GCC (used as the linker, when sent object files) will do LTO even without -flto if some object files contain the GCC IR.

@bjorn3

bjorn3 commented Sep 23, 2026

Copy link
Copy Markdown
Member

But does Rust send -flto to clang by default?

No, only when using -Clinker-plugin-lto.

The difference here is that GCC (used as the linker, when sent object files) will do LTO even without -flto if some object files contain the GCC IR.

lld does do LTO without -flto when object files only contain bitcode (but not for -ffat-lto-objects). Clang doesn't for other linkers though.

@antoyo

antoyo commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

Is there anything we should change in this PR or is it good to merge?

@bjorn3

bjorn3 commented Oct 2, 2026

Copy link
Copy Markdown
Member

I'm not convinced this is indeed what we should do. Happy to approve after #159924 (comment)

@bjorn3 bjorn3 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 Oct 2, 2026
@antoyo

antoyo commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

I'm not convinced this is indeed what we should do.

Do you think that because of the issue you've just opened?
It seems there might be some differences between gcc and clang for whether they automatically do LTO or not: do you think we'll be able to make that work in rustc without the hack in this PR?

I can wait a bit before merging this PR in case we find a better general solution.

@bjorn3

bjorn3 commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

s/not/now 🤦 I think if we fully fix linker plugin LTO (both the trivial case I opened an issue for and including the standard library), we may also need to pass -fno-lto on LLVM in the future.

@rustbot

rustbot commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@rust-log-analyzer

This comment has been minimized.

@bjorn3

bjorn3 commented Oct 2, 2026

Copy link
Copy Markdown
Member

@bors r+

@rust-bors

rust-bors Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 4613f38 has been approved by bjorn3

It is now in the queue for this repository.

@rust-bors rust-bors Bot 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-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 2, 2026
rust-bors Bot pushed a commit that referenced this pull request Oct 2, 2026
…uwer

Rollup of 9 pull requests

Successful merges:

 - #163655 (explicitly handle tests that pass with -Znext-solver)
 - #159924 (Send -fno-lto when linker plugin LTO is not requested to avoid having GCC do LTO when using rustc_codegen_gcc)
 - #163572 (Update the minimum external LLVM to 22)
 - #129822 (Docs - type guarantees update)
 - #157973 (Distinguish `repr(C)` ZSTs from others in ABI compatibility rules)
 - #162332 (preserve overflow in builtin Field candidates)
 - #163574 (intrinsics: Rename `abort` to `abort_immediate`)
 - #163638 (avoid trivial `fn map_bound` validations)
 - #163660 (yeet compare-mode-coherence)
rust-bors Bot pushed a commit that referenced this pull request Oct 3, 2026
…uwer

Rollup of 9 pull requests

Successful merges:

 - #163655 (explicitly handle tests that pass with -Znext-solver)
 - #159924 (Send -fno-lto when linker plugin LTO is not requested to avoid having GCC do LTO when using rustc_codegen_gcc)
 - #163572 (Update the minimum external LLVM to 22)
 - #129822 (Docs - type guarantees update)
 - #157973 (Distinguish `repr(C)` ZSTs from others in ABI compatibility rules)
 - #162332 (preserve overflow in builtin Field candidates)
 - #163574 (intrinsics: Rename `abort` to `abort_immediate`)
 - #163638 (avoid trivial `fn map_bound` validations)
 - #163660 (yeet compare-mode-coherence)
@rust-bors
rust-bors Bot merged commit adb1584 into rust-lang:main Oct 3, 2026
14 checks passed
@rustbot rustbot added this to the 1.101.0 milestone Oct 3, 2026
rust-bors Bot pushed a commit that referenced this pull request Oct 3, 2026
Rollup merge of #159924 - antoyo:fix/fno-lto, r=bjorn3

Send -fno-lto when linker plugin LTO is not requested to avoid having GCC do LTO when using rustc_codegen_gcc

More info on [this Zulip thread](https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/Add.20linker.20flag.20from.20the.20codegen/near/375045533).

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

Labels

A-run-make Area: port run-make Makefiles to rmake.rs S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants