| 
 | 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