Skip to content

Commit 32238ce

Browse files
bjorn3Kobzol
authored andcommitted
Allow LTO for dylibs
1 parent f7f17bf commit 32238ce

File tree

3 files changed

+33
-24
lines changed

3 files changed

+33
-24
lines changed

compiler/rustc_codegen_llvm/src/back/lto.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ pub const THIN_LTO_KEYS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-keys.bin";
3232

3333
pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
3434
match crate_type {
35-
CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => true,
36-
CrateType::Dylib | CrateType::Rlib | CrateType::ProcMacro => false,
35+
CrateType::Executable | CrateType::Dylib | CrateType::Staticlib | CrateType::Cdylib => true,
36+
CrateType::Rlib | CrateType::ProcMacro => false,
3737
}
3838
}
3939

@@ -73,17 +73,6 @@ fn prepare_lto(
7373
// with either fat or thin LTO
7474
let mut upstream_modules = Vec::new();
7575
if cgcx.lto != Lto::ThinLocal {
76-
if cgcx.opts.cg.prefer_dynamic {
77-
diag_handler
78-
.struct_err("cannot prefer dynamic linking when performing LTO")
79-
.note(
80-
"only 'staticlib', 'bin', and 'cdylib' outputs are \
81-
supported with LTO",
82-
)
83-
.emit();
84-
return Err(FatalError);
85-
}
86-
8776
// Make sure we actually can run LTO
8877
for crate_type in cgcx.crate_types.iter() {
8978
if !crate_type_allows_lto(*crate_type) {
@@ -92,6 +81,8 @@ fn prepare_lto(
9281
static library outputs",
9382
);
9483
return Err(e);
84+
} else if *crate_type == CrateType::Dylib {
85+
diag_handler.warn("LTO with dylibs may not be as effective");
9586
}
9687
}
9788

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_metadata::find_native_static_library;
1111
use rustc_metadata::fs::{emit_metadata, METADATA_FILENAME};
1212
use rustc_middle::middle::dependency_format::Linkage;
1313
use rustc_middle::middle::exported_symbols::SymbolExportKind;
14-
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
14+
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Lto, Strip};
1515
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
1616
use rustc_session::cstore::DllImport;
1717
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
@@ -49,6 +49,7 @@ use std::ops::Deref;
4949
use std::path::{Path, PathBuf};
5050
use std::process::{ExitStatus, Output, Stdio};
5151
use std::{env, fmt, fs, io, mem, str};
52+
use itertools::Itertools;
5253

5354
pub fn ensure_removed(diag_handler: &Handler, path: &Path) {
5455
if let Err(e) = fs::remove_file(path) {
@@ -208,11 +209,24 @@ pub fn link_binary<'a>(
208209
}
209210

210211
pub fn each_linked_rlib(
212+
sess: &Session,
211213
info: &CrateInfo,
212214
f: &mut dyn FnMut(CrateNum, &Path),
213215
) -> Result<(), errors::LinkRlibError> {
214216
let crates = info.used_crates.iter();
215217
let mut fmts = None;
218+
219+
let lto_active = matches!(sess.lto(), Lto::Fat | Lto::Thin);
220+
if lto_active {
221+
for combination in info.dependency_formats.iter().combinations(2) {
222+
let (ty1, list1) = combination[0];
223+
let (ty2, list2) = combination[1];
224+
if list1 != list2 {
225+
return Err(format!("{ty1:?} and {ty2:?} do not have equivalent dependency formats (`{list1:?}` vs `{list2:?}`)"));
226+
}
227+
}
228+
}
229+
216230
for (ty, list) in info.dependency_formats.iter() {
217231
match ty {
218232
CrateType::Executable
@@ -222,6 +236,10 @@ pub fn each_linked_rlib(
222236
fmts = Some(list);
223237
break;
224238
}
239+
CrateType::Dylib if lto_active => {
240+
fmts = Some(list);
241+
break;
242+
}
225243
_ => {}
226244
}
227245
}
@@ -490,7 +508,7 @@ fn link_staticlib<'a>(
490508
)?;
491509
let mut all_native_libs = vec![];
492510

493-
let res = each_linked_rlib(&codegen_results.crate_info, &mut |cnum, path| {
511+
let res = each_linked_rlib(sess, &codegen_results.crate_info, &mut |cnum, path| {
494512
let name = codegen_results.crate_info.crate_name[&cnum];
495513
let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
496514

compiler/rustc_codegen_ssa/src/back/write.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,14 @@ fn start_executing_work<B: ExtraBackendMethods>(
999999
let coordinator_send = tx_to_llvm_workers;
10001000
let sess = tcx.sess;
10011001

1002+
let mut each_linked_rlib_for_lto = Vec::new();
1003+
drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| {
1004+
if link::ignored_for_lto(sess, crate_info, cnum) {
1005+
return;
1006+
}
1007+
each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
1008+
}));
1009+
10021010
// Compute the set of symbols we need to retain when doing LTO (if we need to)
10031011
let exported_symbols = {
10041012
let mut exported_symbols = FxHashMap::default();
@@ -1020,7 +1028,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
10201028
}
10211029
Lto::Fat | Lto::Thin => {
10221030
exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE));
1023-
for &cnum in tcx.crates(()).iter() {
1031+
for &(cnum, ref _path) in &each_linked_rlib_for_lto {
10241032
exported_symbols.insert(cnum, copy_symbols(cnum));
10251033
}
10261034
Some(Arc::new(exported_symbols))
@@ -1040,14 +1048,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
10401048
})
10411049
.expect("failed to spawn helper thread");
10421050

1043-
let mut each_linked_rlib_for_lto = Vec::new();
1044-
drop(link::each_linked_rlib(crate_info, &mut |cnum, path| {
1045-
if link::ignored_for_lto(sess, crate_info, cnum) {
1046-
return;
1047-
}
1048-
each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
1049-
}));
1050-
10511051
let ol =
10521052
if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() {
10531053
// If we know that we won’t be doing codegen, create target machines without optimisation.

0 commit comments

Comments
 (0)