Add generation of static libraries to rustc

This commit implements the support necessary for generating both intermediate
and result static rust libraries. This is an implementation of my thoughts in
https://mail.mozilla.org/pipermail/rust-dev/2013-November/006686.html.

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

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

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

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

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

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

Closes #552
This commit is contained in:
Alex Crichton 2013-11-15 14:03:29 -08:00
parent 80991bb578
commit e338a4154b
43 changed files with 1156 additions and 641 deletions

View file

@ -130,6 +130,14 @@ ifndef DEBUG_BORROWS
RUSTFLAGS_STAGE2 += -Z no-debug-borrows RUSTFLAGS_STAGE2 += -Z no-debug-borrows
endif 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 # platform-specific auto-configuration
include $(CFG_SRC_DIR)mk/platform.mk include $(CFG_SRC_DIR)mk/platform.mk
@ -239,6 +247,10 @@ LIBRUSTPKG_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustpkg)
LIBRUSTDOC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustdoc) LIBRUSTDOC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustdoc)
LIBRUSTUV_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustuv) 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 endef
# $(1) is the path for directory to match against # $(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) 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 # The name of the standard and extra libraries used by rustc
ifdef CFG_DISABLE_SHAREDSTD HSTDLIB_DEFAULT$(1)_H_$(3) = \
HSTDLIB_DEFAULT$(1)_H_$(3) = \ $$(HLIB$(1)_H_$(3))/$(CFG_STDLIB_$(3))
$$(HLIB$(1)_H_$(3))/libstd.rlib TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3) = \ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2))
$$(TLIB$(1)_T_$(2)_H_$(3))/libstd.rlib
HEXTRALIB_DEFAULT$(1)_H_$(3) = \ HEXTRALIB_DEFAULT$(1)_H_$(3) = \
$$(HLIB$(1)_H_$(3))/libextra.rlib $$(HLIB$(1)_H_$(3))/$(CFG_EXTRALIB_$(3))
TEXTRALIB_DEFAULT$(1)_T_$(2)_H_$(3) = \ TEXTRALIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
$$(TLIB$(1)_T_$(2)_H_$(3))/libextra.rlib $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2))
HLIBRUSTC_DEFAULT$(1)_H_$(3) = \ HLIBRUSTC_DEFAULT$(1)_H_$(3) = \
$$(HLIB$(1)_H_$(3))/librustc.rlib $$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTC_$(3))
TLIBRUSTC_DEFAULT$(1)_T_$(2)_H_$(3) = \ TLIBRUSTC_DEFAULT$(1)_T_$(2)_H_$(3) = \
$$(TLIB$(1)_T_$(2)_H_$(3))/librustc.rlib $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2))
else
HSTDLIB_DEFAULT$(1)_H_$(3) = \
$$(HLIB$(1)_H_$(3))/$(CFG_STDLIB_$(3))
TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2))
HEXTRALIB_DEFAULT$(1)_H_$(3) = \ HLIBRUSTUV_DEFAULT$(1)_H_$(3) = \
$$(HLIB$(1)_H_$(3))/$(CFG_EXTRALIB_$(3)) $$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTUV_$(3))
TEXTRALIB_DEFAULT$(1)_T_$(2)_H_$(3) = \ TLIBRUSTUV_DEFAULT$(1)_T_$(2)_H_$(3) = \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)) $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(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
# Preqrequisites for using the stageN compiler # Preqrequisites for using the stageN compiler
HSREQ$(1)_H_$(3) = \ HSREQ$(1)_H_$(3) = \

3
configure vendored
View file

@ -364,7 +364,6 @@ fi
BOOL_OPTIONS="" BOOL_OPTIONS=""
VAL_OPTIONS="" VAL_OPTIONS=""
opt sharedstd 1 "build libstd as a shared library"
opt valgrind 0 "run tests with valgrind (memcheck by default)" opt valgrind 0 "run tests with valgrind (memcheck by default)"
opt helgrind 0 "run tests with helgrind instead of memcheck" opt helgrind 0 "run tests with helgrind instead of memcheck"
opt docs 1 "build documentation" opt docs 1 "build documentation"
@ -398,7 +397,7 @@ valopt sysconfdir "/etc" "install system configuration files"
valopt datadir "${CFG_PREFIX}/share" "install data" valopt datadir "${CFG_PREFIX}/share" "install data"
valopt infodir "${CFG_PREFIX}/share/info" "install additional info" valopt infodir "${CFG_PREFIX}/share/info" "install additional info"
valopt mandir "${CFG_PREFIX}/share/man" "install man pages in PATH" 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 # Validate Options
step_msg "validating $CFG_SELF args" step_msg "validating $CFG_SELF args"

View file

@ -1507,19 +1507,15 @@ an `abi` string, as shown here:
extern "stdcall" { } 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} ~~~~ {.xfail-test}
#[link_name = "crypto"] #[link(name = "crypto")]
extern { } 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 The type of a function
declared in an extern block declared in an extern block
is `extern "abi" fn(A1, ..., An) -> R`, is `extern "abi" fn(A1, ..., An) -> R`,

View file

@ -59,6 +59,7 @@ clean-generic-$(2)-$(1):
$(Q)find $(1)/rustllvm \ $(Q)find $(1)/rustllvm \
$(1)/rt \ $(1)/rt \
$(1)/test \ $(1)/test \
$(1)/stage* \
-name '*.[odasS]' -o \ -name '*.[odasS]' -o \
-name '*.so' -o \ -name '*.so' -o \
-name '*.dylib' -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_LIBRUSTC_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBSYNTAX_$(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_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_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))/$(LIBRUSTC_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBSYNTAX_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))/$(LIBRUSTPKG_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTDOC_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))/$(CFG_RUSTLLVM_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/libstd.rlib
endef 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_LIBRUSTC_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(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_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_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_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))/$(LIBRUSTC_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBSYNTAX_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))/$(LIBRUSTPKG_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTDOC_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))/$(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))/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))/librun_pass_stage* # For unix
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/run_pass_stage* # For windows $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/run_pass_stage* # For windows

View file

@ -50,7 +50,7 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)): \
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(4)),$$(notdir $$@)) $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(4)),$$(notdir $$@))
$$(Q)cp $$< $$@ $$(Q)cp $$< $$@
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTC_GLOB_$(4)) \ $$(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)) $$(HLIB$(2)_H_$(4))
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(4)),$$(notdir $$@)) $$(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))/ | $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@) @$$(call E, cp: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_GLOB_$(4)),$$(notdir $$@)) $$(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 $$< $$@ $$(Q)cp $$< $$@
# Subtle: We do not let the shell expand $$(STDLIB_DSYM_GLOB) directly rather # 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 # 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. # Make instead expands the glob to nothing, which gives us the correct behavior.
# (Copy .dsym file if it exists, but do nothing otherwise) # (Copy .dsym file if it exists, but do nothing otherwise)
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_GLOB_$(4)) \ $$(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))) \ $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_DSYM_GLOB_$(4))) \
$$(HLIB$(2)_H_$(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_GLOB_$(4)),$$(notdir $$@))
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_RGLOB_$(4)),$$(notdir $$@))
$$(HLIB$(2)_H_$(4))/$(CFG_EXTRALIB_$(4)): \ $$(HLIB$(2)_H_$(4))/$(CFG_EXTRALIB_$(4)): \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(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))/ | $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@) @$$(call E, cp: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(4)),$$(notdir $$@)) $$(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 $$< $$@
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(EXTRALIB_GLOB_$(4)) \ $$(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))) \ $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(EXTRALIB_DSYM_GLOB_$(4))) \
$$(HLIB$(2)_H_$(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_GLOB_$(4)),$$(notdir $$@))
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_RGLOB_$(4)),$$(notdir $$@))
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTUV_$(4)): \ $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTUV_$(4)): \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(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))/ | $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@) @$$(call E, cp: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@)) $$(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 $$< $$@
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTUV_GLOB_$(4)) \ $$(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))) \ $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTUV_DSYM_GLOB_$(4))) \
$$(HLIB$(2)_H_$(4)) $$(HLIB$(2)_H_$(4))
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@)) $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_RGLOB_$(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 $$< $$@
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)): \ $$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)): \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUSTLLVM_$(4)) \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUSTLLVM_$(4)) \

View file

@ -144,8 +144,11 @@ install-host: $(CSREQ$(ISTAGE)_T_$(CFG_BUILD_)_H_$(CFG_BUILD_))
$(Q)$(call INSTALL,$(HB2),$(PHB),rustpkg$(X_$(CFG_BUILD))) $(Q)$(call INSTALL,$(HB2),$(PHB),rustpkg$(X_$(CFG_BUILD)))
$(Q)$(call INSTALL,$(HB2),$(PHB),rustdoc$(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_GLOB_$(CFG_BUILD)))
$(Q)$(call INSTALL_LIB,$(STDLIB_RGLOB_$(CFG_BUILD)))
$(Q)$(call INSTALL_LIB,$(EXTRALIB_GLOB_$(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_GLOB_$(CFG_BUILD)))
$(Q)$(call INSTALL_LIB,$(LIBRUSTUV_RGLOB_$(CFG_BUILD)))
$(Q)$(call INSTALL_LIB,$(LIBRUSTC_GLOB_$(CFG_BUILD))) $(Q)$(call INSTALL_LIB,$(LIBRUSTC_GLOB_$(CFG_BUILD)))
$(Q)$(call INSTALL_LIB,$(LIBSYNTAX_GLOB_$(CFG_BUILD))) $(Q)$(call INSTALL_LIB,$(LIBSYNTAX_GLOB_$(CFG_BUILD)))
$(Q)$(call INSTALL_LIB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD))) $(Q)$(call INSTALL_LIB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD)))
@ -170,8 +173,11 @@ uninstall:
$(Q)rm -f $(PHL)/$(CFG_RUNTIME_$(CFG_BUILD)) $(Q)rm -f $(PHL)/$(CFG_RUNTIME_$(CFG_BUILD))
$(Q)for i in \ $(Q)for i in \
$(call HOST_LIB_FROM_HL_GLOB,$(STDLIB_GLOB_$(CFG_BUILD))) \ $(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_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_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,$(LIBRUSTC_GLOB_$(CFG_BUILD))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBSYNTAX_GLOB_$(CFG_BUILD))) \ $(call HOST_LIB_FROM_HL_GLOB,$(LIBSYNTAX_GLOB_$(CFG_BUILD))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD))) \ $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD))) \

View file

@ -138,6 +138,7 @@ endif
endif endif
endif endif
CFG_RLIB_GLOB=lib$(1)-*.rlib
# x86_64-unknown-linux-gnu configuration # x86_64-unknown-linux-gnu configuration
CC_x86_64-unknown-linux-gnu=$(CC) CC_x86_64-unknown-linux-gnu=$(CC)

View file

@ -60,8 +60,10 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)): \
| $$(TLIB$(1)_T_$(2)_H_$(3))/ | $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@) @$$(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_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 $$@ $$(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_GLOB_$(2)),$$(notdir $$@))
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_RGLOB_$(2)),$$(notdir $$@))
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)): \ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)): \
$$(EXTRALIB_CRATE) $$(EXTRALIB_INPUTS) \ $$(EXTRALIB_CRATE) $$(EXTRALIB_INPUTS) \
@ -70,8 +72,10 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)): \
| $$(TLIB$(1)_T_$(2)_H_$(3))/ | $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@) @$$(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_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 $$@ $$(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_GLOB_$(2)),$$(notdir $$@))
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_RGLOB_$(2)),$$(notdir $$@))
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2)): \ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2)): \
$$(LIBRUSTUV_CRATE) $$(LIBRUSTUV_INPUTS) \ $$(LIBRUSTUV_CRATE) $$(LIBRUSTUV_INPUTS) \
@ -82,11 +86,13 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2)): \
| $$(TLIB$(1)_T_$(2)_H_$(3))/ | $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@) @$$(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_GLOB_$(2)),$$(notdir $$@))
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_RGLOB_$(2)),$$(notdir $$@))
$$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) \ $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) \
-L $$(UV_SUPPORT_DIR_$(2)) \ -L $$(UV_SUPPORT_DIR_$(2)) \
-L $$(dir $$(LIBUV_LIB_$(2))) \ -L $$(dir $$(LIBUV_LIB_$(2))) \
--out-dir $$(@D) $$< && touch $$@ --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_GLOB_$(2)),$$(notdir $$@))
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_RGLOB_$(2)),$$(notdir $$@))
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \
$$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \ $$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \

View file

@ -584,6 +584,10 @@ TEST_SREQ$(1)_T_$(2)_H_$(3) = \
# remove directive, if present, from CFG_RUSTC_FLAGS (issue #7898). # remove directive, if present, from CFG_RUSTC_FLAGS (issue #7898).
CTEST_RUSTC_FLAGS := $$(subst --cfg ndebug,,$$(CFG_RUSTC_FLAGS)) 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 # 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 # filter out the optimization (if any) from rustc and then figure out if we need
# to be optimized # to be optimized

View file

@ -23,7 +23,7 @@
pub mod rustrt { pub mod rustrt {
use std::libc::{c_int, c_void, size_t}; use std::libc::{c_int, c_void, size_t};
#[link_name = "rustrt"] #[link(name = "rustrt")]
extern { extern {
pub fn tdefl_compress_mem_to_heap(psrc_buf: *c_void, pub fn tdefl_compress_mem_to_heap(psrc_buf: *c_void,
src_buf_len: size_t, src_buf_len: size_t,

View file

@ -32,7 +32,9 @@
#[comment = "Rust extras"]; #[comment = "Rust extras"];
#[license = "MIT/ASL2"]; #[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)]; #[feature(macro_rules, globs, managed_boxes)];

View file

@ -0,0 +1,128 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A helper class for dealing with static archives
use driver::session::Session;
use metadata::filesearch;
use std::io::fs;
use std::os;
use std::run::{ProcessOptions, Process, ProcessOutput};
use std::str;
use extra::tempfile::TempDir;
use syntax::abi;
pub struct Archive {
priv sess: Session,
priv dst: Path,
}
fn run_ar(sess: Session, args: &str, cwd: Option<&Path>,
paths: &[&Path]) -> ProcessOutput {
let ar = sess.opts.ar.clone().unwrap_or(~"ar");
let mut args = ~[args.to_owned()];
let mut paths = paths.iter().map(|p| p.as_str().unwrap().to_owned());
args.extend(&mut paths);
let mut opts = ProcessOptions::new();
opts.dir = cwd;
debug!("{} {}", ar, args.connect(" "));
match cwd {
Some(p) => { debug!("inside {}", p.display()); }
None => {}
}
let o = Process::new(ar, args.as_slice(), opts).finish_with_output();
if !o.status.success() {
sess.err(format!("{} failed with: {}", ar, o.status));
sess.note(format!("stdout ---\n{}", str::from_utf8(o.output)));
sess.note(format!("stderr ---\n{}", str::from_utf8(o.error)));
sess.abort_if_errors();
}
o
}
impl Archive {
/// Initializes a new static archive with the given object file
pub fn create<'a>(sess: Session, dst: &'a Path,
initial_object: &'a Path) -> Archive {
run_ar(sess, "crus", None, [dst, initial_object]);
Archive { sess: sess, dst: dst.clone() }
}
/// Opens an existing static archive
pub fn open(sess: Session, dst: Path) -> Archive {
assert!(dst.exists());
Archive { sess: sess, dst: dst }
}
/// Read a file in the archive
pub fn read(&self, file: &str) -> ~[u8] {
run_ar(self.sess, "p", None, [&self.dst, &Path::new(file)]).output
}
/// Adds all of the contents of a native library to this archive. This will
/// search in the relevant locations for a library named `name`.
pub fn add_native_library(&mut self, name: &str) {
let location = self.find_library(name);
self.add_archive(&location, name);
}
/// Adds all of the contents of the rlib at the specified path to this
/// archive.
pub fn add_rlib(&mut self, rlib: &Path) {
let name = rlib.filename_str().unwrap().split_iter('-').next().unwrap();
self.add_archive(rlib, name);
}
fn add_archive(&mut self, archive: &Path, name: &str) {
let loc = TempDir::new("rsar").unwrap();
// First, extract the contents of the archive to a temporary directory
let archive = os::make_absolute(archive);
run_ar(self.sess, "x", Some(loc.path()), [&archive]);
// Next, we must rename all of the inputs to "guaranteed unique names".
// The reason for this is that archives are keyed off the name of the
// files, so if two files have the same name they will override one
// another in the archive (bad).
let files = fs::readdir(loc.path());
let mut inputs = ~[];
for file in files.iter() {
let filename = file.filename_str().unwrap();
let filename = format!("r-{}-{}", name, filename);
let new_filename = file.with_filename(filename);
fs::rename(file, &new_filename);
inputs.push(new_filename);
}
// Finally, add all the renamed files to this archive
let mut args = ~[&self.dst];
args.extend(&mut inputs.iter());
run_ar(self.sess, "r", None, args.as_slice());
}
fn find_library(&self, name: &str) -> Path {
let (prefix, ext) = match self.sess.targ_cfg.os {
abi::OsWin32 => ("", "lib"), _ => ("lib", "a"),
};
let libname = format!("{}{}.{}", prefix, name, ext);
let mut rustpath = filesearch::rust_path();
rustpath.push(self.sess.filesearch.get_target_lib_path());
let path = self.sess.opts.addl_lib_search_paths.iter();
for path in path.chain(rustpath.iter()) {
debug!("looking for {} inside {}", name, path.display());
let test = path.join(libname.clone());
if test.exists() { return test }
}
self.sess.fatal(format!("could not find native static library `{}`, \
perhaps an -L flag is missing?", name));
}
}

View file

@ -63,6 +63,6 @@ pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::
target_triple: target_triple, target_triple: target_triple,
cc_args: ~[~"-marm"] cc_args: ~[~"-marm"],
}; };
} }

View file

@ -9,6 +9,7 @@
// except according to those terms. // except according to those terms.
use back::archive::Archive;
use back::rpath; use back::rpath;
use driver::session::Session; use driver::session::Session;
use driver::session; use driver::session;
@ -16,7 +17,7 @@
use lib::llvm::ModuleRef; use lib::llvm::ModuleRef;
use lib; use lib;
use metadata::common::LinkMeta; use metadata::common::LinkMeta;
use metadata::{encoder, cstore, filesearch}; use metadata::{encoder, cstore, filesearch, csearch};
use middle::trans::context::CrateContext; use middle::trans::context::CrateContext;
use middle::trans::common::gensym_name; use middle::trans::common::gensym_name;
use middle::ty; use middle::ty;
@ -30,7 +31,6 @@
use std::ptr; use std::ptr;
use std::run; use std::run;
use std::str; use std::str;
use std::vec;
use std::io::fs; use std::io::fs;
use syntax::abi; use syntax::abi;
use syntax::ast; use syntax::ast;
@ -88,7 +88,6 @@ pub mod jit {
use driver::session::Session; use driver::session::Session;
use lib::llvm::llvm; use lib::llvm::llvm;
use lib::llvm::{ModuleRef, ContextRef, ExecutionEngineRef}; use lib::llvm::{ModuleRef, ContextRef, ExecutionEngineRef};
use metadata::cstore;
use std::c_str::ToCStr; use std::c_str::ToCStr;
use std::cast; use std::cast;
@ -125,19 +124,6 @@ pub fn exec(sess: Session,
// core linked into rustc. We don't want that, // core linked into rustc. We don't want that,
// incase the user wants to use an older extra library. // 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 // We custom-build a JIT execution engine via some rust wrappers
// first. This wrappers takes ownership of the module passed in. // first. This wrappers takes ownership of the module passed in.
let ee = llvm::LLVMRustBuildJIT(manager, m, stacks); let ee = llvm::LLVMRustBuildJIT(manager, m, stacks);
@ -368,20 +354,20 @@ pub fn run_passes(sess: Session,
} }
pub fn run_assembler(sess: Session, assembly: &Path, object: &Path) { 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 // FIXME (#9639): This needs to handle non-utf8 paths
let cc_args = ~[ let args = [
~"-c", ~"-c",
~"-o", object.as_str().unwrap().to_owned(), ~"-o", object.as_str().unwrap().to_owned(),
assembly.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() { if !prog.status.success() {
sess.err(format!("linking with `{}` failed: {}", cc_prog, prog.status)); sess.err(format!("linking with `{}` failed: {}", cc, prog.status));
sess.note(format!("{} arguments: {}", sess.note(format!("{} arguments: {}", cc, args.connect(" ")));
cc_prog, cc_args.connect(" ")));
sess.note(str::from_utf8(prog.error + prog.output)); sess.note(str::from_utf8(prog.error + prog.output));
sess.abort_if_errors(); 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) mangle(ccx.sess, path, None, None)
} }
pub fn output_lib_filename(lm: LinkMeta) -> ~str {
pub fn output_dll_filename(os: abi::Os, lm: LinkMeta) -> ~str { format!("{}-{}-{}", lm.name, lm.extras_hash, lm.vers)
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 get_cc_prog(sess: Session) -> ~str { 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. // In the future, FreeBSD will use clang as default compiler.
// It would be flexible to use cc (system's default C compiler) // It would be flexible to use cc (system's default C compiler)
// instead of hard-coded gcc. // instead of hard-coded gcc.
// For win32, there is no cc command, so we add a condition to make it use g++. // For win32, there is no cc command, so we add a condition to make it use
// We use g++ rather than gcc because it automatically adds linker options required // g++. We use g++ rather than gcc because it automatically adds linker
// for generation of dll modules that correctly register stack unwind tables. // options required for generation of dll modules that correctly register
match sess.opts.linker { // stack unwind tables.
Some(ref linker) => linker.to_str(), match sess.targ_cfg.os {
None => match sess.targ_cfg.os { abi::OsAndroid => match sess.opts.android_cross_path {
abi::OsAndroid => Some(ref path) => format!("{}/bin/arm-linux-androideabi-gcc", *path),
match &sess.opts.android_cross_path { None => {
&Some(ref path) => { sess.fatal("need Android NDK path for linking \
format!("{}/bin/arm-linux-androideabi-gcc", *path) (--android-cross-path)")
} }
&None => { },
sess.fatal("need Android NDK path for linking \ abi::OsWin32 => ~"g++",
(--android-cross-path)") _ => ~"cc",
}
},
abi::OsWin32 => ~"g++",
_ => ~"cc"
}
} }
} }
// If the user wants an exe generated we need to invoke /// Perform the linkage portion of the compilation phase. This will generate all
// cc to link the object file with some libs /// of the requested outputs for this compilation session.
pub fn link_binary(sess: Session, pub fn link_binary(sess: Session,
crate_types: &[~str],
obj_filename: &Path, obj_filename: &Path,
out_filename: &Path, out_filename: &Path,
lm: LinkMeta) { lm: LinkMeta) {
let outputs = if sess.opts.test {
let cc_prog = get_cc_prog(sess); // If we're generating a test executable, then ignore all other output
// The invocations of cc share some flags across platforms // styles at all other locations
~[session::OutputExecutable]
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)
} else { } 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()); for output in outputs.move_iter() {
let cc_args = link_args(sess, obj_filename, out_filename, lm); link_binary_output(sess, output, 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()]);
} }
// Remove the temporary object file if we aren't saving temps // 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 { fn is_writeable(p: &Path) -> bool {
use std::io; use std::io;
!p.exists() || match io::result(|| p.stat()) {
(match io::result(|| p.stat()) { Err(..) => true,
Err(..) => false, Ok(m) => m.perm & io::UserWrite == io::UserWrite
Ok(m) => m.perm & io::UserWrite == io::UserWrite }
})
} }
pub fn link_args(sess: Session, fn link_binary_output(sess: Session,
obj_filename: &Path, output: session::OutputStyle,
out_filename: &Path, obj_filename: &Path,
lm:LinkMeta) -> ~[~str] { out_filename: &Path,
lm: LinkMeta) {
// Converts a library file-stem into a cc -l argument let libname = output_lib_filename(lm);
fn unlib(config: @session::config, stem: ~str) -> ~str { let out_filename = match output {
if stem.starts_with("lib") && session::OutputRlib => {
config.os != abi::OsWin32 { out_filename.with_filename(format!("lib{}.rlib", libname))
stem.slice(3, stem.len()).to_owned()
} else {
stem
} }
} session::OutputDylib => {
let (prefix, suffix) = match sess.targ_cfg.os {
abi::OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
let output = if *sess.building_library { abi::OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
let long_libname = output_dll_filename(sess.targ_cfg.os, lm); abi::OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
out_filename.with_filename(long_libname) abi::OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX),
} else { abi::OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
out_filename.clone() };
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. // Make sure the output and obj_filename are both writeable.
@ -1006,61 +975,281 @@ fn unlib(config: @session::config, stem: ~str) -> ~str {
// however, the Linux linker will happily overwrite a read-only file. // however, the Linux linker will happily overwrite a read-only file.
// We should be consistent. // We should be consistent.
let obj_is_writeable = is_writeable(obj_filename); 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 { if !out_is_writeable {
sess.fatal(format!("Output file {} is not writeable -- check its permissions.", sess.fatal(format!("Output file {} is not writeable -- check its permissions.",
output.display())); out_filename.display()));
} }
else if !obj_is_writeable { else if !obj_is_writeable {
sess.fatal(format!("Object file {} is not writeable -- check its permissions.", sess.fatal(format!("Object file {} is not writeable -- check its permissions.",
obj_filename.display())); 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 default library location, we need this to find the runtime.
// The location of crates will be determined as needed. // The location of crates will be determined as needed.
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
let lib_path = sess.filesearch.get_target_lib_path(); let lib_path = sess.filesearch.get_target_lib_path();
let stage: ~str = ~"-L" + lib_path.as_str().unwrap(); 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 // FIXME (#9639): This needs to handle non-utf8 paths
args.push_all([ 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()]); obj_filename.as_str().unwrap().to_owned()]);
let lib_cmd = match sess.targ_cfg.os { if sess.targ_cfg.os == abi::OsLinux {
abi::OsMacos => ~"-dynamiclib", // GNU-style linkers will use this to omit linking to libraries which
_ => ~"-shared" // 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 // GNU-style linkers supports optimization with -O. --gc-sections
// removes metadata and potentially other useful things, so don't
let cstore = sess.cstore; // include it. GNU ld doesn't need a numeric argument, but other linkers
let r = cstore::get_used_crate_files(cstore); // do.
// FIXME (#9639): This needs to handle non-utf8 paths if sess.opts.optimize == session::Default ||
for cratepath in r.iter() { sess.opts.optimize == session::Aggressive {
if cratepath.extension_str() == Some("rlib") { args.push(~"-Wl,-O1");
args.push(cratepath.as_str().unwrap().to_owned());
continue;
} }
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); add_upstream_rust_crates(&mut args, sess, dylib);
for arg in ula.iter() { args.push(arg.to_owned()); } 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 if dylib {
// the same paths used to find Rust crates, so some of them may have been // On mac we need to tell the linker to let this library be rpathed
// added already by the previous crate linking code. This only allows them if sess.targ_cfg.os == abi::OsMacos {
// to be found at compile time so it is still entirely up to outside args.push(~"-dynamiclib");
// forces to make sure that library can be found at runtime. args.push(~"-Wl,-dylib");
// FIXME (#9639): This needs to handle non-utf8 paths
args.push(~"-Wl,-install_name,@rpath/" +
out_filename.filename_str().unwrap());
} else {
args.push(~"-shared")
}
}
if sess.targ_cfg.os == abi::OsFreebsd {
args.push_all([~"-L/usr/local/lib",
~"-L/usr/local/lib/gcc46",
~"-L/usr/local/lib/gcc44"]);
}
// Stack growth requires statically linking a __morestack function
args.push(~"-lmorestack");
// FIXME (#2397): At some point we want to rpath our guesses as to
// where extern libraries might live, based on the
// addl_lib_search_paths
args.push_all(rpath::get_rpath_flags(sess, out_filename));
// Finally add all the linker arguments provided on the command line along
// with any #[link_args] attributes found inside the crate
args.push_all(sess.opts.linker_args);
for arg in cstore::get_used_link_args(sess.cstore).iter() {
args.push(arg.clone());
}
return args;
}
// # Rust Crate linking
//
// Rust crates are not considered at all when creating an rlib output. All
// dependencies will be linked when producing the final output (instead of
// the intermediate rlib version)
fn add_upstream_rust_crates(args: &mut ~[~str], sess: Session,
dylib: bool) {
// Converts a library file-stem into a cc -l argument
fn unlib(config: @session::config, stem: &str) -> ~str {
if stem.starts_with("lib") &&
config.os != abi::OsWin32 {
stem.slice(3, stem.len()).to_owned()
} else {
stem.to_owned()
}
}
let cstore = sess.cstore;
if !dylib && !sess.prefer_dynamic() {
// With an executable, things get a little interesting. As a limitation
// of the current implementation, we require that everything must be
// static, or everything must be dynamic. The reasons for this are a
// little subtle, but as with the above two cases, the goal is to
// prevent duplicate copies of the same library showing up. For example,
// a static immediate dependency might show up as an upstream dynamic
// dependency and we currently have no way of knowing that. We know that
// all dynamic libaries require dynamic dependencies (see above), so
// it's satisfactory to include either all static libraries or all
// dynamic libraries.
let crates = cstore::get_used_crates(cstore,
cstore::RequireStatic);
if crates.iter().all(|&(_, ref p)| p.is_some()) {
for &(cnum, ref path) in crates.iter() {
let cratepath = path.clone().unwrap();
// If we're linking to the static version of the crate, then
// we're mostly good to go. The caveat here is that we need to
// pull in the static crate's native dependencies.
args.push(cratepath.as_str().unwrap().to_owned());
let libs = csearch::get_native_libraries(sess.cstore, cnum);
for lib in libs.iter() {
args.push("-l" + *lib);
}
}
return;
}
}
// This is a fallback of three differnet cases of linking:
//
// * When creating a dynamic library, all inputs are required to be dynamic
// as well
// * If an executable is created with a preference on dynamic linking, then
// this case is the fallback
// * If an executable is being created, and one of the inputs is missing as
// a static library, then this is the fallback case.
let crates = cstore::get_used_crates(cstore, cstore::RequireDynamic);
for &(cnum, ref path) in crates.iter() {
let cratepath = match *path {
Some(ref p) => p.clone(), None => {
sess.err(format!("could not find dynamic library for: `{}`",
cstore::get_crate_data(sess.cstore, cnum).name));
return
}
};
// Just need to tell the linker about where the library lives and what
// its name is
let dir = cratepath.dirname_str().unwrap();
if !dir.is_empty() { args.push("-L" + dir); }
let libarg = unlib(sess.targ_cfg, cratepath.filestem_str().unwrap());
args.push("-l" + libarg);
}
}
// # Native library linking
//
// User-supplied library search paths (-L on the cammand line) These are
// the same paths used to find Rust crates, so some of them may have been
// added already by the previous crate linking code. This only allows them
// to be found at compile time so it is still entirely up to outside
// forces to make sure that library can be found at runtime.
//
// Also note that the native libraries linked here are only the ones located
// in the current crate. Upstream crates with native library dependencies
// may have their native library pulled in above.
fn add_local_native_libraries(args: &mut ~[~str], sess: Session) {
for path in sess.opts.addl_lib_search_paths.iter() { for path in sess.opts.addl_lib_search_paths.iter() {
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
args.push("-L" + path.as_str().unwrap().to_owned()); args.push("-L" + path.as_str().unwrap().to_owned());
@ -1072,73 +1261,7 @@ fn unlib(config: @session::config, stem: ~str) -> ~str {
args.push("-L" + path.as_str().unwrap().to_owned()); args.push("-L" + path.as_str().unwrap().to_owned());
} }
if sess.targ_cfg.os == abi::OsLinux { for &(ref l, _) in cstore::get_used_libraries(sess.cstore).iter() {
// GNU-style linkers will use this to omit linking to libraries which don't actually fulfill args.push(~"-l" + *l);
// any relocations, but only for libraries which follow this flag. Thus, use it before
// specifing libraries to link to.
args.push(~"-Wl,--as-needed");
} }
// 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;
} }

View file

@ -63,6 +63,6 @@ pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::
target_triple: target_triple, target_triple: target_triple,
cc_args: ~[] cc_args: ~[],
}; };
} }

View file

@ -21,8 +21,7 @@ fn not_win32(os: abi::Os) -> bool {
os != abi::OsWin32 os != abi::OsWin32
} }
pub fn get_rpath_flags(sess: session::Session, out_filename: &Path) pub fn get_rpath_flags(sess: session::Session, out_filename: &Path) -> ~[~str] {
-> ~[~str] {
let os = sess.targ_cfg.os; let os = sess.targ_cfg.os;
// No rpath on windows // No rpath on windows
@ -30,18 +29,28 @@ pub fn get_rpath_flags(sess: session::Session, out_filename: &Path)
return ~[]; 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!"); debug!("preparing the RPATH!");
let sysroot = sess.filesearch.sysroot(); let sysroot = sess.filesearch.sysroot();
let output = out_filename; 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 // We don't currently rpath extern libraries, but we know
// where rustrt is and we know every rust program needs it // where rustrt is and we know every rust program needs it
let libs = vec::append_one(libs, get_sysroot_absolute_rt_lib(sess)); let libs = vec::append_one(libs, get_sysroot_absolute_rt_lib(sess));
let rpaths = get_rpaths(os, sysroot, output, libs, let rpaths = get_rpaths(os, sysroot, output, libs,
sess.opts.target_triple); 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 { 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] { pub fn rpaths_to_flags(rpaths: &[~str]) -> ~[~str] {
// FIXME (#9639): This needs to handle non-utf8 paths let mut ret = ~[];
rpaths.iter().map(|rpath| format!("-Wl,-rpath,{}",*rpath)).collect() for rpath in rpaths.iter() {
ret.push("-Wl,-rpath," + *rpath);
}
return ret;
} }
fn get_rpaths(os: abi::Os, fn get_rpaths(os: abi::Os,

View file

@ -14,5 +14,5 @@ pub struct t {
meta_sect_name: ~str, meta_sect_name: ~str,
data_layout: ~str, data_layout: ~str,
target_triple: ~str, target_triple: ~str,
cc_args: ~[~str] cc_args: ~[~str],
} }

View file

@ -46,6 +46,6 @@ pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::
target_triple: target_triple, target_triple: target_triple,
cc_args: ~[~"-m32"] cc_args: ~[~"-m32"],
}; };
} }

View file

@ -54,6 +54,6 @@ pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::
target_triple: target_triple, target_triple: target_triple,
cc_args: ~[~"-m64"] cc_args: ~[~"-m64"],
}; };
} }

View file

@ -11,7 +11,7 @@
use back::link; use back::link;
use back::{arm, x86, x86_64, mips}; 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::{Session, Session_, No, Less, Default};
use driver::session; use driver::session;
use front; use front;
@ -164,8 +164,11 @@ pub fn phase_2_configure_and_expand(sess: Session,
mut crate: ast::Crate) -> ast::Crate { mut crate: ast::Crate) -> ast::Crate {
let time_passes = sess.time_passes(); let time_passes = sess.time_passes();
*sess.building_library = session::building_library(sess.opts.crate_type, *sess.building_library = session::building_library(sess.opts, &crate);
&crate, sess.opts.test); 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", (), |_| time(time_passes, "gated feature checking", (), |_|
front::feature_gate::check_crate(sess, &crate)); 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)); syntax::ast_map::map_crate(sess.diagnostic(), crate));
time(time_passes, "external crate/lib resolution", (), |_| time(time_passes, "external crate/lib resolution", (), |_|
creader::read_crates(sess.diagnostic(), crate, sess.cstore, creader::read_crates(sess, crate,
sess.filesearch,
session::sess_os_to_meta_os(sess.targ_cfg.os), session::sess_os_to_meta_os(sess.targ_cfg.os),
sess.opts.is_static,
token::get_ident_interner())); token::get_ident_interner()));
let lang_items = time(time_passes, "language item collection", (), |_| 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 { pub struct CrateTranslation {
context: ContextRef, context: ContextRef,
module: ModuleRef, module: ModuleRef,
link: LinkMeta link: LinkMeta,
crate_types: ~[~str],
} }
/// Run the translation phase to LLVM, after which the AST and analysis can /// 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) { outputs: &OutputFilenames) {
time(sess.time_passes(), "linking", (), |_| time(sess.time_passes(), "linking", (), |_|
link::link_binary(sess, link::link_binary(sess,
trans.crate_types,
&outputs.obj_filename, &outputs.obj_filename,
&outputs.out_filename, &outputs.out_filename,
trans.link)); trans.link));
@ -417,11 +420,6 @@ pub fn stop_after_phase_5(sess: Session) -> bool {
return true; 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 { if sess.opts.jit {
debug!("running JIT, returning early from compile_input"); debug!("running JIT, returning early from compile_input");
return true; return true;
@ -652,13 +650,21 @@ pub fn build_session_options(binary: @str,
matches: &getopts::Matches, matches: &getopts::Matches,
demitter: @diagnostic::Emitter) demitter: @diagnostic::Emitter)
-> @session::options { -> @session::options {
let crate_type = if matches.opt_present("lib") { let mut outputs = ~[];
session::lib_crate if matches.opt_present("rlib") {
} else if matches.opt_present("bin") { outputs.push(session::OutputRlib)
session::bin_crate }
} else { if matches.opt_present("staticlib") {
session::unknown_crate 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 parse_only = matches.opt_present("parse-only");
let no_trans = matches.opt_present("no-trans"); 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 || let debuginfo = debugging_opts & session::debug_info != 0 ||
extra_debuginfo; extra_debuginfo;
let statik = debugging_opts & session::statik != 0;
let addl_lib_search_paths = matches.opt_strs("L").map(|s| { let addl_lib_search_paths = matches.opt_strs("L").map(|s| {
Path::init(s.as_slice()) Path::init(s.as_slice())
}).move_iter().collect(); }).move_iter().collect();
let ar = matches.opt_str("ar");
let linker = matches.opt_str("linker"); let linker = matches.opt_str("linker");
let linker_args = matches.opt_strs("link-args").flat_map( |a| { let linker_args = matches.opt_strs("link-args").flat_map( |a| {
a.split(' ').map(|arg| arg.to_owned()).collect() a.split(' ').map(|arg| arg.to_owned()).collect()
@ -782,8 +787,7 @@ pub fn build_session_options(binary: @str,
}; };
let sopts = @session::options { let sopts = @session::options {
crate_type: crate_type, outputs: outputs,
is_static: statik,
gc: gc, gc: gc,
optimize: opt_level, optimize: opt_level,
custom_passes: custom_passes, custom_passes: custom_passes,
@ -795,6 +799,7 @@ pub fn build_session_options(binary: @str,
jit: jit, jit: jit,
output_type: output_type, output_type: output_type,
addl_lib_search_paths: @mut addl_lib_search_paths, addl_lib_search_paths: @mut addl_lib_search_paths,
ar: ar,
linker: linker, linker: linker,
linker_args: linker_args, linker_args: linker_args,
maybe_sysroot: sysroot_opt, maybe_sysroot: sysroot_opt,
@ -871,7 +876,6 @@ pub fn parse_pretty(sess: Session, name: &str) -> PpMode {
// rustc command line options // rustc command line options
pub fn optgroups() -> ~[getopts::groups::OptGroup] { pub fn optgroups() -> ~[getopts::groups::OptGroup] {
~[ ~[
optflag("", "bin", "Compile an executable crate (default)"),
optflag("c", "", "Compile and assemble, but do not link"), optflag("c", "", "Compile and assemble, but do not link"),
optmulti("", "cfg", "Configure the compilation optmulti("", "cfg", "Configure the compilation
environment", "SPEC"), environment", "SPEC"),
@ -881,8 +885,13 @@ pub fn optgroups() -> ~[getopts::groups::OptGroup] {
optflag("h", "help","Display this message"), optflag("h", "help","Display this message"),
optmulti("L", "", "Add a directory to the library search path", optmulti("L", "", "Add a directory to the library search path",
"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("", "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 optmulti("", "link-args", "FLAGS is a space-separated list of flags
passed to the linker", "FLAGS"), passed to the linker", "FLAGS"),
optflag("", "ls", "List the symbols defined by a library crate"), 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 obj_path;
let out_path; let out_path;
let sopts = sess.opts; let sopts = sess.opts;
let stop_after_codegen = let stop_after_codegen = sopts.output_type != link::output_type_exe;
sopts.output_type != link::output_type_exe ||
sopts.is_static && *sess.building_library;
let obj_suffix = let obj_suffix = match sopts.output_type {
match sopts.output_type { link::output_type_none => ~"none",
link::output_type_none => ~"none", link::output_type_bitcode => ~"bc",
link::output_type_bitcode => ~"bc", link::output_type_assembly => ~"s",
link::output_type_assembly => ~"s", link::output_type_llvm_assembly => ~"ll",
link::output_type_llvm_assembly => ~"ll", // Object and exe output both use the '.o' extension here
// Object and exe output both use the '.o' extension here link::output_type_object | link::output_type_exe => ~"o"
link::output_type_object | link::output_type_exe => ~"o" };
};
match *ofile { match *ofile {
None => { 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) { pub fn list_metadata(sess: Session, path: &Path, out: @mut io::Writer) {
metadata::loader::list_file_metadata( metadata::loader::list_file_metadata(
sess,
token::get_ident_interner(), token::get_ident_interner(),
session::sess_os_to_meta_os(sess.targ_cfg.os), path, out); session::sess_os_to_meta_os(sess.targ_cfg.os), path, out);
} }

View file

@ -13,7 +13,6 @@
use back::target_strs; use back::target_strs;
use back; use back;
use driver::driver::host_triple; use driver::driver::host_triple;
use driver::session;
use metadata::filesearch; use metadata::filesearch;
use metadata; use metadata;
use middle::lint; use middle::lint;
@ -30,13 +29,6 @@
use std::hashmap::{HashMap,HashSet}; use std::hashmap::{HashMap,HashSet};
#[deriving(Clone)]
pub enum crate_type {
bin_crate,
lib_crate,
unknown_crate,
}
pub struct config { pub struct config {
os: abi::Os, os: abi::Os,
arch: abi::Architecture, arch: abi::Architecture,
@ -66,16 +58,16 @@ pub struct config {
pub static jit: uint = 1 << 18; pub static jit: uint = 1 << 18;
pub static debug_info: uint = 1 << 19; pub static debug_info: uint = 1 << 19;
pub static extra_debug_info: uint = 1 << 20; pub static extra_debug_info: uint = 1 << 20;
pub static statik: uint = 1 << 21; pub static print_link_args: uint = 1 << 21;
pub static print_link_args: uint = 1 << 22; pub static no_debug_borrows: uint = 1 << 22;
pub static no_debug_borrows: uint = 1 << 23; pub static lint_llvm: uint = 1 << 23;
pub static lint_llvm: uint = 1 << 24; pub static print_llvm_passes: uint = 1 << 24;
pub static print_llvm_passes: uint = 1 << 25; pub static no_vectorize_loops: uint = 1 << 25;
pub static no_vectorize_loops: uint = 1 << 26; pub static no_vectorize_slp: uint = 1 << 26;
pub static no_vectorize_slp: uint = 1 << 27; pub static no_prepopulate_passes: uint = 1 << 27;
pub static no_prepopulate_passes: uint = 1 << 28; pub static use_softfp: uint = 1 << 28;
pub static use_softfp: uint = 1 << 29; pub static gen_crate_map: uint = 1 << 29;
pub static gen_crate_map: uint = 1 << 30; pub static prefer_dynamic: uint = 1 << 30;
pub fn debugging_opts_map() -> ~[(&'static str, &'static str, uint)] { pub fn debugging_opts_map() -> ~[(&'static str, &'static str, uint)] {
~[("verbose", "in general, enable more debug printouts", verbose), ~[("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", "Extra debugging info (experimental)",
extra_debug_info), extra_debug_info),
("debug-info", "Produce debug info (experimental)", debug_info), ("debug-info", "Produce debug info (experimental)", debug_info),
("static", "Use or produce static libraries or binaries (experimental)", statik),
("no-debug-borrows", ("no-debug-borrows",
"do not show where borrow checks fail", "do not show where borrow checks fail",
no_debug_borrows), no_debug_borrows),
@ -129,6 +120,7 @@ pub fn debugging_opts_map() -> ~[(&'static str, &'static str, uint)] {
no_vectorize_slp), no_vectorize_slp),
("soft-float", "Generate software floating point library calls", use_softfp), ("soft-float", "Generate software floating point library calls", use_softfp),
("gen-crate-map", "Force generation of a toplevel crate map", gen_crate_map), ("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 { pub struct options {
// The crate config requested for the session, which may be combined // The crate config requested for the session, which may be combined
// with additional crate configurations during the compile process // with additional crate configurations during the compile process
crate_type: crate_type, outputs: ~[OutputStyle],
is_static: bool,
gc: bool, gc: bool,
optimize: OptLevel, optimize: OptLevel,
custom_passes: ~[~str], custom_passes: ~[~str],
@ -159,6 +151,7 @@ pub struct options {
addl_lib_search_paths: @mut HashSet<Path>, // This is mutable for rustpkg, which addl_lib_search_paths: @mut HashSet<Path>, // This is mutable for rustpkg, which
// updates search paths based on the // updates search paths based on the
// parsed code // parsed code
ar: Option<~str>,
linker: Option<~str>, linker: Option<~str>,
linker_args: ~[~str], linker_args: ~[~str],
maybe_sysroot: Option<@Path>, maybe_sysroot: Option<@Path>,
@ -194,6 +187,14 @@ pub enum EntryFnType {
EntryNone, EntryNone,
} }
#[deriving(Eq, Clone)]
pub enum OutputStyle {
OutputExecutable,
OutputDylib,
OutputRlib,
OutputStaticlib,
}
pub struct Session_ { pub struct Session_ {
targ_cfg: @config, targ_cfg: @config,
opts: @options, opts: @options,
@ -337,6 +338,9 @@ pub fn no_vectorize_slp(&self) -> bool {
pub fn gen_crate_map(&self) -> bool { pub fn gen_crate_map(&self) -> bool {
self.debugging_opt(gen_crate_map) self.debugging_opt(gen_crate_map)
} }
pub fn prefer_dynamic(&self) -> bool {
self.debugging_opt(prefer_dynamic)
}
// pointless function, now... // pointless function, now...
pub fn str_of(&self, id: ast::Ident) -> @str { pub fn str_of(&self, id: ast::Ident) -> @str {
@ -357,8 +361,7 @@ pub fn intr(&self) -> @syntax::parse::token::ident_interner {
/// Some reasonable defaults /// Some reasonable defaults
pub fn basic_options() -> @options { pub fn basic_options() -> @options {
@options { @options {
crate_type: session::lib_crate, outputs: ~[],
is_static: false,
gc: false, gc: false,
optimize: No, optimize: No,
custom_passes: ~[], custom_passes: ~[],
@ -370,6 +373,7 @@ pub fn basic_options() -> @options {
jit: false, jit: false,
output_type: link::output_type_exe, output_type: link::output_type_exe,
addl_lib_search_paths: @mut HashSet::new(), addl_lib_search_paths: @mut HashSet::new(),
ar: None,
linker: None, linker: None,
linker_args: ~[], linker_args: ~[],
maybe_sysroot: None, maybe_sysroot: None,
@ -391,24 +395,17 @@ pub fn expect<T:Clone>(sess: Session, opt: Option<T>, msg: || -> ~str) -> T {
diagnostic::expect(sess.diagnostic(), opt, msg) diagnostic::expect(sess.diagnostic(), opt, msg)
} }
pub fn building_library(req_crate_type: crate_type, pub fn building_library(options: &options, crate: &ast::Crate) -> bool {
crate: &ast::Crate, for output in options.outputs.iter() {
testing: bool) -> bool { match *output {
match req_crate_type { OutputExecutable => {}
bin_crate => false, OutputStaticlib | OutputDylib | OutputRlib => return true
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
}
} }
} }
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
} }
} }

View file

@ -21,6 +21,7 @@
use middle::lint; use middle::lint;
use syntax::ast; use syntax::ast;
use syntax::attr;
use syntax::attr::AttrMetaMethods; use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::visit; use syntax::visit;
@ -41,6 +42,7 @@
("managed_boxes", Active), ("managed_boxes", Active),
("non_ascii_idents", Active), ("non_ascii_idents", Active),
("thread_local", Active), ("thread_local", Active),
("link_args", Active),
// These are used to test this portion of the compiler, they don't actually // These are used to test this portion of the compiler, they don't actually
// mean anything // mean anything
@ -111,7 +113,8 @@ fn visit_view_item(&mut self, i: &ast::view_item, _: ()) {
fn visit_item(&mut self, i: @ast::item, _:()) { fn visit_item(&mut self, i: @ast::item, _:()) {
for attr in i.attrs.iter() { 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, self.gate_feature("thread_local", i.span,
"`#[thread_local]` is an experimental feature, and does not \ "`#[thread_local]` is an experimental feature, and does not \
currently handle destructors. There is no corresponding \ currently handle destructors. There is no corresponding \
@ -132,6 +135,16 @@ fn visit_item(&mut self, i: @ast::item, _:()) {
} }
} }
ast::item_foreign_mod(*) => {
if attr::contains_name(i.attrs, "link_args") &&
cfg!(stage0, remove_this_on_next_snapshot) { // NOTE: snap
self.gate_feature("link_args", i.span,
"the `link_args` attribute is not portable \
across platforms, it is recommended to \
use `#[link(name = \"foo\")]` instead")
}
}
_ => {} _ => {}
} }

View file

@ -16,7 +16,8 @@
#[comment = "The Rust compiler"]; #[comment = "The Rust compiler"];
#[license = "MIT/ASL2"]; #[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)]; #[feature(macro_rules, globs, struct_variant, managed_boxes)];
@ -87,6 +88,7 @@ pub mod front {
} }
pub mod back { pub mod back {
pub mod archive;
pub mod link; pub mod link;
pub mod abi; pub mod abi;
pub mod upcall; pub mod upcall;

View file

@ -14,7 +14,6 @@
use std::hashmap::HashMap; use std::hashmap::HashMap;
use std::libc::{c_uint, c_ushort, c_void, free}; use std::libc::{c_uint, c_ushort, c_void, free};
use std::str::raw::from_c_str; use std::str::raw::from_c_str;
use std::option;
use middle::trans::type_::Type; use middle::trans::type_::Type;
@ -304,9 +303,16 @@ pub mod llvm {
use super::{ValueRef, TargetMachineRef, FileType}; use super::{ValueRef, TargetMachineRef, FileType};
use super::{CodeGenModel, RelocMode, CodeGenOptLevel}; use super::{CodeGenModel, RelocMode, CodeGenOptLevel};
use super::debuginfo::*; 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"] #[link_args = "-lrustllvm"]
extern {}
#[cfg(not(stage0))] // if you're deleting this, put this on the block below
#[link(name = "rustllvm")]
extern {}
extern { extern {
/* Create and destroy contexts. */ /* Create and destroy contexts. */
pub fn LLVMContextCreate() -> ContextRef; pub fn LLVMContextCreate() -> ContextRef;
@ -1426,6 +1432,16 @@ pub fn LLVMIsSectionIteratorAtEnd(ObjFile: ObjectFileRef,
LLVMDisposeMemoryBuffer() to get rid of it. */ LLVMDisposeMemoryBuffer() to get rid of it. */
pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(Path: *c_char) pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(Path: *c_char)
-> MemoryBufferRef; -> 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* /** Returns a string describing the last error caused by an LLVMRust*
call. */ call. */
@ -1901,38 +1917,32 @@ pub fn mk_pass_manager() -> PassManager {
/* Memory-managed interface to object files. */ /* Memory-managed interface to object files. */
pub struct object_file_res { pub struct ObjectFile {
ObjectFile: ObjectFileRef, llof: ObjectFileRef,
} }
impl Drop for object_file_res { impl ObjectFile {
fn drop(&mut self) { // This will take ownership of llmb
pub fn new(llmb: MemoryBufferRef) -> Option<ObjectFile> {
unsafe { 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 { impl Drop for ObjectFile {
object_file_res { fn drop(&mut self) {
ObjectFile: ObjFile unsafe {
} llvm::LLVMDisposeObjectFile(self.llof);
} }
pub struct ObjectFile {
llof: ObjectFileRef,
dtor: @object_file_res
}
pub fn mk_object_file(llmb: MemoryBufferRef) -> Option<ObjectFile> {
unsafe {
let llof = llvm::LLVMCreateObjectFile(llmb);
if llof as int == 0 { return option::None::<ObjectFile>; }
option::Some(ObjectFile {
llof: llof,
dtor: @object_file_res(llof)
})
} }
} }

View file

@ -197,6 +197,8 @@ pub fn from_uint(value : uint) -> Option<astencode_tag> {
pub static tag_region_param_def_ident: uint = 0x101; pub static tag_region_param_def_ident: uint = 0x101;
pub static tag_region_param_def_def_id: uint = 0x102; 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 { pub struct LinkMeta {
name: @str, name: @str,

View file

@ -10,10 +10,9 @@
//! Validates all used crates and extern libraries and loads their metadata //! Validates all used crates and extern libraries and loads their metadata
use driver::session::Session;
use metadata::cstore; use metadata::cstore;
use metadata::decoder; use metadata::decoder;
use metadata::filesearch::FileSearch;
use metadata::loader; use metadata::loader;
use std::hashmap::HashMap; use std::hashmap::HashMap;
@ -29,19 +28,13 @@
// Traverses an AST, reading all the information about use'd crates and extern // Traverses an AST, reading all the information about use'd crates and extern
// libraries necessary for later resolving, typechecking, linking, etc. // 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, crate: &ast::Crate,
cstore: @mut cstore::CStore,
filesearch: @FileSearch,
os: loader::Os, os: loader::Os,
statik: bool,
intr: @ident_interner) { intr: @ident_interner) {
let e = @mut Env { let e = @mut Env {
diag: diag, sess: sess,
filesearch: filesearch,
cstore: cstore,
os: os, os: os,
statik: statik,
crate_cache: @mut ~[], crate_cache: @mut ~[],
next_crate_num: 1, next_crate_num: 1,
intr: intr intr: intr
@ -50,7 +43,7 @@ pub fn read_crates(diag: @mut span_handler,
visit_crate(e, crate); visit_crate(e, crate);
visit::walk_crate(&mut v, crate, ()); visit::walk_crate(&mut v, crate, ());
dump_crates(*e.crate_cache); dump_crates(*e.crate_cache);
warn_if_multiple_versions(e, diag, *e.crate_cache); warn_if_multiple_versions(e, sess.diagnostic(), *e.crate_cache);
} }
struct ReadCrateVisitor { e:@mut Env } struct ReadCrateVisitor { e:@mut Env }
@ -113,18 +106,15 @@ fn warn_if_multiple_versions(e: @mut Env,
} }
struct Env { struct Env {
diag: @mut span_handler, sess: Session,
filesearch: @FileSearch,
cstore: @mut cstore::CStore,
os: loader::Os, os: loader::Os,
statik: bool,
crate_cache: @mut ~[cache_entry], crate_cache: @mut ~[cache_entry],
next_crate_num: ast::CrateNum, next_crate_num: ast::CrateNum,
intr: @ident_interner intr: @ident_interner
} }
fn visit_crate(e: &Env, c: &ast::Crate) { 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()) { for a in c.attrs.iter().filter(|m| "link_args" == m.name()) {
match a.value_str() { 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); let p_path = Path::init(p);
match p_path.filestem_str() { match p_path.filestem_str() {
None|Some("") => 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) => Some(s) =>
vec::append( vec::append(
~[attr::mk_name_value_item_str(@"package_id", p), ~[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, meta_items,
@"", @"",
i.span); 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) { fn visit_item(e: &Env, i: @ast::item) {
match i.node { match i.node {
ast::item_foreign_mod(ref fm) => { ast::item_foreign_mod(ref fm) => {
if fm.abis.is_rust() || fm.abis.is_intrinsic() { if fm.abis.is_rust() || fm.abis.is_intrinsic() {
return; return;
} }
let cstore = e.cstore; // First, add all of the custom link_args attributes
let link_args = i.attrs.iter() let cstore = e.sess.cstore;
.filter_map(|at| if "link_args" == at.name() {Some(at)} else {None}) let link_args = i.attrs.iter()
.collect::<~[&ast::Attribute]>(); .filter_map(|at| if "link_args" == at.name() {Some(at)} else {None})
.to_owned_vec();
// XXX: two whom it may concern, this was the old logic applied to the for m in link_args.iter() {
// ast's extern mod blocks which had names (we used to allow match m.value_str() {
// "extern mod foo"). This code was never run for anonymous blocks, Some(linkarg) => {
// and we now only have anonymous blocks. We're still in the midst cstore::add_used_link_args(cstore, linkarg);
// of figuring out what the exact operations we'd like to support }
// when linking external modules, but I wanted to leave this logic None => { /* fallthrough */ }
// here for the time beging to refer back to it }
}
//let mut already_added = false;
//let link_name = i.attrs.iter() // Next, process all of the #[link(..)]-style arguments
// .find(|at| "link_name" == at.name()) let cstore = e.sess.cstore;
// .and_then(|at| at.value_str()); let link_args = i.attrs.iter()
.filter_map(|at| if "link" == at.name() {Some(at)} else {None})
//let foreign_name = match link_name { .to_owned_vec();
// Some(nn) => { for m in link_args.iter() {
// if nn.is_empty() { match m.meta_item_list() {
// e.diag.span_fatal( Some(items) => {
// i.span, let kind = do items.iter().find |k| {
// "empty #[link_name] not allowed; use \ "kind" == k.name()
// #[nolink]."); }.and_then(|a| a.value_str());
// } let kind = match kind {
// nn Some(k) if "static" == k => cstore::NativeStatic,
// } Some(k) => {
// None => token::ident_to_str(&i.ident) e.sess.span_fatal(i.span,
// }; format!("unknown kind: `{}`", k));
//if !attr::contains_name(i.attrs, "nolink") { }
// already_added = None => cstore::NativeUnknown
// !cstore::add_used_library(cstore, foreign_name); };
//} let n = do items.iter().find |n| {
//if !link_args.is_empty() && already_added { "name" == n.name()
// e.diag.span_fatal(i.span, ~"library '" + foreign_name + }.and_then(|a| a.value_str());
// "' already added: can't specify link_args."); let n = match n {
//} Some(n) => n,
None => {
for m in link_args.iter() { e.sess.span_fatal(i.span,
match m.value_str() { "#[link(...)] specified without \
Some(linkarg) => { `name = \"foo\"`");
cstore::add_used_link_args(cstore, linkarg); }
};
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) { match existing_match(e, metas, hash) {
None => { None => {
let load_ctxt = loader::Context { let load_ctxt = loader::Context {
diag: e.diag, sess: e.sess,
filesearch: e.filesearch,
span: span, span: span,
ident: ident, ident: ident,
metas: metas, metas: metas,
hash: hash, hash: hash,
os: e.os, os: e.os,
is_static: e.statik,
intr: e.intr 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 attrs = decoder::get_crate_attributes(metadata);
let cdata = ldata;
let attrs = decoder::get_crate_attributes(cdata);
let linkage_metas = attr::find_linkage_metas(attrs); 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 // Claim this crate number and cache it
let cnum = e.next_crate_num; let cnum = e.next_crate_num;
@ -293,7 +282,7 @@ fn resolve_crate(e: @mut Env,
e.next_crate_num += 1; e.next_crate_num += 1;
// Now resolve the crates referenced by this crate // 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 = let cname =
match attr::last_meta_item_value_str_by_name(load_ctxt.metas, 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 { let cmeta = @cstore::crate_metadata {
name: cname, name: cname,
data: cdata, data: metadata,
cnum_map: cnum_map, cnum_map: cnum_map,
cnum: cnum cnum: cnum
}; };
let cstore = e.cstore; let cstore = e.sess.cstore;
cstore::set_crate_data(cstore, cnum, cmeta); 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; return cnum;
} }
Some(cnum) => { Some(cnum) => {

View file

@ -262,6 +262,12 @@ pub fn get_item_visibility(cstore: @mut cstore::CStore,
decoder::get_item_visibility(cdata, def_id.node) 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, pub fn each_impl(cstore: @mut cstore::CStore,
crate_num: ast::CrateNum, crate_num: ast::CrateNum,
callback: |ast::DefId|) { callback: |ast::DefId|) {

View file

@ -34,12 +34,33 @@ pub struct crate_metadata {
cnum: ast::CrateNum cnum: ast::CrateNum
} }
#[deriving(Eq)]
pub enum LinkagePreference {
RequireDynamic,
RequireStatic,
}
#[deriving(Eq)]
pub enum NativeLibaryKind {
NativeStatic,
NativeUnknown,
}
// Where a crate came from on the local filesystem. One of these two options
// must be non-None.
#[deriving(Eq)]
pub struct CrateSource {
dylib: Option<Path>,
rlib: Option<Path>,
cnum: ast::CrateNum,
}
pub struct CStore { pub struct CStore {
priv metas: HashMap <ast::CrateNum, @crate_metadata>, priv metas: HashMap <ast::CrateNum, @crate_metadata>,
priv extern_mod_crate_map: extern_mod_crate_map, priv extern_mod_crate_map: extern_mod_crate_map,
priv used_crate_files: ~[Path], priv used_crate_sources: ~[CrateSource],
priv used_libraries: ~[@str], priv used_libraries: ~[(~str, NativeLibaryKind)],
priv used_link_args: ~[@str], priv used_link_args: ~[~str],
intr: @ident_interner intr: @ident_interner
} }
@ -50,7 +71,7 @@ pub fn mk_cstore(intr: @ident_interner) -> CStore {
return CStore { return CStore {
metas: HashMap::new(), metas: HashMap::new(),
extern_mod_crate_map: HashMap::new(), extern_mod_crate_map: HashMap::new(),
used_crate_files: ~[], used_crate_sources: ~[],
used_libraries: ~[], used_libraries: ~[],
used_link_args: ~[], used_link_args: ~[],
intr: intr 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) { pub fn add_used_crate_source(cstore: &mut CStore, src: CrateSource) {
if !cstore.used_crate_files.contains(lib) { if !cstore.used_crate_sources.contains(&src) {
cstore.used_crate_files.push((*lib).clone()); cstore.used_crate_sources.push(src);
} }
} }
pub fn get_used_crate_files(cstore: &CStore) -> ~[Path] { pub fn get_used_crate_sources<'a>(cstore: &'a CStore) -> &'a [CrateSource] {
// XXX(pcwalton): Bad copy. cstore.used_crate_sources.as_slice()
return cstore.used_crate_files.clone();
} }
pub fn add_used_library(cstore: &mut CStore, lib: @str) -> bool { pub fn get_used_crates(cstore: &CStore, prefer: LinkagePreference)
-> ~[(ast::CrateNum, Option<Path>)]
{
let mut ret = ~[];
for src in cstore.used_crate_sources.iter() {
ret.push((src.cnum, match prefer {
RequireDynamic => src.dylib.clone(),
RequireStatic => src.rlib.clone(),
}));
}
return ret;
}
pub fn add_used_library(cstore: &mut CStore,
lib: ~str, kind: NativeLibaryKind) -> bool {
assert!(!lib.is_empty()); assert!(!lib.is_empty());
if cstore.used_libraries.iter().any(|x| x == &lib) { return false; } if cstore.used_libraries.iter().any(|&(ref x, _)| x == &lib) { return false; }
cstore.used_libraries.push(lib); cstore.used_libraries.push((lib, kind));
true true
} }
pub fn get_used_libraries<'a>(cstore: &'a CStore) -> &'a [@str] { pub fn get_used_libraries<'a>(cstore: &'a CStore) -> &'a [(~str, NativeLibaryKind)] {
let slice: &'a [@str] = cstore.used_libraries; cstore.used_libraries.as_slice()
slice
} }
pub fn add_used_link_args(cstore: &mut CStore, args: &str) { pub fn add_used_link_args(cstore: &mut CStore, args: &str) {
for s in args.split(' ') { 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] { pub fn get_used_link_args<'a>(cstore: &'a CStore) -> &'a [~str] {
let slice: &'a [@str] = cstore.used_link_args; cstore.used_link_args.as_slice()
slice
} }
pub fn add_extern_mod_stmt_cnum(cstore: &mut CStore, pub fn add_extern_mod_stmt_cnum(cstore: &mut CStore,

View file

@ -1529,3 +1529,13 @@ pub fn get_trait_of_method(cdata: Cmd, id: ast::NodeId, tcx: ty::ctxt)
} }
} }
pub fn get_native_libraries(cdata: Cmd) -> ~[~str] {
let libraries = reader::get_doc(reader::Doc(cdata.data), tag_native_libraries);
let mut result = ~[];
do reader::tagged_docs(libraries, tag_native_libraries_lib) |lib_doc| {
result.push(lib_doc.as_str());
true
};
return result;
}

View file

@ -75,6 +75,7 @@ struct Stats {
attr_bytes: u64, attr_bytes: u64,
dep_bytes: u64, dep_bytes: u64,
lang_item_bytes: u64, lang_item_bytes: u64,
native_lib_bytes: u64,
impl_bytes: u64, impl_bytes: u64,
misc_bytes: u64, misc_bytes: u64,
item_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 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> { struct ImplVisitor<'self> {
ecx: &'self EncodeContext<'self>, ecx: &'self EncodeContext<'self>,
ebml_w: &'self mut writer::Encoder, ebml_w: &'self mut writer::Encoder,
@ -1750,6 +1768,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
attr_bytes: 0, attr_bytes: 0,
dep_bytes: 0, dep_bytes: 0,
lang_item_bytes: 0, lang_item_bytes: 0,
native_lib_bytes: 0,
impl_bytes: 0, impl_bytes: 0,
misc_bytes: 0, misc_bytes: 0,
item_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); encode_lang_items(&ecx, &mut ebml_w);
ecx.stats.lang_item_bytes = wr.tell() - i; 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. // Encode the def IDs of impls, for coherence checking.
i = wr.tell(); i = wr.tell();
encode_impls(&ecx, crate, &mut ebml_w); 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!(" attribute bytes: {}", ecx.stats.attr_bytes);
println!(" dep bytes: {}", ecx.stats.dep_bytes); println!(" dep bytes: {}", ecx.stats.dep_bytes);
println!(" lang item bytes: {}", ecx.stats.lang_item_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!(" impl bytes: {}", ecx.stats.impl_bytes);
println!(" misc bytes: {}", ecx.stats.misc_bytes); println!(" misc bytes: {}", ecx.stats.misc_bytes);
println!(" item bytes: {}", ecx.stats.item_bytes); println!(" item bytes: {}", ecx.stats.item_bytes);

View file

@ -10,11 +10,12 @@
//! Finds crate binaries and loads their metadata //! Finds crate binaries and loads their metadata
use back::archive::Archive;
use lib::llvm::{False, llvm, mk_object_file, mk_section_iter}; use driver::session::Session;
use lib::llvm::{False, llvm, ObjectFile, mk_section_iter};
use metadata::decoder; use metadata::decoder;
use metadata::encoder; use metadata::encoder;
use metadata::filesearch::{FileSearch, FileMatch, FileMatches, FileDoesntMatch}; use metadata::filesearch::{FileMatches, FileDoesntMatch};
use metadata::filesearch; use metadata::filesearch;
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::diagnostic::span_handler; use syntax::diagnostic::span_handler;
@ -26,6 +27,7 @@
use std::c_str::ToCStr; use std::c_str::ToCStr;
use std::cast; use std::cast;
use std::io; use std::io;
use std::libc;
use std::num; use std::num;
use std::option; use std::option;
use std::os::consts::{macos, freebsd, linux, android, win32}; use std::os::consts::{macos, freebsd, linux, android, win32};
@ -43,103 +45,176 @@ pub enum Os {
} }
pub struct Context { pub struct Context {
diag: @mut span_handler, sess: Session,
filesearch: @FileSearch,
span: Span, span: Span,
ident: @str, ident: @str,
metas: ~[@ast::MetaItem], metas: ~[@ast::MetaItem],
hash: @str, hash: @str,
os: Os, os: Os,
is_static: bool,
intr: @ident_interner intr: @ident_interner
} }
pub fn load_library_crate(cx: &Context) -> (~str, @~[u8]) { pub struct Library {
match find_library_crate(cx) { dylib: Option<Path>,
Some(t) => t, rlib: Option<Path>,
None => { metadata: @~[u8],
cx.diag.span_fatal(cx.span, }
format!("can't find crate for `{}`",
cx.ident)); 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])> { fn find_library_crate(&self) -> Option<Library> {
attr::require_unique_names(cx.diag, cx.metas); attr::require_unique_names(self.sess.diagnostic(), self.metas);
find_library_crate_aux(cx, libname(cx), cx.filesearch) 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) { // want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
if cx.is_static { return (~"lib", ~".rlib"); } let dylib_prefix = format!("{}{}-", dyprefix, crate_name);
let (dll_prefix, dll_suffix) = match cx.os { let rlib_prefix = format!("lib{}-", crate_name);
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),
};
(dll_prefix.to_owned(), dll_suffix.to_owned()) let mut matches = ~[];
} do filesearch::search(filesearch) |path| {
match path.filename_str() {
None => FileDoesntMatch,
Some(file) => {
let (candidate, existing) = if file.starts_with(rlib_prefix) &&
file.ends_with(".rlib") {
debug!("{} is an rlib candidate", path.display());
(true, self.add_existing_rlib(matches, path, file))
} else if file.starts_with(dylib_prefix) &&
file.ends_with(dysuffix) {
debug!("{} is a dylib candidate", path.display());
(true, self.add_existing_dylib(matches, path, file))
} else {
(false, false)
};
fn find_library_crate_aux( if candidate && existing {
cx: &Context, FileMatches
(prefix, suffix): (~str, ~str), } else if candidate {
filesearch: @filesearch::FileSearch match get_metadata_section(self.sess, self.os, path,
) -> Option<(~str, @~[u8])> { crate_name) {
let crate_name = crate_name_from_metas(cx.metas); Some(cvec) =>
// want: crate_name.dir_part() + prefix + crate_name.file_part + "-" if crate_matches(cvec, self.metas, self.hash) {
let prefix = format!("{}{}-", prefix, crate_name); debug!("found {} with matching metadata",
let mut matches = ~[]; path.display());
filesearch::search(filesearch, |path| -> FileMatch { let (rlib, dylib) = if file.ends_with(".rlib") {
// FIXME (#9639): This needs to handle non-utf8 paths (Some(path.clone()), None)
let path_str = path.filename_str(); } else {
match path_str { (None, Some(path.clone()))
None => FileDoesntMatch, };
Some(path_str) => matches.push(Library {
if path_str.starts_with(prefix) && path_str.ends_with(suffix) { rlib: rlib,
debug!("{} is a candidate", path.display()); dylib: dylib,
match get_metadata_section(cx.os, path) { metadata: cvec,
Some(cvec) => });
if !crate_matches(cvec, cx.metas, cx.hash) { FileMatches
debug!("skipping {}, metadata doesn't match", } else {
path.display()); debug!("skipping {}, metadata doesn't match",
FileDoesntMatch path.display());
} else { FileDoesntMatch
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)); debug!("could not load metadata for {}",
FileMatches path.display());
}, FileDoesntMatch
_ => { }
debug!("could not load metadata for {}", path.display()); }
FileDoesntMatch } else {
} 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);
} }
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 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)) local_metas.iter().all(|needed| attr::contains(extern_metas, *needed))
} }
fn get_metadata_section(os: Os, fn get_metadata_section(sess: Session, os: Os, filename: &Path,
filename: &Path) -> Option<@~[u8]> { crate_name: &str) -> Option<@~[u8]> {
unsafe { unsafe {
let mb = filename.with_c_str(|buf| { let mb = if filename.filename_str().unwrap().ends_with(".rlib") {
llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf) let archive = Archive::open(sess, filename.clone());
}); let contents = archive.read(crate_name + ".o");
if mb as int == 0 { return option::None::<@~[u8]>; } let ptr = vec::raw::to_ptr(contents);
let of = match mk_object_file(mb) { crate_name.with_c_str(|name| {
option::Some(of) => of, llvm::LLVMCreateMemoryBufferWithMemoryRangeCopy(
_ => return option::None::<@~[u8]> 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); let si = mk_section_iter(of.llof);
while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { 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 // 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, os: Os,
path: &Path, path: &Path,
out: @mut io::Writer) { out: @mut io::Writer) {
match get_metadata_section(os, path) { // guess the crate name from the pathname
let crate_name = path.filename_str().unwrap();
let crate_name = if crate_name.starts_with("lib") {
crate_name.slice_from(3) } else { crate_name };
let crate_name = crate_name.split_iter('-').next().unwrap();
match get_metadata_section(sess, os, path, crate_name) {
option::Some(bytes) => decoder::list_crate_metadata(intr, bytes, out), option::Some(bytes) => decoder::list_crate_metadata(intr, bytes, out),
option::None => { option::None => {
write!(out, "could not find metadata in {}.\n", path.display()) write!(out, "could not find metadata in {}.\n", path.display())

View file

@ -79,12 +79,12 @@
use syntax::ast_map::{path, path_elt_to_str, path_name, path_pretty_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};
use syntax::attr; use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::parse::token; use syntax::parse::token;
use syntax::parse::token::{special_idents}; use syntax::parse::token::{special_idents};
use syntax::print::pprust::stmt_to_str; use syntax::print::pprust::stmt_to_str;
use syntax::{ast, ast_util, codemap, ast_map}; 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::abi::{X86, X86_64, Arm, Mips, Rust, RustIntrinsic, OsWin32, OsAndroid};
use syntax::visit; use syntax::visit;
use syntax::visit::Visitor; use syntax::visit::Visitor;
@ -3106,18 +3106,6 @@ pub fn write_metadata(cx: &CrateContext, crate: &ast::Crate) {
} }
} }
// Writes the current ABI version into the crate.
pub fn write_abi_version(ccx: &mut CrateContext) {
unsafe {
let llval = C_uint(ccx, abi::abi_version);
let llglobal = "rust_abi_version".with_c_str(|buf| {
llvm::LLVMAddGlobal(ccx.llmod, val_ty(llval).to_ref(), buf)
});
llvm::LLVMSetInitializer(llglobal, llval);
llvm::LLVMSetGlobalConstant(llglobal, True);
}
}
pub fn trans_crate(sess: session::Session, pub fn trans_crate(sess: session::Session,
crate: ast::Crate, crate: ast::Crate,
analysis: &CrateAnalysis, analysis: &CrateAnalysis,
@ -3177,7 +3165,6 @@ pub fn trans_crate(sess: session::Session,
} }
glue::emit_tydescs(ccx); glue::emit_tydescs(ccx);
write_abi_version(ccx);
if ccx.sess.opts.debuginfo { if ccx.sess.opts.debuginfo {
debuginfo::finalize(ccx); debuginfo::finalize(ccx);
} }
@ -3217,10 +3204,18 @@ pub fn trans_crate(sess: session::Session,
let llcx = ccx.llcx; let llcx = ccx.llcx;
let link_meta = ccx.link_meta; let link_meta = ccx.link_meta;
let llmod = ccx.llmod; 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 { return CrateTranslation {
context: llcx, context: llcx,
module: llmod, module: llmod,
link: link_meta link: link_meta,
crate_types: crate_types,
}; };
} }

View file

@ -67,7 +67,7 @@ struct buf {
} }
// sundown FFI // sundown FFI
#[link_args = "-lsundown"] #[link(name = "sundown", kind = "static")]
extern { extern {
fn sdhtml_renderer(callbacks: *sd_callbacks, fn sdhtml_renderer(callbacks: *sd_callbacks,
options_ptr: *html_renderopt, options_ptr: *html_renderopt,

View file

@ -16,7 +16,8 @@
#[desc = "rustdoc, the Rust documentation extractor"]; #[desc = "rustdoc, the Rust documentation extractor"];
#[license = "MIT/ASL2"]; #[license = "MIT/ASL2"];
#[crate_type = "lib"]; #[crate_type = "lib"]; // NOTE: remove after stage0 snapshot
#[crate_type = "dylib"];
#[feature(globs, struct_variant, managed_boxes)]; #[feature(globs, struct_variant, managed_boxes)];

View file

@ -17,7 +17,8 @@
url = "https://github.com/mozilla/rust/tree/master/src/librustpkg")]; url = "https://github.com/mozilla/rust/tree/master/src/librustpkg")];
#[license = "MIT/ASL2"]; #[license = "MIT/ASL2"];
#[crate_type = "lib"]; #[crate_type = "lib"]; // NOTE: remove after stage0 snapshot
#[crate_type = "dylib"];
#[feature(globs, managed_boxes)]; #[feature(globs, managed_boxes)];
@ -114,7 +115,7 @@ fn parse<'a>(sysroot: Path,
let options = @session::options { let options = @session::options {
binary: binary, binary: binary,
maybe_sysroot: Some(@sysroot), maybe_sysroot: Some(@sysroot),
crate_type: session::bin_crate, outputs: ~[session::OutputExecutable],
.. (*session::basic_options()).clone() .. (*session::basic_options()).clone()
}; };
let input = driver::file_input(script.clone()); let input = driver::file_input(script.clone());

View file

@ -36,6 +36,7 @@
chmod_read_only, platform_library_name}; chmod_read_only, platform_library_name};
use rustc::back::link::get_cc_prog; use rustc::back::link::get_cc_prog;
use rustc::metadata::filesearch::rust_path; use rustc::metadata::filesearch::rust_path;
use rustc::driver::session;
use rustc::driver::driver::{build_session, build_session_options, host_triple, optgroups}; use rustc::driver::driver::{build_session, build_session_options, host_triple, optgroups};
use syntax::diagnostic; use syntax::diagnostic;
use target::*; use target::*;
@ -1829,10 +1830,11 @@ fn test_linker_build() {
@diagnostic::Emitter); @diagnostic::Emitter);
let test_sys = test_sysroot(); let test_sys = test_sysroot();
// FIXME (#9639): This needs to handle non-utf8 paths // 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(), command_line_test([test_sys.as_str().unwrap().to_owned(),
~"install", ~"install",
~"--linker", ~"--linker",
get_cc_prog(sess), cc,
~"foo"], ~"foo"],
workspace); workspace);
assert_executable_exists(workspace, "foo"); assert_executable_exists(workspace, "foo");

View file

@ -25,7 +25,6 @@
use syntax::util::small_vector::SmallVector; use syntax::util::small_vector::SmallVector;
use rustc::back::link::output_type_exe; use rustc::back::link::output_type_exe;
use rustc::back::link; use rustc::back::link;
use rustc::driver::session::{lib_crate, bin_crate};
use context::{in_target, StopBefore, Link, Assemble, BuildContext}; use context::{in_target, StopBefore, Link, Assemble, BuildContext};
use package_id::PkgId; use package_id::PkgId;
use package_source::PkgSrc; use package_source::PkgSrc;
@ -195,8 +194,8 @@ pub fn compile_input(context: &BuildContext,
debug!("compile_input's sysroot = {}", csysroot.display()); debug!("compile_input's sysroot = {}", csysroot.display());
let crate_type = match what { let crate_type = match what {
Lib => lib_crate, Lib => session::OutputDylib,
Test | Bench | Main => bin_crate Test | Bench | Main => session::OutputExecutable,
}; };
let matches = getopts(debug_flags() let matches = getopts(debug_flags()
+ match what { + match what {
@ -239,7 +238,7 @@ pub fn compile_input(context: &BuildContext,
debug!("Output type = {:?}", output_type); debug!("Output type = {:?}", output_type);
let options = @session::options { let options = @session::options {
crate_type: crate_type, outputs: ~[crate_type],
optimize: opt, optimize: opt,
test: what == Test || what == Bench, test: what == Test || what == Bench,
maybe_sysroot: Some(sysroot_to_use), maybe_sysroot: Some(sysroot_to_use),

View file

@ -41,7 +41,9 @@
url = "https://github.com/mozilla/rust/tree/master/src/librustuv")]; url = "https://github.com/mozilla/rust/tree/master/src/librustuv")];
#[license = "MIT/ASL2"]; #[license = "MIT/ASL2"];
#[crate_type = "lib"]; #[crate_type = "lib"]; // NOTE: remove after stage0 snapshot
#[crate_type = "rlib"];
#[crate_type = "dylib"];
#[feature(macro_rules, globs)]; #[feature(macro_rules, globs)];

View file

@ -524,8 +524,13 @@ pub unsafe fn guess_handle(handle: c_int) -> c_int {
// second copies of everything. We obviously don't want this, so instead of // 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 // dying horribly during testing, we allow all of the test rustuv's references
// to get resolved to the original rustuv crate. // to get resolved to the original rustuv crate.
#[link_args = "-luv_support -luv"] #[cfg(not(test), not(stage0))]
#[cfg(not(test))] #[link(name = "uv_support", kind = "static")]
#[link(name = "uv", kind = "static")]
extern {}
#[cfg(not(test), stage0)]
#[link_args = "-luv -luv_support"]
extern {} extern {}
extern { extern {
@ -717,12 +722,26 @@ pub fn uv_signal_start(h: *uv_signal_t, cb: uv_signal_cb,
pub fn uv_signal_stop(handle: *uv_signal_t) -> c_int; pub fn uv_signal_stop(handle: *uv_signal_t) -> c_int;
} }
// libuv requires various system libraries to successfully link on some // various platform libraries required by libuv
// platforms #[cfg(not(stage0))]
#[cfg(target_os = "linux")] #[link(name = "pthread")]
extern {}
#[cfg(stage0)]
#[link_args = "-lpthread"] #[link_args = "-lpthread"]
extern {} 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"] #[link_args = "-lws2_32 -lpsapi -liphlpapi"]
extern {} extern {}
#[cfg(target_os = "freebsd", not(stage0))]
#[link(name = "kvm")]
extern {}
#[cfg(target_os = "freebsd", stage0)]
#[link_args = "-lkvm"]
extern {}

View file

@ -51,7 +51,9 @@
#[comment = "The Rust standard library"]; #[comment = "The Rust standard library"];
#[license = "MIT/ASL2"]; #[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", #[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", html_favicon_url = "http://www.rust-lang.org/favicon.ico",
@ -79,15 +81,7 @@
#[cfg(test)] pub use ops = realstd::ops; #[cfg(test)] pub use ops = realstd::ops;
#[cfg(test)] pub use cmp = realstd::cmp; #[cfg(test)] pub use cmp = realstd::cmp;
// On Linux, link to the runtime with -lrt. mod rtdeps;
#[cfg(target_os = "linux")]
#[doc(hidden)]
pub mod linkhack {
#[link_args="-lrustrt -lrt"]
#[link_args = "-lpthread"]
extern {
}
}
/* The Prelude. */ /* The Prelude. */

48
src/libstd/rtdeps.rs Normal file
View file

@ -0,0 +1,48 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! This module contains the linkage attributes to all runtime dependencies of
//! the stndard library This varies per-platform, but these libraries are
//! necessary for running libstd.
// All platforms need to link to rustrt
#[link(name = "rustrt")]
extern {}
// LLVM implements the `frem` instruction as a call to `fmod`, which lives in
// libm. Hence, we must explicitly link to it.
//
// On linux librt and libdl are indirect dependencies via rustrt,
// and binutils 2.22+ won't add them automatically
#[cfg(target_os = "linux")]
#[link(name = "rt")]
#[link(name = "dl")]
#[link(name = "m")]
#[link(name = "pthread")]
extern {}
#[cfg(target_os = "android")]
#[link(name = "dl")]
#[link(name = "log")]
#[link(name = "supc++")]
#[link(name = "gnustl_shared")]
#[link(name = "m")]
extern {}
#[cfg(target_os = "freebsd")]
#[link(name = "execinfo")]
#[link(name = "rt")]
#[link(name = "stdc++")]
#[link(name = "pthread")]
extern {}
#[cfg(target_os = "macos")]
#[link(name = "pthread")]
extern {}

View file

@ -19,7 +19,8 @@
uuid = "9311401b-d6ea-4cd9-a1d9-61f89499c645")]; uuid = "9311401b-d6ea-4cd9-a1d9-61f89499c645")];
#[license = "MIT/ASL2"]; #[license = "MIT/ASL2"];
#[crate_type = "lib"]; #[crate_type = "lib"]; // NOTE: remove after stage0 snapshot
#[crate_type = "dylib"];
#[feature(macro_rules, globs, managed_boxes)]; #[feature(macro_rules, globs, managed_boxes)];

View file

@ -630,3 +630,5 @@ LLVMAddReturnAttribute
LLVMRemoveReturnAttribute LLVMRemoveReturnAttribute
LLVMTypeToString LLVMTypeToString
LLVMAddColdAttribute LLVMAddColdAttribute
LLVMCreateMemoryBufferWithMemoryRange
LLVMCreateMemoryBufferWithMemoryRangeCopy