diff --git a/Makefile.in b/Makefile.in index f5bb3cb2ed0..b575312c03b 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 @@ -214,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) @@ -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..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))) @@ -144,13 +142,15 @@ 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))) $(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) @@ -167,11 +167,13 @@ 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))) \ $(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))) \ @@ -232,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)) @@ -241,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/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/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/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..3b4a490f1ad 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 \ @@ -584,6 +585,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 @@ -766,6 +771,7 @@ TEST_GROUPS = \ cfail \ bench \ perf \ + rmake \ debuginfo \ codegen \ doc \ @@ -896,3 +902,37 @@ 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: $$* + $$(Q)python $(S)src/etc/maketest.py $$(dir $$<) \ + $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ + $(3)/test/run-make/$$* \ + "$$(CC_$(3)) $$(CFG_GCCISH_CFLAGS_$(3))" + @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..96c658e5686 --- /dev/null +++ b/src/etc/maketest.py @@ -0,0 +1,27 @@ +# 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])) +os.putenv('CC', sys.argv[4]) + +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/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/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..ce504d8bf6f 100644 --- a/src/libextra/lib.rs +++ b/src/libextra/lib.rs @@ -32,12 +32,15 @@ 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)]; #[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 new file mode 100644 index 00000000000..9f5aaf3a426 --- /dev/null +++ b/src/librustc/back/archive.rs @@ -0,0 +1,138 @@ +// 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_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); + 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] { + // 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 + /// 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('-').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..8119618da57 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,282 @@ 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 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. + 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 different 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 +1262,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..e45ea533f79 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 } } @@ -423,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 82ddb9c2f97..d18a8306812 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..e0073e7ce12 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -16,9 +16,11 @@ #[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)]; +#[allow(attribute_usage)]; // NOTE: remove after the next snapshot extern mod extra; extern mod syntax; @@ -87,6 +89,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..9d28a5abed2 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 = 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 = 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..441f1620e4d 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 = ~[]; + 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..40fca0f42f1 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 = ~[]; + 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('-').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/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/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index ac7b8240176..deb4f00d7a0 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -77,14 +77,14 @@ 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::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; @@ -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); @@ -3106,18 +3107,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 +3166,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 +3205,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 e699aa2edef..7cab7846f15 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..a43759a6da7 100644 --- a/src/librustuv/lib.rs +++ b/src/librustuv/lib.rs @@ -41,9 +41,12 @@ 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)]; +#[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 3917efe9ca8..ca5c75122a6 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), not(target_os = "android"))] +#[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..296091d26e6 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", @@ -64,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 @@ -79,15 +82,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..ba4f120f626 --- /dev/null +++ b/src/libstd/rtdeps.rs @@ -0,0 +1,54 @@ +// 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", kind = "static")] +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")] +#[link(name = "stdc++")] +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")] +#[link(name = "stdc++")] +extern {} + +#[cfg(stage0)] +#[link_args = "-lstdc++"] +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/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/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 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-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); +} 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..2d670cb873f --- /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 + $(CC) -dynamiclib -Wl,-dylib -o $@ $< +%.so: %.o + $(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 a9c6141c18b..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,11 +9,15 @@ // except according to those terms. // xfail-fast +// xfail-pretty // aux-build:anon-extern-mod-cross-crate-1.rs 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..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 @@ -17,6 +18,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;