diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 496a3d4a49847..e674b6ea8363e 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -46,7 +46,7 @@ use rustc_back::target::Target; use hir; use rustc_back::PanicStrategy; -pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown}; +pub use self::NativeLibraryKind::*; // lonely orphan structs and enums looking for a better home @@ -122,6 +122,7 @@ pub enum LinkagePreference { #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub enum NativeLibraryKind { NativeStatic, // native static library (.a archive) + NativeStaticNobundle, // native static library, which doesn't get bundled into .rlibs NativeFramework, // OSX-specific NativeUnknown, // default way to specify a dynamic library } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 104c851e057e6..550f6eb12a7bd 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1473,12 +1473,17 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) (Some(name), "dylib") => (name, cstore::NativeUnknown), (Some(name), "framework") => (name, cstore::NativeFramework), (Some(name), "static") => (name, cstore::NativeStatic), + (Some(name), "static-nobundle") => (name, cstore::NativeStaticNobundle), (_, s) => { early_error(error_format, &format!("unknown library kind `{}`, expected \ one of dylib, framework, or static", s)); } }; + if kind == cstore::NativeStaticNobundle && !nightly_options::is_nightly_build() { + early_error(error_format, &format!("the library kind 'static-nobundle' is only \ + accepted on the nightly compiler")); + } let mut name_parts = name.splitn(2, ':'); let name = name_parts.next().unwrap(); let new_name = name_parts.next(); diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 8f7b9c24cbf8a..a228689363fc3 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -111,6 +111,13 @@ fn register_native_lib(sess: &Session, GateIssue::Language, "is feature gated"); } + if lib.kind == cstore::NativeStaticNobundle && !sess.features.borrow().static_nobundle { + feature_gate::emit_feature_err(&sess.parse_sess, + "static_nobundle", + span.unwrap(), + GateIssue::Language, + "kind=\"static-nobundle\" is feature gated"); + } cstore.add_used_library(lib); } @@ -678,6 +685,9 @@ impl<'a> CrateLoader<'a> { for id in self.get_foreign_items_of_kind(cstore::NativeStatic) { self.cstore.add_statically_included_foreign_item(id); } + for id in self.get_foreign_items_of_kind(cstore::NativeStaticNobundle) { + self.cstore.add_statically_included_foreign_item(id); + } } fn register_dllimport_foreign_items(&mut self) { @@ -917,6 +927,7 @@ impl<'a> CrateLoader<'a> { }).and_then(|a| a.value_str()).map(Symbol::as_str); let kind = match kind.as_ref().map(|s| &s[..]) { Some("static") => cstore::NativeStatic, + Some("static-nobundle") => cstore::NativeStaticNobundle, Some("dylib") => cstore::NativeUnknown, Some("framework") => cstore::NativeFramework, Some(k) => { diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 761041ad7198a..beba5faf3d034 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -32,7 +32,7 @@ use syntax::symbol::Symbol; use syntax_pos; pub use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind, LinkagePreference}; -pub use rustc::middle::cstore::{NativeStatic, NativeFramework, NativeUnknown}; +pub use rustc::middle::cstore::NativeLibraryKind::*; pub use rustc::middle::cstore::{CrateSource, LinkMeta, LibSource}; // A map from external crate numbers (as decoded from some crate file) to diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index defbb44448a9f..20842ea3fe54d 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -476,6 +476,7 @@ fn link_rlib<'a>(sess: &'a Session, for lib in sess.cstore.used_libraries() { match lib.kind { NativeLibraryKind::NativeStatic => {} + NativeLibraryKind::NativeStaticNobundle | NativeLibraryKind::NativeFramework | NativeLibraryKind::NativeUnknown => continue, } @@ -674,6 +675,7 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path, for lib in all_native_libs.iter().filter(|l| relevant_lib(sess, l)) { let name = match lib.kind { + NativeLibraryKind::NativeStaticNobundle | NativeLibraryKind::NativeUnknown => "library", NativeLibraryKind::NativeFramework => "framework", // These are included, no need to print them @@ -894,7 +896,7 @@ fn link_args(cmd: &mut Linker, // on other dylibs (e.g. other native deps). add_local_native_libraries(cmd, sess); add_upstream_rust_crates(cmd, sess, crate_type, tmpdir); - add_upstream_native_libraries(cmd, sess); + add_upstream_native_libraries(cmd, sess, crate_type); // # Telling the linker what we're doing @@ -985,6 +987,7 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) { match lib.kind { NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()), NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()), + NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&lib.name.as_str()), NativeLibraryKind::NativeStatic => bug!(), } } @@ -1210,7 +1213,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // generic function calls a native function, then the generic function must // be instantiated in the target crate, meaning that the native symbol must // also be resolved in the target crate. -fn add_upstream_native_libraries(cmd: &mut Linker, sess: &Session) { +fn add_upstream_native_libraries(cmd: &mut Linker, sess: &Session, crate_type: config::CrateType) { // Be sure to use a topological sorting of crates because there may be // interdependencies between native libraries. When passing -nodefaultlibs, // for example, almost all native libraries depend on libc, so we have to @@ -1220,6 +1223,9 @@ fn add_upstream_native_libraries(cmd: &mut Linker, sess: &Session) { // This passes RequireStatic, but the actual requirement doesn't matter, // we're just getting an ordering of crate numbers, we're not worried about // the paths. + let formats = sess.dependency_formats.borrow(); + let data = formats.get(&crate_type).unwrap(); + let crates = sess.cstore.used_crates(LinkagePreference::RequireStatic); for (cnum, _) in crates { for lib in sess.cstore.native_libraries(cnum) { @@ -1229,7 +1235,15 @@ fn add_upstream_native_libraries(cmd: &mut Linker, sess: &Session) { match lib.kind { NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()), NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()), - + NativeLibraryKind::NativeStaticNobundle => { + // Link "static-nobundle" native libs only if the crate they originate from + // is being linked statically to the current crate. If it's linked dynamically + // or is an rlib already included via some other dylib crate, the symbols from + // native libs will have already been included in that dylib. + if data[cnum.as_usize() - 1] == Linkage::Static { + cmd.link_staticlib(&lib.name.as_str()) + } + }, // ignore statically included native libraries here as we've // already included them when we included the rust library // previously diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index a147b598940a2..7f352f1da517d 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -450,6 +450,7 @@ impl<'a> Linker for MsvcLinker<'a> { writeln!(f, "LIBRARY")?; writeln!(f, "EXPORTS")?; for symbol in self.info.exports[&crate_type].iter() { + debug!(" _{}", symbol); writeln!(f, " {}", symbol)?; } Ok(()) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 924f51fd95251..cf2905e913108 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -322,6 +322,9 @@ declare_features! ( // Allows attributes on struct literal fields. (active, struct_field_attributes, "1.16.0", Some(38814)), + // Allows #[link(kind="static-nobundle"...] + (active, static_nobundle, "1.16.0", Some(37403)), + // `extern "msp430-interrupt" fn()` (active, abi_msp430_interrupt, "1.16.0", Some(38487)), ); diff --git a/src/test/compile-fail/feature-gate-static-nobundle.rs b/src/test/compile-fail/feature-gate-static-nobundle.rs new file mode 100644 index 0000000000000..bc0025c7c9581 --- /dev/null +++ b/src/test/compile-fail/feature-gate-static-nobundle.rs @@ -0,0 +1,13 @@ +// 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. + +#[link(name="foo", kind="static-nobundle")] +//~^ ERROR: kind="static-nobundle" is feature gated +extern {} diff --git a/src/test/run-make/static-nobundle/Makefile b/src/test/run-make/static-nobundle/Makefile new file mode 100644 index 0000000000000..3eac12f5cc9fd --- /dev/null +++ b/src/test/run-make/static-nobundle/Makefile @@ -0,0 +1,21 @@ +-include ../tools.mk + +# aaa is a native static library +# bbb is a rlib +# ccc is a dylib +# ddd is an executable + +all: $(call NATIVE_STATICLIB,aaa) + $(RUSTC) bbb.rs --crate-type=rlib + + # Check that bbb does NOT contain the definition of `native_func` + nm $(TMPDIR)/libbbb.rlib | (! grep "T _*native_func") + nm $(TMPDIR)/libbbb.rlib | grep "U _*native_func" + + # Check that aaa gets linked (either as `-l aaa` or `aaa.lib`) when building ccc. + $(RUSTC) ccc.rs -C prefer-dynamic --crate-type=dylib -Z print-link-args | grep -e "-l[\" ]*aaa" -e "aaa.lib" + + # Check that aaa does NOT get linked when building ddd. + $(RUSTC) ddd.rs -Z print-link-args | (! grep -e "-l[\" ]*aaa" -e "aaa.lib") + + $(call RUN,ddd) diff --git a/src/test/run-make/static-nobundle/aaa.c b/src/test/run-make/static-nobundle/aaa.c new file mode 100644 index 0000000000000..806ef878c7052 --- /dev/null +++ b/src/test/run-make/static-nobundle/aaa.c @@ -0,0 +1,11 @@ +// Copyright 2017 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. + +void native_func() {} diff --git a/src/test/run-make/static-nobundle/bbb.rs b/src/test/run-make/static-nobundle/bbb.rs new file mode 100644 index 0000000000000..2bd69c9932723 --- /dev/null +++ b/src/test/run-make/static-nobundle/bbb.rs @@ -0,0 +1,23 @@ +// Copyright 2017 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"] +#![feature(static_nobundle)] + +#[link(name = "aaa", kind = "static-nobundle")] +extern { + pub fn native_func(); +} + +pub fn wrapped_func() { + unsafe { + native_func(); + } +} diff --git a/src/test/run-make/static-nobundle/ccc.rs b/src/test/run-make/static-nobundle/ccc.rs new file mode 100644 index 0000000000000..bd34753a00d12 --- /dev/null +++ b/src/test/run-make/static-nobundle/ccc.rs @@ -0,0 +1,23 @@ +// Copyright 2017 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 bbb; + +pub fn do_work() { + unsafe { bbb::native_func(); } + bbb::wrapped_func(); +} + +pub fn do_work_generic() { + unsafe { bbb::native_func(); } + bbb::wrapped_func(); +} diff --git a/src/test/run-make/static-nobundle/ddd.rs b/src/test/run-make/static-nobundle/ddd.rs new file mode 100644 index 0000000000000..f7d23a899f758 --- /dev/null +++ b/src/test/run-make/static-nobundle/ddd.rs @@ -0,0 +1,17 @@ +// Copyright 2015 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. + +extern crate ccc; + +fn main() { + ccc::do_work(); + ccc::do_work_generic::(); + ccc::do_work_generic::(); +}