From d1a6d47f943d8df9d565de835babc1e2f3e8d45a Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 28 Nov 2016 17:44:51 -0500 Subject: [PATCH 1/9] Make LLVM symbol visibility FFI types more stable. --- src/librustc_llvm/ffi.rs | 19 +++++++++------- src/librustc_trans/declare.rs | 2 +- src/rustllvm/RustWrapper.cpp | 42 +++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index b8f1540ad84d6..d2592a3acee47 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -64,6 +64,15 @@ pub enum Linkage { CommonLinkage = 10, } +// LLVMRustVisibility +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[repr(C)] +pub enum Visibility { + Default = 0, + Hidden = 1, + Protected = 2, +} + /// LLVMDiagnosticSeverity #[derive(Copy, Clone, Debug)] #[repr(C)] @@ -399,13 +408,6 @@ pub type OperandBundleDefRef = *mut OperandBundleDef_opaque; pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void); pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint); -/// LLVMVisibility -#[repr(C)] -pub enum Visibility { - Default, - Hidden, - Protected, -} pub mod debuginfo { use super::MetadataRef; @@ -655,7 +657,8 @@ extern "C" { pub fn LLVMRustSetLinkage(Global: ValueRef, RustLinkage: Linkage); pub fn LLVMGetSection(Global: ValueRef) -> *const c_char; pub fn LLVMSetSection(Global: ValueRef, Section: *const c_char); - pub fn LLVMSetVisibility(Global: ValueRef, Viz: Visibility); + pub fn LLVMRustGetVisibility(Global: ValueRef) -> Visibility; + pub fn LLVMRustSetVisibility(Global: ValueRef, Viz: Visibility); pub fn LLVMGetAlignment(Global: ValueRef) -> c_uint; pub fn LLVMSetAlignment(Global: ValueRef, Bytes: c_uint); pub fn LLVMSetDLLStorageClass(V: ValueRef, C: DLLStorageClass); diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index 7d6a672077a07..eef3b9b11474b 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -78,7 +78,7 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: // don't want the symbols to get exported. if attr::contains_name(ccx.tcx().map.krate_attrs(), "compiler_builtins") { unsafe { - llvm::LLVMSetVisibility(llfn, llvm::Visibility::Hidden); + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 51859a928c40a..6a95b65d5e92f 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1408,3 +1408,45 @@ extern "C" void LLVMRustSetLinkage(LLVMValueRef V, LLVMRustLinkage RustLinkage) extern "C" LLVMContextRef LLVMRustGetValueContext(LLVMValueRef V) { return wrap(&unwrap(V)->getContext()); } + +enum class LLVMRustVisibility { + Default = 0, + Hidden = 1, + Protected = 2, +}; + +static LLVMRustVisibility to_rust(LLVMVisibility vis) { + switch (vis) { + case LLVMDefaultVisibility: + return LLVMRustVisibility::Default; + case LLVMHiddenVisibility: + return LLVMRustVisibility::Hidden; + case LLVMProtectedVisibility: + return LLVMRustVisibility::Protected; + + default: + llvm_unreachable("Invalid LLVMRustVisibility value!"); + } +} + +static LLVMVisibility from_rust(LLVMRustVisibility vis) { + switch (vis) { + case LLVMRustVisibility::Default: + return LLVMDefaultVisibility; + case LLVMRustVisibility::Hidden: + return LLVMHiddenVisibility; + case LLVMRustVisibility::Protected: + return LLVMProtectedVisibility; + + default: + llvm_unreachable("Invalid LLVMRustVisibility value!"); + } +} + +extern "C" LLVMRustVisibility LLVMRustGetVisibility(LLVMValueRef V) { + return to_rust(LLVMGetVisibility(V)); +} + +extern "C" void LLVMRustSetVisibility(LLVMValueRef V, LLVMRustVisibility RustVisibility) { + LLVMSetVisibility(V, from_rust(RustVisibility)); +} From 5fd7c2bfef50e00fdd6b2f5dc07b17c2c324f396 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 28 Nov 2016 18:05:53 -0500 Subject: [PATCH 2/9] trans: Rename `reachable` to `exported_symbols` where appropriate. --- src/librustc/middle/cstore.rs | 4 +-- src/librustc_metadata/cstore_impl.rs | 4 +-- src/librustc_metadata/decoder.rs | 4 +-- src/librustc_metadata/encoder.rs | 24 +++++++++--------- src/librustc_metadata/schema.rs | 2 +- src/librustc_trans/back/linker.rs | 10 ++++---- src/librustc_trans/back/lto.rs | 6 ++--- src/librustc_trans/back/write.rs | 14 +++++------ src/librustc_trans/base.rs | 36 +++++++++++++-------------- src/librustc_trans/context.rs | 16 ++++++------ src/librustc_trans/debuginfo/utils.rs | 2 +- src/librustc_trans/lib.rs | 2 +- 12 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 822fb4d6770f0..34224b924b948 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -329,7 +329,7 @@ pub trait CrateStore<'tcx> { fn crate_disambiguator(&self, cnum: CrateNum) -> Symbol; fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option; fn native_libraries(&self, cnum: CrateNum) -> Vec; - fn reachable_ids(&self, cnum: CrateNum) -> Vec; + fn exported_symbols(&self, cnum: CrateNum) -> Vec; fn is_no_builtins(&self, cnum: CrateNum) -> bool; // resolve @@ -493,7 +493,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { { bug!("plugin_registrar_fn") } fn native_libraries(&self, cnum: CrateNum) -> Vec { bug!("native_libraries") } - fn reachable_ids(&self, cnum: CrateNum) -> Vec { bug!("reachable_ids") } + fn exported_symbols(&self, cnum: CrateNum) -> Vec { bug!("exported_symbols") } fn is_no_builtins(&self, cnum: CrateNum) -> bool { bug!("is_no_builtins") } // resolve diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 3150f74e61e7c..2965e545eca4e 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -311,9 +311,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(cnum).get_native_libraries() } - fn reachable_ids(&self, cnum: CrateNum) -> Vec + fn exported_symbols(&self, cnum: CrateNum) -> Vec { - self.get_crate_data(cnum).get_reachable_ids() + self.get_crate_data(cnum).get_exported_symbols() } fn is_no_builtins(&self, cnum: CrateNum) -> bool { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index fe536b69c61d5..43635eae76c0f 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1038,8 +1038,8 @@ impl<'a, 'tcx> CrateMetadata { arg_names.decode(self).collect() } - pub fn get_reachable_ids(&self) -> Vec { - self.root.reachable_ids.decode(self).map(|index| self.local_def_id(index)).collect() + pub fn get_exported_symbols(&self) -> Vec { + self.root.exported_symbols.decode(self).map(|index| self.local_def_id(index)).collect() } pub fn get_macro(&self, id: DefIndex) -> (ast::Name, MacroDef) { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 83904b24de328..01cb0f823e8ef 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -50,7 +50,7 @@ pub struct EncodeContext<'a, 'tcx: 'a> { reexports: &'a def::ExportMap, link_meta: &'a LinkMeta, cstore: &'a cstore::CStore, - reachable: &'a NodeSet, + exported_symbols: &'a NodeSet, lazy_state: LazyState, type_shorthands: FxHashMap, usize>, @@ -1223,16 +1223,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_seq(all_impls) } - // Encodes all reachable symbols in this crate into the metadata. + // Encodes all symbols exported from this crate into the metadata. // // This pass is seeded off the reachability list calculated in the // middle::reachable module but filters out items that either don't have a // symbol associated with them (they weren't translated) or if they're an FFI // definition (as that's not defined in this crate). - fn encode_reachable(&mut self) -> LazySeq { - let reachable = self.reachable; + fn encode_exported_symbols(&mut self) -> LazySeq { + let exported_symbols = self.exported_symbols; let tcx = self.tcx; - self.lazy_seq(reachable.iter().map(|&id| tcx.map.local_def_id(id).index)) + self.lazy_seq(exported_symbols.iter().map(|&id| tcx.map.local_def_id(id).index)) } fn encode_dylib_dependency_formats(&mut self) -> LazySeq> { @@ -1278,10 +1278,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let impls = self.encode_impls(); let impl_bytes = self.position() - i; - // Encode reachability info. + // Encode exported symbols info. i = self.position(); - let reachable_ids = self.encode_reachable(); - let reachable_bytes = self.position() - i; + let exported_symbols = self.encode_exported_symbols(); + let exported_symbols_bytes = self.position() - i; // Encode and index the items. i = self.position(); @@ -1319,7 +1319,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { native_libraries: native_libraries, codemap: codemap, impls: impls, - reachable_ids: reachable_ids, + exported_symbols: exported_symbols, index: index, }); @@ -1339,7 +1339,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { println!(" native bytes: {}", native_lib_bytes); println!(" codemap bytes: {}", codemap_bytes); println!(" impl bytes: {}", impl_bytes); - println!(" reachable bytes: {}", reachable_bytes); + println!(" exp. symbols bytes: {}", exported_symbols_bytes); println!(" item bytes: {}", item_bytes); println!(" index bytes: {}", index_bytes); println!(" zero bytes: {}", zero_bytes); @@ -1377,7 +1377,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cstore: &cstore::CStore, reexports: &def::ExportMap, link_meta: &LinkMeta, - reachable: &NodeSet) + exported_symbols: &NodeSet) -> Vec { let mut cursor = Cursor::new(vec![]); cursor.write_all(METADATA_HEADER).unwrap(); @@ -1392,7 +1392,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, reexports: reexports, link_meta: link_meta, cstore: cstore, - reachable: reachable, + exported_symbols: exported_symbols, lazy_state: LazyState::NoNode, type_shorthands: Default::default(), predicate_shorthands: Default::default(), diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 00c3709435de5..f92051cbf1943 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -180,7 +180,7 @@ pub struct CrateRoot { pub native_libraries: LazySeq, pub codemap: LazySeq, pub impls: LazySeq, - pub reachable_ids: LazySeq, + pub exported_symbols: LazySeq, pub index: LazySeq, } diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 860903d259fe5..b8d5fc9042f10 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -34,10 +34,10 @@ pub struct LinkerInfo { impl<'a, 'tcx> LinkerInfo { pub fn new(scx: &SharedCrateContext<'a, 'tcx>, - reachable: &[String]) -> LinkerInfo { + exports: &[String]) -> LinkerInfo { LinkerInfo { exports: scx.sess().crate_types.borrow().iter().map(|&c| { - (c, exported_symbols(scx, reachable, c)) + (c, exported_symbols(scx, exports, c)) }).collect(), } } @@ -473,7 +473,7 @@ impl<'a> Linker for MsvcLinker<'a> { } fn exported_symbols(scx: &SharedCrateContext, - reachable: &[String], + exported_symbols: &[String], crate_type: CrateType) -> Vec { // See explanation in GnuLinker::export_symbols, for @@ -485,7 +485,7 @@ fn exported_symbols(scx: &SharedCrateContext, } } - let mut symbols = reachable.to_vec(); + let mut symbols = exported_symbols.to_vec(); // If we're producing anything other than a dylib then the `reachable` array // above is the exhaustive set of symbols we should be exporting. @@ -507,7 +507,7 @@ fn exported_symbols(scx: &SharedCrateContext, None } }).flat_map(|cnum| { - cstore.reachable_ids(cnum) + cstore.exported_symbols(cnum) }).map(|did| -> String { Instance::mono(scx, did).symbol_name(scx) })); diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 522864c6ec3a4..46b1241de368f 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -25,7 +25,7 @@ use std::ffi::CString; use std::path::Path; pub fn run(sess: &session::Session, llmod: ModuleRef, - tm: TargetMachineRef, reachable: &[String], + tm: TargetMachineRef, exported_symbols: &[String], config: &ModuleConfig, temp_no_opt_bc_filename: &Path) { if sess.opts.cg.prefer_dynamic { @@ -118,8 +118,8 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, } }); - // Internalize everything but the reachable symbols of the current module - let cstrs: Vec = reachable.iter().map(|s| { + // Internalize everything but the exported symbols of the current module + let cstrs: Vec = exported_symbols.iter().map(|s| { CString::new(s.clone()).unwrap() }).collect(); let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect(); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index ae5d02c7e048a..84bba64dd70b2 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -343,9 +343,9 @@ struct CodegenContext<'a> { } impl<'a> CodegenContext<'a> { - fn new_with_session(sess: &'a Session, reachable: &'a [String]) -> CodegenContext<'a> { + fn new_with_session(sess: &'a Session, exported_symbols: &'a [String]) -> CodegenContext<'a> { CodegenContext { - lto_ctxt: Some((sess, reachable)), + lto_ctxt: Some((sess, exported_symbols)), handler: sess.diagnostic(), plugin_passes: sess.plugin_llvm_passes.borrow().clone(), remark: sess.opts.cg.remark.clone(), @@ -516,14 +516,14 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, llvm::LLVMDisposePassManager(mpm); match cgcx.lto_ctxt { - Some((sess, reachable)) if sess.lto() => { + Some((sess, exported_symbols)) if sess.lto() => { time(sess.time_passes(), "all lto passes", || { let temp_no_opt_bc_filename = output_names.temp_path_ext("no-opt.lto.bc", module_name); lto::run(sess, llmod, tm, - reachable, + exported_symbols, &config, &temp_no_opt_bc_filename); }); @@ -753,7 +753,7 @@ pub fn run_passes(sess: &Session, // potentially create hundreds of them). let num_workers = work_items.len() - 1; if num_workers == 1 { - run_work_singlethreaded(sess, &trans.reachable, work_items); + run_work_singlethreaded(sess, &trans.exported_symbols, work_items); } else { run_work_multithreaded(sess, work_items, num_workers); } @@ -997,9 +997,9 @@ fn execute_work_item(cgcx: &CodegenContext, } fn run_work_singlethreaded(sess: &Session, - reachable: &[String], + exported_symbols: &[String], work_items: Vec) { - let cgcx = CodegenContext::new_with_session(sess, reachable); + let cgcx = CodegenContext::new_with_session(sess, exported_symbols); // Since we're running single-threaded, we can pass the session to // the proc, allowing `optimize_and_codegen` to perform LTO. diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 259ef2a780cc2..74e6a1dac80b1 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1243,7 +1243,7 @@ fn contains_null(s: &str) -> bool { } fn write_metadata(cx: &SharedCrateContext, - reachable_ids: &NodeSet) -> Vec { + exported_symbols: &NodeSet) -> Vec { use flate; #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -1275,7 +1275,7 @@ fn write_metadata(cx: &SharedCrateContext, let metadata = cstore.encode_metadata(cx.tcx(), cx.export_map(), cx.link_meta(), - reachable_ids); + exported_symbols); if kind == MetadataKind::Uncompressed { return metadata; } @@ -1313,7 +1313,7 @@ fn write_metadata(cx: &SharedCrateContext, fn internalize_symbols<'a, 'tcx>(sess: &Session, ccxs: &CrateContextList<'a, 'tcx>, symbol_map: &SymbolMap<'tcx>, - reachable: &FxHashSet<&str>) { + exported_symbols: &FxHashSet<&str>) { let scx = ccxs.shared(); let tcx = scx.tcx(); @@ -1379,7 +1379,7 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, let name_cow = Cow::Borrowed(name_str); let is_referenced_somewhere = referenced_somewhere.contains(&name_cstr); - let is_reachable = reachable.contains(&name_str); + let is_reachable = exported_symbols.contains(&name_str); let has_fixed_linkage = linkage_fixed_explicitly.contains(&name_cow); if !is_referenced_somewhere && !is_reachable && !has_fixed_linkage { @@ -1481,7 +1481,7 @@ fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter { /// /// This list is later used by linkers to determine the set of symbols needed to /// be exposed from a dynamic library and it's also encoded into the metadata. -pub fn filter_reachable_ids(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { +pub fn find_exported_symbols(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { reachable.into_iter().filter(|&id| { // Next, we want to ignore some FFI functions that are not exposed from // this crate. Reachable FFI functions can be lumped into two @@ -1535,7 +1535,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let krate = tcx.map.krate(); let ty::CrateAnalysis { export_map, reachable, name, .. } = analysis; - let reachable = filter_reachable_ids(tcx, reachable); + let exported_symbols = find_exported_symbols(tcx, reachable); let check_overflow = if let Some(v) = tcx.sess.opts.debugging_opts.force_overflow_checks { v @@ -1548,11 +1548,11 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let shared_ccx = SharedCrateContext::new(tcx, export_map, link_meta.clone(), - reachable, + exported_symbols, check_overflow); // Translate the metadata. let metadata = time(tcx.sess.time_passes(), "write metadata", || { - write_metadata(&shared_ccx, shared_ccx.reachable()) + write_metadata(&shared_ccx, shared_ccx.exported_symbols()) }); let metadata_module = ModuleTranslation { @@ -1608,7 +1608,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, metadata_module: metadata_module, link: link_meta, metadata: metadata, - reachable: vec![], + exported_symbols: vec![], no_builtins: no_builtins, linker_info: linker_info, windows_subsystem: None, @@ -1688,17 +1688,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let sess = shared_ccx.sess(); - let mut reachable_symbols = shared_ccx.reachable().iter().map(|&id| { + let mut exported_symbols = shared_ccx.exported_symbols().iter().map(|&id| { let def_id = shared_ccx.tcx().map.local_def_id(id); symbol_for_def_id(def_id, &shared_ccx, &symbol_map) }).collect::>(); if sess.entry_fn.borrow().is_some() { - reachable_symbols.push("main".to_string()); + exported_symbols.push("main".to_string()); } if sess.crate_types.borrow().contains(&config::CrateTypeDylib) { - reachable_symbols.push(shared_ccx.metadata_symbol_name()); + exported_symbols.push(shared_ccx.metadata_symbol_name()); } // For the purposes of LTO or when creating a cdylib, we add to the @@ -1708,10 +1708,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // // Note that this happens even if LTO isn't requested or we're not creating // a cdylib. In those cases, though, we're not even reading the - // `reachable_symbols` list later on so it should be ok. + // `exported_symbols` list later on so it should be ok. for cnum in sess.cstore.crates() { - let syms = sess.cstore.reachable_ids(cnum); - reachable_symbols.extend(syms.into_iter().filter(|&def_id| { + let syms = sess.cstore.exported_symbols(cnum); + exported_symbols.extend(syms.into_iter().filter(|&def_id| { let applicable = match sess.cstore.describe_def(def_id) { Some(Def::Static(..)) => true, Some(Def::Fn(_)) => { @@ -1735,7 +1735,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, internalize_symbols(sess, &crate_context_list, &symbol_map, - &reachable_symbols.iter() + &exported_symbols.iter() .map(|s| &s[..]) .collect()) }); @@ -1749,7 +1749,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, create_imps(&crate_context_list); } - let linker_info = LinkerInfo::new(&shared_ccx, &reachable_symbols); + let linker_info = LinkerInfo::new(&shared_ccx, &exported_symbols); let subsystem = attr::first_attr_value_str_by_name(&krate.attrs, "windows_subsystem"); @@ -1767,7 +1767,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, metadata_module: metadata_module, link: link_meta, metadata: metadata, - reachable: reachable_symbols, + exported_symbols: exported_symbols, no_builtins: no_builtins, linker_info: linker_info, windows_subsystem: windows_subsystem, diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index c0d7c64bd192c..262b83623977c 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -67,7 +67,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { metadata_llcx: ContextRef, export_map: ExportMap, - reachable: NodeSet, + exported_symbols: NodeSet, link_meta: LinkMeta, tcx: TyCtxt<'a, 'tcx, 'tcx>, stats: Stats, @@ -437,7 +437,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>, export_map: ExportMap, link_meta: LinkMeta, - reachable: NodeSet, + exported_symbols: NodeSet, check_overflow: bool) -> SharedCrateContext<'b, 'tcx> { let (metadata_llcx, metadata_llmod) = unsafe { @@ -454,7 +454,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { // they're not available to be linked against. This poses a few problems // for the compiler, some of which are somewhat fundamental, but we use // the `use_dll_storage_attrs` variable below to attach the `dllexport` - // attribute to all LLVM functions that are reachable (e.g. they're + // attribute to all LLVM functions that are exported e.g. they're // already tagged with external linkage). This is suboptimal for a few // reasons: // @@ -493,7 +493,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { metadata_llmod: metadata_llmod, metadata_llcx: metadata_llcx, export_map: export_map, - reachable: reachable, + exported_symbols: exported_symbols, link_meta: link_meta, tcx: tcx, stats: Stats { @@ -527,8 +527,8 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { &self.export_map } - pub fn reachable<'a>(&'a self) -> &'a NodeSet { - &self.reachable + pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet { + &self.exported_symbols } pub fn trait_cache(&self) -> &RefCell>> { @@ -768,8 +768,8 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.shared.export_map } - pub fn reachable<'a>(&'a self) -> &'a NodeSet { - &self.shared.reachable + pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet { + &self.shared.exported_symbols } pub fn link_meta<'a>(&'a self) -> &'a LinkMeta { diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs index 7cac9172a9c8b..3ee2497009f65 100644 --- a/src/librustc_trans/debuginfo/utils.rs +++ b/src/librustc_trans/debuginfo/utils.rs @@ -34,7 +34,7 @@ pub fn is_node_local_to_unit(cx: &CrateContext, node_id: ast::NodeId) -> bool // visible). It might better to use the `exported_items` set from // `driver::CrateAnalysis` in the future, but (atm) this set is not // available in the translation pass. - !cx.reachable().contains(&node_id) + !cx.exported_symbols().contains(&node_id) } #[allow(non_snake_case)] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 0e7ead30a933a..8a7ab16ee2b01 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -169,7 +169,7 @@ pub struct CrateTranslation { pub metadata_module: ModuleTranslation, pub link: middle::cstore::LinkMeta, pub metadata: Vec, - pub reachable: Vec, + pub exported_symbols: Vec, pub no_builtins: bool, pub windows_subsystem: Option, pub linker_info: back::linker::LinkerInfo From 133aeacf2f28b985bba88eebc08c7a9924453738 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 30 Nov 2016 10:03:42 -0500 Subject: [PATCH 3/9] Refactor symbol export list generation. --- src/librustc/middle/cstore.rs | 3 + src/librustc_metadata/cstore_impl.rs | 8 + src/librustc_trans/back/linker.rs | 54 ++--- src/librustc_trans/back/lto.rs | 65 ++++-- src/librustc_trans/back/symbol_export.rs | 185 +++++++++++++++++ src/librustc_trans/back/write.rs | 9 +- src/librustc_trans/base.rs | 210 +++++++++----------- src/librustc_trans/lib.rs | 3 +- src/test/run-make/sepcomp-inlining/Makefile | 4 +- 9 files changed, 371 insertions(+), 170 deletions(-) create mode 100644 src/librustc_trans/back/symbol_export.rs diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 34224b924b948..4357518b332cc 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -328,6 +328,7 @@ pub trait CrateStore<'tcx> { fn crate_hash(&self, cnum: CrateNum) -> Svh; fn crate_disambiguator(&self, cnum: CrateNum) -> Symbol; fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option; + fn derive_registrar_fn(&self, cnum: CrateNum) -> Option; fn native_libraries(&self, cnum: CrateNum) -> Vec; fn exported_symbols(&self, cnum: CrateNum) -> Vec; fn is_no_builtins(&self, cnum: CrateNum) -> bool; @@ -491,6 +492,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { -> Symbol { bug!("crate_disambiguator") } fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option { bug!("plugin_registrar_fn") } + fn derive_registrar_fn(&self, cnum: CrateNum) -> Option + { bug!("derive_registrar_fn") } fn native_libraries(&self, cnum: CrateNum) -> Vec { bug!("native_libraries") } fn exported_symbols(&self, cnum: CrateNum) -> Vec { bug!("exported_symbols") } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 2965e545eca4e..aca1d2f761281 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -306,6 +306,14 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { }) } + fn derive_registrar_fn(&self, cnum: CrateNum) -> Option + { + self.get_crate_data(cnum).root.macro_derive_registrar.map(|index| DefId { + krate: cnum, + index: index + }) + } + fn native_libraries(&self, cnum: CrateNum) -> Vec { self.get_crate_data(cnum).get_native_libraries() diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index b8d5fc9042f10..933813ac4d931 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -17,11 +17,11 @@ use std::path::{Path, PathBuf}; use std::process::Command; use context::SharedCrateContext; -use monomorphize::Instance; use back::archive; +use back::symbol_export::{self, ExportedSymbols}; use middle::dependency_format::Linkage; -use rustc::hir::def_id::CrateNum; +use rustc::hir::def_id::{LOCAL_CRATE, CrateNum}; use session::Session; use session::config::CrateType; use session::config; @@ -34,7 +34,7 @@ pub struct LinkerInfo { impl<'a, 'tcx> LinkerInfo { pub fn new(scx: &SharedCrateContext<'a, 'tcx>, - exports: &[String]) -> LinkerInfo { + exports: &ExportedSymbols) -> LinkerInfo { LinkerInfo { exports: scx.sess().crate_types.borrow().iter().map(|&c| { (c, exported_symbols(scx, exports, c)) @@ -473,43 +473,29 @@ impl<'a> Linker for MsvcLinker<'a> { } fn exported_symbols(scx: &SharedCrateContext, - exported_symbols: &[String], + exported_symbols: &ExportedSymbols, crate_type: CrateType) -> Vec { - // See explanation in GnuLinker::export_symbols, for - // why we don't ever need dylib symbols on non-MSVC. - if crate_type == CrateType::CrateTypeDylib || - crate_type == CrateType::CrateTypeProcMacro { - if !scx.sess().target.target.options.is_like_msvc { - return vec![]; - } - } - - let mut symbols = exported_symbols.to_vec(); + let export_threshold = symbol_export::crate_export_threshold(crate_type); - // If we're producing anything other than a dylib then the `reachable` array - // above is the exhaustive set of symbols we should be exporting. - // - // For dylibs, however, we need to take a look at how all upstream crates - // are linked into this dynamic library. For all statically linked - // libraries we take all their reachable symbols and emit them as well. - if crate_type != CrateType::CrateTypeDylib { - return symbols - } + let mut symbols = Vec::new(); + exported_symbols.for_each_exported_symbol(LOCAL_CRATE, export_threshold, |name, _| { + symbols.push(name.to_owned()); + }); - let cstore = &scx.sess().cstore; let formats = scx.sess().dependency_formats.borrow(); let deps = formats[&crate_type].iter(); - symbols.extend(deps.enumerate().filter_map(|(i, f)| { - if *f == Linkage::Static { - Some(CrateNum::new(i + 1)) - } else { - None + + for (index, dep_format) in deps.enumerate() { + let cnum = CrateNum::new(index + 1); + // For each dependency that we are linking to statically ... + if *dep_format == Linkage::Static { + // ... we add its symbol list to our export list. + exported_symbols.for_each_exported_symbol(cnum, export_threshold, |name, _| { + symbols.push(name.to_owned()); + }) } - }).flat_map(|cnum| { - cstore.exported_symbols(cnum) - }).map(|did| -> String { - Instance::mono(scx, did).symbol_name(scx) - })); + } + symbols } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 46b1241de368f..1960b36827874 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -8,14 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::link; -use super::write; +use back::link; +use back::write; +use back::symbol_export::{self, ExportedSymbols}; use rustc::session::{self, config}; use llvm; use llvm::archive_ro::ArchiveRO; use llvm::{ModuleRef, TargetMachineRef, True, False}; use rustc::util::common::time; use rustc::util::common::path2cstr; +use rustc::hir::def_id::LOCAL_CRATE; use back::write::{ModuleConfig, with_llvm_pmb}; use libc; @@ -24,8 +26,23 @@ use flate; use std::ffi::CString; use std::path::Path; -pub fn run(sess: &session::Session, llmod: ModuleRef, - tm: TargetMachineRef, exported_symbols: &[String], +pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool { + match crate_type { + config::CrateTypeExecutable | + config::CrateTypeStaticlib | + config::CrateTypeCdylib => true, + + config::CrateTypeDylib | + config::CrateTypeRlib | + config::CrateTypeMetadata | + config::CrateTypeProcMacro => false, + } +} + +pub fn run(sess: &session::Session, + llmod: ModuleRef, + tm: TargetMachineRef, + exported_symbols: &ExportedSymbols, config: &ModuleConfig, temp_no_opt_bc_filename: &Path) { if sess.opts.cg.prefer_dynamic { @@ -38,17 +55,31 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, // Make sure we actually can run LTO for crate_type in sess.crate_types.borrow().iter() { - match *crate_type { - config::CrateTypeExecutable | - config::CrateTypeCdylib | - config::CrateTypeStaticlib => {} - _ => { - sess.fatal("lto can only be run for executables and \ + if !crate_type_allows_lto(*crate_type) { + sess.fatal("lto can only be run for executables and \ static library outputs"); - } } } + let export_threshold = + symbol_export::crates_export_threshold(&sess.crate_types.borrow()[..]); + + let symbol_filter = &|&(ref name, level): &(String, _)| { + if symbol_export::is_below_threshold(level, export_threshold) { + let mut bytes = Vec::with_capacity(name.len() + 1); + bytes.extend(name.bytes()); + Some(CString::new(bytes).unwrap()) + } else { + None + } + }; + + let mut symbol_white_list: Vec = exported_symbols + .exported_symbols(LOCAL_CRATE) + .iter() + .filter_map(symbol_filter) + .collect(); + // For each of our upstream dependencies, find the corresponding rlib and // load the bitcode from the archive. Then merge it into the current LLVM // module that we've got. @@ -58,6 +89,11 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, return; } + symbol_white_list.extend( + exported_symbols.exported_symbols(cnum) + .iter() + .filter_map(symbol_filter)); + let archive = ArchiveRO::open(&path).expect("wanted an rlib"); let bytecodes = archive.iter().filter_map(|child| { child.ok().and_then(|c| c.name().map(|name| (name, c))) @@ -119,10 +155,9 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, }); // Internalize everything but the exported symbols of the current module - let cstrs: Vec = exported_symbols.iter().map(|s| { - CString::new(s.clone()).unwrap() - }).collect(); - let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect(); + let arr: Vec<*const libc::c_char> = symbol_white_list.iter() + .map(|c| c.as_ptr()) + .collect(); let ptr = arr.as_ptr(); unsafe { llvm::LLVMRustRunRestrictionPass(llmod, diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs new file mode 100644 index 0000000000000..2290cb0f48785 --- /dev/null +++ b/src/librustc_trans/back/symbol_export.rs @@ -0,0 +1,185 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use context::SharedCrateContext; +use monomorphize::Instance; +use symbol_map::SymbolMap; +use util::nodemap::FxHashMap; +use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; +use rustc::session::config; +use syntax::attr; +use trans_item::TransItem; + +/// The SymbolExportLevel of a symbols specifies from which kinds of crates +/// the symbol will be exported. `C` symbols will be exported from any +/// kind of crate, including cdylibs which export very few things. +/// `Rust` will only be exported if the crate produced is a Rust +/// dylib. +#[derive(Eq, PartialEq, Debug, Copy, Clone)] +pub enum SymbolExportLevel { + C, + Rust, +} + +/// The set of symbols exported from each crate in the crate graph. +pub struct ExportedSymbols { + exports: FxHashMap>, +} + +impl ExportedSymbols { + + pub fn empty() -> ExportedSymbols { + ExportedSymbols { + exports: FxHashMap(), + } + } + + pub fn compute_from<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, + symbol_map: &SymbolMap<'tcx>) + -> ExportedSymbols { + let mut local_crate: Vec<_> = scx + .exported_symbols() + .iter() + .map(|&node_id| { + scx.tcx().map.local_def_id(node_id) + }) + .map(|def_id| { + (symbol_for_def_id(scx, def_id, symbol_map), + export_level(scx, def_id)) + }) + .collect(); + + if scx.sess().entry_fn.borrow().is_some() { + local_crate.push(("main".to_string(), SymbolExportLevel::C)); + } + + if scx.sess().crate_types.borrow().contains(&config::CrateTypeDylib) { + local_crate.push((scx.metadata_symbol_name(), + SymbolExportLevel::Rust)); + } + + let mut exports = FxHashMap(); + exports.insert(LOCAL_CRATE, local_crate); + + for cnum in scx.sess().cstore.crates() { + debug_assert!(cnum != LOCAL_CRATE); + + if scx.sess().cstore.plugin_registrar_fn(cnum).is_some() || + scx.sess().cstore.derive_registrar_fn(cnum).is_some() { + continue; + } + + let crate_exports = scx + .sess() + .cstore + .exported_symbols(cnum) + .iter() + .map(|&def_id| { + debug!("EXTERN-SYMBOL: {:?}", def_id); + let name = Instance::mono(scx, def_id).symbol_name(scx); + (name, export_level(scx, def_id)) + }) + .collect(); + + exports.insert(cnum, crate_exports); + } + + return ExportedSymbols { + exports: exports + }; + + fn export_level(scx: &SharedCrateContext, + sym_def_id: DefId) + -> SymbolExportLevel { + let attrs = scx.tcx().get_attrs(sym_def_id); + if attr::contains_extern_indicator(scx.sess().diagnostic(), &attrs) { + SymbolExportLevel::C + } else { + SymbolExportLevel::Rust + } + } + } + + pub fn exported_symbols(&self, + cnum: CrateNum) + -> &[(String, SymbolExportLevel)] { + match self.exports.get(&cnum) { + Some(exports) => &exports[..], + None => &[] + } + } + + pub fn for_each_exported_symbol(&self, + cnum: CrateNum, + export_threshold: SymbolExportLevel, + mut f: F) + where F: FnMut(&str, SymbolExportLevel) + { + for &(ref name, export_level) in self.exported_symbols(cnum) { + if is_below_threshold(export_level, export_threshold) { + f(&name[..], export_level) + } + } + } +} + +pub fn crate_export_threshold(crate_type: config::CrateType) + -> SymbolExportLevel { + match crate_type { + config::CrateTypeExecutable | + config::CrateTypeStaticlib | + config::CrateTypeCdylib => SymbolExportLevel::C, + config::CrateTypeProcMacro | + config::CrateTypeRlib | + config::CrateTypeMetadata | + config::CrateTypeDylib => SymbolExportLevel::Rust, + } +} + +pub fn crates_export_threshold(crate_types: &[config::CrateType]) + -> SymbolExportLevel { + if crate_types.iter().any(|&crate_type| { + crate_export_threshold(crate_type) == SymbolExportLevel::Rust + }) { + SymbolExportLevel::Rust + } else { + SymbolExportLevel::C + } +} + +pub fn is_below_threshold(level: SymbolExportLevel, + threshold: SymbolExportLevel) + -> bool { + if threshold == SymbolExportLevel::Rust { + // We export everything from Rust dylibs + true + } else { + level == SymbolExportLevel::C + } +} + +fn symbol_for_def_id<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, + def_id: DefId, + symbol_map: &SymbolMap<'tcx>) + -> String { + // Just try to look things up in the symbol map. If nothing's there, we + // recompute. + if let Some(node_id) = scx.tcx().map.as_local_node_id(def_id) { + if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) { + return sym.to_owned(); + } + } + + let instance = Instance::mono(scx, def_id); + + symbol_map.get(TransItem::Fn(instance)) + .map(str::to_owned) + .unwrap_or_else(|| instance.symbol_name(scx)) +} diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 84bba64dd70b2..ffab0bde7abde 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -10,6 +10,7 @@ use back::lto; use back::link::{get_linker, remove}; +use back::symbol_export::ExportedSymbols; use rustc_incremental::{save_trans_partition, in_incr_comp_dir}; use session::config::{OutputFilenames, OutputTypes, Passes, SomePasses, AllPasses}; use session::Session; @@ -328,7 +329,7 @@ impl ModuleConfig { struct CodegenContext<'a> { // Extra resources used for LTO: (sess, reachable). This will be `None` // when running in a worker thread. - lto_ctxt: Option<(&'a Session, &'a [String])>, + lto_ctxt: Option<(&'a Session, &'a ExportedSymbols)>, // Handler to use for diagnostics produced during codegen. handler: &'a Handler, // LLVM passes added by plugins. @@ -343,7 +344,9 @@ struct CodegenContext<'a> { } impl<'a> CodegenContext<'a> { - fn new_with_session(sess: &'a Session, exported_symbols: &'a [String]) -> CodegenContext<'a> { + fn new_with_session(sess: &'a Session, + exported_symbols: &'a ExportedSymbols) + -> CodegenContext<'a> { CodegenContext { lto_ctxt: Some((sess, exported_symbols)), handler: sess.diagnostic(), @@ -997,7 +1000,7 @@ fn execute_work_item(cgcx: &CodegenContext, } fn run_work_singlethreaded(sess: &Session, - exported_symbols: &[String], + exported_symbols: &ExportedSymbols, work_items: Vec) { let cgcx = CodegenContext::new_with_session(sess, exported_symbols); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 74e6a1dac80b1..a31b61e42c440 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -33,10 +33,10 @@ use super::ModuleTranslation; use assert_module_sources; use back::link; use back::linker::LinkerInfo; +use back::symbol_export::{self, ExportedSymbols}; use llvm::{Linkage, ValueRef, Vector, get_param}; use llvm; -use rustc::hir::def::Def; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; use rustc::ty::subst::Substs; use rustc::traits; @@ -84,7 +84,6 @@ use util::nodemap::{NodeSet, FxHashMap, FxHashSet}; use arena::TypedArena; use libc::c_uint; use std::ffi::{CStr, CString}; -use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::ptr; use std::rc::Rc; @@ -1313,16 +1312,23 @@ fn write_metadata(cx: &SharedCrateContext, fn internalize_symbols<'a, 'tcx>(sess: &Session, ccxs: &CrateContextList<'a, 'tcx>, symbol_map: &SymbolMap<'tcx>, - exported_symbols: &FxHashSet<&str>) { + exported_symbols: &ExportedSymbols) { + let export_threshold = + symbol_export::crates_export_threshold(&sess.crate_types.borrow()[..]); + + let exported_symbols = exported_symbols + .exported_symbols(LOCAL_CRATE) + .iter() + .filter(|&&(_, export_level)| { + symbol_export::is_below_threshold(export_level, export_threshold) + }) + .map(|&(ref name, _)| &name[..]) + .collect::>(); + let scx = ccxs.shared(); let tcx = scx.tcx(); - // In incr. comp. mode, we can't necessarily see all refs since we - // don't generate LLVM IR for reused modules, so skip this - // step. Later we should get smarter. - if sess.opts.debugging_opts.incremental.is_some() { - return; - } + let incr_comp = sess.opts.debugging_opts.incremental.is_some(); // 'unsafe' because we are holding on to CStr's from the LLVM module within // this block. @@ -1330,34 +1336,43 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, let mut referenced_somewhere = FxHashSet(); // Collect all symbols that need to stay externally visible because they - // are referenced via a declaration in some other codegen unit. - for ccx in ccxs.iter_need_trans() { - for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { - let linkage = llvm::LLVMRustGetLinkage(val); - // We only care about external declarations (not definitions) - // and available_externally definitions. - let is_available_externally = linkage == llvm::Linkage::AvailableExternallyLinkage; - let is_decl = llvm::LLVMIsDeclaration(val) != 0; - - if is_decl || is_available_externally { - let symbol_name = CStr::from_ptr(llvm::LLVMGetValueName(val)); - referenced_somewhere.insert(symbol_name); + // are referenced via a declaration in some other codegen unit. In + // incremental compilation, we don't need to collect. See below for more + // information. + if !incr_comp { + for ccx in ccxs.iter_need_trans() { + for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { + let linkage = llvm::LLVMRustGetLinkage(val); + // We only care about external declarations (not definitions) + // and available_externally definitions. + let is_available_externally = + linkage == llvm::Linkage::AvailableExternallyLinkage; + let is_decl = llvm::LLVMIsDeclaration(val) == llvm::True; + + if is_decl || is_available_externally { + let symbol_name = CStr::from_ptr(llvm::LLVMGetValueName(val)); + referenced_somewhere.insert(symbol_name); + } } } } // Also collect all symbols for which we cannot adjust linkage, because - // it is fixed by some directive in the source code (e.g. #[no_mangle]). - let linkage_fixed_explicitly: FxHashSet<_> = scx - .translation_items() - .borrow() - .iter() - .cloned() - .filter(|trans_item|{ - trans_item.explicit_linkage(tcx).is_some() - }) - .map(|trans_item| symbol_map.get_or_compute(scx, trans_item)) - .collect(); + // it is fixed by some directive in the source code. + let (locally_defined_symbols, linkage_fixed_explicitly) = { + let mut locally_defined_symbols = FxHashSet(); + let mut linkage_fixed_explicitly = FxHashSet(); + + for trans_item in scx.translation_items().borrow().iter() { + let symbol_name = symbol_map.get_or_compute(scx, *trans_item); + if trans_item.explicit_linkage(tcx).is_some() { + linkage_fixed_explicitly.insert(symbol_name.clone()); + } + locally_defined_symbols.insert(symbol_name); + } + + (locally_defined_symbols, linkage_fixed_explicitly) + }; // Examine each external definition. If the definition is not used in // any other compilation unit, and is not reachable from other crates, @@ -1369,23 +1384,46 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, let is_externally_visible = (linkage == llvm::Linkage::ExternalLinkage) || (linkage == llvm::Linkage::LinkOnceODRLinkage) || (linkage == llvm::Linkage::WeakODRLinkage); - let is_definition = llvm::LLVMIsDeclaration(val) == 0; - - // If this is a definition (as opposed to just a declaration) - // and externally visible, check if we can internalize it - if is_definition && is_externally_visible { - let name_cstr = CStr::from_ptr(llvm::LLVMGetValueName(val)); - let name_str = name_cstr.to_str().unwrap(); - let name_cow = Cow::Borrowed(name_str); - - let is_referenced_somewhere = referenced_somewhere.contains(&name_cstr); - let is_reachable = exported_symbols.contains(&name_str); - let has_fixed_linkage = linkage_fixed_explicitly.contains(&name_cow); - - if !is_referenced_somewhere && !is_reachable && !has_fixed_linkage { - llvm::LLVMRustSetLinkage(val, llvm::Linkage::InternalLinkage); - llvm::LLVMSetDLLStorageClass(val, - llvm::DLLStorageClass::Default); + + if !is_externally_visible { + // This symbol is not visible outside of its codegen unit, + // so there is nothing to do for it. + continue; + } + + let name_cstr = CStr::from_ptr(llvm::LLVMGetValueName(val)); + let name_str = name_cstr.to_str().unwrap(); + + if exported_symbols.contains(&name_str) { + // This symbol is explicitly exported, so we can't + // mark it as internal or hidden. + continue; + } + + let is_declaration = llvm::LLVMIsDeclaration(val) == llvm::True; + + if is_declaration { + if locally_defined_symbols.contains(name_str) { + // Only mark declarations from the current crate as hidden. + // Otherwise we would mark things as hidden that are + // imported from other crates or native libraries. + llvm::LLVMRustSetVisibility(val, llvm::Visibility::Hidden); + } + } else { + let has_fixed_linkage = linkage_fixed_explicitly.contains(name_str); + + if !has_fixed_linkage { + // In incremental compilation mode, we can't be sure that + // we saw all references because we don't know what's in + // cached compilation units, so we always assume that the + // given item has been referenced. + if incr_comp || referenced_somewhere.contains(&name_cstr) { + llvm::LLVMRustSetVisibility(val, llvm::Visibility::Hidden); + } else { + llvm::LLVMRustSetLinkage(val, llvm::Linkage::InternalLinkage); + } + + llvm::LLVMSetDLLStorageClass(val, llvm::DLLStorageClass::Default); llvm::UnsetComdat(val); } } @@ -1602,13 +1640,13 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Skip crate items and just output metadata in -Z no-trans mode. if tcx.sess.opts.debugging_opts.no_trans || tcx.sess.crate_types.borrow().iter().all(|ct| ct == &config::CrateTypeMetadata) { - let linker_info = LinkerInfo::new(&shared_ccx, &[]); + let linker_info = LinkerInfo::new(&shared_ccx, &ExportedSymbols::empty()); return CrateTranslation { modules: modules, metadata_module: metadata_module, link: link_meta, metadata: metadata, - exported_symbols: vec![], + exported_symbols: ExportedSymbols::empty(), no_builtins: no_builtins, linker_info: linker_info, windows_subsystem: None, @@ -1688,56 +1726,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let sess = shared_ccx.sess(); - let mut exported_symbols = shared_ccx.exported_symbols().iter().map(|&id| { - let def_id = shared_ccx.tcx().map.local_def_id(id); - symbol_for_def_id(def_id, &shared_ccx, &symbol_map) - }).collect::>(); - - if sess.entry_fn.borrow().is_some() { - exported_symbols.push("main".to_string()); - } - - if sess.crate_types.borrow().contains(&config::CrateTypeDylib) { - exported_symbols.push(shared_ccx.metadata_symbol_name()); - } - // For the purposes of LTO or when creating a cdylib, we add to the - // reachable set all of the upstream reachable extern fns. These functions - // are all part of the public ABI of the final product, so we need to - // preserve them. - // - // Note that this happens even if LTO isn't requested or we're not creating - // a cdylib. In those cases, though, we're not even reading the - // `exported_symbols` list later on so it should be ok. - for cnum in sess.cstore.crates() { - let syms = sess.cstore.exported_symbols(cnum); - exported_symbols.extend(syms.into_iter().filter(|&def_id| { - let applicable = match sess.cstore.describe_def(def_id) { - Some(Def::Static(..)) => true, - Some(Def::Fn(_)) => { - shared_ccx.tcx().item_generics(def_id).types.is_empty() - } - _ => false - }; - - if applicable { - let attrs = shared_ccx.tcx().get_attrs(def_id); - attr::contains_extern_indicator(sess.diagnostic(), &attrs) - } else { - false - } - }).map(|did| { - symbol_for_def_id(did, &shared_ccx, &symbol_map) - })); - } + let exported_symbols = ExportedSymbols::compute_from(&shared_ccx, + &symbol_map); + // Now that we have all symbols that are exported from the CGUs of this + // crate, we can run the `internalize_symbols` pass. time(shared_ccx.sess().time_passes(), "internalize symbols", || { internalize_symbols(sess, &crate_context_list, &symbol_map, - &exported_symbols.iter() - .map(|s| &s[..]) - .collect()) + &exported_symbols); }); if tcx.sess.opts.debugging_opts.print_type_sizes { @@ -2107,22 +2106,3 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a (codegen_units, symbol_map) } - -fn symbol_for_def_id<'a, 'tcx>(def_id: DefId, - scx: &SharedCrateContext<'a, 'tcx>, - symbol_map: &SymbolMap<'tcx>) - -> String { - // Just try to look things up in the symbol map. If nothing's there, we - // recompute. - if let Some(node_id) = scx.tcx().map.as_local_node_id(def_id) { - if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) { - return sym.to_owned(); - } - } - - let instance = Instance::mono(scx, def_id); - - symbol_map.get(TransItem::Fn(instance)) - .map(str::to_owned) - .unwrap_or_else(|| instance.symbol_name(scx)) -} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 8a7ab16ee2b01..e2da635b1592a 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -78,6 +78,7 @@ pub mod back { pub mod linker; pub mod link; pub mod lto; + pub mod symbol_export; pub mod symbol_names; pub mod write; pub mod msvc; @@ -169,7 +170,7 @@ pub struct CrateTranslation { pub metadata_module: ModuleTranslation, pub link: middle::cstore::LinkMeta, pub metadata: Vec, - pub exported_symbols: Vec, + pub exported_symbols: back::symbol_export::ExportedSymbols, pub no_builtins: bool, pub windows_subsystem: Option, pub linker_info: back::linker::LinkerInfo diff --git a/src/test/run-make/sepcomp-inlining/Makefile b/src/test/run-make/sepcomp-inlining/Makefile index ef43b0d97e417..720dfff2c0438 100644 --- a/src/test/run-make/sepcomp-inlining/Makefile +++ b/src/test/run-make/sepcomp-inlining/Makefile @@ -10,5 +10,5 @@ all: $(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3 [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*inlined)" -eq "0" ] [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ internal\ i32\ .*inlined)" -eq "2" ] - [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*normal)" -eq "1" ] - [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c declare\ i32\ .*normal)" -eq "2" ] + [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ hidden\ i32\ .*normal)" -eq "1" ] + [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c declare\ hidden\ i32\ .*normal)" -eq "2" ] From e48160f6e40352a7f72ab108e78754ef1f3f5da1 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 30 Nov 2016 13:16:53 -0500 Subject: [PATCH 4/9] Generate a version script for linkers on Linux. --- src/librustc_trans/back/linker.rs | 39 ++++++++++++++----------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 933813ac4d931..67c8d268a819c 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -253,46 +253,43 @@ impl<'a> Linker for GnuLinker<'a> { let mut arg = OsString::new(); let path = tmpdir.join("list"); - if self.sess.target.target.options.is_like_solaris { + if self.sess.target.target.options.is_like_osx { + // Write a plain, newline-separated list of symbols let res = (|| -> io::Result<()> { let mut f = BufWriter::new(File::create(&path)?); - writeln!(f, "{{\n global:")?; for sym in self.info.exports[&crate_type].iter() { - writeln!(f, " {};", sym)?; + writeln!(f, "_{}", sym)?; } - writeln!(f, "\n local:\n *;\n}};")?; Ok(()) })(); if let Err(e) = res { - self.sess.fatal(&format!("failed to write version script: {}", e)); + self.sess.fatal(&format!("failed to write lib.def file: {}", e)); } - - arg.push("-Wl,-M,"); - arg.push(&path); } else { - let prefix = if self.sess.target.target.options.is_like_osx { - "_" - } else { - "" - }; + // Write an LD version script let res = (|| -> io::Result<()> { let mut f = BufWriter::new(File::create(&path)?); + writeln!(f, "{{\n global:")?; for sym in self.info.exports[&crate_type].iter() { - writeln!(f, "{}{}", prefix, sym)?; + writeln!(f, " {};", sym)?; } + writeln!(f, "\n local:\n *;\n}};")?; Ok(()) })(); if let Err(e) = res { - self.sess.fatal(&format!("failed to write lib.def file: {}", e)); - } - if self.sess.target.target.options.is_like_osx { - arg.push("-Wl,-exported_symbols_list,"); - } else { - arg.push("-Wl,--retain-symbols-file="); + self.sess.fatal(&format!("failed to write version script: {}", e)); } - arg.push(&path); } + if self.sess.target.target.options.is_like_osx { + arg.push("-Wl,-exported_symbols_list,"); + } else if self.sess.target.target.options.is_like_solaris { + arg.push("-Wl,-M,"); + } else { + arg.push("-Wl,--version-script="); + } + + arg.push(&path); self.cmd.arg(arg); } From bfd4910fa2c7a1487d06c7c9cb764bc31e787f12 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 1 Dec 2016 14:57:46 -0500 Subject: [PATCH 5/9] Linking: Include export lists in debug output. --- src/librustc_trans/back/linker.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 67c8d268a819c..d59ee5d825d86 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -253,11 +253,14 @@ impl<'a> Linker for GnuLinker<'a> { let mut arg = OsString::new(); let path = tmpdir.join("list"); + debug!("EXPORTED SYMBOLS:"); + if self.sess.target.target.options.is_like_osx { // Write a plain, newline-separated list of symbols let res = (|| -> io::Result<()> { let mut f = BufWriter::new(File::create(&path)?); for sym in self.info.exports[&crate_type].iter() { + debug!(" _{}", sym); writeln!(f, "_{}", sym)?; } Ok(()) @@ -271,6 +274,7 @@ impl<'a> Linker for GnuLinker<'a> { let mut f = BufWriter::new(File::create(&path)?); writeln!(f, "{{\n global:")?; for sym in self.info.exports[&crate_type].iter() { + debug!(" {};", sym); writeln!(f, " {};", sym)?; } writeln!(f, "\n local:\n *;\n}};")?; From ea9f61353a77a704c9abf3fb1f8e19fdcecff6a9 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 1 Dec 2016 15:06:33 -0500 Subject: [PATCH 6/9] Add test case for symbol visibility in dylibs. --- src/test/run-make/symbol-visibility/Makefile | 26 +++++++++++++++++++ .../run-make/symbol-visibility/a_cdylib.rs | 22 ++++++++++++++++ .../symbol-visibility/a_rust_dylib.rs | 20 ++++++++++++++ .../symbol-visibility/an_executable.rs | 17 ++++++++++++ .../run-make/symbol-visibility/an_rlib.rs | 16 ++++++++++++ 5 files changed, 101 insertions(+) create mode 100644 src/test/run-make/symbol-visibility/Makefile create mode 100644 src/test/run-make/symbol-visibility/a_cdylib.rs create mode 100644 src/test/run-make/symbol-visibility/a_rust_dylib.rs create mode 100644 src/test/run-make/symbol-visibility/an_executable.rs create mode 100644 src/test/run-make/symbol-visibility/an_rlib.rs diff --git a/src/test/run-make/symbol-visibility/Makefile b/src/test/run-make/symbol-visibility/Makefile new file mode 100644 index 0000000000000..d6c31d148b304 --- /dev/null +++ b/src/test/run-make/symbol-visibility/Makefile @@ -0,0 +1,26 @@ +include ../tools.mk + +all: + $(RUSTC) an_rlib.rs + $(RUSTC) a_cdylib.rs + $(RUSTC) a_rust_dylib.rs + $(RUSTC) an_executable.rs + + # Check that a cdylib exports its public #[no_mangle] functions + [ "$$(nm -D $(TMPDIR)/liba_cdylib.so | grep -c public_c_function_from_cdylib)" -eq "1" ] + # Check that a cdylib exports the public #[no_mangle] functions of dependencies + [ "$$(nm -D $(TMPDIR)/liba_cdylib.so | grep -c public_c_function_from_rlib)" -eq "1" ] + # Check that a cdylib DOES NOT export any public Rust functions + [ "$$(nm -D $(TMPDIR)/liba_cdylib.so | grep -c _ZN.*h.*E)" -eq "0" ] + + # Check that a Rust dylib exports its monomorphic functions + [ "$$(nm -D $(TMPDIR)/liba_rust_dylib.so | grep -c public_c_function_from_rust_dylib)" -eq "1" ] + [ "$$(nm -D $(TMPDIR)/liba_rust_dylib.so | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ] + + # Check that a Rust dylib exports the monomorphic functions from its dependencies + [ "$$(nm -D $(TMPDIR)/liba_rust_dylib.so | grep -c public_c_function_from_rlib)" -eq "1" ] + [ "$$(nm -D $(TMPDIR)/liba_rust_dylib.so | grep -c public_rust_function_from_rlib)" -eq "1" ] + + # Check that an executable does not export any dynamic symbols + [ "$$(nm -D $(TMPDIR)/an_executable | grep -c public_c_function_from_rlib)" -eq "0" ] + [ "$$(nm -D $(TMPDIR)/an_executable | grep -c public_rust_function_from_exe)" -eq "0" ] diff --git a/src/test/run-make/symbol-visibility/a_cdylib.rs b/src/test/run-make/symbol-visibility/a_cdylib.rs new file mode 100644 index 0000000000000..9a70542c06ca7 --- /dev/null +++ b/src/test/run-make/symbol-visibility/a_cdylib.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type="cdylib"] + +extern crate an_rlib; + +// This should not be exported +pub fn public_rust_function_from_cdylib() {} + +// This should be exported +#[no_mangle] +pub extern "C" fn public_c_function_from_cdylib() { + an_rlib::public_c_function_from_rlib(); +} diff --git a/src/test/run-make/symbol-visibility/a_rust_dylib.rs b/src/test/run-make/symbol-visibility/a_rust_dylib.rs new file mode 100644 index 0000000000000..b826211c9a42a --- /dev/null +++ b/src/test/run-make/symbol-visibility/a_rust_dylib.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type="dylib"] + +extern crate an_rlib; + +// This should be exported +pub fn public_rust_function_from_rust_dylib() {} + +// This should be exported +#[no_mangle] +pub extern "C" fn public_c_function_from_rust_dylib() {} diff --git a/src/test/run-make/symbol-visibility/an_executable.rs b/src/test/run-make/symbol-visibility/an_executable.rs new file mode 100644 index 0000000000000..73059c5e374f2 --- /dev/null +++ b/src/test/run-make/symbol-visibility/an_executable.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type="bin"] + +extern crate an_rlib; + +pub fn public_rust_function_from_exe() {} + +fn main() {} diff --git a/src/test/run-make/symbol-visibility/an_rlib.rs b/src/test/run-make/symbol-visibility/an_rlib.rs new file mode 100644 index 0000000000000..cd19500d14021 --- /dev/null +++ b/src/test/run-make/symbol-visibility/an_rlib.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type="rlib"] + +pub fn public_rust_function_from_rlib() {} + +#[no_mangle] +pub extern "C" fn public_c_function_from_rlib() {} From 93da4f81bfb879eea9236d5fd16734a68836c97c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 2 Dec 2016 18:00:41 -0500 Subject: [PATCH 7/9] Export the plugin registrar from proc-macro crates (and not much else) --- src/librustc_trans/back/symbol_export.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 2290cb0f48785..f99f543d9b7df 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -60,6 +60,14 @@ impl ExportedSymbols { local_crate.push(("main".to_string(), SymbolExportLevel::C)); } + if let Some(id) = scx.sess().derive_registrar_fn.get() { + let svh = &scx.link_meta().crate_hash; + let def_id = scx.tcx().map.local_def_id(id); + let idx = def_id.index; + let registrar = scx.sess().generate_derive_registrar_symbol(svh, idx); + local_crate.push((registrar, SymbolExportLevel::C)); + } + if scx.sess().crate_types.borrow().contains(&config::CrateTypeDylib) { local_crate.push((scx.metadata_symbol_name(), SymbolExportLevel::Rust)); @@ -135,8 +143,8 @@ pub fn crate_export_threshold(crate_type: config::CrateType) match crate_type { config::CrateTypeExecutable | config::CrateTypeStaticlib | - config::CrateTypeCdylib => SymbolExportLevel::C, config::CrateTypeProcMacro | + config::CrateTypeCdylib => SymbolExportLevel::C, config::CrateTypeRlib | config::CrateTypeMetadata | config::CrateTypeDylib => SymbolExportLevel::Rust, From 3548c8f56011ade169453231389bade8ca8a6bb1 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 2 Dec 2016 18:02:14 -0500 Subject: [PATCH 8/9] Mention cdylibs in LTO error message. --- src/librustc_trans/back/lto.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 1960b36827874..f137bfff034d0 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -56,7 +56,7 @@ pub fn run(sess: &session::Session, // Make sure we actually can run LTO for crate_type in sess.crate_types.borrow().iter() { if !crate_type_allows_lto(*crate_type) { - sess.fatal("lto can only be run for executables and \ + sess.fatal("lto can only be run for executables, cdylibs and \ static library outputs"); } } From 8ecdc4ee3bde4a7986bafe4010f5358d89a4eeab Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 2 Dec 2016 18:02:46 -0500 Subject: [PATCH 9/9] Make symbol-visibility test case work on all platforms. --- src/test/run-make/symbol-visibility/Makefile | 42 +++++++++++++++----- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/src/test/run-make/symbol-visibility/Makefile b/src/test/run-make/symbol-visibility/Makefile index d6c31d148b304..988c9473f6a7e 100644 --- a/src/test/run-make/symbol-visibility/Makefile +++ b/src/test/run-make/symbol-visibility/Makefile @@ -1,5 +1,27 @@ include ../tools.mk +ifdef IS_WINDOWS +# Do nothing on MSVC. +# On MINGW the --version-script, --dynamic-list, and --retain-symbol args don't +# seem to work reliably. +all: + exit 0 +else + +NM=nm -D +DYLIB_EXT=so +CDYLIB_NAME=liba_cdylib.so +RDYLIB_NAME=liba_rust_dylib.so +EXE_NAME=an_executable + +ifeq ($(UNAME),Darwin) +NM=nm -gU +DYLIB_EXT=dylib +CDYLIB_NAME=liba_cdylib.dylib +RDYLIB_NAME=liba_rust_dylib.dylib +EXE_NAME=an_executable +endif + all: $(RUSTC) an_rlib.rs $(RUSTC) a_cdylib.rs @@ -7,20 +29,22 @@ all: $(RUSTC) an_executable.rs # Check that a cdylib exports its public #[no_mangle] functions - [ "$$(nm -D $(TMPDIR)/liba_cdylib.so | grep -c public_c_function_from_cdylib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_cdylib)" -eq "1" ] # Check that a cdylib exports the public #[no_mangle] functions of dependencies - [ "$$(nm -D $(TMPDIR)/liba_cdylib.so | grep -c public_c_function_from_rlib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] # Check that a cdylib DOES NOT export any public Rust functions - [ "$$(nm -D $(TMPDIR)/liba_cdylib.so | grep -c _ZN.*h.*E)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ] # Check that a Rust dylib exports its monomorphic functions - [ "$$(nm -D $(TMPDIR)/liba_rust_dylib.so | grep -c public_c_function_from_rust_dylib)" -eq "1" ] - [ "$$(nm -D $(TMPDIR)/liba_rust_dylib.so | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ] # Check that a Rust dylib exports the monomorphic functions from its dependencies - [ "$$(nm -D $(TMPDIR)/liba_rust_dylib.so | grep -c public_c_function_from_rlib)" -eq "1" ] - [ "$$(nm -D $(TMPDIR)/liba_rust_dylib.so | grep -c public_rust_function_from_rlib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ] # Check that an executable does not export any dynamic symbols - [ "$$(nm -D $(TMPDIR)/an_executable | grep -c public_c_function_from_rlib)" -eq "0" ] - [ "$$(nm -D $(TMPDIR)/an_executable | grep -c public_rust_function_from_exe)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_rust_function_from_exe)" -eq "0" ] + +endif