From 91f8144906137335c3683b99d9c5c4ccaaebcde6 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Tue, 13 Dec 2016 09:50:30 -0800 Subject: [PATCH 1/3] Implement the "static-nobundle" library kind (RFC 1717). These are static libraries that are not bundled (as the name implies) into rlibs and staticlibs that rustc generates, and must be present when the final binary artifact is being linked. --- src/librustc/middle/cstore.rs | 3 ++- src/librustc/session/config.rs | 1 + src/librustc_metadata/creader.rs | 1 + src/librustc_metadata/cstore.rs | 2 +- src/librustc_trans/back/link.rs | 4 ++++ src/test/run-make/static-nobundle/Makefile | 13 +++++++++++++ src/test/run-make/static-nobundle/bar.rs | 22 ++++++++++++++++++++++ src/test/run-make/static-nobundle/foo.c | 11 +++++++++++ src/test/run-make/static-nobundle/main.rs | 16 ++++++++++++++++ 9 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 src/test/run-make/static-nobundle/Makefile create mode 100644 src/test/run-make/static-nobundle/bar.rs create mode 100644 src/test/run-make/static-nobundle/foo.c create mode 100644 src/test/run-make/static-nobundle/main.rs 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..ef68b2f76b07f 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1473,6 +1473,7 @@ 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", diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 8f7b9c24cbf8a..d9c64d3e7b343 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -917,6 +917,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..aa42364f951c7 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 @@ -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!(), } } @@ -1229,6 +1232,7 @@ 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 => 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 diff --git a/src/test/run-make/static-nobundle/Makefile b/src/test/run-make/static-nobundle/Makefile new file mode 100644 index 0000000000000..b184d54ff9c6f --- /dev/null +++ b/src/test/run-make/static-nobundle/Makefile @@ -0,0 +1,13 @@ +-include ../tools.mk + +all: $(call NATIVE_STATICLIB,foo) + $(RUSTC) bar.rs + + # Check that libbar.rlib does not contain the definition of `func` + nm $(TMPDIR)/libbar.rlib | (! grep "T _*func") + nm $(TMPDIR)/libbar.rlib | grep "U _*func" + + # Check that foo gets passed to the linker (as either `-l foo` or `foo.lib`) + $(RUSTC) main.rs -Z print-link-args | grep -e "-l[\" ]*foo" -e "foo.lib" + + $(call RUN,main) diff --git a/src/test/run-make/static-nobundle/bar.rs b/src/test/run-make/static-nobundle/bar.rs new file mode 100644 index 0000000000000..e14b5a669f440 --- /dev/null +++ b/src/test/run-make/static-nobundle/bar.rs @@ -0,0 +1,22 @@ +// 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. + +#![crate_type = "rlib"] + +#[link(name = "foo", kind = "static-nobundle")] +extern { + pub fn func(); +} + +pub fn wrapped_func() { + unsafe { + func(); + } +} diff --git a/src/test/run-make/static-nobundle/foo.c b/src/test/run-make/static-nobundle/foo.c new file mode 100644 index 0000000000000..5ccf713f79c61 --- /dev/null +++ b/src/test/run-make/static-nobundle/foo.c @@ -0,0 +1,11 @@ +// 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. + +void func() {} diff --git a/src/test/run-make/static-nobundle/main.rs b/src/test/run-make/static-nobundle/main.rs new file mode 100644 index 0000000000000..7aa730f1dd26b --- /dev/null +++ b/src/test/run-make/static-nobundle/main.rs @@ -0,0 +1,16 @@ +// 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 bar; + +fn main() { + unsafe { bar::func(); } + bar::wrapped_func(); +} From 3ae2174fc5bfef0b2220a44d5e371220f3dca532 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Thu, 15 Dec 2016 23:46:21 -0800 Subject: [PATCH 2/3] Feature gate --- src/librustc/session/config.rs | 4 ++++ src/librustc_metadata/creader.rs | 7 +++++++ src/libsyntax/feature_gate.rs | 3 +++ .../compile-fail/feature-gate-static-nobundle.rs | 13 +++++++++++++ src/test/run-make/static-nobundle/bar.rs | 1 + 5 files changed, 28 insertions(+) create mode 100644 src/test/compile-fail/feature-gate-static-nobundle.rs diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index ef68b2f76b07f..550f6eb12a7bd 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1480,6 +1480,10 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) 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 d9c64d3e7b343..87ba2edbfda7d 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); } 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/bar.rs b/src/test/run-make/static-nobundle/bar.rs index e14b5a669f440..c5d6237c9d594 100644 --- a/src/test/run-make/static-nobundle/bar.rs +++ b/src/test/run-make/static-nobundle/bar.rs @@ -9,6 +9,7 @@ // except according to those terms. #![crate_type = "rlib"] +#![feature(static_nobundle)] #[link(name = "foo", kind = "static-nobundle")] extern { From 7504897e6b4b1121191bc6612bcbcce1f70f5f06 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 3 Feb 2017 18:25:20 -0800 Subject: [PATCH 3/3] Don't link "nobundle" libs which had already been included in upstream crate. --- src/librustc_metadata/creader.rs | 3 +++ src/librustc_trans/back/link.rs | 18 ++++++++++---- src/librustc_trans/back/linker.rs | 1 + src/test/run-make/static-nobundle/Makefile | 24 ++++++++++++------- .../run-make/static-nobundle/{foo.c => aaa.c} | 4 ++-- .../static-nobundle/{bar.rs => bbb.rs} | 8 +++---- src/test/run-make/static-nobundle/ccc.rs | 23 ++++++++++++++++++ .../static-nobundle/{main.rs => ddd.rs} | 7 +++--- 8 files changed, 67 insertions(+), 21 deletions(-) rename src/test/run-make/static-nobundle/{foo.c => aaa.c} (82%) rename src/test/run-make/static-nobundle/{bar.rs => bbb.rs} (76%) create mode 100644 src/test/run-make/static-nobundle/ccc.rs rename src/test/run-make/static-nobundle/{main.rs => ddd.rs} (81%) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 87ba2edbfda7d..a228689363fc3 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -685,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) { diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index aa42364f951c7..20842ea3fe54d 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -896,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 @@ -1213,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 @@ -1223,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) { @@ -1232,8 +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 => cmd.link_staticlib(&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/test/run-make/static-nobundle/Makefile b/src/test/run-make/static-nobundle/Makefile index b184d54ff9c6f..3eac12f5cc9fd 100644 --- a/src/test/run-make/static-nobundle/Makefile +++ b/src/test/run-make/static-nobundle/Makefile @@ -1,13 +1,21 @@ -include ../tools.mk -all: $(call NATIVE_STATICLIB,foo) - $(RUSTC) bar.rs +# aaa is a native static library +# bbb is a rlib +# ccc is a dylib +# ddd is an executable - # Check that libbar.rlib does not contain the definition of `func` - nm $(TMPDIR)/libbar.rlib | (! grep "T _*func") - nm $(TMPDIR)/libbar.rlib | grep "U _*func" +all: $(call NATIVE_STATICLIB,aaa) + $(RUSTC) bbb.rs --crate-type=rlib - # Check that foo gets passed to the linker (as either `-l foo` or `foo.lib`) - $(RUSTC) main.rs -Z print-link-args | grep -e "-l[\" ]*foo" -e "foo.lib" + # 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" - $(call RUN,main) + # 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/foo.c b/src/test/run-make/static-nobundle/aaa.c similarity index 82% rename from src/test/run-make/static-nobundle/foo.c rename to src/test/run-make/static-nobundle/aaa.c index 5ccf713f79c61..806ef878c7052 100644 --- a/src/test/run-make/static-nobundle/foo.c +++ b/src/test/run-make/static-nobundle/aaa.c @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -void func() {} +void native_func() {} diff --git a/src/test/run-make/static-nobundle/bar.rs b/src/test/run-make/static-nobundle/bbb.rs similarity index 76% rename from src/test/run-make/static-nobundle/bar.rs rename to src/test/run-make/static-nobundle/bbb.rs index c5d6237c9d594..2bd69c9932723 100644 --- a/src/test/run-make/static-nobundle/bar.rs +++ b/src/test/run-make/static-nobundle/bbb.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -11,13 +11,13 @@ #![crate_type = "rlib"] #![feature(static_nobundle)] -#[link(name = "foo", kind = "static-nobundle")] +#[link(name = "aaa", kind = "static-nobundle")] extern { - pub fn func(); + pub fn native_func(); } pub fn wrapped_func() { unsafe { - func(); + 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/main.rs b/src/test/run-make/static-nobundle/ddd.rs similarity index 81% rename from src/test/run-make/static-nobundle/main.rs rename to src/test/run-make/static-nobundle/ddd.rs index 7aa730f1dd26b..f7d23a899f758 100644 --- a/src/test/run-make/static-nobundle/main.rs +++ b/src/test/run-make/static-nobundle/ddd.rs @@ -8,9 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern crate bar; +extern crate ccc; fn main() { - unsafe { bar::func(); } - bar::wrapped_func(); + ccc::do_work(); + ccc::do_work_generic::(); + ccc::do_work_generic::(); }