From e338a4154b134fc1d4628496d4ccf85b7af7c443 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 15 Nov 2013 14:03:29 -0800 Subject: [PATCH 1/5] Add generation of static libraries to rustc 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 --- Makefile.in | 61 ++-- configure | 3 +- doc/rust.md | 12 +- mk/clean.mk | 10 +- mk/host.mk | 35 +- mk/install.mk | 6 + mk/platform.mk | 1 + mk/target.mk | 6 + mk/tests.mk | 4 + src/libextra/flate.rs | 2 +- src/libextra/lib.rs | 4 +- src/librustc/back/archive.rs | 128 +++++++ src/librustc/back/arm.rs | 2 +- src/librustc/back/link.rs | 547 ++++++++++++++++++----------- src/librustc/back/mips.rs | 2 +- src/librustc/back/rpath.rs | 24 +- src/librustc/back/target_strs.rs | 2 +- src/librustc/back/x86.rs | 2 +- src/librustc/back/x86_64.rs | 2 +- src/librustc/driver/driver.rs | 83 +++-- src/librustc/driver/session.rs | 77 ++-- src/librustc/front/feature_gate.rs | 15 +- src/librustc/lib.rs | 4 +- src/librustc/lib/llvm.rs | 64 ++-- src/librustc/metadata/common.rs | 2 + src/librustc/metadata/creader.rs | 155 ++++---- src/librustc/metadata/csearch.rs | 6 + src/librustc/metadata/cstore.rs | 72 ++-- src/librustc/metadata/decoder.rs | 10 + src/librustc/metadata/encoder.rs | 25 ++ src/librustc/metadata/loader.rs | 283 ++++++++++----- src/librustc/middle/trans/base.rs | 25 +- src/librustdoc/html/markdown.rs | 2 +- src/librustdoc/lib.rs | 3 +- src/librustpkg/lib.rs | 5 +- src/librustpkg/tests.rs | 4 +- src/librustpkg/util.rs | 7 +- src/librustuv/lib.rs | 4 +- src/librustuv/uvll.rs | 31 +- src/libstd/lib.rs | 14 +- src/libstd/rtdeps.rs | 48 +++ src/libsyntax/lib.rs | 3 +- src/rustllvm/rustllvm.def.in | 2 + 43 files changed, 1156 insertions(+), 641 deletions(-) create mode 100644 src/librustc/back/archive.rs create mode 100644 src/libstd/rtdeps.rs diff --git a/Makefile.in b/Makefile.in index f5bb3cb2ed0..73400610f67 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 +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))/libextra.rlib - TEXTRALIB_DEFAULT$(1)_T_$(2)_H_$(3) = \ - $$(TLIB$(1)_T_$(2)_H_$(3))/libextra.rlib +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))/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)) +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)) - 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 +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) = \ diff --git a/configure b/configure index 2390016b3f1..074e522a20c 100755 --- 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" diff --git a/doc/rust.md b/doc/rust.md index a25f19371bd..969e40e632a 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -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`, diff --git a/mk/clean.mk b/mk/clean.mk index dc2aefeb865..1994fec0990 100644 --- a/mk/clean.mk +++ b/mk/clean.mk @@ -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 diff --git a/mk/host.mk b/mk/host.mk index 9ba2b978f10..7e8a3e8a6eb 100644 --- a/mk/host.mk +++ b/mk/host.mk @@ -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)) \ diff --git a/mk/install.mk b/mk/install.mk index 49f1fdbf547..d8208003b7b 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -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))) \ diff --git a/mk/platform.mk b/mk/platform.mk index bc2536cce48..35d4279eaef 100644 --- a/mk/platform.mk +++ b/mk/platform.mk @@ -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) diff --git a/mk/target.mk b/mk/target.mk index f7d8ec83a5a..a8606cbdbcb 100644 --- a/mk/target.mk +++ b/mk/target.mk @@ -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) \ diff --git a/mk/tests.mk b/mk/tests.mk index a24791d76af..c3614cbcc6b 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -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 diff --git a/src/libextra/flate.rs b/src/libextra/flate.rs index 3d1d0c91e31..a4a10ccfa73 100644 --- a/src/libextra/flate.rs +++ b/src/libextra/flate.rs @@ -23,7 +23,7 @@ use std::vec; 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, diff --git a/src/libextra/lib.rs b/src/libextra/lib.rs index a74c4993be3..571891f1830 100644 --- a/src/libextra/lib.rs +++ b/src/libextra/lib.rs @@ -32,7 +32,9 @@ Rust extras are part of the standard Rust distribution. #[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 index 00000000000..e3c8e859f72 --- /dev/null +++ b/src/librustc/back/archive.rs @@ -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 or the MIT license +// , 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)); + } +} diff --git a/src/librustc/back/arm.rs b/src/librustc/back/arm.rs index a3ac468a5f0..c155f4bd15b 100644 --- a/src/librustc/back/arm.rs +++ b/src/librustc/back/arm.rs @@ -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"], }; } diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 9aba16422d3..98d5958ac4f 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -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::llvm; 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::os::consts::{macos, freebsd, linux, android, win32}; 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 mod jit { // 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 mod write { } 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,61 +975,281 @@ pub fn link_args(sess: Session, // 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())); } + 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); + } + } +} + +// 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; +} + +// 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)); + } + } +} + +// 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(" ")); + } + + // May have not found libraries in the right formats. + sess.abort_if_errors(); + + // Invoke the system linker + debug!("{} {}", cc_prog, cc_args.connect(" ")); + 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 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 + run::process_status("dsymutil", + [out_filename.as_str().unwrap().to_owned()]); + } +} + +fn link_args(sess: Session, + dylib: bool, + obj_filename: &Path, + out_filename: &Path) -> ~[~str] { + // 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); + let mut args = ~[stage]; // FIXME (#9639): This needs to handle non-utf8 paths args.push_all([ - ~"-o", output.as_str().unwrap().to_owned(), + ~"-o", out_filename.as_str().unwrap().to_owned(), obj_filename.as_str().unwrap().to_owned()]); - let lib_cmd = match sess.targ_cfg.os { - abi::OsMacos => ~"-dynamiclib", - _ => ~"-shared" - }; + 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"); - // # Crate linking - - 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; + // 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"); } - 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()); } + add_upstream_rust_crates(&mut args, sess, dylib); + add_local_native_libraries(&mut args, sess); - // # Extern library linking + // # Telling the linker what we're doing - // 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. + 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([~"-L/usr/local/lib", + ~"-L/usr/local/lib/gcc46", + ~"-L/usr/local/lib/gcc44"]); + } + + // Stack growth requires statically linking a __morestack function + args.push(~"-lmorestack"); + + // 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)); + + // 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()); @@ -1072,73 +1261,7 @@ pub fn link_args(sess: Session, args.push("-L" + path.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"); + for &(ref l, _) in cstore::get_used_libraries(sess.cstore).iter() { + args.push(~"-l" + *l); } - - // The names of the extern libraries - let used_libs = cstore::get_used_libraries(cstore); - for l in used_libs.iter() { args.push(~"-l" + *l); } - - if *sess.building_library { - args.push(lib_cmd); - - // 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()); - } - } - - // 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 { - args.push(~"-Wl,-O1"); - } - - args.push_all([~"-lrt", ~"-ldl"]); - - // 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"); - } - - if sess.targ_cfg.os == abi::OsFreebsd { - args.push_all([~"-pthread", ~"-lrt", - ~"-L/usr/local/lib", ~"-lexecinfo", - ~"-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"]); - } - - // 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, &output)); - - // Finally add all the linker arguments provided on the command line - args.push_all(sess.opts.linker_args); - - return args; } diff --git a/src/librustc/back/mips.rs b/src/librustc/back/mips.rs index cbe39efdf8c..ce716f6f94b 100644 --- a/src/librustc/back/mips.rs +++ b/src/librustc/back/mips.rs @@ -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: ~[], }; } diff --git a/src/librustc/back/rpath.rs b/src/librustc/back/rpath.rs index 5f01a57c23f..0853213a529 100644 --- a/src/librustc/back/rpath.rs +++ b/src/librustc/back/rpath.rs @@ -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, diff --git a/src/librustc/back/target_strs.rs b/src/librustc/back/target_strs.rs index 7baaac4fc95..87133237878 100644 --- a/src/librustc/back/target_strs.rs +++ b/src/librustc/back/target_strs.rs @@ -14,5 +14,5 @@ pub struct t { meta_sect_name: ~str, data_layout: ~str, target_triple: ~str, - cc_args: ~[~str] + cc_args: ~[~str], } diff --git a/src/librustc/back/x86.rs b/src/librustc/back/x86.rs index b3c92bc4057..de0372b83b9 100644 --- a/src/librustc/back/x86.rs +++ b/src/librustc/back/x86.rs @@ -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"], }; } diff --git a/src/librustc/back/x86_64.rs b/src/librustc/back/x86_64.rs index 3237085dfb9..dce4de3dce3 100644 --- a/src/librustc/back/x86_64.rs +++ b/src/librustc/back/x86_64.rs @@ -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"], }; } diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 8821f5f6229..7d13cb2da65 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -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 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" - }; + 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); } diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index e497caa4946..ba9e8449418 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -13,7 +13,6 @@ use back::link; use back::target_strs; use back; use driver::driver::host_triple; -use driver::session; use metadata::filesearch; use metadata; use middle::lint; @@ -30,13 +29,6 @@ use syntax; 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 static gc: uint = 1 << 17; 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, // 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 @@ impl Session_ { 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 @@ impl Session_ { /// 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(sess: Session, opt: Option, 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 } } diff --git a/src/librustc/front/feature_gate.rs b/src/librustc/front/feature_gate.rs index 82ddb9c2f97..3cff0b81e87 100644 --- a/src/librustc/front/feature_gate.rs +++ b/src/librustc/front/feature_gate.rs @@ -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 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[ ("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 @@ impl Visitor<()> for Context { 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 @@ impl Visitor<()> for Context { } } + 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") + } + } + _ => {} } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index b5703a62a1f..90a005568b6 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -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; diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index a6a96b25ff5..5e5cc242358 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -14,7 +14,6 @@ use std::c_str::ToCStr; 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 mod llvm { 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 { 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 { - unsafe { - let llof = llvm::LLVMCreateObjectFile(llmb); - if llof as int == 0 { return option::None::; } - - option::Some(ObjectFile { - llof: llof, - dtor: @object_file_res(llof) - }) +impl Drop for ObjectFile { + fn drop(&mut self) { + unsafe { + llvm::LLVMDisposeObjectFile(self.llof); + } } } diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 5e6d0f27615..5ed1eac746c 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -197,6 +197,8 @@ pub static tag_region_param_def: uint = 0x100; 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, diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index f18357999a1..1f10699b765 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -10,10 +10,9 @@ //! 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; @@ -29,19 +28,13 @@ use syntax::visit; // 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; - } + 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()); - - //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."); - //} - - for m in link_args.iter() { - match m.value_str() { - Some(linkarg) => { - cstore::add_used_link_args(cstore, linkarg); + // 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 */ } + } + } + + // 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) => { diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 9c9dba52453..96250fd5ec8 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -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|) { diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index bc15312d98e..50da84d3895 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -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, + rlib: Option, + cnum: ast::CrateNum, +} + pub struct CStore { priv metas: HashMap , 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 add_used_library(cstore: &mut CStore, lib: @str) -> bool { +pub fn get_used_crates(cstore: &CStore, prefer: LinkagePreference) + -> ~[(ast::CrateNum, Option)] +{ + 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, 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, diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 48621459228..c43324456d1 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -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; +} diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 6da75397002..269054c6fd2 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -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); diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index ecd1c8985bd..1aff16cc23c 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -10,11 +10,12 @@ //! 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 syntax::attr::AttrMetaMethods; 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, + rlib: Option, + metadata: @~[u8], +} + +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 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) -} + fn find_library_crate(&self) -> Option { + 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(); -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), - }; + // want: crate_name.dir_part() + prefix + crate_name.file_part + "-" + let dylib_prefix = format!("{}{}-", dyprefix, crate_name); + let rlib_prefix = format!("lib{}-", crate_name); - (dll_prefix.to_owned(), dll_suffix.to_owned()) -} + 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) + }; -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 - } - } - }); - - 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()) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index ac7b8240176..f14fc265b82 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -79,12 +79,12 @@ use syntax::ast::Name; 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, }; } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index ac7c50fdfd8..3dcc1dbebca 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -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, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index c51244cddf5..1a4537f9138 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -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)]; diff --git a/src/librustpkg/lib.rs b/src/librustpkg/lib.rs index b87bd0c5824..157d8ba0105 100644 --- a/src/librustpkg/lib.rs +++ b/src/librustpkg/lib.rs @@ -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 @@ impl<'self> PkgScript<'self> { 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()); diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 5e867951b54..3b177b449d9 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -36,6 +36,7 @@ use path_util::{target_executable_in_workspace, target_test_in_workspace, 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"); diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index f21357d0271..a8dbf145e53 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -25,7 +25,6 @@ use syntax::visit::Visitor; 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), diff --git a/src/librustuv/lib.rs b/src/librustuv/lib.rs index 76882e885a8..feb1c6b92bd 100644 --- a/src/librustuv/lib.rs +++ b/src/librustuv/lib.rs @@ -41,7 +41,9 @@ via `close` and `delete` methods. 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)]; diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs index 3917efe9ca8..f62ac3450e6 100644 --- a/src/librustuv/uvll.rs +++ b/src/librustuv/uvll.rs @@ -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 @@ extern { pub fn uv_signal_stop(handle: *uv_signal_t) -> c_int; } -// libuv requires various system libraries to successfully link on some -// platforms -#[cfg(target_os = "linux")] +// various platform libraries required by libuv +#[cfg(not(stage0))] +#[link(name = "pthread")] +extern {} +#[cfg(stage0)] #[link_args = "-lpthread"] extern {} -#[cfg(target_os = "win32")] +#[cfg(target_os = "win32", not(stage0))] +#[link(name = "ws2_32")] +#[link(name = "psapi")] +#[link(name = "iphlpapi")] +extern {} +#[cfg(target_os = "win32", stage0)] #[link_args = "-lws2_32 -lpsapi -liphlpapi"] extern {} + +#[cfg(target_os = "freebsd", not(stage0))] +#[link(name = "kvm")] +extern {} +#[cfg(target_os = "freebsd", stage0)] +#[link_args = "-lkvm"] +extern {} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a72bc6b8328..0489fff31f9 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -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", @@ -79,15 +81,7 @@ #[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 index 00000000000..761d630f771 --- /dev/null +++ b/src/libstd/rtdeps.rs @@ -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 or the MIT license +// , 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 {} diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 351eab35a77..7fd503a8d42 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -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)]; diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in index a6b887f058a..069f29e909d 100644 --- a/src/rustllvm/rustllvm.def.in +++ b/src/rustllvm/rustllvm.def.in @@ -630,3 +630,5 @@ LLVMAddReturnAttribute LLVMRemoveReturnAttribute LLVMTypeToString LLVMAddColdAttribute +LLVMCreateMemoryBufferWithMemoryRange +LLVMCreateMemoryBufferWithMemoryRangeCopy From 9fbba7b2eeabd073f9518f2dbd50f4eabb621c67 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 16 Nov 2013 02:02:07 -0800 Subject: [PATCH 2/5] Statically link librustrt to libstd This commit alters the build process of the compiler to build a static librustrt.a instead of a dynamic version. This means that we can stop distributing librustrt as well as default linking against it in the compiler. This also means that if you attempt to build rust code without libstd, it will no longer work if there are any landing pads in play. The reason for this is that LLVM and rustc will emit calls to the various upcalls in librustrt used to manage exception handling. In theory we could split librustrt into librustrt and librustupcall. We would then distribute librustupcall and link to it for all programs using landing pads, but I would rather see just one librustrt artifact and simplify the build process. The major benefit of doing this is that building a static rust library for use in embedded situations all of a sudden just became a whole lot more feasible. Closes #3361 --- Makefile.in | 2 +- mk/install.mk | 6 --- mk/rt.mk | 6 +-- src/etc/snapshot.py | 4 -- src/libstd/rtdeps.rs | 8 ++- src/rt/rustrt.def.in | 51 ------------------- .../anon-extern-mod-cross-crate-1.rs | 5 +- .../auxiliary/extern-crosscrate-source.rs | 1 + src/test/auxiliary/foreign_lib.rs | 1 + .../run-pass/anon-extern-mod-cross-crate-2.rs | 3 ++ src/test/run-pass/anon-extern-mod.rs | 2 +- src/test/run-pass/c-stack-as-value.rs | 1 + src/test/run-pass/extern-call-deep.rs | 1 + src/test/run-pass/extern-call-deep2.rs | 1 + src/test/run-pass/extern-call-indirect.rs | 1 + src/test/run-pass/extern-call-scrub.rs | 1 + src/test/run-pass/extern-pass-TwoU16s.rs | 1 + src/test/run-pass/extern-pass-TwoU32s.rs | 1 + src/test/run-pass/extern-pass-TwoU64s.rs | 1 + src/test/run-pass/extern-pass-TwoU8s.rs | 1 + src/test/run-pass/extern-pass-char.rs | 1 + src/test/run-pass/extern-pass-double.rs | 1 + src/test/run-pass/extern-pass-u32.rs | 1 + src/test/run-pass/extern-pass-u64.rs | 1 + src/test/run-pass/extern-return-TwoU16s.rs | 1 + src/test/run-pass/extern-return-TwoU32s.rs | 1 + src/test/run-pass/extern-return-TwoU64s.rs | 1 + src/test/run-pass/extern-return-TwoU8s.rs | 1 + src/test/run-pass/extern-stress.rs | 1 + src/test/run-pass/extern-yield.rs | 1 + src/test/run-pass/foreign-call-no-runtime.rs | 1 + src/test/run-pass/foreign-dupe.rs | 4 +- src/test/run-pass/foreign-no-abi.rs | 1 + src/test/run-pass/invoke-external-foreign.rs | 3 ++ src/test/run-pass/static-mut-foreign.rs | 2 +- src/test/run-pass/struct-return.rs | 2 +- 36 files changed, 46 insertions(+), 75 deletions(-) delete mode 100644 src/rt/rustrt.def.in diff --git a/Makefile.in b/Makefile.in index 73400610f67..b575312c03b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -222,7 +222,7 @@ GENERATED := define DEF_LIBS -CFG_RUNTIME_$(1) :=$(call CFG_LIB_NAME_$(1),rustrt) +CFG_RUNTIME_$(1) :=$(call CFG_STATIC_LIB_NAME_$(1),rustrt) CFG_RUSTLLVM_$(1) :=$(call CFG_LIB_NAME_$(1),rustllvm) CFG_STDLIB_$(1) :=$(call CFG_LIB_NAME_$(1),std) CFG_EXTRALIB_$(1) :=$(call CFG_LIB_NAME_$(1),extra) diff --git a/mk/install.mk b/mk/install.mk index d8208003b7b..7d6c0ea5264 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -88,7 +88,6 @@ install-target-$(1)-host-$(2): LIB_SOURCE_DIR=$$(TL$(1)$(2)) install-target-$(1)-host-$(2): LIB_DESTIN_DIR=$$(PTL$(1)$(2)) install-target-$(1)-host-$(2): $$(TSREQ$$(ISTAGE)_T_$(1)_H_$(2)) $$(SREQ$$(ISTAGE)_T_$(1)_H_$(2)) $$(Q)$$(call MK_INSTALL_DIR,$$(PTL$(1)$(2))) - $$(Q)$$(call INSTALL_LIB,$$(CFG_RUNTIME_$(1))) $$(Q)$$(call INSTALL_LIB,$$(STDLIB_GLOB_$(1))) $$(Q)$$(call INSTALL_LIB,$$(EXTRALIB_GLOB_$(1))) $$(Q)$$(call INSTALL_LIB,$$(LIBRUSTUV_GLOB_$(1))) @@ -101,7 +100,6 @@ install-target-$(1)-host-$(2): LIB_SOURCE_DIR=$$(TL$(1)$(2)) install-target-$(1)-host-$(2): LIB_DESTIN_DIR=$$(PTL$(1)$(2)) install-target-$(1)-host-$(2): $$(CSREQ$$(ISTAGE)_T_$(1)_H_$(2)) $$(Q)$$(call MK_INSTALL_DIR,$$(PTL$(1)$(2))) - $$(Q)$$(call INSTALL_LIB,$$(CFG_RUNTIME_$(1))) $$(Q)$$(call INSTALL_LIB,$$(CFG_RUSTLLVM_$(1))) $$(Q)$$(call INSTALL_LIB,$$(STDLIB_GLOB_$(1))) $$(Q)$$(call INSTALL_LIB,$$(EXTRALIB_GLOB_$(1))) @@ -153,7 +151,6 @@ install-host: $(CSREQ$(ISTAGE)_T_$(CFG_BUILD_)_H_$(CFG_BUILD_)) $(Q)$(call INSTALL_LIB,$(LIBSYNTAX_GLOB_$(CFG_BUILD))) $(Q)$(call INSTALL_LIB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD))) $(Q)$(call INSTALL_LIB,$(LIBRUSTDOC_GLOB_$(CFG_BUILD))) - $(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_RUNTIME_$(CFG_BUILD))) $(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_RUSTLLVM_$(CFG_BUILD))) $(Q)$(call INSTALL,$(S)/man,$(CFG_MANDIR)/man1,rustc.1) $(Q)$(call INSTALL,$(S)/man,$(CFG_MANDIR)/man1,rustdoc.1) @@ -170,7 +167,6 @@ uninstall: $(Q)rm -f $(PHB)/rustpkg$(X_$(CFG_BUILD)) $(Q)rm -f $(PHB)/rustdoc$(X_$(CFG_BUILD)) $(Q)rm -f $(PHL)/$(CFG_RUSTLLVM_$(CFG_BUILD)) - $(Q)rm -f $(PHL)/$(CFG_RUNTIME_$(CFG_BUILD)) $(Q)for i in \ $(call HOST_LIB_FROM_HL_GLOB,$(STDLIB_GLOB_$(CFG_BUILD))) \ $(call HOST_LIB_FROM_HL_GLOB,$(STDLIB_RGLOB_$(CFG_BUILD))) \ @@ -238,7 +234,6 @@ endif define INSTALL_RUNTIME_TARGET_N install-runtime-target-$(1)-host-$(2): $$(TSREQ$$(ISTAGE)_T_$(1)_H_$(2)) $$(SREQ$$(ISTAGE)_T_$(1)_H_$(2)) $(Q)$(call ADB_SHELL,mkdir,$(CFG_RUNTIME_PUSH_DIR)) - $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(CFG_RUNTIME_$(1)),$(CFG_RUNTIME_PUSH_DIR)) $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(STDLIB_GLOB_$(1)),$(CFG_RUNTIME_PUSH_DIR)) $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(EXTRALIB_GLOB_$(1)),$(CFG_RUNTIME_PUSH_DIR)) $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(LIBRUSTUV_GLOB_$(1)),$(CFG_RUNTIME_PUSH_DIR)) @@ -247,7 +242,6 @@ endef define INSTALL_RUNTIME_TARGET_CLEANUP_N install-runtime-target-$(1)-cleanup: $(Q)$(call ADB,remount) - $(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(CFG_RUNTIME_$(1))) $(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(STDLIB_GLOB_$(1))) $(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(EXTRALIB_GLOB_$(1))) $(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(LIBRUSTUV_GLOB_$(1))) diff --git a/mk/rt.mk b/mk/rt.mk index cc22d5781a6..f27ed8714f4 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -121,11 +121,9 @@ $$(RT_BUILD_DIR_$(1)_$(2))/arch/$$(HOST_$(1))/libmorestack.a: $$(MORESTACK_OBJS_ @$$(call E, link: $$@) $$(Q)$(AR_$(1)) rcs $$@ $$^ -$$(RT_BUILD_DIR_$(1)_$(2))/$(CFG_RUNTIME_$(1)): $$(RUNTIME_OBJS_$(1)_$(2)) $$(MKFILE_DEPS) \ - $$(RUNTIME_DEF_$(1)_$(2)) +$$(RT_BUILD_DIR_$(1)_$(2))/$(CFG_RUNTIME_$(1)): $$(RUNTIME_OBJS_$(1)_$(2)) $$(MKFILE_DEPS) @$$(call E, link: $$@) - $$(Q)$$(call CFG_LINK_CXX_$(1),$$@, $$(RUNTIME_OBJS_$(1)_$(2)) \ - $$(CFG_LIBUV_LINK_FLAGS_$(1)),$$(RUNTIME_DEF_$(1)_$(2)),$$(CFG_RUNTIME_$(1))) + $$(Q)$(AR_$(1)) rcs $$@ $$(RUNTIME_OBJS_$(1)_$(2)) # These could go in rt.mk or rustllvm.mk, they're needed for both. diff --git a/src/etc/snapshot.py b/src/etc/snapshot.py index 99193d905f8..03ada0eef18 100644 --- a/src/etc/snapshot.py +++ b/src/etc/snapshot.py @@ -31,7 +31,6 @@ snapshot_files = { "lib/librustc-*.so", "lib/libsyntax-*.so", "lib/librustuv-*.so", - "lib/librustrt.so", "lib/librustllvm.so"], "macos": ["bin/rustc", "lib/libstd-*.dylib", @@ -39,7 +38,6 @@ snapshot_files = { "lib/librustc-*.dylib", "lib/libsyntax-*.dylib", "lib/librustuv-*.dylib", - "lib/librustrt.dylib", "lib/librustllvm.dylib"], "winnt": ["bin/rustc.exe", "bin/std-*.dll", @@ -47,7 +45,6 @@ snapshot_files = { "bin/rustc-*.dll", "bin/syntax-*.dll", "bin/rustuv-*.dll", - "bin/rustrt.dll", "bin/rustllvm.dll"], "freebsd": ["bin/rustc", "lib/libstd-*.so", @@ -55,7 +52,6 @@ snapshot_files = { "lib/librustc-*.so", "lib/libsyntax-*.so", "lib/librustuv-*.so", - "lib/librustrt.so", "lib/librustllvm.so"] } diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs index 761d630f771..ba4f120f626 100644 --- a/src/libstd/rtdeps.rs +++ b/src/libstd/rtdeps.rs @@ -13,7 +13,7 @@ //! necessary for running libstd. // All platforms need to link to rustrt -#[link(name = "rustrt")] +#[link(name = "rustrt", kind = "static")] extern {} // LLVM implements the `frem` instruction as a call to `fmod`, which lives in @@ -26,6 +26,7 @@ extern {} #[link(name = "dl")] #[link(name = "m")] #[link(name = "pthread")] +#[link(name = "stdc++")] extern {} #[cfg(target_os = "android")] @@ -45,4 +46,9 @@ extern {} #[cfg(target_os = "macos")] #[link(name = "pthread")] +#[link(name = "stdc++")] +extern {} + +#[cfg(stage0)] +#[link_args = "-lstdc++"] extern {} diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in deleted file mode 100644 index 2a3e687ee55..00000000000 --- a/src/rt/rustrt.def.in +++ /dev/null @@ -1,51 +0,0 @@ -rust_dbg_abi_1 -rust_dbg_abi_2 -rust_dbg_static_mut -rust_dbg_static_mut_check_four -rust_get_time -rust_tzset -rust_gmtime -rust_localtime -rust_timegm -rust_mktime -rust_precise_time_ns -rust_list_dir_val -rust_list_dir_wfd_size -rust_list_dir_wfd_fp_buf -rust_unset_sigprocmask -rust_env_pairs -rust_win32_rand_acquire -rust_win32_rand_gen -rust_win32_rand_release -upcall_rust_personality -upcall_reset_stack_limit -rust_dbg_call -rust_dbg_do_nothing -tdefl_compress_mem_to_heap -tinfl_decompress_mem_to_heap -rust_swap_registers -rust_readdir -rust_opendir -rust_dbg_extern_identity_u32 -rust_dbg_extern_identity_u64 -rust_dbg_extern_identity_TwoU8s -rust_dbg_extern_identity_TwoU16s -rust_dbg_extern_identity_TwoU32s -rust_dbg_extern_identity_TwoU64s -rust_dbg_extern_identity_TwoDoubles -rust_dbg_extern_return_TwoU8s -rust_dbg_extern_return_TwoU16s -rust_dbg_extern_return_TwoU32s -rust_dbg_extern_return_TwoU64s -rust_dbg_extern_identity_double -rust_dbg_extern_identity_u8 -rust_try -rust_begin_unwind -rust_valgrind_stack_register -rust_valgrind_stack_deregister -rust_running_on_valgrind -rust_get_num_cpus -rust_get_test_int -rust_pthread_mutex_t_size -rust_pthread_cond_t_size -rust_crit_section_size diff --git a/src/test/auxiliary/anon-extern-mod-cross-crate-1.rs b/src/test/auxiliary/anon-extern-mod-cross-crate-1.rs index ca9c6eb79f9..01a90f1ad44 100644 --- a/src/test/auxiliary/anon-extern-mod-cross-crate-1.rs +++ b/src/test/auxiliary/anon-extern-mod-cross-crate-1.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[link_name = "rustrt"]; -#[link(name = "anonexternmod", - vers = "0.1")]; +#[link(name = "anonexternmod", vers = "0.1")]; #[crate_type = "lib"]; use std::libc; extern { + #[link(name = "rustrt")] pub fn rust_get_test_int() -> libc::intptr_t; } diff --git a/src/test/auxiliary/extern-crosscrate-source.rs b/src/test/auxiliary/extern-crosscrate-source.rs index e77efce7f58..89317a45171 100644 --- a/src/test/auxiliary/extern-crosscrate-source.rs +++ b/src/test/auxiliary/extern-crosscrate-source.rs @@ -18,6 +18,7 @@ use std::libc; pub mod rustrt { use std::libc; + #[link(name = "rustrt")] extern { pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t, data: libc::uintptr_t) diff --git a/src/test/auxiliary/foreign_lib.rs b/src/test/auxiliary/foreign_lib.rs index d67e329b04e..4705d13cd96 100644 --- a/src/test/auxiliary/foreign_lib.rs +++ b/src/test/auxiliary/foreign_lib.rs @@ -13,6 +13,7 @@ pub mod rustrt { use std::libc; + #[link(name = "rustrt")] extern { fn rust_get_test_int() -> libc::intptr_t; } diff --git a/src/test/run-pass/anon-extern-mod-cross-crate-2.rs b/src/test/run-pass/anon-extern-mod-cross-crate-2.rs index a9c6141c18b..65421227054 100644 --- a/src/test/run-pass/anon-extern-mod-cross-crate-2.rs +++ b/src/test/run-pass/anon-extern-mod-cross-crate-2.rs @@ -14,6 +14,9 @@ extern mod anonexternmod; use anonexternmod::rust_get_test_int; +#[link(name = "rustrt")] // we have explicitly chosen to require this +extern {} + pub fn main() { unsafe { rust_get_test_int(); diff --git a/src/test/run-pass/anon-extern-mod.rs b/src/test/run-pass/anon-extern-mod.rs index 3323aa4e2cd..7e05bcc1fd2 100644 --- a/src/test/run-pass/anon-extern-mod.rs +++ b/src/test/run-pass/anon-extern-mod.rs @@ -10,7 +10,7 @@ use std::libc; -#[link_name = "rustrt"] +#[link(name = "rustrt")] extern { fn rust_get_test_int() -> libc::intptr_t; } diff --git a/src/test/run-pass/c-stack-as-value.rs b/src/test/run-pass/c-stack-as-value.rs index f8d30a9a667..d590c35d9e2 100644 --- a/src/test/run-pass/c-stack-as-value.rs +++ b/src/test/run-pass/c-stack-as-value.rs @@ -11,6 +11,7 @@ mod rustrt { use std::libc; + #[link(name = "rustrt")] extern { pub fn rust_get_test_int() -> libc::intptr_t; } diff --git a/src/test/run-pass/extern-call-deep.rs b/src/test/run-pass/extern-call-deep.rs index f55be369b57..e3b727fafd3 100644 --- a/src/test/run-pass/extern-call-deep.rs +++ b/src/test/run-pass/extern-call-deep.rs @@ -13,6 +13,7 @@ use std::libc; mod rustrt { use std::libc; + #[link(name = "rustrt")] extern { pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t, data: libc::uintptr_t) diff --git a/src/test/run-pass/extern-call-deep2.rs b/src/test/run-pass/extern-call-deep2.rs index 5bda762a68b..00ac0bfa118 100644 --- a/src/test/run-pass/extern-call-deep2.rs +++ b/src/test/run-pass/extern-call-deep2.rs @@ -14,6 +14,7 @@ use std::task; mod rustrt { use std::libc; + #[link(name = "rustrt")] extern { pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t, data: libc::uintptr_t) diff --git a/src/test/run-pass/extern-call-indirect.rs b/src/test/run-pass/extern-call-indirect.rs index 6222b681dc9..c49d589572c 100644 --- a/src/test/run-pass/extern-call-indirect.rs +++ b/src/test/run-pass/extern-call-indirect.rs @@ -13,6 +13,7 @@ use std::libc; mod rustrt { use std::libc; + #[link(name = "rustrt")] extern { pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t, data: libc::uintptr_t) diff --git a/src/test/run-pass/extern-call-scrub.rs b/src/test/run-pass/extern-call-scrub.rs index 548336962f5..0044f0f468f 100644 --- a/src/test/run-pass/extern-call-scrub.rs +++ b/src/test/run-pass/extern-call-scrub.rs @@ -18,6 +18,7 @@ use std::task; mod rustrt { use std::libc; + #[link(name = "rustrt")] extern { pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t, data: libc::uintptr_t) diff --git a/src/test/run-pass/extern-pass-TwoU16s.rs b/src/test/run-pass/extern-pass-TwoU16s.rs index bb6a68dfda4..c224a2f1f05 100644 --- a/src/test/run-pass/extern-pass-TwoU16s.rs +++ b/src/test/run-pass/extern-pass-TwoU16s.rs @@ -18,6 +18,7 @@ struct TwoU16s { one: u16, two: u16 } +#[link(name = "rustrt")] extern { pub fn rust_dbg_extern_identity_TwoU16s(v: TwoU16s) -> TwoU16s; } diff --git a/src/test/run-pass/extern-pass-TwoU32s.rs b/src/test/run-pass/extern-pass-TwoU32s.rs index 3389c56c83b..592d42c65d1 100644 --- a/src/test/run-pass/extern-pass-TwoU32s.rs +++ b/src/test/run-pass/extern-pass-TwoU32s.rs @@ -16,6 +16,7 @@ struct TwoU32s { one: u32, two: u32 } +#[link(name = "rustrt")] extern { pub fn rust_dbg_extern_identity_TwoU32s(v: TwoU32s) -> TwoU32s; } diff --git a/src/test/run-pass/extern-pass-TwoU64s.rs b/src/test/run-pass/extern-pass-TwoU64s.rs index 033359f85fa..d2520f32c7b 100644 --- a/src/test/run-pass/extern-pass-TwoU64s.rs +++ b/src/test/run-pass/extern-pass-TwoU64s.rs @@ -18,6 +18,7 @@ struct TwoU64s { one: u64, two: u64 } +#[link(name = "rustrt")] extern { pub fn rust_dbg_extern_identity_TwoU64s(v: TwoU64s) -> TwoU64s; } diff --git a/src/test/run-pass/extern-pass-TwoU8s.rs b/src/test/run-pass/extern-pass-TwoU8s.rs index 8757f9593f7..5548b8a7d39 100644 --- a/src/test/run-pass/extern-pass-TwoU8s.rs +++ b/src/test/run-pass/extern-pass-TwoU8s.rs @@ -18,6 +18,7 @@ struct TwoU8s { one: u8, two: u8 } +#[link(name = "rustrt")] extern { pub fn rust_dbg_extern_identity_TwoU8s(v: TwoU8s) -> TwoU8s; } diff --git a/src/test/run-pass/extern-pass-char.rs b/src/test/run-pass/extern-pass-char.rs index 0cdfaf29a05..85d0463fe72 100644 --- a/src/test/run-pass/extern-pass-char.rs +++ b/src/test/run-pass/extern-pass-char.rs @@ -10,6 +10,7 @@ // Test a function that takes/returns a u8. +#[link(name = "rustrt")] extern { pub fn rust_dbg_extern_identity_u8(v: u8) -> u8; } diff --git a/src/test/run-pass/extern-pass-double.rs b/src/test/run-pass/extern-pass-double.rs index cb0a061a7ab..2d35fe6043e 100644 --- a/src/test/run-pass/extern-pass-double.rs +++ b/src/test/run-pass/extern-pass-double.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[link(name = "rustrt")] extern { pub fn rust_dbg_extern_identity_double(v: f64) -> f64; } diff --git a/src/test/run-pass/extern-pass-u32.rs b/src/test/run-pass/extern-pass-u32.rs index aa54f014046..5ff3353a8c0 100644 --- a/src/test/run-pass/extern-pass-u32.rs +++ b/src/test/run-pass/extern-pass-u32.rs @@ -10,6 +10,7 @@ // Test a function that takes/returns a u32. +#[link(name = "rustrt")] extern { pub fn rust_dbg_extern_identity_u32(v: u32) -> u32; } diff --git a/src/test/run-pass/extern-pass-u64.rs b/src/test/run-pass/extern-pass-u64.rs index 7c39080a568..b94c57a7a66 100644 --- a/src/test/run-pass/extern-pass-u64.rs +++ b/src/test/run-pass/extern-pass-u64.rs @@ -10,6 +10,7 @@ // Test a call to a function that takes/returns a u64. +#[link(name = "rustrt")] extern { pub fn rust_dbg_extern_identity_u64(v: u64) -> u64; } diff --git a/src/test/run-pass/extern-return-TwoU16s.rs b/src/test/run-pass/extern-return-TwoU16s.rs index ba671a1c494..45efbbb2785 100644 --- a/src/test/run-pass/extern-return-TwoU16s.rs +++ b/src/test/run-pass/extern-return-TwoU16s.rs @@ -12,6 +12,7 @@ struct TwoU16s { one: u16, two: u16 } +#[link(name = "rustrt")] extern { pub fn rust_dbg_extern_return_TwoU16s() -> TwoU16s; } diff --git a/src/test/run-pass/extern-return-TwoU32s.rs b/src/test/run-pass/extern-return-TwoU32s.rs index 90562f0f6b1..8258ee623ab 100644 --- a/src/test/run-pass/extern-return-TwoU32s.rs +++ b/src/test/run-pass/extern-return-TwoU32s.rs @@ -12,6 +12,7 @@ struct TwoU32s { one: u32, two: u32 } +#[link(name = "rustrt")] extern { pub fn rust_dbg_extern_return_TwoU32s() -> TwoU32s; } diff --git a/src/test/run-pass/extern-return-TwoU64s.rs b/src/test/run-pass/extern-return-TwoU64s.rs index b52808ea32d..d8b051f57a9 100644 --- a/src/test/run-pass/extern-return-TwoU64s.rs +++ b/src/test/run-pass/extern-return-TwoU64s.rs @@ -14,6 +14,7 @@ struct TwoU64s { one: u64, two: u64 } +#[link(name = "rustrt")] extern { pub fn rust_dbg_extern_return_TwoU64s() -> TwoU64s; } diff --git a/src/test/run-pass/extern-return-TwoU8s.rs b/src/test/run-pass/extern-return-TwoU8s.rs index 5d2fd140758..99dbd93fb7d 100644 --- a/src/test/run-pass/extern-return-TwoU8s.rs +++ b/src/test/run-pass/extern-return-TwoU8s.rs @@ -12,6 +12,7 @@ struct TwoU8s { one: u8, two: u8 } +#[link(name = "rustrt")] extern { pub fn rust_dbg_extern_return_TwoU8s() -> TwoU8s; } diff --git a/src/test/run-pass/extern-stress.rs b/src/test/run-pass/extern-stress.rs index 6ef196ccd41..7c16ae74c4a 100644 --- a/src/test/run-pass/extern-stress.rs +++ b/src/test/run-pass/extern-stress.rs @@ -17,6 +17,7 @@ use std::task; mod rustrt { use std::libc; + #[link(name = "rustrt")] extern { pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t, data: libc::uintptr_t) diff --git a/src/test/run-pass/extern-yield.rs b/src/test/run-pass/extern-yield.rs index 1d2f52d8c2e..a4ac197ac6a 100644 --- a/src/test/run-pass/extern-yield.rs +++ b/src/test/run-pass/extern-yield.rs @@ -14,6 +14,7 @@ use std::task; mod rustrt { use std::libc; + #[link(name = "rustrt")] extern { pub fn rust_dbg_call(cb: extern "C" fn (libc::uintptr_t) -> libc::uintptr_t, data: libc::uintptr_t) diff --git a/src/test/run-pass/foreign-call-no-runtime.rs b/src/test/run-pass/foreign-call-no-runtime.rs index 283efa2ac7c..ee54423a97d 100644 --- a/src/test/run-pass/foreign-call-no-runtime.rs +++ b/src/test/run-pass/foreign-call-no-runtime.rs @@ -2,6 +2,7 @@ use std::cast; use std::libc; use std::unstable::run_in_bare_thread; +#[link(name = "rustrt")] extern { fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t), data: libc::uintptr_t) -> libc::uintptr_t; diff --git a/src/test/run-pass/foreign-dupe.rs b/src/test/run-pass/foreign-dupe.rs index 66d3bda30e6..260b1f272c2 100644 --- a/src/test/run-pass/foreign-dupe.rs +++ b/src/test/run-pass/foreign-dupe.rs @@ -14,7 +14,7 @@ mod rustrt1 { use std::libc; - #[link_name = "rustrt"] + #[link(name = "rustrt")] extern { pub fn rust_get_test_int() -> libc::intptr_t; } @@ -23,7 +23,7 @@ mod rustrt1 { mod rustrt2 { use std::libc; - #[link_name = "rustrt"] + #[link(name = "rustrt")] extern { pub fn rust_get_test_int() -> libc::intptr_t; } diff --git a/src/test/run-pass/foreign-no-abi.rs b/src/test/run-pass/foreign-no-abi.rs index 0702d49cfc1..eef45532265 100644 --- a/src/test/run-pass/foreign-no-abi.rs +++ b/src/test/run-pass/foreign-no-abi.rs @@ -13,6 +13,7 @@ mod rustrt { use std::libc; + #[link(name = "rustrt")] extern { pub fn rust_get_test_int() -> libc::intptr_t; } diff --git a/src/test/run-pass/invoke-external-foreign.rs b/src/test/run-pass/invoke-external-foreign.rs index 7e79311c5ad..6850e9d9bd2 100644 --- a/src/test/run-pass/invoke-external-foreign.rs +++ b/src/test/run-pass/invoke-external-foreign.rs @@ -17,6 +17,9 @@ extern mod foreign_lib; +#[link(name = "rustrt")] // we have explicitly chosen to require this +extern {} + pub fn main() { unsafe { let _foo = foreign_lib::rustrt::rust_get_test_int(); diff --git a/src/test/run-pass/static-mut-foreign.rs b/src/test/run-pass/static-mut-foreign.rs index bdfc747c8bc..0afe01bf7ed 100644 --- a/src/test/run-pass/static-mut-foreign.rs +++ b/src/test/run-pass/static-mut-foreign.rs @@ -14,7 +14,7 @@ use std::libc; -#[nolink] +#[link(name = "rustrt")] extern { static mut rust_dbg_static_mut: libc::c_int; pub fn rust_dbg_static_mut_check_four(); diff --git a/src/test/run-pass/struct-return.rs b/src/test/run-pass/struct-return.rs index 324186021b8..e2fe7a96016 100644 --- a/src/test/run-pass/struct-return.rs +++ b/src/test/run-pass/struct-return.rs @@ -16,7 +16,7 @@ pub struct Floats { a: f64, b: u8, c: f64 } mod rustrt { use super::{Floats, Quad}; - #[nolink] + #[link(name = "rustrt")] extern { pub fn rust_dbg_abi_1(q: Quad) -> Quad; pub fn rust_dbg_abi_2(f: Floats) -> Floats; From 6d6ccb75ff2240ed294fcf6aa57e96c72316954c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 16 Nov 2013 17:07:32 -0800 Subject: [PATCH 3/5] Add a new run-make test directory This infrastructure is meant to support runnings tests that involve various interesting interdependencies about the types of crates being linked or possibly interacting with C libraries. The goal of these make tests is to not restrict them to a particular test runner, but allow each test to run its own tests. To this end, there is a new src/test/run-make directory which has sub-folders of tests. Each test requires a `Makefile`, and running the tests constitues simply running `make` inside the directory. The new target is `check-stageN-rmake`. These tests will have the destination directory (as TMPDIR) and the local rust compiler (as RUSTC) passed along to them. There is also some helpful cross-platform utilities included in src/test/run-make/tools.mk to aid with compiling C programs and running them. The impetus for adding this new test suite is to allow various interesting forms of testing rust linkage. All of the tests initially added are various flavors of compiling Rust and C with one another as well as just making sure that rust linkage works in general. Closes #10434 --- mk/tests.mk | 39 ++++++++++++++++++- src/etc/maketest.py | 26 +++++++++++++ src/test/run-make/c-dynamic-dylib/Makefile | 14 +++++++ src/test/run-make/c-dynamic-dylib/bar.rs | 5 +++ src/test/run-make/c-dynamic-dylib/cfoo.c | 1 + src/test/run-make/c-dynamic-dylib/foo.rs | 10 +++++ src/test/run-make/c-dynamic-rlib/Makefile | 14 +++++++ src/test/run-make/c-dynamic-rlib/bar.rs | 5 +++ src/test/run-make/c-dynamic-rlib/cfoo.c | 1 + src/test/run-make/c-dynamic-rlib/foo.rs | 10 +++++ .../run-make/c-link-to-rust-dylib/Makefile | 9 +++++ src/test/run-make/c-link-to-rust-dylib/bar.c | 6 +++ src/test/run-make/c-link-to-rust-dylib/foo.rs | 4 ++ .../c-link-to-rust-staticlib/Makefile | 13 +++++++ .../run-make/c-link-to-rust-staticlib/bar.c | 6 +++ .../run-make/c-link-to-rust-staticlib/foo.rs | 4 ++ src/test/run-make/c-static-dylib/Makefile | 9 +++++ src/test/run-make/c-static-dylib/bar.rs | 5 +++ src/test/run-make/c-static-dylib/cfoo.c | 1 + src/test/run-make/c-static-dylib/foo.rs | 10 +++++ src/test/run-make/c-static-rlib/Makefile | 8 ++++ src/test/run-make/c-static-rlib/bar.rs | 5 +++ src/test/run-make/c-static-rlib/cfoo.c | 1 + src/test/run-make/c-static-rlib/foo.rs | 10 +++++ src/test/run-make/dylib-chain/Makefile | 12 ++++++ src/test/run-make/dylib-chain/m1.rs | 2 + src/test/run-make/dylib-chain/m2.rs | 4 ++ src/test/run-make/dylib-chain/m3.rs | 4 ++ src/test/run-make/dylib-chain/m4.rs | 3 ++ src/test/run-make/mixing-deps/Makefile | 7 ++++ src/test/run-make/mixing-deps/both.rs | 4 ++ src/test/run-make/mixing-deps/dylib.rs | 6 +++ src/test/run-make/mixing-deps/prog.rs | 9 +++++ src/test/run-make/mixing-libs/Makefile | 9 +++++ src/test/run-make/mixing-libs/dylib.rs | 4 ++ src/test/run-make/mixing-libs/prog.rs | 7 ++++ src/test/run-make/mixing-libs/rlib.rs | 2 + src/test/run-make/prefer-dylib/Makefile | 8 ++++ src/test/run-make/prefer-dylib/bar.rs | 1 + src/test/run-make/prefer-dylib/foo.rs | 5 +++ src/test/run-make/prefer-rlib/Makefile | 8 ++++ src/test/run-make/prefer-rlib/bar.rs | 1 + src/test/run-make/prefer-rlib/foo.rs | 5 +++ src/test/run-make/rlib-chain/Makefile | 10 +++++ src/test/run-make/rlib-chain/m1.rs | 2 + src/test/run-make/rlib-chain/m2.rs | 4 ++ src/test/run-make/rlib-chain/m3.rs | 4 ++ src/test/run-make/rlib-chain/m4.rs | 3 ++ src/test/run-make/simple-dylib/Makefile | 5 +++ src/test/run-make/simple-dylib/bar.rs | 1 + src/test/run-make/simple-dylib/foo.rs | 5 +++ src/test/run-make/simple-rlib/Makefile | 5 +++ src/test/run-make/simple-rlib/bar.rs | 1 + src/test/run-make/simple-rlib/foo.rs | 5 +++ src/test/run-make/static-unwinding/Makefile | 6 +++ src/test/run-make/static-unwinding/lib.rs | 15 +++++++ src/test/run-make/static-unwinding/main.rs | 25 ++++++++++++ src/test/run-make/tools.mk | 27 +++++++++++++ 58 files changed, 433 insertions(+), 2 deletions(-) create mode 100644 src/etc/maketest.py create mode 100644 src/test/run-make/c-dynamic-dylib/Makefile create mode 100644 src/test/run-make/c-dynamic-dylib/bar.rs create mode 100644 src/test/run-make/c-dynamic-dylib/cfoo.c create mode 100644 src/test/run-make/c-dynamic-dylib/foo.rs create mode 100644 src/test/run-make/c-dynamic-rlib/Makefile create mode 100644 src/test/run-make/c-dynamic-rlib/bar.rs create mode 100644 src/test/run-make/c-dynamic-rlib/cfoo.c create mode 100644 src/test/run-make/c-dynamic-rlib/foo.rs create mode 100644 src/test/run-make/c-link-to-rust-dylib/Makefile create mode 100644 src/test/run-make/c-link-to-rust-dylib/bar.c create mode 100644 src/test/run-make/c-link-to-rust-dylib/foo.rs create mode 100644 src/test/run-make/c-link-to-rust-staticlib/Makefile create mode 100644 src/test/run-make/c-link-to-rust-staticlib/bar.c create mode 100644 src/test/run-make/c-link-to-rust-staticlib/foo.rs create mode 100644 src/test/run-make/c-static-dylib/Makefile create mode 100644 src/test/run-make/c-static-dylib/bar.rs create mode 100644 src/test/run-make/c-static-dylib/cfoo.c create mode 100644 src/test/run-make/c-static-dylib/foo.rs create mode 100644 src/test/run-make/c-static-rlib/Makefile create mode 100644 src/test/run-make/c-static-rlib/bar.rs create mode 100644 src/test/run-make/c-static-rlib/cfoo.c create mode 100644 src/test/run-make/c-static-rlib/foo.rs create mode 100644 src/test/run-make/dylib-chain/Makefile create mode 100644 src/test/run-make/dylib-chain/m1.rs create mode 100644 src/test/run-make/dylib-chain/m2.rs create mode 100644 src/test/run-make/dylib-chain/m3.rs create mode 100644 src/test/run-make/dylib-chain/m4.rs create mode 100644 src/test/run-make/mixing-deps/Makefile create mode 100644 src/test/run-make/mixing-deps/both.rs create mode 100644 src/test/run-make/mixing-deps/dylib.rs create mode 100644 src/test/run-make/mixing-deps/prog.rs create mode 100644 src/test/run-make/mixing-libs/Makefile create mode 100644 src/test/run-make/mixing-libs/dylib.rs create mode 100644 src/test/run-make/mixing-libs/prog.rs create mode 100644 src/test/run-make/mixing-libs/rlib.rs create mode 100644 src/test/run-make/prefer-dylib/Makefile create mode 100644 src/test/run-make/prefer-dylib/bar.rs create mode 100644 src/test/run-make/prefer-dylib/foo.rs create mode 100644 src/test/run-make/prefer-rlib/Makefile create mode 100644 src/test/run-make/prefer-rlib/bar.rs create mode 100644 src/test/run-make/prefer-rlib/foo.rs create mode 100644 src/test/run-make/rlib-chain/Makefile create mode 100644 src/test/run-make/rlib-chain/m1.rs create mode 100644 src/test/run-make/rlib-chain/m2.rs create mode 100644 src/test/run-make/rlib-chain/m3.rs create mode 100644 src/test/run-make/rlib-chain/m4.rs create mode 100644 src/test/run-make/simple-dylib/Makefile create mode 100644 src/test/run-make/simple-dylib/bar.rs create mode 100644 src/test/run-make/simple-dylib/foo.rs create mode 100644 src/test/run-make/simple-rlib/Makefile create mode 100644 src/test/run-make/simple-rlib/bar.rs create mode 100644 src/test/run-make/simple-rlib/foo.rs create mode 100644 src/test/run-make/static-unwinding/Makefile create mode 100644 src/test/run-make/static-unwinding/lib.rs create mode 100644 src/test/run-make/static-unwinding/main.rs create mode 100644 src/test/run-make/tools.mk diff --git a/mk/tests.mk b/mk/tests.mk index c3614cbcc6b..5b021eb48f1 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -193,7 +193,7 @@ check-lite: cleantestlibs cleantmptestlogs \ check-stage2-std check-stage2-extra check-stage2-rpass \ check-stage2-rustuv \ check-stage2-rustpkg \ - check-stage2-rfail check-stage2-cfail + check-stage2-rfail check-stage2-cfail check-stage2-rmake $(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log .PHONY: cleantmptestlogs cleantestlibs @@ -284,7 +284,8 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \ check-stage$(1)-T-$(2)-H-$(3)-rfail-exec \ check-stage$(1)-T-$(2)-H-$(3)-cfail-exec \ check-stage$(1)-T-$(2)-H-$(3)-rpass-full-exec \ - check-stage$(1)-T-$(2)-H-$(3)-crates-exec \ + check-stage$(1)-T-$(2)-H-$(3)-rmake-exec \ + check-stage$(1)-T-$(2)-H-$(3)-crates-exec \ check-stage$(1)-T-$(2)-H-$(3)-bench-exec \ check-stage$(1)-T-$(2)-H-$(3)-debuginfo-exec \ check-stage$(1)-T-$(2)-H-$(3)-codegen-exec \ @@ -770,6 +771,7 @@ TEST_GROUPS = \ cfail \ bench \ perf \ + rmake \ debuginfo \ codegen \ doc \ @@ -900,3 +902,36 @@ endef $(foreach host,$(CFG_HOST), \ $(eval $(call DEF_CHECK_FAST_FOR_H,$(host)))) + +RMAKE_TESTS := $(shell ls -d $(S)src/test/run-make/*/) +RMAKE_TESTS := $(RMAKE_TESTS:$(S)src/test/run-make/%/=%) + +define DEF_RMAKE_FOR_T_H +# $(1) the stage +# $(2) target triple +# $(3) host triple + +check-stage$(1)-T-$(2)-H-$(3)-rmake-exec: \ + $$(call TEST_OK_FILE,$(1),$(2),$(3),rmake) + +$$(call TEST_OK_FILE,$(1),$(2),$(3),rmake): \ + $$(RMAKE_TESTS:%=$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok) + @touch $$@ + +$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \ + $(S)src/test/run-make/%/Makefile \ + $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) + @rm -rf $(3)/test/run-make/$$* + @mkdir -p $(3)/test/run-make/$$* + @echo maketest: $$* + @python $(S)src/etc/maketest.py $$(dir $$<) \ + $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ + $(3)/test/run-make/$$* + @touch $$@ + +endef + +$(foreach stage,$(STAGES), \ + $(foreach target,$(CFG_TARGET), \ + $(foreach host,$(CFG_HOST), \ + $(eval $(call DEF_RMAKE_FOR_T_H,$(stage),$(target),$(host)))))) diff --git a/src/etc/maketest.py b/src/etc/maketest.py new file mode 100644 index 00000000000..d42bf065657 --- /dev/null +++ b/src/etc/maketest.py @@ -0,0 +1,26 @@ +# xfail-license + +import subprocess +import os +import sys + +os.putenv('RUSTC', os.path.abspath(sys.argv[2])) +os.putenv('TMPDIR', os.path.abspath(sys.argv[3])) + +proc = subprocess.Popen(['make', '-C', sys.argv[1]], + stdout = subprocess.PIPE, + stderr = subprocess.PIPE) +out, err = proc.communicate() +i = proc.wait() + +if i != 0: + + print '----- ' + sys.argv[1] + """ -------------------- +------ stdout --------------------------------------------- +""" + out + """ +------ stderr --------------------------------------------- +""" + err + """ +------ --------------------------------------------- +""" + sys.exit(i) + diff --git a/src/test/run-make/c-dynamic-dylib/Makefile b/src/test/run-make/c-dynamic-dylib/Makefile new file mode 100644 index 00000000000..2b2e5d56e92 --- /dev/null +++ b/src/test/run-make/c-dynamic-dylib/Makefile @@ -0,0 +1,14 @@ +-include ../tools.mk + +# This hits an assertion in the linker on older versions of osx apparently +ifeq ($(shell uname),Darwin) +all: + echo ignored +else +all: $(call DYLIB,cfoo) + $(RUSTC) foo.rs + $(RUSTC) bar.rs + $(call RUN,bar) + rm $(TMPDIR)/$(call DYLIB_GLOB,cfoo) + $(call FAIL,bar) +endif diff --git a/src/test/run-make/c-dynamic-dylib/bar.rs b/src/test/run-make/c-dynamic-dylib/bar.rs new file mode 100644 index 00000000000..7c4aca1e028 --- /dev/null +++ b/src/test/run-make/c-dynamic-dylib/bar.rs @@ -0,0 +1,5 @@ +extern mod foo; + +fn main() { + foo::rsfoo(); +} diff --git a/src/test/run-make/c-dynamic-dylib/cfoo.c b/src/test/run-make/c-dynamic-dylib/cfoo.c new file mode 100644 index 00000000000..9fe07f82f9e --- /dev/null +++ b/src/test/run-make/c-dynamic-dylib/cfoo.c @@ -0,0 +1 @@ +int foo() { return 0; } diff --git a/src/test/run-make/c-dynamic-dylib/foo.rs b/src/test/run-make/c-dynamic-dylib/foo.rs new file mode 100644 index 00000000000..0c4a6f7df4b --- /dev/null +++ b/src/test/run-make/c-dynamic-dylib/foo.rs @@ -0,0 +1,10 @@ +#[crate_type = "dylib"]; + +#[link(name = "cfoo")] +extern { + fn foo(); +} + +pub fn rsfoo() { + unsafe { foo() } +} diff --git a/src/test/run-make/c-dynamic-rlib/Makefile b/src/test/run-make/c-dynamic-rlib/Makefile new file mode 100644 index 00000000000..18992703b2c --- /dev/null +++ b/src/test/run-make/c-dynamic-rlib/Makefile @@ -0,0 +1,14 @@ +-include ../tools.mk + +# This hits an assertion in the linker on older versions of osx apparently +ifeq ($(shell uname),Darwin) +all: + echo ignored +else +all: $(call DYLIB,cfoo) + $(RUSTC) foo.rs + $(RUSTC) bar.rs + LD_LIBRARY_PATH=$(TMPDIR) $(call RUN,bar) + rm $(TMPDIR)/$(call DYLIB_GLOB,cfoo) + $(call FAIL,bar) +endif diff --git a/src/test/run-make/c-dynamic-rlib/bar.rs b/src/test/run-make/c-dynamic-rlib/bar.rs new file mode 100644 index 00000000000..7c4aca1e028 --- /dev/null +++ b/src/test/run-make/c-dynamic-rlib/bar.rs @@ -0,0 +1,5 @@ +extern mod foo; + +fn main() { + foo::rsfoo(); +} diff --git a/src/test/run-make/c-dynamic-rlib/cfoo.c b/src/test/run-make/c-dynamic-rlib/cfoo.c new file mode 100644 index 00000000000..9fe07f82f9e --- /dev/null +++ b/src/test/run-make/c-dynamic-rlib/cfoo.c @@ -0,0 +1 @@ +int foo() { return 0; } diff --git a/src/test/run-make/c-dynamic-rlib/foo.rs b/src/test/run-make/c-dynamic-rlib/foo.rs new file mode 100644 index 00000000000..e64811af9c7 --- /dev/null +++ b/src/test/run-make/c-dynamic-rlib/foo.rs @@ -0,0 +1,10 @@ +#[crate_type = "rlib"]; + +#[link(name = "cfoo")] +extern { + fn foo(); +} + +pub fn rsfoo() { + unsafe { foo() } +} diff --git a/src/test/run-make/c-link-to-rust-dylib/Makefile b/src/test/run-make/c-link-to-rust-dylib/Makefile new file mode 100644 index 00000000000..fb57a08a826 --- /dev/null +++ b/src/test/run-make/c-link-to-rust-dylib/Makefile @@ -0,0 +1,9 @@ +-include ../tools.mk + +all: + $(RUSTC) foo.rs + ln -s $(call DYLIB,foo-*) $(call DYLIB,foo) + $(CC) bar.c -lfoo -o $(call RUN,bar) -Wl,-rpath,$(TMPDIR) + $(call RUN,bar) + rm $(call DYLIB,foo) + $(call FAIL,bar) diff --git a/src/test/run-make/c-link-to-rust-dylib/bar.c b/src/test/run-make/c-link-to-rust-dylib/bar.c new file mode 100644 index 00000000000..bb4036b06e1 --- /dev/null +++ b/src/test/run-make/c-link-to-rust-dylib/bar.c @@ -0,0 +1,6 @@ +void foo(); + +int main() { + foo(); + return 0; +} diff --git a/src/test/run-make/c-link-to-rust-dylib/foo.rs b/src/test/run-make/c-link-to-rust-dylib/foo.rs new file mode 100644 index 00000000000..6b6a786ef54 --- /dev/null +++ b/src/test/run-make/c-link-to-rust-dylib/foo.rs @@ -0,0 +1,4 @@ +#[crate_type = "dylib"]; + +#[no_mangle] +pub extern "C" fn foo() {} diff --git a/src/test/run-make/c-link-to-rust-staticlib/Makefile b/src/test/run-make/c-link-to-rust-staticlib/Makefile new file mode 100644 index 00000000000..a81f19d6eb3 --- /dev/null +++ b/src/test/run-make/c-link-to-rust-staticlib/Makefile @@ -0,0 +1,13 @@ +-include ../tools.mk + +ifneq ($(shell uname),Darwin) + EXTRAFLAGS := -lm -lrt -ldl -lpthread +endif + +all: + $(RUSTC) foo.rs -Z gen-crate-map + ln -s $(call STATICLIB,foo-*) $(call STATICLIB,foo) + $(CC) bar.c -lfoo -o $(call RUN,bar) $(EXTRAFLAGS) -lstdc++ + $(call RUN,bar) + rm $(call STATICLIB,foo*) + $(call RUN,bar) diff --git a/src/test/run-make/c-link-to-rust-staticlib/bar.c b/src/test/run-make/c-link-to-rust-staticlib/bar.c new file mode 100644 index 00000000000..bb4036b06e1 --- /dev/null +++ b/src/test/run-make/c-link-to-rust-staticlib/bar.c @@ -0,0 +1,6 @@ +void foo(); + +int main() { + foo(); + return 0; +} diff --git a/src/test/run-make/c-link-to-rust-staticlib/foo.rs b/src/test/run-make/c-link-to-rust-staticlib/foo.rs new file mode 100644 index 00000000000..3da09eb6bb6 --- /dev/null +++ b/src/test/run-make/c-link-to-rust-staticlib/foo.rs @@ -0,0 +1,4 @@ +#[crate_type = "staticlib"]; + +#[no_mangle] +pub extern "C" fn foo() {} diff --git a/src/test/run-make/c-static-dylib/Makefile b/src/test/run-make/c-static-dylib/Makefile new file mode 100644 index 00000000000..62d9c8e90f2 --- /dev/null +++ b/src/test/run-make/c-static-dylib/Makefile @@ -0,0 +1,9 @@ +-include ../tools.mk + +all: $(call STATICLIB,cfoo) + $(RUSTC) foo.rs + $(RUSTC) bar.rs + rm $(TMPDIR)/$(call STATICLIB_GLOB,cfoo) + $(call RUN,bar) + rm $(TMPDIR)/$(call DYLIB_GLOB,foo) + $(call FAIL,bar) diff --git a/src/test/run-make/c-static-dylib/bar.rs b/src/test/run-make/c-static-dylib/bar.rs new file mode 100644 index 00000000000..7c4aca1e028 --- /dev/null +++ b/src/test/run-make/c-static-dylib/bar.rs @@ -0,0 +1,5 @@ +extern mod foo; + +fn main() { + foo::rsfoo(); +} diff --git a/src/test/run-make/c-static-dylib/cfoo.c b/src/test/run-make/c-static-dylib/cfoo.c new file mode 100644 index 00000000000..9fe07f82f9e --- /dev/null +++ b/src/test/run-make/c-static-dylib/cfoo.c @@ -0,0 +1 @@ +int foo() { return 0; } diff --git a/src/test/run-make/c-static-dylib/foo.rs b/src/test/run-make/c-static-dylib/foo.rs new file mode 100644 index 00000000000..0c4a6f7df4b --- /dev/null +++ b/src/test/run-make/c-static-dylib/foo.rs @@ -0,0 +1,10 @@ +#[crate_type = "dylib"]; + +#[link(name = "cfoo")] +extern { + fn foo(); +} + +pub fn rsfoo() { + unsafe { foo() } +} diff --git a/src/test/run-make/c-static-rlib/Makefile b/src/test/run-make/c-static-rlib/Makefile new file mode 100644 index 00000000000..09eb4b1249e --- /dev/null +++ b/src/test/run-make/c-static-rlib/Makefile @@ -0,0 +1,8 @@ +-include ../tools.mk + +all: $(call STATICLIB,cfoo) + $(RUSTC) foo.rs + $(RUSTC) bar.rs + rm $(TMPDIR)/$(call RLIB_GLOB,foo) + rm $(TMPDIR)/$(call STATICLIB_GLOB,cfoo) + $(call RUN,bar) diff --git a/src/test/run-make/c-static-rlib/bar.rs b/src/test/run-make/c-static-rlib/bar.rs new file mode 100644 index 00000000000..7c4aca1e028 --- /dev/null +++ b/src/test/run-make/c-static-rlib/bar.rs @@ -0,0 +1,5 @@ +extern mod foo; + +fn main() { + foo::rsfoo(); +} diff --git a/src/test/run-make/c-static-rlib/cfoo.c b/src/test/run-make/c-static-rlib/cfoo.c new file mode 100644 index 00000000000..9fe07f82f9e --- /dev/null +++ b/src/test/run-make/c-static-rlib/cfoo.c @@ -0,0 +1 @@ +int foo() { return 0; } diff --git a/src/test/run-make/c-static-rlib/foo.rs b/src/test/run-make/c-static-rlib/foo.rs new file mode 100644 index 00000000000..e64811af9c7 --- /dev/null +++ b/src/test/run-make/c-static-rlib/foo.rs @@ -0,0 +1,10 @@ +#[crate_type = "rlib"]; + +#[link(name = "cfoo")] +extern { + fn foo(); +} + +pub fn rsfoo() { + unsafe { foo() } +} diff --git a/src/test/run-make/dylib-chain/Makefile b/src/test/run-make/dylib-chain/Makefile new file mode 100644 index 00000000000..e60e904240d --- /dev/null +++ b/src/test/run-make/dylib-chain/Makefile @@ -0,0 +1,12 @@ +-include ../tools.mk + +all: + $(RUSTC) m1.rs + $(RUSTC) m2.rs + $(RUSTC) m3.rs + $(RUSTC) m4.rs + $(call RUN,m4) + rm $(TMPDIR)/$(call DYLIB_GLOB,m1) + rm $(TMPDIR)/$(call DYLIB_GLOB,m2) + rm $(TMPDIR)/$(call DYLIB_GLOB,m3) + $(call FAIL,m4) diff --git a/src/test/run-make/dylib-chain/m1.rs b/src/test/run-make/dylib-chain/m1.rs new file mode 100644 index 00000000000..69ea8dcecfc --- /dev/null +++ b/src/test/run-make/dylib-chain/m1.rs @@ -0,0 +1,2 @@ +#[crate_type = "dylib"]; +pub fn m1() {} diff --git a/src/test/run-make/dylib-chain/m2.rs b/src/test/run-make/dylib-chain/m2.rs new file mode 100644 index 00000000000..2f5d75a3872 --- /dev/null +++ b/src/test/run-make/dylib-chain/m2.rs @@ -0,0 +1,4 @@ +#[crate_type = "dylib"]; +extern mod m1; + +pub fn m2() { m1::m1() } diff --git a/src/test/run-make/dylib-chain/m3.rs b/src/test/run-make/dylib-chain/m3.rs new file mode 100644 index 00000000000..cc4ff2cff74 --- /dev/null +++ b/src/test/run-make/dylib-chain/m3.rs @@ -0,0 +1,4 @@ +#[crate_type = "dylib"]; +extern mod m2; + +pub fn m3() { m2::m2() } diff --git a/src/test/run-make/dylib-chain/m4.rs b/src/test/run-make/dylib-chain/m4.rs new file mode 100644 index 00000000000..c52d1f7fcbc --- /dev/null +++ b/src/test/run-make/dylib-chain/m4.rs @@ -0,0 +1,3 @@ +extern mod m3; + +fn main() { m3::m3() } diff --git a/src/test/run-make/mixing-deps/Makefile b/src/test/run-make/mixing-deps/Makefile new file mode 100644 index 00000000000..9ab2abca729 --- /dev/null +++ b/src/test/run-make/mixing-deps/Makefile @@ -0,0 +1,7 @@ +-include ../tools.mk + +all: + $(RUSTC) both.rs + $(RUSTC) dylib.rs -Z prefer-dynamic + $(RUSTC) prog.rs + $(call RUN,prog) diff --git a/src/test/run-make/mixing-deps/both.rs b/src/test/run-make/mixing-deps/both.rs new file mode 100644 index 00000000000..89d7b6452c9 --- /dev/null +++ b/src/test/run-make/mixing-deps/both.rs @@ -0,0 +1,4 @@ +#[crate_type = "rlib"]; +#[crate_type = "dylib"]; + +pub static foo: int = 4; diff --git a/src/test/run-make/mixing-deps/dylib.rs b/src/test/run-make/mixing-deps/dylib.rs new file mode 100644 index 00000000000..130bc2fe803 --- /dev/null +++ b/src/test/run-make/mixing-deps/dylib.rs @@ -0,0 +1,6 @@ +#[crate_type = "dylib"]; +extern mod both; + +use std::cast; + +pub fn addr() -> uint { unsafe { cast::transmute(&both::foo) } } diff --git a/src/test/run-make/mixing-deps/prog.rs b/src/test/run-make/mixing-deps/prog.rs new file mode 100644 index 00000000000..da90f8731f4 --- /dev/null +++ b/src/test/run-make/mixing-deps/prog.rs @@ -0,0 +1,9 @@ +extern mod dylib; +extern mod both; + +use std::cast; + +fn main() { + assert_eq!(unsafe { cast::transmute::<&int, uint>(&both::foo) }, + dylib::addr()); +} diff --git a/src/test/run-make/mixing-libs/Makefile b/src/test/run-make/mixing-libs/Makefile new file mode 100644 index 00000000000..eb00c801390 --- /dev/null +++ b/src/test/run-make/mixing-libs/Makefile @@ -0,0 +1,9 @@ +-include ../tools.mk + +all: + $(RUSTC) rlib.rs + $(RUSTC) dylib.rs && exit 1 || exit 0 + $(RUSTC) rlib.rs --dylib + $(RUSTC) dylib.rs + rm $(call DYLIB,rlib-*) + $(RUSTC) prog.rs && exit 1 || exit 0 diff --git a/src/test/run-make/mixing-libs/dylib.rs b/src/test/run-make/mixing-libs/dylib.rs new file mode 100644 index 00000000000..9652cb27641 --- /dev/null +++ b/src/test/run-make/mixing-libs/dylib.rs @@ -0,0 +1,4 @@ +#[crate_type = "dylib"]; +extern mod rlib; + +pub fn dylib() { rlib::rlib() } diff --git a/src/test/run-make/mixing-libs/prog.rs b/src/test/run-make/mixing-libs/prog.rs new file mode 100644 index 00000000000..ec67dea0ab0 --- /dev/null +++ b/src/test/run-make/mixing-libs/prog.rs @@ -0,0 +1,7 @@ +extern mod dylib; +extern mod rlib; + +fn main() { + dylib::dylib(); + rlib::rlib(); +} diff --git a/src/test/run-make/mixing-libs/rlib.rs b/src/test/run-make/mixing-libs/rlib.rs new file mode 100644 index 00000000000..32c322f3f59 --- /dev/null +++ b/src/test/run-make/mixing-libs/rlib.rs @@ -0,0 +1,2 @@ +#[crate_type = "rlib"]; +pub fn rlib() {} diff --git a/src/test/run-make/prefer-dylib/Makefile b/src/test/run-make/prefer-dylib/Makefile new file mode 100644 index 00000000000..8229547176a --- /dev/null +++ b/src/test/run-make/prefer-dylib/Makefile @@ -0,0 +1,8 @@ +-include ../tools.mk + +all: + $(RUSTC) bar.rs --dylib --rlib + $(RUSTC) foo.rs -Z prefer-dynamic + $(call RUN,foo) + rm $(TMPDIR)/*bar* + $(call FAILS,foo) diff --git a/src/test/run-make/prefer-dylib/bar.rs b/src/test/run-make/prefer-dylib/bar.rs new file mode 100644 index 00000000000..c5c0bc606cd --- /dev/null +++ b/src/test/run-make/prefer-dylib/bar.rs @@ -0,0 +1 @@ +pub fn bar() {} diff --git a/src/test/run-make/prefer-dylib/foo.rs b/src/test/run-make/prefer-dylib/foo.rs new file mode 100644 index 00000000000..f86ef62a9fe --- /dev/null +++ b/src/test/run-make/prefer-dylib/foo.rs @@ -0,0 +1,5 @@ +extern mod bar; + +fn main() { + bar::bar(); +} diff --git a/src/test/run-make/prefer-rlib/Makefile b/src/test/run-make/prefer-rlib/Makefile new file mode 100644 index 00000000000..eedb70c4efd --- /dev/null +++ b/src/test/run-make/prefer-rlib/Makefile @@ -0,0 +1,8 @@ +-include ../tools.mk + +all: + $(RUSTC) bar.rs --dylib --rlib + ls $(TMPDIR)/$(call RLIB_GLOB,bar) + $(RUSTC) foo.rs + rm $(TMPDIR)/*bar* + $(call RUN,foo) diff --git a/src/test/run-make/prefer-rlib/bar.rs b/src/test/run-make/prefer-rlib/bar.rs new file mode 100644 index 00000000000..c5c0bc606cd --- /dev/null +++ b/src/test/run-make/prefer-rlib/bar.rs @@ -0,0 +1 @@ +pub fn bar() {} diff --git a/src/test/run-make/prefer-rlib/foo.rs b/src/test/run-make/prefer-rlib/foo.rs new file mode 100644 index 00000000000..f86ef62a9fe --- /dev/null +++ b/src/test/run-make/prefer-rlib/foo.rs @@ -0,0 +1,5 @@ +extern mod bar; + +fn main() { + bar::bar(); +} diff --git a/src/test/run-make/rlib-chain/Makefile b/src/test/run-make/rlib-chain/Makefile new file mode 100644 index 00000000000..30b6811a388 --- /dev/null +++ b/src/test/run-make/rlib-chain/Makefile @@ -0,0 +1,10 @@ +-include ../tools.mk + +all: + $(RUSTC) m1.rs + $(RUSTC) m2.rs + $(RUSTC) m3.rs + $(RUSTC) m4.rs + $(call RUN,m4) + rm $(TMPDIR)/*lib + $(call RUN,m4) diff --git a/src/test/run-make/rlib-chain/m1.rs b/src/test/run-make/rlib-chain/m1.rs new file mode 100644 index 00000000000..1a244efd4dd --- /dev/null +++ b/src/test/run-make/rlib-chain/m1.rs @@ -0,0 +1,2 @@ +#[crate_type = "rlib"]; +pub fn m1() {} diff --git a/src/test/run-make/rlib-chain/m2.rs b/src/test/run-make/rlib-chain/m2.rs new file mode 100644 index 00000000000..96f77122083 --- /dev/null +++ b/src/test/run-make/rlib-chain/m2.rs @@ -0,0 +1,4 @@ +#[crate_type = "rlib"]; +extern mod m1; + +pub fn m2() { m1::m1() } diff --git a/src/test/run-make/rlib-chain/m3.rs b/src/test/run-make/rlib-chain/m3.rs new file mode 100644 index 00000000000..cb8d7529160 --- /dev/null +++ b/src/test/run-make/rlib-chain/m3.rs @@ -0,0 +1,4 @@ +#[crate_type = "rlib"]; +extern mod m2; + +pub fn m3() { m2::m2() } diff --git a/src/test/run-make/rlib-chain/m4.rs b/src/test/run-make/rlib-chain/m4.rs new file mode 100644 index 00000000000..c52d1f7fcbc --- /dev/null +++ b/src/test/run-make/rlib-chain/m4.rs @@ -0,0 +1,3 @@ +extern mod m3; + +fn main() { m3::m3() } diff --git a/src/test/run-make/simple-dylib/Makefile b/src/test/run-make/simple-dylib/Makefile new file mode 100644 index 00000000000..d4f215c69f0 --- /dev/null +++ b/src/test/run-make/simple-dylib/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk +all: + $(RUSTC) bar.rs --dylib + $(RUSTC) foo.rs + $(call RUN,foo) diff --git a/src/test/run-make/simple-dylib/bar.rs b/src/test/run-make/simple-dylib/bar.rs new file mode 100644 index 00000000000..c5c0bc606cd --- /dev/null +++ b/src/test/run-make/simple-dylib/bar.rs @@ -0,0 +1 @@ +pub fn bar() {} diff --git a/src/test/run-make/simple-dylib/foo.rs b/src/test/run-make/simple-dylib/foo.rs new file mode 100644 index 00000000000..f86ef62a9fe --- /dev/null +++ b/src/test/run-make/simple-dylib/foo.rs @@ -0,0 +1,5 @@ +extern mod bar; + +fn main() { + bar::bar(); +} diff --git a/src/test/run-make/simple-rlib/Makefile b/src/test/run-make/simple-rlib/Makefile new file mode 100644 index 00000000000..e8909ef134b --- /dev/null +++ b/src/test/run-make/simple-rlib/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk +all: + $(RUSTC) bar.rs --rlib + $(RUSTC) foo.rs + $(call RUN,foo) diff --git a/src/test/run-make/simple-rlib/bar.rs b/src/test/run-make/simple-rlib/bar.rs new file mode 100644 index 00000000000..c5c0bc606cd --- /dev/null +++ b/src/test/run-make/simple-rlib/bar.rs @@ -0,0 +1 @@ +pub fn bar() {} diff --git a/src/test/run-make/simple-rlib/foo.rs b/src/test/run-make/simple-rlib/foo.rs new file mode 100644 index 00000000000..f86ef62a9fe --- /dev/null +++ b/src/test/run-make/simple-rlib/foo.rs @@ -0,0 +1,5 @@ +extern mod bar; + +fn main() { + bar::bar(); +} diff --git a/src/test/run-make/static-unwinding/Makefile b/src/test/run-make/static-unwinding/Makefile new file mode 100644 index 00000000000..cb039744265 --- /dev/null +++ b/src/test/run-make/static-unwinding/Makefile @@ -0,0 +1,6 @@ +-include ../tools.mk + +all: + $(RUSTC) lib.rs + $(RUSTC) main.rs + $(call RUN,main) diff --git a/src/test/run-make/static-unwinding/lib.rs b/src/test/run-make/static-unwinding/lib.rs new file mode 100644 index 00000000000..4e2cdb6c222 --- /dev/null +++ b/src/test/run-make/static-unwinding/lib.rs @@ -0,0 +1,15 @@ +#[crate_type = "rlib"]; + +pub static mut statik: int = 0; + +struct A; +impl Drop for A { + fn drop(&mut self) { + unsafe { statik = 1; } + } +} + +pub fn callback(f: ||) { + let _a = A; + f(); +} diff --git a/src/test/run-make/static-unwinding/main.rs b/src/test/run-make/static-unwinding/main.rs new file mode 100644 index 00000000000..029933a819c --- /dev/null +++ b/src/test/run-make/static-unwinding/main.rs @@ -0,0 +1,25 @@ +extern mod lib; + +use std::task; + +static mut statik: int = 0; + +struct A; +impl Drop for A { + fn drop(&mut self) { + unsafe { statik = 1; } + } +} + +fn main() { + do task::try { + let _a = A; + lib::callback(|| fail!()); + 1 + }; + + unsafe { + assert!(lib::statik == 1); + assert!(statik == 1); + } +} diff --git a/src/test/run-make/tools.mk b/src/test/run-make/tools.mk new file mode 100644 index 00000000000..9c7af7f52c1 --- /dev/null +++ b/src/test/run-make/tools.mk @@ -0,0 +1,27 @@ +RUSTC := $(RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) +CC := $(CC) -L $(TMPDIR) + +RUN = $(TMPDIR)/$(1) +FAILS = $(TMPDIR)/$(1) && exit 1 || exit 0 + +RLIB_GLOB = lib$(1)*.rlib +STATICLIB = $(TMPDIR)/lib$(1).a +STATICLIB_GLOB = lib$(1)*.a + +ifeq ($(shell uname),Darwin) +DYLIB_GLOB = lib$(1)*.dylib +DYLIB = $(TMPDIR)/lib$(1).dylib +else +DYLIB_GLOB = lib$(1)*.so +DYLIB = $(TMPDIR)/lib$(1).so +endif + +%.a: %.o + ar crus $@ $< +%.dylib: %.o + ld -o $@ $< -dylib +%.so: %.o + ld -o $@ $< -shared +$(TMPDIR)/lib%.o: %.c + $(CC) -c -o $@ $< + From c1e287af7788261bd50f47a166fbbd3493355a38 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 12 Nov 2013 01:29:09 -0800 Subject: [PATCH 4/5] Make -Z gen-crate-map usable for I/O In #10422, I didn't actually test to make sure that the '-Z gen-crate-map' option was usable before I implemented it. The crate map was indeed generated when '-Z gen-crate-map' was specified, but the I/O factory slot was empty because of an extra check in trans about filling in that location. This commit both fixes that location, and checks in a "fancy test" which does lots of fun stuff. The test will use the rustc library to compile a rust crate, and then compile a C program to link against that crate and run the C program. To my knowledge this is the first test of its kind, so it's a little ad-hoc, but it seems to get the job done. We could perhaps generalize running tests like this, but for now I think it's fine to have this sort of functionality tucked away in a test. --- src/librustc/middle/trans/base.rs | 21 ++++++++-------- .../bootstrap-from-c-with-uvio/Makefile | 9 +++++++ .../bootstrap-from-c-with-uvio/lib.rs | 25 +++++++++++++++++++ .../bootstrap-from-c-with-uvio/main.c | 16 ++++++++++++ 4 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 src/test/run-make/bootstrap-from-c-with-uvio/Makefile create mode 100644 src/test/run-make/bootstrap-from-c-with-uvio/lib.rs create mode 100644 src/test/run-make/bootstrap-from-c-with-uvio/main.c diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index f14fc265b82..deb4f00d7a0 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -77,7 +77,7 @@ use extra::time; use extra::sort; use syntax::ast::Name; use syntax::ast_map::{path, path_elt_to_str, path_name, path_pretty_name}; -use syntax::ast_util::{local_def}; +use syntax::ast_util::{local_def, is_local}; use syntax::attr; use syntax::codemap::Span; use syntax::parse::token; @@ -2996,7 +2996,7 @@ pub fn decl_crate_map(sess: session::Session, mapmeta: LinkMeta, return map; } -pub fn fill_crate_map(ccx: &mut CrateContext, map: ValueRef) { +pub fn fill_crate_map(ccx: @mut CrateContext, map: ValueRef) { let mut subcrates: ~[ValueRef] = ~[]; let mut i = 1; let cstore = ccx.sess.cstore; @@ -3014,19 +3014,20 @@ pub fn fill_crate_map(ccx: &mut CrateContext, map: ValueRef) { subcrates.push(p2i(ccx, cr)); i += 1; } - let event_loop_factory = if !*ccx.sess.building_library { - match ccx.tcx.lang_items.event_loop_factory() { - Some(did) => unsafe { + let event_loop_factory = match ccx.tcx.lang_items.event_loop_factory() { + Some(did) => unsafe { + if is_local(did) { + llvm::LLVMConstPointerCast(get_item_val(ccx, did.node), + ccx.int_type.ptr_to().to_ref()) + } else { let name = csearch::get_symbol(ccx.sess.cstore, did); let global = name.with_c_str(|buf| { llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type.to_ref(), buf) }); global - }, - None => C_null(ccx.int_type.ptr_to()) - } - } else { - C_null(ccx.int_type.ptr_to()) + } + }, + None => C_null(ccx.int_type.ptr_to()) }; unsafe { let maptype = Type::array(&ccx.int_type, subcrates.len() as u64); diff --git a/src/test/run-make/bootstrap-from-c-with-uvio/Makefile b/src/test/run-make/bootstrap-from-c-with-uvio/Makefile new file mode 100644 index 00000000000..7f466573da7 --- /dev/null +++ b/src/test/run-make/bootstrap-from-c-with-uvio/Makefile @@ -0,0 +1,9 @@ +-include ../tools.mk + +all: + $(RUSTC) lib.rs -Z gen-crate-map + ln -nsf $(call DYLIB,boot-*) $(call DYLIB,boot) + $(CC) main.c -o $(call RUN,main) -lboot -Wl,-rpath,$(TMPDIR) + $(call RUN,main) + rm $(call DYLIB,boot) + $(call FAIL,main) diff --git a/src/test/run-make/bootstrap-from-c-with-uvio/lib.rs b/src/test/run-make/bootstrap-from-c-with-uvio/lib.rs new file mode 100644 index 00000000000..85941ec74a8 --- /dev/null +++ b/src/test/run-make/bootstrap-from-c-with-uvio/lib.rs @@ -0,0 +1,25 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[link(package_id = "boot", name = "boot", vers = "0.1")]; +#[crate_type = "lib"]; + +extern mod rustuv; // pull in uvio + +use std::rt; + +#[no_mangle] // this needs to get called from C +pub extern "C" fn foo(argc: int, argv: **u8) -> int { + do rt::start(argc, argv) { + do spawn { + println!("hello"); + } + } +} diff --git a/src/test/run-make/bootstrap-from-c-with-uvio/main.c b/src/test/run-make/bootstrap-from-c-with-uvio/main.c new file mode 100644 index 00000000000..1872c1ea43b --- /dev/null +++ b/src/test/run-make/bootstrap-from-c-with-uvio/main.c @@ -0,0 +1,16 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// this is the rust entry point that we're going to call. +int foo(int argc, char *argv[]); + +int main(int argc, char *argv[]) { + return foo(argc, argv); +} From 56e4c82a38cfb2bcf7de2d6323dab0073a70726d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 28 Nov 2013 18:03:38 -0800 Subject: [PATCH 5/5] Test fixes and merge conflicts --- mk/tests.mk | 5 +- src/etc/maketest.py | 1 + src/libextra/lib.rs | 1 + src/librustc/back/archive.rs | 16 ++++- src/librustc/back/link.rs | 7 +- src/librustc/driver/session.rs | 72 ------------------- src/librustc/front/feature_gate.rs | 2 +- src/librustc/lib.rs | 1 + src/librustc/metadata/creader.rs | 8 +-- src/librustc/metadata/decoder.rs | 4 +- src/librustc/metadata/loader.rs | 10 +-- src/librustc/middle/lint.rs | 4 +- src/librustuv/lib.rs | 1 + src/librustuv/uvll.rs | 2 +- src/libstd/lib.rs | 1 + src/test/run-make/tools.mk | 4 +- .../run-pass/anon-extern-mod-cross-crate-2.rs | 1 + src/test/run-pass/invoke-external-foreign.rs | 1 + 18 files changed, 44 insertions(+), 97 deletions(-) diff --git a/mk/tests.mk b/mk/tests.mk index 5b021eb48f1..3b4a490f1ad 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -924,9 +924,10 @@ $(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \ @rm -rf $(3)/test/run-make/$$* @mkdir -p $(3)/test/run-make/$$* @echo maketest: $$* - @python $(S)src/etc/maketest.py $$(dir $$<) \ + $$(Q)python $(S)src/etc/maketest.py $$(dir $$<) \ $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ - $(3)/test/run-make/$$* + $(3)/test/run-make/$$* \ + "$$(CC_$(3)) $$(CFG_GCCISH_CFLAGS_$(3))" @touch $$@ endef diff --git a/src/etc/maketest.py b/src/etc/maketest.py index d42bf065657..96c658e5686 100644 --- a/src/etc/maketest.py +++ b/src/etc/maketest.py @@ -6,6 +6,7 @@ import sys os.putenv('RUSTC', os.path.abspath(sys.argv[2])) os.putenv('TMPDIR', os.path.abspath(sys.argv[3])) +os.putenv('CC', sys.argv[4]) proc = subprocess.Popen(['make', '-C', sys.argv[1]], stdout = subprocess.PIPE, diff --git a/src/libextra/lib.rs b/src/libextra/lib.rs index 571891f1830..ce504d8bf6f 100644 --- a/src/libextra/lib.rs +++ b/src/libextra/lib.rs @@ -40,6 +40,7 @@ Rust extras are part of the standard Rust distribution. #[deny(non_camel_case_types)]; #[deny(missing_doc)]; +#[allow(attribute_usage)]; // NOTE: remove after the next snapshot use std::str::{StrSlice, OwnedStr}; diff --git a/src/librustc/back/archive.rs b/src/librustc/back/archive.rs index e3c8e859f72..9f5aaf3a426 100644 --- a/src/librustc/back/archive.rs +++ b/src/librustc/back/archive.rs @@ -27,7 +27,7 @@ pub struct Archive { fn run_ar(sess: Session, args: &str, cwd: Option<&Path>, paths: &[&Path]) -> ProcessOutput { - let ar = sess.opts.ar.clone().unwrap_or(~"ar"); + let ar = sess.opts.ar.clone().unwrap_or_else(|| ~"ar"); let mut args = ~[args.to_owned()]; let mut paths = paths.iter().map(|p| p.as_str().unwrap().to_owned()); args.extend(&mut paths); @@ -64,7 +64,17 @@ impl Archive { /// 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 + // Apparently if "ar p" is used on windows, it generates a corrupt file + // which has bad headers and LLVM will immediately choke on it + if cfg!(windows) && cfg!(windows) { // FIXME(#10734) double-and + let loc = TempDir::new("rsar").unwrap(); + let archive = os::make_absolute(&self.dst); + run_ar(self.sess, "x", Some(loc.path()), [&archive, + &Path::init(file)]); + fs::File::open(&loc.path().join(file)).read_to_end() + } else { + run_ar(self.sess, "p", None, [&self.dst, &Path::init(file)]).output + } } /// Adds all of the contents of a native library to this archive. This will @@ -77,7 +87,7 @@ impl Archive { /// 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(); + let name = rlib.filename_str().unwrap().split('-').next().unwrap(); self.add_archive(rlib, name); } diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 98d5958ac4f..8119618da57 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -1112,7 +1112,7 @@ fn link_args(sess: Session, // 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 + // GNU-style linkers support 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. @@ -1212,7 +1212,7 @@ fn add_upstream_rust_crates(args: &mut ~[~str], sess: Session, } } - // This is a fallback of three differnet cases of linking: + // This is a fallback of three different cases of linking: // // * When creating a dynamic library, all inputs are required to be dynamic // as well @@ -1223,7 +1223,8 @@ fn add_upstream_rust_crates(args: &mut ~[~str], sess: Session, 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 => { + Some(ref p) => p.clone(), + None => { sess.err(format!("could not find dynamic library for: `{}`", cstore::get_crate_data(sess.cstore, cnum).name)); return diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index ba9e8449418..e45ea533f79 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -420,75 +420,3 @@ pub fn sess_os_to_meta_os(os: abi::Os) -> metadata::loader::Os { abi::OsFreebsd => loader::OsFreebsd } } - -#[cfg(test)] -mod test { - use driver::session::{bin_crate, building_library, lib_crate}; - use driver::session::{unknown_crate}; - - use syntax::ast; - use syntax::attr; - use syntax::codemap; - - fn make_crate_type_attr(t: @str) -> ast::Attribute { - attr::mk_attr(attr::mk_name_value_item_str(@"crate_type", t)) - } - - fn make_crate(with_bin: bool, with_lib: bool) -> @ast::Crate { - let mut attrs = ~[]; - if with_bin { - attrs.push(make_crate_type_attr(@"bin")); - } - if with_lib { - attrs.push(make_crate_type_attr(@"lib")); - } - @ast::Crate { - module: ast::_mod { view_items: ~[], items: ~[] }, - attrs: attrs, - config: ~[], - span: codemap::dummy_sp(), - } - } - - #[test] - fn bin_crate_type_attr_results_in_bin_output() { - let crate = make_crate(true, false); - assert!(!building_library(unknown_crate, crate, false)); - } - - #[test] - fn lib_crate_type_attr_results_in_lib_output() { - let crate = make_crate(false, true); - assert!(building_library(unknown_crate, crate, false)); - } - - #[test] - fn bin_option_overrides_lib_crate_type() { - let crate = make_crate(false, true); - assert!(!building_library(bin_crate, crate, false)); - } - - #[test] - fn lib_option_overrides_bin_crate_type() { - let crate = make_crate(true, false); - assert!(building_library(lib_crate, crate, false)); - } - - #[test] - fn bin_crate_type_is_default() { - let crate = make_crate(false, false); - assert!(!building_library(unknown_crate, crate, false)); - } - - #[test] - fn test_option_overrides_lib_crate_type() { - let crate = make_crate(false, true); - assert!(!building_library(unknown_crate, crate, true)); - } - - #[test] - fn test_option_does_not_override_requested_lib_type() { - let crate = make_crate(false, false); - assert!(building_library(lib_crate, crate, true)); - } -} diff --git a/src/librustc/front/feature_gate.rs b/src/librustc/front/feature_gate.rs index 3cff0b81e87..d18a8306812 100644 --- a/src/librustc/front/feature_gate.rs +++ b/src/librustc/front/feature_gate.rs @@ -135,7 +135,7 @@ impl Visitor<()> for Context { } } - ast::item_foreign_mod(*) => { + 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, diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 90a005568b6..e0073e7ce12 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -20,6 +20,7 @@ #[crate_type = "dylib"]; #[feature(macro_rules, globs, struct_variant, managed_boxes)]; +#[allow(attribute_usage)]; // NOTE: remove after the next snapshot extern mod extra; extern mod syntax; diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 1f10699b765..9d28a5abed2 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -187,9 +187,9 @@ fn visit_item(e: &Env, i: @ast::item) { for m in link_args.iter() { match m.meta_item_list() { Some(items) => { - let kind = do items.iter().find |k| { + let kind = items.iter().find(|k| { "kind" == k.name() - }.and_then(|a| a.value_str()); + }).and_then(|a| a.value_str()); let kind = match kind { Some(k) if "static" == k => cstore::NativeStatic, Some(k) => { @@ -198,9 +198,9 @@ fn visit_item(e: &Env, i: @ast::item) { } None => cstore::NativeUnknown }; - let n = do items.iter().find |n| { + let n = items.iter().find(|n| { "name" == n.name() - }.and_then(|a| a.value_str()); + }).and_then(|a| a.value_str()); let n = match n { Some(n) => n, None => { diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index c43324456d1..441f1620e4d 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -1533,9 +1533,9 @@ 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| { + reader::tagged_docs(libraries, tag_native_libraries_lib, |lib_doc| { result.push(lib_doc.as_str()); true - }; + }); return result; } diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 1aff16cc23c..40fca0f42f1 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -83,7 +83,7 @@ impl Context { let rlib_prefix = format!("lib{}-", crate_name); let mut matches = ~[]; - do filesearch::search(filesearch) |path| { + filesearch::search(filesearch, |path| { match path.filename_str() { None => FileDoesntMatch, Some(file) => { @@ -135,7 +135,7 @@ impl Context { } } } - } + }); match matches.len() { 0 => None, @@ -180,7 +180,7 @@ impl Context { lib.rlib = Some(path.clone()); return true; } - Some(*) | None => {} + Some(..) | None => {} } } return false; @@ -200,7 +200,7 @@ impl Context { lib.dylib = Some(path.clone()); return true; } - Some(*) | None => {} + Some(..) | None => {} } } return false; @@ -360,7 +360,7 @@ pub fn list_file_metadata(sess: Session, 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(); + let crate_name = crate_name.split('-').next().unwrap(); match get_metadata_section(sess, os, path, crate_name) { option::Some(bytes) => decoder::list_crate_metadata(intr, bytes, out), option::None => { diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 4c6ca53694a..1b2ae78c627 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -808,7 +808,7 @@ fn check_heap_item(cx: &Context, it: &ast::item) { } static crate_attrs: &'static [&'static str] = &[ - "crate_type", "link", "feature", "no_uv", "no_main", "no_std", + "crate_type", "feature", "no_uv", "no_main", "no_std", "desc", "comment", "license", "copyright", // not used in rustc now ]; @@ -830,7 +830,7 @@ static other_attrs: &'static [&'static str] = &[ "deprecated", "experimental", "unstable", "stable", "locked", "frozen", //item stability "crate_map", "cfg", "doc", "export_name", "link_section", "no_freeze", "no_mangle", "no_send", "static_assert", "unsafe_no_drop_flag", - "packed", "simd", "repr", "deriving", "unsafe_destructor", + "packed", "simd", "repr", "deriving", "unsafe_destructor", "link", //mod-level "path", "link_name", "link_args", "nolink", "macro_escape", "no_implicit_prelude", diff --git a/src/librustuv/lib.rs b/src/librustuv/lib.rs index feb1c6b92bd..a43759a6da7 100644 --- a/src/librustuv/lib.rs +++ b/src/librustuv/lib.rs @@ -46,6 +46,7 @@ via `close` and `delete` methods. #[crate_type = "dylib"]; #[feature(macro_rules, globs)]; +#[allow(attribute_usage)]; // NOTE: remove after the next snapshot use std::cast::transmute; use std::cast; diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs index f62ac3450e6..ca5c75122a6 100644 --- a/src/librustuv/uvll.rs +++ b/src/librustuv/uvll.rs @@ -723,7 +723,7 @@ extern { } // various platform libraries required by libuv -#[cfg(not(stage0))] +#[cfg(not(stage0), not(target_os = "android"))] #[link(name = "pthread")] extern {} #[cfg(stage0)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 0489fff31f9..296091d26e6 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -66,6 +66,7 @@ #[deny(non_camel_case_types)]; #[deny(missing_doc)]; +#[allow(attribute_usage)]; // NOTE: remove after the next snapshot // When testing libstd, bring in libuv as the I/O backend so tests can print // things and all of the std::io tests have an I/O interface to run on top diff --git a/src/test/run-make/tools.mk b/src/test/run-make/tools.mk index 9c7af7f52c1..2d670cb873f 100644 --- a/src/test/run-make/tools.mk +++ b/src/test/run-make/tools.mk @@ -19,9 +19,9 @@ endif %.a: %.o ar crus $@ $< %.dylib: %.o - ld -o $@ $< -dylib + $(CC) -dynamiclib -Wl,-dylib -o $@ $< %.so: %.o - ld -o $@ $< -shared + $(CC) -o $@ $< -shared $(TMPDIR)/lib%.o: %.c $(CC) -c -o $@ $< diff --git a/src/test/run-pass/anon-extern-mod-cross-crate-2.rs b/src/test/run-pass/anon-extern-mod-cross-crate-2.rs index 65421227054..4c2e78db398 100644 --- a/src/test/run-pass/anon-extern-mod-cross-crate-2.rs +++ b/src/test/run-pass/anon-extern-mod-cross-crate-2.rs @@ -9,6 +9,7 @@ // except according to those terms. // xfail-fast +// xfail-pretty // aux-build:anon-extern-mod-cross-crate-1.rs extern mod anonexternmod; diff --git a/src/test/run-pass/invoke-external-foreign.rs b/src/test/run-pass/invoke-external-foreign.rs index 6850e9d9bd2..ec531d391e4 100644 --- a/src/test/run-pass/invoke-external-foreign.rs +++ b/src/test/run-pass/invoke-external-foreign.rs @@ -9,6 +9,7 @@ // except according to those terms. // xfail-fast +// xfail-pretty // aux-build:foreign_lib.rs // The purpose of this test is to check that we can