pub static tag_method_argument_names: uint = 0x8e;
pub static tag_method_argument_name: uint = 0x8f;
+pub static tag_reachable_extern_fns: uint = 0x90;
+pub static tag_reachable_extern_fn_id: uint = 0x91;
+
#[deriving(Clone, Show)]
pub struct LinkMeta {
pub crateid: CrateId,
let cdata = cstore.get_crate_data(did.krate);
decoder::get_method_arg_names(&*cdata, did.node)
}
+
+pub fn get_reachable_extern_fns(cstore: &cstore::CStore, cnum: ast::CrateNum)
+ -> Vec<ast::DefId>
+{
+ let cdata = cstore.get_crate_data(cnum);
+ decoder::get_reachable_extern_fns(&*cdata)
+}
}
return ret;
}
+
+pub fn get_reachable_extern_fns(cdata: Cmd) -> Vec<ast::DefId> {
+ let mut ret = Vec::new();
+ let items = reader::get_doc(ebml::Doc::new(cdata.data()),
+ tag_reachable_extern_fns);
+ reader::tagged_docs(items, tag_reachable_extern_fn_id, |doc| {
+ ret.push(ast::DefId {
+ krate: cdata.cnum,
+ node: reader::doc_as_u32(doc),
+ });
+ true
+ });
+ return ret;
+}
pub link_meta: &'a LinkMeta,
pub cstore: &'a cstore::CStore,
pub encode_inlined_item: EncodeInlinedItem<'a>,
+ pub reachable: &'a NodeSet,
}
pub struct EncodeContext<'a> {
pub cstore: &'a cstore::CStore,
pub encode_inlined_item: RefCell<EncodeInlinedItem<'a>>,
pub type_abbrevs: tyencode::abbrev_map,
+ pub reachable: &'a NodeSet,
}
fn encode_name(ebml_w: &mut Encoder, name: Name) {
ebml_w.end_tag();
}
+fn encode_reachable_extern_fns(ecx: &EncodeContext, ebml_w: &mut Encoder) {
+ ebml_w.start_tag(tag_reachable_extern_fns);
+
+ for id in ecx.reachable.iter() {
+ match ecx.tcx.map.find(*id) {
+ Some(ast_map::NodeItem(i)) => {
+ match i.node {
+ ast::ItemFn(_, _, abi, _, _) if abi != abi::Rust => {
+ ebml_w.wr_tagged_u32(tag_reachable_extern_fn_id, *id);
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+ }
+
+ ebml_w.end_tag();
+}
+
fn encode_crate_dep(ebml_w: &mut Encoder,
dep: decoder::CrateDep) {
ebml_w.start_tag(tag_crate_dep);
encode_inlined_item,
link_meta,
non_inlineable_statics,
+ reachable,
..
} = parms;
let ecx = EncodeContext {
cstore: cstore,
encode_inlined_item: RefCell::new(encode_inlined_item),
type_abbrevs: RefCell::new(HashMap::new()),
+ reachable: reachable,
};
let mut ebml_w = writer::Encoder::new(wr);
// Encode miscellaneous info.
i = ebml_w.writer.tell().unwrap();
encode_misc_info(&ecx, krate, &mut ebml_w);
+ encode_reachable_extern_fns(&ecx, &mut ebml_w);
stats.misc_bytes = ebml_w.writer.tell().unwrap() - i;
// Encode and index the items.
link_meta: &cx.link_meta,
cstore: &cx.sess().cstore,
encode_inlined_item: ie,
+ reachable: &cx.reachable,
}
}
ccx.item_symbols.borrow().find(id).map(|s| s.to_string())
}).collect();
+ // For the purposes of LTO, we add to the reachable set all of the upstream
+ // reachable extern fns. These functions are all part of the public ABI of
+ // the final product, so LTO needs to preserve them.
+ ccx.sess().cstore.iter_crate_data(|cnum, _| {
+ let syms = csearch::get_reachable_extern_fns(&ccx.sess().cstore, cnum);
+ reachable.extend(syms.move_iter().map(|did| {
+ csearch::get_symbol(&ccx.sess().cstore, did)
+ }));
+ });
+
// Make sure that some other crucial symbols are not eliminated from the
// module. This includes the main function, the crate map (used for debug
// log settings and I/O), and finally the curious rust_stack_exhausted
--- /dev/null
+-include ../tools.mk
+
+# Test to make sure that reachable extern fns are always available in final
+# productcs, including when LTO is used. In this test, the `foo` crate has a
+# reahable symbol, and is a dependency of the `bar` crate. When the `bar` crate
+# is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the
+# only way that `foo.c` will successfully compile.
+
+all:
+ $(RUSTC) foo.rs --crate-type=rlib
+ $(RUSTC) bar.rs --crate-type=staticlib -Zlto -L. -o $(TMPDIR)/libbar.a
+ $(CC) foo.c -lbar -o $(call RUN_BINFILE,foo) $(EXTRACFLAGS)
+ $(call RUN,foo)
+
--- /dev/null
+// Copyright 2014 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 foo;
--- /dev/null
+// Copyright 2014 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 void foo();
+
+int main() {
+ foo();
+ return 0;
+}
--- /dev/null
+// Copyright 2014 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.
+
+#[no_mangle]
+pub extern fn foo() {}
-include ../tools.mk
-ifdef IS_WINDOWS
- EXTRAFLAGS :=
-else
-ifeq ($(shell uname),Darwin)
-else
-ifeq ($(shell uname),FreeBSD)
- EXTRAFLAGS := -lm -lpthread -lgcc_s
-else
- EXTRAFLAGS := -lm -lrt -ldl -lpthread
-endif
-endif
-endif
-
# Apparently older versions of GCC segfault if -g is passed...
CC := $(CC:-g=)
all:
$(RUSTC) foo.rs -Z lto
ln -s $(call STATICLIB,foo-*) $(call STATICLIB,foo)
- $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(EXTRAFLAGS) -lstdc++
+ $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(EXTRACFLAGS) -lstdc++
$(call RUN,bar)
endif
endif
+# Extra flags needed to compile a working executable with the standard library
+ifdef IS_WINDOWS
+ EXTRACFLAGS :=
+else
+ifeq ($(shell uname),Darwin)
+else
+ifeq ($(shell uname),FreeBSD)
+ EXTRACFLAGS := -lm -lpthread -lgcc_s
+else
+ EXTRACFLAGS := -lm -lrt -ldl -lpthread
+endif
+endif
+endif
+
REMOVE_DYLIBS = rm $(TMPDIR)/$(call DYLIB_GLOB,$(1))
REMOVE_RLIBS = rm $(TMPDIR)/$(call RLIB_GLOB,$(1))