Skip to content

Commit 7525cf2

Browse files
Rollup merge of rust-lang#151933 - foxtran:doc/linker-plugin-lto-full-lto, r=nnethercote
Linker-plugin-based LTO: give an explanation how to use linker-plugin-lto with full LTO Closes rust-lang#138910 The existing linker-plugin-based LTO documentation does not describe the correct usage of full LTO. Specifically, when invoking `rustc` with full LTO, the `-C lto` flag must be passed in addition to `-C linker-plugin-lto`. Also, this PR documents the use of full LTO when linking Rust with Fortran. Unfortunately, LLVM `flang` does not currently support ThinLTO, so full LTO is the only viable option in this case. Toolchain combinations were slightly updated. TODO: - [x] check swiftc compiler. Almost unusable. - [x] check how std lib is actually compiled - [x] add note about LLD and bitcode - [x] report bug to LLVM: llvm/llvm-project#179800 <details> <summary>Swiftc is unusable</summary> https://www.swift.org/install/ gave me LLVM-17. During playing with swift main + rust static library, LLVM-23 removed main :D ```console # thin LTO Rust: rustc --crate-type=staticlib -Clinker-plugin-lto -Copt-level=3 ./ftn.rs # full LTO swift: swiftc -static libftn.a main.swift -lto=llvm-full -O -use-ld=/tmp/test/llvm-project/install/bin/ld.lld -Xlinker --gc-sections -Xlinker --as-needed -o sr ./sr > ftn() returned: 77 # thin LTO swift: swiftc -static libftn.a main.swift -lto=llvm-thin -O -use-ld=/tmp/test/llvm-project/install/bin/ld.lld -Xlinker --gc-sections -Xlinker --as-needed -o sr ./sr > No output ``` </details>
2 parents 330a7f3 + cd50e62 commit 7525cf2

1 file changed

Lines changed: 66 additions & 14 deletions

File tree

src/doc/rustc/src/linker-plugin-lto.md

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,35 @@
33
The `-C linker-plugin-lto` flag allows for deferring the LTO optimization
44
to the actual linking step, which in turn allows for performing
55
interprocedural optimizations across programming language boundaries if
6-
all the object files being linked were created by LLVM based toolchains.
7-
The prime example here would be linking Rust code together with
8-
Clang-compiled C/C++ code.
6+
all the object files being linked were created by LLVM-based toolchains
7+
using the **same** LTO mode: either thin LTO or fat LTO.
8+
The examples would be linking Rust code together with
9+
Clang-compiled C/C++ code and LLVM Flang-compiled Fortran code.
910

1011
## Usage
1112

12-
There are two main cases how linker plugin based LTO can be used:
13+
There are two main cases how linker-plugin-based LTO can be used:
1314

1415
- compiling a Rust `staticlib` that is used as a C ABI dependency
1516
- compiling a Rust binary where `rustc` invokes the linker
1617

17-
In both cases the Rust code has to be compiled with `-C linker-plugin-lto` and
18-
the C/C++ code with `-flto` or `-flto=thin` so that object files are emitted
19-
as LLVM bitcode.
18+
In both cases, the Rust code must be compiled with `-C linker-plugin-lto`.
19+
By default, this enables thin LTO, so any interoperable language code must
20+
also be compiled in thin LTO mode. To use fat LTO with linker-plugin-based LTO,
21+
the `rustc` compiler requires the additional `-C lto=fat` flag, and the
22+
interoperable language must likewise be compiled in fat LTO mode. Note that
23+
interoperable language must be compiled using the LLVM infrastructure
24+
(see more details in [toolchain compability](#toolchain-compatibility)).
25+
26+
The following table summarizes how to enable thin LTO and fat LTO in
27+
different compilers:
28+
29+
| Compiler | Thin LTO | Fat LTO |
30+
|:---------|-----------------:|---------------:|
31+
| rustc | -Clto=thin | -Clto=fat |
32+
| clang | -flto=thin | -flto=full |
33+
| clang++ | -flto=thin | -flto=full |
34+
| flang | -flto=thin (WIP) | -flto=full |
2035

2136
### Rust `staticlib` as dependency in C/C++ program
2237

@@ -54,7 +69,7 @@ that an appropriate linker is used.
5469
Using `rustc` directly:
5570

5671
```bash
57-
# Compile C code with `-flto`
72+
# Compile C code with `-flto=thin`
5873
clang ./clib.c -flto=thin -c -o ./clib.o -O2
5974
# Create a static library from the C code
6075
ar crus ./libxyz.a ./clib.o
@@ -66,7 +81,7 @@ rustc -Clinker-plugin-lto -L. -Copt-level=2 -Clinker=clang -Clink-arg=-fuse-ld=l
6681
Using `cargo` directly:
6782

6883
```bash
69-
# Compile C code with `-flto`
84+
# Compile C code with `-flto=thin`
7085
clang ./clib.c -flto=thin -c -o ./clib.o -O2
7186
# Create a static library from the C code
7287
ar crus ./libxyz.a ./clib.o
@@ -75,6 +90,41 @@ ar crus ./libxyz.a ./clib.o
7590
RUSTFLAGS="-Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld" cargo build --release
7691
```
7792

93+
### Fortran code as a dependency in Rust
94+
95+
Rust code can also be linked together with Fortran code compiled by LLVM `flang`.
96+
The following examples demonstrate fat LTO usage, as LLVM `flang` has WIP status for
97+
thin LTO. The same approach can be applied to compile C and C++ code with fat LTO.
98+
99+
Using `rustc` directly:
100+
101+
```bash
102+
# Compile Fortran code with `-flto=full`
103+
flang ./ftnlib.f90 -flto=full -c -o ./ftnlib.f90.o -O3
104+
# Create a static library from the Fortran code
105+
ar crus ./libftn.a ./ftnlib.f90.o
106+
107+
# Invoke `rustc` with the additional arguments, `-Clto=fat` is mandatory
108+
rustc -Clinker-plugin-lto -Clto=fat -Clink-arg=path/to/libftn.a -Copt-level=3 -Clinker=flang -C default-linker-libraries=yes -Clink-arg=-fuse-ld=lld ./main.rs
109+
```
110+
111+
Using `cargo` directly:
112+
113+
```bash
114+
# Compile Fortran code with `-flto=full`
115+
flang ./ftnlib.f90 -flto=full -c -o ./ftnlib.f90.o -O3
116+
# Create a static library from the Fortran code
117+
ar crus ./libftn.a ./ftnlib.f90.o
118+
119+
# Set the linking arguments via RUSTFLAGS, `-Clto=fat` is mandatory
120+
RUSTFLAGS="-Clinker-plugin-lto -Clto=fat -Clink-arg=path/to/libftn.a -Clinker=flang -C default-linker-libraries=yes -Clink-arg=-fuse-ld=lld" cargo build --release
121+
```
122+
123+
Note, LLVM `flang` can be used as a linker driver starting from flang 21.1.8.
124+
The `-C default-linker-libraries=yes` option may be omitted if the Fortran
125+
runtime is not required; however, most Fortran code depends on the runtime,
126+
so enabling default linker libraries is usually necessary.
127+
78128
### Explicitly specifying the linker plugin to be used by `rustc`
79129

80130
If one wants to use a linker other than LLD, the LLVM linker plugin has to be
@@ -179,11 +229,13 @@ for clang, rust in sorted(version_map.items()):
179229
-->
180230

181231
In order for this kind of LTO to work, the LLVM linker plugin must be able to
182-
handle the LLVM bitcode produced by both `rustc` and `clang`.
232+
handle the LLVM bitcode produced by `rustc` and by compilers of all
233+
interoperable languages. A good rule of thumb is to use an LLVM linker plugin
234+
whose version is at least as new as the newest compiler involved.
183235

184-
Best results are achieved by using a `rustc` and `clang` that are based on the
185-
exact same version of LLVM. One can use `rustc -vV` in order to view the LLVM
186-
used by a given `rustc` version. Note that the version number given
236+
Best results are achieved by using a `rustc` and LLVM compilers that are based
237+
on the exact same version of LLVM. One can use `rustc -vV` in order to view
238+
the LLVM used by a given `rustc` version. Note that the version number given
187239
here is only an approximation as Rust sometimes uses unstable revisions of
188240
LLVM. However, the approximation is usually reliable.
189241

@@ -204,6 +256,6 @@ The following table shows known good combinations of toolchain versions.
204256
| 1.78 - 1.81 | 18 |
205257
| 1.82 - 1.86 | 19 |
206258
| 1.87 - 1.90 | 20 |
207-
| 1.91 - 1.92 | 21 |
259+
| 1.91 - 1.93 | 21 |
208260

209261
Note that the compatibility policy for this feature might change in the future.

0 commit comments

Comments
 (0)