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:
use metadata::decoder;
use metadata::loader;
use metadata::loader::CratePaths;
+use util::nodemap::FnvHashMap;
use std::cell::RefCell;
use std::path::PathBuf;
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> {
CrateReader {
sess: sess,
next_crate_num: sess.cstore.next_crate_num(),
+ foreign_item_map: FnvHashMap(),
}
}
_ => 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> {
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) {
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));
}
}
}
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;
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>,
}
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()),
}
}
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
-> 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 {