RUSTFLAGS_STAGE2 += -Z no-debug-borrows
endif
+# The executables crated during this compilation process have no need to include
+# static copies of libstd and libextra. We also generate dynamic versions of all
+# libraries, so in the interest of space, prefer dynamic linking throughout the
+# compilation process.
+RUSTFLAGS_STAGE1 += -Z prefer-dynamic
+RUSTFLAGS_STAGE2 += -Z prefer-dynamic
+RUSTFLAGS_STAGE3 += -Z prefer-dynamic
+
# platform-specific auto-configuration
include $(CFG_SRC_DIR)mk/platform.mk
LIBRUSTDOC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustdoc)
LIBRUSTUV_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustuv)
+EXTRALIB_RGLOB_$(1) :=$(call CFG_RLIB_GLOB,extra)
+STDLIB_RGLOB_$(1) :=$(call CFG_RLIB_GLOB,std)
+LIBRUSTUV_RGLOB_$(1) :=$(call CFG_RLIB_GLOB,rustuv)
+
endef
# $(1) is the path for directory to match against
TLIB$(1)_T_$(2)_H_$(3) = $$(TROOT$(1)_T_$(2)_H_$(3))/$$(CFG_LIBDIR)
# The name of the standard and extra libraries used by rustc
-ifdef CFG_DISABLE_SHAREDSTD
- HSTDLIB_DEFAULT$(1)_H_$(3) = \
- $$(HLIB$(1)_H_$(3))/libstd.rlib
- TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
- $$(TLIB$(1)_T_$(2)_H_$(3))/libstd.rlib
-
- HEXTRALIB_DEFAULT$(1)_H_$(3) = \
- $$(HLIB$(1)_H_$(3))/libextra.rlib
- TEXTRALIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
- $$(TLIB$(1)_T_$(2)_H_$(3))/libextra.rlib
-
- HLIBRUSTC_DEFAULT$(1)_H_$(3) = \
- $$(HLIB$(1)_H_$(3))/librustc.rlib
- TLIBRUSTC_DEFAULT$(1)_T_$(2)_H_$(3) = \
- $$(TLIB$(1)_T_$(2)_H_$(3))/librustc.rlib
-else
- HSTDLIB_DEFAULT$(1)_H_$(3) = \
- $$(HLIB$(1)_H_$(3))/$(CFG_STDLIB_$(3))
- TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2))
-
- HEXTRALIB_DEFAULT$(1)_H_$(3) = \
- $$(HLIB$(1)_H_$(3))/$(CFG_EXTRALIB_$(3))
- TEXTRALIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2))
-
- HLIBRUSTC_DEFAULT$(1)_H_$(3) = \
- $$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTC_$(3))
- TLIBRUSTC_DEFAULT$(1)_T_$(2)_H_$(3) = \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2))
-
- HLIBRUSTUV_DEFAULT$(1)_H_$(3) = \
- $$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTUV_$(3))
- TLIBRUSTUV_DEFAULT$(1)_T_$(2)_H_$(3) = \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2))
-endif
+HSTDLIB_DEFAULT$(1)_H_$(3) = \
+ $$(HLIB$(1)_H_$(3))/$(CFG_STDLIB_$(3))
+TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
+ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2))
+
+HEXTRALIB_DEFAULT$(1)_H_$(3) = \
+ $$(HLIB$(1)_H_$(3))/$(CFG_EXTRALIB_$(3))
+TEXTRALIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
+ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2))
+
+HLIBRUSTC_DEFAULT$(1)_H_$(3) = \
+ $$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTC_$(3))
+TLIBRUSTC_DEFAULT$(1)_T_$(2)_H_$(3) = \
+ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2))
+
+HLIBRUSTUV_DEFAULT$(1)_H_$(3) = \
+ $$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTUV_$(3))
+TLIBRUSTUV_DEFAULT$(1)_T_$(2)_H_$(3) = \
+ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2))
# Preqrequisites for using the stageN compiler
HSREQ$(1)_H_$(3) = \
BOOL_OPTIONS=""
VAL_OPTIONS=""
-opt sharedstd 1 "build libstd as a shared library"
opt valgrind 0 "run tests with valgrind (memcheck by default)"
opt helgrind 0 "run tests with helgrind instead of memcheck"
opt docs 1 "build documentation"
valopt datadir "${CFG_PREFIX}/share" "install data"
valopt infodir "${CFG_PREFIX}/share/info" "install additional info"
valopt mandir "${CFG_PREFIX}/share/man" "install man pages in PATH"
-valopt libdir "${CFG_PREFIX}/lib" "install libraries"
+valopt libdir "${CFG_PREFIX}/lib" "install libraries"
# Validate Options
step_msg "validating $CFG_SELF args"
extern "stdcall" { }
~~~~
-The `link_name` attribute allows the name of the library to be specified.
+The `link` attribute allows the name of the library to be specified. When
+specified the compiler will attempt to link against the native library of the
+specified name.
~~~~ {.xfail-test}
-#[link_name = "crypto"]
+#[link(name = "crypto")]
extern { }
~~~~
-The `nolink` attribute tells the Rust compiler
-not to do any linking for the external block.
-This is particularly useful for creating external blocks for libc,
-which tends to not follow standard library naming conventions
-and is linked to all Rust programs anyway.
-
The type of a function
declared in an extern block
is `extern "abi" fn(A1, ..., An) -> R`,
$(Q)find $(1)/rustllvm \
$(1)/rt \
$(1)/test \
+ $(1)/stage* \
-name '*.[odasS]' -o \
-name '*.so' -o \
-name '*.dylib' -o \
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTC_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBSYNTAX_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(STDLIB_GLOB_$(2))
+ $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(STDLIB_RGLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(EXTRALIB_GLOB_$(2))
+ $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(EXTRALIB_RGLOB_$(2))
+ $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTUV_GLOB_$(2))
+ $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTUV_RGLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTC_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBSYNTAX_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTPKG_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTDOC_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_RUSTLLVM_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/libstd.rlib
endef
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(STDLIB_GLOB_$(2))
+ $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(STDLIB_RGLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(EXTRALIB_GLOB_$(2))
+ $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(EXTRALIB_RGLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTUV_GLOB_$(2))
+ $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTUV_RGLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTC_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBSYNTAX_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTPKG_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTDOC_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libstd.rlib
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/librun_pass_stage* # For unix
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/run_pass_stage* # For windows
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(4)),$$(notdir $$@))
$$(Q)cp $$< $$@
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTC_GLOB_$(4)) \
- $(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTC_DSYM_GLOB_$(4))) \
+ $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTC_DSYM_GLOB_$(4))) \
$$(HLIB$(2)_H_$(4))
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(4)),$$(notdir $$@))
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_GLOB_$(4)),$$(notdir $$@))
+ $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_RGLOB_$(4)),$$(notdir $$@))
$$(Q)cp $$< $$@
# Subtle: We do not let the shell expand $$(STDLIB_DSYM_GLOB) directly rather
# we use Make's $$(wildcard) facility. The reason is that, on mac, when using
# Make instead expands the glob to nothing, which gives us the correct behavior.
# (Copy .dsym file if it exists, but do nothing otherwise)
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_GLOB_$(4)) \
+ $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_RGLOB_$(4))) \
$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_DSYM_GLOB_$(4))) \
$$(HLIB$(2)_H_$(4))
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_GLOB_$(4)),$$(notdir $$@))
+ $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_RGLOB_$(4)),$$(notdir $$@))
$$(HLIB$(2)_H_$(4))/$(CFG_EXTRALIB_$(4)): \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_EXTRALIB_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(4)),$$(notdir $$@))
+ $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_RGLOB_$(4)),$$(notdir $$@))
$$(Q)cp $$< $$@
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(EXTRALIB_GLOB_$(4)) \
+ $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(EXTRALIB_RGLOB_$(4))) \
$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(EXTRALIB_DSYM_GLOB_$(4))) \
$$(HLIB$(2)_H_$(4))
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(4)),$$(notdir $$@))
+ $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_RGLOB_$(4)),$$(notdir $$@))
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTUV_$(4)): \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTUV_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
+ $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_RGLOB_$(4)),$$(notdir $$@))
$$(Q)cp $$< $$@
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTUV_GLOB_$(4)) \
+ $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTUV_RGLOB_$(4))) \
$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTUV_DSYM_GLOB_$(4))) \
$$(HLIB$(2)_H_$(4))
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
-
-$$(HLIB$(2)_H_$(4))/libstd.rlib: \
- $$(TLIB$(1)_T_$(4)_H_$(3))/libstd.rlib \
- $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \
- | $$(HLIB$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(Q)cp $$< $$@
-
-$$(HLIB$(2)_H_$(4))/libextra.rlib: \
- $$(TLIB$(1)_T_$(4)_H_$(3))/libextra.rlib \
- $$(HLIB$(2)_H_$(4))/libstd.rlib \
- $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \
- | $$(HLIB$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(Q)cp $$< $$@
-
-$$(HLIB$(2)_H_$(4))/librustc.rlib: \
- $$(TLIB$(1)_T_$(4)_H_$(3))/librustc.rlib \
- $$(HLIB$(2)_H_$(4))/libstd.rlib \
- $$(HLIB$(2)_H_$(4))/libextra.rlib \
- $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \
- | $$(HLIB$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(Q)cp $$< $$@
+ $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_RGLOB_$(4)),$$(notdir $$@))
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)): \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUSTLLVM_$(4)) \
$(Q)$(call INSTALL,$(HB2),$(PHB),rustpkg$(X_$(CFG_BUILD)))
$(Q)$(call INSTALL,$(HB2),$(PHB),rustdoc$(X_$(CFG_BUILD)))
$(Q)$(call INSTALL_LIB,$(STDLIB_GLOB_$(CFG_BUILD)))
+ $(Q)$(call INSTALL_LIB,$(STDLIB_RGLOB_$(CFG_BUILD)))
$(Q)$(call INSTALL_LIB,$(EXTRALIB_GLOB_$(CFG_BUILD)))
+ $(Q)$(call INSTALL_LIB,$(EXTRALIB_RGLOB_$(CFG_BUILD)))
$(Q)$(call INSTALL_LIB,$(LIBRUSTUV_GLOB_$(CFG_BUILD)))
+ $(Q)$(call INSTALL_LIB,$(LIBRUSTUV_RGLOB_$(CFG_BUILD)))
$(Q)$(call INSTALL_LIB,$(LIBRUSTC_GLOB_$(CFG_BUILD)))
$(Q)$(call INSTALL_LIB,$(LIBSYNTAX_GLOB_$(CFG_BUILD)))
$(Q)$(call INSTALL_LIB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD)))
$(Q)rm -f $(PHL)/$(CFG_RUNTIME_$(CFG_BUILD))
$(Q)for i in \
$(call HOST_LIB_FROM_HL_GLOB,$(STDLIB_GLOB_$(CFG_BUILD))) \
+ $(call HOST_LIB_FROM_HL_GLOB,$(STDLIB_RGLOB_$(CFG_BUILD))) \
$(call HOST_LIB_FROM_HL_GLOB,$(EXTRALIB_GLOB_$(CFG_BUILD))) \
+ $(call HOST_LIB_FROM_HL_GLOB,$(EXTRALIB_RGLOB_$(CFG_BUILD))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTUV_GLOB_$(CFG_BUILD))) \
+ $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTUV_RGLOB_$(CFG_BUILD))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTC_GLOB_$(CFG_BUILD))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBSYNTAX_GLOB_$(CFG_BUILD))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD))) \
endif
endif
+CFG_RLIB_GLOB=lib$(1)-*.rlib
# x86_64-unknown-linux-gnu configuration
CC_x86_64-unknown-linux-gnu=$(CC)
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_GLOB_$(2)),$$(notdir $$@))
+ $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_RGLOB_$(2)),$$(notdir $$@))
$$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_GLOB_$(2)),$$(notdir $$@))
+ $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_RGLOB_$(2)),$$(notdir $$@))
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)): \
$$(EXTRALIB_CRATE) $$(EXTRALIB_INPUTS) \
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(2)),$$(notdir $$@))
+ $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_RGLOB_$(2)),$$(notdir $$@))
$$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(2)),$$(notdir $$@))
+ $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_RGLOB_$(2)),$$(notdir $$@))
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2)): \
$$(LIBRUSTUV_CRATE) $$(LIBRUSTUV_INPUTS) \
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(2)),$$(notdir $$@))
+ $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_RGLOB_$(2)),$$(notdir $$@))
$$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) \
-L $$(UV_SUPPORT_DIR_$(2)) \
-L $$(dir $$(LIBUV_LIB_$(2))) \
--out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(2)),$$(notdir $$@))
+ $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_RGLOB_$(2)),$$(notdir $$@))
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \
$$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \
# remove directive, if present, from CFG_RUSTC_FLAGS (issue #7898).
CTEST_RUSTC_FLAGS := $$(subst --cfg ndebug,,$$(CFG_RUSTC_FLAGS))
+# There's no need our entire test suite to take up gigabytes of space on disk
+# including copies of libstd/libextra all over the place
+CTEST_RUSTC_FLAGS := $$(CTEST_RUSTC_FLAGS) -Z prefer-dynamic
+
# The tests can not be optimized while the rest of the compiler is optimized, so
# filter out the optimization (if any) from rustc and then figure out if we need
# to be optimized
pub mod rustrt {
use std::libc::{c_int, c_void, size_t};
- #[link_name = "rustrt"]
+ #[link(name = "rustrt")]
extern {
pub fn tdefl_compress_mem_to_heap(psrc_buf: *c_void,
src_buf_len: size_t,
#[comment = "Rust extras"];
#[license = "MIT/ASL2"];
-#[crate_type = "lib"];
+#[crate_type = "lib"]; // NOTE: remove after stage0 snapshot
+#[crate_type = "rlib"];
+#[crate_type = "dylib"];
#[feature(macro_rules, globs, managed_boxes)];
--- /dev/null
+// Copyright 2013 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.
+
+//! A helper class for dealing with static archives
+
+use driver::session::Session;
+use metadata::filesearch;
+
+use std::io::fs;
+use std::os;
+use std::run::{ProcessOptions, Process, ProcessOutput};
+use std::str;
+use extra::tempfile::TempDir;
+use syntax::abi;
+
+pub struct Archive {
+ priv sess: Session,
+ priv dst: Path,
+}
+
+fn run_ar(sess: Session, args: &str, cwd: Option<&Path>,
+ paths: &[&Path]) -> ProcessOutput {
+ let ar = sess.opts.ar.clone().unwrap_or(~"ar");
+ let mut args = ~[args.to_owned()];
+ let mut paths = paths.iter().map(|p| p.as_str().unwrap().to_owned());
+ args.extend(&mut paths);
+ let mut opts = ProcessOptions::new();
+ opts.dir = cwd;
+ debug!("{} {}", ar, args.connect(" "));
+ match cwd {
+ Some(p) => { debug!("inside {}", p.display()); }
+ None => {}
+ }
+ let o = Process::new(ar, args.as_slice(), opts).finish_with_output();
+ if !o.status.success() {
+ sess.err(format!("{} failed with: {}", ar, o.status));
+ sess.note(format!("stdout ---\n{}", str::from_utf8(o.output)));
+ sess.note(format!("stderr ---\n{}", str::from_utf8(o.error)));
+ sess.abort_if_errors();
+ }
+ o
+}
+
+impl Archive {
+ /// Initializes a new static archive with the given object file
+ pub fn create<'a>(sess: Session, dst: &'a Path,
+ initial_object: &'a Path) -> Archive {
+ run_ar(sess, "crus", None, [dst, initial_object]);
+ Archive { sess: sess, dst: dst.clone() }
+ }
+
+ /// Opens an existing static archive
+ pub fn open(sess: Session, dst: Path) -> Archive {
+ assert!(dst.exists());
+ Archive { sess: sess, dst: dst }
+ }
+
+ /// Read a file in the archive
+ pub fn read(&self, file: &str) -> ~[u8] {
+ run_ar(self.sess, "p", None, [&self.dst, &Path::new(file)]).output
+ }
+
+ /// Adds all of the contents of a native library to this archive. This will
+ /// search in the relevant locations for a library named `name`.
+ pub fn add_native_library(&mut self, name: &str) {
+ let location = self.find_library(name);
+ self.add_archive(&location, name);
+ }
+
+ /// Adds all of the contents of the rlib at the specified path to this
+ /// archive.
+ pub fn add_rlib(&mut self, rlib: &Path) {
+ let name = rlib.filename_str().unwrap().split_iter('-').next().unwrap();
+ self.add_archive(rlib, name);
+ }
+
+ fn add_archive(&mut self, archive: &Path, name: &str) {
+ let loc = TempDir::new("rsar").unwrap();
+
+ // First, extract the contents of the archive to a temporary directory
+ let archive = os::make_absolute(archive);
+ run_ar(self.sess, "x", Some(loc.path()), [&archive]);
+
+ // Next, we must rename all of the inputs to "guaranteed unique names".
+ // The reason for this is that archives are keyed off the name of the
+ // files, so if two files have the same name they will override one
+ // another in the archive (bad).
+ let files = fs::readdir(loc.path());
+ let mut inputs = ~[];
+ for file in files.iter() {
+ let filename = file.filename_str().unwrap();
+ let filename = format!("r-{}-{}", name, filename);
+ let new_filename = file.with_filename(filename);
+ fs::rename(file, &new_filename);
+ inputs.push(new_filename);
+ }
+
+ // Finally, add all the renamed files to this archive
+ let mut args = ~[&self.dst];
+ args.extend(&mut inputs.iter());
+ run_ar(self.sess, "r", None, args.as_slice());
+ }
+
+ fn find_library(&self, name: &str) -> Path {
+ let (prefix, ext) = match self.sess.targ_cfg.os {
+ abi::OsWin32 => ("", "lib"), _ => ("lib", "a"),
+ };
+ let libname = format!("{}{}.{}", prefix, name, ext);
+
+ let mut rustpath = filesearch::rust_path();
+ rustpath.push(self.sess.filesearch.get_target_lib_path());
+ let path = self.sess.opts.addl_lib_search_paths.iter();
+ for path in path.chain(rustpath.iter()) {
+ debug!("looking for {} inside {}", name, path.display());
+ let test = path.join(libname.clone());
+ if test.exists() { return test }
+ }
+ self.sess.fatal(format!("could not find native static library `{}`, \
+ perhaps an -L flag is missing?", name));
+ }
+}
target_triple: target_triple,
- cc_args: ~[~"-marm"]
+ cc_args: ~[~"-marm"],
};
}
// except according to those terms.
+use back::archive::Archive;
use back::rpath;
use driver::session::Session;
use driver::session;
use lib::llvm::ModuleRef;
use lib;
use metadata::common::LinkMeta;
-use metadata::{encoder, cstore, filesearch};
+use metadata::{encoder, cstore, filesearch, csearch};
use middle::trans::context::CrateContext;
use middle::trans::common::gensym_name;
use middle::ty;
use std::ptr;
use std::run;
use std::str;
-use std::vec;
use std::io::fs;
use syntax::abi;
use syntax::ast;
use driver::session::Session;
use lib::llvm::llvm;
use lib::llvm::{ModuleRef, ContextRef, ExecutionEngineRef};
- use metadata::cstore;
use std::c_str::ToCStr;
use std::cast;
// core linked into rustc. We don't want that,
// incase the user wants to use an older extra library.
- let cstore = sess.cstore;
- let r = cstore::get_used_crate_files(cstore);
- for cratepath in r.iter() {
- debug!("linking: {}", cratepath.display());
-
- cratepath.with_c_str(|buf_t| {
- if !llvm::LLVMRustLoadCrate(manager, buf_t) {
- llvm_err(sess, ~"Could not link");
- }
- debug!("linked: {}", cratepath.display());
- })
- }
-
// We custom-build a JIT execution engine via some rust wrappers
// first. This wrappers takes ownership of the module passed in.
let ee = llvm::LLVMRustBuildJIT(manager, m, stacks);
}
pub fn run_assembler(sess: Session, assembly: &Path, object: &Path) {
- let cc_prog = super::get_cc_prog(sess);
+ let cc = super::get_cc_prog(sess);
// FIXME (#9639): This needs to handle non-utf8 paths
- let cc_args = ~[
+ let args = [
~"-c",
~"-o", object.as_str().unwrap().to_owned(),
assembly.as_str().unwrap().to_owned()];
- let prog = run::process_output(cc_prog, cc_args);
+ debug!("{} {}", cc, args.connect(" "));
+ let prog = run::process_output(cc, args);
if !prog.status.success() {
- sess.err(format!("linking with `{}` failed: {}", cc_prog, prog.status));
- sess.note(format!("{} arguments: {}",
- cc_prog, cc_args.connect(" ")));
+ sess.err(format!("linking with `{}` failed: {}", cc, prog.status));
+ sess.note(format!("{} arguments: {}", cc, args.connect(" ")));
sess.note(str::from_utf8(prog.error + prog.output));
sess.abort_if_errors();
}
mangle(ccx.sess, path, None, None)
}
-
-pub fn output_dll_filename(os: abi::Os, lm: LinkMeta) -> ~str {
- let (dll_prefix, dll_suffix) = match os {
- abi::OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
- abi::OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
- abi::OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
- abi::OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX),
- abi::OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
- };
- format!("{}{}-{}-{}{}", dll_prefix, lm.name, lm.extras_hash, lm.vers, dll_suffix)
+pub fn output_lib_filename(lm: LinkMeta) -> ~str {
+ format!("{}-{}-{}", lm.name, lm.extras_hash, lm.vers)
}
pub fn get_cc_prog(sess: Session) -> ~str {
+ match sess.opts.linker {
+ Some(ref linker) => return linker.to_owned(),
+ None => {}
+ }
+
// In the future, FreeBSD will use clang as default compiler.
// It would be flexible to use cc (system's default C compiler)
// instead of hard-coded gcc.
- // For win32, there is no cc command, so we add a condition to make it use g++.
- // We use g++ rather than gcc because it automatically adds linker options required
- // for generation of dll modules that correctly register stack unwind tables.
- match sess.opts.linker {
- Some(ref linker) => linker.to_str(),
- None => match sess.targ_cfg.os {
- abi::OsAndroid =>
- match &sess.opts.android_cross_path {
- &Some(ref path) => {
- format!("{}/bin/arm-linux-androideabi-gcc", *path)
- }
- &None => {
- sess.fatal("need Android NDK path for linking \
- (--android-cross-path)")
- }
- },
- abi::OsWin32 => ~"g++",
- _ => ~"cc"
- }
+ // For win32, there is no cc command, so we add a condition to make it use
+ // g++. We use g++ rather than gcc because it automatically adds linker
+ // options required for generation of dll modules that correctly register
+ // stack unwind tables.
+ match sess.targ_cfg.os {
+ abi::OsAndroid => match sess.opts.android_cross_path {
+ Some(ref path) => format!("{}/bin/arm-linux-androideabi-gcc", *path),
+ None => {
+ sess.fatal("need Android NDK path for linking \
+ (--android-cross-path)")
+ }
+ },
+ abi::OsWin32 => ~"g++",
+ _ => ~"cc",
}
}
-// If the user wants an exe generated we need to invoke
-// cc to link the object file with some libs
+/// Perform the linkage portion of the compilation phase. This will generate all
+/// of the requested outputs for this compilation session.
pub fn link_binary(sess: Session,
+ crate_types: &[~str],
obj_filename: &Path,
out_filename: &Path,
lm: LinkMeta) {
-
- let cc_prog = get_cc_prog(sess);
- // The invocations of cc share some flags across platforms
-
- let output = if *sess.building_library {
- let long_libname = output_dll_filename(sess.targ_cfg.os, lm);
- debug!("link_meta.name: {}", lm.name);
- debug!("long_libname: {}", long_libname);
- debug!("out_filename: {}", out_filename.display());
- let out_dirname = out_filename.dir_path();
- debug!("dirname(out_filename): {}", out_dirname.display());
-
- out_filename.with_filename(long_libname)
+ let outputs = if sess.opts.test {
+ // If we're generating a test executable, then ignore all other output
+ // styles at all other locations
+ ~[session::OutputExecutable]
} else {
- out_filename.clone()
+ // Always generate whatever was specified on the command line, but also
+ // look at what was in the crate file itself for generating output
+ // formats.
+ let mut outputs = sess.opts.outputs.clone();
+ for ty in crate_types.iter() {
+ if "bin" == *ty {
+ outputs.push(session::OutputExecutable);
+ } else if "dylib" == *ty || "lib" == *ty {
+ outputs.push(session::OutputDylib);
+ } else if "rlib" == *ty {
+ outputs.push(session::OutputRlib);
+ } else if "staticlib" == *ty {
+ outputs.push(session::OutputStaticlib);
+ }
+ }
+ if outputs.len() == 0 {
+ outputs.push(session::OutputExecutable);
+ }
+ outputs
};
- debug!("output: {}", output.display());
- let cc_args = link_args(sess, obj_filename, out_filename, lm);
- debug!("{} link args: {}", cc_prog, cc_args.connect(" "));
- if (sess.opts.debugging_opts & session::print_link_args) != 0 {
- println!("{} link args: {}", cc_prog, cc_args.connect(" "));
- }
-
- // We run 'cc' here
- let prog = run::process_output(cc_prog, cc_args);
-
- if !prog.status.success() {
- sess.err(format!("linking with `{}` failed: {}", cc_prog, prog.status));
- sess.note(format!("{} arguments: {}",
- cc_prog, cc_args.connect(" ")));
- sess.note(str::from_utf8(prog.error + prog.output));
- sess.abort_if_errors();
- }
-
- // On OSX, debuggers needs this utility to get run to do some munging of the
- // symbols
- if sess.targ_cfg.os == abi::OsMacos && sess.opts.debuginfo {
- // FIXME (#9639): This needs to handle non-utf8 paths
- run::process_status("dsymutil", [output.as_str().unwrap().to_owned()]);
+ for output in outputs.move_iter() {
+ link_binary_output(sess, output, obj_filename, out_filename, lm);
}
// Remove the temporary object file if we aren't saving temps
fn is_writeable(p: &Path) -> bool {
use std::io;
- !p.exists() ||
- (match io::result(|| p.stat()) {
- Err(..) => false,
- Ok(m) => m.perm & io::UserWrite == io::UserWrite
- })
+ match io::result(|| p.stat()) {
+ Err(..) => true,
+ Ok(m) => m.perm & io::UserWrite == io::UserWrite
+ }
}
-pub fn link_args(sess: Session,
- obj_filename: &Path,
- out_filename: &Path,
- lm:LinkMeta) -> ~[~str] {
-
- // Converts a library file-stem into a cc -l argument
- fn unlib(config: @session::config, stem: ~str) -> ~str {
- if stem.starts_with("lib") &&
- config.os != abi::OsWin32 {
- stem.slice(3, stem.len()).to_owned()
- } else {
- stem
+fn link_binary_output(sess: Session,
+ output: session::OutputStyle,
+ obj_filename: &Path,
+ out_filename: &Path,
+ lm: LinkMeta) {
+ let libname = output_lib_filename(lm);
+ let out_filename = match output {
+ session::OutputRlib => {
+ out_filename.with_filename(format!("lib{}.rlib", libname))
}
- }
-
-
- let output = if *sess.building_library {
- let long_libname = output_dll_filename(sess.targ_cfg.os, lm);
- out_filename.with_filename(long_libname)
- } else {
- out_filename.clone()
+ session::OutputDylib => {
+ let (prefix, suffix) = match sess.targ_cfg.os {
+ abi::OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
+ abi::OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
+ abi::OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
+ abi::OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX),
+ abi::OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
+ };
+ out_filename.with_filename(format!("{}{}{}", prefix, libname, suffix))
+ }
+ session::OutputStaticlib => {
+ out_filename.with_filename(format!("lib{}.a", libname))
+ }
+ session::OutputExecutable => out_filename.clone(),
};
// Make sure the output and obj_filename are both writeable.
// however, the Linux linker will happily overwrite a read-only file.
// We should be consistent.
let obj_is_writeable = is_writeable(obj_filename);
- let out_is_writeable = is_writeable(&output);
+ let out_is_writeable = is_writeable(&out_filename);
if !out_is_writeable {
sess.fatal(format!("Output file {} is not writeable -- check its permissions.",
- output.display()));
+ out_filename.display()));
}
else if !obj_is_writeable {
sess.fatal(format!("Object file {} is not writeable -- check its permissions.",
obj_filename.display()));
}
- // The default library location, we need this to find the runtime.
- // The location of crates will be determined as needed.
- // FIXME (#9639): This needs to handle non-utf8 paths
- let lib_path = sess.filesearch.get_target_lib_path();
- let stage: ~str = ~"-L" + lib_path.as_str().unwrap();
-
- let mut args = vec::append(~[stage], sess.targ_cfg.target_strs.cc_args);
-
- // FIXME (#9639): This needs to handle non-utf8 paths
- args.push_all([
- ~"-o", output.as_str().unwrap().to_owned(),
- obj_filename.as_str().unwrap().to_owned()]);
-
- let lib_cmd = match sess.targ_cfg.os {
- abi::OsMacos => ~"-dynamiclib",
- _ => ~"-shared"
- };
+ match output {
+ session::OutputRlib => {
+ link_rlib(sess, obj_filename, &out_filename);
+ }
+ session::OutputStaticlib => {
+ link_staticlib(sess, obj_filename, &out_filename);
+ }
+ session::OutputExecutable => {
+ link_natively(sess, false, obj_filename, &out_filename);
+ }
+ session::OutputDylib => {
+ link_natively(sess, true, obj_filename, &out_filename);
+ }
+ }
+}
- // # Crate linking
+// Create an 'rlib'
+//
+// An rlib in its current incarnation is essentially a renamed .a file. The
+// rlib primarily contains the object file of the crate, but it also contains
+// all of the object files from native libraries. This is done by unzipping
+// native libraries and inserting all of the contents into this archive.
+fn link_rlib(sess: Session, obj_filename: &Path,
+ out_filename: &Path) -> Archive {
+ let mut a = Archive::create(sess, out_filename, obj_filename);
+ for &(ref l, kind) in cstore::get_used_libraries(sess.cstore).iter() {
+ match kind {
+ cstore::NativeStatic => {
+ a.add_native_library(l.as_slice());
+ }
+ cstore::NativeUnknown => {}
+ }
+ }
+ return a;
+}
- let cstore = sess.cstore;
- let r = cstore::get_used_crate_files(cstore);
- // FIXME (#9639): This needs to handle non-utf8 paths
- for cratepath in r.iter() {
- if cratepath.extension_str() == Some("rlib") {
- args.push(cratepath.as_str().unwrap().to_owned());
- continue;
+// Create a static archive
+//
+// This is essentially the same thing as an rlib, but it also involves adding
+// all of the upstream crates' objects into the the archive. This will slurp in
+// all of the native libraries of upstream dependencies as well.
+//
+// Additionally, there's no way for us to link dynamic libraries, so we warn
+// about all dynamic library dependencies that they're not linked in.
+fn link_staticlib(sess: Session, obj_filename: &Path, out_filename: &Path) {
+ let mut a = link_rlib(sess, obj_filename, out_filename);
+ a.add_native_library("morestack");
+
+ let crates = cstore::get_used_crates(sess.cstore, cstore::RequireStatic);
+ for &(cnum, ref path) in crates.iter() {
+ let p = match *path {
+ Some(ref p) => p.clone(), None => {
+ sess.err(format!("could not find rlib for: `{}`",
+ cstore::get_crate_data(sess.cstore, cnum).name));
+ continue
+ }
+ };
+ a.add_rlib(&p);
+ let native_libs = csearch::get_native_libraries(sess.cstore, cnum);
+ for lib in native_libs.iter() {
+ sess.warn(format!("unlinked native library: {}", *lib));
}
- let dir = cratepath.dirname_str().unwrap();
- if !dir.is_empty() { args.push("-L" + dir); }
- let libarg = unlib(sess.targ_cfg, cratepath.filestem_str().unwrap().to_owned());
- args.push("-l" + libarg);
}
+}
- let ula = cstore::get_used_link_args(cstore);
- for arg in ula.iter() { args.push(arg.to_owned()); }
+// Create a dynamic library or executable
+//
+// This will invoke the system linker/cc to create the resulting file. This
+// links to all upstream files as well.
+fn link_natively(sess: Session, dylib: bool, obj_filename: &Path,
+ out_filename: &Path) {
+ // The invocations of cc share some flags across platforms
+ let cc_prog = get_cc_prog(sess);
+ let mut cc_args = sess.targ_cfg.target_strs.cc_args.clone();
+ cc_args.push_all_move(link_args(sess, dylib, obj_filename, out_filename));
+ if (sess.opts.debugging_opts & session::print_link_args) != 0 {
+ println!("{} link args: {}", cc_prog, cc_args.connect(" "));
+ }
- // # Extern library linking
+ // May have not found libraries in the right formats.
+ sess.abort_if_errors();
- // User-supplied library search paths (-L on the cammand line) These are
- // the same paths used to find Rust crates, so some of them may have been
- // added already by the previous crate linking code. This only allows them
- // to be found at compile time so it is still entirely up to outside
- // forces to make sure that library can be found at runtime.
+ // Invoke the system linker
+ debug!("{} {}", cc_prog, cc_args.connect(" "));
+ let prog = run::process_output(cc_prog, cc_args);
- for path in sess.opts.addl_lib_search_paths.iter() {
- // FIXME (#9639): This needs to handle non-utf8 paths
- args.push("-L" + path.as_str().unwrap().to_owned());
+ if !prog.status.success() {
+ sess.err(format!("linking with `{}` failed: {}", cc_prog, prog.status));
+ sess.note(format!("{} arguments: {}", cc_prog, cc_args.connect(" ")));
+ sess.note(str::from_utf8(prog.error + prog.output));
+ sess.abort_if_errors();
}
- let rustpath = filesearch::rust_path();
- for path in rustpath.iter() {
+
+ // On OSX, debuggers need this utility to get run to do some munging of
+ // the symbols
+ if sess.targ_cfg.os == abi::OsMacos && sess.opts.debuginfo {
// FIXME (#9639): This needs to handle non-utf8 paths
- args.push("-L" + path.as_str().unwrap().to_owned());
+ run::process_status("dsymutil",
+ [out_filename.as_str().unwrap().to_owned()]);
}
+}
- if sess.targ_cfg.os == abi::OsLinux {
- // GNU-style linkers will use this to omit linking to libraries which don't actually fulfill
- // any relocations, but only for libraries which follow this flag. Thus, use it before
- // specifing libraries to link to.
- args.push(~"-Wl,--as-needed");
- }
+fn link_args(sess: Session,
+ dylib: bool,
+ obj_filename: &Path,
+ out_filename: &Path) -> ~[~str] {
- // The names of the extern libraries
- let used_libs = cstore::get_used_libraries(cstore);
- for l in used_libs.iter() { args.push(~"-l" + *l); }
+ // The default library location, we need this to find the runtime.
+ // The location of crates will be determined as needed.
+ // FIXME (#9639): This needs to handle non-utf8 paths
+ let lib_path = sess.filesearch.get_target_lib_path();
+ let stage: ~str = ~"-L" + lib_path.as_str().unwrap();
- if *sess.building_library {
- args.push(lib_cmd);
+ let mut args = ~[stage];
- // On mac we need to tell the linker to let this library
- // be rpathed
- if sess.targ_cfg.os == abi::OsMacos {
- // FIXME (#9639): This needs to handle non-utf8 paths
- args.push("-Wl,-install_name,@rpath/"
- + output.filename_str().unwrap());
- }
- }
+ // FIXME (#9639): This needs to handle non-utf8 paths
+ args.push_all([
+ ~"-o", out_filename.as_str().unwrap().to_owned(),
+ obj_filename.as_str().unwrap().to_owned()]);
- // On linux librt and libdl are an indirect dependencies via rustrt,
- // and binutils 2.22+ won't add them automatically
if sess.targ_cfg.os == abi::OsLinux {
- // GNU-style linkers supports optimization with -O. --gc-sections removes metadata and
- // potentially other useful things, so don't include it. GNU ld doesn't need a numeric
- // argument, but other linkers do.
- if sess.opts.optimize == session::Default || sess.opts.optimize == session::Aggressive {
+ // GNU-style linkers will use this to omit linking to libraries which
+ // don't actually fulfill any relocations, but only for libraries which
+ // follow this flag. Thus, use it before specifing libraries to link to.
+ args.push(~"-Wl,--as-needed");
+
+ // GNU-style linkers supports optimization with -O. --gc-sections
+ // removes metadata and potentially other useful things, so don't
+ // include it. GNU ld doesn't need a numeric argument, but other linkers
+ // do.
+ if sess.opts.optimize == session::Default ||
+ sess.opts.optimize == session::Aggressive {
args.push(~"-Wl,-O1");
}
+ }
- args.push_all([~"-lrt", ~"-ldl"]);
+ add_upstream_rust_crates(&mut args, sess, dylib);
+ add_local_native_libraries(&mut args, sess);
- // LLVM implements the `frem` instruction as a call to `fmod`,
- // which lives in libm. Similar to above, on some linuxes we
- // have to be explicit about linking to it. See #2510
- args.push(~"-lm");
- }
- else if sess.targ_cfg.os == abi::OsAndroid {
- args.push_all([~"-ldl", ~"-llog", ~"-lsupc++", ~"-lgnustl_shared"]);
- args.push(~"-lm");
+ // # Telling the linker what we're doing
+
+ if dylib {
+ // On mac we need to tell the linker to let this library be rpathed
+ if sess.targ_cfg.os == abi::OsMacos {
+ args.push(~"-dynamiclib");
+ args.push(~"-Wl,-dylib");
+ // FIXME (#9639): This needs to handle non-utf8 paths
+ args.push(~"-Wl,-install_name,@rpath/" +
+ out_filename.filename_str().unwrap());
+ } else {
+ args.push(~"-shared")
+ }
}
if sess.targ_cfg.os == abi::OsFreebsd {
- args.push_all([~"-pthread", ~"-lrt",
- ~"-L/usr/local/lib", ~"-lexecinfo",
+ args.push_all([~"-L/usr/local/lib",
~"-L/usr/local/lib/gcc46",
- ~"-L/usr/local/lib/gcc44", ~"-lstdc++",
- ~"-Wl,-z,origin",
- ~"-Wl,-rpath,/usr/local/lib/gcc46",
- ~"-Wl,-rpath,/usr/local/lib/gcc44"]);
+ ~"-L/usr/local/lib/gcc44"]);
}
// Stack growth requires statically linking a __morestack function
args.push(~"-lmorestack");
- // Always want the runtime linked in
- args.push(~"-lrustrt");
+ // FIXME (#2397): At some point we want to rpath our guesses as to
+ // where extern libraries might live, based on the
+ // addl_lib_search_paths
+ args.push_all(rpath::get_rpath_flags(sess, out_filename));
- // FIXME (#2397): At some point we want to rpath our guesses as to where
- // extern libraries might live, based on the addl_lib_search_paths
- args.push_all(rpath::get_rpath_flags(sess, &output));
-
- // Finally add all the linker arguments provided on the command line
+ // Finally add all the linker arguments provided on the command line along
+ // with any #[link_args] attributes found inside the crate
args.push_all(sess.opts.linker_args);
-
+ for arg in cstore::get_used_link_args(sess.cstore).iter() {
+ args.push(arg.clone());
+ }
return args;
}
+
+// # Rust Crate linking
+//
+// Rust crates are not considered at all when creating an rlib output. All
+// dependencies will be linked when producing the final output (instead of
+// the intermediate rlib version)
+fn add_upstream_rust_crates(args: &mut ~[~str], sess: Session,
+ dylib: bool) {
+ // Converts a library file-stem into a cc -l argument
+ fn unlib(config: @session::config, stem: &str) -> ~str {
+ if stem.starts_with("lib") &&
+ config.os != abi::OsWin32 {
+ stem.slice(3, stem.len()).to_owned()
+ } else {
+ stem.to_owned()
+ }
+ }
+
+ let cstore = sess.cstore;
+ if !dylib && !sess.prefer_dynamic() {
+ // With an executable, things get a little interesting. As a limitation
+ // of the current implementation, we require that everything must be
+ // static, or everything must be dynamic. The reasons for this are a
+ // little subtle, but as with the above two cases, the goal is to
+ // prevent duplicate copies of the same library showing up. For example,
+ // a static immediate dependency might show up as an upstream dynamic
+ // dependency and we currently have no way of knowing that. We know that
+ // all dynamic libaries require dynamic dependencies (see above), so
+ // it's satisfactory to include either all static libraries or all
+ // dynamic libraries.
+ let crates = cstore::get_used_crates(cstore,
+ cstore::RequireStatic);
+ if crates.iter().all(|&(_, ref p)| p.is_some()) {
+ for &(cnum, ref path) in crates.iter() {
+ let cratepath = path.clone().unwrap();
+
+ // If we're linking to the static version of the crate, then
+ // we're mostly good to go. The caveat here is that we need to
+ // pull in the static crate's native dependencies.
+ args.push(cratepath.as_str().unwrap().to_owned());
+
+ let libs = csearch::get_native_libraries(sess.cstore, cnum);
+ for lib in libs.iter() {
+ args.push("-l" + *lib);
+ }
+ }
+ return;
+ }
+ }
+
+ // This is a fallback of three differnet cases of linking:
+ //
+ // * When creating a dynamic library, all inputs are required to be dynamic
+ // as well
+ // * If an executable is created with a preference on dynamic linking, then
+ // this case is the fallback
+ // * If an executable is being created, and one of the inputs is missing as
+ // a static library, then this is the fallback case.
+ let crates = cstore::get_used_crates(cstore, cstore::RequireDynamic);
+ for &(cnum, ref path) in crates.iter() {
+ let cratepath = match *path {
+ Some(ref p) => p.clone(), None => {
+ sess.err(format!("could not find dynamic library for: `{}`",
+ cstore::get_crate_data(sess.cstore, cnum).name));
+ return
+ }
+ };
+ // Just need to tell the linker about where the library lives and what
+ // its name is
+ let dir = cratepath.dirname_str().unwrap();
+ if !dir.is_empty() { args.push("-L" + dir); }
+ let libarg = unlib(sess.targ_cfg, cratepath.filestem_str().unwrap());
+ args.push("-l" + libarg);
+ }
+}
+
+// # Native library linking
+//
+// User-supplied library search paths (-L on the cammand line) These are
+// the same paths used to find Rust crates, so some of them may have been
+// added already by the previous crate linking code. This only allows them
+// to be found at compile time so it is still entirely up to outside
+// forces to make sure that library can be found at runtime.
+//
+// Also note that the native libraries linked here are only the ones located
+// in the current crate. Upstream crates with native library dependencies
+// may have their native library pulled in above.
+fn add_local_native_libraries(args: &mut ~[~str], sess: Session) {
+ for path in sess.opts.addl_lib_search_paths.iter() {
+ // FIXME (#9639): This needs to handle non-utf8 paths
+ args.push("-L" + path.as_str().unwrap().to_owned());
+ }
+
+ let rustpath = filesearch::rust_path();
+ for path in rustpath.iter() {
+ // FIXME (#9639): This needs to handle non-utf8 paths
+ args.push("-L" + path.as_str().unwrap().to_owned());
+ }
+
+ for &(ref l, _) in cstore::get_used_libraries(sess.cstore).iter() {
+ args.push(~"-l" + *l);
+ }
+}
target_triple: target_triple,
- cc_args: ~[]
+ cc_args: ~[],
};
}
os != abi::OsWin32
}
-pub fn get_rpath_flags(sess: session::Session, out_filename: &Path)
- -> ~[~str] {
+pub fn get_rpath_flags(sess: session::Session, out_filename: &Path) -> ~[~str] {
let os = sess.targ_cfg.os;
// No rpath on windows
return ~[];
}
+ let mut flags = ~[];
+
+ if sess.targ_cfg.os == abi::OsFreebsd {
+ flags.push_all([~"-Wl,-rpath,/usr/local/lib/gcc46",
+ ~"-Wl,-rpath,/usr/local/lib/gcc44",
+ ~"-Wl,-z,origin"]);
+ }
+
debug!("preparing the RPATH!");
let sysroot = sess.filesearch.sysroot();
let output = out_filename;
- let libs = cstore::get_used_crate_files(sess.cstore);
+ let libs = cstore::get_used_crates(sess.cstore, cstore::RequireDynamic);
+ let libs = libs.move_iter().filter_map(|(_, l)| l.map(|p| p.clone())).collect();
// We don't currently rpath extern libraries, but we know
// where rustrt is and we know every rust program needs it
let libs = vec::append_one(libs, get_sysroot_absolute_rt_lib(sess));
let rpaths = get_rpaths(os, sysroot, output, libs,
sess.opts.target_triple);
- rpaths_to_flags(rpaths)
+ flags.push_all(rpaths_to_flags(rpaths));
+ flags
}
fn get_sysroot_absolute_rt_lib(sess: session::Session) -> Path {
}
pub fn rpaths_to_flags(rpaths: &[~str]) -> ~[~str] {
- // FIXME (#9639): This needs to handle non-utf8 paths
- rpaths.iter().map(|rpath| format!("-Wl,-rpath,{}",*rpath)).collect()
+ let mut ret = ~[];
+ for rpath in rpaths.iter() {
+ ret.push("-Wl,-rpath," + *rpath);
+ }
+ return ret;
}
fn get_rpaths(os: abi::Os,
meta_sect_name: ~str,
data_layout: ~str,
target_triple: ~str,
- cc_args: ~[~str]
+ cc_args: ~[~str],
}
target_triple: target_triple,
- cc_args: ~[~"-m32"]
+ cc_args: ~[~"-m32"],
};
}
target_triple: target_triple,
- cc_args: ~[~"-m64"]
+ cc_args: ~[~"-m64"],
};
}
use back::link;
use back::{arm, x86, x86_64, mips};
-use driver::session::{Aggressive};
+use driver::session::{Aggressive, OutputExecutable};
use driver::session::{Session, Session_, No, Less, Default};
use driver::session;
use front;
mut crate: ast::Crate) -> ast::Crate {
let time_passes = sess.time_passes();
- *sess.building_library = session::building_library(sess.opts.crate_type,
- &crate, sess.opts.test);
+ *sess.building_library = session::building_library(sess.opts, &crate);
+ let want_exe = sess.opts.outputs.iter().any(|&o| o == OutputExecutable);
+ if *sess.building_library && want_exe {
+ sess.err("cannot build both a library and an executable");
+ }
time(time_passes, "gated feature checking", (), |_|
front::feature_gate::check_crate(sess, &crate));
syntax::ast_map::map_crate(sess.diagnostic(), crate));
time(time_passes, "external crate/lib resolution", (), |_|
- creader::read_crates(sess.diagnostic(), crate, sess.cstore,
- sess.filesearch,
+ creader::read_crates(sess, crate,
session::sess_os_to_meta_os(sess.targ_cfg.os),
- sess.opts.is_static,
token::get_ident_interner()));
let lang_items = time(time_passes, "language item collection", (), |_|
pub struct CrateTranslation {
context: ContextRef,
module: ModuleRef,
- link: LinkMeta
+ link: LinkMeta,
+ crate_types: ~[~str],
}
/// Run the translation phase to LLVM, after which the AST and analysis can
outputs: &OutputFilenames) {
time(sess.time_passes(), "linking", (), |_|
link::link_binary(sess,
+ trans.crate_types,
&outputs.obj_filename,
&outputs.out_filename,
trans.link));
return true;
}
- if sess.opts.is_static && *sess.building_library {
- debug!("building static library, returning early from compile_input");
- return true;
- }
-
if sess.opts.jit {
debug!("running JIT, returning early from compile_input");
return true;
matches: &getopts::Matches,
demitter: @diagnostic::Emitter)
-> @session::options {
- let crate_type = if matches.opt_present("lib") {
- session::lib_crate
- } else if matches.opt_present("bin") {
- session::bin_crate
- } else {
- session::unknown_crate
- };
+ let mut outputs = ~[];
+ if matches.opt_present("rlib") {
+ outputs.push(session::OutputRlib)
+ }
+ if matches.opt_present("staticlib") {
+ outputs.push(session::OutputStaticlib)
+ }
+ // dynamic libraries are the "compiler blesssed" default library
+ if matches.opt_present("dylib") || matches.opt_present("lib") {
+ outputs.push(session::OutputDylib)
+ }
+ if matches.opt_present("bin") {
+ outputs.push(session::OutputExecutable)
+ }
+
let parse_only = matches.opt_present("parse-only");
let no_trans = matches.opt_present("no-trans");
let debuginfo = debugging_opts & session::debug_info != 0 ||
extra_debuginfo;
- let statik = debugging_opts & session::statik != 0;
-
let addl_lib_search_paths = matches.opt_strs("L").map(|s| {
- Path::init(s.as_slice())
+ Path::init(s.as_slice())
}).move_iter().collect();
+ let ar = matches.opt_str("ar");
let linker = matches.opt_str("linker");
let linker_args = matches.opt_strs("link-args").flat_map( |a| {
a.split(' ').map(|arg| arg.to_owned()).collect()
};
let sopts = @session::options {
- crate_type: crate_type,
- is_static: statik,
+ outputs: outputs,
gc: gc,
optimize: opt_level,
custom_passes: custom_passes,
jit: jit,
output_type: output_type,
addl_lib_search_paths: @mut addl_lib_search_paths,
+ ar: ar,
linker: linker,
linker_args: linker_args,
maybe_sysroot: sysroot_opt,
// rustc command line options
pub fn optgroups() -> ~[getopts::groups::OptGroup] {
~[
- optflag("", "bin", "Compile an executable crate (default)"),
optflag("c", "", "Compile and assemble, but do not link"),
optmulti("", "cfg", "Configure the compilation
environment", "SPEC"),
optflag("h", "help","Display this message"),
optmulti("L", "", "Add a directory to the library search path",
"PATH"),
- optflag("", "lib", "Compile a library crate"),
+ optflag("", "bin", "Compile an executable crate (default)"),
+ optflag("", "lib", "Compile a rust library crate using the compiler's default"),
+ optflag("", "rlib", "Compile a rust library crate as an rlib file"),
+ optflag("", "staticlib", "Compile a static library crate"),
+ optflag("", "dylib", "Compile a dynamic library crate"),
optopt("", "linker", "Program to use for linking instead of the default.", "LINKER"),
+ optopt("", "ar", "Program to use for managing archives instead of the default.", "AR"),
optmulti("", "link-args", "FLAGS is a space-separated list of flags
passed to the linker", "FLAGS"),
optflag("", "ls", "List the symbols defined by a library crate"),
let obj_path;
let out_path;
let sopts = sess.opts;
- let stop_after_codegen =
- sopts.output_type != link::output_type_exe ||
- sopts.is_static && *sess.building_library;
-
- let obj_suffix =
- match sopts.output_type {
- link::output_type_none => ~"none",
- link::output_type_bitcode => ~"bc",
- link::output_type_assembly => ~"s",
- link::output_type_llvm_assembly => ~"ll",
- // Object and exe output both use the '.o' extension here
- link::output_type_object | link::output_type_exe => ~"o"
- };
+ let stop_after_codegen = sopts.output_type != link::output_type_exe;
+
+ let obj_suffix = match sopts.output_type {
+ link::output_type_none => ~"none",
+ link::output_type_bitcode => ~"bc",
+ link::output_type_assembly => ~"s",
+ link::output_type_llvm_assembly => ~"ll",
+ // Object and exe output both use the '.o' extension here
+ link::output_type_object | link::output_type_exe => ~"o"
+ };
match *ofile {
None => {
pub fn list_metadata(sess: Session, path: &Path, out: @mut io::Writer) {
metadata::loader::list_file_metadata(
+ sess,
token::get_ident_interner(),
session::sess_os_to_meta_os(sess.targ_cfg.os), path, out);
}
use back::target_strs;
use back;
use driver::driver::host_triple;
-use driver::session;
use metadata::filesearch;
use metadata;
use middle::lint;
use std::hashmap::{HashMap,HashSet};
-#[deriving(Clone)]
-pub enum crate_type {
- bin_crate,
- lib_crate,
- unknown_crate,
-}
-
pub struct config {
os: abi::Os,
arch: abi::Architecture,
pub static jit: uint = 1 << 18;
pub static debug_info: uint = 1 << 19;
pub static extra_debug_info: uint = 1 << 20;
-pub static statik: uint = 1 << 21;
-pub static print_link_args: uint = 1 << 22;
-pub static no_debug_borrows: uint = 1 << 23;
-pub static lint_llvm: uint = 1 << 24;
-pub static print_llvm_passes: uint = 1 << 25;
-pub static no_vectorize_loops: uint = 1 << 26;
-pub static no_vectorize_slp: uint = 1 << 27;
-pub static no_prepopulate_passes: uint = 1 << 28;
-pub static use_softfp: uint = 1 << 29;
-pub static gen_crate_map: uint = 1 << 30;
+pub static print_link_args: uint = 1 << 21;
+pub static no_debug_borrows: uint = 1 << 22;
+pub static lint_llvm: uint = 1 << 23;
+pub static print_llvm_passes: uint = 1 << 24;
+pub static no_vectorize_loops: uint = 1 << 25;
+pub static no_vectorize_slp: uint = 1 << 26;
+pub static no_prepopulate_passes: uint = 1 << 27;
+pub static use_softfp: uint = 1 << 28;
+pub static gen_crate_map: uint = 1 << 29;
+pub static prefer_dynamic: uint = 1 << 30;
pub fn debugging_opts_map() -> ~[(&'static str, &'static str, uint)] {
~[("verbose", "in general, enable more debug printouts", verbose),
("extra-debug-info", "Extra debugging info (experimental)",
extra_debug_info),
("debug-info", "Produce debug info (experimental)", debug_info),
- ("static", "Use or produce static libraries or binaries (experimental)", statik),
("no-debug-borrows",
"do not show where borrow checks fail",
no_debug_borrows),
no_vectorize_slp),
("soft-float", "Generate software floating point library calls", use_softfp),
("gen-crate-map", "Force generation of a toplevel crate map", gen_crate_map),
+ ("prefer-dynamic", "Prefer dynamic linking to static linking", prefer_dynamic),
]
}
pub struct options {
// The crate config requested for the session, which may be combined
// with additional crate configurations during the compile process
- crate_type: crate_type,
- is_static: bool,
+ outputs: ~[OutputStyle],
+
gc: bool,
optimize: OptLevel,
custom_passes: ~[~str],
addl_lib_search_paths: @mut HashSet<Path>, // This is mutable for rustpkg, which
// updates search paths based on the
// parsed code
+ ar: Option<~str>,
linker: Option<~str>,
linker_args: ~[~str],
maybe_sysroot: Option<@Path>,
EntryNone,
}
+#[deriving(Eq, Clone)]
+pub enum OutputStyle {
+ OutputExecutable,
+ OutputDylib,
+ OutputRlib,
+ OutputStaticlib,
+}
+
pub struct Session_ {
targ_cfg: @config,
opts: @options,
pub fn gen_crate_map(&self) -> bool {
self.debugging_opt(gen_crate_map)
}
+ pub fn prefer_dynamic(&self) -> bool {
+ self.debugging_opt(prefer_dynamic)
+ }
// pointless function, now...
pub fn str_of(&self, id: ast::Ident) -> @str {
/// Some reasonable defaults
pub fn basic_options() -> @options {
@options {
- crate_type: session::lib_crate,
- is_static: false,
+ outputs: ~[],
gc: false,
optimize: No,
custom_passes: ~[],
jit: false,
output_type: link::output_type_exe,
addl_lib_search_paths: @mut HashSet::new(),
+ ar: None,
linker: None,
linker_args: ~[],
maybe_sysroot: None,
diagnostic::expect(sess.diagnostic(), opt, msg)
}
-pub fn building_library(req_crate_type: crate_type,
- crate: &ast::Crate,
- testing: bool) -> bool {
- match req_crate_type {
- bin_crate => false,
- lib_crate => true,
- unknown_crate => {
- if testing {
- false
- } else {
- match syntax::attr::first_attr_value_str_by_name(
- crate.attrs,
- "crate_type") {
- Some(s) => "lib" == s,
- _ => false
- }
+pub fn building_library(options: &options, crate: &ast::Crate) -> bool {
+ for output in options.outputs.iter() {
+ match *output {
+ OutputExecutable => {}
+ OutputStaticlib | OutputDylib | OutputRlib => return true
}
- }
+ }
+ if options.test { return false }
+ match syntax::attr::first_attr_value_str_by_name(crate.attrs, "crate_type") {
+ Some(s) => "lib" == s || "rlib" == s || "dylib" == s || "staticlib" == s,
+ _ => false
}
}
use middle::lint;
use syntax::ast;
+use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
use syntax::visit;
("managed_boxes", Active),
("non_ascii_idents", Active),
("thread_local", Active),
+ ("link_args", Active),
// These are used to test this portion of the compiler, they don't actually
// mean anything
fn visit_item(&mut self, i: @ast::item, _:()) {
for attr in i.attrs.iter() {
- if "thread_local" == attr.name() {
+ if "thread_local" == attr.name() &&
+ cfg!(stage0, remove_this_on_next_snapshot) { // NOTE: snap rem
self.gate_feature("thread_local", i.span,
"`#[thread_local]` is an experimental feature, and does not \
currently handle destructors. There is no corresponding \
}
}
+ ast::item_foreign_mod(*) => {
+ if attr::contains_name(i.attrs, "link_args") &&
+ cfg!(stage0, remove_this_on_next_snapshot) { // NOTE: snap
+ self.gate_feature("link_args", i.span,
+ "the `link_args` attribute is not portable \
+ across platforms, it is recommended to \
+ use `#[link(name = \"foo\")]` instead")
+ }
+ }
+
_ => {}
}
#[comment = "The Rust compiler"];
#[license = "MIT/ASL2"];
-#[crate_type = "lib"];
+#[crate_type = "lib"]; // NOTE: remove after stage0 snapshot
+#[crate_type = "dylib"];
#[feature(macro_rules, globs, struct_variant, managed_boxes)];
}
pub mod back {
+ pub mod archive;
pub mod link;
pub mod abi;
pub mod upcall;
use std::hashmap::HashMap;
use std::libc::{c_uint, c_ushort, c_void, free};
use std::str::raw::from_c_str;
-use std::option;
use middle::trans::type_::Type;
use super::{ValueRef, TargetMachineRef, FileType};
use super::{CodeGenModel, RelocMode, CodeGenOptLevel};
use super::debuginfo::*;
- use std::libc::{c_char, c_int, c_longlong, c_ushort, c_uint, c_ulonglong};
+ use std::libc::{c_char, c_int, c_longlong, c_ushort, c_uint, c_ulonglong,
+ size_t};
+ #[cfg(stage0)]
#[link_args = "-lrustllvm"]
+ extern {}
+ #[cfg(not(stage0))] // if you're deleting this, put this on the block below
+ #[link(name = "rustllvm")]
+ extern {}
+
extern {
/* Create and destroy contexts. */
pub fn LLVMContextCreate() -> ContextRef;
LLVMDisposeMemoryBuffer() to get rid of it. */
pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(Path: *c_char)
-> MemoryBufferRef;
+ /** Borrows the contents of the memory buffer (doesn't copy it) */
+ pub fn LLVMCreateMemoryBufferWithMemoryRange(InputData: *c_char,
+ InputDataLength: size_t,
+ BufferName: *c_char,
+ RequiresNull: Bool)
+ -> MemoryBufferRef;
+ pub fn LLVMCreateMemoryBufferWithMemoryRangeCopy(InputData: *c_char,
+ InputDataLength: size_t,
+ BufferName: *c_char)
+ -> MemoryBufferRef;
/** Returns a string describing the last error caused by an LLVMRust*
call. */
/* Memory-managed interface to object files. */
-pub struct object_file_res {
- ObjectFile: ObjectFileRef,
+pub struct ObjectFile {
+ llof: ObjectFileRef,
}
-impl Drop for object_file_res {
- fn drop(&mut self) {
+impl ObjectFile {
+ // This will take ownership of llmb
+ pub fn new(llmb: MemoryBufferRef) -> Option<ObjectFile> {
unsafe {
- llvm::LLVMDisposeObjectFile(self.ObjectFile);
+ let llof = llvm::LLVMCreateObjectFile(llmb);
+ if llof as int == 0 {
+ llvm::LLVMDisposeMemoryBuffer(llmb);
+ return None
+ }
+
+ Some(ObjectFile {
+ llof: llof,
+ })
}
}
}
-pub fn object_file_res(ObjFile: ObjectFileRef) -> object_file_res {
- object_file_res {
- ObjectFile: ObjFile
- }
-}
-
-pub struct ObjectFile {
- llof: ObjectFileRef,
- dtor: @object_file_res
-}
-
-pub fn mk_object_file(llmb: MemoryBufferRef) -> Option<ObjectFile> {
- unsafe {
- let llof = llvm::LLVMCreateObjectFile(llmb);
- if llof as int == 0 { return option::None::<ObjectFile>; }
-
- option::Some(ObjectFile {
- llof: llof,
- dtor: @object_file_res(llof)
- })
+impl Drop for ObjectFile {
+ fn drop(&mut self) {
+ unsafe {
+ llvm::LLVMDisposeObjectFile(self.llof);
+ }
}
}
pub static tag_region_param_def_ident: uint = 0x101;
pub static tag_region_param_def_def_id: uint = 0x102;
+pub static tag_native_libraries: uint = 0x103;
+pub static tag_native_libraries_lib: uint = 0x104;
pub struct LinkMeta {
name: @str,
//! Validates all used crates and extern libraries and loads their metadata
-
+use driver::session::Session;
use metadata::cstore;
use metadata::decoder;
-use metadata::filesearch::FileSearch;
use metadata::loader;
use std::hashmap::HashMap;
// Traverses an AST, reading all the information about use'd crates and extern
// libraries necessary for later resolving, typechecking, linking, etc.
-pub fn read_crates(diag: @mut span_handler,
+pub fn read_crates(sess: Session,
crate: &ast::Crate,
- cstore: @mut cstore::CStore,
- filesearch: @FileSearch,
os: loader::Os,
- statik: bool,
intr: @ident_interner) {
let e = @mut Env {
- diag: diag,
- filesearch: filesearch,
- cstore: cstore,
+ sess: sess,
os: os,
- statik: statik,
crate_cache: @mut ~[],
next_crate_num: 1,
intr: intr
visit_crate(e, crate);
visit::walk_crate(&mut v, crate, ());
dump_crates(*e.crate_cache);
- warn_if_multiple_versions(e, diag, *e.crate_cache);
+ warn_if_multiple_versions(e, sess.diagnostic(), *e.crate_cache);
}
struct ReadCrateVisitor { e:@mut Env }
}
struct Env {
- diag: @mut span_handler,
- filesearch: @FileSearch,
- cstore: @mut cstore::CStore,
+ sess: Session,
os: loader::Os,
- statik: bool,
crate_cache: @mut ~[cache_entry],
next_crate_num: ast::CrateNum,
intr: @ident_interner
}
fn visit_crate(e: &Env, c: &ast::Crate) {
- let cstore = e.cstore;
+ let cstore = e.sess.cstore;
for a in c.attrs.iter().filter(|m| "link_args" == m.name()) {
match a.value_str() {
let p_path = Path::init(p);
match p_path.filestem_str() {
None|Some("") =>
- e.diag.span_bug(i.span, "Bad package path in `extern mod` item"),
+ e.sess.span_bug(i.span, "Bad package path in `extern mod` item"),
Some(s) =>
vec::append(
~[attr::mk_name_value_item_str(@"package_id", p),
meta_items,
@"",
i.span);
- cstore::add_extern_mod_stmt_cnum(e.cstore, id, cnum);
+ cstore::add_extern_mod_stmt_cnum(e.sess.cstore, id, cnum);
}
_ => ()
}
fn visit_item(e: &Env, i: @ast::item) {
match i.node {
- ast::item_foreign_mod(ref fm) => {
- if fm.abis.is_rust() || fm.abis.is_intrinsic() {
- return;
- }
-
- let cstore = e.cstore;
- let link_args = i.attrs.iter()
- .filter_map(|at| if "link_args" == at.name() {Some(at)} else {None})
- .collect::<~[&ast::Attribute]>();
-
- // XXX: two whom it may concern, this was the old logic applied to the
- // ast's extern mod blocks which had names (we used to allow
- // "extern mod foo"). This code was never run for anonymous blocks,
- // and we now only have anonymous blocks. We're still in the midst
- // of figuring out what the exact operations we'd like to support
- // when linking external modules, but I wanted to leave this logic
- // here for the time beging to refer back to it
-
- //let mut already_added = false;
- //let link_name = i.attrs.iter()
- // .find(|at| "link_name" == at.name())
- // .and_then(|at| at.value_str());
+ ast::item_foreign_mod(ref fm) => {
+ if fm.abis.is_rust() || fm.abis.is_intrinsic() {
+ return;
+ }
- //let foreign_name = match link_name {
- // Some(nn) => {
- // if nn.is_empty() {
- // e.diag.span_fatal(
- // i.span,
- // "empty #[link_name] not allowed; use \
- // #[nolink].");
- // }
- // nn
- // }
- // None => token::ident_to_str(&i.ident)
- // };
- //if !attr::contains_name(i.attrs, "nolink") {
- // already_added =
- // !cstore::add_used_library(cstore, foreign_name);
- //}
- //if !link_args.is_empty() && already_added {
- // e.diag.span_fatal(i.span, ~"library '" + foreign_name +
- // "' already added: can't specify link_args.");
- //}
+ // First, add all of the custom link_args attributes
+ let cstore = e.sess.cstore;
+ let link_args = i.attrs.iter()
+ .filter_map(|at| if "link_args" == at.name() {Some(at)} else {None})
+ .to_owned_vec();
+ for m in link_args.iter() {
+ match m.value_str() {
+ Some(linkarg) => {
+ cstore::add_used_link_args(cstore, linkarg);
+ }
+ None => { /* fallthrough */ }
+ }
+ }
- for m in link_args.iter() {
- match m.value_str() {
- Some(linkarg) => {
- cstore::add_used_link_args(cstore, linkarg);
+ // Next, process all of the #[link(..)]-style arguments
+ let cstore = e.sess.cstore;
+ let link_args = i.attrs.iter()
+ .filter_map(|at| if "link" == at.name() {Some(at)} else {None})
+ .to_owned_vec();
+ for m in link_args.iter() {
+ match m.meta_item_list() {
+ Some(items) => {
+ let kind = do items.iter().find |k| {
+ "kind" == k.name()
+ }.and_then(|a| a.value_str());
+ let kind = match kind {
+ Some(k) if "static" == k => cstore::NativeStatic,
+ Some(k) => {
+ e.sess.span_fatal(i.span,
+ format!("unknown kind: `{}`", k));
+ }
+ None => cstore::NativeUnknown
+ };
+ let n = do items.iter().find |n| {
+ "name" == n.name()
+ }.and_then(|a| a.value_str());
+ let n = match n {
+ Some(n) => n,
+ None => {
+ e.sess.span_fatal(i.span,
+ "#[link(...)] specified without \
+ `name = \"foo\"`");
+ }
+ };
+ cstore::add_used_library(cstore, n.to_owned(), kind);
+ }
+ None => {}
}
- None => { /* fallthrough */ }
}
}
- }
- _ => { }
+ _ => { }
}
}
match existing_match(e, metas, hash) {
None => {
let load_ctxt = loader::Context {
- diag: e.diag,
- filesearch: e.filesearch,
+ sess: e.sess,
span: span,
ident: ident,
metas: metas,
hash: hash,
os: e.os,
- is_static: e.statik,
intr: e.intr
};
- let (lident, ldata) = loader::load_library_crate(&load_ctxt);
+ let loader::Library {
+ dylib, rlib, metadata
+ } = load_ctxt.load_library_crate();
- let cfilename = Path::init(lident);
- let cdata = ldata;
-
- let attrs = decoder::get_crate_attributes(cdata);
+ let attrs = decoder::get_crate_attributes(metadata);
let linkage_metas = attr::find_linkage_metas(attrs);
- let hash = decoder::get_crate_hash(cdata);
+ let hash = decoder::get_crate_hash(metadata);
// Claim this crate number and cache it
let cnum = e.next_crate_num;
e.next_crate_num += 1;
// Now resolve the crates referenced by this crate
- let cnum_map = resolve_crate_deps(e, cdata);
+ let cnum_map = resolve_crate_deps(e, metadata);
let cname =
match attr::last_meta_item_value_str_by_name(load_ctxt.metas,
};
let cmeta = @cstore::crate_metadata {
name: cname,
- data: cdata,
+ data: metadata,
cnum_map: cnum_map,
cnum: cnum
};
- let cstore = e.cstore;
+ let cstore = e.sess.cstore;
cstore::set_crate_data(cstore, cnum, cmeta);
- cstore::add_used_crate_file(cstore, &cfilename);
+ cstore::add_used_crate_source(cstore, cstore::CrateSource {
+ dylib: dylib,
+ rlib: rlib,
+ cnum: cnum,
+ });
return cnum;
}
Some(cnum) => {
decoder::get_item_visibility(cdata, def_id.node)
}
+pub fn get_native_libraries(cstore: @mut cstore::CStore,
+ crate_num: ast::CrateNum) -> ~[~str] {
+ let cdata = cstore::get_crate_data(cstore, crate_num);
+ decoder::get_native_libraries(cdata)
+}
+
pub fn each_impl(cstore: @mut cstore::CStore,
crate_num: ast::CrateNum,
callback: |ast::DefId|) {
cnum: ast::CrateNum
}
+#[deriving(Eq)]
+pub enum LinkagePreference {
+ RequireDynamic,
+ RequireStatic,
+}
+
+#[deriving(Eq)]
+pub enum NativeLibaryKind {
+ NativeStatic,
+ NativeUnknown,
+}
+
+// Where a crate came from on the local filesystem. One of these two options
+// must be non-None.
+#[deriving(Eq)]
+pub struct CrateSource {
+ dylib: Option<Path>,
+ rlib: Option<Path>,
+ cnum: ast::CrateNum,
+}
+
pub struct CStore {
priv metas: HashMap <ast::CrateNum, @crate_metadata>,
priv extern_mod_crate_map: extern_mod_crate_map,
- priv used_crate_files: ~[Path],
- priv used_libraries: ~[@str],
- priv used_link_args: ~[@str],
+ priv used_crate_sources: ~[CrateSource],
+ priv used_libraries: ~[(~str, NativeLibaryKind)],
+ priv used_link_args: ~[~str],
intr: @ident_interner
}
return CStore {
metas: HashMap::new(),
extern_mod_crate_map: HashMap::new(),
- used_crate_files: ~[],
+ used_crate_sources: ~[],
used_libraries: ~[],
used_link_args: ~[],
intr: intr
}
}
-pub fn add_used_crate_file(cstore: &mut CStore, lib: &Path) {
- if !cstore.used_crate_files.contains(lib) {
- cstore.used_crate_files.push((*lib).clone());
+pub fn add_used_crate_source(cstore: &mut CStore, src: CrateSource) {
+ if !cstore.used_crate_sources.contains(&src) {
+ cstore.used_crate_sources.push(src);
}
}
-pub fn get_used_crate_files(cstore: &CStore) -> ~[Path] {
- // XXX(pcwalton): Bad copy.
- return cstore.used_crate_files.clone();
+pub fn get_used_crate_sources<'a>(cstore: &'a CStore) -> &'a [CrateSource] {
+ cstore.used_crate_sources.as_slice()
+}
+
+pub fn get_used_crates(cstore: &CStore, prefer: LinkagePreference)
+ -> ~[(ast::CrateNum, Option<Path>)]
+{
+ let mut ret = ~[];
+ for src in cstore.used_crate_sources.iter() {
+ ret.push((src.cnum, match prefer {
+ RequireDynamic => src.dylib.clone(),
+ RequireStatic => src.rlib.clone(),
+ }));
+ }
+ return ret;
}
-pub fn add_used_library(cstore: &mut CStore, lib: @str) -> bool {
+pub fn add_used_library(cstore: &mut CStore,
+ lib: ~str, kind: NativeLibaryKind) -> bool {
assert!(!lib.is_empty());
- if cstore.used_libraries.iter().any(|x| x == &lib) { return false; }
- cstore.used_libraries.push(lib);
+ if cstore.used_libraries.iter().any(|&(ref x, _)| x == &lib) { return false; }
+ cstore.used_libraries.push((lib, kind));
true
}
-pub fn get_used_libraries<'a>(cstore: &'a CStore) -> &'a [@str] {
- let slice: &'a [@str] = cstore.used_libraries;
- slice
+pub fn get_used_libraries<'a>(cstore: &'a CStore) -> &'a [(~str, NativeLibaryKind)] {
+ cstore.used_libraries.as_slice()
}
pub fn add_used_link_args(cstore: &mut CStore, args: &str) {
for s in args.split(' ') {
- cstore.used_link_args.push(s.to_managed());
+ cstore.used_link_args.push(s.to_owned());
}
}
-pub fn get_used_link_args<'a>(cstore: &'a CStore) -> &'a [@str] {
- let slice: &'a [@str] = cstore.used_link_args;
- slice
+pub fn get_used_link_args<'a>(cstore: &'a CStore) -> &'a [~str] {
+ cstore.used_link_args.as_slice()
}
pub fn add_extern_mod_stmt_cnum(cstore: &mut CStore,
}
}
+
+pub fn get_native_libraries(cdata: Cmd) -> ~[~str] {
+ let libraries = reader::get_doc(reader::Doc(cdata.data), tag_native_libraries);
+ let mut result = ~[];
+ do reader::tagged_docs(libraries, tag_native_libraries_lib) |lib_doc| {
+ result.push(lib_doc.as_str());
+ true
+ };
+ return result;
+}
attr_bytes: u64,
dep_bytes: u64,
lang_item_bytes: u64,
+ native_lib_bytes: u64,
impl_bytes: u64,
misc_bytes: u64,
item_bytes: u64,
ebml_w.end_tag(); // tag_lang_items
}
+fn encode_native_libraries(ecx: &EncodeContext, ebml_w: &mut writer::Encoder) {
+ ebml_w.start_tag(tag_native_libraries);
+
+ for &(ref lib, kind) in cstore::get_used_libraries(ecx.cstore).iter() {
+ match kind {
+ cstore::NativeStatic => {} // these libraries are not propagated
+ cstore::NativeUnknown => {
+ ebml_w.start_tag(tag_native_libraries_lib);
+ ebml_w.writer.write(lib.as_bytes());
+ ebml_w.end_tag();
+ }
+ }
+ }
+
+ ebml_w.end_tag();
+}
+
struct ImplVisitor<'self> {
ecx: &'self EncodeContext<'self>,
ebml_w: &'self mut writer::Encoder,
attr_bytes: 0,
dep_bytes: 0,
lang_item_bytes: 0,
+ native_lib_bytes: 0,
impl_bytes: 0,
misc_bytes: 0,
item_bytes: 0,
encode_lang_items(&ecx, &mut ebml_w);
ecx.stats.lang_item_bytes = wr.tell() - i;
+ // Encode the native libraries used
+ i = wr.tell();
+ encode_native_libraries(&ecx, &mut ebml_w);
+ ecx.stats.native_lib_bytes = wr.tell() - i;
+
// Encode the def IDs of impls, for coherence checking.
i = wr.tell();
encode_impls(&ecx, crate, &mut ebml_w);
println!(" attribute bytes: {}", ecx.stats.attr_bytes);
println!(" dep bytes: {}", ecx.stats.dep_bytes);
println!(" lang item bytes: {}", ecx.stats.lang_item_bytes);
+ println!(" native bytes: {}", ecx.stats.native_lib_bytes);
println!(" impl bytes: {}", ecx.stats.impl_bytes);
println!(" misc bytes: {}", ecx.stats.misc_bytes);
println!(" item bytes: {}", ecx.stats.item_bytes);
//! Finds crate binaries and loads their metadata
-
-use lib::llvm::{False, llvm, mk_object_file, mk_section_iter};
+use back::archive::Archive;
+use driver::session::Session;
+use lib::llvm::{False, llvm, ObjectFile, mk_section_iter};
use metadata::decoder;
use metadata::encoder;
-use metadata::filesearch::{FileSearch, FileMatch, FileMatches, FileDoesntMatch};
+use metadata::filesearch::{FileMatches, FileDoesntMatch};
use metadata::filesearch;
use syntax::codemap::Span;
use syntax::diagnostic::span_handler;
use std::c_str::ToCStr;
use std::cast;
use std::io;
+use std::libc;
use std::num;
use std::option;
use std::os::consts::{macos, freebsd, linux, android, win32};
}
pub struct Context {
- diag: @mut span_handler,
- filesearch: @FileSearch,
+ sess: Session,
span: Span,
ident: @str,
metas: ~[@ast::MetaItem],
hash: @str,
os: Os,
- is_static: bool,
intr: @ident_interner
}
-pub fn load_library_crate(cx: &Context) -> (~str, @~[u8]) {
- match find_library_crate(cx) {
- Some(t) => t,
- None => {
- cx.diag.span_fatal(cx.span,
- format!("can't find crate for `{}`",
- cx.ident));
- }
- }
+pub struct Library {
+ dylib: Option<Path>,
+ rlib: Option<Path>,
+ metadata: @~[u8],
}
-fn find_library_crate(cx: &Context) -> Option<(~str, @~[u8])> {
- attr::require_unique_names(cx.diag, cx.metas);
- find_library_crate_aux(cx, libname(cx), cx.filesearch)
-}
+impl Context {
+ pub fn load_library_crate(&self) -> Library {
+ match self.find_library_crate() {
+ Some(t) => t,
+ None => {
+ self.sess.span_fatal(self.span,
+ format!("can't find crate for `{}`",
+ self.ident));
+ }
+ }
+ }
-fn libname(cx: &Context) -> (~str, ~str) {
- if cx.is_static { return (~"lib", ~".rlib"); }
- let (dll_prefix, dll_suffix) = match cx.os {
- OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
- OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
- OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
- OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX),
- OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
- };
+ fn find_library_crate(&self) -> Option<Library> {
+ attr::require_unique_names(self.sess.diagnostic(), self.metas);
+ let filesearch = self.sess.filesearch;
+ let crate_name = crate_name_from_metas(self.metas);
+ let (dyprefix, dysuffix) = self.dylibname();
- (dll_prefix.to_owned(), dll_suffix.to_owned())
-}
+ // want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
+ let dylib_prefix = format!("{}{}-", dyprefix, crate_name);
+ let rlib_prefix = format!("lib{}-", crate_name);
-fn find_library_crate_aux(
- cx: &Context,
- (prefix, suffix): (~str, ~str),
- filesearch: @filesearch::FileSearch
-) -> Option<(~str, @~[u8])> {
- let crate_name = crate_name_from_metas(cx.metas);
- // want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
- let prefix = format!("{}{}-", prefix, crate_name);
- let mut matches = ~[];
- filesearch::search(filesearch, |path| -> FileMatch {
- // FIXME (#9639): This needs to handle non-utf8 paths
- let path_str = path.filename_str();
- match path_str {
- None => FileDoesntMatch,
- Some(path_str) =>
- if path_str.starts_with(prefix) && path_str.ends_with(suffix) {
- debug!("{} is a candidate", path.display());
- match get_metadata_section(cx.os, path) {
- Some(cvec) =>
- if !crate_matches(cvec, cx.metas, cx.hash) {
- debug!("skipping {}, metadata doesn't match",
- path.display());
- FileDoesntMatch
- } else {
- debug!("found {} with matching metadata", path.display());
- // FIXME (#9639): This needs to handle non-utf8 paths
- matches.push((path.as_str().unwrap().to_owned(), cvec));
- FileMatches
- },
- _ => {
- debug!("could not load metadata for {}", path.display());
- FileDoesntMatch
- }
- }
- }
- else {
- FileDoesntMatch
- }
- }
- });
+ let mut matches = ~[];
+ do filesearch::search(filesearch) |path| {
+ match path.filename_str() {
+ None => FileDoesntMatch,
+ Some(file) => {
+ let (candidate, existing) = if file.starts_with(rlib_prefix) &&
+ file.ends_with(".rlib") {
+ debug!("{} is an rlib candidate", path.display());
+ (true, self.add_existing_rlib(matches, path, file))
+ } else if file.starts_with(dylib_prefix) &&
+ file.ends_with(dysuffix) {
+ debug!("{} is a dylib candidate", path.display());
+ (true, self.add_existing_dylib(matches, path, file))
+ } else {
+ (false, false)
+ };
- match matches.len() {
- 0 => None,
- 1 => Some(matches[0]),
- _ => {
- cx.diag.span_err(
- cx.span, format!("multiple matching crates for `{}`", crate_name));
- cx.diag.handler().note("candidates:");
- for pair in matches.iter() {
- let ident = pair.first();
- let data = pair.second();
- cx.diag.handler().note(format!("path: {}", ident));
- let attrs = decoder::get_crate_attributes(data);
- note_linkage_attrs(cx.intr, cx.diag, attrs);
+ if candidate && existing {
+ FileMatches
+ } else if candidate {
+ match get_metadata_section(self.sess, self.os, path,
+ crate_name) {
+ Some(cvec) =>
+ if crate_matches(cvec, self.metas, self.hash) {
+ debug!("found {} with matching metadata",
+ path.display());
+ let (rlib, dylib) = if file.ends_with(".rlib") {
+ (Some(path.clone()), None)
+ } else {
+ (None, Some(path.clone()))
+ };
+ matches.push(Library {
+ rlib: rlib,
+ dylib: dylib,
+ metadata: cvec,
+ });
+ FileMatches
+ } else {
+ debug!("skipping {}, metadata doesn't match",
+ path.display());
+ FileDoesntMatch
+ },
+ _ => {
+ debug!("could not load metadata for {}",
+ path.display());
+ FileDoesntMatch
+ }
+ }
+ } else {
+ FileDoesntMatch
+ }
}
- cx.diag.handler().abort_if_errors();
+ }
+ }
+
+ match matches.len() {
+ 0 => None,
+ 1 => Some(matches[0]),
+ _ => {
+ self.sess.span_err(self.span,
+ format!("multiple matching crates for `{}`", crate_name));
+ self.sess.note("candidates:");
+ for lib in matches.iter() {
+ match lib.dylib {
+ Some(ref p) => {
+ self.sess.note(format!("path: {}", p.display()));
+ }
+ None => {}
+ }
+ match lib.rlib {
+ Some(ref p) => {
+ self.sess.note(format!("path: {}", p.display()));
+ }
+ None => {}
+ }
+ let attrs = decoder::get_crate_attributes(lib.metadata);
+ note_linkage_attrs(self.intr, self.sess.diagnostic(), attrs);
+ }
+ self.sess.abort_if_errors();
None
+ }
+ }
+ }
+
+ fn add_existing_rlib(&self, libs: &mut [Library],
+ path: &Path, file: &str) -> bool {
+ let (prefix, suffix) = self.dylibname();
+ let file = file.slice_from(3); // chop off 'lib'
+ let file = file.slice_to(file.len() - 5); // chop off '.rlib'
+ let file = format!("{}{}{}", prefix, file, suffix);
+
+ for lib in libs.mut_iter() {
+ match lib.dylib {
+ Some(ref p) if p.filename_str() == Some(file.as_slice()) => {
+ assert!(lib.rlib.is_none()); // XXX: legit compiler error
+ lib.rlib = Some(path.clone());
+ return true;
+ }
+ Some(*) | None => {}
+ }
+ }
+ return false;
+ }
+
+ fn add_existing_dylib(&self, libs: &mut [Library],
+ path: &Path, file: &str) -> bool {
+ let (prefix, suffix) = self.dylibname();
+ let file = file.slice_from(prefix.len());
+ let file = file.slice_to(file.len() - suffix.len());
+ let file = format!("lib{}.rlib", file);
+
+ for lib in libs.mut_iter() {
+ match lib.rlib {
+ Some(ref p) if p.filename_str() == Some(file.as_slice()) => {
+ assert!(lib.dylib.is_none()); // XXX: legit compiler error
+ lib.dylib = Some(path.clone());
+ return true;
+ }
+ Some(*) | None => {}
+ }
+ }
+ return false;
+ }
+
+ // Returns the corresponding (prefix, suffix) that files need to have for
+ // dynamic libraries
+ fn dylibname(&self) -> (&'static str, &'static str) {
+ match self.os {
+ OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
+ OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
+ OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
+ OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX),
+ OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
}
}
}
local_metas.iter().all(|needed| attr::contains(extern_metas, *needed))
}
-fn get_metadata_section(os: Os,
- filename: &Path) -> Option<@~[u8]> {
+fn get_metadata_section(sess: Session, os: Os, filename: &Path,
+ crate_name: &str) -> Option<@~[u8]> {
unsafe {
- let mb = filename.with_c_str(|buf| {
- llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
- });
- if mb as int == 0 { return option::None::<@~[u8]>; }
- let of = match mk_object_file(mb) {
- option::Some(of) => of,
- _ => return option::None::<@~[u8]>
+ let mb = if filename.filename_str().unwrap().ends_with(".rlib") {
+ let archive = Archive::open(sess, filename.clone());
+ let contents = archive.read(crate_name + ".o");
+ let ptr = vec::raw::to_ptr(contents);
+ crate_name.with_c_str(|name| {
+ llvm::LLVMCreateMemoryBufferWithMemoryRangeCopy(
+ ptr as *i8, contents.len() as libc::size_t, name)
+ })
+ } else {
+ filename.with_c_str(|buf| {
+ llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
+ })
+ };
+ if mb as int == 0 { return None }
+ let of = match ObjectFile::new(mb) {
+ Some(of) => of,
+ _ => return None
};
let si = mk_section_iter(of.llof);
while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
}
// A diagnostic function for dumping crate metadata to an output stream
-pub fn list_file_metadata(intr: @ident_interner,
+pub fn list_file_metadata(sess: Session,
+ intr: @ident_interner,
os: Os,
path: &Path,
out: @mut io::Writer) {
- match get_metadata_section(os, path) {
+ // guess the crate name from the pathname
+ let crate_name = path.filename_str().unwrap();
+ let crate_name = if crate_name.starts_with("lib") {
+ crate_name.slice_from(3) } else { crate_name };
+ let crate_name = crate_name.split_iter('-').next().unwrap();
+ match get_metadata_section(sess, os, path, crate_name) {
option::Some(bytes) => decoder::list_crate_metadata(intr, bytes, out),
option::None => {
write!(out, "could not find metadata in {}.\n", path.display())
use syntax::ast_map::{path, path_elt_to_str, path_name, path_pretty_name};
use syntax::ast_util::{local_def};
use syntax::attr;
-use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::parse::token::{special_idents};
use syntax::print::pprust::stmt_to_str;
use syntax::{ast, ast_util, codemap, ast_map};
+use syntax::attr::AttrMetaMethods;
use syntax::abi::{X86, X86_64, Arm, Mips, Rust, RustIntrinsic, OsWin32, OsAndroid};
use syntax::visit;
use syntax::visit::Visitor;
}
}
-// Writes the current ABI version into the crate.
-pub fn write_abi_version(ccx: &mut CrateContext) {
- unsafe {
- let llval = C_uint(ccx, abi::abi_version);
- let llglobal = "rust_abi_version".with_c_str(|buf| {
- llvm::LLVMAddGlobal(ccx.llmod, val_ty(llval).to_ref(), buf)
- });
- llvm::LLVMSetInitializer(llglobal, llval);
- llvm::LLVMSetGlobalConstant(llglobal, True);
- }
-}
-
pub fn trans_crate(sess: session::Session,
crate: ast::Crate,
analysis: &CrateAnalysis,
}
glue::emit_tydescs(ccx);
- write_abi_version(ccx);
if ccx.sess.opts.debuginfo {
debuginfo::finalize(ccx);
}
let llcx = ccx.llcx;
let link_meta = ccx.link_meta;
let llmod = ccx.llmod;
+ let crate_types = crate.attrs.iter().filter_map(|a| {
+ if "crate_type" == a.name() {
+ a.value_str()
+ } else {
+ None
+ }
+ }).map(|a| a.to_owned()).collect();
return CrateTranslation {
context: llcx,
module: llmod,
- link: link_meta
+ link: link_meta,
+ crate_types: crate_types,
};
}
}
// sundown FFI
-#[link_args = "-lsundown"]
+#[link(name = "sundown", kind = "static")]
extern {
fn sdhtml_renderer(callbacks: *sd_callbacks,
options_ptr: *html_renderopt,
#[desc = "rustdoc, the Rust documentation extractor"];
#[license = "MIT/ASL2"];
-#[crate_type = "lib"];
+#[crate_type = "lib"]; // NOTE: remove after stage0 snapshot
+#[crate_type = "dylib"];
#[feature(globs, struct_variant, managed_boxes)];
url = "https://github.com/mozilla/rust/tree/master/src/librustpkg")];
#[license = "MIT/ASL2"];
-#[crate_type = "lib"];
+#[crate_type = "lib"]; // NOTE: remove after stage0 snapshot
+#[crate_type = "dylib"];
#[feature(globs, managed_boxes)];
let options = @session::options {
binary: binary,
maybe_sysroot: Some(@sysroot),
- crate_type: session::bin_crate,
+ outputs: ~[session::OutputExecutable],
.. (*session::basic_options()).clone()
};
let input = driver::file_input(script.clone());
chmod_read_only, platform_library_name};
use rustc::back::link::get_cc_prog;
use rustc::metadata::filesearch::rust_path;
+use rustc::driver::session;
use rustc::driver::driver::{build_session, build_session_options, host_triple, optgroups};
use syntax::diagnostic;
use target::*;
@diagnostic::Emitter);
let test_sys = test_sysroot();
// FIXME (#9639): This needs to handle non-utf8 paths
+ let cc = get_cc_prog(sess);
command_line_test([test_sys.as_str().unwrap().to_owned(),
~"install",
~"--linker",
- get_cc_prog(sess),
+ cc,
~"foo"],
workspace);
assert_executable_exists(workspace, "foo");
use syntax::util::small_vector::SmallVector;
use rustc::back::link::output_type_exe;
use rustc::back::link;
-use rustc::driver::session::{lib_crate, bin_crate};
use context::{in_target, StopBefore, Link, Assemble, BuildContext};
use package_id::PkgId;
use package_source::PkgSrc;
debug!("compile_input's sysroot = {}", csysroot.display());
let crate_type = match what {
- Lib => lib_crate,
- Test | Bench | Main => bin_crate
+ Lib => session::OutputDylib,
+ Test | Bench | Main => session::OutputExecutable,
};
let matches = getopts(debug_flags()
+ match what {
debug!("Output type = {:?}", output_type);
let options = @session::options {
- crate_type: crate_type,
+ outputs: ~[crate_type],
optimize: opt,
test: what == Test || what == Bench,
maybe_sysroot: Some(sysroot_to_use),
url = "https://github.com/mozilla/rust/tree/master/src/librustuv")];
#[license = "MIT/ASL2"];
-#[crate_type = "lib"];
+#[crate_type = "lib"]; // NOTE: remove after stage0 snapshot
+#[crate_type = "rlib"];
+#[crate_type = "dylib"];
#[feature(macro_rules, globs)];
// second copies of everything. We obviously don't want this, so instead of
// dying horribly during testing, we allow all of the test rustuv's references
// to get resolved to the original rustuv crate.
-#[link_args = "-luv_support -luv"]
-#[cfg(not(test))]
+#[cfg(not(test), not(stage0))]
+#[link(name = "uv_support", kind = "static")]
+#[link(name = "uv", kind = "static")]
+extern {}
+
+#[cfg(not(test), stage0)]
+#[link_args = "-luv -luv_support"]
extern {}
extern {
pub fn uv_signal_stop(handle: *uv_signal_t) -> c_int;
}
-// libuv requires various system libraries to successfully link on some
-// platforms
-#[cfg(target_os = "linux")]
+// various platform libraries required by libuv
+#[cfg(not(stage0))]
+#[link(name = "pthread")]
+extern {}
+#[cfg(stage0)]
#[link_args = "-lpthread"]
extern {}
-#[cfg(target_os = "win32")]
+#[cfg(target_os = "win32", not(stage0))]
+#[link(name = "ws2_32")]
+#[link(name = "psapi")]
+#[link(name = "iphlpapi")]
+extern {}
+#[cfg(target_os = "win32", stage0)]
#[link_args = "-lws2_32 -lpsapi -liphlpapi"]
extern {}
+
+#[cfg(target_os = "freebsd", not(stage0))]
+#[link(name = "kvm")]
+extern {}
+#[cfg(target_os = "freebsd", stage0)]
+#[link_args = "-lkvm"]
+extern {}
#[comment = "The Rust standard library"];
#[license = "MIT/ASL2"];
-#[crate_type = "lib"];
+#[crate_type = "lib"]; // NOTE: remove after stage0 snapshot
+#[crate_type = "rlib"];
+#[crate_type = "dylib"];
#[doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
#[cfg(test)] pub use ops = realstd::ops;
#[cfg(test)] pub use cmp = realstd::cmp;
-// On Linux, link to the runtime with -lrt.
-#[cfg(target_os = "linux")]
-#[doc(hidden)]
-pub mod linkhack {
- #[link_args="-lrustrt -lrt"]
- #[link_args = "-lpthread"]
- extern {
- }
-}
+mod rtdeps;
/* The Prelude. */
--- /dev/null
+// Copyright 2013 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.
+
+//! This module contains the linkage attributes to all runtime dependencies of
+//! the stndard library This varies per-platform, but these libraries are
+//! necessary for running libstd.
+
+// All platforms need to link to rustrt
+#[link(name = "rustrt")]
+extern {}
+
+// LLVM implements the `frem` instruction as a call to `fmod`, which lives in
+// libm. Hence, we must explicitly link to it.
+//
+// On linux librt and libdl are indirect dependencies via rustrt,
+// and binutils 2.22+ won't add them automatically
+#[cfg(target_os = "linux")]
+#[link(name = "rt")]
+#[link(name = "dl")]
+#[link(name = "m")]
+#[link(name = "pthread")]
+extern {}
+
+#[cfg(target_os = "android")]
+#[link(name = "dl")]
+#[link(name = "log")]
+#[link(name = "supc++")]
+#[link(name = "gnustl_shared")]
+#[link(name = "m")]
+extern {}
+
+#[cfg(target_os = "freebsd")]
+#[link(name = "execinfo")]
+#[link(name = "rt")]
+#[link(name = "stdc++")]
+#[link(name = "pthread")]
+extern {}
+
+#[cfg(target_os = "macos")]
+#[link(name = "pthread")]
+extern {}
uuid = "9311401b-d6ea-4cd9-a1d9-61f89499c645")];
#[license = "MIT/ASL2"];
-#[crate_type = "lib"];
+#[crate_type = "lib"]; // NOTE: remove after stage0 snapshot
+#[crate_type = "dylib"];
#[feature(macro_rules, globs, managed_boxes)];
LLVMRemoveReturnAttribute
LLVMTypeToString
LLVMAddColdAttribute
+LLVMCreateMemoryBufferWithMemoryRange
+LLVMCreateMemoryBufferWithMemoryRangeCopy