Skip to content

Commit

Permalink
Auto merge of #38426 - vadimcn:nobundle, r=alexcrichton
Browse files Browse the repository at this point in the history
Implement kind="static-nobundle" (RFC 1717)

This implements the "static-nobundle" library kind (last item from #37403).

Rustc handles "static-nobundle" libs very similarly to dylibs, except that on Windows, uses of their symbols do not get marked with "dllimport".  Which is the whole point of this feature.
  • Loading branch information
bors committed Feb 4, 2017
2 parents eb5cb95 + 7504897 commit ea7a648
Show file tree
Hide file tree
Showing 13 changed files with 148 additions and 5 deletions.
3 changes: 2 additions & 1 deletion src/librustc/middle/cstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,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

Expand Down Expand Up @@ -123,6 +123,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
}
Expand Down
5 changes: 5 additions & 0 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1476,12 +1476,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();
Expand Down
11 changes: 11 additions & 0 deletions src/librustc_metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -688,6 +695,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) {
Expand Down Expand Up @@ -927,6 +937,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) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_metadata/cstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 17 additions & 3 deletions src/librustc_trans/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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!(),
}
}
Expand Down Expand Up @@ -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
Expand All @@ -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) {
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/librustc_trans/back/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,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)),
);
Expand Down
13 changes: 13 additions & 0 deletions src/test/compile-fail/feature-gate-static-nobundle.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 {}
21 changes: 21 additions & 0 deletions src/test/run-make/static-nobundle/Makefile
Original file line number Diff line number Diff line change
@@ -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)
11 changes: 11 additions & 0 deletions src/test/run-make/static-nobundle/aaa.c
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

void native_func() {}
23 changes: 23 additions & 0 deletions src/test/run-make/static-nobundle/bbb.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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();
}
}
23 changes: 23 additions & 0 deletions src/test/run-make/static-nobundle/ccc.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T>() {
unsafe { bbb::native_func(); }
bbb::wrapped_func();
}
17 changes: 17 additions & 0 deletions src/test/run-make/static-nobundle/ddd.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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::<i16>();
ccc::do_work_generic::<i32>();
}

0 comments on commit ea7a648

Please sign in to comment.