]> git.lizzy.rs Git - rust.git/commitdiff
Add generation of static libraries to rustc
authorAlex Crichton <alex@alexcrichton.com>
Fri, 15 Nov 2013 22:03:29 +0000 (14:03 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Sat, 30 Nov 2013 02:36:13 +0000 (18:36 -0800)
This commit implements the support necessary for generating both intermediate
and result static rust libraries. This is an implementation of my thoughts in
https://mail.mozilla.org/pipermail/rust-dev/2013-November/006686.html.

When compiling a library, we still retain the "lib" option, although now there
are "rlib", "staticlib", and "dylib" as options for crate_type (and these are
stackable). The idea of "lib" is to generate the "compiler default" instead of
having too choose (although all are interchangeable). For now I have left the
"complier default" to be a dynamic library for size reasons.

Of the rust libraries, lib{std,extra,rustuv} will bootstrap with an
rlib/dylib pair, but lib{rustc,syntax,rustdoc,rustpkg} will only be built as a
dynamic object. I chose this for size reasons, but also because you're probably
not going to be embedding the rustc compiler anywhere any time soon.

Other than the options outlined above, there are a few defaults/preferences that
are now opinionated in the compiler:

* If both a .dylib and .rlib are found for a rust library, the compiler will
  prefer the .rlib variant. This is overridable via the -Z prefer-dynamic option
* If generating a "lib", the compiler will generate a dynamic library. This is
  overridable by explicitly saying what flavor you'd like (rlib, staticlib,
  dylib).
* If no options are passed to the command line, and no crate_type is found in
  the destination crate, then an executable is generated

With this change, you can successfully build a rust program with 0 dynamic
dependencies on rust libraries. There is still a dynamic dependency on
librustrt, but I plan on removing that in a subsequent commit.

This change includes no tests just yet. Our current testing
infrastructure/harnesses aren't very amenable to doing flavorful things with
linking, so I'm planning on adding a new mode of testing which I believe belongs
as a separate commit.

Closes #552

43 files changed:
Makefile.in
configure
doc/rust.md
mk/clean.mk
mk/host.mk
mk/install.mk
mk/platform.mk
mk/target.mk
mk/tests.mk
src/libextra/flate.rs
src/libextra/lib.rs
src/librustc/back/archive.rs [new file with mode: 0644]
src/librustc/back/arm.rs
src/librustc/back/link.rs
src/librustc/back/mips.rs
src/librustc/back/rpath.rs
src/librustc/back/target_strs.rs
src/librustc/back/x86.rs
src/librustc/back/x86_64.rs
src/librustc/driver/driver.rs
src/librustc/driver/session.rs
src/librustc/front/feature_gate.rs
src/librustc/lib.rs
src/librustc/lib/llvm.rs
src/librustc/metadata/common.rs
src/librustc/metadata/creader.rs
src/librustc/metadata/csearch.rs
src/librustc/metadata/cstore.rs
src/librustc/metadata/decoder.rs
src/librustc/metadata/encoder.rs
src/librustc/metadata/loader.rs
src/librustc/middle/trans/base.rs
src/librustdoc/html/markdown.rs
src/librustdoc/lib.rs
src/librustpkg/lib.rs
src/librustpkg/tests.rs
src/librustpkg/util.rs
src/librustuv/lib.rs
src/librustuv/uvll.rs
src/libstd/lib.rs
src/libstd/rtdeps.rs [new file with mode: 0644]
src/libsyntax/lib.rs
src/rustllvm/rustllvm.def.in

index f5bb3cb2ed00fcdacc16ea594ac04f11a60d005c..73400610f670654fd2deb2013a0c00a8f68648cc 100644 (file)
@@ -130,6 +130,14 @@ ifndef DEBUG_BORROWS
   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
 
@@ -239,6 +247,10 @@ LIBRUSTPKG_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustpkg)
 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
@@ -392,42 +404,25 @@ TBIN$(1)_T_$(2)_H_$(3) = $$(TROOT$(1)_T_$(2)_H_$(3))/bin
 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) = \
index 2390016b3f189e28e09cbdc14480197c44900c07..074e522a20c2a09ee88ab53b1941281450b7c64c 100755 (executable)
--- a/configure
+++ b/configure
@@ -364,7 +364,6 @@ fi
 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"
@@ -398,7 +397,7 @@ valopt sysconfdir "/etc" "install system configuration files"
 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"
index a25f19371bd7b70e0148fad92a245c4d91a2dfe9..969e40e632a158cf972cff38af942277b0ac071b 100644 (file)
@@ -1507,19 +1507,15 @@ an `abi` string, as shown here:
 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`,
index dc2aefeb8653475587559a1acac443131e9bc2c7..1994fec0990caf129ea4ca41838edb383a73b040 100644 (file)
@@ -59,6 +59,7 @@ clean-generic-$(2)-$(1):
        $(Q)find $(1)/rustllvm \
                 $(1)/rt \
                 $(1)/test \
+                $(1)/stage* \
          -name '*.[odasS]' -o \
          -name '*.so' -o      \
          -name '*.dylib' -o   \
@@ -91,13 +92,16 @@ clean$(1)_H_$(2):
        $(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
 
@@ -122,14 +126,16 @@ clean$(1)_T_$(2)_H_$(3):
        $(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
index 9ba2b978f1075775ef028186493da62d9121536c..7e8a3e8a6eb1497497e182aced1a08986f92cf4b 100644 (file)
@@ -50,7 +50,7 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)): \
        $$(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 $$@))
 
@@ -82,6 +82,7 @@ $$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)): \
        | $$(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
@@ -91,9 +92,11 @@ $$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)): \
 # 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)) \
@@ -102,11 +105,14 @@ $$(HLIB$(2)_H_$(4))/$(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)) \
@@ -115,35 +121,14 @@ $$(HLIB$(2)_H_$(4))/$(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)) \
index 49f1fdbf547c958f76886fd0ad715f0dc80a968c..d8208003b7bb14ec447f1e0ef1662792c8356788 100644 (file)
@@ -144,8 +144,11 @@ install-host: $(CSREQ$(ISTAGE)_T_$(CFG_BUILD_)_H_$(CFG_BUILD_))
        $(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)))
@@ -170,8 +173,11 @@ uninstall:
        $(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))) \
index bc2536cce4834874c7b1f383c23f74cc8876daca..35d4279eaef97bb7f925e068b52da86bc1b47ce1 100644 (file)
@@ -138,6 +138,7 @@ endif
 endif
 endif
 
+CFG_RLIB_GLOB=lib$(1)-*.rlib
 
 # x86_64-unknown-linux-gnu configuration
 CC_x86_64-unknown-linux-gnu=$(CC)
index f7d8ec83a5a17cc70775b9bd923d17de066aa14a..a8606cbdbcb658baa0368b9324ddd714aa17a1ff 100644 (file)
@@ -60,8 +60,10 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)): \
                | $$(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) \
@@ -70,8 +72,10 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)): \
                | $$(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) \
@@ -82,11 +86,13 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2)): \
                | $$(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) \
index a24791d76af975d8a54c26d161fdba7be6aa58f7..c3614cbcc6b693d4e8132e5fbe67e3d49ee1ed89 100644 (file)
@@ -584,6 +584,10 @@ TEST_SREQ$(1)_T_$(2)_H_$(3) = \
 # 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
index 3d1d0c91e317d1c57b52d4f4cc09bea35f5ba098..a4a10ccfa73fa98067cf752ddc792750cf38b01d 100644 (file)
@@ -23,7 +23,7 @@
 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,
index a74c4993be3507e6b317bd9c019481d0f0a2b137..571891f1830a461910c8f868739790ff9acbf9ab 100644 (file)
@@ -32,7 +32,9 @@
 
 #[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)];
 
diff --git a/src/librustc/back/archive.rs b/src/librustc/back/archive.rs
new file mode 100644 (file)
index 0000000..e3c8e85
--- /dev/null
@@ -0,0 +1,128 @@
+// 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));
+    }
+}
index a3ac468a5f02427cbbeaa25b56e973894c9778d7..c155f4bd15b899371e84b39e042badc1eccdc433 100644 (file)
@@ -63,6 +63,6 @@ pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::
 
         target_triple: target_triple,
 
-        cc_args: ~[~"-marm"]
+        cc_args: ~[~"-marm"],
     };
 }
index 9aba16422d3fd4fdb637d23f21397390d96c7937..98d5958ac4f31be7ad1b46f8cbe688f36ad9f271 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 
+use back::archive::Archive;
 use back::rpath;
 use driver::session::Session;
 use driver::session;
@@ -16,7 +17,7 @@
 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;
@@ -30,7 +31,6 @@
 use std::ptr;
 use std::run;
 use std::str;
-use std::vec;
 use std::io::fs;
 use syntax::abi;
 use syntax::ast;
@@ -88,7 +88,6 @@ pub mod jit {
     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;
@@ -125,19 +124,6 @@ pub fn exec(sess: Session,
             // 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);
@@ -368,20 +354,20 @@ pub fn run_passes(sess: Session,
     }
 
     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();
         }
@@ -876,90 +862,71 @@ pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str
     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
@@ -971,34 +938,36 @@ pub fn link_binary(sess: Session,
 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.
@@ -1006,139 +975,293 @@ fn unlib(config: @session::config, stem: ~str) -> ~str {
     // 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);
+    }
+}
index cbe39efdf8cf0646c0c8e20189f3c0aef559b041..ce716f6f94b3570e079ae24928f2b199a3616ca1 100644 (file)
@@ -63,6 +63,6 @@ pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::
 
         target_triple: target_triple,
 
-        cc_args: ~[]
+        cc_args: ~[],
     };
 }
index 5f01a57c23f8e46d17e008d720ef3dac5402c4f0..0853213a5294375f01a76910970b80ad537192f7 100644 (file)
@@ -21,8 +21,7 @@ fn not_win32(os: abi::Os) -> bool {
   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
@@ -30,18 +29,28 @@ pub fn get_rpath_flags(sess: session::Session, out_filename: &Path)
         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 {
@@ -52,8 +61,11 @@ 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,
index 7baaac4fc9537687b37466cc23dd066ca9971159..8713323787825e3d4de0952577b16d086b2cc356 100644 (file)
@@ -14,5 +14,5 @@ pub struct t {
     meta_sect_name: ~str,
     data_layout: ~str,
     target_triple: ~str,
-    cc_args: ~[~str]
+    cc_args: ~[~str],
 }
index b3c92bc40577e69ba22e02419ec6296104c58cdc..de0372b83b972453783381bcfd56ba85481c73cc 100644 (file)
@@ -46,6 +46,6 @@ pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::
 
         target_triple: target_triple,
 
-        cc_args: ~[~"-m32"]
+        cc_args: ~[~"-m32"],
     };
 }
index 3237085dfb9ece94f1ef5294550e57fc7e5e31a6..dce4de3dce3c10d593d232090213d9e58970e91b 100644 (file)
@@ -54,6 +54,6 @@ pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::
 
         target_triple: target_triple,
 
-        cc_args: ~[~"-m64"]
+        cc_args: ~[~"-m64"],
     };
 }
index 8821f5f622978e5c1fd55630a24f12a0a44894f7..7d13cb2da6501eaf81c1201d228699266f0a8c88 100644 (file)
@@ -11,7 +11,7 @@
 
 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;
@@ -164,8 +164,11 @@ pub fn phase_2_configure_and_expand(sess: Session,
                                     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));
@@ -225,10 +228,8 @@ pub fn phase_3_run_analysis_passes(sess: Session,
                        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", (), |_|
@@ -330,7 +331,8 @@ pub fn phase_3_run_analysis_passes(sess: Session,
 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
@@ -390,6 +392,7 @@ pub fn phase_6_link_output(sess: Session,
                            outputs: &OutputFilenames) {
     time(sess.time_passes(), "linking", (), |_|
          link::link_binary(sess,
+                           trans.crate_types,
                            &outputs.obj_filename,
                            &outputs.out_filename,
                            trans.link));
@@ -417,11 +420,6 @@ pub fn stop_after_phase_5(sess: Session) -> bool {
         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;
@@ -652,13 +650,21 @@ pub fn build_session_options(binary: @str,
                              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");
 
@@ -750,11 +756,10 @@ pub fn build_session_options(binary: @str,
     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()
@@ -782,8 +787,7 @@ pub fn build_session_options(binary: @str,
     };
 
     let sopts = @session::options {
-        crate_type: crate_type,
-        is_static: statik,
+        outputs: outputs,
         gc: gc,
         optimize: opt_level,
         custom_passes: custom_passes,
@@ -795,6 +799,7 @@ pub fn build_session_options(binary: @str,
         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,
@@ -871,7 +876,6 @@ pub fn parse_pretty(sess: Session, name: &str) -> PpMode {
 // 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"),
@@ -881,8 +885,13 @@ pub fn optgroups() -> ~[getopts::groups::OptGroup] {
   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"),
@@ -957,19 +966,16 @@ pub fn build_output_filenames(input: &input,
     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 => {
@@ -1047,6 +1053,7 @@ pub fn early_error(emitter: @diagnostic::Emitter, msg: &str) -> ! {
 
 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);
 }
index e497caa494604cd9232be437de824a262dc95337..ba9e84494183596e0998069e3da6dfd877ace95b 100644 (file)
@@ -13,7 +13,6 @@
 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,
@@ -66,16 +58,16 @@ pub struct config {
 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),
@@ -107,7 +99,6 @@ pub fn debugging_opts_map() -> ~[(&'static str, &'static str, uint)] {
      ("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),
@@ -129,6 +120,7 @@ pub fn debugging_opts_map() -> ~[(&'static str, &'static str, uint)] {
       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),
     ]
 }
 
@@ -144,8 +136,8 @@ pub enum OptLevel {
 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],
@@ -159,6 +151,7 @@ pub struct options {
     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>,
@@ -194,6 +187,14 @@ pub enum EntryFnType {
     EntryNone,
 }
 
+#[deriving(Eq, Clone)]
+pub enum OutputStyle {
+    OutputExecutable,
+    OutputDylib,
+    OutputRlib,
+    OutputStaticlib,
+}
+
 pub struct Session_ {
     targ_cfg: @config,
     opts: @options,
@@ -337,6 +338,9 @@ pub fn no_vectorize_slp(&self) -> bool {
     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 {
@@ -357,8 +361,7 @@ pub fn intr(&self) -> @syntax::parse::token::ident_interner {
 /// Some reasonable defaults
 pub fn basic_options() -> @options {
     @options {
-        crate_type: session::lib_crate,
-        is_static: false,
+        outputs: ~[],
         gc: false,
         optimize: No,
         custom_passes: ~[],
@@ -370,6 +373,7 @@ pub fn basic_options() -> @options {
         jit: false,
         output_type: link::output_type_exe,
         addl_lib_search_paths: @mut HashSet::new(),
+        ar: None,
         linker: None,
         linker_args: ~[],
         maybe_sysroot: None,
@@ -391,24 +395,17 @@ pub fn expect<T:Clone>(sess: Session, opt: Option<T>, msg: || -> ~str) -> T {
     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
     }
 }
 
index 82ddb9c2f973cf55e6c34c2bea869ea68d3d3d4c..3cff0b81e875ebab169fe87711964080d971c635 100644 (file)
@@ -21,6 +21,7 @@
 use middle::lint;
 
 use syntax::ast;
+use syntax::attr;
 use syntax::attr::AttrMetaMethods;
 use syntax::codemap::Span;
 use syntax::visit;
@@ -41,6 +42,7 @@
     ("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
@@ -111,7 +113,8 @@ fn visit_view_item(&mut self, i: &ast::view_item, _: ()) {
 
     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 \
@@ -132,6 +135,16 @@ fn visit_item(&mut self, i: @ast::item, _:()) {
                 }
             }
 
+            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")
+                }
+            }
+
             _ => {}
         }
 
index b5703a62a1fd527695bbb23f42169219dbde0d75..90a005568b6b63bf393c21198270393d475966b3 100644 (file)
@@ -16,7 +16,8 @@
 
 #[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)];
 
@@ -87,6 +88,7 @@ pub mod front {
 }
 
 pub mod back {
+    pub mod archive;
     pub mod link;
     pub mod abi;
     pub mod upcall;
index a6a96b25ff5591e7829b9ad8f902d6214acb9d90..5e5cc242358bf9bd9a2d9b288b4593bac0dba31a 100644 (file)
@@ -14,7 +14,6 @@
 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;
 
@@ -304,9 +303,16 @@ pub mod llvm {
     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;
@@ -1426,6 +1432,16 @@ pub fn LLVMIsSectionIteratorAtEnd(ObjFile: ObjectFileRef,
             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. */
@@ -1901,38 +1917,32 @@ pub fn mk_pass_manager() -> PassManager {
 
 /* 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);
+        }
     }
 }
 
index 5e6d0f276152341c3f282e6583a3ac6649f86f4b..5ed1eac746c495e0ab627d8c748a84b738323cf3 100644 (file)
@@ -197,6 +197,8 @@ pub fn from_uint(value : uint) -> Option<astencode_tag> {
 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,
index f18357999a19430736de92a988591221f955deb0..1f10699b765009bc7d055827c7efba4f95393fc9 100644 (file)
 
 //! 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
@@ -50,7 +43,7 @@ pub fn read_crates(diag: @mut span_handler,
     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 }
@@ -113,18 +106,15 @@ fn warn_if_multiple_versions(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() {
@@ -146,7 +136,7 @@ fn visit_view_item(e: @mut Env, i: &ast::view_item) {
                   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),
@@ -162,7 +152,7 @@ fn visit_view_item(e: @mut Env, i: &ast::view_item) {
                                    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);
       }
       _ => ()
   }
@@ -170,60 +160,62 @@ fn visit_view_item(e: @mut Env, i: &ast::view_item) {
 
 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 */ }
             }
         }
-      }
-      _ => { }
+        _ => { }
     }
 }
 
@@ -263,24 +255,21 @@ fn resolve_crate(e: @mut Env,
     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;
@@ -293,7 +282,7 @@ fn resolve_crate(e: @mut Env,
         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,
@@ -303,14 +292,18 @@ fn resolve_crate(e: @mut Env,
             };
         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) => {
index 9c9dba524534bb64a26c4d37ba8fdb28298dd2d7..96250fd5ec81d761260cc3a13941eb2f8c223568 100644 (file)
@@ -262,6 +262,12 @@ pub fn get_item_visibility(cstore: @mut cstore::CStore,
     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|) {
index bc15312d98e18cdfbe076ed568580fdcaca02981..50da84d389538666cf8a8ed89430d6b3928782d2 100644 (file)
@@ -34,12 +34,33 @@ pub struct crate_metadata {
     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
 }
 
@@ -50,7 +71,7 @@ pub fn mk_cstore(intr: @ident_interner) -> CStore {
     return CStore {
         metas: HashMap::new(),
         extern_mod_crate_map: HashMap::new(),
-        used_crate_files: ~[],
+        used_crate_sources: ~[],
         used_libraries: ~[],
         used_link_args: ~[],
         intr: intr
@@ -88,39 +109,50 @@ pub fn iter_crate_data(cstore: &CStore, i: |ast::CrateNum, @crate_metadata|) {
     }
 }
 
-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,
index 48621459228fb4fcbd98fddc576f812c34058837..c43324456d1f719182e9f28141df97cbf25ac644 100644 (file)
@@ -1529,3 +1529,13 @@ pub fn get_trait_of_method(cdata: Cmd, id: ast::NodeId, tcx: ty::ctxt)
     }
 }
 
+
+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;
+}
index 6da75397002df4662ecc42fb009eecc6763985e9..269054c6fd21fdb9509144f42b5aab2dd7823aa7 100644 (file)
@@ -75,6 +75,7 @@ struct Stats {
     attr_bytes: u64,
     dep_bytes: u64,
     lang_item_bytes: u64,
+    native_lib_bytes: u64,
     impl_bytes: u64,
     misc_bytes: u64,
     item_bytes: u64,
@@ -1633,6 +1634,23 @@ fn encode_lang_items(ecx: &EncodeContext, ebml_w: &mut writer::Encoder) {
     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,
@@ -1750,6 +1768,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
         attr_bytes: 0,
         dep_bytes: 0,
         lang_item_bytes: 0,
+        native_lib_bytes: 0,
         impl_bytes: 0,
         misc_bytes: 0,
         item_bytes: 0,
@@ -1806,6 +1825,11 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
     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);
@@ -1842,6 +1866,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
         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);
index ecd1c8985bd00dc52404f3aa9e4eb71bfd67737f..1aff16cc23c4b86f75bb3ba868cde9cbe787a76b 100644 (file)
 
 //! 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;
@@ -26,6 +27,7 @@
 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};
@@ -43,103 +45,176 @@ pub enum Os {
 }
 
 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),
         }
     }
 }
@@ -196,16 +271,26 @@ pub fn metadata_matches(extern_metas: &[@ast::MetaItem],
     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 {
@@ -266,11 +351,17 @@ pub fn read_meta_section_name(os: Os) -> &'static str {
 }
 
 // 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())
index ac7b82401768226118cec65b9819e9d259f338e8..f14fc265b82b0d979369c8555fb813ff2010615b 100644 (file)
 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;
@@ -3106,18 +3106,6 @@ pub fn write_metadata(cx: &CrateContext, crate: &ast::Crate) {
     }
 }
 
-// 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,
@@ -3177,7 +3165,6 @@ pub fn trans_crate(sess: session::Session,
     }
 
     glue::emit_tydescs(ccx);
-    write_abi_version(ccx);
     if ccx.sess.opts.debuginfo {
         debuginfo::finalize(ccx);
     }
@@ -3217,10 +3204,18 @@ pub fn trans_crate(sess: session::Session,
     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,
     };
 }
index ac7c50fdfd809673571474ea653919dbcec324a2..3dcc1dbebcab2d932bb5c2470e673fde9ea9d25a 100644 (file)
@@ -67,7 +67,7 @@ struct buf {
 }
 
 // sundown FFI
-#[link_args = "-lsundown"]
+#[link(name = "sundown", kind = "static")]
 extern {
     fn sdhtml_renderer(callbacks: *sd_callbacks,
                        options_ptr: *html_renderopt,
index c51244cddf52f065f03c03e5e52cc6c0a449aabb..1a4537f9138c2f3dd737fc94e2f0bf8a7a4553e5 100644 (file)
@@ -16,7 +16,8 @@
 
 #[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)];
 
index b87bd0c58246b59f5ee4188d5c462c6e94387887..157d8ba0105fce76649d8030557c7ec18c79c3fc 100644 (file)
@@ -17,7 +17,8 @@
        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)];
 
@@ -114,7 +115,7 @@ fn parse<'a>(sysroot: Path,
         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());
index 5e867951b54ed85e492a330f584b7dd61ae23e4f..3b177b449d9109523d8d43e77a13ab741a2721fb 100644 (file)
@@ -36,6 +36,7 @@
                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::*;
@@ -1829,10 +1830,11 @@ fn test_linker_build() {
                                 @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");
index f21357d0271db524047e3d71c24e22b116d4d3ba..a8dbf145e533321b082413fd6168f23e64eeea6b 100644 (file)
@@ -25,7 +25,6 @@
 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;
@@ -195,8 +194,8 @@ pub fn compile_input(context: &BuildContext,
     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 {
@@ -239,7 +238,7 @@ pub fn compile_input(context: &BuildContext,
     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),
index 76882e885a8c924c15a230afa59f21433d6c916d..feb1c6b92bdec816725612670636de94c83fb36f 100644 (file)
@@ -41,7 +41,9 @@
        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)];
 
index 3917efe9ca823966c48b0469faa9b2e9b0ba8511..f62ac3450e6ebb8a178b5accb4ea7d490cbb6a59 100644 (file)
@@ -524,8 +524,13 @@ pub unsafe fn guess_handle(handle: c_int) -> c_int {
 // 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 {
@@ -717,12 +722,26 @@ pub fn uv_signal_start(h: *uv_signal_t, cb: uv_signal_cb,
     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 {}
index a72bc6b832863e0700e35d599f0804b9d57596bb..0489fff31f93a9968e54007d1b7a4f9f5e5e88cf 100644 (file)
@@ -51,7 +51,9 @@
 
 #[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. */
 
diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs
new file mode 100644 (file)
index 0000000..761d630
--- /dev/null
@@ -0,0 +1,48 @@
+// 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 {}
index 351eab35a77fbfdb5aa6e352fa53a0c926a55244..7fd503a8d42942bbe83bfad68731353ffc996a3d 100644 (file)
@@ -19,7 +19,8 @@
        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)];
 
index a6b887f058af89933c1c5c7265020f0cbcd2a556..069f29e909d4b2204ff10b388b3593929d460f9e 100644 (file)
@@ -630,3 +630,5 @@ LLVMAddReturnAttribute
 LLVMRemoveReturnAttribute
 LLVMTypeToString
 LLVMAddColdAttribute
+LLVMCreateMemoryBufferWithMemoryRange
+LLVMCreateMemoryBufferWithMemoryRangeCopy