|
29 | 29 |
|
30 | 30 | #![cfg_attr(stage0, feature(const_fn))] |
31 | 31 |
|
| 32 | +#[macro_use] |
| 33 | +extern crate log; |
32 | 34 | extern crate rustc; |
| 35 | +extern crate rustc_incremental; |
33 | 36 | extern crate syntax; |
34 | 37 | extern crate syntax_pos; |
35 | 38 |
|
| 39 | +use rustc::ty::TyCtxt; |
| 40 | +use rustc::hir; |
| 41 | +use rustc::hir::map as hir_map; |
| 42 | +use rustc::util::nodemap::NodeSet; |
| 43 | + |
| 44 | +use syntax::attr; |
| 45 | + |
36 | 46 | pub mod link; |
| 47 | + |
| 48 | +/// The context provided lists a set of reachable ids as calculated by |
| 49 | +/// middle::reachable, but this contains far more ids and symbols than we're |
| 50 | +/// actually exposing from the object file. This function will filter the set in |
| 51 | +/// the context to the set of ids which correspond to symbols that are exposed |
| 52 | +/// from the object file being generated. |
| 53 | +/// |
| 54 | +/// This list is later used by linkers to determine the set of symbols needed to |
| 55 | +/// be exposed from a dynamic library and it's also encoded into the metadata. |
| 56 | +pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet { |
| 57 | + reachable.iter().cloned().filter(|&id| { |
| 58 | + // Next, we want to ignore some FFI functions that are not exposed from |
| 59 | + // this crate. Reachable FFI functions can be lumped into two |
| 60 | + // categories: |
| 61 | + // |
| 62 | + // 1. Those that are included statically via a static library |
| 63 | + // 2. Those included otherwise (e.g. dynamically or via a framework) |
| 64 | + // |
| 65 | + // Although our LLVM module is not literally emitting code for the |
| 66 | + // statically included symbols, it's an export of our library which |
| 67 | + // needs to be passed on to the linker and encoded in the metadata. |
| 68 | + // |
| 69 | + // As a result, if this id is an FFI item (foreign item) then we only |
| 70 | + // let it through if it's included statically. |
| 71 | + match tcx.hir.get(id) { |
| 72 | + hir_map::NodeForeignItem(..) => { |
| 73 | + let def_id = tcx.hir.local_def_id(id); |
| 74 | + tcx.sess.cstore.is_statically_included_foreign_item(def_id) |
| 75 | + } |
| 76 | + |
| 77 | + // Only consider nodes that actually have exported symbols. |
| 78 | + hir_map::NodeItem(&hir::Item { |
| 79 | + node: hir::ItemStatic(..), .. }) | |
| 80 | + hir_map::NodeItem(&hir::Item { |
| 81 | + node: hir::ItemFn(..), .. }) | |
| 82 | + hir_map::NodeImplItem(&hir::ImplItem { |
| 83 | + node: hir::ImplItemKind::Method(..), .. }) => { |
| 84 | + let def_id = tcx.hir.local_def_id(id); |
| 85 | + let generics = tcx.generics_of(def_id); |
| 86 | + let attributes = tcx.get_attrs(def_id); |
| 87 | + (generics.parent_types == 0 && generics.types.is_empty()) && |
| 88 | + // Functions marked with #[inline] are only ever translated |
| 89 | + // with "internal" linkage and are never exported. |
| 90 | + !attr::requests_inline(&attributes) |
| 91 | + } |
| 92 | + |
| 93 | + _ => false |
| 94 | + } |
| 95 | + }).collect() |
| 96 | +} |
0 commit comments