|
| 1 | +# Linker-plugin-LTO |
| 2 | + |
| 3 | +The `-C linker-plugin-lto` flag allows for deferring the LTO optimization |
| 4 | +to the actual linking step, which in turn allows for performing |
| 5 | +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. |
| 9 | + |
| 10 | +## Usage |
| 11 | + |
| 12 | +There are two main cases how linker plugin based LTO can be used: |
| 13 | + |
| 14 | + - compiling a Rust `staticlib` that is used as a C ABI dependency |
| 15 | + - compiling a Rust binary where `rustc` invokes the linker |
| 16 | + |
| 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. |
| 20 | + |
| 21 | +### Rust `staticlib` as dependency in C/C++ program |
| 22 | + |
| 23 | +In this case the Rust compiler just has to make sure that the object files in |
| 24 | +the `staticlib` are in the right format. For linking, a linker with the |
| 25 | +LLVM plugin must be used (e.g. LLD). |
| 26 | + |
| 27 | +Using `rustc` directly: |
| 28 | + |
| 29 | +```bash |
| 30 | +# Compile the Rust staticlib |
| 31 | +rustc --crate-type=staticlib -Clinker-plugin-lto -Copt-level=2 ./lib.rs |
| 32 | +# Compile the C code with `-flto=thin` |
| 33 | +clang -c -O2 -flto=thin -o main.o ./main.c |
| 34 | +# Link everything, making sure that we use an appropriate linker |
| 35 | +clang -flto=thin -fuse-ld=lld -L . -l"name-of-your-rust-lib" -o main -O2 ./cmain.o |
| 36 | +``` |
| 37 | + |
| 38 | +Using `cargo`: |
| 39 | + |
| 40 | +```bash |
| 41 | +# Compile the Rust staticlib |
| 42 | +RUSTFLAGS="-Clinker-plugin-lto" cargo build --release |
| 43 | +# Compile the C code with `-flto=thin` |
| 44 | +clang -c -O2 -flto=thin -o main.o ./main.c |
| 45 | +# Link everything, making sure that we use an appropriate linker |
| 46 | +clang -flto=thin -fuse-ld=lld -L . -l"name-of-your-rust-lib" -o main -O2 ./cmain.o |
| 47 | +``` |
| 48 | + |
| 49 | +### C/C++ code as a dependency in Rust |
| 50 | + |
| 51 | +In this case the linker will be invoked by `rustc`. We again have to make sure |
| 52 | +that an appropriate linker is used. |
| 53 | + |
| 54 | +Using `rustc` directly: |
| 55 | + |
| 56 | +```bash |
| 57 | +# Compile C code with `-flto` |
| 58 | +clang ./clib.c -flto=thin -c -o ./clib.o -O2 |
| 59 | +# Create a static library from the C code |
| 60 | +ar crus ./libxyz.a ./clib.o |
| 61 | + |
| 62 | +# Invoke `rustc` with the additional arguments |
| 63 | +rustc -Clinker-plugin-lto -L. -Copt-level=2 -Clinker=clang -Clink-arg=-fuse-ld=lld ./main.rs |
| 64 | +``` |
| 65 | + |
| 66 | +Using `cargo` directly: |
| 67 | + |
| 68 | +```bash |
| 69 | +# Compile C code with `-flto` |
| 70 | +clang ./clib.c -flto=thin -c -o ./clib.o -O2 |
| 71 | +# Create a static library from the C code |
| 72 | +ar crus ./libxyz.a ./clib.o |
| 73 | + |
| 74 | +# Set the linking arguments via RUSTFLAGS |
| 75 | +RUSTFLAGS="-Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld" cargo build --release |
| 76 | +``` |
| 77 | + |
| 78 | +### Explicitly specifying the linker plugin to be used by `rustc` |
| 79 | + |
| 80 | +If one wants to use a linker other than LLD, the LLVM linker plugin has to be |
| 81 | +specified explicitly. Otherwise the linker cannot read the object files. The |
| 82 | +path to the plugin is passed as an argument to the `-Clinker-plugin-lto` |
| 83 | +option: |
| 84 | + |
| 85 | +```bash |
| 86 | +rustc -Clinker-plugin-lto="/path/to/LLVMgold.so" -L. -Copt-level=2 ./main.rs |
| 87 | +``` |
| 88 | + |
| 89 | + |
| 90 | +## Toolchain Compatibility |
| 91 | + |
| 92 | +In order for this kind of LTO to work, the LLVM linker plugin must be able to |
| 93 | +handle the LLVM bitcode produced by both `rustc` and `clang`. |
| 94 | + |
| 95 | +Best results are achieved by using a `rustc` and `clang` that are based on the |
| 96 | +exact same version of LLVM. One can use `rustc -vV` in order to view the LLVM |
| 97 | +used by a given `rustc` version. Note that the version number given |
| 98 | +here is only an approximation as Rust sometimes uses unstable revisions of |
| 99 | +LLVM. However, the approximation is usually reliable. |
| 100 | + |
| 101 | +The following table shows known good combinations of toolchain versions. |
| 102 | + |
| 103 | +| | Clang 7 | Clang 8 | |
| 104 | +|-----------|-----------|-----------| |
| 105 | +| Rust 1.34 | ✗ | ✓ | |
| 106 | +| Rust 1.35 | ✗ | ✓(?) | |
| 107 | + |
| 108 | +Note that the compatibility policy for this feature might change in the future. |
0 commit comments