diff options
| -rw-r--r-- | src/doc/reference.md | 10 | ||||
| -rw-r--r-- | src/librustc/metadata/creader.rs | 150 | ||||
| -rw-r--r-- | src/librustc/metadata/cstore.rs | 15 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 5 |
4 files changed, 103 insertions, 77 deletions
diff --git a/src/doc/reference.md b/src/doc/reference.md index e905ed917d7..4d5564d9faf 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1924,10 +1924,16 @@ On an `extern` block, the following attributes are interpreted: name and type. This is feature gated and the exact behavior is implementation-defined (due to variety of linker invocation syntax). - `link` - indicate that a native library should be linked to for the - declarations in this block to be linked correctly. `link` supports an optional `kind` - key with three possible values: `dylib`, `static`, and `framework`. See [external blocks](#external-blocks) for more about external blocks. Two + declarations in this block to be linked correctly. `link` supports an optional + `kind` key with three possible values: `dylib`, `static`, and `framework`. See + [external blocks](#external-blocks) for more about external blocks. Two examples: `#[link(name = "readline")]` and `#[link(name = "CoreFoundation", kind = "framework")]`. +- `linked_from` - indicates what native library this block of FFI items is + coming from. This attribute is of the form `#[linked_from = "foo"]` where + `foo` is the name of a library in either `#[link]` or a `-l` flag. This + attribute is currently required to export symbols from a Rust dynamic library + on Windows, and it is feature gated behind the `linked_from` feature. On declarations inside an `extern` block, the following attributes are interpreted: diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index bbb2d4fade1..3226a99c6b3 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -20,6 +20,7 @@ use metadata::cstore::{CStore, CrateSource, MetadataBlob}; use metadata::decoder; use metadata::loader; use metadata::loader::CratePaths; +use util::nodemap::FnvHashMap; use std::cell::RefCell; use std::path::PathBuf; @@ -47,6 +48,7 @@ pub struct LocalCrateReader<'a, 'b:'a> { pub struct CrateReader<'a> { sess: &'a Session, next_crate_num: ast::CrateNum, + foreign_item_map: FnvHashMap<String, Vec<ast::NodeId>>, } impl<'a, 'b, 'v> visit::Visitor<'v> for LocalCrateReader<'a, 'b> { @@ -157,6 +159,7 @@ impl<'a> CrateReader<'a> { CrateReader { sess: sess, next_crate_num: sess.cstore.next_crate_num(), + foreign_item_map: FnvHashMap(), } } @@ -490,6 +493,20 @@ impl<'a> CrateReader<'a> { _ => None, } } + + fn register_statically_included_foreign_items(&mut self) { + let libs = self.sess.cstore.get_used_libraries(); + for (lib, list) in self.foreign_item_map.iter() { + let is_static = libs.borrow().iter().any(|&(ref name, kind)| { + lib == name && kind == cstore::NativeStatic + }); + if is_static { + for id in list { + self.sess.cstore.add_statically_included_foreign_item(*id); + } + } + } + } } impl<'a, 'b> LocalCrateReader<'a, 'b> { @@ -515,6 +532,7 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> { for &(ref name, kind) in &self.sess.opts.libs { register_native_lib(self.sess, None, name.clone(), kind); } + self.creader.register_statically_included_foreign_items(); } fn process_crate(&self, c: &ast::Crate) { @@ -541,87 +559,73 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> { None, i.span, PathKind::Crate); - self.ast_map.with_path(i.id, |path| - cmeta.update_local_path(path)); + self.ast_map.with_path(i.id, |path| { + cmeta.update_local_path(path) + }); self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum); } None => () } } - ast::ItemForeignMod(ref fm) => { - if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic { - return; - } + ast::ItemForeignMod(ref fm) => self.process_foreign_mod(i, fm), + _ => { } + } + } - // First, add all of the custom link_args attributes - let link_args = i.attrs.iter() - .filter_map(|at| if at.name() == "link_args" { - Some(at) - } else { - None - }) - .collect::<Vec<&ast::Attribute>>(); - for m in &link_args { - match m.value_str() { - Some(linkarg) => self.sess.cstore.add_used_link_args(&linkarg), - None => { /* fallthrough */ } - } - } + fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod) { + if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic { + return; + } - // Next, process all of the #[link(..)]-style arguments - let link_args = i.attrs.iter() - .filter_map(|at| if at.name() == "link" { - Some(at) - } else { - None - }) - .collect::<Vec<&ast::Attribute>>(); - for m in &link_args { - match m.meta_item_list() { - Some(items) => { - let kind = items.iter().find(|k| { - k.name() == "kind" - }).and_then(|a| a.value_str()); - let kind = match kind { - Some(k) => { - if k == "static" { - cstore::NativeStatic - } else if self.sess.target.target.options.is_like_osx - && k == "framework" { - cstore::NativeFramework - } else if k == "framework" { - cstore::NativeFramework - } else if k == "dylib" { - cstore::NativeUnknown - } else { - self.sess.span_err(m.span, - &format!("unknown kind: `{}`", - k)); - cstore::NativeUnknown - } - } - None => cstore::NativeUnknown - }; - let n = items.iter().find(|n| { - n.name() == "name" - }).and_then(|a| a.value_str()); - let n = match n { - Some(n) => n, - None => { - self.sess.span_err(m.span, - "#[link(...)] specified without \ - `name = \"foo\"`"); - InternedString::new("foo") - } - }; - register_native_lib(self.sess, Some(m.span), - n.to_string(), kind); - } - None => {} - } - } + // First, add all of the custom #[link_args] attributes + for m in i.attrs.iter().filter(|a| a.check_name("link_args")) { + if let Some(linkarg) = m.value_str() { + self.sess.cstore.add_used_link_args(&linkarg); } - _ => { } + } + + // Next, process all of the #[link(..)]-style arguments + for m in i.attrs.iter().filter(|a| a.check_name("link")) { + let items = match m.meta_item_list() { + Some(item) => item, + None => continue, + }; + let kind = items.iter().find(|k| { + k.check_name("kind") + }).and_then(|a| a.value_str()); + let kind = match kind.as_ref().map(|s| &s[..]) { + Some("static") => cstore::NativeStatic, + Some("dylib") => cstore::NativeUnknown, + Some("framework") => cstore::NativeFramework, + Some(k) => { + self.sess.span_err(m.span, &format!("unknown kind: `{}`", k)); + cstore::NativeUnknown + } + None => cstore::NativeUnknown + }; + let n = items.iter().find(|n| { + n.check_name("name") + }).and_then(|a| a.value_str()); + let n = match n { + Some(n) => n, + None => { + self.sess.span_err(m.span, "#[link(...)] specified without \ + `name = \"foo\"`"); + InternedString::new("foo") + } + }; + register_native_lib(self.sess, Some(m.span), n.to_string(), kind); + } + + // Finally, process the #[linked_from = "..."] attribute + for m in i.attrs.iter().filter(|a| a.check_name("linked_from")) { + let lib_name = match m.value_str() { + Some(name) => name, + None => continue, + }; + let list = self.creader.foreign_item_map.entry(lib_name.to_string()) + .or_insert(Vec::new()); + list.extend(fm.items.iter().map(|it| it.id)); } } } diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index 19d494824cf..ae5e797a029 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -20,7 +20,7 @@ pub use self::NativeLibraryKind::*; use back::svh::Svh; use metadata::{creader, decoder, loader}; use session::search_paths::PathKind; -use util::nodemap::{FnvHashMap, NodeMap}; +use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; use std::cell::{RefCell, Ref}; use std::rc::Rc; @@ -97,6 +97,7 @@ pub struct CStore { used_crate_sources: RefCell<Vec<CrateSource>>, used_libraries: RefCell<Vec<(String, NativeLibraryKind)>>, used_link_args: RefCell<Vec<String>>, + statically_included_foreign_items: RefCell<NodeSet>, pub intr: Rc<IdentInterner>, } @@ -108,7 +109,8 @@ impl CStore { used_crate_sources: RefCell::new(Vec::new()), used_libraries: RefCell::new(Vec::new()), used_link_args: RefCell::new(Vec::new()), - intr: intr + intr: intr, + statically_included_foreign_items: RefCell::new(NodeSet()), } } @@ -167,6 +169,7 @@ impl CStore { self.used_crate_sources.borrow_mut().clear(); self.used_libraries.borrow_mut().clear(); self.used_link_args.borrow_mut().clear(); + self.statically_included_foreign_items.borrow_mut().clear(); } // This method is used when generating the command line to pass through to @@ -240,6 +243,14 @@ impl CStore { -> Option<ast::CrateNum> { self.extern_mod_crate_map.borrow().get(&emod_id).cloned() } + + pub fn add_statically_included_foreign_item(&self, id: ast::NodeId) { + self.statically_included_foreign_items.borrow_mut().insert(id); + } + + pub fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { + self.statically_included_foreign_items.borrow().contains(&id) + } } impl crate_metadata { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 60a5730a3da..87149ff81da 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -85,6 +85,7 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ ("on_unimplemented", "1.0.0", Active), ("simd_ffi", "1.0.0", Active), ("allocator", "1.0.0", Active), + ("linked_from", "1.3.0", Active), ("if_let", "1.0.0", Accepted), ("while_let", "1.0.0", Accepted), @@ -269,6 +270,10 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ "the `#[fundamental]` attribute \ is an experimental feature")), + ("linked_from", Gated("linked_from", + "the `#[linked_from]` attribute \ + is an experimental feature")), + // FIXME: #14408 whitelist docs since rustdoc looks at them ("doc", Whitelisted), |
