about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-11-04 11:11:20 +0000
committerbors <bors@rust-lang.org>2014-11-04 11:11:20 +0000
commit3a8f4ec32a80d372db2d02c76acba0276c4effd0 (patch)
tree4b61274b97d2d2fc0c7283d84b67e58f730b3b4c
parent82fb413d370f1f1094964ed07b65f97dba52cc30 (diff)
parent61aeab4c9ece6b40e3941665bc9e695922e2ad25 (diff)
downloadrust-3a8f4ec32a80d372db2d02c76acba0276c4effd0.tar.gz
rust-3a8f4ec32a80d372db2d02c76acba0276c4effd0.zip
auto merge of #16156 : cmr/rust/target-spec, r=alexcrichton
See commit message.
-rwxr-xr-xconfigure57
-rw-r--r--mk/cfg/arm-apple-ios3
-rw-r--r--mk/cfg/arm-linux-androideabi1
-rw-r--r--mk/cfg/arm-unknown-linux-gnueabi1
-rw-r--r--mk/cfg/arm-unknown-linux-gnueabihf1
-rw-r--r--mk/cfg/i386-apple-ios1
-rw-r--r--mk/cfg/i586-mingw32msvc29
-rw-r--r--mk/cfg/i686-apple-darwin2
-rw-r--r--mk/cfg/i686-pc-windows-gnu28
-rw-r--r--mk/cfg/i686-unknown-linux-gnu2
-rw-r--r--mk/cfg/i686-w64-mingw3231
-rw-r--r--mk/cfg/mips-unknown-linux-gnu1
-rw-r--r--mk/cfg/mipsel-linux27
-rw-r--r--mk/cfg/mipsel-unknown-linux-gnu28
-rw-r--r--mk/cfg/x86_64-apple-darwin1
-rw-r--r--mk/cfg/x86_64-pc-windows-gnu28
-rw-r--r--mk/cfg/x86_64-unknown-dragonfly1
-rw-r--r--mk/cfg/x86_64-unknown-freebsd1
-rw-r--r--mk/cfg/x86_64-unknown-linux-gnu2
-rw-r--r--mk/cfg/x86_64-w64-mingw3228
-rw-r--r--mk/main.mk1
-rw-r--r--mk/rt.mk2
-rw-r--r--src/etc/snapshot.py5
-rw-r--r--src/librustc/back/link.rs290
-rw-r--r--src/librustc/back/write.rs55
-rw-r--r--src/librustc/driver/config.rs157
-rw-r--r--src/librustc/driver/driver.rs4
-rw-r--r--src/librustc/driver/mod.rs2
-rw-r--r--src/librustc/driver/session.rs6
-rw-r--r--src/librustc/lint/builtin.rs8
-rw-r--r--src/librustc/metadata/creader.rs16
-rw-r--r--src/librustc/metadata/encoder.rs3
-rw-r--r--src/librustc/metadata/loader.rs100
-rw-r--r--src/librustc/middle/dependency_format.rs6
-rw-r--r--src/librustc/middle/trans/adt.rs9
-rw-r--r--src/librustc/middle/trans/base.rs41
-rw-r--r--src/librustc/middle/trans/cabi.rs24
-rw-r--r--src/librustc/middle/trans/cabi_x86.rs23
-rw-r--r--src/librustc/middle/trans/context.rs25
-rw-r--r--src/librustc/middle/trans/debuginfo.rs5
-rw-r--r--src/librustc/middle/trans/foreign.rs96
-rw-r--r--src/librustc/middle/trans/type_.rs8
-rw-r--r--src/librustc/middle/typeck/check/mod.rs4
-rw-r--r--src/librustc_back/archive.rs26
-rw-r--r--src/librustc_back/lib.rs1
-rw-r--r--src/librustc_back/rpath.rs41
-rw-r--r--src/librustc_back/target/apple_base.rs29
-rw-r--r--src/librustc_back/target/arm_apple_ios.rs37
-rw-r--r--src/librustc_back/target/arm_linux_androideabi.rs35
-rw-r--r--src/librustc_back/target/arm_unknown_linux_gnueabi.rs32
-rw-r--r--src/librustc_back/target/arm_unknown_linux_gnueabihf.rs32
-rw-r--r--src/librustc_back/target/dragonfly_base.rs30
-rw-r--r--src/librustc_back/target/freebsd_base.rs30
-rw-r--r--src/librustc_back/target/i386_apple_ios.rs28
-rw-r--r--src/librustc_back/target/i686_apple_darwin.rs30
-rw-r--r--src/librustc_back/target/i686_pc_windows_gnu.rs34
-rw-r--r--src/librustc_back/target/i686_unknown_dragonfly.rs26
-rw-r--r--src/librustc_back/target/i686_unknown_linux_gnu.rs26
-rw-r--r--src/librustc_back/target/linux_base.rs31
-rw-r--r--src/librustc_back/target/mips_unknown_linux_gnu.rs27
-rw-r--r--src/librustc_back/target/mipsel_unknown_linux_gnu.rs28
-rw-r--r--src/librustc_back/target/mod.rs379
-rw-r--r--src/librustc_back/target/windows_base.rs66
-rw-r--r--src/librustc_back/target/x86_64_apple_darwin.rs29
-rw-r--r--src/librustc_back/target/x86_64_pc_windows_gnu.rs31
-rw-r--r--src/librustc_back/target/x86_64_unknown_dragonfly.rs23
-rw-r--r--src/librustc_back/target/x86_64_unknown_freebsd.rs28
-rw-r--r--src/librustc_back/target/x86_64_unknown_linux_gnu.rs28
-rw-r--r--src/librustdoc/test.rs2
-rw-r--r--src/libsyntax/abi.rs74
-rw-r--r--src/test/run-make/rustdoc-hidden-line/Makefile1
-rw-r--r--src/test/run-make/target-specs/Makefile11
-rw-r--r--src/test/run-make/target-specs/foo.rs26
-rw-r--r--src/test/run-make/target-specs/my-awesome-platform.json9
-rw-r--r--src/test/run-make/target-specs/my-incomplete-platform.json8
-rw-r--r--src/test/run-make/target-specs/my-invalid-platform.json1
-rw-r--r--src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json9
77 files changed, 1610 insertions, 801 deletions
diff --git a/configure b/configure
index 59e51356c6c..9eccc2f6e40 100755
--- a/configure
+++ b/configure
@@ -291,6 +291,22 @@ envopt() {
     fi
 }
 
+to_llvm_triple() {
+    case $1 in
+        i686-w64-mingw32) echo i686-pc-windows-gnu ;;
+        x86_64-w64-mingw32) echo x86_64-pc-windows-gnu ;;
+        *) echo $1 ;;
+    esac
+}
+
+to_gnu_triple() {
+    case $1 in
+        i686-pc-windows-gnu) echo i686-w64-mingw32 ;;
+        x86_64-pc-windows-gnu) echo x86_64-w64-mingw32 ;;
+        *) echo $1 ;;
+    esac
+}
+
 msg "looking for configure programs"
 need_cmd cmp
 need_cmd mkdir
@@ -350,37 +366,40 @@ case $CFG_OSTYPE in
         # instead, msys defines $MSYSTEM which is MINGW32 on i686 and
         # MINGW64 on x86_64.
         CFG_CPUTYPE=i686
-        CFG_OSTYPE=w64-mingw32
+        CFG_OSTYPE=pc-windows-gnu
         if [ "$MSYSTEM" = MINGW64 ]
         then
             CFG_CPUTYPE=x86_64
-            CFG_OSTYPE=w64-mingw32
         fi
         ;;
 
+    MSYS*)
+        CFG_OSTYPE=pc-windows-gnu
+        ;;
+
 # Thad's Cygwin identifers below
 
 #   Vista 32 bit
     CYGWIN_NT-6.0)
-        CFG_OSTYPE=pc-mingw32
+        CFG_OSTYPE=pc-windows-gnu
         CFG_CPUTYPE=i686
         ;;
 
 #   Vista 64 bit
     CYGWIN_NT-6.0-WOW64)
-        CFG_OSTYPE=w64-mingw32
+        CFG_OSTYPE=pc-windows-gnu
         CFG_CPUTYPE=x86_64
         ;;
 
 #   Win 7 32 bit
     CYGWIN_NT-6.1)
-        CFG_OSTYPE=pc-mingw32
+        CFG_OSTYPE=pc-windows-gnu
         CFG_CPUTYPE=i686
         ;;
 
 #   Win 7 64 bit
     CYGWIN_NT-6.1-WOW64)
-        CFG_OSTYPE=w64-mingw32
+        CFG_OSTYPE=pc-windows-gnu
         CFG_CPUTYPE=x86_64
         ;;
 
@@ -466,7 +485,6 @@ opt llvm-assertions 1 "build LLVM with assertions"
 opt debug 1 "build with extra debug fun"
 opt ratchet-bench 0 "ratchet benchmarks"
 opt fast-make 0 "use .gitmodules as timestamp for submodule deps"
-opt mingw-cross 0 "cross-compile for win32 using mingw"
 opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds"
 opt local-rust 0 "use an installed rustc rather than downloading a snapshot"
 opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM"
@@ -487,7 +505,6 @@ valopt llvm-root "" "set LLVM root"
 valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
 valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
 valopt android-cross-path "/opt/ndk_standalone" "Android NDK standalone path"
-valopt mingw32-cross-path "" "MinGW32 cross compiler path"
 
 # Many of these are saved below during the "writing configuration" step
 # (others are conditionally saved).
@@ -501,12 +518,18 @@ valopt_nosave target "${CFG_HOST}" "GNUs ./configure syntax LLVM target triples"
 valopt_nosave mandir "${CFG_PREFIX}/share/man" "install man pages in PATH"
 valopt_nosave release-channel "dev" "the name of the release channel to build"
 
+# Temporarily support old triples until buildbots get updated
+CFG_BUILD=$(to_llvm_triple $CFG_BUILD)
+putvar CFG_BUILD # Yes, this creates a duplicate entry, but the last one wins.
+CFG_HOST=$(to_llvm_triple $CFG_HOST)
+CFG_TARGET=$(to_llvm_triple $CFG_TARGET)
+
 # On windows we just store the libraries in the bin directory because
 # there's no rpath. This is where the build system itself puts libraries;
 # --libdir is used to configure the installation directory.
 # FIXME: This needs to parameterized over target triples. Do it in platform.mk
 CFG_LIBDIR_RELATIVE=lib
-if [ "$CFG_OSTYPE" = "pc-mingw32" ] || [ "$CFG_OSTYPE" = "w64-mingw32" ]
+if [ "$CFG_OSTYPE" = "pc-windows-gnu" ]
 then
     CFG_LIBDIR_RELATIVE=bin
 fi
@@ -632,7 +655,7 @@ then
 fi
 
 BIN_SUF=
-if [ "$CFG_OSTYPE" = "pc-mingw32" ] || [ "$CFG_OSTYPE" = "w64-mingw32" ]
+if [ "$CFG_OSTYPE" = "pc-windows-gnu" ]
 then
     BIN_SUF=.exe
 fi
@@ -1100,12 +1123,15 @@ do
 
     if [ ${do_reconfigure} -ne 0 ]
     then
-        msg "configuring LLVM for $t"
+        # LLVM's configure doesn't recognize the new Windows triples yet
+        gnu_t=$(to_gnu_triple $t)
+
+        msg "configuring LLVM for $gnu_t"
 
         LLVM_TARGETS="--enable-targets=x86,x86_64,arm,mips"
-        LLVM_BUILD="--build=$t"
-        LLVM_HOST="--host=$t"
-        LLVM_TARGET="--target=$t"
+        LLVM_BUILD="--build=$gnu_t"
+        LLVM_HOST="--host=$gnu_t"
+        LLVM_TARGET="--target=$gnu_t"
 
         # Disable unused LLVM features
         LLVM_OPTS="$LLVM_DBG_OPTS $LLVM_ASSERTION_OPTS --disable-docs --enable-bindings=none"
@@ -1119,7 +1145,7 @@ do
         # (llvm's configure tries to find pthread first, so we have to disable it explicitly.)
         # Also note that pthreads works badly on mingw-w64 systems: #8996
         case "$CFG_BUILD" in
-            (*-mingw32)
+            (*-windows-*)
             LLVM_OPTS="$LLVM_OPTS --disable-pthreads"
             ;;
         esac
@@ -1269,6 +1295,7 @@ putvar CFG_HOST
 putvar CFG_TARGET
 putvar CFG_LIBDIR_RELATIVE
 putvar CFG_DISABLE_MANAGE_SUBMODULES
+putvar CFG_ANDROID_CROSS_PATH
 putvar CFG_MANDIR
 
 # Avoid spurious warnings from clang by feeding it original source on
diff --git a/mk/cfg/arm-apple-ios b/mk/cfg/arm-apple-ios
index b2ce37ad460..6a66ff46a36 100644
--- a/mk/cfg/arm-apple-ios
+++ b/mk/cfg/arm-apple-ios
@@ -3,7 +3,7 @@ CFG_SDK_NAME_arm-apple-ios = iphoneos
 CFG_SDK_ARCHS_arm-apple-ios = armv7
 ifneq ($(findstring darwin,$(CFG_OSTYPE)),)
 CFG_IOS_SDK = $(shell xcrun --show-sdk-path -sdk iphoneos 2>/dev/null)
-CFG_IOS_FLAGS = -target armv7-apple-darwin -isysroot $(CFG_IOS_SDK) -mios-version-min=7.0
+CFG_IOS_FLAGS = -target armv7-apple-ios -isysroot $(CFG_IOS_SDK) -mios-version-min=7.0
 CC_arm-apple-ios = $(shell xcrun -find -sdk iphoneos clang)
 CXX_arm-apple-ios = $(shell xcrun -find -sdk iphoneos clang++)
 CPP_arm-apple-ios = $(shell xcrun -find -sdk iphoneos clang++)
@@ -32,3 +32,4 @@ CFG_RUN_arm-apple-ios = $(2)
 CFG_RUN_TARG_arm-apple-ios = $(call CFG_RUN_arm-apple-ios,,$(2))
 RUSTC_FLAGS_arm-apple-ios := -C relocation_model=pic
 RUSTC_CROSS_FLAGS_arm-apple-ios :=-C relocation_model=pic
+CFG_GNU_TRIPLE_arm-apple-ios := arm-apple-ios
diff --git a/mk/cfg/arm-linux-androideabi b/mk/cfg/arm-linux-androideabi
index bf7ec39b654..e24a805b416 100644
--- a/mk/cfg/arm-linux-androideabi
+++ b/mk/cfg/arm-linux-androideabi
@@ -26,3 +26,4 @@ CFG_RUN_arm-linux-androideabi=
 CFG_RUN_TARG_arm-linux-androideabi=
 RUSTC_FLAGS_arm-linux-androideabi :=
 RUSTC_CROSS_FLAGS_arm-linux-androideabi :=
+CFG_GNU_TRIPLE_arm-linux-androideabi := arm-linux-androideabi
diff --git a/mk/cfg/arm-unknown-linux-gnueabi b/mk/cfg/arm-unknown-linux-gnueabi
index e76ce27ac96..4b7b9ad87ca 100644
--- a/mk/cfg/arm-unknown-linux-gnueabi
+++ b/mk/cfg/arm-unknown-linux-gnueabi
@@ -27,3 +27,4 @@ CFG_RUN_arm-unknown-linux-gnueabi=$(2)
 CFG_RUN_TARG_arm-unknown-linux-gnueabi=$(call CFG_RUN_arm-unknown-linux-gnueabi,,$(2))
 RUSTC_FLAGS_arm-unknown-linux-gnueabi :=
 RUSTC_CROSS_FLAGS_arm-unknown-linux-gnueabi :=
+CFG_GNU_TRIPLE_arm-unknown-linux-gnueabi := arm-unknown-linux-gnueabi
diff --git a/mk/cfg/arm-unknown-linux-gnueabihf b/mk/cfg/arm-unknown-linux-gnueabihf
index 22bfc2574ca..535dce6b9f3 100644
--- a/mk/cfg/arm-unknown-linux-gnueabihf
+++ b/mk/cfg/arm-unknown-linux-gnueabihf
@@ -27,3 +27,4 @@ CFG_RUN_arm-unknown-linux-gnueabihf=$(2)
 CFG_RUN_TARG_arm-unknown-linux-gnueabihf=$(call CFG_RUN_arm-unknown-linux-gnueabihf,,$(2))
 RUSTC_FLAGS_arm-unknown-linux-gnueabihf := -C target-feature=+v6,+vfp2
 RUSTC_CROSS_FLAGS_arm-unknown-linux-gnueabihf :=
+CFG_GNU_TRIPLE_arm-unknown-linux-gnueabihf := arm-unknown-linux-gnueabihf
diff --git a/mk/cfg/i386-apple-ios b/mk/cfg/i386-apple-ios
index c71d664db34..0e0d2724ddb 100644
--- a/mk/cfg/i386-apple-ios
+++ b/mk/cfg/i386-apple-ios
@@ -31,3 +31,4 @@ CFG_LDPATH_i386-apple-ios =
 CFG_RUN_i386-apple-ios = $(2)
 CFG_RUN_TARG_i386-apple-ios = $(call CFG_RUN_i386-apple-ios,,$(2))
 CFG_JEMALLOC_CFLAGS_i386-apple-ios = -target i386-apple-ios -Wl,-syslibroot $(CFG_IOSSIM_SDK) -Wl,-no_compact_unwind
+CFG_GNU_TRIPLE_i386-apple-ios := i386-apple-ios
diff --git a/mk/cfg/i586-mingw32msvc b/mk/cfg/i586-mingw32msvc
deleted file mode 100644
index 30ebbb34d4f..00000000000
--- a/mk/cfg/i586-mingw32msvc
+++ /dev/null
@@ -1,29 +0,0 @@
-# i586-mingw32msvc configuration
-CC_i586-mingw32msvc=$(CFG_MINGW32_CROSS_PATH)/bin/i586-mingw32msvc-gcc
-CXX_i586-mingw32msvc=$(CFG_MINGW32_CROSS_PATH)/bin/i586-mingw32msvc-g++
-CPP_i586-mingw32msvc=$(CFG_MINGW32_CROSS_PATH)/bin/i586-mingw32msvc-cpp
-AR_i586-mingw32msvc=$(CFG_MINGW32_CROSS_PATH)/bin/i586-mingw32msvc-ar
-CFG_LIB_NAME_i586-mingw32msvc=$(1).dll
-CFG_STATIC_LIB_NAME_i586-mingw32msvc=$(1).lib
-CFG_LIB_GLOB_i586-mingw32msvc=$(1)-*.dll
-CFG_LIB_DSYM_GLOB_i586-mingw32msvc=$(1)-*.dylib.dSYM
-CFG_CFLAGS_i586-mingw32msvc := -march=i586 -m32 $(CFLAGS)
-CFG_GCCISH_CFLAGS_i586-mingw32msvc := -Wall -Werror -g -march=i586 -m32 $(CFLAGS)
-CFG_GCCISH_CXXFLAGS_i586-mingw32msvc := -fno-rtti $(CXXFLAGS)
-CFG_GCCISH_LINK_FLAGS_i586-mingw32msvc := -shared -g -m32
-CFG_GCCISH_DEF_FLAG_i586-mingw32msvc :=
-CFG_GCCISH_PRE_LIB_FLAGS_i586-mingw32msvc :=
-CFG_GCCISH_POST_LIB_FLAGS_i586-mingw32msvc :=
-CFG_DEF_SUFFIX_i586-mingw32msvc := .mingw32.def
-CFG_LLC_FLAGS_i586-mingw32msvc :=
-CFG_INSTALL_NAME_i586-mingw32msvc =
-CFG_EXE_SUFFIX_i586-mingw32msvc := .exe
-CFG_WINDOWSY_i586-mingw32msvc := 1
-CFG_UNIXY_i586-mingw32msvc :=
-CFG_PATH_MUNGE_i586-mingw32msvc := $(strip perl -i.bak -p \
-                             -e 's@\\(\S)@/\1@go;' \
-                             -e 's@^/([a-zA-Z])/@\1:/@o;')
-CFG_LDPATH_i586-mingw32msvc :=
-CFG_RUN_i586-mingw32msvc=
-CFG_RUN_TARG_i586-mingw32msvc=
-
diff --git a/mk/cfg/i686-apple-darwin b/mk/cfg/i686-apple-darwin
index 0f8a7732834..97ab0b31f63 100644
--- a/mk/cfg/i686-apple-darwin
+++ b/mk/cfg/i686-apple-darwin
@@ -24,4 +24,4 @@ CFG_PATH_MUNGE_i686-apple-darwin := true
 CFG_LDPATH_i686-apple-darwin :=
 CFG_RUN_i686-apple-darwin=$(2)
 CFG_RUN_TARG_i686-apple-darwin=$(call CFG_RUN_i686-apple-darwin,,$(2))
-
+CFG_GNU_TRIPLE_i686-apple-darwin := i686-apple-darwin
diff --git a/mk/cfg/i686-pc-windows-gnu b/mk/cfg/i686-pc-windows-gnu
new file mode 100644
index 00000000000..f24d8312f3c
--- /dev/null
+++ b/mk/cfg/i686-pc-windows-gnu
@@ -0,0 +1,28 @@
+# i686-pc-windows-gnu configuration
+CROSS_PREFIX_i686-pc-windows-gnu=i686-pc-windows-gnu-
+CC_i686-pc-windows-gnu=gcc
+CXX_i686-pc-windows-gnu=g++
+CPP_i686-pc-windows-gnu=gcc -E
+AR_i686-pc-windows-gnu=ar
+CFG_LIB_NAME_i686-pc-windows-gnu=$(1).dll
+CFG_STATIC_LIB_NAME_i686-pc-windows-gnu=$(1).lib
+CFG_LIB_GLOB_i686-pc-windows-gnu=$(1)-*.dll
+CFG_LIB_DSYM_GLOB_i686-pc-windows-gnu=$(1)-*.dylib.dSYM
+CFG_CFLAGS_i686-pc-windows-gnu := -march=i686 -m32 -D_WIN32_WINNT=0x0600 $(CFLAGS)
+CFG_GCCISH_CFLAGS_i686-pc-windows-gnu := -Wall -Werror -g -m32 -D_WIN32_WINNT=0x0600 $(CFLAGS)
+CFG_GCCISH_CXXFLAGS_i686-pc-windows-gnu := -fno-rtti $(CXXFLAGS)
+CFG_GCCISH_LINK_FLAGS_i686-pc-windows-gnu := -shared -g -m32
+CFG_GCCISH_DEF_FLAG_i686-pc-windows-gnu :=
+CFG_GCCISH_PRE_LIB_FLAGS_i686-pc-windows-gnu :=
+CFG_GCCISH_POST_LIB_FLAGS_i686-pc-windows-gnu :=
+CFG_DEF_SUFFIX_i686-pc-windows-gnu := .windows.def
+CFG_LLC_FLAGS_i686-pc-windows-gnu :=
+CFG_INSTALL_NAME_i686-pc-windows-gnu =
+CFG_EXE_SUFFIX_i686-pc-windows-gnu := .exe
+CFG_WINDOWSY_i686-pc-windows-gnu := 1
+CFG_UNIXY_i686-pc-windows-gnu :=
+CFG_PATH_MUNGE_i686-pc-windows-gnu :=
+CFG_LDPATH_i686-pc-windows-gnu :=$(CFG_LDPATH_i686-pc-windows-gnu):$(PATH)
+CFG_RUN_i686-pc-windows-gnu=PATH="$(CFG_LDPATH_i686-pc-windows-gnu):$(1)" $(2)
+CFG_RUN_TARG_i686-pc-windows-gnu=$(call CFG_RUN_i686-pc-windows-gnu,$(HLIB$(1)_H_$(CFG_BUILD)),$(2))
+CFG_GNU_TRIPLE_i686-pc-windows-gnu := i686-w64-mingw32
diff --git a/mk/cfg/i686-unknown-linux-gnu b/mk/cfg/i686-unknown-linux-gnu
index 0b34e0feee7..76ed56d145b 100644
--- a/mk/cfg/i686-unknown-linux-gnu
+++ b/mk/cfg/i686-unknown-linux-gnu
@@ -24,4 +24,4 @@ CFG_PATH_MUNGE_i686-unknown-linux-gnu := true
 CFG_LDPATH_i686-unknown-linux-gnu :=
 CFG_RUN_i686-unknown-linux-gnu=$(2)
 CFG_RUN_TARG_i686-unknown-linux-gnu=$(call CFG_RUN_i686-unknown-linux-gnu,,$(2))
-
+CFG_GNU_TRIPLE_i686-unknown-linux-gnu := i686-unknown-linux-gnu
diff --git a/mk/cfg/i686-w64-mingw32 b/mk/cfg/i686-w64-mingw32
deleted file mode 100644
index b62b805a4fb..00000000000
--- a/mk/cfg/i686-w64-mingw32
+++ /dev/null
@@ -1,31 +0,0 @@
-# i686-w64-mingw32 configuration
-CROSS_PREFIX_i686-w64-mingw32=i686-w64-mingw32-
-CC_i686-w64-mingw32=gcc
-CXX_i686-w64-mingw32=g++
-CPP_i686-w64-mingw32=gcc -E
-AR_i686-w64-mingw32=ar
-CFG_LIB_NAME_i686-w64-mingw32=$(1).dll
-CFG_STATIC_LIB_NAME_i686-w64-mingw32=$(1).lib
-CFG_LIB_GLOB_i686-w64-mingw32=$(1)-*.dll
-CFG_LIB_DSYM_GLOB_i686-w64-mingw32=$(1)-*.dylib.dSYM
-CFG_CFLAGS_i686-w64-mingw32 := -march=i686 -m32 -D_WIN32_WINNT=0x0600 $(CFLAGS)
-CFG_GCCISH_CFLAGS_i686-w64-mingw32 := -Wall -Werror -g -m32 -D_WIN32_WINNT=0x0600 $(CFLAGS)
-CFG_GCCISH_CXXFLAGS_i686-w64-mingw32 := -fno-rtti $(CXXFLAGS)
-CFG_GCCISH_LINK_FLAGS_i686-w64-mingw32 := -shared -g -m32
-CFG_GCCISH_DEF_FLAG_i686-w64-mingw32 :=
-CFG_GCCISH_PRE_LIB_FLAGS_i686-w64-mingw32 :=
-CFG_GCCISH_POST_LIB_FLAGS_i686-w64-mingw32 :=
-CFG_DEF_SUFFIX_i686-w64-mingw32 := .mingw32.def
-CFG_LLC_FLAGS_i686-w64-mingw32 :=
-CFG_INSTALL_NAME_i686-w64-mingw32 =
-CFG_EXE_SUFFIX_i686-w64-mingw32 := .exe
-CFG_WINDOWSY_i686-w64-mingw32 := 1
-CFG_UNIXY_i686-w64-mingw32 :=
-CFG_PATH_MUNGE_i686-w64-mingw32 :=
-CFG_LDPATH_i686-w64-mingw32 :=$(CFG_LDPATH_i686-w64-mingw32):$(PATH)
-CFG_RUN_i686-w64-mingw32=PATH="$(CFG_LDPATH_i686-w64-mingw32):$(1)" $(2)
-CFG_RUN_TARG_i686-w64-mingw32=$(call CFG_RUN_i686-w64-mingw32,$(HLIB$(1)_H_$(CFG_BUILD)),$(2))
-# Stop rustc from OOMing when building itself (I think)
-RUSTC_FLAGS_i686-w64-mingw32=-C link-args="-Wl,--large-address-aware"
-RUSTC_CROSS_FLAGS_i686-w64-mingw32 :=
-
diff --git a/mk/cfg/mips-unknown-linux-gnu b/mk/cfg/mips-unknown-linux-gnu
index c01fdf00f66..1caecec93d1 100644
--- a/mk/cfg/mips-unknown-linux-gnu
+++ b/mk/cfg/mips-unknown-linux-gnu
@@ -25,3 +25,4 @@ CFG_LDPATH_mips-unknown-linux-gnu :=
 CFG_RUN_mips-unknown-linux-gnu=
 CFG_RUN_TARG_mips-unknown-linux-gnu=
 RUSTC_FLAGS_mips-unknown-linux-gnu := -C target-cpu=mips32r2 -C target-feature="+mips32r2,+o32" -C soft-float
+CFG_GNU_TRIPLE_mips-unknown-linux-gnu := mips-unknown-linux-gnu
diff --git a/mk/cfg/mipsel-linux b/mk/cfg/mipsel-linux
deleted file mode 100644
index 963965cbd6c..00000000000
--- a/mk/cfg/mipsel-linux
+++ /dev/null
@@ -1,27 +0,0 @@
-# mipsel-linux configuration
-CC_mipsel-linux=mipsel-linux-gcc
-CXX_mipsel-linux=mipsel-linux-g++
-CPP_mipsel-linux=mipsel-linux-gcc
-AR_mipsel-linux=mipsel-linux-ar
-CFG_LIB_NAME_mipsel-linux=lib$(1).so
-CFG_STATIC_LIB_NAME_mipsel-linux=lib$(1).a
-CFG_LIB_GLOB_mipsel-linux=lib$(1)-*.so
-CFG_LIB_DSYM_GLOB_mipsel-linux=lib$(1)-*.dylib.dSYM
-CFG_CFLAGS_mipsel-linux := -mips32 -mabi=32 $(CFLAGS)
-CFG_GCCISH_CFLAGS_mipsel-linux := -Wall -g -fPIC -mips32 -mabi=32 $(CFLAGS)
-CFG_GCCISH_CXXFLAGS_mipsel-linux := -fno-rtti $(CXXFLAGS)
-CFG_GCCISH_LINK_FLAGS_mipsel-linux := -shared -fPIC -g -mips32
-CFG_GCCISH_DEF_FLAG_mipsel-linux := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_mipsel-linux := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_mipsel-linux := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_mipsel-linux := .linux.def
-CFG_LLC_FLAGS_mipsel-linux :=
-CFG_INSTALL_NAME_mipsel-linux =
-CFG_EXE_SUFFIX_mipsel-linux :=
-CFG_WINDOWSY_mipsel-linux :=
-CFG_UNIXY_mipsel-linux := 1
-CFG_PATH_MUNGE_mipsel-linux := true
-CFG_LDPATH_mipsel-linux :=
-CFG_RUN_mipsel-linux=
-CFG_RUN_TARG_mipsel-linux=
-RUSTC_FLAGS_mipsel-linux := -C target-cpu=mips32 -C target-feature="+mips32,+o32"
diff --git a/mk/cfg/mipsel-unknown-linux-gnu b/mk/cfg/mipsel-unknown-linux-gnu
new file mode 100644
index 00000000000..d761d5dd090
--- /dev/null
+++ b/mk/cfg/mipsel-unknown-linux-gnu
@@ -0,0 +1,28 @@
+# mipsel-unknown-linux-gnu configuration
+CC_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-gcc
+CXX_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-g++
+CPP_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-gcc
+AR_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-ar
+CFG_LIB_NAME_mipsel-unknown-linux-gnu=lib$(1).so
+CFG_STATIC_LIB_NAME_mipsel-unknown-linux-gnu=lib$(1).a
+CFG_LIB_GLOB_mipsel-unknown-linux-gnu=lib$(1)-*.so
+CFG_LIB_DSYM_GLOB_mipsel-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
+CFG_CFLAGS_mipsel-unknown-linux-gnu := -mips32 -mabi=32 $(CFLAGS)
+CFG_GCCISH_CFLAGS_mipsel-unknown-linux-gnu := -Wall -g -fPIC -mips32 -mabi=32 $(CFLAGS)
+CFG_GCCISH_CXXFLAGS_mipsel-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
+CFG_GCCISH_LINK_FLAGS_mipsel-unknown-linux-gnu := -shared -fPIC -g -mips32
+CFG_GCCISH_DEF_FLAG_mipsel-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
+CFG_GCCISH_PRE_LIB_FLAGS_mipsel-unknown-linux-gnu := -Wl,-whole-archive
+CFG_GCCISH_POST_LIB_FLAGS_mipsel-unknown-linux-gnu := -Wl,-no-whole-archive
+CFG_DEF_SUFFIX_mipsel-unknown-linux-gnu := .linux.def
+CFG_LLC_FLAGS_mipsel-unknown-linux-gnu :=
+CFG_INSTALL_NAME_mipsel-unknown-linux-gnu =
+CFG_EXE_SUFFIX_mipsel-unknown-linux-gnu :=
+CFG_WINDOWSY_mipsel-unknown-linux-gnu :=
+CFG_UNIXY_mipsel-unknown-linux-gnu := 1
+CFG_PATH_MUNGE_mipsel-unknown-linux-gnu := true
+CFG_LDPATH_mipsel-unknown-linux-gnu :=
+CFG_RUN_mipsel-unknown-linux-gnu=
+CFG_RUN_TARG_mipsel-unknown-linux-gnu=
+RUSTC_FLAGS_mipsel-unknown-linux-gnu := -C target-cpu=mips32 -C target-feature="+mips32,+o32"
+CFG_GNU_TRIPLE_mipsel-unknown-linux-gnu := mipsel-unknown-linux-gnu
diff --git a/mk/cfg/x86_64-apple-darwin b/mk/cfg/x86_64-apple-darwin
index 67b32a6930c..5da7c928da9 100644
--- a/mk/cfg/x86_64-apple-darwin
+++ b/mk/cfg/x86_64-apple-darwin
@@ -24,3 +24,4 @@ CFG_PATH_MUNGE_x86_64-apple-darwin := true
 CFG_LDPATH_x86_64-apple-darwin :=
 CFG_RUN_x86_64-apple-darwin=$(2)
 CFG_RUN_TARG_x86_64-apple-darwin=$(call CFG_RUN_x86_64-apple-darwin,,$(2))
+CFG_GNU_TRIPLE_x86_64-apple-darwin := x86_64-apple-darwin
diff --git a/mk/cfg/x86_64-pc-windows-gnu b/mk/cfg/x86_64-pc-windows-gnu
new file mode 100644
index 00000000000..fbe2e832f40
--- /dev/null
+++ b/mk/cfg/x86_64-pc-windows-gnu
@@ -0,0 +1,28 @@
+# x86_64-pc-windows-gnu configuration
+CROSS_PREFIX_x86_64-pc-windows-gnu=x86_64-pc-windows-gnu-
+CC_x86_64-pc-windows-gnu=gcc
+CXX_x86_64-pc-windows-gnu=g++
+CPP_x86_64-pc-windows-gnu=gcc -E
+AR_x86_64-pc-windows-gnu=ar
+CFG_LIB_NAME_x86_64-pc-windows-gnu=$(1).dll
+CFG_STATIC_LIB_NAME_x86_64-pc-windows-gnu=$(1).lib
+CFG_LIB_GLOB_x86_64-pc-windows-gnu=$(1)-*.dll
+CFG_LIB_DSYM_GLOB_x86_64-pc-windows-gnu=$(1)-*.dylib.dSYM
+CFG_CFLAGS_x86_64-pc-windows-gnu := -m64 -D_WIN32_WINNT=0x0600 $(CFLAGS)
+CFG_GCCISH_CFLAGS_x86_64-pc-windows-gnu := -Wall -Werror -g -m64 -D_WIN32_WINNT=0x0600 $(CFLAGS)
+CFG_GCCISH_CXXFLAGS_x86_64-pc-windows-gnu := -fno-rtti $(CXXFLAGS)
+CFG_GCCISH_LINK_FLAGS_x86_64-pc-windows-gnu := -shared -g -m64
+CFG_GCCISH_DEF_FLAG_x86_64-pc-windows-gnu :=
+CFG_GCCISH_PRE_LIB_FLAGS_x86_64-pc-windows-gnu :=
+CFG_GCCISH_POST_LIB_FLAGS_x86_64-pc-windows-gnu :=
+CFG_DEF_SUFFIX_x86_64-pc-windows-gnu := .windows.def
+CFG_LLC_FLAGS_x86_64-pc-windows-gnu :=
+CFG_INSTALL_NAME_x86_64-pc-windows-gnu =
+CFG_EXE_SUFFIX_x86_64-pc-windows-gnu := .exe
+CFG_WINDOWSY_x86_64-pc-windows-gnu := 1
+CFG_UNIXY_x86_64-pc-windows-gnu :=
+CFG_PATH_MUNGE_x86_64-pc-windows-gnu :=
+CFG_LDPATH_x86_64-pc-windows-gnu :=$(CFG_LDPATH_x86_64-pc-windows-gnu):$(PATH)
+CFG_RUN_x86_64-pc-windows-gnu=PATH="$(CFG_LDPATH_x86_64-pc-windows-gnu):$(1)" $(2)
+CFG_RUN_TARG_x86_64-pc-windows-gnu=$(call CFG_RUN_x86_64-pc-windows-gnu,$(HLIB$(1)_H_$(CFG_BUILD)),$(2))
+CFG_GNU_TRIPLE_x86_64-pc-windows-gnu := x86_64-w64-mingw32
diff --git a/mk/cfg/x86_64-unknown-dragonfly b/mk/cfg/x86_64-unknown-dragonfly
index 48e872c5ed3..50928d3c20e 100644
--- a/mk/cfg/x86_64-unknown-dragonfly
+++ b/mk/cfg/x86_64-unknown-dragonfly
@@ -23,3 +23,4 @@ CFG_PATH_MUNGE_x86_64-unknown-dragonfly :=
 CFG_LDPATH_x86_64-unknown-dragonfly :=
 CFG_RUN_x86_64-unknown-dragonfly=$(2)
 CFG_RUN_TARG_x86_64-unknown-dragonfly=$(call CFG_RUN_x86_64-unknown-dragonfly,,$(2))
+CFG_GNU_TRIPLE_x86_64-unknown-dragonfly := x86_64-unknown-dragonfly
diff --git a/mk/cfg/x86_64-unknown-freebsd b/mk/cfg/x86_64-unknown-freebsd
index 8ad42d25642..1926c9873b7 100644
--- a/mk/cfg/x86_64-unknown-freebsd
+++ b/mk/cfg/x86_64-unknown-freebsd
@@ -23,3 +23,4 @@ CFG_PATH_MUNGE_x86_64-unknown-freebsd :=
 CFG_LDPATH_x86_64-unknown-freebsd :=
 CFG_RUN_x86_64-unknown-freebsd=$(2)
 CFG_RUN_TARG_x86_64-unknown-freebsd=$(call CFG_RUN_x86_64-unknown-freebsd,,$(2))
+CFG_GNU_TRIPLE_x86_64-unknown-freebsd := x86_64-unknown-freebsd
diff --git a/mk/cfg/x86_64-unknown-linux-gnu b/mk/cfg/x86_64-unknown-linux-gnu
index d6d0fd7677f..5f165ade3a7 100644
--- a/mk/cfg/x86_64-unknown-linux-gnu
+++ b/mk/cfg/x86_64-unknown-linux-gnu
@@ -24,3 +24,5 @@ CFG_PATH_MUNGE_x86_64-unknown-linux-gnu := true
 CFG_LDPATH_x86_64-unknown-linux-gnu :=
 CFG_RUN_x86_64-unknown-linux-gnu=$(2)
 CFG_RUN_TARG_x86_64-unknown-linux-gnu=$(call CFG_RUN_x86_64-unknown-linux-gnu,,$(2))
+CFG_GNU_TRIPLE_x86_64-unknown-linux-gnu := x86_64-unknown-linux-gnu
+
diff --git a/mk/cfg/x86_64-w64-mingw32 b/mk/cfg/x86_64-w64-mingw32
deleted file mode 100644
index b292a83bbb4..00000000000
--- a/mk/cfg/x86_64-w64-mingw32
+++ /dev/null
@@ -1,28 +0,0 @@
-# x86_64-w64-mingw32 configuration
-CROSS_PREFIX_x86_64-w64-mingw32=x86_64-w64-mingw32-
-CC_x86_64-w64-mingw32=gcc
-CXX_x86_64-w64-mingw32=g++
-CPP_x86_64-w64-mingw32=gcc -E
-AR_x86_64-w64-mingw32=ar
-CFG_LIB_NAME_x86_64-w64-mingw32=$(1).dll
-CFG_STATIC_LIB_NAME_x86_64-w64-mingw32=$(1).lib
-CFG_LIB_GLOB_x86_64-w64-mingw32=$(1)-*.dll
-CFG_LIB_DSYM_GLOB_x86_64-w64-mingw32=$(1)-*.dylib.dSYM
-CFG_CFLAGS_x86_64-w64-mingw32 := -m64 -D_WIN32_WINNT=0x0600 $(CFLAGS)
-CFG_GCCISH_CFLAGS_x86_64-w64-mingw32 := -Wall -Werror -g -m64 -D_WIN32_WINNT=0x0600 $(CFLAGS)
-CFG_GCCISH_CXXFLAGS_x86_64-w64-mingw32 := -fno-rtti $(CXXFLAGS)
-CFG_GCCISH_LINK_FLAGS_x86_64-w64-mingw32 := -shared -g -m64
-CFG_GCCISH_DEF_FLAG_x86_64-w64-mingw32 :=
-CFG_GCCISH_PRE_LIB_FLAGS_x86_64-w64-mingw32 :=
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-w64-mingw32 :=
-CFG_DEF_SUFFIX_x86_64-w64-mingw32 := .mingw32.def
-CFG_LLC_FLAGS_x86_64-w64-mingw32 :=
-CFG_INSTALL_NAME_x86_64-w64-mingw32 =
-CFG_EXE_SUFFIX_x86_64-w64-mingw32 := .exe
-CFG_WINDOWSY_x86_64-w64-mingw32 := 1
-CFG_UNIXY_x86_64-w64-mingw32 :=
-CFG_PATH_MUNGE_x86_64-w64-mingw32 :=
-CFG_LDPATH_x86_64-w64-mingw32 :=$(CFG_LDPATH_x86_64-w64-mingw32):$(PATH)
-CFG_RUN_x86_64-w64-mingw32=PATH="$(CFG_LDPATH_x86_64-w64-mingw32):$(1)" $(2)
-CFG_RUN_TARG_x86_64-w64-mingw32=$(call CFG_RUN_x86_64-w64-mingw32,$(HLIB$(1)_H_$(CFG_BUILD)),$(2))
-RUSTC_CROSS_FLAGS_x86_64-w64-mingw32 :=
diff --git a/mk/main.mk b/mk/main.mk
index 181bca69462..e10fb4c7f75 100644
--- a/mk/main.mk
+++ b/mk/main.mk
@@ -311,7 +311,6 @@ export CFG_RELEASE
 export CFG_PACKAGE_NAME
 export CFG_BUILD
 export CFG_LLVM_ROOT
-export CFG_ENABLE_MINGW_CROSS
 export CFG_PREFIX
 export CFG_LIBDIR
 export CFG_LIBDIR_RELATIVE
diff --git a/mk/rt.mk b/mk/rt.mk
index 3e050123274..7204808c30a 100644
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -176,7 +176,7 @@ $$(JEMALLOC_LOCAL_$(1)): $$(JEMALLOC_DEPS) $$(MKFILE_DEPS)
 	@$$(call E, make: jemalloc)
 	cd "$$(JEMALLOC_BUILD_DIR_$(1))"; "$(S)src/jemalloc/configure" \
 		$$(JEMALLOC_ARGS_$(1)) --with-jemalloc-prefix=je_ $(CFG_JEMALLOC_FLAGS) \
-		--build=$(CFG_BUILD) --host=$(1) \
+		--build=$$(CFG_GNU_TRIPLE_$(CFG_BUILD)) --host=$$(CFG_GNU_TRIPLE_$(1)) \
 		CC="$$(CC_$(1))" \
 		AR="$$(AR_$(1))" \
 		RANLIB="$$(AR_$(1)) s" \
diff --git a/src/etc/snapshot.py b/src/etc/snapshot.py
index 268b82bdca3..e0610bfbdfe 100644
--- a/src/etc/snapshot.py
+++ b/src/etc/snapshot.py
@@ -75,9 +75,8 @@ def full_snapshot_name(date, rev, platform, hsh):
 
 
 def get_kernel(triple):
-    os_name = triple.split('-')[-1]
-    #scrub(os.getenv("CFG_ENABLE_MINGW_CROSS")):
-    if os_name == "nt" or os_name == "mingw32":
+    os_name = triple.split('-')[2]
+    if os_name == "windows":
         return "winnt"
     if os_name == "darwin":
         return "macos"
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index d47ca892b13..81f856c29d5 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -19,7 +19,7 @@ use driver::config::NoDebugInfo;
 use driver::session::Session;
 use driver::config;
 use metadata::common::LinkMeta;
-use metadata::{encoder, cstore, filesearch, csearch, loader, creader};
+use metadata::{encoder, cstore, filesearch, csearch, creader};
 use middle::trans::context::CrateContext;
 use middle::trans::common::gensym_name;
 use middle::ty;
@@ -36,7 +36,6 @@ use std::str;
 use std::string::String;
 use flate;
 use serialize::hex::ToHex;
-use syntax::abi;
 use syntax::ast;
 use syntax::ast_map::{PathElem, PathElems, PathName};
 use syntax::ast_map;
@@ -363,17 +362,8 @@ pub fn mangle_internal_name_by_path_and_seq(path: PathElems, flav: &str) -> Stri
 pub fn get_cc_prog(sess: &Session) -> String {
     match sess.opts.cg.linker {
         Some(ref linker) => return linker.to_string(),
-        None => {}
+        None => sess.target.target.options.linker.clone(),
     }
-
-    // In the future, FreeBSD will use clang as default compiler.
-    // It would be flexible to use cc (system's default C compiler)
-    // instead of hard-coded gcc.
-    // For Windows, there is no cc command, so we add a condition to make it use gcc.
-    match sess.targ_cfg.os {
-        abi::OsWindows => "gcc",
-        _ => "cc",
-    }.to_string()
 }
 
 pub fn remove(sess: &Session, path: &Path) {
@@ -397,7 +387,7 @@ pub fn link_binary(sess: &Session,
     for &crate_type in sess.crate_types.borrow().iter() {
         if invalid_output_for_target(sess, crate_type) {
             sess.bug(format!("invalid output type `{}` for target os `{}`",
-                             crate_type, sess.targ_cfg.os).as_slice());
+                             crate_type, sess.opts.target_triple).as_slice());
         }
         let out_file = link_binary_output(sess, trans, crate_type, outputs,
                                           crate_name);
@@ -427,17 +417,20 @@ pub fn link_binary(sess: &Session,
 /// interaction with Rust code through static library is the only
 /// option for now
 pub fn default_output_for_target(sess: &Session) -> config::CrateType {
-    match sess.targ_cfg.os {
-        abi::OsiOS => config::CrateTypeStaticlib,
-        _ => config::CrateTypeExecutable
+    if !sess.target.target.options.executables {
+        config::CrateTypeStaticlib
+    } else {
+        config::CrateTypeExecutable
     }
 }
 
 /// Checks if target supports crate_type as output
 pub fn invalid_output_for_target(sess: &Session,
                                  crate_type: config::CrateType) -> bool {
-    match (sess.targ_cfg.os, crate_type) {
-        (abi::OsiOS, config::CrateTypeDylib) => true,
+    match (sess.target.target.options.dynamic_linking,
+           sess.target.target.options.executables, crate_type) {
+        (false, _, config::CrateTypeDylib) => true,
+        (_, false, config::CrateTypeExecutable) => true,
         _ => false
     }
 }
@@ -459,15 +452,8 @@ pub fn filename_for_input(sess: &Session,
             out_filename.with_filename(format!("lib{}.rlib", libname))
         }
         config::CrateTypeDylib => {
-            let (prefix, suffix) = match sess.targ_cfg.os {
-                abi::OsWindows => (loader::WIN32_DLL_PREFIX, loader::WIN32_DLL_SUFFIX),
-                abi::OsMacos => (loader::MACOS_DLL_PREFIX, loader::MACOS_DLL_SUFFIX),
-                abi::OsLinux => (loader::LINUX_DLL_PREFIX, loader::LINUX_DLL_SUFFIX),
-                abi::OsAndroid => (loader::ANDROID_DLL_PREFIX, loader::ANDROID_DLL_SUFFIX),
-                abi::OsFreebsd => (loader::FREEBSD_DLL_PREFIX, loader::FREEBSD_DLL_SUFFIX),
-                abi::OsDragonfly => (loader::DRAGONFLY_DLL_PREFIX, loader::DRAGONFLY_DLL_SUFFIX),
-                abi::OsiOS => unreachable!(),
-            };
+            let (prefix, suffix) = (sess.target.target.options.dll_prefix.as_slice(),
+                                    sess.target.target.options.dll_suffix.as_slice());
             out_filename.with_filename(format!("{}{}{}",
                                                prefix,
                                                libname,
@@ -477,15 +463,8 @@ pub fn filename_for_input(sess: &Session,
             out_filename.with_filename(format!("lib{}.a", libname))
         }
         config::CrateTypeExecutable => {
-            match sess.targ_cfg.os {
-                abi::OsWindows => out_filename.with_extension("exe"),
-                abi::OsMacos |
-                abi::OsLinux |
-                abi::OsAndroid |
-                abi::OsFreebsd |
-                abi::OsDragonfly |
-                abi::OsiOS => out_filename.clone(),
-            }
+            let suffix = sess.target.target.options.exe_suffix.as_slice();
+            out_filename.with_filename(format!("{}{}", libname, suffix))
         }
     }
 }
@@ -562,7 +541,8 @@ fn link_rlib<'a>(sess: &'a Session,
         handler: handler,
         dst: out_filename.clone(),
         lib_search_paths: archive_search_paths(sess),
-        os: sess.targ_cfg.os,
+        slib_prefix: sess.target.target.options.staticlib_prefix.clone(),
+        slib_suffix: sess.target.target.options.staticlib_suffix.clone(),
         maybe_ar_prog: sess.opts.cg.ar.clone()
     };
     let mut ab = ArchiveBuilder::create(config);
@@ -581,12 +561,12 @@ fn link_rlib<'a>(sess: &'a Session,
     // symbol table of the archive.
     ab.update_symbols();
 
-    let mut ab = match sess.targ_cfg.os {
+    let mut ab = match sess.target.target.options.is_like_osx {
         // For OSX/iOS, we must be careful to update symbols only when adding
         // object files.  We're about to start adding non-object files, so run
         // `ar` now to process the object files.
-        abi::OsMacos | abi::OsiOS => ab.build().extend(),
-        _ => ab,
+        true => ab.build().extend(),
+        false => ab,
     };
 
     // Note that it is important that we add all of our non-object "magical
@@ -686,6 +666,13 @@ fn link_rlib<'a>(sess: &'a Session,
                     remove(sess, &bc_filename);
                 }
             }
+
+            // After adding all files to the archive, we need to update the
+            // symbol table of the archive. This currently dies on OSX (see
+            // #11162), and isn't necessary there anyway
+            if !sess.target.target.options.is_like_osx {
+                ab.update_symbols();
+            }
         }
 
         None => {}
@@ -734,11 +721,13 @@ fn write_rlib_bytecode_object_v1<T: Writer>(writer: &mut T,
 // metadata file).
 fn link_staticlib(sess: &Session, obj_filename: &Path, out_filename: &Path) {
     let ab = link_rlib(sess, None, obj_filename, out_filename);
-    let mut ab = match sess.targ_cfg.os {
-        abi::OsMacos | abi::OsiOS => ab.build().extend(),
-        _ => ab,
+    let mut ab = match sess.target.target.options.is_like_osx {
+        true => ab.build().extend(),
+        false => ab,
     };
-    ab.add_native_library("morestack").unwrap();
+    if sess.target.target.options.morestack {
+        ab.add_native_library("morestack").unwrap();
+    }
     ab.add_native_library("compiler-rt").unwrap();
 
     let crates = sess.cstore.get_used_crates(cstore::RequireStatic);
@@ -791,9 +780,13 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
     let pname = get_cc_prog(sess);
     let mut cmd = Command::new(pname.as_slice());
 
-    cmd.args(sess.targ_cfg.target_strs.cc_args.as_slice());
+    cmd.args(sess.target.target.options.pre_link_args.as_slice());
     link_args(&mut cmd, sess, dylib, tmpdir.path(),
               trans, obj_filename, out_filename);
+    cmd.args(sess.target.target.options.post_link_args.as_slice());
+    if !sess.target.target.options.no_compiler_rt {
+        cmd.arg("-lcompiler-rt");
+    }
 
     if (sess.opts.debugging_opts & config::PRINT_LINK_ARGS) != 0 {
         println!("{}", &cmd);
@@ -831,16 +824,15 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
 
     // On OSX, debuggers need this utility to get run to do some munging of
     // the symbols
-    if (sess.targ_cfg.os == abi::OsMacos || sess.targ_cfg.os == abi::OsiOS)
-        && (sess.opts.debuginfo != NoDebugInfo) {
-            match Command::new("dsymutil").arg(out_filename).output() {
-                Ok(..) => {}
-                Err(e) => {
-                    sess.err(format!("failed to run dsymutil: {}", e).as_slice());
-                    sess.abort_if_errors();
-                }
+    if sess.target.target.options.is_like_osx && sess.opts.debuginfo != NoDebugInfo {
+        match Command::new("dsymutil").arg(out_filename).output() {
+            Ok(..) => {}
+            Err(e) => {
+                sess.err(format!("failed to run dsymutil: {}", e).as_slice());
+                sess.abort_if_errors();
             }
         }
+    }
 }
 
 fn link_args(cmd: &mut Command,
@@ -854,10 +846,15 @@ fn link_args(cmd: &mut Command,
     // The default library location, we need this to find the runtime.
     // The location of crates will be determined as needed.
     let lib_path = sess.target_filesearch().get_lib_path();
+
+    // target descriptor
+    let t = &sess.target.target;
+
     cmd.arg("-L").arg(&lib_path);
 
     cmd.arg("-o").arg(out_filename).arg(obj_filename);
 
+
     // Stack growth requires statically linking a __morestack function. Note
     // that this is listed *before* all other libraries. Due to the usage of the
     // --as-needed flag below, the standard library may only be useful for its
@@ -874,17 +871,15 @@ fn link_args(cmd: &mut Command,
     // all contents of this library. This way we're guaranteed that the linker
     // will include the __morestack symbol 100% of the time, always resolving
     // references to it even if the object above didn't use it.
-    match sess.targ_cfg.os {
-        abi::OsMacos | abi::OsiOS => {
+    if t.options.morestack {
+        if t.options.is_like_osx {
             let morestack = lib_path.join("libmorestack.a");
 
             let mut v = b"-Wl,-force_load,".to_vec();
             v.push_all(morestack.as_vec());
             cmd.arg(v.as_slice());
-        }
-        _ => {
-            cmd.args(["-Wl,--whole-archive", "-lmorestack",
-                      "-Wl,--no-whole-archive"]);
+        } else {
+            cmd.args(["-Wl,--whole-archive", "-lmorestack", "-Wl,--no-whole-archive"]);
         }
     }
 
@@ -895,131 +890,72 @@ fn link_args(cmd: &mut Command,
         cmd.arg(obj_filename.with_extension("metadata.o"));
     }
 
-    // We want to prevent the compiler from accidentally leaking in any system
-    // libraries, so we explicitly ask gcc to not link to any libraries by
-    // default. Note that this does not happen for windows because windows pulls
-    // in some large number of libraries and I couldn't quite figure out which
-    // subset we wanted.
-    //
-    // FIXME(#11937) we should invoke the system linker directly
-    if sess.targ_cfg.os != abi::OsWindows {
-        cmd.arg("-nodefaultlibs");
-    }
-
     // Rust does its' own LTO
     cmd.arg("-fno-lto");
 
-    // clang fails hard if -fno-use-linker-plugin is passed
-    if sess.targ_cfg.os == abi::OsWindows {
-        cmd.arg("-fno-use-linker-plugin");
+    if t.options.is_like_osx {
+        // The dead_strip option to the linker specifies that functions and data
+        // unreachable by the entry point will be removed. This is quite useful
+        // with Rust's compilation model of compiling libraries at a time into
+        // one object file. For example, this brings hello world from 1.7MB to
+        // 458K.
+        //
+        // Note that this is done for both executables and dynamic libraries. We
+        // won't get much benefit from dylibs because LLVM will have already
+        // stripped away as much as it could. This has not been seen to impact
+        // link times negatively.
+        //
+        // -dead_strip can't be part of the pre_link_args because it's also used for partial
+        // linking when using multiple codegen units (-r). So we insert it here.
+        cmd.arg("-Wl,-dead_strip");
     }
 
     // If we're building a dylib, we don't use --gc-sections because LLVM has
     // already done the best it can do, and we also don't want to eliminate the
     // metadata. If we're building an executable, however, --gc-sections drops
     // the size of hello world from 1.8MB to 597K, a 67% reduction.
-    if !dylib && sess.targ_cfg.os != abi::OsMacos && sess.targ_cfg.os != abi::OsiOS {
+    if !dylib && !t.options.is_like_osx {
         cmd.arg("-Wl,--gc-sections");
     }
 
     let used_link_args = sess.cstore.get_used_link_args().borrow();
 
-    // Dynamically linked executables can be compiled as position independent if the default
-    // relocation model of position independent code is not changed. This is a requirement to take
-    // advantage of ASLR, as otherwise the functions in the executable are not randomized and can
-    // be used during an exploit of a vulnerability in any code.
-    if sess.targ_cfg.os == abi::OsLinux {
-        let mut args = sess.opts.cg.link_args.iter().chain(used_link_args.iter());
-        if !dylib && sess.opts.cg.relocation_model.as_slice() == "pic" &&
-            !args.any(|x| x.as_slice() == "-static") {
+    if t.options.position_independant_executables {
+        let empty_vec = Vec::new();
+        let empty_str = String::new();
+        let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec);
+        let mut args = args.iter().chain(used_link_args.iter());
+        if !dylib
+            && (t.options.relocation_model.as_slice() == "pic"
+                || sess.opts.cg.relocation_model.as_ref()
+                   .unwrap_or(&empty_str).as_slice() == "pic")
+            && !args.any(|x| x.as_slice() == "-static") {
             cmd.arg("-pie");
         }
     }
 
-    if sess.targ_cfg.os == abi::OsLinux || sess.targ_cfg.os == abi::OsDragonfly {
-        // GNU-style linkers will use this to omit linking to libraries which
-        // don't actually fulfill any relocations, but only for libraries which
-        // follow this flag. Thus, use it before specifying libraries to link to.
-        cmd.arg("-Wl,--as-needed");
-
+    if t.options.linker_is_gnu {
         // GNU-style linkers support optimization with -O. GNU ld doesn't need a
         // numeric argument, but other linkers do.
         if sess.opts.optimize == config::Default ||
            sess.opts.optimize == config::Aggressive {
             cmd.arg("-Wl,-O1");
         }
-    } else if sess.targ_cfg.os == abi::OsMacos || sess.targ_cfg.os == abi::OsiOS {
-        // The dead_strip option to the linker specifies that functions and data
-        // unreachable by the entry point will be removed. This is quite useful
-        // with Rust's compilation model of compiling libraries at a time into
-        // one object file. For example, this brings hello world from 1.7MB to
-        // 458K.
-        //
-        // Note that this is done for both executables and dynamic libraries. We
-        // won't get much benefit from dylibs because LLVM will have already
-        // stripped away as much as it could. This has not been seen to impact
-        // link times negatively.
-        cmd.arg("-Wl,-dead_strip");
     }
 
-    if sess.targ_cfg.os == abi::OsWindows {
-        if sess.targ_cfg.arch == abi::X86 {
-            // Make sure that we link to the dynamic libgcc, otherwise cross-module
-            // DWARF stack unwinding will not work.
-            // This behavior may be overridden by -Clink-args="-static-libgcc"
-            cmd.arg("-shared-libgcc");
-        } else {
-            // On Win64 unwinding is handled by the OS, so we can link libgcc statically.
-            cmd.arg("-static-libgcc");
-        }
-
-        // And here, we see obscure linker flags #45. On windows, it has been
-        // found to be necessary to have this flag to compile liblibc.
-        //
-        // First a bit of background. On Windows, the file format is not ELF,
-        // but COFF (at least according to LLVM). COFF doesn't officially allow
-        // for section names over 8 characters, apparently. Our metadata
-        // section, ".note.rustc", you'll note is over 8 characters.
-        //
-        // On more recent versions of gcc on mingw, apparently the section name
-        // is *not* truncated, but rather stored elsewhere in a separate lookup
-        // table. On older versions of gcc, they apparently always truncated the
-        // section names (at least in some cases). Truncating the section name
-        // actually creates "invalid" objects [1] [2], but only for some
-        // introspection tools, not in terms of whether it can be loaded.
-        //
-        // Long story short, passing this flag forces the linker to *not*
-        // truncate section names (so we can find the metadata section after
-        // it's compiled). The real kicker is that rust compiled just fine on
-        // windows for quite a long time *without* this flag, so I have no idea
-        // why it suddenly started failing for liblibc. Regardless, we
-        // definitely don't want section name truncation, so we're keeping this
-        // flag for windows.
-        //
-        // [1] - https://sourceware.org/bugzilla/show_bug.cgi?id=13130
-        // [2] - https://code.google.com/p/go/issues/detail?id=2139
-        cmd.arg("-Wl,--enable-long-section-names");
-
-        // Always enable DEP (NX bit) when it is available
-        cmd.arg("-Wl,--nxcompat");
-
-        // Mark all dynamic libraries and executables as compatible with ASLR
-        // FIXME #16514: ASLR is disabled on Windows due to MinGW-w64 bugs:
-        // FIXME #17098: ASLR breaks gdb on Windows
-        // FIXME #17684: ASLR breaks thread-local storage on Windows
-        //cmd.arg("-Wl,--dynamicbase");
-
-        // Mark all dynamic libraries and executables as compatible with the larger 4GiB address
-        // space available to x86 Windows binaries on x86_64.
-        if sess.targ_cfg.arch == abi::X86 {
-            cmd.arg("-Wl,--large-address-aware");
-        }
+    // We want to prevent the compiler from accidentally leaking in any system
+    // libraries, so we explicitly ask gcc to not link to any libraries by
+    // default. Note that this does not happen for windows because windows pulls
+    // in some large number of libraries and I couldn't quite figure out which
+    // subset we wanted.
+    if !t.options.is_like_windows {
+        cmd.arg("-nodefaultlibs");
     }
 
-    if sess.targ_cfg.os == abi::OsAndroid {
-        // Many of the symbols defined in compiler-rt are also defined in libgcc.
-        // Android linker doesn't like that by default.
-        cmd.arg("-Wl,--allow-multiple-definition");
+    // Mark all dynamic libraries and executables as compatible with ASLR
+    // FIXME #17098: ASLR breaks gdb
+    if t.options.is_like_windows && sess.opts.debuginfo == NoDebugInfo {
+        // cmd.arg("-Wl,--dynamicbase");
     }
 
     // Take careful note of the ordering of the arguments we pass to the linker
@@ -1063,7 +999,7 @@ fn link_args(cmd: &mut Command,
 
     if dylib {
         // On mac we need to tell the linker to let this library be rpathed
-        if sess.targ_cfg.os == abi::OsMacos {
+        if sess.target.target.options.is_like_osx {
             cmd.args(["-dynamiclib", "-Wl,-dylib"]);
 
             if sess.opts.cg.rpath {
@@ -1076,18 +1012,6 @@ fn link_args(cmd: &mut Command,
         }
     }
 
-    if sess.targ_cfg.os == abi::OsFreebsd {
-        cmd.args(["-L/usr/local/lib",
-                  "-L/usr/local/lib/gcc46",
-                  "-L/usr/local/lib/gcc44"]);
-    }
-    else if sess.targ_cfg.os == abi::OsDragonfly {
-        cmd.args(["-L/usr/local/lib",
-                  "-L/usr/lib/gcc47",
-                  "-L/usr/lib/gcc44"]);
-    }
-
-
     // 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
@@ -1103,27 +1027,20 @@ fn link_args(cmd: &mut Command,
             path
         };
         let rpath_config = RPathConfig {
-            os: sess.targ_cfg.os,
             used_crates: sess.cstore.get_used_crates(cstore::RequireDynamic),
             out_filename: out_filename.clone(),
+            has_rpath: sess.target.target.options.has_rpath,
+            is_like_osx: sess.target.target.options.is_like_osx,
             get_install_prefix_lib_path: get_install_prefix_lib_path,
             realpath: ::util::fs::realpath
         };
         cmd.args(rpath::get_rpath_flags(rpath_config).as_slice());
     }
 
-    // compiler-rt contains implementations of low-level LLVM helpers. This is
-    // used to resolve symbols from the object file we just created, as well as
-    // any system static libraries that may be expecting gcc instead. Most
-    // symbols in libgcc also appear in compiler-rt.
-    //
-    // This is the end of the command line, so this library is used to resolve
-    // *all* undefined symbols in all other libraries, and this is intentional.
-    cmd.arg("-lcompiler-rt");
-
     // Finally add all the linker arguments provided on the command line along
     // with any #[link_args] attributes found inside the crate
-    cmd.args(sess.opts.cg.link_args.as_slice());
+    let empty = Vec::new();
+    cmd.args(sess.opts.cg.link_args.as_ref().unwrap_or(&empty).as_slice());
     cmd.args(used_link_args.as_slice());
 }
 
@@ -1152,8 +1069,7 @@ fn add_local_native_libraries(cmd: &mut Command, sess: &Session) {
     // For those that support this, we ensure we pass the option if the library
     // was flagged "static" (most defaults are dynamic) to ensure that if
     // libfoo.a and libfoo.so both exist that the right one is chosen.
-    let takes_hints = sess.targ_cfg.os != abi::OsMacos &&
-                      sess.targ_cfg.os != abi::OsiOS;
+    let takes_hints = !sess.target.target.options.is_like_osx;
 
     let libs = sess.cstore.get_used_libraries();
     let libs = libs.borrow();
@@ -1184,7 +1100,8 @@ fn add_local_native_libraries(cmd: &mut Command, sess: &Session) {
             // -force_load is the OSX equivalent of --whole-archive, but it
             // involves passing the full path to the library to link.
             let lib = archive::find_library(l.as_slice(),
-                                            sess.targ_cfg.os,
+                                            sess.target.target.options.staticlib_prefix.as_slice(),
+                                            sess.target.target.options.staticlib_suffix.as_slice(),
                                             search_path.as_slice(),
                                             &sess.diagnostic().handler);
             let mut v = b"-Wl,-force_load,".to_vec();
@@ -1257,7 +1174,7 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session,
 
     // Converts a library file-stem into a cc -l argument
     fn unlib<'a>(config: &config::Config, stem: &'a [u8]) -> &'a [u8] {
-        if stem.starts_with("lib".as_bytes()) && config.os != abi::OsWindows {
+        if stem.starts_with("lib".as_bytes()) && !config.target.options.is_like_windows {
             stem[3..]
         } else {
             stem
@@ -1315,7 +1232,8 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session,
                     handler: handler,
                     dst: dst.clone(),
                     lib_search_paths: archive_search_paths(sess),
-                    os: sess.targ_cfg.os,
+                    slib_prefix: sess.target.target.options.staticlib_prefix.clone(),
+                    slib_suffix: sess.target.target.options.staticlib_suffix.clone(),
                     maybe_ar_prog: sess.opts.cg.ar.clone()
                 };
                 let mut archive = Archive::open(config);
@@ -1342,7 +1260,7 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session,
         if !dir.is_empty() { cmd.arg("-L").arg(dir); }
 
         let mut v = "-l".as_bytes().to_vec();
-        v.push_all(unlib(&sess.targ_cfg, cratepath.filestem().unwrap()));
+        v.push_all(unlib(&sess.target, cratepath.filestem().unwrap()));
         cmd.arg(v.as_slice());
     }
 }
diff --git a/src/librustc/back/write.rs b/src/librustc/back/write.rs
index 031fc731f41..a869db9eb6b 100644
--- a/src/librustc/back/write.rs
+++ b/src/librustc/back/write.rs
@@ -18,7 +18,6 @@ use llvm;
 use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef};
 use llvm::SMDiagnosticRef;
 use util::common::time;
-use syntax::abi;
 use syntax::codemap;
 use syntax::diagnostic;
 use syntax::diagnostic::{Emitter, Handler, Level, mk_handler};
@@ -150,20 +149,8 @@ impl Emitter for SharedEmitter {
 // Note that without those flags various linking errors might
 // arise as some of intrinsics are converted into function calls
 // and nobody provides implementations those functions
-fn target_feature<'a>(sess: &'a Session) -> &'a str {
-    match sess.targ_cfg.os {
-        abi::OsAndroid => {
-            if "" == sess.opts.cg.target_feature.as_slice() {
-                "+v7"
-            } else {
-                sess.opts.cg.target_feature.as_slice()
-            }
-        },
-        abi::OsiOS if sess.targ_cfg.arch == abi::Arm => {
-            "+v7,+thumb2,+vfp3,+neon"
-        },
-        _ => sess.opts.cg.target_feature.as_slice()
-    }
+fn target_feature(sess: &Session) -> String {
+    format!("{},{}", sess.target.target.options.features, sess.opts.cg.target_feature)
 }
 
 fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel {
@@ -176,7 +163,11 @@ fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel {
 }
 
 fn create_target_machine(sess: &Session) -> TargetMachineRef {
-    let reloc_model = match sess.opts.cg.relocation_model.as_slice() {
+    let reloc_model_arg = match sess.opts.cg.relocation_model {
+        Some(ref s) => s.as_slice(),
+        None => sess.target.target.options.relocation_model.as_slice()
+    };
+    let reloc_model = match reloc_model_arg {
         "pic" => llvm::RelocPIC,
         "static" => llvm::RelocStatic,
         "default" => llvm::RelocDefault,
@@ -195,22 +186,22 @@ fn create_target_machine(sess: &Session) -> TargetMachineRef {
     let use_softfp = sess.opts.cg.soft_float;
 
     // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a parameter.
-    // FIXME: #11954: mac64 unwinding may not work with fp elim
     let no_fp_elim = (sess.opts.debuginfo != NoDebugInfo) ||
-                     (sess.targ_cfg.os == abi::OsMacos &&
-                      sess.targ_cfg.arch == abi::X86_64);
+                     !sess.target.target.options.eliminate_frame_pointer;
 
     let any_library = sess.crate_types.borrow().iter().any(|ty| {
         *ty != config::CrateTypeExecutable
     });
 
-    // OSX has -dead_strip, which doesn't rely on ffunction_sections
-    // FIXME(#13846) this should be enabled for windows
-    let ffunction_sections = sess.targ_cfg.os != abi::OsMacos &&
-                             sess.targ_cfg.os != abi::OsWindows;
+    let ffunction_sections = sess.target.target.options.function_sections;
     let fdata_sections = ffunction_sections;
 
-    let code_model = match sess.opts.cg.code_model.as_slice() {
+    let code_model_arg = match sess.opts.cg.code_model {
+        Some(ref s) => s.as_slice(),
+        None => sess.target.target.options.code_model.as_slice()
+    };
+
+    let code_model = match code_model_arg {
         "default" => llvm::CodeModelDefault,
         "small" => llvm::CodeModelSmall,
         "kernel" => llvm::CodeModelKernel,
@@ -226,11 +217,15 @@ fn create_target_machine(sess: &Session) -> TargetMachineRef {
         }
     };
 
-    let triple = sess.targ_cfg.target_strs.target_triple.as_slice();
+    let triple = sess.target.target.llvm_target.as_slice();
 
     let tm = unsafe {
-            triple.with_c_str(|t| {
-            sess.opts.cg.target_cpu.as_slice().with_c_str(|cpu| {
+        triple.with_c_str(|t| {
+            let cpu = match sess.opts.cg.target_cpu {
+                Some(ref s) => s.as_slice(),
+                None => sess.target.target.options.cpu.as_slice()
+            };
+            cpu.with_c_str(|cpu| {
                 target_feature(sess).with_c_str(|features| {
                     llvm::LLVMRustCreateTargetMachine(
                         t, cpu, features,
@@ -692,7 +687,7 @@ pub fn run_passes(sess: &Session,
         // the desired path.  This will give the correct behavior whether or
         // not GCC adds --force-exe-suffix.
         let windows_output_path =
-            if sess.targ_cfg.os == abi::OsWindows {
+            if sess.target.target.options.is_like_windows {
                 Some(output_path.with_extension("o.exe"))
             } else {
                 None
@@ -701,7 +696,7 @@ pub fn run_passes(sess: &Session,
         let pname = get_cc_prog(sess);
         let mut cmd = Command::new(pname.as_slice());
 
-        cmd.args(sess.targ_cfg.target_strs.cc_args.as_slice());
+        cmd.args(sess.target.target.options.pre_link_args.as_slice());
         cmd.arg("-nostdlib");
 
         for index in range(0, trans.modules.len()) {
@@ -712,6 +707,8 @@ pub fn run_passes(sess: &Session,
            .arg("-o")
            .arg(windows_output_path.as_ref().unwrap_or(output_path));
 
+        cmd.args(sess.target.target.options.post_link_args.as_slice());
+
         if (sess.opts.debugging_opts & config::PRINT_LINK_ARGS) != 0 {
             println!("{}", &cmd);
         }
diff --git a/src/librustc/driver/config.rs b/src/librustc/driver/config.rs
index 10c40a32da6..8c1d7c839ac 100644
--- a/src/librustc/driver/config.rs
+++ b/src/librustc/driver/config.rs
@@ -17,17 +17,15 @@ use driver::session::Session;
 
 use back;
 use back::write;
-use back::target_strs;
-use back::{arm, x86, x86_64, mips, mipsel};
+use rustc_back::target::Target;
 use lint;
 use metadata::cstore;
 
-use syntax::abi;
 use syntax::ast;
 use syntax::ast::{IntTy, UintTy};
 use syntax::attr;
 use syntax::attr::AttrMetaMethods;
-use syntax::diagnostic::{ColorConfig, Auto, Always, Never};
+use syntax::diagnostic::{ColorConfig, Auto, Always, Never, SpanHandler};
 use syntax::parse;
 use syntax::parse::token::InternedString;
 
@@ -41,9 +39,7 @@ use std::fmt;
 use llvm;
 
 pub struct Config {
-    pub os: abi::Os,
-    pub arch: abi::Architecture,
-    pub target_strs: target_strs::t,
+    pub target: Target,
     pub int_type: IntTy,
     pub uint_type: UintTy,
 }
@@ -291,6 +287,13 @@ macro_rules! cgoptions(
             }
         }
 
+        fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
+            match v {
+                Some(..) => false,
+                None => { *slot = Some(true); true }
+            }
+        }
+
         fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
             match v {
                 Some(s) => { *slot = Some(s.to_string()); true },
@@ -318,6 +321,18 @@ macro_rules! cgoptions(
             }
         }
 
+        fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
+                      -> bool {
+            match v {
+                Some(s) => {
+                    let v = s.words().map(|s| s.to_string()).collect();
+                    *slot = Some(v);
+                    true
+                },
+                None => false,
+            }
+        }
+
         fn parse_uint(slot: &mut uint, v: Option<&str>) -> bool {
             use std::from_str::FromStr;
             match v.and_then(FromStr::from_str) {
@@ -351,11 +366,11 @@ cgoptions!(
         "tool to assemble archives with"),
     linker: Option<String> = (None, parse_opt_string,
         "system linker to link outputs with"),
-    link_args: Vec<String> = (Vec::new(), parse_list,
+    link_args: Option<Vec<String>> = (None, parse_opt_list,
         "extra arguments to pass to the linker (space separated)"),
     lto: bool = (false, parse_bool,
         "perform LLVM link-time optimizations"),
-    target_cpu: String = ("generic".to_string(), parse_string,
+    target_cpu: Option<String> = (None, parse_opt_string,
         "select target processor (llc -mcpu=help for details)"),
     target_feature: String = ("".to_string(), parse_string,
         "target specific attributes (llc -mattr=help for details)"),
@@ -379,11 +394,11 @@ cgoptions!(
         "prefer dynamic linking to static linking"),
     no_integrated_as: bool = (false, parse_bool,
         "use an external assembler rather than LLVM's integrated one"),
-    no_redzone: bool = (false, parse_bool,
+    no_redzone: Option<bool> = (None, parse_opt_bool,
         "disable the use of the redzone"),
-    relocation_model: String = ("pic".to_string(), parse_string,
+    relocation_model: Option<String> = (None, parse_opt_string,
          "choose the relocation model to use (llc -relocation-model for details)"),
-    code_model: String = ("default".to_string(), parse_string,
+    code_model: Option<String> = (None, parse_opt_string,
          "choose the code model to use (llc -code-model for details)"),
     metadata: Vec<String> = (Vec::new(), parse_list,
          "metadata to mangle symbol names with"),
@@ -437,40 +452,27 @@ pub fn default_lib_output() -> CrateType {
 }
 
 pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
-    let tos = match sess.targ_cfg.os {
-        abi::OsWindows =>   InternedString::new("windows"),
-        abi::OsMacos =>     InternedString::new("macos"),
-        abi::OsLinux =>     InternedString::new("linux"),
-        abi::OsAndroid =>   InternedString::new("android"),
-        abi::OsFreebsd =>   InternedString::new("freebsd"),
-        abi::OsDragonfly => InternedString::new("dragonfly"),
-        abi::OsiOS =>       InternedString::new("ios"),
-    };
+    use syntax::parse::token::intern_and_get_ident as intern;
 
-    // ARM is bi-endian, however using NDK seems to default
-    // to little-endian unless a flag is provided.
-    let (end,arch,wordsz) = match sess.targ_cfg.arch {
-        abi::X86 =>    ("little", "x86",    "32"),
-        abi::X86_64 => ("little", "x86_64", "64"),
-        abi::Arm =>    ("little", "arm",    "32"),
-        abi::Mips =>   ("big",    "mips",   "32"),
-        abi::Mipsel => ("little", "mipsel", "32")
-    };
+    let end = sess.target.target.target_endian.as_slice();
+    let arch = sess.target.target.arch.as_slice();
+    let wordsz = sess.target.target.target_word_size.as_slice();
+    let os = sess.target.target.target_os.as_slice();
 
-    let fam = match sess.targ_cfg.os {
-        abi::OsWindows => InternedString::new("windows"),
-        _ => InternedString::new("unix")
+    let fam = match sess.target.target.options.is_like_windows {
+        true  => InternedString::new("windows"),
+        false => InternedString::new("unix")
     };
 
     let mk = attr::mk_name_value_item_str;
     return vec!(// Target bindings.
          attr::mk_word_item(fam.clone()),
-         mk(InternedString::new("target_os"), tos),
+         mk(InternedString::new("target_os"), intern(os)),
          mk(InternedString::new("target_family"), fam),
-         mk(InternedString::new("target_arch"), InternedString::new(arch)),
-         mk(InternedString::new("target_endian"), InternedString::new(end)),
+         mk(InternedString::new("target_arch"), intern(arch)),
+         mk(InternedString::new("target_endian"), intern(end)),
          mk(InternedString::new("target_word_size"),
-            InternedString::new(wordsz))
+            intern(wordsz))
     );
 }
 
@@ -495,78 +497,23 @@ pub fn build_configuration(sess: &Session) -> ast::CrateConfig {
     v
 }
 
-pub fn get_os(triple: &str) -> Option<abi::Os> {
-    for &(name, os) in os_names.iter() {
-        if triple.contains(name) { return Some(os) }
-    }
-    None
-}
-#[allow(non_upper_case_globals)]
-static os_names : &'static [(&'static str, abi::Os)] = &[
-    ("mingw32",   abi::OsWindows),
-    ("win32",     abi::OsWindows),
-    ("windows",   abi::OsWindows),
-    ("darwin",    abi::OsMacos),
-    ("android",   abi::OsAndroid),
-    ("linux",     abi::OsLinux),
-    ("freebsd",   abi::OsFreebsd),
-    ("dragonfly", abi::OsDragonfly),
-    ("ios",       abi::OsiOS)];
-
-pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
-    for &(arch, abi) in architecture_abis.iter() {
-        if triple.contains(arch) { return Some(abi) }
+pub fn build_target_config(opts: &Options, sp: &SpanHandler) -> Config {
+    let target = match Target::search(opts.target_triple.as_slice()) {
+        Ok(t) => t,
+        Err(e) => {
+            sp.handler().fatal((format!("Error loading target specification: {}", e)).as_slice());
     }
-    None
-}
-#[allow(non_upper_case_globals)]
-static architecture_abis : &'static [(&'static str, abi::Architecture)] = &[
-    ("i386",   abi::X86),
-    ("i486",   abi::X86),
-    ("i586",   abi::X86),
-    ("i686",   abi::X86),
-    ("i786",   abi::X86),
-
-    ("x86_64", abi::X86_64),
-
-    ("arm",    abi::Arm),
-    ("xscale", abi::Arm),
-    ("thumb",  abi::Arm),
-
-    ("mipsel", abi::Mipsel),
-    ("mips",   abi::Mips)];
-
-pub fn build_target_config(sopts: &Options) -> Config {
-    let os = match get_os(sopts.target_triple.as_slice()) {
-      Some(os) => os,
-      None => early_error("unknown operating system")
-    };
-    let arch = match get_arch(sopts.target_triple.as_slice()) {
-      Some(arch) => arch,
-      None => {
-          early_error(format!("unknown architecture: {}",
-                              sopts.target_triple.as_slice()).as_slice())
-      }
-    };
-    let (int_type, uint_type) = match arch {
-      abi::X86 => (ast::TyI32, ast::TyU32),
-      abi::X86_64 => (ast::TyI64, ast::TyU64),
-      abi::Arm => (ast::TyI32, ast::TyU32),
-      abi::Mips => (ast::TyI32, ast::TyU32),
-      abi::Mipsel => (ast::TyI32, ast::TyU32)
     };
-    let target_triple = sopts.target_triple.clone();
-    let target_strs = match arch {
-      abi::X86 => x86::get_target_strs(target_triple, os),
-      abi::X86_64 => x86_64::get_target_strs(target_triple, os),
-      abi::Arm => arm::get_target_strs(target_triple, os),
-      abi::Mips => mips::get_target_strs(target_triple, os),
-      abi::Mipsel => mipsel::get_target_strs(target_triple, os)
+
+    let (int_type, uint_type) = match target.target_word_size.as_slice() {
+        "32" => (ast::TyI32, ast::TyU32),
+        "64" => (ast::TyI64, ast::TyU64),
+        w    => sp.handler().fatal((format!("target specification was invalid: unrecognized \
+                                            target-word-size {}", w)).as_slice())
     };
+
     Config {
-        os: os,
-        arch: arch,
-        target_strs: target_strs,
+        target: target,
         int_type: int_type,
         uint_type: uint_type,
     }
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index d3ed0dbd99e..d347f113af3 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -749,8 +749,8 @@ pub fn collect_crate_types(session: &Session,
 
         if !res {
             session.warn(format!("dropping unsupported crate type `{}` \
-                                   for target os `{}`",
-                                 *crate_type, session.targ_cfg.os).as_slice());
+                                   for target `{}`",
+                                 *crate_type, session.opts.target_triple).as_slice());
         }
 
         res
diff --git a/src/librustc/driver/mod.rs b/src/librustc/driver/mod.rs
index 028d0ec607a..7715f0e10f5 100644
--- a/src/librustc/driver/mod.rs
+++ b/src/librustc/driver/mod.rs
@@ -435,7 +435,7 @@ pub fn early_warn(msg: &str) {
 
 pub fn list_metadata(sess: &Session, path: &Path,
                      out: &mut io::Writer) -> io::IoResult<()> {
-    metadata::loader::list_file_metadata(sess.targ_cfg.os, path, out)
+    metadata::loader::list_file_metadata(sess.target.target.options.is_like_osx, path, out)
 }
 
 /// Run a procedure which will detect failures in the compiler and print nicer
diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs
index f8e778ce15f..57c65ccebc5 100644
--- a/src/librustc/driver/session.rs
+++ b/src/librustc/driver/session.rs
@@ -32,7 +32,7 @@ use std::cell::{Cell, RefCell};
 // Represents the data associated with a compilation
 // session for a single crate.
 pub struct Session {
-    pub targ_cfg: config::Config,
+    pub target: config::Config,
     pub opts: config::Options,
     pub cstore: CStore,
     pub parse_sess: ParseSess,
@@ -219,7 +219,7 @@ pub fn build_session_(sopts: config::Options,
                       local_crate_source_file: Option<Path>,
                       span_diagnostic: diagnostic::SpanHandler)
                       -> Session {
-    let target_cfg = config::build_target_config(&sopts);
+    let target_cfg = config::build_target_config(&sopts, &span_diagnostic);
     let p_s = parse::new_parse_sess_special_handler(span_diagnostic);
     let default_sysroot = match sopts.maybe_sysroot {
         Some(_) => None,
@@ -236,7 +236,7 @@ pub fn build_session_(sopts: config::Options,
     );
 
     let sess = Session {
-        targ_cfg: target_cfg,
+        target: target_cfg,
         opts: sopts,
         cstore: CStore::new(token::get_ident_interner()),
         parse_sess: p_s,
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 0c26981c2a0..f72b1262bdf 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -180,8 +180,8 @@ impl LintPass for TypeLimits {
 
                 if is_shift_binop(binop) {
                     let opt_ty_bits = match ty::get(ty::expr_ty(cx.tcx, &**l)).sty {
-                        ty::ty_int(t) => Some(int_ty_bits(t, cx.sess().targ_cfg.int_type)),
-                        ty::ty_uint(t) => Some(uint_ty_bits(t, cx.sess().targ_cfg.uint_type)),
+                        ty::ty_int(t) => Some(int_ty_bits(t, cx.sess().target.int_type)),
+                        ty::ty_uint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)),
                         _ => None
                     };
 
@@ -210,7 +210,7 @@ impl LintPass for TypeLimits {
                             ast::LitInt(v, ast::SignedIntLit(_, ast::Plus)) |
                             ast::LitInt(v, ast::UnsuffixedIntLit(ast::Plus)) => {
                                 let int_type = if t == ast::TyI {
-                                    cx.sess().targ_cfg.int_type
+                                    cx.sess().target.int_type
                                 } else { t };
                                 let (min, max) = int_ty_range(int_type);
                                 let negative = self.negated_expr_id == e.id;
@@ -227,7 +227,7 @@ impl LintPass for TypeLimits {
                     },
                     ty::ty_uint(t) => {
                         let uint_type = if t == ast::TyU {
-                            cx.sess().targ_cfg.uint_type
+                            cx.sess().target.uint_type
                         } else { t };
                         let (min, max) = uint_ty_range(uint_type);
                         let lit_val: u64 = match lit.node {
diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs
index 797bc5814fc..91d7eeaf8f2 100644
--- a/src/librustc/metadata/creader.rs
+++ b/src/librustc/metadata/creader.rs
@@ -14,7 +14,7 @@
 
 use back::svh::Svh;
 use driver::session::Session;
-use driver::{driver, config};
+use driver::driver;
 use metadata::cstore;
 use metadata::cstore::{CStore, CrateSource};
 use metadata::decoder;
@@ -237,6 +237,9 @@ fn visit_item(e: &Env, i: &ast::Item) {
                             Some(k) => {
                                 if k.equiv(&("static")) {
                                     cstore::NativeStatic
+                                } else if e.sess.target.target.options.is_like_osx
+                                          && k.equiv(&("framework")) {
+                                    cstore::NativeFramework
                                 } else if k.equiv(&("framework")) {
                                     cstore::NativeFramework
                                 } else {
@@ -285,8 +288,7 @@ fn register_native_lib(sess: &Session, span: Option<Span>, name: String,
         }
         return
     }
-    let is_osx = sess.targ_cfg.os == abi::OsMacos ||
-                 sess.targ_cfg.os == abi::OsiOS;
+    let is_osx = sess.target.target.options.is_like_osx;
     if kind == cstore::NativeFramework && !is_osx {
         let msg = "native frameworks are only available on OSX targets";
         match span {
@@ -400,8 +402,7 @@ fn resolve_crate<'a>(e: &mut Env,
                 crate_name: name,
                 hash: hash.map(|a| &*a),
                 filesearch: e.sess.target_filesearch(),
-                os: e.sess.targ_cfg.os,
-                triple: e.sess.targ_cfg.target_strs.target_triple.as_slice(),
+                triple: e.sess.opts.target_triple.as_slice(),
                 root: root,
                 rejected_via_hash: vec!(),
                 rejected_via_triple: vec!(),
@@ -451,10 +452,9 @@ impl<'a> PluginMetadataReader<'a> {
 
     pub fn read_plugin_metadata(&mut self, krate: &ast::ViewItem) -> PluginMetadata {
         let info = extract_crate_info(&self.env, krate).unwrap();
-        let target_triple = self.env.sess.targ_cfg.target_strs.target_triple.as_slice();
+        let target_triple = self.env.sess.opts.target_triple.as_slice();
         let is_cross = target_triple != driver::host_triple();
         let mut should_link = info.should_link && !is_cross;
-        let os = config::get_os(driver::host_triple()).unwrap();
         let mut load_ctxt = loader::Context {
             sess: self.env.sess,
             span: krate.span,
@@ -463,7 +463,6 @@ impl<'a> PluginMetadataReader<'a> {
             hash: None,
             filesearch: self.env.sess.host_filesearch(),
             triple: driver::host_triple(),
-            os: os,
             root: &None,
             rejected_via_hash: vec!(),
             rejected_via_triple: vec!(),
@@ -475,7 +474,6 @@ impl<'a> PluginMetadataReader<'a> {
                 // try loading from target crates (only valid if there are
                 // no syntax extensions)
                 load_ctxt.triple = target_triple;
-                load_ctxt.os = self.env.sess.targ_cfg.os;
                 load_ctxt.filesearch = self.env.sess.target_filesearch();
                 let lib = load_ctxt.load_library_crate();
                 if decoder::get_plugin_registrar_fn(lib.metadata.as_slice()).is_some() {
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index fd389c1f314..da7e78d272f 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -2071,8 +2071,7 @@ fn encode_metadata_inner(wr: &mut SeekableMemWriter, parms: EncodeParams, krate:
     encode_crate_name(&mut rbml_w, ecx.link_meta.crate_name.as_slice());
     encode_crate_triple(&mut rbml_w,
                         tcx.sess
-                           .targ_cfg
-                           .target_strs
+                           .opts
                            .target_triple
                            .as_slice());
     encode_hash(&mut rbml_w, &ecx.link_meta.crate_hash);
diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs
index 738eeaae6a5..f46af9088d8 100644
--- a/src/librustc/metadata/loader.rs
+++ b/src/librustc/metadata/loader.rs
@@ -222,7 +222,6 @@ use metadata::cstore::{MetadataBlob, MetadataVec, MetadataArchive};
 use metadata::decoder;
 use metadata::encoder;
 use metadata::filesearch::{FileSearch, FileMatches, FileDoesntMatch};
-use syntax::abi;
 use syntax::codemap::Span;
 use syntax::diagnostic::SpanHandler;
 use util::fs;
@@ -240,24 +239,6 @@ use std::collections::hash_map::{Occupied, Vacant};
 use flate;
 use time;
 
-pub const MACOS_DLL_PREFIX: &'static str = "lib";
-pub const MACOS_DLL_SUFFIX: &'static str = ".dylib";
-
-pub const WIN32_DLL_PREFIX: &'static str = "";
-pub const WIN32_DLL_SUFFIX: &'static str = ".dll";
-
-pub const LINUX_DLL_PREFIX: &'static str = "lib";
-pub const LINUX_DLL_SUFFIX: &'static str = ".so";
-
-pub const FREEBSD_DLL_PREFIX: &'static str = "lib";
-pub const FREEBSD_DLL_SUFFIX: &'static str = ".so";
-
-pub const DRAGONFLY_DLL_PREFIX: &'static str = "lib";
-pub const DRAGONFLY_DLL_SUFFIX: &'static str = ".so";
-
-pub const ANDROID_DLL_PREFIX: &'static str = "lib";
-pub const ANDROID_DLL_SUFFIX: &'static str = ".so";
-
 pub struct CrateMismatch {
     path: Path,
     got: String,
@@ -270,7 +251,6 @@ pub struct Context<'a> {
     pub crate_name: &'a str,
     pub hash: Option<&'a Svh>,
     pub triple: &'a str,
-    pub os: abi::Os,
     pub filesearch: FileSearch<'a>,
     pub root: &'a Option<CratePaths>,
     pub rejected_via_hash: Vec<CrateMismatch>,
@@ -387,9 +367,7 @@ impl<'a> Context<'a> {
         let dypair = self.dylibname();
 
         // want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
-        let dylib_prefix = dypair.map(|(prefix, _)| {
-            format!("{}{}", prefix, self.crate_name)
-        });
+        let dylib_prefix = format!("{}{}", dypair.ref0(), self.crate_name);
         let rlib_prefix = format!("lib{}", self.crate_name);
 
         let mut candidates = HashMap::new();
@@ -416,13 +394,9 @@ impl<'a> Context<'a> {
                     file.ends_with(".rlib") {
                 (file.slice(rlib_prefix.len(), file.len() - ".rlib".len()),
                  true)
-            } else if dypair.map_or(false, |(_, suffix)| {
-                file.starts_with(dylib_prefix.as_ref().unwrap().as_slice()) &&
-                file.ends_with(suffix)
-            }) {
-                let (_, suffix) = dypair.unwrap();
-                let dylib_prefix = dylib_prefix.as_ref().unwrap().as_slice();
-                (file.slice(dylib_prefix.len(), file.len() - suffix.len()),
+            } else if file.starts_with(dylib_prefix.as_slice()) &&
+                      file.ends_with(dypair.ref1().as_slice()) {
+                (file.slice(dylib_prefix.len(), file.len() - dypair.ref1().len()),
                  false)
             } else {
                 return FileDoesntMatch
@@ -530,7 +504,8 @@ impl<'a> Context<'a> {
 
         for lib in m.into_iter() {
             info!("{} reading metadata from: {}", flavor, lib.display());
-            let metadata = match get_metadata_section(self.os, &lib) {
+            let metadata = match get_metadata_section(self.sess.target.target.options.is_like_osx,
+                                                      &lib) {
                 Ok(blob) => {
                     if self.crate_matches(blob.as_slice(), &lib) {
                         blob
@@ -617,16 +592,9 @@ impl<'a> Context<'a> {
 
     // Returns the corresponding (prefix, suffix) that files need to have for
     // dynamic libraries
-    fn dylibname(&self) -> Option<(&'static str, &'static str)> {
-        match self.os {
-            abi::OsWindows => Some((WIN32_DLL_PREFIX, WIN32_DLL_SUFFIX)),
-            abi::OsMacos => Some((MACOS_DLL_PREFIX, MACOS_DLL_SUFFIX)),
-            abi::OsLinux => Some((LINUX_DLL_PREFIX, LINUX_DLL_SUFFIX)),
-            abi::OsAndroid => Some((ANDROID_DLL_PREFIX, ANDROID_DLL_SUFFIX)),
-            abi::OsFreebsd => Some((FREEBSD_DLL_PREFIX, FREEBSD_DLL_SUFFIX)),
-            abi::OsDragonfly => Some((DRAGONFLY_DLL_PREFIX, DRAGONFLY_DLL_SUFFIX)),
-            abi::OsiOS => None,
-        }
+    fn dylibname(&self) -> (String, String) {
+        let t = &self.sess.target.target;
+        (t.options.dll_prefix.clone(), t.options.dll_suffix.clone())
     }
 
     fn find_commandline_library(&mut self) -> Option<Library> {
@@ -660,13 +628,9 @@ impl<'a> Context<'a> {
                 if file.starts_with("lib") && file.ends_with(".rlib") {
                     return true
                 } else {
-                    match dylibname {
-                        Some((prefix, suffix)) => {
-                            if file.starts_with(prefix) && file.ends_with(suffix) {
-                                return true
-                            }
-                        }
-                        None => {}
+                    let (ref prefix, ref suffix) = dylibname;
+                    if file.starts_with(prefix.as_slice()) && file.ends_with(suffix.as_slice()) {
+                        return true
                     }
                 }
                 sess.err(format!("extern location for {} is of an unknown type: {}",
@@ -726,15 +690,15 @@ impl ArchiveMetadata {
 }
 
 // Just a small wrapper to time how long reading metadata takes.
-fn get_metadata_section(os: abi::Os, filename: &Path) -> Result<MetadataBlob, String> {
+fn get_metadata_section(is_osx: bool, filename: &Path) -> Result<MetadataBlob, String> {
     let start = time::precise_time_ns();
-    let ret = get_metadata_section_imp(os, filename);
+    let ret = get_metadata_section_imp(is_osx, filename);
     info!("reading {} => {}ms", filename.filename_display(),
            (time::precise_time_ns() - start) / 1000000);
     return ret;
 }
 
-fn get_metadata_section_imp(os: abi::Os, filename: &Path) -> Result<MetadataBlob, String> {
+fn get_metadata_section_imp(is_osx: bool, filename: &Path) -> Result<MetadataBlob, String> {
     if !filename.exists() {
         return Err(format!("no such file: '{}'", filename.display()));
     }
@@ -780,7 +744,7 @@ fn get_metadata_section_imp(os: abi::Os, filename: &Path) -> Result<MetadataBlob
             let name = string::raw::from_buf_len(name_buf as *const u8,
                                               name_len as uint);
             debug!("get_metadata_section: name {}", name);
-            if read_meta_section_name(os).as_slice() == name.as_slice() {
+            if read_meta_section_name(is_osx).as_slice() == name.as_slice() {
                 let cbuf = llvm::LLVMGetSectionContents(si.llsi);
                 let csz = llvm::LLVMGetSectionSize(si.llsi) as uint;
                 let mut found =
@@ -821,34 +785,26 @@ fn get_metadata_section_imp(os: abi::Os, filename: &Path) -> Result<MetadataBlob
     }
 }
 
-pub fn meta_section_name(os: abi::Os) -> Option<&'static str> {
-    match os {
-        abi::OsMacos => Some("__DATA,__note.rustc"),
-        abi::OsiOS => Some("__DATA,__note.rustc"),
-        abi::OsWindows => Some(".note.rustc"),
-        abi::OsLinux => Some(".note.rustc"),
-        abi::OsAndroid => Some(".note.rustc"),
-        abi::OsFreebsd => Some(".note.rustc"),
-        abi::OsDragonfly => Some(".note.rustc"),
+pub fn meta_section_name(is_osx: bool) -> &'static str {
+    if is_osx {
+        "__DATA,__note.rustc"
+    } else {
+        ".note.rustc"
     }
 }
 
-pub fn read_meta_section_name(os: abi::Os) -> &'static str {
-    match os {
-        abi::OsMacos => "__note.rustc",
-        abi::OsiOS => unreachable!(),
-        abi::OsWindows => ".note.rustc",
-        abi::OsLinux => ".note.rustc",
-        abi::OsAndroid => ".note.rustc",
-        abi::OsFreebsd => ".note.rustc",
-        abi::OsDragonfly => ".note.rustc"
+pub fn read_meta_section_name(is_osx: bool) -> &'static str {
+    if is_osx {
+        "__note.rustc"
+    } else {
+        ".note.rustc"
     }
 }
 
 // A diagnostic function for dumping crate metadata to an output stream
-pub fn list_file_metadata(os: abi::Os, path: &Path,
+pub fn list_file_metadata(is_osx: bool, path: &Path,
                           out: &mut io::Writer) -> io::IoResult<()> {
-    match get_metadata_section(os, path) {
+    match get_metadata_section(is_osx, path) {
         Ok(bytes) => decoder::list_crate_metadata(bytes.as_slice(), out),
         Err(msg) => {
             write!(out, "{}\n", msg)
diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs
index 15ca00f6a7f..0a28c93a34e 100644
--- a/src/librustc/middle/dependency_format.rs
+++ b/src/librustc/middle/dependency_format.rs
@@ -135,13 +135,13 @@ fn calculate_type(sess: &session::Session,
     sess.cstore.iter_crate_data(|cnum, data| {
         let src = sess.cstore.get_used_crate_source(cnum).unwrap();
         if src.dylib.is_some() {
-            add_library(sess, cnum, cstore::RequireDynamic, &mut formats);
             debug!("adding dylib: {}", data.name);
+            add_library(sess, cnum, cstore::RequireDynamic, &mut formats);
             let deps = csearch::get_dylib_dependency_formats(&sess.cstore, cnum);
             for &(depnum, style) in deps.iter() {
-                add_library(sess, depnum, style, &mut formats);
                 debug!("adding {}: {}", style,
                        sess.cstore.get_crate_data(depnum).name.clone());
+                add_library(sess, depnum, style, &mut formats);
             }
         }
     });
@@ -160,9 +160,9 @@ fn calculate_type(sess: &session::Session,
         let src = sess.cstore.get_used_crate_source(cnum).unwrap();
         if src.dylib.is_none() && !formats.contains_key(&cnum) {
             assert!(src.rlib.is_some());
+            debug!("adding staticlib: {}", data.name);
             add_library(sess, cnum, cstore::RequireStatic, &mut formats);
             ret[cnum as uint - 1] = Some(cstore::RequireStatic);
-            debug!("adding staticlib: {}", data.name);
         }
     });
 
diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs
index 7dbddd3f5df..d3658e89a2a 100644
--- a/src/librustc/middle/trans/adt.rs
+++ b/src/librustc/middle/trans/adt.rs
@@ -62,7 +62,6 @@ use middle::trans::type_::Type;
 use middle::trans::type_of;
 use middle::ty;
 use middle::ty::Disr;
-use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel};
 use syntax::ast;
 use syntax::attr;
 use syntax::attr::IntType;
@@ -410,14 +409,12 @@ fn range_to_inttype(cx: &CrateContext, hint: Hint, bounds: &IntBounds) -> IntTyp
             return ity;
         }
         attr::ReprExtern => {
-            attempts = match cx.sess().targ_cfg.arch {
-                X86 | X86_64 => at_least_32,
+            attempts = match cx.sess().target.target.arch.as_slice() {
                 // WARNING: the ARM EABI has two variants; the one corresponding to `at_least_32`
                 // appears to be used on Linux and NetBSD, but some systems may use the variant
                 // corresponding to `choose_shortest`.  However, we don't run on those yet...?
-                Arm => at_least_32,
-                Mips => at_least_32,
-                Mipsel => at_least_32,
+                "arm" => at_least_32,
+                _ => at_least_32,
             }
         }
         attr::ReprAny => {
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 5c9546bf212..b80425e7ac8 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -87,8 +87,7 @@ use std::cell::{Cell, RefCell};
 use std::collections::HashSet;
 use std::rc::Rc;
 use std::{i8, i16, i32, i64};
-use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel, Rust, RustCall};
-use syntax::abi::{RustIntrinsic, Abi, OsWindows};
+use syntax::abi::{Rust, RustCall, RustIntrinsic, Abi};
 use syntax::ast_util::local_def;
 use syntax::attr::AttrMetaMethods;
 use syntax::attr;
@@ -193,7 +192,8 @@ pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv,
         llvm::SetFunctionAttribute(llfn, llvm::NoReturnAttribute);
     }
 
-    if ccx.tcx().sess.opts.cg.no_redzone {
+    if ccx.tcx().sess.opts.cg.no_redzone
+        .unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) {
         llvm::SetFunctionAttribute(llfn, llvm::NoRedZoneAttribute)
     }
 
@@ -934,17 +934,16 @@ pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> Val
     let name = csearch::get_symbol(&ccx.sess().cstore, did);
     match ty::get(t).sty {
         ty::ty_bare_fn(ref fn_ty) => {
-            match fn_ty.abi.for_target(ccx.sess().targ_cfg.os,
-                                       ccx.sess().targ_cfg.arch) {
-                Some(Rust) | Some(RustCall) => {
+            match ccx.sess().target.target.adjust_abi(fn_ty.abi) {
+                Rust | RustCall => {
                     get_extern_rust_fn(ccx, t, name.as_slice(), did)
                 }
-                Some(RustIntrinsic) => {
+                RustIntrinsic => {
                     ccx.sess().bug("unexpected intrinsic in trans_external_path")
                 }
-                Some(..) | None => {
+                _ => {
                     foreign::register_foreign_item_fn(ccx, fn_ty.abi, t,
-                                                      name.as_slice(), None)
+                                                      name.as_slice())
                 }
             }
         }
@@ -1143,9 +1142,10 @@ pub fn call_lifetime_end(cx: Block, ptr: ValueRef) {
 pub fn call_memcpy(cx: Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, align: u32) {
     let _icx = push_ctxt("call_memcpy");
     let ccx = cx.ccx();
-    let key = match ccx.sess().targ_cfg.arch {
-        X86 | Arm | Mips | Mipsel => "llvm.memcpy.p0i8.p0i8.i32",
-        X86_64 => "llvm.memcpy.p0i8.p0i8.i64"
+    let key = match ccx.sess().target.target.target_word_size.as_slice() {
+        "32" => "llvm.memcpy.p0i8.p0i8.i32",
+        "64" => "llvm.memcpy.p0i8.p0i8.i64",
+        tws => panic!("Unsupported target word size for memcpy: {}", tws),
     };
     let memcpy = ccx.get_intrinsic(&key);
     let src_ptr = PointerCast(cx, src, Type::i8p(ccx));
@@ -1187,9 +1187,10 @@ fn memzero(b: &Builder, llptr: ValueRef, ty: ty::t) {
 
     let llty = type_of::type_of(ccx, ty);
 
-    let intrinsic_key = match ccx.sess().targ_cfg.arch {
-        X86 | Arm | Mips | Mipsel => "llvm.memset.p0i8.i32",
-        X86_64 => "llvm.memset.p0i8.i64"
+    let intrinsic_key = match ccx.sess().target.target.target_word_size.as_slice() {
+        "32" => "llvm.memset.p0i8.i32",
+        "64" => "llvm.memset.p0i8.i64",
+        tws => panic!("Unsupported target word size for memset: {}", tws),
     };
 
     let llintrinsicfn = ccx.get_intrinsic(&intrinsic_key);
@@ -2583,7 +2584,7 @@ pub fn create_entry_wrapper(ccx: &CrateContext,
 
         // FIXME: #16581: Marking a symbol in the executable with `dllexport`
         // linkage forces MinGW's linker to output a `.reloc` section for ASLR
-        if ccx.sess().targ_cfg.os == OsWindows {
+        if ccx.sess().target.target.options.is_like_windows {
             unsafe { llvm::LLVMRustSetDLLExportStorageClass(llfn) }
         }
 
@@ -2803,9 +2804,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
                     let abi = ccx.tcx().map.get_foreign_abi(id);
                     let ty = ty::node_id_to_type(ccx.tcx(), ni.id);
                     let name = foreign::link_name(&*ni);
-                    foreign::register_foreign_item_fn(ccx, abi, ty,
-                                                      name.get().as_slice(),
-                                                      Some(ni.span))
+                    foreign::register_foreign_item_fn(ccx, abi, ty, name.get().as_slice())
                 }
                 ast::ForeignItemStatic(..) => {
                     foreign::register_static(ccx, &*ni)
@@ -2946,8 +2945,8 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec<u8> {
     });
     unsafe {
         llvm::LLVMSetInitializer(llglobal, llconst);
-        let name = loader::meta_section_name(cx.sess().targ_cfg.os);
-        name.unwrap_or("rust_metadata").with_c_str(|buf| {
+        let name = loader::meta_section_name(cx.sess().target.target.options.is_like_osx);
+        name.with_c_str(|buf| {
             llvm::LLVMSetSection(llglobal, buf)
         });
     }
diff --git a/src/librustc/middle/trans/cabi.rs b/src/librustc/middle/trans/cabi.rs
index d419a56ec14..940964ce9af 100644
--- a/src/librustc/middle/trans/cabi.rs
+++ b/src/librustc/middle/trans/cabi.rs
@@ -17,8 +17,6 @@ use middle::trans::cabi_x86_win64;
 use middle::trans::cabi_arm;
 use middle::trans::cabi_mips;
 use middle::trans::type_::Type;
-use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel};
-use syntax::abi::{OsWindows};
 
 #[deriving(Clone, PartialEq)]
 pub enum ArgKind {
@@ -107,16 +105,16 @@ pub fn compute_abi_info(ccx: &CrateContext,
                         atys: &[Type],
                         rty: Type,
                         ret_def: bool) -> FnType {
-    match ccx.sess().targ_cfg.arch {
-        X86 => cabi_x86::compute_abi_info(ccx, atys, rty, ret_def),
-        X86_64 =>
-            if ccx.sess().targ_cfg.os == OsWindows {
-                cabi_x86_win64::compute_abi_info(ccx, atys, rty, ret_def)
-            } else {
-                cabi_x86_64::compute_abi_info(ccx, atys, rty, ret_def)
-            },
-        Arm => cabi_arm::compute_abi_info(ccx, atys, rty, ret_def),
-        Mips => cabi_mips::compute_abi_info(ccx, atys, rty, ret_def),
-        Mipsel => cabi_mips::compute_abi_info(ccx, atys, rty, ret_def),
+    match ccx.sess().target.target.arch.as_slice() {
+        "x86" => cabi_x86::compute_abi_info(ccx, atys, rty, ret_def),
+        "x86_64" => if ccx.sess().target.target.options.is_like_windows {
+            cabi_x86_win64::compute_abi_info(ccx, atys, rty, ret_def)
+        } else {
+            cabi_x86_64::compute_abi_info(ccx, atys, rty, ret_def)
+        },
+        "arm" => cabi_arm::compute_abi_info(ccx, atys, rty, ret_def),
+        "mips" => cabi_mips::compute_abi_info(ccx, atys, rty, ret_def),
+        a => ccx.sess().fatal((format!("unrecognized arch \"{}\" in target specification", a))
+                              .as_slice()),
     }
 }
diff --git a/src/librustc/middle/trans/cabi_x86.rs b/src/librustc/middle/trans/cabi_x86.rs
index b5de0ae29d4..6f8651c3e44 100644
--- a/src/librustc/middle/trans/cabi_x86.rs
+++ b/src/librustc/middle/trans/cabi_x86.rs
@@ -13,7 +13,6 @@ use middle::trans::cabi::{ArgType, FnType};
 use middle::trans::type_::Type;
 use super::common::*;
 use super::machine::*;
-use syntax::abi::{OsWindows, OsMacos, OsiOS};
 
 pub fn compute_abi_info(ccx: &CrateContext,
                         atys: &[Type],
@@ -34,19 +33,17 @@ pub fn compute_abi_info(ccx: &CrateContext,
         // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
 
         enum Strategy { RetValue(Type), RetPointer }
-        let strategy = match ccx.sess().targ_cfg.os {
-            OsWindows | OsMacos | OsiOS => {
-                match llsize_of_alloc(ccx, rty) {
-                    1 => RetValue(Type::i8(ccx)),
-                    2 => RetValue(Type::i16(ccx)),
-                    4 => RetValue(Type::i32(ccx)),
-                    8 => RetValue(Type::i64(ccx)),
-                    _ => RetPointer
-                }
-            }
-            _ => {
-                RetPointer
+        let t = &ccx.sess().target.target;
+        let strategy = if t.options.is_like_osx || t.options.is_like_windows {
+            match llsize_of_alloc(ccx, rty) {
+                1 => RetValue(Type::i8(ccx)),
+                2 => RetValue(Type::i16(ccx)),
+                4 => RetValue(Type::i32(ccx)),
+                8 => RetValue(Type::i64(ccx)),
+                _ => RetPointer
             }
+        } else {
+            RetPointer
         };
 
         match strategy {
diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs
index 955fcbfab84..7d2460093fe 100644
--- a/src/librustc/middle/trans/context.rs
+++ b/src/librustc/middle/trans/context.rs
@@ -34,7 +34,6 @@ use std::c_str::ToCStr;
 use std::ptr;
 use std::rc::Rc;
 use std::collections::{HashMap, HashSet};
-use syntax::abi;
 use syntax::ast;
 use syntax::parse::token::InternedString;
 
@@ -220,16 +219,16 @@ unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextR
     let llmod = mod_name.with_c_str(|buf| {
         llvm::LLVMModuleCreateWithNameInContext(buf, llcx)
     });
-    sess.targ_cfg
-        .target_strs
+    sess.target
+        .target
         .data_layout
         .as_slice()
         .with_c_str(|buf| {
         llvm::LLVMSetDataLayout(llmod, buf);
     });
-    sess.targ_cfg
-        .target_strs
-        .target_triple
+    sess.target
+        .target
+        .llvm_target
         .as_slice()
         .with_c_str(|buf| {
         llvm::LLVMRustSetNormalizedTarget(llmod, buf);
@@ -378,8 +377,8 @@ impl LocalCrateContext {
 
             let td = mk_target_data(shared.tcx
                                           .sess
-                                          .targ_cfg
-                                          .target_strs
+                                          .target
+                                          .target
                                           .data_layout
                                           .as_slice());
 
@@ -531,16 +530,8 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         }
     }
 
-    // Although there is an experimental implementation of LLVM which
-    // supports SS on armv7 it wasn't approved by Apple, see:
-    // http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20140505/216350.html
-    // It looks like it might be never accepted to upstream LLVM.
-    //
-    // So far the decision was to disable them in default builds
-    // but it could be enabled (with patched LLVM)
     pub fn is_split_stack_supported(&self) -> bool {
-        let ref cfg = self.sess().targ_cfg;
-        (cfg.os != abi::OsiOS || cfg.arch != abi::Arm) && cfg.os != abi::OsWindows
+        self.sess().target.target.options.morestack
     }
 
 
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 3d76d1f5d4d..ea7f28796f0 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -211,7 +211,7 @@ use std::ptr;
 use std::rc::{Rc, Weak};
 use syntax::util::interner::Interner;
 use syntax::codemap::{Span, Pos};
-use syntax::{abi, ast, codemap, ast_util, ast_map};
+use syntax::{ast, codemap, ast_util, ast_map};
 use syntax::ast_util::PostExpansionMethod;
 use syntax::parse::token;
 use syntax::parse::token::special_idents;
@@ -750,8 +750,7 @@ pub fn finalize(cx: &CrateContext) {
         // instruct LLVM to emit an older version of dwarf, however,
         // for OS X to understand. For more info see #11352
         // This can be overridden using --llvm-opts -dwarf-version,N.
-        if cx.sess().targ_cfg.os == abi::OsMacos ||
-            cx.sess().targ_cfg.os == abi::OsiOS {
+        if cx.sess().target.target.options.is_like_osx {
             "Dwarf Version".with_c_str(
                 |s| llvm::LLVMRustAddModuleFlag(cx.llmod(), s, 2));
         }
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index d979024c160..bed45a28691 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -34,7 +34,7 @@ use syntax::parse::token::{InternedString, special_idents};
 use syntax::parse::token;
 use syntax::{ast};
 use syntax::{attr, ast_map};
-use util::ppaux::{Repr, UserString};
+use util::ppaux::Repr;
 
 ///////////////////////////////////////////////////////////////////////////
 // Type definitions
@@ -70,39 +70,35 @@ struct LlvmSignature {
 // Calls to external functions
 
 pub fn llvm_calling_convention(ccx: &CrateContext,
-                               abi: Abi) -> Option<CallConv> {
-    let os = ccx.sess().targ_cfg.os;
-    let arch = ccx.sess().targ_cfg.arch;
-    abi.for_target(os, arch).map(|abi| {
-        match abi {
-            RustIntrinsic => {
-                // Intrinsics are emitted at the call site
-                ccx.sess().bug("asked to register intrinsic fn");
-            }
+                               abi: Abi) -> CallConv {
+    match ccx.sess().target.target.adjust_abi(abi) {
+        RustIntrinsic => {
+            // Intrinsics are emitted at the call site
+            ccx.sess().bug("asked to register intrinsic fn");
+        }
 
-            Rust => {
-                // FIXME(#3678) Implement linking to foreign fns with Rust ABI
-                ccx.sess().unimpl("foreign functions with Rust ABI");
-            }
+        Rust => {
+            // FIXME(#3678) Implement linking to foreign fns with Rust ABI
+            ccx.sess().unimpl("foreign functions with Rust ABI");
+        }
 
-            RustCall => {
-                // FIXME(#3678) Implement linking to foreign fns with Rust ABI
-                ccx.sess().unimpl("foreign functions with RustCall ABI");
-            }
+        RustCall => {
+            // FIXME(#3678) Implement linking to foreign fns with Rust ABI
+            ccx.sess().unimpl("foreign functions with RustCall ABI");
+        }
 
-            // It's the ABI's job to select this, not us.
-            System => ccx.sess().bug("system abi should be selected elsewhere"),
+        // It's the ABI's job to select this, not us.
+        System => ccx.sess().bug("system abi should be selected elsewhere"),
 
-            Stdcall => llvm::X86StdcallCallConv,
-            Fastcall => llvm::X86FastcallCallConv,
-            C => llvm::CCallConv,
-            Win64 => llvm::X86_64_Win64,
+        Stdcall => llvm::X86StdcallCallConv,
+        Fastcall => llvm::X86FastcallCallConv,
+        C => llvm::CCallConv,
+        Win64 => llvm::X86_64_Win64,
 
-            // These API constants ought to be more specific...
-            Cdecl => llvm::CCallConv,
-            Aapcs => llvm::CCallConv,
-        }
-    })
+        // These API constants ought to be more specific...
+        Cdecl => llvm::CCallConv,
+        Aapcs => llvm::CCallConv,
+    }
 }
 
 pub fn llvm_linkage_by_name(name: &str) -> Option<Linkage> {
@@ -191,7 +187,7 @@ pub fn register_static(ccx: &CrateContext,
 }
 
 pub fn register_foreign_item_fn(ccx: &CrateContext, abi: Abi, fty: ty::t,
-                                name: &str, span: Option<Span>) -> ValueRef {
+                                name: &str) -> ValueRef {
     /*!
      * Registers a foreign function found in a library.
      * Just adds a LLVM global.
@@ -204,25 +200,7 @@ pub fn register_foreign_item_fn(ccx: &CrateContext, abi: Abi, fty: ty::t,
            fty.repr(ccx.tcx()),
            name);
 
-    let cc = match llvm_calling_convention(ccx, abi) {
-        Some(cc) => cc,
-        None => {
-            match span {
-                Some(s) => {
-                    ccx.sess().span_fatal(s,
-                        format!("ABI `{}` has no suitable calling convention \
-                                 for target architecture",
-                                abi.user_string(ccx.tcx())).as_slice())
-                }
-                None => {
-                    ccx.sess().fatal(
-                        format!("ABI `{}` has no suitable calling convention \
-                                 for target architecture",
-                                abi.user_string(ccx.tcx())).as_slice())
-                }
-            }
-        }
-    };
+    let cc = llvm_calling_convention(ccx, abi);
 
     // Register the function as a C extern fn
     let tys = foreign_types_for_fn_ty(ccx, fty);
@@ -375,16 +353,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         llargs_foreign.push(llarg_foreign);
     }
 
-    let cc = match llvm_calling_convention(ccx, fn_abi) {
-        Some(cc) => cc,
-        None => {
-            // FIXME(#8357) We really ought to report a span here
-            ccx.sess().fatal(
-                format!("ABI string `{}` has no suitable ABI \
-                         for target architecture",
-                         fn_abi.user_string(ccx.tcx())).as_slice());
-        }
-    };
+    let cc = llvm_calling_convention(ccx, fn_abi);
 
     // A function pointer is called without the declaration available, so we have to apply
     // any attributes with ABI implications directly to the call instruction.
@@ -498,8 +467,7 @@ pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) {
                     abi => {
                         let ty = ty::node_id_to_type(ccx.tcx(), foreign_item.id);
                         register_foreign_item_fn(ccx, abi, ty,
-                                                 lname.get().as_slice(),
-                                                 Some(foreign_item.span));
+                                                 lname.get().as_slice());
                         // Unlike for other items, we shouldn't call
                         // `base::update_linkage` here.  Foreign items have
                         // special linkage requirements, which are handled
@@ -548,8 +516,7 @@ pub fn decl_rust_fn_with_foreign_abi(ccx: &CrateContext,
     let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
     let cconv = match ty::get(t).sty {
         ty::ty_bare_fn(ref fn_ty) => {
-            let c = llvm_calling_convention(ccx, fn_ty.abi);
-            c.unwrap_or(llvm::CCallConv)
+            llvm_calling_convention(ccx, fn_ty.abi)
         }
         _ => panic!("expected bare fn in decl_rust_fn_with_foreign_abi")
     };
@@ -572,8 +539,7 @@ pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext,
     let t = ty::node_id_to_type(ccx.tcx(), node_id);
     let cconv = match ty::get(t).sty {
         ty::ty_bare_fn(ref fn_ty) => {
-            let c = llvm_calling_convention(ccx, fn_ty.abi);
-            c.unwrap_or(llvm::CCallConv)
+            llvm_calling_convention(ccx, fn_ty.abi)
         }
         _ => panic!("expected bare fn in register_rust_fn_with_foreign_abi")
     };
diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs
index 1746f785311..7b8eb4e02b2 100644
--- a/src/librustc/middle/trans/type_.rs
+++ b/src/librustc/middle/trans/type_.rs
@@ -17,7 +17,6 @@ use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};
 use middle::trans::context::CrateContext;
 
 use syntax::ast;
-use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel};
 
 use std::c_str::ToCStr;
 use std::mem;
@@ -105,9 +104,10 @@ impl Type {
     }
 
     pub fn int(ccx: &CrateContext) -> Type {
-        match ccx.tcx().sess.targ_cfg.arch {
-            X86 | Arm | Mips | Mipsel => Type::i32(ccx),
-            X86_64 => Type::i64(ccx)
+        match ccx.tcx().sess.target.target.target_word_size.as_slice() {
+            "32" => Type::i32(ccx),
+            "64" => Type::i64(ccx),
+            tws => panic!("Unsupported target word size for int: {}", tws),
         }
     }
 
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 92b5b696e52..0c7de4b3ac4 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -4840,7 +4840,7 @@ pub fn check_enum_variants(ccx: &CrateCtxt,
                 ast::TyU16 => disr as u16 as Disr == disr,
                 ast::TyU32 => disr as u32 as Disr == disr,
                 ast::TyU64 => disr as u64 as Disr == disr,
-                ast::TyU => uint_in_range(ccx, ccx.tcx.sess.targ_cfg.uint_type, disr)
+                ast::TyU => uint_in_range(ccx, ccx.tcx.sess.target.uint_type, disr)
             }
         }
         fn int_in_range(ccx: &CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
@@ -4849,7 +4849,7 @@ pub fn check_enum_variants(ccx: &CrateCtxt,
                 ast::TyI16 => disr as i16 as Disr == disr,
                 ast::TyI32 => disr as i32 as Disr == disr,
                 ast::TyI64 => disr as i64 as Disr == disr,
-                ast::TyI => int_in_range(ccx, ccx.tcx.sess.targ_cfg.int_type, disr)
+                ast::TyI => int_in_range(ccx, ccx.tcx.sess.target.int_type, disr)
             }
         }
         match ty {
diff --git a/src/librustc_back/archive.rs b/src/librustc_back/archive.rs
index 2e58a8dab3b..db2f291e5e7 100644
--- a/src/librustc_back/archive.rs
+++ b/src/librustc_back/archive.rs
@@ -16,7 +16,6 @@ use std::io::{fs, TempDir};
 use std::io;
 use std::os;
 use std::str;
-use syntax::abi;
 use syntax::diagnostic::Handler as ErrorHandler;
 
 pub static METADATA_FILENAME: &'static str = "rust.metadata.bin";
@@ -25,7 +24,8 @@ pub struct ArchiveConfig<'a> {
     pub handler: &'a ErrorHandler,
     pub dst: Path,
     pub lib_search_paths: Vec<Path>,
-    pub os: abi::Os,
+    pub slib_prefix: String,
+    pub slib_suffix: String,
     pub maybe_ar_prog: Option<String>
 }
 
@@ -33,7 +33,8 @@ pub struct Archive<'a> {
     handler: &'a ErrorHandler,
     dst: Path,
     lib_search_paths: Vec<Path>,
-    os: abi::Os,
+    slib_prefix: String,
+    slib_suffix: String,
     maybe_ar_prog: Option<String>
 }
 
@@ -96,14 +97,11 @@ fn run_ar(handler: &ErrorHandler, maybe_ar_prog: &Option<String>,
     }
 }
 
-pub fn find_library(name: &str, os: abi::Os, search_paths: &[Path],
-                    handler: &ErrorHandler) -> Path {
-    let (osprefix, osext) = match os {
-        abi::OsWindows => ("", "lib"), _ => ("lib", "a"),
-    };
+pub fn find_library(name: &str, osprefix: &str, ossuffix: &str,
+                    search_paths: &[Path], handler: &ErrorHandler) -> Path {
     // On Windows, static libraries sometimes show up as libfoo.a and other
     // times show up as foo.lib
-    let oslibname = format!("{}{}.{}", osprefix, name, osext);
+    let oslibname = format!("{}{}{}", osprefix, name, ossuffix);
     let unixlibname = format!("lib{}.a", name);
 
     for path in search_paths.iter() {
@@ -122,12 +120,14 @@ pub fn find_library(name: &str, os: abi::Os, search_paths: &[Path],
 
 impl<'a> Archive<'a> {
     fn new(config: ArchiveConfig<'a>) -> Archive<'a> {
-        let ArchiveConfig { handler, dst, lib_search_paths, os, maybe_ar_prog } = config;
+        let ArchiveConfig { handler, dst, lib_search_paths, slib_prefix, slib_suffix,
+            maybe_ar_prog } = config;
         Archive {
             handler: handler,
             dst: dst,
             lib_search_paths: lib_search_paths,
-            os: os,
+            slib_prefix: slib_prefix,
+            slib_suffix: slib_suffix,
             maybe_ar_prog: maybe_ar_prog
         }
     }
@@ -178,7 +178,9 @@ impl<'a> ArchiveBuilder<'a> {
     /// 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) -> io::IoResult<()> {
-        let location = find_library(name, self.archive.os,
+        let location = find_library(name,
+                                    self.archive.slib_prefix.as_slice(),
+                                    self.archive.slib_suffix.as_slice(),
                                     self.archive.lib_search_paths.as_slice(),
                                     self.archive.handler);
         self.add_archive(&location, name, [])
diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs
index c11eb3ab603..97d94437acd 100644
--- a/src/librustc_back/lib.rs
+++ b/src/librustc_back/lib.rs
@@ -51,3 +51,4 @@ pub mod svh;
 pub mod target_strs;
 pub mod x86;
 pub mod x86_64;
+pub mod target;
diff --git a/src/librustc_back/rpath.rs b/src/librustc_back/rpath.rs
index 4c62ba54ac4..e7ac1bbcf84 100644
--- a/src/librustc_back/rpath.rs
+++ b/src/librustc_back/rpath.rs
@@ -12,13 +12,13 @@
 use std::collections::HashSet;
 use std::os;
 use std::io::IoError;
-use syntax::abi;
 use syntax::ast;
 
 pub struct RPathConfig<'a> {
-    pub os: abi::Os,
     pub used_crates: Vec<(ast::CrateNum, Option<Path>)>,
     pub out_filename: Path,
+    pub is_like_osx: bool,
+    pub has_rpath: bool,
     pub get_install_prefix_lib_path: ||:'a -> Path,
     pub realpath: |&Path|:'a -> Result<Path, IoError>
 }
@@ -26,24 +26,12 @@ pub struct RPathConfig<'a> {
 pub fn get_rpath_flags(config: RPathConfig) -> Vec<String> {
 
     // No rpath on windows
-    if config.os == abi::OsWindows {
+    if !config.has_rpath {
         return Vec::new();
     }
 
     let mut flags = Vec::new();
 
-    if config.os == abi::OsFreebsd {
-        flags.push_all(["-Wl,-rpath,/usr/local/lib/gcc46".to_string(),
-                        "-Wl,-rpath,/usr/local/lib/gcc44".to_string(),
-                        "-Wl,-z,origin".to_string()]);
-    }
-    else if config.os == abi::OsDragonfly {
-        flags.push_all(["-Wl,-rpath,/usr/lib/gcc47".to_string(),
-                        "-Wl,-rpath,/usr/lib/gcc44".to_string(),
-                        "-Wl,-z,origin".to_string()]);
-    }
-
-
     debug!("preparing the RPATH!");
 
     let libs = config.used_crates.clone();
@@ -107,14 +95,11 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig,
                                 lib: &Path) -> String {
     use std::os;
 
-    assert!(config.os != abi::OsWindows);
-
     // Mac doesn't appear to support $ORIGIN
-    let prefix = match config.os {
-        abi::OsAndroid | abi::OsLinux | abi::OsFreebsd | abi::OsDragonfly
-                          => "$ORIGIN",
-        abi::OsMacos => "@loader_path",
-        abi::OsWindows | abi::OsiOS => unreachable!()
+    let prefix = if config.is_like_osx {
+        "@loader_path"
+    } else {
+        "$ORIGIN"
     };
 
     let mut lib = (config.realpath)(&os::make_absolute(lib)).unwrap();
@@ -203,10 +188,11 @@ mod test {
     #[cfg(any(target_os = "linux", target_os = "android"))]
     fn test_rpath_relative() {
         let config = &mut RPathConfig {
-            os: abi::OsLinux,
             used_crates: Vec::new(),
             out_filename: Path::new("bin/rustc"),
             get_install_prefix_lib_path: || panic!(),
+            has_rpath: true,
+            is_like_osx: false,
             realpath: |p| Ok(p.clone())
         };
         let res = get_rpath_relative_to_output(config, &Path::new("lib/libstd.so"));
@@ -217,8 +203,9 @@ mod test {
     #[cfg(target_os = "freebsd")]
     fn test_rpath_relative() {
         let config = &mut RPathConfig {
-            os: abi::OsFreebsd,
             used_crates: Vec::new(),
+            has_rpath: true,
+            is_like_osx: false,
             out_filename: Path::new("bin/rustc"),
             get_install_prefix_lib_path: || panic!(),
             realpath: |p| Ok(p.clone())
@@ -231,8 +218,9 @@ mod test {
     #[cfg(target_os = "dragonfly")]
     fn test_rpath_relative() {
         let config = &mut RPathConfig {
-            os: abi::OsDragonfly,
             used_crates: Vec::new(),
+            has_rpath: true,
+            is_like_osx: false,
             out_filename: Path::new("bin/rustc"),
             get_install_prefix_lib_path: || panic!(),
             realpath: |p| Ok(p.clone())
@@ -245,8 +233,9 @@ mod test {
     #[cfg(target_os = "macos")]
     fn test_rpath_relative() {
         let config = &mut RPathConfig {
-            os: abi::OsMacos,
             used_crates: Vec::new(),
+            has_rpath: true,
+            is_like_osx: true,
             out_filename: Path::new("bin/rustc"),
             get_install_prefix_lib_path: || panic!(),
             realpath: |p| Ok(p.clone())
diff --git a/src/librustc_back/target/apple_base.rs b/src/librustc_back/target/apple_base.rs
new file mode 100644
index 00000000000..795a2c18bc6
--- /dev/null
+++ b/src/librustc_back/target/apple_base.rs
@@ -0,0 +1,29 @@
+// Copyright 2014 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.
+
+use target::TargetOptions;
+use std::default::Default;
+
+pub fn opts() -> TargetOptions {
+    TargetOptions {
+        // OSX has -dead_strip, which doesn't rely on ffunction_sections
+        function_sections: false,
+        linker: "cc".to_string(),
+        dynamic_linking: true,
+        executables: true,
+        is_like_osx: true,
+        morestack: true,
+        has_rpath: true,
+        dll_prefix: "lib".to_string(),
+        dll_suffix: ".dylib".to_string(),
+        pre_link_args: Vec::new(),
+        .. Default::default()
+    }
+}
diff --git a/src/librustc_back/target/arm_apple_ios.rs b/src/librustc_back/target/arm_apple_ios.rs
new file mode 100644
index 00000000000..8be98a51775
--- /dev/null
+++ b/src/librustc_back/target/arm_apple_ios.rs
@@ -0,0 +1,37 @@
+// Copyright 2014 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.
+
+use target::{Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        data_layout: "e-p:32:32:32\
+                      -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
+                      -f32:32:32-f64:64:64\
+                      -v64:64:64-v128:64:128\
+                      -a0:0:64-n32".to_string(),
+        llvm_target: "arm-apple-ios".to_string(),
+        target_endian: "little".to_string(),
+        target_word_size: "32".to_string(),
+        arch: "arm".to_string(),
+        target_os: "ios".to_string(),
+        options: TargetOptions {
+            features: "+v7,+thumb2,+vfp3,+neon".to_string(),
+            executables: false,
+            dynamic_linking: false,
+            // Although there is an experimental implementation of LLVM which
+            // supports SS on armv7 it wasn't approved by Apple, see:
+            // http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20140505/216350.html
+            // It looks like it might be never accepted to upstream LLVM.
+            morestack: false,
+            .. super::apple_base::opts()
+        }
+    }
+}
diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_back/target/arm_linux_androideabi.rs
new file mode 100644
index 00000000000..b47e3d0b237
--- /dev/null
+++ b/src/librustc_back/target/arm_linux_androideabi.rs
@@ -0,0 +1,35 @@
+// Copyright 2014 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.
+
+use target::Target;
+
+pub fn target() -> Target {
+    let mut base = super::linux_base::opts();
+    base.features = "+v7".to_string();
+    // Many of the symbols defined in compiler-rt are also defined in libgcc.  Android
+    // linker doesn't like that by default.
+    base.pre_link_args.push("-Wl,--allow-multiple-definition".to_string());
+    // FIXME #17437 (and #17448): Android doesn't support position dependant executables anymore.
+    base.position_independant_executables = false;
+
+    Target {
+        data_layout: "e-p:32:32:32\
+                      -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
+                      -f32:32:32-f64:64:64\
+                      -v64:64:64-v128:64:128\
+                      -a0:0:64-n32".to_string(),
+        llvm_target: "arm-linux-androideabi".to_string(),
+        target_endian: "little".to_string(),
+        target_word_size: "32".to_string(),
+        arch: "arm".to_string(),
+        target_os: "android".to_string(),
+        options: base,
+    }
+}
diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
new file mode 100644
index 00000000000..aecab188264
--- /dev/null
+++ b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
@@ -0,0 +1,32 @@
+// Copyright 2014 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.
+
+use target::{Target, TargetOptions};
+
+pub fn target() -> Target {
+    let base = super::linux_base::opts();
+    Target {
+        data_layout: "e-p:32:32:32\
+                      -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
+                      -f32:32:32-f64:64:64\
+                      -v64:64:64-v128:64:128\
+                      -a0:0:64-n32".to_string(),
+        llvm_target: "arm-unknown-linux-gnueabi".to_string(),
+        target_endian: "little".to_string(),
+        target_word_size: "32".to_string(),
+        arch: "arm".to_string(),
+        target_os: "linux".to_string(),
+
+        options: TargetOptions {
+            features: "+v6".to_string(),
+            .. base
+        },
+    }
+}
diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
new file mode 100644
index 00000000000..32d183d6254
--- /dev/null
+++ b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
@@ -0,0 +1,32 @@
+// Copyright 2014 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.
+
+use target::{Target, TargetOptions};
+
+pub fn target() -> Target {
+    let base = super::linux_base::opts();
+    Target {
+        data_layout: "e-p:32:32:32\
+                      -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
+                      -f32:32:32-f64:64:64\
+                      -v64:64:64-v128:64:128\
+                      -a0:0:64-n32".to_string(),
+        llvm_target: "arm-unknown-linux-gnueabi".to_string(),
+        target_endian: "little".to_string(),
+        target_word_size: "32".to_string(),
+        arch: "arm".to_string(),
+        target_os: "linux".to_string(),
+
+        options: TargetOptions {
+            features: "+v6,+vfp2".to_string(),
+            .. base
+        }
+    }
+}
diff --git a/src/librustc_back/target/dragonfly_base.rs b/src/librustc_back/target/dragonfly_base.rs
new file mode 100644
index 00000000000..4e982b2b76e
--- /dev/null
+++ b/src/librustc_back/target/dragonfly_base.rs
@@ -0,0 +1,30 @@
+// Copyright 2014 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.
+
+use target::TargetOptions;
+use std::default::Default;
+
+pub fn opts() -> TargetOptions {
+    TargetOptions {
+        linker: "cc".to_string(),
+        dynamic_linking: true,
+        executables: true,
+        morestack: true,
+        has_rpath: true,
+        pre_link_args: vec!(
+            "-L/usr/local/lib".to_string(),
+            "-L/usr/local/lib/gcc47".to_string(),
+            "-L/usr/local/lib/gcc44".to_string(),
+        ),
+
+        .. Default::default()
+    }
+}
+
diff --git a/src/librustc_back/target/freebsd_base.rs b/src/librustc_back/target/freebsd_base.rs
new file mode 100644
index 00000000000..ab8398fc605
--- /dev/null
+++ b/src/librustc_back/target/freebsd_base.rs
@@ -0,0 +1,30 @@
+// Copyright 2014 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.
+
+use target::TargetOptions;
+use std::default::Default;
+
+pub fn opts() -> TargetOptions {
+    TargetOptions {
+        linker: "cc".to_string(),
+        dynamic_linking: true,
+        executables: true,
+        morestack: true,
+        has_rpath: true,
+        pre_link_args: vec!(
+            "-L/usr/local/lib".to_string(),
+            "-L/usr/local/lib/gcc46".to_string(),
+            "-L/usr/local/lib/gcc44".to_string(),
+        ),
+
+        .. Default::default()
+    }
+}
+
diff --git a/src/librustc_back/target/i386_apple_ios.rs b/src/librustc_back/target/i386_apple_ios.rs
new file mode 100644
index 00000000000..fe336601a81
--- /dev/null
+++ b/src/librustc_back/target/i386_apple_ios.rs
@@ -0,0 +1,28 @@
+// Copyright 2014 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.
+
+use target::Target;
+
+pub fn target() -> Target {
+    Target {
+        data_layout: "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16\
+                      -i32:32:32-i64:32:64\
+                      -f32:32:32-f64:32:64-v64:64:64\
+                      -v128:128:128-a0:0:64-f80:128:128\
+                      -n8:16:32".to_string(),
+        llvm_target: "i386-apple-ios".to_string(),
+        target_endian: "little".to_string(),
+        target_word_size: "32".to_string(),
+        arch: "x86".to_string(),
+        target_os: "ios".to_string(),
+
+        options: super::apple_base::opts()
+    }
+}
diff --git a/src/librustc_back/target/i686_apple_darwin.rs b/src/librustc_back/target/i686_apple_darwin.rs
new file mode 100644
index 00000000000..bd3dd3246aa
--- /dev/null
+++ b/src/librustc_back/target/i686_apple_darwin.rs
@@ -0,0 +1,30 @@
+// Copyright 2014 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.
+
+use target::Target;
+
+pub fn target() -> Target {
+    let mut base = super::apple_base::opts();
+    base.pre_link_args.push("-m32".to_string());
+
+    Target {
+        data_layout: "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16\
+                      -i32:32:32-i64:32:64\
+                      -f32:32:32-f64:32:64-v64:64:64\
+                      -v128:128:128-a0:0:64-f80:128:128\
+                      -n8:16:32".to_string(),
+        llvm_target: "i686-apple-darwin".to_string(),
+        target_endian: "little".to_string(),
+        target_word_size: "32".to_string(),
+        arch: "x86".to_string(),
+        target_os: "macos".to_string(),
+        options: base,
+    }
+}
diff --git a/src/librustc_back/target/i686_pc_windows_gnu.rs b/src/librustc_back/target/i686_pc_windows_gnu.rs
new file mode 100644
index 00000000000..4d75590e664
--- /dev/null
+++ b/src/librustc_back/target/i686_pc_windows_gnu.rs
@@ -0,0 +1,34 @@
+// Copyright 2014 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.
+
+use target::Target;
+
+pub fn target() -> Target {
+    let mut options = super::windows_base::opts();
+
+    // Mark all dynamic libraries and executables as compatible with the larger 4GiB address
+    // space available to x86 Windows binaries on x86_64.
+    options.pre_link_args.push("-Wl,--large-address-aware".to_string());
+
+    // Make sure that we link to the dynamic libgcc, otherwise cross-module
+    // DWARF stack unwinding will not work.
+    // This behavior may be overridden by -Clink-args="-static-libgcc"
+    options.pre_link_args.push("-shared-libgcc".to_string());
+
+    Target {
+        data_layout: "e-p:32:32-f64:64:64-i64:64:64-f80:32:32-n8:16:32".to_string(),
+        llvm_target: "i686-pc-windows-gnu".to_string(),
+        target_endian: "little".to_string(),
+        target_word_size: "32".to_string(),
+        arch: "x86".to_string(),
+        target_os: "windows".to_string(),
+        options: options,
+    }
+}
diff --git a/src/librustc_back/target/i686_unknown_dragonfly.rs b/src/librustc_back/target/i686_unknown_dragonfly.rs
new file mode 100644
index 00000000000..296d7117efa
--- /dev/null
+++ b/src/librustc_back/target/i686_unknown_dragonfly.rs
@@ -0,0 +1,26 @@
+// Copyright 2014 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.
+
+use target::Target;
+
+pub fn target() -> Target {
+    let mut base = super::draginfly_base::opts();
+    base.pre_link_args.push("-m32".to_string());
+
+    Target {
+        data_layout: "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32".to_string(),
+        llvm_target: "i686-unknown-dragonfly".to_string(),
+        target_endian: "little".to_string(),
+        target_word_size: "32".to_string(),
+        arch: "x86".to_string(),
+        target_os: "dragonfly".to_string(),
+        options: base,
+    }
+}
diff --git a/src/librustc_back/target/i686_unknown_linux_gnu.rs b/src/librustc_back/target/i686_unknown_linux_gnu.rs
new file mode 100644
index 00000000000..1a4560d5cd5
--- /dev/null
+++ b/src/librustc_back/target/i686_unknown_linux_gnu.rs
@@ -0,0 +1,26 @@
+// Copyright 2014 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.
+
+use target::Target;
+
+pub fn target() -> Target {
+    let mut base = super::linux_base::opts();
+    base.pre_link_args.push("-m32".to_string());
+
+    Target {
+        data_layout: "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32".to_string(),
+        llvm_target: "i686-unknown-linux-gnu".to_string(),
+        target_endian: "little".to_string(),
+        target_word_size: "32".to_string(),
+        arch: "x86".to_string(),
+        target_os: "linux".to_string(),
+        options: base,
+    }
+}
diff --git a/src/librustc_back/target/linux_base.rs b/src/librustc_back/target/linux_base.rs
new file mode 100644
index 00000000000..51b817a6175
--- /dev/null
+++ b/src/librustc_back/target/linux_base.rs
@@ -0,0 +1,31 @@
+// Copyright 2014 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.
+
+use target::TargetOptions;
+use std::default::Default;
+
+pub fn opts() -> TargetOptions {
+    TargetOptions {
+        linker: "cc".to_string(),
+        dynamic_linking: true,
+        executables: true,
+        morestack: true,
+        linker_is_gnu: true,
+        has_rpath: true,
+        pre_link_args: vec!(
+            // GNU-style linkers will use this to omit linking to libraries which
+            // don't actually fulfill any relocations, but only for libraries which
+            // follow this flag. Thus, use it before specifying libraries to link to.
+            "-Wl,--as-needed".to_string(),
+        ),
+        position_independant_executables: true,
+        .. Default::default()
+    }
+}
diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_back/target/mips_unknown_linux_gnu.rs
new file mode 100644
index 00000000000..45e02ecb98c
--- /dev/null
+++ b/src/librustc_back/target/mips_unknown_linux_gnu.rs
@@ -0,0 +1,27 @@
+// Copyright 2014 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.
+
+use target::Target;
+
+pub fn target() -> Target {
+    Target {
+        data_layout: "E-p:32:32:32\
+                      -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
+                      -f32:32:32-f64:64:64\
+                      -v64:64:64-v128:64:128\
+                      -a0:0:64-n32".to_string(),
+        llvm_target: "mips-unknown-linux-gnu".to_string(),
+        target_endian: "big".to_string(),
+        target_word_size: "32".to_string(),
+        arch: "mips".to_string(),
+        target_os: "linux".to_string(),
+        options: super::linux_base::opts()
+    }
+}
diff --git a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs
new file mode 100644
index 00000000000..1ba99b167c3
--- /dev/null
+++ b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs
@@ -0,0 +1,28 @@
+// Copyright 2014 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.
+
+use target::Target;
+
+pub fn target() -> Target {
+    Target {
+        data_layout: "e-p:32:32:32\
+                      -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
+                      -f32:32:32-f64:64:64\
+                      -v64:64:64-v128:64:128\
+                      -a0:0:64-n32".to_string(),
+        llvm_target: "mipsel-unknown-linux-gnu".to_string(),
+        target_endian: "little".to_string(),
+        target_word_size: "32".to_string(),
+        arch: "mips".to_string(),
+        target_os: "linux".to_string(),
+
+        options: super::linux_base::opts()
+    }
+}
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
new file mode 100644
index 00000000000..0978fba2a21
--- /dev/null
+++ b/src/librustc_back/target/mod.rs
@@ -0,0 +1,379 @@
+// Copyright 2014 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.
+
+//! [Flexible target specification.](https://github.com/rust-lang/rfcs/pull/131)
+//!
+//! Rust targets a wide variety of usecases, and in the interest of flexibility,
+//! allows new target triples to be defined in configuration files. Most users
+//! will not need to care about these, but this is invaluable when porting Rust
+//! to a new platform, and allows for an unprecedented level of control over how
+//! the compiler works.
+//!
+//! # Using custom targets
+//!
+//! A target triple, as passed via `rustc --target=TRIPLE`, will first be
+//! compared against the list of built-in targets. This is to ease distributing
+//! rustc (no need for configuration files) and also to hold these built-in
+//! targets as immutable and sacred. If `TRIPLE` is not one of the built-in
+//! targets, rustc will check if a file named `TRIPLE` exists. If it does, it
+//! will be loaded as the target configuration. If the file does not exist,
+//! rustc will search each directory in the environment variable
+//! `RUST_TARGET_PATH` for a file named `TRIPLE.json`. The first one found will
+//! be loaded. If no file is found in any of those directories, a fatal error
+//! will be given.  `RUST_TARGET_PATH` includes `/etc/rustc` as its last entry,
+//! to be searched by default.
+//!
+//! Projects defining their own targets should use
+//! `--target=path/to/my-awesome-platform.json` instead of adding to
+//! `RUST_TARGET_PATH`.
+//!
+//! # Defining a new target
+//!
+//! Targets are defined using [JSON](http://json.org/). The `Target` struct in
+//! this module defines the format the JSON file should take, though each
+//! underscore in the field names should be replaced with a hyphen (`-`) in the
+//! JSON file. Some fields are required in every target specification, such as
+//! `data-layout`, `llvm-target`, `target-endian`, `target-word-size`, and
+//! `arch`. In general, options passed to rustc with `-C` override the target's
+//! settings, though `target-feature` and `link-args` will *add* to the list
+//! specified by the target, rather than replace.
+
+use serialize::json::Json;
+use syntax::{diagnostic, abi};
+use std::default::Default;
+use std::io::fs::PathExtensions;
+
+mod windows_base;
+mod linux_base;
+mod apple_base;
+mod freebsd_base;
+mod dragonfly_base;
+
+mod arm_apple_ios;
+mod arm_linux_androideabi;
+mod arm_unknown_linux_gnueabi;
+mod arm_unknown_linux_gnueabihf;
+mod i686_apple_darwin;
+mod i386_apple_ios;
+mod i686_pc_windows_gnu;
+mod i686_unknown_linux_gnu;
+mod mips_unknown_linux_gnu;
+mod mipsel_unknown_linux_gnu;
+mod x86_64_apple_darwin;
+mod x86_64_pc_windows_gnu;
+mod x86_64_unknown_freebsd;
+mod x86_64_unknown_dragonfly;
+mod x86_64_unknown_linux_gnu;
+
+/// Everything `rustc` knows about how to compile for a specific target.
+///
+/// Every field here must be specified, and has no default value.
+#[deriving(Clone, Show)]
+pub struct Target {
+    /// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM.
+    pub data_layout: String,
+    /// Target triple to pass to LLVM.
+    pub llvm_target: String,
+    /// String to use as the `target_endian` `cfg` variable.
+    pub target_endian: String,
+    /// String to use as the `target_word_size` `cfg` variable.
+    pub target_word_size: String,
+    /// OS name to use for conditional compilation.
+    pub target_os: String,
+    /// Architecture to use for ABI considerations. Valid options: "x86", "x86_64", "arm", and
+    /// "mips". "mips" includes "mipsel".
+    pub arch: String,
+    /// Optional settings with defaults.
+    pub options: TargetOptions,
+}
+
+/// Optional aspects of a target specification.
+///
+/// This has an implementation of `Default`, see each field for what the default is. In general,
+/// these try to take "minimal defaults" that don't assume anything about the runtime they run in.
+#[deriving(Clone, Show)]
+pub struct TargetOptions {
+    /// Linker to invoke. Defaults to "cc".
+    pub linker: String,
+    /// Linker arguments that are unconditionally passed *before* any user-defined libraries.
+    pub pre_link_args: Vec<String>,
+    /// Linker arguments that are unconditionally passed *after* any user-defined libraries.
+    pub post_link_args: Vec<String>,
+    /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults to "default".
+    pub cpu: String,
+    /// Default target features to pass to LLVM. These features will *always* be passed, and cannot
+    /// be disabled even via `-C`. Corresponds to `llc -mattr=$features`.
+    pub features: String,
+    /// Whether dynamic linking is available on this target. Defaults to false.
+    pub dynamic_linking: bool,
+    /// Whether executables are available on this target. iOS, for example, only allows static
+    /// libraries. Defaults to false.
+    pub executables: bool,
+    /// Whether LLVM's segmented stack prelude is supported by whatever runtime is available.
+    /// Will emit stack checks and calls to __morestack. Defaults to false.
+    pub morestack: bool,
+    /// Relocation model to use in object file. Corresponds to `llc
+    /// -relocation-model=$relocation_model`. Defaults to "pic".
+    pub relocation_model: String,
+    /// Code model to use. Corresponds to `llc -code-model=$code_model`. Defaults to "default".
+    pub code_model: String,
+    /// Do not emit code that uses the "red zone", if the ABI has one. Defaults to false.
+    pub disable_redzone: bool,
+    /// Eliminate frame pointers from stack frames if possible. Defaults to true.
+    pub eliminate_frame_pointer: bool,
+    /// Emit each function in its own section. Defaults to true.
+    pub function_sections: bool,
+    /// String to prepend to the name of every dynamic library. Defaults to "lib".
+    pub dll_prefix: String,
+    /// String to append to the name of every dynamic library. Defaults to ".so".
+    pub dll_suffix: String,
+    /// String to append to the name of every executable.
+    pub exe_suffix: String,
+    /// String to prepend to the name of every static library. Defaults to "lib".
+    pub staticlib_prefix: String,
+    /// String to append to the name of every static library. Defaults to ".a".
+    pub staticlib_suffix: String,
+    /// Whether the target toolchain is like OSX's. Only useful for compiling against iOS/OS X, in
+    /// particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false.
+    pub is_like_osx: bool,
+    /// Whether the target toolchain is like Windows'. Only useful for compiling against Windows,
+    /// only realy used for figuring out how to find libraries, since Windows uses its own
+    /// library naming convention. Defaults to false.
+    pub is_like_windows: bool,
+    /// Whether the linker support GNU-like arguments such as -O. Defaults to false.
+    pub linker_is_gnu: bool,
+    /// Whether the linker support rpaths or not. Defaults to false.
+    pub has_rpath: bool,
+    /// Whether to disable linking to compiler-rt. Defaults to false, as LLVM will emit references
+    /// to the functions that compiler-rt provides.
+    pub no_compiler_rt: bool,
+    /// Dynamically linked executables can be compiled as position independent if the default
+    /// relocation model of position independent code is not changed. This is a requirement to take
+    /// advantage of ASLR, as otherwise the functions in the executable are not randomized and can
+    /// be used during an exploit of a vulnerability in any code.
+    pub position_independant_executables: bool,
+}
+
+impl Default for TargetOptions {
+    /// Create a set of "sane defaults" for any target. This is still incomplete, and if used for
+    /// compilation, will certainly not work.
+    fn default() -> TargetOptions {
+        TargetOptions {
+            linker: "cc".to_string(),
+            pre_link_args: Vec::new(),
+            post_link_args: Vec::new(),
+            cpu: "generic".to_string(),
+            features: "".to_string(),
+            dynamic_linking: false,
+            executables: false,
+            morestack: false,
+            relocation_model: "pic".to_string(),
+            code_model: "default".to_string(),
+            disable_redzone: false,
+            eliminate_frame_pointer: true,
+            function_sections: true,
+            dll_prefix: "lib".to_string(),
+            dll_suffix: ".so".to_string(),
+            exe_suffix: "".to_string(),
+            staticlib_prefix: "lib".to_string(),
+            staticlib_suffix: ".a".to_string(),
+            is_like_osx: false,
+            is_like_windows: false,
+            linker_is_gnu: false,
+            has_rpath: false,
+            no_compiler_rt: false,
+            position_independant_executables: false,
+        }
+    }
+}
+
+impl Target {
+    /// Given a function ABI, turn "System" into the correct ABI for this target.
+    pub fn adjust_abi(&self, abi: abi::Abi) -> abi::Abi {
+        match abi {
+            abi::System => {
+                if self.options.is_like_windows && self.arch.as_slice() == "x86" {
+                    abi::Stdcall
+                } else {
+                    abi::C
+                }
+            },
+            abi => abi
+        }
+    }
+
+    /// Load a target descriptor from a JSON object.
+    pub fn from_json(obj: Json) -> Target {
+        // this is 1. ugly, 2. error prone.
+
+
+        let handler = diagnostic::default_handler(diagnostic::Auto, None);
+
+        let get_req_field = |name: &str| {
+            match obj.find(name)
+                     .map(|s| s.as_string())
+                     .and_then(|os| os.map(|s| s.to_string())) {
+                Some(val) => val,
+                None =>
+                    handler.fatal((format!("Field {} in target specification is required", name))
+                                  .as_slice())
+            }
+        };
+
+        let mut base = Target {
+            data_layout: get_req_field("data-layout"),
+            llvm_target: get_req_field("llvm-target"),
+            target_endian: get_req_field("target-endian"),
+            target_word_size: get_req_field("target-word-size"),
+            arch: get_req_field("arch"),
+            target_os: get_req_field("os"),
+            options: Default::default(),
+        };
+
+        macro_rules! key (
+            ($key_name:ident) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                obj.find(name[]).map(|o| o.as_string()
+                                    .map(|s| base.options.$key_name = s.to_string()));
+            } );
+            ($key_name:ident, bool) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                obj.find(name[]).map(|o| o.as_boolean().map(|s| base.options.$key_name = s));
+            } );
+            ($key_name:ident, list) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                obj.find(name[]).map(|o| o.as_list()
+                    .map(|v| base.options.$key_name = v.iter()
+                        .map(|a| a.as_string().unwrap().to_string()).collect()
+                        )
+                    );
+            } );
+        )
+
+        key!(cpu);
+        key!(linker);
+        key!(relocation_model);
+        key!(code_model);
+        key!(dll_prefix);
+        key!(dll_suffix);
+        key!(exe_suffix);
+        key!(staticlib_prefix);
+        key!(staticlib_suffix);
+        key!(features);
+        key!(dynamic_linking, bool);
+        key!(executables, bool);
+        key!(morestack, bool);
+        key!(disable_redzone, bool);
+        key!(eliminate_frame_pointer, bool);
+        key!(function_sections, bool);
+        key!(is_like_osx, bool);
+        key!(is_like_windows, bool);
+        key!(linker_is_gnu, bool);
+        key!(has_rpath, bool);
+        key!(no_compiler_rt, bool);
+        key!(pre_link_args, list);
+        key!(post_link_args, list);
+
+        base
+    }
+
+    /// Search RUST_TARGET_PATH for a JSON file specifying the given target triple. Note that it
+    /// could also just be a bare filename already, so also check for that. If one of the hardcoded
+    /// targets we know about, just return it directly.
+    ///
+    /// The error string could come from any of the APIs called, including filesystem access and
+    /// JSON decoding.
+    pub fn search(target: &str) -> Result<Target, String> {
+        use std::os;
+        use std::io::File;
+        use std::path::Path;
+        use serialize::json;
+
+        fn load_file(path: &Path) -> Result<Target, String> {
+            let mut f = try!(File::open(path).map_err(|e| e.to_string()));
+            let obj = try!(json::from_reader(&mut f).map_err(|e| e.to_string()));
+            Ok(Target::from_json(obj))
+        }
+
+        // this would use a match if stringify! were allowed in pattern position
+        macro_rules! load_specific (
+            ( $($name:ident),+ ) => (
+                {
+                    let target = target.replace("-", "_");
+                    let target = target.as_slice();
+                    if false { }
+                    $(
+                        else if target == stringify!($name) {
+                            let t = $name::target();
+                            debug!("Got builtin target: {}", t);
+                            return Ok(t);
+                        }
+                    )*
+                    else if target == "x86_64-w64-mingw32" {
+                        let t = x86_64_pc_windows_gnu::target();
+                        return Ok(t);
+                    } else if target == "i686-w64-mingw32" {
+                        let t = i686_pc_windows_gnu::target();
+                        return Ok(t);
+                    }
+                }
+            )
+        )
+
+        load_specific!(
+            x86_64_unknown_linux_gnu,
+            i686_unknown_linux_gnu,
+            mips_unknown_linux_gnu,
+            mipsel_unknown_linux_gnu,
+            arm_linux_androideabi,
+            arm_unknown_linux_gnueabi,
+            arm_unknown_linux_gnueabihf,
+
+            x86_64_unknown_freebsd,
+
+            x86_64_unknown_dragonfly,
+
+            x86_64_apple_darwin,
+            i686_apple_darwin,
+            i386_apple_ios,
+            arm_apple_ios,
+
+            x86_64_pc_windows_gnu,
+            i686_pc_windows_gnu
+        )
+
+
+        let path = Path::new(target);
+
+        if path.is_file() {
+            return load_file(&path);
+        }
+
+        let path = {
+            let mut target = target.to_string();
+            target.push_str(".json");
+            Path::new(target)
+        };
+
+        let target_path = os::getenv("RUST_TARGET_PATH").unwrap_or(String::new());
+
+        let paths = os::split_paths(target_path.as_slice());
+        // FIXME 16351: add a sane default search path?
+
+        for dir in paths.iter() {
+            let p =  dir.join(path.clone());
+            if p.is_file() {
+                return load_file(&p);
+            }
+        }
+
+        Err(format!("Could not find specification for target {}", target))
+    }
+}
diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_back/target/windows_base.rs
new file mode 100644
index 00000000000..148be8cab76
--- /dev/null
+++ b/src/librustc_back/target/windows_base.rs
@@ -0,0 +1,66 @@
+// Copyright 2014 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.
+
+use target::TargetOptions;
+use std::default::Default;
+
+pub fn opts() -> TargetOptions {
+    TargetOptions {
+        // FIXME(#13846) this should be enabled for windows
+        function_sections: false,
+        linker: "gcc".to_string(),
+        dynamic_linking: true,
+        executables: true,
+        dll_prefix: "".to_string(),
+        dll_suffix: ".dll".to_string(),
+        exe_suffix: ".exe".to_string(),
+        staticlib_prefix: "".to_string(),
+        staticlib_suffix: ".lib".to_string(),
+        morestack: false,
+        is_like_windows: true,
+        pre_link_args: vec!(
+            // And here, we see obscure linker flags #45. On windows, it has been
+            // found to be necessary to have this flag to compile liblibc.
+            //
+            // First a bit of background. On Windows, the file format is not ELF,
+            // but COFF (at least according to LLVM). COFF doesn't officially allow
+            // for section names over 8 characters, apparently. Our metadata
+            // section, ".note.rustc", you'll note is over 8 characters.
+            //
+            // On more recent versions of gcc on mingw, apparently the section name
+            // is *not* truncated, but rather stored elsewhere in a separate lookup
+            // table. On older versions of gcc, they apparently always truncated th
+            // section names (at least in some cases). Truncating the section name
+            // actually creates "invalid" objects [1] [2], but only for some
+            // introspection tools, not in terms of whether it can be loaded.
+            //
+            // Long story short, passing this flag forces the linker to *not*
+            // truncate section names (so we can find the metadata section after
+            // it's compiled). The real kicker is that rust compiled just fine on
+            // windows for quite a long time *without* this flag, so I have no idea
+            // why it suddenly started failing for liblibc. Regardless, we
+            // definitely don't want section name truncation, so we're keeping this
+            // flag for windows.
+            //
+            // [1] - https://sourceware.org/bugzilla/show_bug.cgi?id=13130
+            // [2] - https://code.google.com/p/go/issues/detail?id=2139
+            "-Wl,--enable-long-section-names".to_string(),
+
+            // Tell GCC to avoid linker plugins, because we are not bundling
+            // them with Windows installer, and Rust does its own LTO anyways.
+            "-fno-use-linker-plugin".to_string(),
+
+            // Always enable DEP (NX bit) when it is available
+            "-Wl,--nxcompat".to_string(),
+        ),
+
+        .. Default::default()
+    }
+}
diff --git a/src/librustc_back/target/x86_64_apple_darwin.rs b/src/librustc_back/target/x86_64_apple_darwin.rs
new file mode 100644
index 00000000000..4e958d73a39
--- /dev/null
+++ b/src/librustc_back/target/x86_64_apple_darwin.rs
@@ -0,0 +1,29 @@
+// Copyright 2014 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.
+
+use target::Target;
+
+pub fn target() -> Target {
+    let mut base = super::apple_base::opts();
+    base.eliminate_frame_pointer = false;
+    base.pre_link_args.push("-m64".to_string());
+
+    Target {
+        data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
+                      f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
+                      s0:64:64-f80:128:128-n8:16:32:64".to_string(),
+        llvm_target: "x86_64-apple-darwin".to_string(),
+        target_endian: "little".to_string(),
+        target_word_size: "64".to_string(),
+        arch: "x86_64".to_string(),
+        target_os: "macos".to_string(),
+        options: base,
+    }
+}
diff --git a/src/librustc_back/target/x86_64_pc_windows_gnu.rs b/src/librustc_back/target/x86_64_pc_windows_gnu.rs
new file mode 100644
index 00000000000..9247e1da0a5
--- /dev/null
+++ b/src/librustc_back/target/x86_64_pc_windows_gnu.rs
@@ -0,0 +1,31 @@
+// Copyright 2014 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.
+
+use target::Target;
+
+pub fn target() -> Target {
+    let mut base = super::windows_base::opts();
+    // On Win64 unwinding is handled by the OS, so we can link libgcc statically.
+    base.pre_link_args.push("-static-libgcc".to_string());
+    base.pre_link_args.push("-m64".to_string());
+
+    Target {
+        // FIXME: Test this. Copied from linux (#2398)
+        data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
+                      f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
+                      s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(),
+        llvm_target: "x86_64-pc-windows-gnu".to_string(),
+        target_endian: "little".to_string(),
+        target_word_size: "64".to_string(),
+        arch: "x86_64".to_string(),
+        target_os: "windows".to_string(),
+        options: base,
+    }
+}
diff --git a/src/librustc_back/target/x86_64_unknown_dragonfly.rs b/src/librustc_back/target/x86_64_unknown_dragonfly.rs
new file mode 100644
index 00000000000..79f09a3b00b
--- /dev/null
+++ b/src/librustc_back/target/x86_64_unknown_dragonfly.rs
@@ -0,0 +1,23 @@
+// Copyright 2014 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.
+
+use target::Target;
+
+pub fn target() -> Target {
+    Target {
+        data_layout: "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32".to_string(),
+        llvm_target: "x86_64-unknown-dragonfly".to_string(),
+        target_endian: "little".to_string(),
+        target_word_size: "32".to_string(),
+        arch: "x86_64".to_string(),
+        target_os: "dragonfly".to_string(),
+        options: super::dragonfly_base::opts()
+    }
+}
diff --git a/src/librustc_back/target/x86_64_unknown_freebsd.rs b/src/librustc_back/target/x86_64_unknown_freebsd.rs
new file mode 100644
index 00000000000..37801f3bf25
--- /dev/null
+++ b/src/librustc_back/target/x86_64_unknown_freebsd.rs
@@ -0,0 +1,28 @@
+// Copyright 2014 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.
+
+use target::Target;
+
+pub fn target() -> Target {
+    let mut base = super::freebsd_base::opts();
+    base.pre_link_args.push("-m64".to_string());
+
+    Target {
+        data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
+                     f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
+                     s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(),
+        llvm_target: "x86_64-unknown-freebsd".to_string(),
+        target_endian: "little".to_string(),
+        target_word_size: "64".to_string(),
+        arch: "x86_64".to_string(),
+        target_os: "freebsd".to_string(),
+        options: base,
+    }
+}
diff --git a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs
new file mode 100644
index 00000000000..ac04e6e14ba
--- /dev/null
+++ b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs
@@ -0,0 +1,28 @@
+// Copyright 2014 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.
+
+use target::Target;
+
+pub fn target() -> Target {
+    let mut base = super::linux_base::opts();
+    base.pre_link_args.push("-m64".to_string());
+
+    Target {
+        data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
+                      f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
+                      s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(),
+        llvm_target: "x86_64-unknown-linux-gnu".to_string(),
+        target_endian: "little".to_string(),
+        target_word_size: "64".to_string(),
+        arch: "x86_64".to_string(),
+        target_os: "linux".to_string(),
+        options: base,
+    }
+}
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 3e8ebc00579..93662b3b63e 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -183,7 +183,7 @@ fn runtest(test: &str, cratename: &str, libs: Vec<Path>, externs: core::Externs,
     // environment to ensure that the target loads the right libraries at
     // runtime. It would be a sad day if the *host* libraries were loaded as a
     // mistake.
-    let mut cmd = Command::new(outdir.path().join("rust_out"));
+    let mut cmd = Command::new(outdir.path().join("rust-out"));
     let newpath = {
         let mut path = DynamicLibrary::search_path();
         path.insert(0, libdir.clone());
diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs
index dc41f3d9279..912755d0ea0 100644
--- a/src/libsyntax/abi.rs
+++ b/src/libsyntax/abi.rs
@@ -37,9 +37,6 @@ pub enum Abi {
 #[allow(non_camel_case_types)]
 #[deriving(PartialEq)]
 pub enum Architecture {
-    // NB. You cannot change the ordering of these
-    // constants without adjusting IntelBits below.
-    // (This is ensured by the test indices_are_correct().)
     X86,
     X86_64,
     Arm,
@@ -47,20 +44,11 @@ pub enum Architecture {
     Mipsel
 }
 
-#[allow(non_upper_case_globals)]
-const IntelBits: u32 = (1 << (X86 as uint)) | (1 << (X86_64 as uint));
-#[allow(non_upper_case_globals)]
-const ArmBits: u32 = (1 << (Arm as uint));
-
 pub struct AbiData {
     abi: Abi,
 
     // Name of this ABI as we like it called.
     name: &'static str,
-
-    // Is it specific to a platform? If so, which one?  Also, what is
-    // the name that LLVM gives it (in case we disagree)
-    abi_arch: AbiArchitecture
 }
 
 pub enum AbiArchitecture {
@@ -75,22 +63,21 @@ pub enum AbiArchitecture {
 #[allow(non_upper_case_globals)]
 static AbiDatas: &'static [AbiData] = &[
     // Platform-specific ABIs
-    AbiData {abi: Cdecl, name: "cdecl", abi_arch: Archs(IntelBits)},
-    AbiData {abi: Stdcall, name: "stdcall", abi_arch: Archs(IntelBits)},
-    AbiData {abi: Fastcall, name:"fastcall", abi_arch: Archs(IntelBits)},
-    AbiData {abi: Aapcs, name: "aapcs", abi_arch: Archs(ArmBits)},
-    AbiData {abi: Win64, name: "win64",
-             abi_arch: Archs(1 << (X86_64 as uint))},
+    AbiData {abi: Cdecl, name: "cdecl" },
+    AbiData {abi: Stdcall, name: "stdcall" },
+    AbiData {abi: Fastcall, name:"fastcall" },
+    AbiData {abi: Aapcs, name: "aapcs" },
+    AbiData {abi: Win64, name: "win64" },
 
     // Cross-platform ABIs
     //
     // NB: Do not adjust this ordering without
     // adjusting the indices below.
-    AbiData {abi: Rust, name: "Rust", abi_arch: RustArch},
-    AbiData {abi: C, name: "C", abi_arch: AllArch},
-    AbiData {abi: System, name: "system", abi_arch: AllArch},
-    AbiData {abi: RustIntrinsic, name: "rust-intrinsic", abi_arch: RustArch},
-    AbiData {abi: RustCall, name: "rust-call", abi_arch: RustArch},
+    AbiData {abi: Rust, name: "Rust" },
+    AbiData {abi: C, name: "C" },
+    AbiData {abi: System, name: "system" },
+    AbiData {abi: RustIntrinsic, name: "rust-intrinsic" },
+    AbiData {abi: RustCall, name: "rust-call" },
 ];
 
 /// Returns the ABI with the given name (if any).
@@ -116,28 +103,6 @@ impl Abi {
     pub fn name(&self) -> &'static str {
         self.data().name
     }
-
-    pub fn for_target(&self, os: Os, arch: Architecture) -> Option<Abi> {
-        // If this ABI isn't actually for the specified architecture, then we
-        // short circuit early
-        match self.data().abi_arch {
-            Archs(a) if a & arch.bit() == 0 => return None,
-            Archs(_) | RustArch | AllArch => {}
-        }
-        // Transform this ABI as appropriate for the requested os/arch
-        // combination.
-        Some(match (*self, os, arch) {
-            (System, OsWindows, X86) => Stdcall,
-            (System, _, _) => C,
-            (me, _, _) => me,
-        })
-    }
-}
-
-impl Architecture {
-    fn bit(&self) -> u32 {
-        1 << (*self as uint)
-    }
 }
 
 impl fmt::Show for Abi {
@@ -184,23 +149,4 @@ fn indices_are_correct() {
     for (i, abi_data) in AbiDatas.iter().enumerate() {
         assert_eq!(i, abi_data.abi.index());
     }
-
-    let bits = 1 << (X86 as uint);
-    let bits = bits | 1 << (X86_64 as uint);
-    assert_eq!(IntelBits, bits);
-
-    let bits = 1 << (Arm as uint);
-    assert_eq!(ArmBits, bits);
-}
-
-#[test]
-fn pick_uniplatform() {
-    assert_eq!(Stdcall.for_target(OsLinux, X86), Some(Stdcall));
-    assert_eq!(Stdcall.for_target(OsLinux, Arm), None);
-    assert_eq!(System.for_target(OsLinux, X86), Some(C));
-    assert_eq!(System.for_target(OsWindows, X86), Some(Stdcall));
-    assert_eq!(System.for_target(OsWindows, X86_64), Some(C));
-    assert_eq!(System.for_target(OsWindows, Arm), Some(C));
-    assert_eq!(Stdcall.for_target(OsWindows, X86), Some(Stdcall));
-    assert_eq!(Stdcall.for_target(OsWindows, X86_64), Some(Stdcall));
 }
diff --git a/src/test/run-make/rustdoc-hidden-line/Makefile b/src/test/run-make/rustdoc-hidden-line/Makefile
index b08c6625f17..bc7e4e5863e 100644
--- a/src/test/run-make/rustdoc-hidden-line/Makefile
+++ b/src/test/run-make/rustdoc-hidden-line/Makefile
@@ -4,6 +4,7 @@
 ifndef IS_WINDOWS
 
 all:
+	@echo $(RUSTDOC)
 	$(HOST_RPATH_ENV) $(RUSTDOC) --test foo.rs
 	$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs
 	cp verify.sh $(TMPDIR)
diff --git a/src/test/run-make/target-specs/Makefile b/src/test/run-make/target-specs/Makefile
new file mode 100644
index 00000000000..746870d201f
--- /dev/null
+++ b/src/test/run-make/target-specs/Makefile
@@ -0,0 +1,11 @@
+-include ../tools.mk
+all:
+	$(RUSTC) foo.rs --target=my-awesome-platform.json --crate-type=lib --emit=asm
+	grep --quiet --invert-match morestack < $(TMPDIR)/foo.s
+	$(RUSTC) foo.rs --target=my-invalid-platform.json 2>&1 | grep --quiet --invert-match "Error loading taget specification"
+	$(RUSTC) foo.rs --target=my-incomplete-platform.json 2>&1 | grep 'Field llvm-target'
+	RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=my-awesome-platform --crate-type=lib --emit=asm
+	RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=x86_64-unknown-linux-gnu --crate-type=lib --emit=asm
+	# The built-in target *should* override the one we have here, and thus we
+	# should have morestack
+	grep --quiet morestack < $(TMPDIR)/foo.s
diff --git a/src/test/run-make/target-specs/foo.rs b/src/test/run-make/target-specs/foo.rs
new file mode 100644
index 00000000000..eeddd5e19a8
--- /dev/null
+++ b/src/test/run-make/target-specs/foo.rs
@@ -0,0 +1,26 @@
+// Copyright 2014 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.
+
+#![feature(lang_items)]
+#![no_std]
+
+#[lang="sized"]
+trait Sized { }
+
+#[lang="start"]
+fn start(_main: *const u8, _argc: int, _argv: *const *const u8) -> int { 0 }
+
+extern {
+    fn _foo() -> [u8, ..16];
+}
+
+fn _main() {
+    let _a = unsafe { _foo() };
+}
diff --git a/src/test/run-make/target-specs/my-awesome-platform.json b/src/test/run-make/target-specs/my-awesome-platform.json
new file mode 100644
index 00000000000..f5f622bbcda
--- /dev/null
+++ b/src/test/run-make/target-specs/my-awesome-platform.json
@@ -0,0 +1,9 @@
+{
+    "data-layout": "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32",
+    "llvm-target": "i686-unknown-linux-gnu",
+    "target-endian": "little",
+    "target-word-size": "32",
+    "arch": "x86",
+    "os": "linux",
+    "morestack": false
+}
diff --git a/src/test/run-make/target-specs/my-incomplete-platform.json b/src/test/run-make/target-specs/my-incomplete-platform.json
new file mode 100644
index 00000000000..5005a9ff839
--- /dev/null
+++ b/src/test/run-make/target-specs/my-incomplete-platform.json
@@ -0,0 +1,8 @@
+{
+    "data-layout": "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32",
+    "target-endian": "little",
+    "target-word-size": "32",
+    "arch": "x86",
+    "os": "foo",
+    "morestack": false
+}
diff --git a/src/test/run-make/target-specs/my-invalid-platform.json b/src/test/run-make/target-specs/my-invalid-platform.json
new file mode 100644
index 00000000000..3feac45b7d6
--- /dev/null
+++ b/src/test/run-make/target-specs/my-invalid-platform.json
@@ -0,0 +1 @@
+wow this json is really broke!
diff --git a/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json b/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json
new file mode 100644
index 00000000000..f5f622bbcda
--- /dev/null
+++ b/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json
@@ -0,0 +1,9 @@
+{
+    "data-layout": "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32",
+    "llvm-target": "i686-unknown-linux-gnu",
+    "target-endian": "little",
+    "target-word-size": "32",
+    "arch": "x86",
+    "os": "linux",
+    "morestack": false
+}