Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement kind="static-nobundle" (RFC 1717) #38426

Merged
merged 3 commits into from
Feb 4, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/librustc/middle/cstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
}
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 @@ -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();
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 @@ -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) {
Expand Down Expand Up @@ -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) => {
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 @@ -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)),
);
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>();
}