about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-07-05 22:51:38 +0000
committerbors <bors@rust-lang.org>2014-07-05 22:51:38 +0000
commitc3ef04be5589901e7f3d9428ebe8f1eb2bdca7e4 (patch)
tree38550cd6dbb5daa27969c3f05b3e46c01ba4f2d0
parentb8ef5cf1310a7b1e31d0993885d867a6804597ad (diff)
parent56f71015515490b65b5fbb46ff0bbc7d7af82450 (diff)
downloadrust-c3ef04be5589901e7f3d9428ebe8f1eb2bdca7e4.tar.gz
rust-c3ef04be5589901e7f3d9428ebe8f1eb2bdca7e4.zip
auto merge of #15319 : alexcrichton/rust/no-crate-id, r=brson
This is an implementation of [RFC 35](https://github.com/rust-lang/rfcs/blob/master/active/0035-remove-crate-id.md).

The summary for this PR is the same as that of the RFC, with one addendum:


* Removes the `#[crate_id]` attribute and knowledge of versions from rustc.
* Added a `#[crate_name]` attribute similar to the old `#[crate_id]` attribute
* Output filenames no longer have versions or hashes
* Symbols no longer have versions (they still have hashes)
* A new flag, `--extern`, is used to override searching for external crates
* A new flag, `-C metadata=foo`, used when hashing symbols
* [added] An old flag, `--crate-name`, was re purposed to specify the crate name from the command line.

I tried to maintain backwards compatibility wherever possible (with warnings being printed). If I missed anywhere, however, please let me know!

[breaking-change]

Closes #14468
Closes #14469
Closes #14470
Closes #14471
-rw-r--r--mk/main.mk2
-rw-r--r--mk/target.mk11
-rw-r--r--src/liballoc/lib.rs4
-rw-r--r--src/libarena/lib.rs2
-rw-r--r--src/libcollections/lib.rs4
-rw-r--r--src/libcore/lib.rs2
-rw-r--r--src/libdebug/lib.rs4
-rw-r--r--src/libflate/lib.rs4
-rw-r--r--src/libfmt_macros/lib.rs4
-rw-r--r--src/libfourcc/lib.rs4
-rw-r--r--src/libgetopts/lib.rs4
-rw-r--r--src/libglob/lib.rs4
-rw-r--r--src/libgraphviz/lib.rs6
-rw-r--r--src/libgreen/lib.rs10
-rw-r--r--src/libhexfloat/lib.rs4
-rw-r--r--src/liblibc/lib.rs4
-rw-r--r--src/liblog/lib.rs5
-rw-r--r--src/libnative/lib.rs4
-rw-r--r--src/libnum/lib.rs5
-rw-r--r--src/librand/lib.rs4
-rw-r--r--src/libregex/lib.rs4
-rw-r--r--src/libregex_macros/lib.rs4
-rw-r--r--src/librlibc/lib.rs4
-rw-r--r--src/librustc/back/link.rs139
-rw-r--r--src/librustc/back/svh.rs8
-rw-r--r--src/librustc/driver/config.rs59
-rw-r--r--src/librustc/driver/driver.rs76
-rw-r--r--src/librustc/driver/mod.rs21
-rw-r--r--src/librustc/driver/session.rs2
-rw-r--r--src/librustc/front/std_inject.rs22
-rw-r--r--src/librustc/front/test.rs11
-rw-r--r--src/librustc/lib.rs4
-rw-r--r--src/librustc/metadata/common.rs7
-rw-r--r--src/librustc/metadata/creader.rs123
-rw-r--r--src/librustc/metadata/cstore.rs3
-rw-r--r--src/librustc/metadata/decoder.rs27
-rw-r--r--src/librustc/metadata/encoder.rs52
-rw-r--r--src/librustc/metadata/loader.rs399
-rw-r--r--src/librustc/middle/save/mod.rs8
-rw-r--r--src/librustc/middle/trans/base.rs16
-rw-r--r--src/librustc/middle/trans/debuginfo.rs4
-rw-r--r--src/librustc/middle/trans/foreign.rs2
-rw-r--r--src/librustc/middle/trans/monomorphize.rs4
-rw-r--r--src/librustc/middle/typeck/infer/test.rs6
-rw-r--r--src/librustdoc/clean/mod.rs10
-rw-r--r--src/librustdoc/core.rs9
-rw-r--r--src/librustdoc/lib.rs4
-rw-r--r--src/librustdoc/test.rs2
-rw-r--r--src/librustrt/lib.rs4
-rw-r--r--src/librustuv/lib.rs4
-rw-r--r--src/libsemver/lib.rs4
-rw-r--r--src/libserialize/lib.rs4
-rw-r--r--src/libstd/lib.rs4
-rw-r--r--src/libsync/lib.rs4
-rw-r--r--src/libsyntax/attr.rs8
-rw-r--r--src/libsyntax/ext/base.rs2
-rw-r--r--src/libsyntax/ext/expand.rs11
-rw-r--r--src/libsyntax/lib.rs4
-rw-r--r--src/libterm/lib.rs4
-rw-r--r--src/libtest/lib.rs4
-rw-r--r--src/libtime/lib.rs4
-rw-r--r--src/liburl/lib.rs4
-rw-r--r--src/libuuid/lib.rs4
-rw-r--r--src/test/auxiliary/crateresolve1-1.rs4
-rw-r--r--src/test/auxiliary/crateresolve1-2.rs4
-rw-r--r--src/test/auxiliary/crateresolve1-3.rs4
-rw-r--r--src/test/auxiliary/crateresolve2-1.rs15
-rw-r--r--src/test/auxiliary/extern-crosscrate-source.rs2
-rw-r--r--src/test/compile-fail/bad-crate-id.rs3
-rw-r--r--src/test/compile-fail/bad-crate-id2.rs (renamed from src/test/auxiliary/crateresolve2-2.rs)7
-rw-r--r--src/test/compile-fail/crateresolve2.rs24
-rw-r--r--src/test/compile-fail/crateresolve5.rs21
-rw-r--r--src/test/compile-fail/issue-11908-1.rs24
-rw-r--r--src/test/run-make/bootstrap-from-c-with-green/Makefile1
-rw-r--r--src/test/run-make/bootstrap-from-c-with-green/lib.rs2
-rw-r--r--src/test/run-make/bootstrap-from-c-with-native/Makefile1
-rw-r--r--src/test/run-make/c-link-to-rust-dylib/Makefile1
-rw-r--r--src/test/run-make/c-link-to-rust-staticlib/Makefile1
-rw-r--r--src/test/run-make/crate-data-smoke/Makefile13
-rw-r--r--src/test/run-make/crate-data-smoke/crate.rs2
-rw-r--r--src/test/run-make/crate-data-smoke/lib.rs2
-rw-r--r--src/test/run-make/crate-data-smoke/rlib.rs2
-rw-r--r--src/test/run-make/dep-info/lib.rs2
-rw-r--r--src/test/run-make/extern-flag-disambiguates/Makefile24
-rw-r--r--src/test/run-make/extern-flag-disambiguates/a.rs16
-rw-r--r--src/test/run-make/extern-flag-disambiguates/b.rs (renamed from src/test/compile-fail/issue-11908-2.rs)14
-rw-r--r--src/test/run-make/extern-flag-disambiguates/c.rs19
-rw-r--r--src/test/run-make/extern-flag-disambiguates/d.rs (renamed from src/test/run-pass/crateresolve8.rs)17
-rw-r--r--src/test/run-make/extern-flag-fun/Makefile16
-rw-r--r--src/test/run-make/extern-flag-fun/bar.rs10
-rw-r--r--src/test/run-make/extern-flag-fun/foo.rs (renamed from src/test/auxiliary/issue-11908-1.rs)5
-rw-r--r--src/test/run-make/issue-11908/Makefile23
-rw-r--r--src/test/run-make/issue-11908/bar.rs (renamed from src/test/compile-fail/use-meta.rc)6
-rw-r--r--src/test/run-make/issue-11908/foo.rs11
-rw-r--r--src/test/run-make/lto-smoke-c/Makefile1
-rw-r--r--src/test/run-make/lto-syntax-extension/lib.rs2
-rw-r--r--src/test/run-make/manual-crate-name/Makefile5
-rw-r--r--src/test/run-make/manual-crate-name/bar.rs (renamed from src/test/auxiliary/issue-11908-2.rs)3
-rw-r--r--src/test/run-make/metadata-flag-frobs-symbols/Makefile10
-rw-r--r--src/test/run-make/metadata-flag-frobs-symbols/bar.rs18
-rw-r--r--src/test/run-make/metadata-flag-frobs-symbols/foo.rs16
-rw-r--r--src/test/run-make/multiple-versions/Makefile9
-rw-r--r--src/test/run-make/multiple-versions/bar.rs (renamed from src/test/auxiliary/crateresolve2-3.rs)9
-rw-r--r--src/test/run-make/multiple-versions/foo.rs11
-rw-r--r--src/test/run-make/output-type-permutations/foo.rs2
-rw-r--r--src/test/run-make/weird-output-filenames/Makefile15
-rw-r--r--src/test/run-pass/crateresolve1.rs19
-rw-r--r--src/test/run-pass/crateresolve2.rs34
-rw-r--r--src/test/run-pass/crateresolve3.rs30
-rw-r--r--src/test/run-pass/crateresolve4.rs29
-rw-r--r--src/test/run-pass/crateresolve5.rs23
-rw-r--r--src/test/run-pass/extern-crosscrate.rs2
-rw-r--r--src/test/run-pass/use.rs2
113 files changed, 1009 insertions, 717 deletions
diff --git a/mk/main.mk b/mk/main.mk
index c4be89033a6..c01410a591b 100644
--- a/mk/main.mk
+++ b/mk/main.mk
@@ -16,6 +16,8 @@
 CFG_RELEASE_NUM=0.11.0
 CFG_RELEASE_LABEL=
 
+CFG_FILENAME_EXTRA=4e7c5e5c
+
 ifndef CFG_ENABLE_NIGHTLY
 # This is the normal version string
 CFG_RELEASE=$(CFG_RELEASE_NUM)$(CFG_RELEASE_LABEL)
diff --git a/mk/target.mk b/mk/target.mk
index 0f63ef9a430..b7a570e3275 100644
--- a/mk/target.mk
+++ b/mk/target.mk
@@ -44,6 +44,13 @@ $(foreach host,$(CFG_HOST),						    \
    $(foreach crate,$(CRATES),						    \
     $(eval $(call RUST_CRATE_FULLDEPS,$(stage),$(target),$(host),$(crate)))))))
 
+# NOTE: after a stage0 snap this should be just EXTRA_FILENAME, not with a stage
+# bound
+EXTRA_FILENAME_0 =
+EXTRA_FILENAME_1 = -C extra-filename=-$(CFG_FILENAME_EXTRA)
+EXTRA_FILENAME_2 = -C extra-filename=-$(CFG_FILENAME_EXTRA)
+EXTRA_FILENAME_3 = -C extra-filename=-$(CFG_FILENAME_EXTRA)
+
 # RUST_TARGET_STAGE_N template: This defines how target artifacts are built
 # for all stage/target architecture combinations. This is one giant rule which
 # works as follows:
@@ -85,7 +92,9 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4):				    \
 		-L "$$(LLVM_LIBDIR_$(2))" \
 		-L "$$(dir $$(LLVM_STDCPP_LOCATION_$(2)))" \
 		$$(RUSTFLAGS_$(4)) \
-		--out-dir $$(@D) $$<
+		--out-dir $$(@D) \
+		$$(EXTRA_FILENAME_$(1)) \
+		$$<
 	@touch $$@
 	$$(call LIST_ALL_OLD_GLOB_MATCHES,\
 	    $$(dir $$@)$$(call CFG_LIB_GLOB_$(2),$(4)))
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 26b8ccaf573..3e403d122ac 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -60,7 +60,8 @@
 //! by libc malloc/free.  The `libc_heap` module is defined to be wired up to
 //! the system malloc/free.
 
-#![crate_id = "alloc#0.11.0"]
+#![crate_id = "alloc#0.11.0"] // NOTE: remove after a stage0 snap
+#![crate_name = "alloc"]
 #![experimental]
 #![license = "MIT/ASL2"]
 #![crate_type = "rlib"]
@@ -70,6 +71,7 @@
 
 #![no_std]
 #![feature(lang_items, phase, unsafe_destructor)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 #[phase(plugin, link)]
 extern crate core;
diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs
index 917de94470b..51eacd3fb4e 100644
--- a/src/libarena/lib.rs
+++ b/src/libarena/lib.rs
@@ -20,6 +20,7 @@
 //! more complex, slower Arena which can hold objects of any type.
 
 #![crate_id = "arena#0.11.0"]
+#![crate_name = "arena"]
 #![experimental]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
@@ -30,6 +31,7 @@
 
 #![feature(unsafe_destructor)]
 #![allow(missing_doc)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 use std::cell::{Cell, RefCell};
 use std::cmp;
diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs
index c698b35c848..d9a62cd9acd 100644
--- a/src/libcollections/lib.rs
+++ b/src/libcollections/lib.rs
@@ -12,7 +12,8 @@
  * Collection types.
  */
 
-#![crate_id = "collections#0.11.0"]
+#![crate_id = "collections#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "collections"]
 #![experimental]
 #![crate_type = "rlib"]
 #![license = "MIT/ASL2"]
@@ -24,6 +25,7 @@
 #![feature(macro_rules, managed_boxes, default_type_params, phase, globs)]
 #![feature(unsafe_destructor)]
 #![no_std]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 #[phase(plugin, link)] extern crate core;
 extern crate alloc;
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 5e238aeae32..6966c96b30b 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -48,6 +48,7 @@
 // separate crate, libcoretest, to avoid bizarre issues.
 
 #![crate_id = "core#0.11.0"]
+#![crate_name = "core"]
 #![experimental]
 #![license = "MIT/ASL2"]
 #![crate_type = "rlib"]
@@ -60,6 +61,7 @@
 #![feature(globs, intrinsics, lang_items, macro_rules, managed_boxes, phase)]
 #![feature(simd, unsafe_destructor)]
 #![deny(missing_doc)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 mod macros;
 
diff --git a/src/libdebug/lib.rs b/src/libdebug/lib.rs
index 850002b595e..e5424fccbed 100644
--- a/src/libdebug/lib.rs
+++ b/src/libdebug/lib.rs
@@ -16,7 +16,8 @@
 //! Additionally, it is not guaranteed that functionality such as reflection
 //! will persist into the future.
 
-#![crate_id = "debug#0.11.0"]
+#![crate_id = "debug#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "debug"]
 #![experimental]
 #![license = "MIT/ASL2"]
 #![crate_type = "rlib"]
@@ -27,6 +28,7 @@
 #![experimental]
 #![feature(managed_boxes, macro_rules)]
 #![allow(experimental)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 pub mod fmt;
 pub mod reflect;
diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs
index d944818abc5..923aab5e032 100644
--- a/src/libflate/lib.rs
+++ b/src/libflate/lib.rs
@@ -18,7 +18,8 @@ Simple [DEFLATE][def]-based compression. This is a wrapper around the
 
 */
 
-#![crate_id = "flate#0.11.0"]
+#![crate_id = "flate#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "flate"]
 #![experimental]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
@@ -27,6 +28,7 @@ Simple [DEFLATE][def]-based compression. This is a wrapper around the
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/0.11.0/")]
 #![feature(phase)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 #[cfg(test)] #[phase(plugin, link)] extern crate log;
 
diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs
index b9c0fcce52d..c32f27adf65 100644
--- a/src/libfmt_macros/lib.rs
+++ b/src/libfmt_macros/lib.rs
@@ -14,12 +14,14 @@
 //! Parsing does not happen at runtime: structures of `std::fmt::rt` are
 //! generated instead.
 
-#![crate_id = "fmt_macros#0.11.0"]
+#![crate_id = "fmt_macros#0.11.0"] // NOTE: remove after stage0c
+#![crate_name = "fmt_macros"]
 #![experimental]
 #![license = "MIT/ASL2"]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
 #![feature(macro_rules, globs)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 use std::char;
 use std::str;
diff --git a/src/libfourcc/lib.rs b/src/libfourcc/lib.rs
index e854cd3069c..55e55ba7e51 100644
--- a/src/libfourcc/lib.rs
+++ b/src/libfourcc/lib.rs
@@ -39,7 +39,8 @@ fn main() {
 
 */
 
-#![crate_id = "fourcc#0.11.0"]
+#![crate_id = "fourcc#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "fourcc"]
 #![experimental]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
@@ -47,6 +48,7 @@ fn main() {
 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 #![feature(plugin_registrar, managed_boxes)]
 
diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs
index 00e6df9ffbb..790df13c1ff 100644
--- a/src/libgetopts/lib.rs
+++ b/src/libgetopts/lib.rs
@@ -76,7 +76,8 @@
 //! }
 //! ~~~
 
-#![crate_id = "getopts#0.11.0"]
+#![crate_id = "getopts#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "getopts"]
 #![experimental]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
@@ -87,6 +88,7 @@
        html_playground_url = "http://play.rust-lang.org/")]
 #![feature(globs, phase)]
 #![deny(missing_doc)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 #[cfg(test)] extern crate debug;
 #[cfg(test)] #[phase(plugin, link)] extern crate log;
diff --git a/src/libglob/lib.rs b/src/libglob/lib.rs
index 3cb21601e33..6aa48dc748e 100644
--- a/src/libglob/lib.rs
+++ b/src/libglob/lib.rs
@@ -23,7 +23,8 @@
  * `glob`/`fnmatch` functions.
  */
 
-#![crate_id = "glob#0.11.0"]
+#![crate_id = "glob#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "glob"]
 #![experimental]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
@@ -32,6 +33,7 @@
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/0.11.0/",
        html_playground_url = "http://play.rust-lang.org/")]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 use std::cell::Cell;
 use std::{cmp, os, path};
diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs
index 16298f51ea9..52990bae554 100644
--- a/src/libgraphviz/lib.rs
+++ b/src/libgraphviz/lib.rs
@@ -266,7 +266,8 @@ pub fn main() {
 
 */
 
-#![crate_id = "graphviz#0.11.0"]
+#![crate_id = "graphviz#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "graphviz"]
 #![experimental]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
@@ -274,8 +275,7 @@ pub fn main() {
 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/0.11.0/")]
-
-#![experimental]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 use std::io;
 use std::str;
diff --git a/src/libgreen/lib.rs b/src/libgreen/lib.rs
index 1b34679b0a1..357644aed03 100644
--- a/src/libgreen/lib.rs
+++ b/src/libgreen/lib.rs
@@ -197,7 +197,8 @@
 //! pool.shutdown();
 //! ```
 
-#![crate_id = "green#0.11.0"]
+#![crate_id = "green#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "green"]
 #![experimental]
 #![license = "MIT/ASL2"]
 #![crate_type = "rlib"]
@@ -208,10 +209,9 @@
        html_playground_url = "http://play.rust-lang.org/")]
 
 // NB this does *not* include globs, please keep it that way.
-#![feature(macro_rules, phase)]
-#![allow(visible_private_types)]
-#![allow(deprecated)]
-#![feature(default_type_params)]
+#![feature(macro_rules, phase, default_type_params)]
+#![allow(visible_private_types, deprecated)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 #[cfg(test)] #[phase(plugin, link)] extern crate log;
 #[cfg(test)] extern crate rustuv;
diff --git a/src/libhexfloat/lib.rs b/src/libhexfloat/lib.rs
index 64538bd2212..17c71c6365e 100644
--- a/src/libhexfloat/lib.rs
+++ b/src/libhexfloat/lib.rs
@@ -36,7 +36,8 @@ fn main() {
 
 */
 
-#![crate_id = "hexfloat#0.11.0"]
+#![crate_id = "hexfloat#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "hexfloat"]
 #![experimental]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
@@ -45,6 +46,7 @@ fn main() {
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/0.11.0/")]
 #![feature(plugin_registrar, managed_boxes)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 extern crate syntax;
 extern crate rustc;
diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs
index 81e50889952..e0dd57f6ae9 100644
--- a/src/liblibc/lib.rs
+++ b/src/liblibc/lib.rs
@@ -9,7 +9,8 @@
 // except according to those terms.
 
 #![feature(globs)]
-#![crate_id = "libc#0.11.0"]
+#![crate_id = "libc#0.11.0"] // NOTE: remove after a stage0 snap
+#![crate_name = "libc"]
 #![experimental]
 #![no_std] // we don't need std, and we can't have std, since it doesn't exist
            // yet. std depends on us.
@@ -18,6 +19,7 @@
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/0.11.0/",
        html_playground_url = "http://play.rust-lang.org/")]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 /*!
 * Bindings for the C standard library and other platform libraries
diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs
index 6216e79fe84..33d1cc87b73 100644
--- a/src/liblog/lib.rs
+++ b/src/liblog/lib.rs
@@ -105,7 +105,8 @@ if logging is disabled, none of the components of the log will be executed.
 
 */
 
-#![crate_id = "log#0.11.0"]
+#![crate_id = "log#0.11.0"] // NOTE: Remove after stage0
+#![crate_name = "log"]
 #![experimental]
 #![license = "MIT/ASL2"]
 #![crate_type = "rlib"]
@@ -114,7 +115,7 @@ if logging is disabled, none of the components of the log will be executed.
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/0.11.0/",
        html_playground_url = "http://play.rust-lang.org/")]
-
+#![allow(unused_attribute)] // NOTE: remove after stage0
 #![feature(macro_rules)]
 #![deny(missing_doc)]
 
diff --git a/src/libnative/lib.rs b/src/libnative/lib.rs
index 2e43ddba644..85813a7dde3 100644
--- a/src/libnative/lib.rs
+++ b/src/libnative/lib.rs
@@ -46,7 +46,8 @@
 //! }
 //! ```
 
-#![crate_id = "native#0.11.0"]
+#![crate_id = "native#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "native"]
 #![experimental]
 #![license = "MIT/ASL2"]
 #![crate_type = "rlib"]
@@ -57,6 +58,7 @@
 
 #![deny(unused_result, unused_must_use)]
 #![allow(non_camel_case_types, deprecated)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 #![feature(default_type_params, lang_items)]
 
 // NB this crate explicitly does *not* allow glob imports, please seriously
diff --git a/src/libnum/lib.rs b/src/libnum/lib.rs
index db0cd7f2567..06e69c132bd 100644
--- a/src/libnum/lib.rs
+++ b/src/libnum/lib.rs
@@ -44,7 +44,8 @@
 
 #![feature(macro_rules)]
 
-#![crate_id = "num#0.11.0"]
+#![crate_id = "num#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "num"]
 #![experimental]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
@@ -53,7 +54,7 @@
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/0.11.0/",
        html_playground_url = "http://play.rust-lang.org/")]
-
+#![allow(unused_attribute)] // NOTE: remove after stage0
 #![allow(deprecated)] // from_str_radix
 
 extern crate rand;
diff --git a/src/librand/lib.rs b/src/librand/lib.rs
index 593b9785d47..ac0f59225e8 100644
--- a/src/librand/lib.rs
+++ b/src/librand/lib.rs
@@ -16,7 +16,8 @@
 //! is not recommended to use this library directly, but rather the official
 //! interface through `std::rand`.
 
-#![crate_id = "rand#0.11.0"]
+#![crate_id = "rand#0.11.0"] // NOTE: remove after a stage0 snap
+#![crate_name = "rand"]
 #![license = "MIT/ASL2"]
 #![crate_type = "rlib"]
 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
@@ -25,6 +26,7 @@
        html_playground_url = "http://play.rust-lang.org/")]
 
 #![feature(macro_rules, phase, globs)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 #![no_std]
 #![experimental]
 
diff --git a/src/libregex/lib.rs b/src/libregex/lib.rs
index b69c4471267..2275f9639d1 100644
--- a/src/libregex/lib.rs
+++ b/src/libregex/lib.rs
@@ -353,7 +353,8 @@
 //! characters in the search text and `m` is the number of instructions in a
 //! compiled expression.
 
-#![crate_id = "regex#0.11.0"]
+#![crate_id = "regex#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "regex"]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
 #![experimental]
@@ -364,6 +365,7 @@
        html_playground_url = "http://play.rust-lang.org/")]
 
 #![feature(macro_rules, phase)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 #![deny(missing_doc)]
 
 #[cfg(test)]
diff --git a/src/libregex_macros/lib.rs b/src/libregex_macros/lib.rs
index e699816347c..c15b232d8e1 100644
--- a/src/libregex_macros/lib.rs
+++ b/src/libregex_macros/lib.rs
@@ -11,13 +11,15 @@
 //! This crate provides the `regex!` macro. Its use is documented in the
 //! `regex` crate.
 
-#![crate_id = "regex_macros#0.11.0"]
+#![crate_id = "regex_macros#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "regex_macros"]
 #![crate_type = "dylib"]
 #![experimental]
 #![license = "MIT/ASL2"]
 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 #![feature(plugin_registrar, managed_boxes, quote)]
 
diff --git a/src/librlibc/lib.rs b/src/librlibc/lib.rs
index c653e1ca077..7b0fd3d6366 100644
--- a/src/librlibc/lib.rs
+++ b/src/librlibc/lib.rs
@@ -20,13 +20,15 @@
 //! necessary. It is an error to include this library when also linking with
 //! the system libc library.
 
-#![crate_id = "rlibc#0.11.0"]
+#![crate_id = "rlibc#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "rlibc"]
 #![license = "MIT/ASL2"]
 #![crate_type = "rlib"]
 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/0.11.0/")]
 #![feature(intrinsics)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 #![no_std]
 #![experimental]
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index a190d9309cc..f1856850701 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -11,7 +11,7 @@
 use back::archive::{Archive, METADATA_FILENAME};
 use back::rpath;
 use back::svh::Svh;
-use driver::driver::{CrateTranslation, OutputFilenames};
+use driver::driver::{CrateTranslation, OutputFilenames, Input, FileInput};
 use driver::config::NoDebugInfo;
 use driver::session::Session;
 use driver::config;
@@ -19,7 +19,7 @@ use lib::llvm::llvm;
 use lib::llvm::ModuleRef;
 use lib;
 use metadata::common::LinkMeta;
-use metadata::{encoder, cstore, filesearch, csearch, loader};
+use metadata::{encoder, cstore, filesearch, csearch, loader, creader};
 use middle::trans::context::CrateContext;
 use middle::trans::common::gensym_name;
 use middle::ty;
@@ -40,9 +40,8 @@ use syntax::abi;
 use syntax::ast;
 use syntax::ast_map::{PathElem, PathElems, PathName};
 use syntax::ast_map;
-use syntax::attr;
 use syntax::attr::AttrMetaMethods;
-use syntax::crateid::CrateId;
+use syntax::codemap::Span;
 use syntax::parse::token;
 
 #[deriving(Clone, PartialEq, PartialOrd, Ord, Eq)]
@@ -546,32 +545,69 @@ pub mod write {
  *    system linkers understand.
  */
 
-// FIXME (#9639): This needs to handle non-utf8 `out_filestem` values
-pub fn find_crate_id(attrs: &[ast::Attribute], out_filestem: &str) -> CrateId {
-    match attr::find_crateid(attrs) {
-        None => from_str(out_filestem).unwrap_or_else(|| {
-            let mut s = out_filestem.chars().filter(|c| c.is_XID_continue());
-            from_str(s.collect::<String>().as_slice())
-                .or(from_str("rust-out")).unwrap()
-        }),
-        Some(s) => s,
+pub fn find_crate_name(sess: Option<&Session>,
+                       attrs: &[ast::Attribute],
+                       input: &Input) -> String {
+    use syntax::crateid::CrateId;
+
+    let validate = |s: String, span: Option<Span>| {
+        creader::validate_crate_name(sess, s.as_slice(), span);
+        s
+    };
+
+    match sess {
+        Some(sess) => {
+            match sess.opts.crate_name {
+                Some(ref s) => return validate(s.clone(), None),
+                None => {}
+            }
+        }
+        None => {}
+    }
+
+    let crate_name = attrs.iter().find(|at| at.check_name("crate_name"))
+                          .and_then(|at| at.value_str().map(|s| (at, s)));
+    match crate_name {
+        Some((attr, s)) => return validate(s.get().to_string(), Some(attr.span)),
+        None => {}
+    }
+    let crate_id = attrs.iter().find(|at| at.check_name("crate_id"))
+                        .and_then(|at| at.value_str().map(|s| (at, s)))
+                        .and_then(|(at, s)| {
+                            from_str::<CrateId>(s.get()).map(|id| (at, id))
+                        });
+    match crate_id {
+        Some((attr, id)) => {
+            match sess {
+                Some(sess) => {
+                    sess.span_warn(attr.span, "the #[crate_id] attribute is \
+                                               deprecated for the \
+                                               #[crate_name] attribute");
+                }
+                None => {}
+            }
+            return validate(id.name, Some(attr.span))
+        }
+        None => {}
+    }
+    match *input {
+        FileInput(ref path) => {
+            match path.filestem_str() {
+                Some(s) => return validate(s.to_string(), None),
+                None => {}
+            }
+        }
+        _ => {}
     }
-}
 
-pub fn crate_id_hash(crate_id: &CrateId) -> String {
-    // This calculates CMH as defined above. Note that we don't use the path of
-    // the crate id in the hash because lookups are only done by (name/vers),
-    // not by path.
-    let mut s = Sha256::new();
-    s.input_str(crate_id.short_name_with_version().as_slice());
-    truncated_hash_result(&mut s).as_slice().slice_to(8).to_string()
+    "rust-out".to_string()
 }
 
-// FIXME (#9639): This needs to handle non-utf8 `out_filestem` values
-pub fn build_link_meta(krate: &ast::Crate, out_filestem: &str) -> LinkMeta {
+pub fn build_link_meta(sess: &Session, krate: &ast::Crate,
+                       name: String) -> LinkMeta {
     let r = LinkMeta {
-        crateid: find_crate_id(krate.attrs.as_slice(), out_filestem),
-        crate_hash: Svh::calculate(krate),
+        crate_name: name,
+        crate_hash: Svh::calculate(sess, krate),
     };
     info!("{}", r);
     return r;
@@ -594,9 +630,12 @@ fn symbol_hash(tcx: &ty::ctxt,
     // to be independent of one another in the crate.
 
     symbol_hasher.reset();
-    symbol_hasher.input_str(link_meta.crateid.name.as_slice());
+    symbol_hasher.input_str(link_meta.crate_name.as_slice());
     symbol_hasher.input_str("-");
     symbol_hasher.input_str(link_meta.crate_hash.as_str());
+    for meta in tcx.sess.crate_metadata.borrow().iter() {
+        symbol_hasher.input_str(meta.as_slice());
+    }
     symbol_hasher.input_str("-");
     symbol_hasher.input_str(encoder::encoded_ty(tcx, t).as_slice());
     // Prefix with 'h' so that it never blends into adjacent digits
@@ -666,8 +705,7 @@ pub fn sanitize(s: &str) -> String {
 }
 
 pub fn mangle<PI: Iterator<PathElem>>(mut path: PI,
-                                      hash: Option<&str>,
-                                      vers: Option<&str>) -> String {
+                                      hash: Option<&str>) -> String {
     // Follow C++ namespace-mangling style, see
     // http://en.wikipedia.org/wiki/Name_mangling for more info.
     //
@@ -698,25 +736,13 @@ pub fn mangle<PI: Iterator<PathElem>>(mut path: PI,
         Some(s) => push(&mut n, s),
         None => {}
     }
-    match vers {
-        Some(s) => push(&mut n, s),
-        None => {}
-    }
 
     n.push_char('E'); // End name-sequence.
     n
 }
 
-pub fn exported_name(path: PathElems, hash: &str, vers: &str) -> String {
-    // The version will get mangled to have a leading '_', but it makes more
-    // sense to lead with a 'v' b/c this is a version...
-    let vers = if vers.len() > 0 && !char::is_XID_start(vers.char_at(0)) {
-        format!("v{}", vers)
-    } else {
-        vers.to_string()
-    };
-
-    mangle(path, Some(hash), Some(vers.as_slice()))
+pub fn exported_name(path: PathElems, hash: &str) -> String {
+    mangle(path, Some(hash))
 }
 
 pub fn mangle_exported_name(ccx: &CrateContext, path: PathElems,
@@ -741,9 +767,7 @@ pub fn mangle_exported_name(ccx: &CrateContext, path: PathElems,
     hash.push_char(EXTRA_CHARS.as_bytes()[extra2] as char);
     hash.push_char(EXTRA_CHARS.as_bytes()[extra3] as char);
 
-    exported_name(path,
-                  hash.as_slice(),
-                  ccx.link_meta.crateid.version_or_default())
+    exported_name(path, hash.as_slice())
 }
 
 pub fn mangle_internal_name_by_type_and_seq(ccx: &CrateContext,
@@ -753,15 +777,11 @@ pub fn mangle_internal_name_by_type_and_seq(ccx: &CrateContext,
     let path = [PathName(token::intern(s.as_slice())),
                 gensym_name(name)];
     let hash = get_symbol_hash(ccx, t);
-    mangle(ast_map::Values(path.iter()), Some(hash.as_slice()), None)
+    mangle(ast_map::Values(path.iter()), Some(hash.as_slice()))
 }
 
 pub fn mangle_internal_name_by_path_and_seq(path: PathElems, flav: &str) -> String {
-    mangle(path.chain(Some(gensym_name(flav)).move_iter()), None, None)
-}
-
-pub fn output_lib_filename(id: &CrateId) -> String {
-    format!("{}-{}-{}", id.name, crate_id_hash(id), id.version_or_default())
+    mangle(path.chain(Some(gensym_name(flav)).move_iter()), None)
 }
 
 pub fn get_cc_prog(sess: &Session) -> String {
@@ -803,14 +823,15 @@ fn remove(sess: &Session, path: &Path) {
 pub fn link_binary(sess: &Session,
                    trans: &CrateTranslation,
                    outputs: &OutputFilenames,
-                   id: &CrateId) -> Vec<Path> {
+                   crate_name: &str) -> Vec<Path> {
     let mut out_filenames = Vec::new();
     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());
         }
-        let out_file = link_binary_output(sess, trans, crate_type, outputs, id);
+        let out_file = link_binary_output(sess, trans, crate_type, outputs,
+                                          crate_name);
         out_filenames.push(out_file);
     }
 
@@ -859,9 +880,11 @@ fn is_writeable(p: &Path) -> bool {
     }
 }
 
-pub fn filename_for_input(sess: &Session, crate_type: config::CrateType,
-                          id: &CrateId, out_filename: &Path) -> Path {
-    let libname = output_lib_filename(id);
+pub fn filename_for_input(sess: &Session,
+                          crate_type: config::CrateType,
+                          name: &str,
+                          out_filename: &Path) -> Path {
+    let libname = format!("{}{}", name, sess.opts.cg.extra_filename);
     match crate_type {
         config::CrateTypeRlib => {
             out_filename.with_filename(format!("lib{}.rlib", libname))
@@ -891,13 +914,13 @@ fn link_binary_output(sess: &Session,
                       trans: &CrateTranslation,
                       crate_type: config::CrateType,
                       outputs: &OutputFilenames,
-                      id: &CrateId) -> Path {
+                      crate_name: &str) -> Path {
     let obj_filename = outputs.temp_path(OutputTypeObject);
     let out_filename = match outputs.single_output_file {
         Some(ref file) => file.clone(),
         None => {
             let out_filename = outputs.path(OutputTypeExe);
-            filename_for_input(sess, crate_type, id, &out_filename)
+            filename_for_input(sess, crate_type, crate_name, &out_filename)
         }
     };
 
diff --git a/src/librustc/back/svh.rs b/src/librustc/back/svh.rs
index c487f674c2d..24b9ff970aa 100644
--- a/src/librustc/back/svh.rs
+++ b/src/librustc/back/svh.rs
@@ -53,6 +53,8 @@ use std::iter::range_step;
 use syntax::ast;
 use syntax::visit;
 
+use driver::session::Session;
+
 #[deriving(Clone, PartialEq)]
 pub struct Svh {
     hash: String,
@@ -68,7 +70,7 @@ impl Svh {
         self.hash.as_slice()
     }
 
-    pub fn calculate(krate: &ast::Crate) -> Svh {
+    pub fn calculate(sess: &Session, krate: &ast::Crate) -> Svh {
         // FIXME (#14132): This is better than it used to be, but it still not
         // ideal. We now attempt to hash only the relevant portions of the
         // Crate AST as well as the top-level crate attributes. (However,
@@ -80,6 +82,10 @@ impl Svh {
         //        avoid collisions.
         let mut state = SipState::new();
 
+        for data in sess.opts.cg.metadata.iter() {
+            data.hash(&mut state);
+        }
+
         {
             let mut visit = svh_visitor::make(&mut state);
             visit::walk_crate(&mut visit, krate, ());
diff --git a/src/librustc/driver/config.rs b/src/librustc/driver/config.rs
index 09ba098b21d..e91dfd9587b 100644
--- a/src/librustc/driver/config.rs
+++ b/src/librustc/driver/config.rs
@@ -11,7 +11,7 @@
 //! Contains infrastructure for configuring the compiler, including parsing
 //! command line options.
 
-use driver::early_error;
+use driver::{early_error, early_warn};
 use driver::driver;
 use driver::session::Session;
 
@@ -30,7 +30,7 @@ use syntax::diagnostic::{ColorConfig, Auto, Always, Never};
 use syntax::parse;
 use syntax::parse::token::InternedString;
 
-use std::collections::HashSet;
+use std::collections::{HashSet, HashMap};
 use getopts::{optopt, optmulti, optflag, optflagopt};
 use getopts;
 use lib::llvm::llvm;
@@ -91,10 +91,12 @@ pub struct Options {
     pub debugging_opts: u64,
     /// Whether to write dependency files. It's (enabled, optional filename).
     pub write_dependency_info: (bool, Option<Path>),
-    /// Crate id-related things to maybe print. It's (crate_id, crate_name, crate_file_name).
-    pub print_metas: (bool, bool, bool),
+    /// Crate id-related things to maybe print. It's (crate_name, crate_file_name).
+    pub print_metas: (bool, bool),
     pub cg: CodegenOptions,
     pub color: ColorConfig,
+    pub externs: HashMap<String, Vec<String>>,
+    pub crate_name: Option<String>,
 }
 
 /// Some reasonable defaults
@@ -117,9 +119,11 @@ pub fn basic_options() -> Options {
         no_analysis: false,
         debugging_opts: 0,
         write_dependency_info: (false, None),
-        print_metas: (false, false, false),
+        print_metas: (false, false),
         cg: basic_codegen_options(),
         color: Auto,
+        externs: HashMap::new(),
+        crate_name: None,
     }
 }
 
@@ -318,6 +322,10 @@ cgoptions!(
         "use an external assembler rather than LLVM's integrated one"),
     relocation_model: String = ("pic".to_string(), parse_string,
          "choose the relocation model to use (llc -relocation-model for details)"),
+    metadata: Vec<String> = (Vec::new(), parse_list,
+         "metadata to mangle symbol names with"),
+    extra_filename: String = ("".to_string(), parse_string,
+         "extra data to put in each output filename"),
 )
 
 pub fn build_codegen_options(matches: &getopts::Matches) -> CodegenOptions
@@ -505,10 +513,12 @@ pub fn optgroups() -> Vec<getopts::OptGroup> {
                  "[bin|lib|rlib|dylib|staticlib]"),
         optmulti("", "emit", "Comma separated list of types of output for the compiler to emit",
                  "[asm|bc|ir|obj|link]"),
-        optflag("", "crate-id", "Output the crate id and exit"),
-        optflag("", "crate-name", "Output the crate name and exit"),
-        optflag("", "crate-file-name", "Output the file(s) that would be written if compilation \
+        optopt("", "crate-name", "Specify the name of the crate being built",
+               "NAME"),
+        optflag("", "print-crate-name", "Output the crate name and exit"),
+        optflag("", "print-file-name", "Output the file(s) that would be written if compilation \
               continued and exit"),
+        optflag("", "crate-file-name", "deprecated in favor of --print-file-name"),
         optflag("g",  "",  "Equivalent to --debuginfo=2"),
         optopt("",  "debuginfo",  "Emit DWARF debug info to the objects created:
              0 = no debug info,
@@ -548,7 +558,9 @@ pub fn optgroups() -> Vec<getopts::OptGroup> {
         optopt("", "color", "Configure coloring of output:
             auto   = colorize, if output goes to a tty (default);
             always = always colorize output;
-            never  = never colorize output", "auto|always|never")
+            never  = never colorize output", "auto|always|never"),
+        optmulti("", "extern", "Specify where an external rust library is located",
+                 "PATH"),
     )
 }
 
@@ -709,9 +721,13 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
                                  matches.opt_str("dep-info")
                                         .map(|p| Path::new(p)));
 
-    let print_metas = (matches.opt_present("crate-id"),
-                       matches.opt_present("crate-name"),
+    let print_metas = (matches.opt_present("print-crate-name"),
+                       matches.opt_present("print-file-name") ||
                        matches.opt_present("crate-file-name"));
+    if matches.opt_present("crate-file-name") {
+        early_warn("the --crate-file-name argument has been renamed to \
+                    --print-file-name");
+    }
     let cg = build_codegen_options(matches);
 
     let color = match matches.opt_str("color").as_ref().map(|s| s.as_slice()) {
@@ -728,6 +744,23 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         }
     };
 
+    let mut externs = HashMap::new();
+    for arg in matches.opt_strs("extern").iter() {
+        let mut parts = arg.as_slice().splitn('=', 1);
+        let name = match parts.next() {
+            Some(s) => s,
+            None => early_error("--extern value must not be empty"),
+        };
+        let location = match parts.next() {
+            Some(s) => s,
+            None => early_error("--extern value must be of the format `foo=bar`"),
+        };
+        let locs = externs.find_or_insert(name.to_string(), Vec::new());
+        locs.push(location.to_string());
+    }
+
+    let crate_name = matches.opt_str("crate-name");
+
     Options {
         crate_types: crate_types,
         gc: gc,
@@ -748,7 +781,9 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         write_dependency_info: write_dependency_info,
         print_metas: print_metas,
         cg: cg,
-        color: color
+        color: color,
+        externs: externs,
+        crate_name: crate_name,
     }
 }
 
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index 978a4310652..16605c06017 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -41,7 +41,6 @@ use std::io::MemReader;
 use syntax::ast;
 use syntax::attr;
 use syntax::attr::{AttrMetaMethods};
-use syntax::crateid::CrateId;
 use syntax::parse;
 use syntax::parse::token;
 use syntax::print::{pp, pprust};
@@ -69,7 +68,7 @@ pub fn compile_input(sess: Session,
     // large chunks of memory alive and we want to free them as soon as
     // possible to keep the peak memory usage low
     let (outputs, trans, sess) = {
-        let (outputs, expanded_crate, ast_map) = {
+        let (outputs, expanded_crate, ast_map, id) = {
             let krate = phase_1_parse_input(&sess, cfg, input);
             if stop_after_phase_1(&sess) { return; }
             let outputs = build_output_filenames(input,
@@ -77,25 +76,25 @@ pub fn compile_input(sess: Session,
                                                  output,
                                                  krate.attrs.as_slice(),
                                                  &sess);
-            let id = link::find_crate_id(krate.attrs.as_slice(),
-                                         outputs.out_filestem.as_slice());
+            let id = link::find_crate_name(Some(&sess), krate.attrs.as_slice(),
+                                           input);
             let (expanded_crate, ast_map)
-                = match phase_2_configure_and_expand(&sess, krate, &id) {
+                = match phase_2_configure_and_expand(&sess, krate, id.as_slice()) {
                     None => return,
                     Some(p) => p,
                 };
 
-            (outputs, expanded_crate, ast_map)
+            (outputs, expanded_crate, ast_map, id)
         };
-        write_out_deps(&sess, input, &outputs, &expanded_crate);
+        write_out_deps(&sess, input, &outputs, id.as_slice());
 
         if stop_after_phase_2(&sess) { return; }
 
-        let analysis = phase_3_run_analysis_passes(sess, &expanded_crate, ast_map);
+        let analysis = phase_3_run_analysis_passes(sess, &expanded_crate,
+                                                   ast_map, id);
         phase_save_analysis(&analysis.ty_cx.sess, &expanded_crate, &analysis, outdir);
         if stop_after_phase_3(&analysis.ty_cx.sess) { return; }
-        let (tcx, trans) = phase_4_translate_to_llvm(expanded_crate,
-                                                     analysis, &outputs);
+        let (tcx, trans) = phase_4_translate_to_llvm(expanded_crate, analysis);
 
         // Discard interned strings as they are no longer required.
         token::get_ident_interner().clear();
@@ -181,11 +180,14 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
 /// Returns `None` if we're aborting after handling -W help.
 pub fn phase_2_configure_and_expand(sess: &Session,
                                     mut krate: ast::Crate,
-                                    crate_id: &CrateId)
+                                    crate_name: &str)
                                     -> Option<(ast::Crate, syntax::ast_map::Map)> {
     let time_passes = sess.time_passes();
 
-    *sess.crate_types.borrow_mut() = collect_crate_types(sess, krate.attrs.as_slice());
+    *sess.crate_types.borrow_mut() =
+        collect_crate_types(sess, krate.attrs.as_slice());
+    *sess.crate_metadata.borrow_mut() =
+        collect_crate_metadata(sess, krate.attrs.as_slice());
 
     time(time_passes, "gated feature checking", (), |_|
          front::feature_gate::check_crate(sess, &krate));
@@ -247,7 +249,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
             }
             let cfg = syntax::ext::expand::ExpansionConfig {
                 deriving_hash_type_parameter: sess.features.default_type_params.get(),
-                crate_id: crate_id.clone(),
+                crate_name: crate_name.to_string(),
             };
             syntax::ext::expand::expand_crate(&sess.parse_sess,
                                               cfg,
@@ -286,6 +288,7 @@ pub struct CrateAnalysis {
     pub public_items: middle::privacy::PublicItems,
     pub ty_cx: ty::ctxt,
     pub reachable: NodeSet,
+    pub name: String,
 }
 
 /// Run the resolution, typechecking, region checking and other
@@ -293,7 +296,8 @@ pub struct CrateAnalysis {
 /// structures carrying the results of the analysis.
 pub fn phase_3_run_analysis_passes(sess: Session,
                                    krate: &ast::Crate,
-                                   ast_map: syntax::ast_map::Map) -> CrateAnalysis {
+                                   ast_map: syntax::ast_map::Map,
+                                   name: String) -> CrateAnalysis {
 
     let time_passes = sess.time_passes();
 
@@ -398,6 +402,7 @@ pub fn phase_3_run_analysis_passes(sess: Session,
         exported_items: exported_items,
         public_items: public_items,
         reachable: reachable_map,
+        name: name,
     }
 }
 
@@ -426,8 +431,7 @@ pub struct CrateTranslation {
 /// Run the translation phase to LLVM, after which the AST and analysis can
 /// be discarded.
 pub fn phase_4_translate_to_llvm(krate: ast::Crate,
-                                 analysis: CrateAnalysis,
-                                 outputs: &OutputFilenames) -> (ty::ctxt, CrateTranslation) {
+                                 analysis: CrateAnalysis) -> (ty::ctxt, CrateTranslation) {
     let time_passes = analysis.ty_cx.sess.time_passes();
 
     time(time_passes, "resolving dependency formats", (), |_|
@@ -435,7 +439,7 @@ pub fn phase_4_translate_to_llvm(krate: ast::Crate,
 
     // Option dance to work around the lack of stack once closures.
     time(time_passes, "translation", (krate, analysis), |(krate, analysis)|
-         trans::base::trans_crate(krate, analysis, outputs))
+         trans::base::trans_crate(krate, analysis))
 }
 
 /// Run LLVM itself, producing a bitcode file, assembly file or object file
@@ -473,7 +477,7 @@ pub fn phase_6_link_output(sess: &Session,
          link::link_binary(sess,
                            trans,
                            outputs,
-                           &trans.link.crateid));
+                           trans.link.crate_name.as_slice()));
 }
 
 pub fn stop_after_phase_3(sess: &Session) -> bool {
@@ -514,9 +518,7 @@ pub fn stop_after_phase_5(sess: &Session) -> bool {
 fn write_out_deps(sess: &Session,
                   input: &Input,
                   outputs: &OutputFilenames,
-                  krate: &ast::Crate) {
-    let id = link::find_crate_id(krate.attrs.as_slice(),
-                                 outputs.out_filestem.as_slice());
+                  id: &str) {
 
     let mut out_filenames = Vec::new();
     for output_type in sess.opts.output_types.iter() {
@@ -524,7 +526,8 @@ fn write_out_deps(sess: &Session,
         match *output_type {
             link::OutputTypeExe => {
                 for output in sess.crate_types.borrow().iter() {
-                    let p = link::filename_for_input(sess, *output, &id, &file);
+                    let p = link::filename_for_input(sess, *output,
+                                                     id, &file);
                     out_filenames.push(p);
                 }
             }
@@ -649,13 +652,13 @@ pub fn pretty_print_input(sess: Session,
                           ppm: PpMode,
                           ofile: Option<Path>) {
     let krate = phase_1_parse_input(&sess, cfg, input);
-    let id = link::find_crate_id(krate.attrs.as_slice(),
-                                 input.filestem().as_slice());
+    let id = link::find_crate_name(Some(&sess), krate.attrs.as_slice(), input);
 
     let (krate, ast_map, is_expanded) = match ppm {
         PpmExpanded | PpmExpandedIdentified | PpmTyped | PpmFlowGraph(_) => {
             let (krate, ast_map)
-                = match phase_2_configure_and_expand(&sess, krate, &id) {
+                = match phase_2_configure_and_expand(&sess, krate,
+                                                     id.as_slice()) {
                     None => return,
                     Some(p) => p,
                 };
@@ -695,7 +698,7 @@ pub fn pretty_print_input(sess: Session,
         }
         PpmTyped => {
             let ast_map = ast_map.expect("--pretty=typed missing ast_map");
-            let analysis = phase_3_run_analysis_passes(sess, &krate, ast_map);
+            let analysis = phase_3_run_analysis_passes(sess, &krate, ast_map, id);
             let annotation = TypedAnnotation {
                 analysis: analysis
             };
@@ -728,7 +731,8 @@ pub fn pretty_print_input(sess: Session,
                     }
                 }
             };
-            let analysis = phase_3_run_analysis_passes(sess, &krate, ast_map);
+            let analysis = phase_3_run_analysis_passes(sess, &krate,
+                                                       ast_map, id);
             print_flowgraph(analysis, block, out)
         }
         _ => {
@@ -845,6 +849,11 @@ pub fn collect_crate_types(session: &Session,
     }).collect()
 }
 
+pub fn collect_crate_metadata(session: &Session,
+                              _attrs: &[ast::Attribute]) -> Vec<String> {
+    session.opts.cg.metadata.clone()
+}
+
 pub struct OutputFilenames {
     pub out_directory: Path,
     pub out_filestem: String,
@@ -893,14 +902,11 @@ pub fn build_output_filenames(input: &Input,
                 None => Path::new(".")
             };
 
-            let mut stem = input.filestem();
-
-            // If a crateid is present, we use it as the link name
-            let crateid = attr::find_crateid(attrs);
-            match crateid {
-                None => {}
-                Some(crateid) => stem = crateid.name.to_string(),
-            }
+            // If a crate name is present, we use it as the link name
+           let stem = match attr::find_crate_name(attrs) {
+                None => input.filestem(),
+                Some(name) => name.get().to_string(),
+            };
             OutputFilenames {
                 out_directory: dirpath,
                 out_filestem: stem,
diff --git a/src/librustc/driver/mod.rs b/src/librustc/driver/mod.rs
index 87c0a270839..807c2590566 100644
--- a/src/librustc/driver/mod.rs
+++ b/src/librustc/driver/mod.rs
@@ -294,28 +294,26 @@ fn print_crate_info(sess: &Session,
                     odir: &Option<Path>,
                     ofile: &Option<Path>)
                     -> bool {
-    let (crate_id, crate_name, crate_file_name) = sess.opts.print_metas;
+    let (crate_name, crate_file_name) = sess.opts.print_metas;
     // these nasty nested conditions are to avoid doing extra work
-    if crate_id || crate_name || crate_file_name {
+    if crate_name || crate_file_name {
         let attrs = parse_crate_attrs(sess, input);
         let t_outputs = driver::build_output_filenames(input,
                                                        odir,
                                                        ofile,
                                                        attrs.as_slice(),
                                                        sess);
-        let id = link::find_crate_id(attrs.as_slice(),
-                                     t_outputs.out_filestem.as_slice());
+        let id = link::find_crate_name(Some(sess), attrs.as_slice(), input);
 
-        if crate_id {
-            println!("{}", id.to_str());
-        }
         if crate_name {
-            println!("{}", id.name);
+            println!("{}", id);
         }
         if crate_file_name {
             let crate_types = driver::collect_crate_types(sess, attrs.as_slice());
+            let metadata = driver::collect_crate_metadata(sess, attrs.as_slice());
+            *sess.crate_metadata.borrow_mut() = metadata;
             for &style in crate_types.iter() {
-                let fname = link::filename_for_input(sess, style, &id,
+                let fname = link::filename_for_input(sess, style, id.as_slice(),
                                                      &t_outputs.with_extension(""));
                 println!("{}", fname.filename_display());
             }
@@ -390,6 +388,11 @@ pub fn early_error(msg: &str) -> ! {
     fail!(diagnostic::FatalError);
 }
 
+pub fn early_warn(msg: &str) {
+    let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto);
+    emitter.emit(None, msg, diagnostic::Warning);
+}
+
 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)
diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs
index 07366f34c4e..50f61f8f06a 100644
--- a/src/librustc/driver/session.rs
+++ b/src/librustc/driver/session.rs
@@ -47,6 +47,7 @@ pub struct Session {
     pub lints: RefCell<NodeMap<Vec<(lint::LintId, codemap::Span, String)>>>,
     pub node_id: Cell<ast::NodeId>,
     pub crate_types: RefCell<Vec<config::CrateType>>,
+    pub crate_metadata: RefCell<Vec<String>>,
     pub features: front::feature_gate::Features,
 
     /// The maximum recursion limit for potentially infinitely recursive
@@ -243,6 +244,7 @@ pub fn build_session_(sopts: config::Options,
         lints: RefCell::new(NodeMap::new()),
         node_id: Cell::new(1),
         crate_types: RefCell::new(Vec::new()),
+        crate_metadata: RefCell::new(Vec::new()),
         features: front::feature_gate::Features::new(),
         recursion_limit: Cell::new(64),
     };
diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs
index 54ba9db570e..351c9a6b771 100644
--- a/src/librustc/front/std_inject.rs
+++ b/src/librustc/front/std_inject.rs
@@ -25,8 +25,6 @@ use syntax::util::small_vector::SmallVector;
 use std::mem;
 use std::gc::{Gc, GC};
 
-pub static VERSION: &'static str = "0.11.0";
-
 pub fn maybe_inject_crates_ref(sess: &Session, krate: ast::Crate)
                                -> ast::Crate {
     if use_std(&krate) {
@@ -60,24 +58,12 @@ struct StandardLibraryInjector<'a> {
     sess: &'a Session,
 }
 
-pub fn with_version(krate: &str) -> Option<(InternedString, ast::StrStyle)> {
-    match option_env!("CFG_DISABLE_INJECT_STD_VERSION") {
-        Some("1") => None,
-        _ => {
-            Some((token::intern_and_get_ident(format!("{}#{}",
-                                                      krate,
-                                                      VERSION).as_slice()),
-                  ast::CookedStr))
-        }
-    }
-}
-
 impl<'a> fold::Folder for StandardLibraryInjector<'a> {
     fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
         let mut vis = vec!(ast::ViewItem {
             node: ast::ViewItemExternCrate(token::str_to_ident("std"),
-                                         with_version("std"),
-                                         ast::DUMMY_NODE_ID),
+                                           None,
+                                           ast::DUMMY_NODE_ID),
             attrs: vec!(
                 attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_list_item(
                         InternedString::new("phase"),
@@ -95,8 +81,8 @@ impl<'a> fold::Folder for StandardLibraryInjector<'a> {
         if use_start(&krate) && any_exe {
             vis.push(ast::ViewItem {
                 node: ast::ViewItemExternCrate(token::str_to_ident("native"),
-                                             with_version("native"),
-                                             ast::DUMMY_NODE_ID),
+                                               None,
+                                               ast::DUMMY_NODE_ID),
                 attrs: Vec::new(),
                 vis: ast::Inherited,
                 span: DUMMY_SP
diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs
index d33b76ae08c..b2c6840ad22 100644
--- a/src/librustc/front/test.rs
+++ b/src/librustc/front/test.rs
@@ -15,7 +15,6 @@
 
 use driver::session::Session;
 use front::config;
-use front::std_inject::with_version;
 
 use std::cell::RefCell;
 use std::gc::{Gc, GC};
@@ -154,7 +153,7 @@ fn generate_test_harness(sess: &Session, krate: ast::Crate)
         ext_cx: ExtCtxt::new(&sess.parse_sess, sess.opts.cfg.clone(),
                              ExpansionConfig {
                                  deriving_hash_type_parameter: false,
-                                 crate_id: from_str("test").unwrap(),
+                                 crate_name: "test".to_string(),
                              }),
         path: RefCell::new(Vec::new()),
         testfns: RefCell::new(Vec::new()),
@@ -298,9 +297,7 @@ fn mk_std(cx: &TestCtxt) -> ast::ViewItem {
                                         ast::DUMMY_NODE_ID))),
          ast::Public)
     } else {
-        (ast::ViewItemExternCrate(id_test,
-                               with_version("test"),
-                               ast::DUMMY_NODE_ID),
+        (ast::ViewItemExternCrate(id_test, None, ast::DUMMY_NODE_ID),
          ast::Inherited)
     };
     ast::ViewItem {
@@ -395,8 +392,8 @@ fn mk_tests(cx: &TestCtxt) -> Gc<ast::Item> {
 }
 
 fn is_test_crate(krate: &ast::Crate) -> bool {
-    match attr::find_crateid(krate.attrs.as_slice()) {
-        Some(ref s) if "test" == s.name.as_slice() => true,
+    match attr::find_crate_name(krate.attrs.as_slice()) {
+        Some(ref s) if "test" == s.get().as_slice() => true,
         _ => false
     }
 }
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 729eb908e39..eee909f59e3 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -18,7 +18,8 @@ This API is completely unstable and subject to change.
 
 */
 
-#![crate_id = "rustc#0.11.0"]
+#![crate_id = "rustc#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "rustc"]
 #![experimental]
 #![comment = "The Rust compiler"]
 #![license = "MIT/ASL2"]
@@ -31,6 +32,7 @@ This API is completely unstable and subject to change.
 #![allow(deprecated)]
 #![feature(macro_rules, globs, struct_variant, managed_boxes, quote)]
 #![feature(default_type_params, phase, unsafe_destructor)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 extern crate arena;
 extern crate debug;
diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs
index 9e1d272f5da..cdeecf3a080 100644
--- a/src/librustc/metadata/common.rs
+++ b/src/librustc/metadata/common.rs
@@ -11,7 +11,6 @@
 #![allow(non_camel_case_types)]
 
 use std::mem;
-use syntax::crateid::CrateId;
 use back::svh::Svh;
 
 // EBML enum definitions and utils shared by the encoder and decoder
@@ -71,9 +70,9 @@ pub static tag_crate_deps: uint = 0x18;
 pub static tag_crate_dep: uint = 0x19;
 
 pub static tag_crate_hash: uint = 0x1a;
-pub static tag_crate_crateid: uint = 0x1b;
+pub static tag_crate_crate_name: uint = 0x1b;
 
-pub static tag_crate_dep_crateid: uint = 0x1d;
+pub static tag_crate_dep_crate_name: uint = 0x1d;
 pub static tag_crate_dep_hash: uint = 0x1e;
 
 pub static tag_mod_impl: uint = 0x1f;
@@ -215,7 +214,7 @@ pub static tag_items_data_item_stability: uint = 0x92;
 
 #[deriving(Clone, Show)]
 pub struct LinkMeta {
-    pub crateid: CrateId,
+    pub crate_name: String,
     pub crate_hash: Svh,
 }
 
diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs
index 218fc31f623..29566fb1e7c 100644
--- a/src/librustc/metadata/creader.rs
+++ b/src/librustc/metadata/creader.rs
@@ -12,7 +12,6 @@
 
 //! Validates all used crates and extern libraries and loads their metadata
 
-use back::link;
 use back::svh::Svh;
 use driver::session::Session;
 use driver::{driver, config};
@@ -33,7 +32,6 @@ use syntax::codemap::{Span};
 use syntax::diagnostic::SpanHandler;
 use syntax::parse::token::InternedString;
 use syntax::parse::token;
-use syntax::crateid::CrateId;
 use syntax::visit;
 
 struct Env<'a> {
@@ -69,7 +67,7 @@ impl<'a> visit::Visitor<()> for Env<'a> {
 fn dump_crates(cstore: &CStore) {
     debug!("resolved crates:");
     cstore.iter_crate_data_origins(|_, data, opt_source| {
-        debug!("crate_id: {}", data.crate_id());
+        debug!("  name: {}", data.name());
         debug!("  cnum: {}", data.cnum);
         debug!("  hash: {}", data.hash());
         opt_source.map(|cs| {
@@ -83,20 +81,17 @@ fn dump_crates(cstore: &CStore) {
 fn warn_if_multiple_versions(diag: &SpanHandler, cstore: &CStore) {
     let mut map = HashMap::new();
     cstore.iter_crate_data(|cnum, data| {
-        let crateid = data.crate_id();
-        let key = (crateid.name.clone(), crateid.path.clone());
-        map.find_or_insert_with(key, |_| Vec::new()).push(cnum);
+        map.find_or_insert_with(data.name(), |_| Vec::new()).push(cnum);
     });
 
-    for ((name, _), dupes) in map.move_iter() {
+    for (name, dupes) in map.move_iter() {
         if dupes.len() == 1 { continue }
         diag.handler().warn(
-            format!("using multiple versions of crate `{}`",
-                    name).as_slice());
+            format!("using multiple versions of crate `{}`", name).as_slice());
         for dupe in dupes.move_iter() {
             let data = cstore.get_crate_data(dupe);
             diag.span_note(data.span, "used here");
-            loader::note_crateid_attr(diag, &data.crate_id());
+            loader::note_crate_name(diag, data.name().as_slice());
         }
     }
 }
@@ -129,7 +124,7 @@ fn visit_view_item(e: &mut Env, i: &ast::ViewItem) {
             let (cnum, _, _) = resolve_crate(e,
                                              &None,
                                              info.ident.as_slice(),
-                                             &info.crate_id,
+                                             info.name.as_slice(),
                                              None,
                                              i.span);
             e.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
@@ -140,7 +135,7 @@ fn visit_view_item(e: &mut Env, i: &ast::ViewItem) {
 
 struct CrateInfo {
     ident: String,
-    crate_id: CrateId,
+    name: String,
     id: ast::NodeId,
     should_link: bool,
 }
@@ -151,22 +146,18 @@ fn extract_crate_info(e: &Env, i: &ast::ViewItem) -> Option<CrateInfo> {
             let ident = token::get_ident(ident);
             debug!("resolving extern crate stmt. ident: {:?} path_opt: {:?}",
                    ident, path_opt);
-            let crate_id = match *path_opt {
+            let name = match *path_opt {
                 Some((ref path_str, _)) => {
-                    let crateid: Option<CrateId> = from_str(path_str.get());
-                    match crateid {
-                        None => {
-                            e.sess.span_err(i.span, "malformed crate id");
-                            return None
-                        }
-                        Some(id) => id
-                    }
+                    let name = path_str.get().to_str();
+                    validate_crate_name(Some(e.sess), name.as_slice(),
+                                        Some(i.span));
+                    name
                 }
-                None => from_str(ident.get().to_str().as_slice()).unwrap()
+                None => ident.get().to_str(),
             };
             Some(CrateInfo {
                 ident: ident.get().to_string(),
-                crate_id: crate_id,
+                name: name,
                 id: id,
                 should_link: should_link(i),
             })
@@ -175,6 +166,28 @@ fn extract_crate_info(e: &Env, i: &ast::ViewItem) -> Option<CrateInfo> {
     }
 }
 
+pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
+    let err = |s: &str| {
+        match (sp, sess) {
+            (_, None) => fail!("{}", s),
+            (Some(sp), Some(sess)) => sess.span_err(sp, s),
+            (None, Some(sess)) => sess.err(s),
+        }
+    };
+    if s.len() == 0 {
+        err("crate name must not be empty");
+    }
+    for c in s.chars() {
+        if c.is_alphanumeric() { continue }
+        if c == '_' || c == '-' { continue }
+        err(format!("invalid character `{}` in crate name: `{}`", c, s).as_slice());
+    }
+    match sess {
+        Some(sess) => sess.abort_if_errors(),
+        None => {}
+    }
+}
+
 fn visit_item(e: &Env, i: &ast::Item) {
     match i.node {
         ast::ItemForeignMod(ref fm) => {
@@ -263,17 +276,36 @@ fn visit_item(e: &Env, i: &ast::Item) {
     }
 }
 
-fn existing_match(e: &Env, crate_id: &CrateId,
+fn existing_match(e: &Env, name: &str,
                   hash: Option<&Svh>) -> Option<ast::CrateNum> {
     let mut ret = None;
     e.sess.cstore.iter_crate_data(|cnum, data| {
-        let other_id = data.crate_id();
-        if crate_id.matches(&other_id) {
-            let other_hash = data.hash();
-            match hash {
-                Some(hash) if *hash != other_hash => {}
-                Some(..) | None => { ret = Some(cnum); }
+        if data.name().as_slice() != name { return }
+
+        match hash {
+            Some(hash) if *hash == data.hash() => { ret = Some(cnum); return }
+            Some(..) => return,
+            None => {}
+        }
+
+        // When the hash is None we're dealing with a top-level dependency in
+        // which case we may have a specification on the command line for this
+        // library. Even though an upstream library may have loaded something of
+        // the same name, we have to make sure it was loaded from the exact same
+        // location as well.
+        let source = e.sess.cstore.get_used_crate_source(cnum).unwrap();
+        let dylib = source.dylib.as_ref().map(|p| p.as_vec());
+        let rlib = source.rlib.as_ref().map(|p| p.as_vec());
+        match e.sess.opts.externs.find_equiv(&name) {
+            Some(locs) => {
+                let found = locs.iter().any(|l| {
+                    Some(l.as_bytes()) == dylib || Some(l.as_bytes()) == rlib
+                });
+                if found {
+                    ret = Some(cnum);
+                }
             }
+            None => ret = Some(cnum),
         }
     });
     return ret;
@@ -282,7 +314,7 @@ fn existing_match(e: &Env, crate_id: &CrateId,
 fn register_crate<'a>(e: &mut Env,
                   root: &Option<CratePaths>,
                   ident: &str,
-                  crate_id: &CrateId,
+                  name: &str,
                   span: Span,
                   lib: loader::Library)
                         -> (ast::CrateNum, Rc<cstore::crate_metadata>,
@@ -309,7 +341,7 @@ fn register_crate<'a>(e: &mut Env,
     let loader::Library{ dylib, rlib, metadata } = lib;
 
     let cmeta = Rc::new( cstore::crate_metadata {
-        name: crate_id.name.to_string(),
+        name: name.to_string(),
         data: metadata,
         cnum_map: cnum_map,
         cnum: cnum,
@@ -330,20 +362,18 @@ fn register_crate<'a>(e: &mut Env,
 fn resolve_crate<'a>(e: &mut Env,
                  root: &Option<CratePaths>,
                  ident: &str,
-                 crate_id: &CrateId,
+                 name: &str,
                  hash: Option<&Svh>,
                  span: Span)
                      -> (ast::CrateNum, Rc<cstore::crate_metadata>,
                          cstore::CrateSource) {
-    match existing_match(e, crate_id, hash) {
+    match existing_match(e, name, hash) {
         None => {
-            let id_hash = link::crate_id_hash(crate_id);
             let mut load_ctxt = loader::Context {
                 sess: e.sess,
                 span: span,
                 ident: ident,
-                crate_id: crate_id,
-                id_hash: id_hash.as_slice(),
+                crate_name: name,
                 hash: hash.map(|a| &*a),
                 filesearch: e.sess.target_filesearch(),
                 os: e.sess.targ_cfg.os,
@@ -351,9 +381,10 @@ fn resolve_crate<'a>(e: &mut Env,
                 root: root,
                 rejected_via_hash: vec!(),
                 rejected_via_triple: vec!(),
+                should_match_name: true,
             };
             let library = load_ctxt.load_library_crate();
-            register_crate(e, root, ident, crate_id, span, library)
+            register_crate(e, root, ident, name, span, library)
         }
         Some(cnum) => (cnum,
                        e.sess.cstore.get_crate_data(cnum),
@@ -370,10 +401,10 @@ fn resolve_crate_deps(e: &mut Env,
     // The map from crate numbers in the crate we're resolving to local crate
     // numbers
     decoder::get_crate_deps(cdata).iter().map(|dep| {
-        debug!("resolving dep crate {} hash: `{}`", dep.crate_id, dep.hash);
+        debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
         let (local_cnum, _, _) = resolve_crate(e, root,
-                                               dep.crate_id.name.as_slice(),
-                                               &dep.crate_id,
+                                               dep.name.as_slice(),
+                                               dep.name.as_slice(),
                                                Some(&dep.hash),
                                                span);
         (dep.cnum, local_cnum)
@@ -399,14 +430,12 @@ impl<'a> PluginMetadataReader<'a> {
         let target_triple = self.env.sess.targ_cfg.target_strs.target_triple.as_slice();
         let is_cross = target_triple != driver::host_triple();
         let mut should_link = info.should_link && !is_cross;
-        let id_hash = link::crate_id_hash(&info.crate_id);
         let os = config::get_os(driver::host_triple()).unwrap();
         let mut load_ctxt = loader::Context {
             sess: self.env.sess,
             span: krate.span,
             ident: info.ident.as_slice(),
-            crate_id: &info.crate_id,
-            id_hash: id_hash.as_slice(),
+            crate_name: info.name.as_slice(),
             hash: None,
             filesearch: self.env.sess.host_filesearch(),
             triple: driver::host_triple(),
@@ -414,6 +443,7 @@ impl<'a> PluginMetadataReader<'a> {
             root: &None,
             rejected_via_hash: vec!(),
             rejected_via_triple: vec!(),
+            should_match_name: true,
         };
         let library = match load_ctxt.maybe_load_library_crate() {
             Some (l) => l,
@@ -448,10 +478,11 @@ impl<'a> PluginMetadataReader<'a> {
             macros: macros,
             registrar_symbol: registrar,
         };
-        if should_link && existing_match(&self.env, &info.crate_id, None).is_none() {
+        if should_link && existing_match(&self.env, info.name.as_slice(),
+                                         None).is_none() {
             // register crate now to avoid double-reading metadata
             register_crate(&mut self.env, &None, info.ident.as_slice(),
-                           &info.crate_id, krate.span, library);
+                           info.name.as_slice(), krate.span, library);
         }
         pc
     }
diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs
index 846f879104f..9d6fd109b48 100644
--- a/src/librustc/metadata/cstore.rs
+++ b/src/librustc/metadata/cstore.rs
@@ -22,7 +22,6 @@ use std::c_vec::CVec;
 use std::rc::Rc;
 use std::collections::HashMap;
 use syntax::ast;
-use syntax::crateid::CrateId;
 use syntax::codemap::Span;
 use syntax::parse::token::IdentInterner;
 
@@ -220,7 +219,7 @@ impl CStore {
 
 impl crate_metadata {
     pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() }
-    pub fn crate_id(&self) -> CrateId { decoder::get_crate_id(self.data()) }
+    pub fn name(&self) -> String { decoder::get_crate_name(self.data()) }
     pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
 }
 
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 78a29b52bdf..f88c0d34ed8 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -46,7 +46,6 @@ use syntax::parse::token;
 use syntax::print::pprust;
 use syntax::ast;
 use syntax::codemap;
-use syntax::crateid::CrateId;
 
 pub type Cmd<'a> = &'a crate_metadata;
 
@@ -1101,7 +1100,7 @@ pub fn get_crate_attributes(data: &[u8]) -> Vec<ast::Attribute> {
 #[deriving(Clone)]
 pub struct CrateDep {
     pub cnum: ast::CrateNum,
-    pub crate_id: CrateId,
+    pub name: String,
     pub hash: Svh,
 }
 
@@ -1115,13 +1114,11 @@ pub fn get_crate_deps(data: &[u8]) -> Vec<CrateDep> {
         d.as_str_slice().to_string()
     }
     reader::tagged_docs(depsdoc, tag_crate_dep, |depdoc| {
-        let crate_id =
-            from_str(docstr(depdoc,
-                            tag_crate_dep_crateid).as_slice()).unwrap();
+        let name = docstr(depdoc, tag_crate_dep_crate_name);
         let hash = Svh::new(docstr(depdoc, tag_crate_dep_hash).as_slice());
         deps.push(CrateDep {
             cnum: crate_num,
-            crate_id: crate_id,
+            name: name,
             hash: hash,
         });
         crate_num += 1;
@@ -1133,7 +1130,7 @@ pub fn get_crate_deps(data: &[u8]) -> Vec<CrateDep> {
 fn list_crate_deps(data: &[u8], out: &mut io::Writer) -> io::IoResult<()> {
     try!(write!(out, "=External Dependencies=\n"));
     for dep in get_crate_deps(data).iter() {
-        try!(write!(out, "{} {}-{}\n", dep.cnum, dep.crate_id, dep.hash));
+        try!(write!(out, "{} {}-{}\n", dep.cnum, dep.name, dep.hash));
     }
     try!(write!(out, "\n"));
     Ok(())
@@ -1152,23 +1149,21 @@ pub fn get_crate_hash(data: &[u8]) -> Svh {
     Svh::new(hashdoc.as_str_slice())
 }
 
-pub fn maybe_get_crate_id(data: &[u8]) -> Option<CrateId> {
+pub fn maybe_get_crate_name(data: &[u8]) -> Option<String> {
     let cratedoc = ebml::Doc::new(data);
-    reader::maybe_get_doc(cratedoc, tag_crate_crateid).map(|doc| {
-        from_str(doc.as_str_slice()).unwrap()
+    reader::maybe_get_doc(cratedoc, tag_crate_crate_name).map(|doc| {
+        doc.as_str_slice().to_string()
     })
 }
 
-pub fn get_crate_triple(data: &[u8]) -> String {
+pub fn get_crate_triple(data: &[u8]) -> Option<String> {
     let cratedoc = ebml::Doc::new(data);
     let triple_doc = reader::maybe_get_doc(cratedoc, tag_crate_triple);
-    triple_doc.expect("No triple in crate").as_str().to_string()
+    triple_doc.map(|s| s.as_str().to_string())
 }
 
-pub fn get_crate_id(data: &[u8]) -> CrateId {
-    let cratedoc = ebml::Doc::new(data);
-    let hashdoc = reader::get_doc(cratedoc, tag_crate_crateid);
-    from_str(hashdoc.as_str_slice()).unwrap()
+pub fn get_crate_name(data: &[u8]) -> String {
+    maybe_get_crate_name(data).expect("no crate name in crate")
 }
 
 pub fn list_crate_metadata(bytes: &[u8], out: &mut io::Writer) -> io::IoResult<()> {
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 6eb7c5a4310..21713672f81 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -44,11 +44,9 @@ use syntax::ast_map::{PathElem, PathElems};
 use syntax::ast_map;
 use syntax::ast_util::*;
 use syntax::ast_util;
-use syntax::attr::AttrMetaMethods;
 use syntax::attr;
-use syntax::crateid::CrateId;
+use syntax::attr::AttrMetaMethods;
 use syntax::diagnostic::SpanHandler;
-use syntax::parse::token::InternedString;
 use syntax::parse::token::special_idents;
 use syntax::parse::token;
 use syntax::visit::Visitor;
@@ -1494,35 +1492,6 @@ fn encode_attributes(ebml_w: &mut Encoder, attrs: &[Attribute]) {
     ebml_w.end_tag();
 }
 
-// So there's a special crate attribute called 'crate_id' which defines the
-// metadata that Rust cares about for linking crates. If the user didn't
-// provide it we will throw it in anyway with a default value.
-fn synthesize_crate_attrs(ecx: &EncodeContext,
-                          krate: &Crate) -> Vec<Attribute> {
-
-    fn synthesize_crateid_attr(ecx: &EncodeContext) -> Attribute {
-        assert!(!ecx.link_meta.crateid.name.is_empty());
-
-        attr::mk_attr_inner(attr::mk_attr_id(),
-            attr::mk_name_value_item_str(
-                InternedString::new("crate_id"),
-                token::intern_and_get_ident(ecx.link_meta
-                                               .crateid
-                                               .to_str()
-                                               .as_slice())))
-    }
-
-    let mut attrs = Vec::new();
-    for attr in krate.attrs.iter() {
-        if !attr.check_name("crate_id") {
-            attrs.push(*attr);
-        }
-    }
-    attrs.push(synthesize_crateid_attr(ecx));
-
-    attrs
-}
-
 fn encode_crate_deps(ebml_w: &mut Encoder, cstore: &cstore::CStore) {
     fn get_ordered_deps(cstore: &cstore::CStore) -> Vec<decoder::CrateDep> {
         // Pull the cnums and name,vers,hash out of cstore
@@ -1530,8 +1499,8 @@ fn encode_crate_deps(ebml_w: &mut Encoder, cstore: &cstore::CStore) {
         cstore.iter_crate_data(|key, val| {
             let dep = decoder::CrateDep {
                 cnum: key,
-                crate_id: decoder::get_crate_id(val.data()),
-                hash: decoder::get_crate_hash(val.data())
+                name: decoder::get_crate_name(val.data()),
+                hash: decoder::get_crate_hash(val.data()),
             };
             deps.push(dep);
         });
@@ -1766,8 +1735,8 @@ fn encode_reachable_extern_fns(ecx: &EncodeContext, ebml_w: &mut Encoder) {
 fn encode_crate_dep(ebml_w: &mut Encoder,
                     dep: decoder::CrateDep) {
     ebml_w.start_tag(tag_crate_dep);
-    ebml_w.start_tag(tag_crate_dep_crateid);
-    ebml_w.writer.write(dep.crate_id.to_str().as_bytes());
+    ebml_w.start_tag(tag_crate_dep_crate_name);
+    ebml_w.writer.write(dep.name.as_bytes());
     ebml_w.end_tag();
     ebml_w.start_tag(tag_crate_dep_hash);
     ebml_w.writer.write(dep.hash.as_str().as_bytes());
@@ -1781,9 +1750,9 @@ fn encode_hash(ebml_w: &mut Encoder, hash: &Svh) {
     ebml_w.end_tag();
 }
 
-fn encode_crate_id(ebml_w: &mut Encoder, crate_id: &CrateId) {
-    ebml_w.start_tag(tag_crate_crateid);
-    ebml_w.writer.write(crate_id.to_str().as_bytes());
+fn encode_crate_name(ebml_w: &mut Encoder, crate_name: &str) {
+    ebml_w.start_tag(tag_crate_crate_name);
+    ebml_w.writer.write(crate_name.as_bytes());
     ebml_w.end_tag();
 }
 
@@ -1880,7 +1849,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
 
     let mut ebml_w = writer::Encoder::new(wr);
 
-    encode_crate_id(&mut ebml_w, &ecx.link_meta.crateid);
+    encode_crate_name(&mut ebml_w, ecx.link_meta.crate_name.as_slice());
     encode_crate_triple(&mut ebml_w,
                         tcx.sess
                            .targ_cfg
@@ -1891,8 +1860,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
     encode_dylib_dependency_formats(&mut ebml_w, &ecx);
 
     let mut i = ebml_w.writer.tell().unwrap();
-    let crate_attrs = synthesize_crate_attrs(&ecx, krate);
-    encode_attributes(&mut ebml_w, crate_attrs.as_slice());
+    encode_attributes(&mut ebml_w, krate.attrs.as_slice());
     stats.attr_bytes = ebml_w.writer.tell().unwrap() - i;
 
     i = ebml_w.writer.tell().unwrap();
diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs
index ccab76ca6f0..1b2349a271e 100644
--- a/src/librustc/metadata/loader.rs
+++ b/src/librustc/metadata/loader.rs
@@ -9,6 +9,208 @@
 // except according to those terms.
 
 //! Finds crate binaries and loads their metadata
+//!
+//! Might I be the first to welcome you to a world of platform differences,
+//! version requirements, dependency graphs, conficting desires, and fun! This
+//! is the major guts (along with metadata::creader) of the compiler for loading
+//! crates and resolving dependencies. Let's take a tour!
+//!
+//! # The problem
+//!
+//! Each invocation of the compiler is immediately concerned with one primary
+//! problem, to connect a set of crates to resolved crates on the filesystem.
+//! Concretely speaking, the compiler follows roughly these steps to get here:
+//!
+//! 1. Discover a set of `extern crate` statements.
+//! 2. Transform these directives into crate names. If the directive does not
+//!    have an explicit name, then the identifier is the name.
+//! 3. For each of these crate names, find a corresponding crate on the
+//!    filesystem.
+//!
+//! Sounds easy, right? Let's walk into some of the nuances.
+//!
+//! ## Transitive Dependencies
+//!
+//! Let's say we've got three crates: A, B, and C. A depends on B, and B depends
+//! on C. When we're compiling A, we primarily need to find and locate B, but we
+//! also end up needing to find and locate C as well.
+//!
+//! The reason for this is that any of B's types could be composed of C's types,
+//! any function in B could return a type from C, etc. To be able to guarantee
+//! that we can always typecheck/translate any function, we have to have
+//! complete knowledge of the whole ecosystem, not just our immediate
+//! dependencies.
+//!
+//! So now as part of the "find a corresponding crate on the filesystem" step
+//! above, this involves also finding all crates for *all upstream
+//! dependencies*. This includes all dependencies transitively.
+//!
+//! ## Rlibs and Dylibs
+//!
+//! The compiler has two forms of intermediate dependencies. These are dubbed
+//! rlibs and dylibs for the static and dynamic variants, respectively. An rlib
+//! is a rustc-defined file format (currently just an ar archive) while a dylib
+//! is a platform-defined dynamic library. Each library has a metadata somewhere
+//! inside of it.
+//!
+//! When translating a crate name to a crate on the filesystem, we all of a
+//! sudden need to take into account both rlibs and dylibs! Linkage later on may
+//! use either one of these files, as each has their pros/cons. The job of crate
+//! loading is to discover what's possible by finding all candidates.
+//!
+//! Most parts of this loading systems keep the dylib/rlib as just separate
+//! variables.
+//!
+//! ## Where to look?
+//!
+//! We can't exactly scan your whole hard drive when looking for dependencies,
+//! so we need to places to look. Currently the compiler will implicitly add the
+//! target lib search path ($prefix/lib/rustlib/$target/lib) to any compilation,
+//! and otherwise all -L flags are added to the search paths.
+//!
+//! ## What criterion to select on?
+//!
+//! This a pretty tricky area of loading crates. Given a file, how do we know
+//! whether it's the right crate? Currently, the rules look along these lines:
+//!
+//! 1. Does the filename match an rlib/dylib pattern? That is to say, does the
+//!    filename have the right prefix/suffix?
+//! 2. Does the filename have the right prefix for the crate name being queried?
+//!    This is filtering for files like `libfoo*.rlib` and such.
+//! 3. Is the file an actual rust library? This is done by loading the metadata
+//!    from the library and making sure it's actually there.
+//! 4. Does the name in the metadata agree with the name of the library?
+//! 5. Does the target in the metadata agree with the current target?
+//! 6. Does the SVH match? (more on this later)
+//!
+//! If the file answeres `yes` to all these questions, then the file is
+//! considered as being *candidate* for being accepted. It is illegal to have
+//! more than two candidates as the compiler has no method by which to resolve
+//! this conflict. Additionally, rlib/dylib candidates are considered
+//! separately.
+//!
+//! After all this has happened, we have 1 or two files as candidates. These
+//! represent the rlib/dylib file found for a library, and they're returned as
+//! being found.
+//!
+//! ### What about versions?
+//!
+//! A lot of effort has been put forth to remove versioning from the compiler.
+//! There have been forays in the past to have versioning baked in, but it was
+//! largely always deemed insufficient to the point that it was recognized that
+//! it's probably something the compiler shouldn't do anyway due to its
+//! complicated nature and the state of the half-baked solutions.
+//!
+//! With a departure from versioning, the primary criterion for loading crates
+//! is just the name of a crate. If we stopped here, it would imply that you
+//! could never link two crates of the same name from different sources
+//! together, which is clearly a bad state to be in.
+//!
+//! To resolve this problem, we come to the next section!
+//!
+//! # Expert Mode
+//!
+//! A number of flags have been added to the compiler to solve the "version
+//! problem" in the previous section, as well as generally enabling more
+//! powerful usage of the crate loading system of the compiler. The goal of
+//! these flags and options are to enable third-party tools to drive the
+//! compiler with prior knowledge about how the world should look.
+//!
+//! ## The `--extern` flag
+//!
+//! The compiler accepts a flag of this form a number of times:
+//!
+//! ```notrust
+//! --extern crate-name=path/to/the/crate.rlib
+//! ```
+//!
+//! This flag is basically the following letter to the compiler:
+//!
+//! > Dear rustc,
+//! >
+//! > When you are attempting to load the immediate dependency `crate-name`, I
+//! > would like you too assume that the library is located at
+//! > `path/to/the/crate.rlib`, and look nowhere else. Also, please do not
+//! > assume that the path I specified has the name `crate-name`.
+//!
+//! This flag basically overrides most matching logic except for validating that
+//! the file is indeed a rust library. The same `crate-name` can be specified
+//! twice to specify the rlib/dylib pair.
+//!
+//! ## Enabling "multiple versions"
+//!
+//! This basically boils down to the ability to specify arbitrary packages to
+//! the compiler. For example, if crate A wanted to use Bv1 and Bv2, then it
+//! would look something like:
+//!
+//! ```ignore
+//! extern crate b1;
+//! extern crate b2;
+//!
+//! fn main() {}
+//! ```
+//!
+//! and the compiler would be invoked as:
+//!
+//! ```notrust
+//! rustc a.rs --extern b1=path/to/libb1.rlib --extern b2=path/to/libb2.rlib
+//! ```
+//!
+//! In this scenario there are two crates named `b` and the compiler must be
+//! manually driven to be informed where each crate is.
+//!
+//! ## Frobbing symbols
+//!
+//! One of the immediate problems with linking the same library together twice
+//! in the same problem is dealing with duplicate symbols. The primary way to
+//! deal with this in rustc is to add hashes to the end of each symbol.
+//!
+//! In order to force hashes to change between versions of a library, if
+//! desired, the compiler exposes an option `-C metadata=foo`, which is used to
+//! initially seed each symbol hash. The string `foo` is prepended to each
+//! string-to-hash to ensure that symbols change over time.
+//!
+//! ## Loading transitive dependencies
+//!
+//! Dealing with same-named-but-distinct crates is not just a local problem, but
+//! one that also needs to be dealt with for transitive dependences. Note that
+//! in the letter above `--extern` flags only apply to the *local* set of
+//! dependencies, not the upstream transitive dependencies. Consider this
+//! dependency graph:
+//!
+//! ```notrust
+//! A.1   A.2
+//! |     |
+//! |     |
+//! B     C
+//!  \   /
+//!   \ /
+//!    D
+//! ```
+//!
+//! In this scenario, when we compile `D`, we need to be able to distinctly
+//! resolve `A.1` and `A.2`, but an `--extern` flag cannot apply to these
+//! transitive dependencies.
+//!
+//! Note that the key idea here is that `B` and `C` are both *already compiled*.
+//! That is, they have already resolved their dependencies. Due to unrelated
+//! technical reasons, when a library is compiled, it is only compatible with
+//! the *exact same* version of the upstream libraries it was compiled against.
+//! We use the "Strict Version Hash" to identify the exact copy of an upstream
+//! library.
+//!
+//! With this knowledge, we know that `B` and `C` will depend on `A` with
+//! different SVH values, so we crawl the normal `-L` paths looking for
+//! `liba*.rlib` and filter based on the contained SVH.
+//!
+//! In the end, this ends up not needing `--extern` to specify upstream
+//! transitive dependencies.
+//!
+//! # Wrapping up
+//!
+//! That's the general overview of loading crates in the compiler, but it's by
+//! no means all of the necessary details. Take a look at the rest of
+//! metadata::loader or metadata::creader for all the juicy details!
 
 use back::archive::{ArchiveRO, METADATA_FILENAME};
 use back::svh::Svh;
@@ -21,8 +223,6 @@ use metadata::filesearch::{FileSearch, FileMatches, FileDoesntMatch};
 use syntax::abi;
 use syntax::codemap::Span;
 use syntax::diagnostic::SpanHandler;
-use syntax::crateid::CrateId;
-use syntax::attr::AttrMetaMethods;
 use util::fs;
 
 use std::c_str::ToCStr;
@@ -61,8 +261,7 @@ pub struct Context<'a> {
     pub sess: &'a Session,
     pub span: Span,
     pub ident: &'a str,
-    pub crate_id: &'a CrateId,
-    pub id_hash: &'a str,
+    pub crate_name: &'a str,
     pub hash: Option<&'a Svh>,
     pub triple: &'a str,
     pub os: abi::Os,
@@ -70,6 +269,7 @@ pub struct Context<'a> {
     pub root: &'a Option<CratePaths>,
     pub rejected_via_hash: Vec<CrateMismatch>,
     pub rejected_via_triple: Vec<CrateMismatch>,
+    pub should_match_name: bool,
 }
 
 pub struct Library {
@@ -167,19 +367,30 @@ impl<'a> Context<'a> {
     }
 
     fn find_library_crate(&mut self) -> Option<Library> {
+        // If an SVH is specified, then this is a transitive dependency that
+        // must be loaded via -L plus some filtering.
+        if self.hash.is_none() {
+            self.should_match_name = false;
+            match self.find_commandline_library() {
+                Some(l) => return Some(l),
+                None => {}
+            }
+            self.should_match_name = true;
+        }
+
         let dypair = self.dylibname();
 
         // want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
         let dylib_prefix = dypair.map(|(prefix, _)| {
-            format!("{}{}-", prefix, self.crate_id.name)
+            format!("{}{}", prefix, self.crate_name)
         });
-        let rlib_prefix = format!("lib{}-", self.crate_id.name);
+        let rlib_prefix = format!("lib{}", self.crate_name);
 
         let mut candidates = HashMap::new();
 
         // First, find all possible candidate rlibs and dylibs purely based on
         // the name of the files themselves. We're trying to match against an
-        // exact crate_id and a possibly an exact hash.
+        // exact crate name and a possibly an exact hash.
         //
         // During this step, we can filter all found libraries based on the
         // name and id found in the crate id (we ignore the path portion for
@@ -195,49 +406,32 @@ impl<'a> Context<'a> {
                 None => return FileDoesntMatch,
                 Some(file) => file,
             };
-            if file.starts_with(rlib_prefix.as_slice()) &&
+            let (hash, rlib) = if file.starts_with(rlib_prefix.as_slice()) &&
                     file.ends_with(".rlib") {
-                info!("rlib candidate: {}", path.display());
-                match self.try_match(file, rlib_prefix.as_slice(), ".rlib") {
-                    Some(hash) => {
-                        info!("rlib accepted, hash: {}", hash);
-                        let slot = candidates.find_or_insert_with(hash, |_| {
-                            (HashSet::new(), HashSet::new())
-                        });
-                        let (ref mut rlibs, _) = *slot;
-                        rlibs.insert(fs::realpath(path).unwrap());
-                        FileMatches
-                    }
-                    None => {
-                        info!("rlib rejected");
-                        FileDoesntMatch
-                    }
-                }
+                (file.slice(rlib_prefix.len(), file.len() - ".rlib".len()),
+                 true)
             } else if dypair.map_or(false, |(_, suffix)| {
                 file.starts_with(dylib_prefix.get_ref().as_slice()) &&
                 file.ends_with(suffix)
             }) {
                 let (_, suffix) = dypair.unwrap();
                 let dylib_prefix = dylib_prefix.get_ref().as_slice();
-                info!("dylib candidate: {}", path.display());
-                match self.try_match(file, dylib_prefix, suffix) {
-                    Some(hash) => {
-                        info!("dylib accepted, hash: {}", hash);
-                        let slot = candidates.find_or_insert_with(hash, |_| {
-                            (HashSet::new(), HashSet::new())
-                        });
-                        let (_, ref mut dylibs) = *slot;
-                        dylibs.insert(fs::realpath(path).unwrap());
-                        FileMatches
-                    }
-                    None => {
-                        info!("dylib rejected");
-                        FileDoesntMatch
-                    }
-                }
+                (file.slice(dylib_prefix.len(), file.len() - suffix.len()),
+                 false)
             } else {
-                FileDoesntMatch
+                return FileDoesntMatch
+            };
+            info!("lib candidate: {}", path.display());
+            let slot = candidates.find_or_insert_with(hash.to_string(), |_| {
+                (HashSet::new(), HashSet::new())
+            });
+            let (ref mut rlibs, ref mut dylibs) = *slot;
+            if rlib {
+                rlibs.insert(fs::realpath(path).unwrap());
+            } else {
+                dylibs.insert(fs::realpath(path).unwrap());
             }
+            FileMatches
         });
 
         // We have now collected all known libraries into a set of candidates
@@ -274,7 +468,7 @@ impl<'a> Context<'a> {
             _ => {
                 self.sess.span_err(self.span,
                     format!("multiple matching crates for `{}`",
-                            self.crate_id.name).as_slice());
+                            self.crate_name).as_slice());
                 self.sess.note("candidates:");
                 for lib in libraries.iter() {
                     match lib.dylib {
@@ -292,50 +486,14 @@ impl<'a> Context<'a> {
                         None => {}
                     }
                     let data = lib.metadata.as_slice();
-                    let crate_id = decoder::get_crate_id(data);
-                    note_crateid_attr(self.sess.diagnostic(), &crate_id);
+                    let name = decoder::get_crate_name(data);
+                    note_crate_name(self.sess.diagnostic(), name.as_slice());
                 }
                 None
             }
         }
     }
 
-    // Attempts to match the requested version of a library against the file
-    // specified. The prefix/suffix are specified (disambiguates between
-    // rlib/dylib).
-    //
-    // The return value is `None` if `file` doesn't look like a rust-generated
-    // library, or if a specific version was requested and it doesn't match the
-    // apparent file's version.
-    //
-    // If everything checks out, then `Some(hash)` is returned where `hash` is
-    // the listed hash in the filename itself.
-    fn try_match(&self, file: &str, prefix: &str, suffix: &str) -> Option<String>{
-        let middle = file.slice(prefix.len(), file.len() - suffix.len());
-        debug!("matching -- {}, middle: {}", file, middle);
-        let mut parts = middle.splitn('-', 1);
-        let hash = match parts.next() { Some(h) => h, None => return None };
-        debug!("matching -- {}, hash: {} (want {})", file, hash, self.id_hash);
-        let vers = match parts.next() { Some(v) => v, None => return None };
-        debug!("matching -- {}, vers: {} (want {})", file, vers,
-               self.crate_id.version);
-        match self.crate_id.version {
-            Some(ref version) if version.as_slice() != vers => return None,
-            Some(..) => {} // check the hash
-
-            // hash is irrelevant, no version specified
-            None => return Some(hash.to_string())
-        }
-        debug!("matching -- {}, vers ok", file);
-        // hashes in filenames are prefixes of the "true hash"
-        if self.id_hash == hash.as_slice() {
-            debug!("matching -- {}, hash ok", file);
-            Some(hash.to_string())
-        } else {
-            None
-        }
-    }
-
     // Attempts to extract *one* library from the set `m`. If the set has no
     // elements, `None` is returned. If the set has more than one element, then
     // the errors and notes are emitted about the set of libraries.
@@ -382,7 +540,7 @@ impl<'a> Context<'a> {
                                    format!("multiple {} candidates for `{}` \
                                             found",
                                            flavor,
-                                           self.crate_id.name).as_slice());
+                                           self.crate_name).as_slice());
                 self.sess.span_note(self.span,
                                     format!(r"candidate #1: {}",
                                             ret.get_ref()
@@ -404,9 +562,11 @@ impl<'a> Context<'a> {
     }
 
     fn crate_matches(&mut self, crate_data: &[u8], libpath: &Path) -> bool {
-        match decoder::maybe_get_crate_id(crate_data) {
-            Some(ref id) if self.crate_id.matches(id) => {}
-            _ => { info!("Rejecting via crate_id"); return false }
+        if self.should_match_name {
+            match decoder::maybe_get_crate_name(crate_data) {
+                Some(ref name) if self.crate_name == name.as_slice() => {}
+                _ => { info!("Rejecting via crate name"); return false }
+            }
         }
         let hash = match decoder::maybe_get_crate_hash(crate_data) {
             Some(hash) => hash, None => {
@@ -415,7 +575,10 @@ impl<'a> Context<'a> {
             }
         };
 
-        let triple = decoder::get_crate_triple(crate_data);
+        let triple = match decoder::get_crate_triple(crate_data) {
+            None => { debug!("triple not present"); return false }
+            Some(t) => t,
+        };
         if triple.as_slice() != self.triple {
             info!("Rejecting via crate triple: expected {} got {}", self.triple, triple);
             self.rejected_via_triple.push(CrateMismatch {
@@ -456,10 +619,72 @@ impl<'a> Context<'a> {
         }
     }
 
+    fn find_commandline_library(&mut self) -> Option<Library> {
+        let locs = match self.sess.opts.externs.find_equiv(&self.crate_name) {
+            Some(s) => s,
+            None => return None,
+        };
+
+        // First, filter out all libraries that look suspicious. We only accept
+        // files which actually exist that have the correct naming scheme for
+        // rlibs/dylibs.
+        let sess = self.sess;
+        let dylibname = self.dylibname();
+        let mut locs = locs.iter().map(|l| Path::new(l.as_slice())).filter(|loc| {
+            if !loc.exists() {
+                sess.err(format!("extern location does not exist: {}",
+                                 loc.display()).as_slice());
+                return false;
+            }
+            let file = loc.filename_str().unwrap();
+            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 => {}
+                }
+            }
+            sess.err(format!("extern location is of an unknown type: {}",
+                             loc.display()).as_slice());
+            false
+        });
+
+        // Now that we have an itertor of good candidates, make sure there's at
+        // most one rlib and at most one dylib.
+        let mut rlibs = HashSet::new();
+        let mut dylibs = HashSet::new();
+        for loc in locs {
+            if loc.filename_str().unwrap().ends_with(".rlib") {
+                rlibs.insert(loc.clone());
+            } else {
+                dylibs.insert(loc.clone());
+            }
+        }
+
+        // Extract the rlib/dylib pair.
+        let mut metadata = None;
+        let rlib = self.extract_one(rlibs, "rlib", &mut metadata);
+        let dylib = self.extract_one(dylibs, "dylib", &mut metadata);
+
+        if rlib.is_none() && dylib.is_none() { return None }
+        match metadata {
+            Some(metadata) => Some(Library {
+                dylib: dylib,
+                rlib: rlib,
+                metadata: metadata,
+            }),
+            None => None,
+        }
+    }
 }
 
-pub fn note_crateid_attr(diag: &SpanHandler, crateid: &CrateId) {
-    diag.handler().note(format!("crate_id: {}", crateid.to_str()).as_slice());
+pub fn note_crate_name(diag: &SpanHandler, name: &str) {
+    diag.handler().note(format!("crate name: {}", name).as_slice());
 }
 
 impl ArchiveMetadata {
diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs
index bdb7d30339d..1bb5ffdccb5 100644
--- a/src/librustc/middle/save/mod.rs
+++ b/src/librustc/middle/save/mod.rs
@@ -1373,15 +1373,15 @@ pub fn process_crate(sess: &Session,
         return;
     }
 
-    let (cratename, crateid) = match attr::find_crateid(krate.attrs.as_slice()) {
-        Some(crateid) => (crateid.name.clone(), crateid.to_str()),
+    let cratename = match attr::find_crate_name(krate.attrs.as_slice()) {
+        Some(name) => name.get().to_string(),
         None => {
             info!("Could not find crate name, using 'unknown_crate'");
-            (String::from_str("unknown_crate"),"unknown_crate".to_owned())
+            String::from_str("unknown_crate")
         },
     };
 
-    info!("Dumping crate {} ({})", cratename, crateid);
+    info!("Dumping crate {}", cratename);
 
     // find a path to dump our data to
     let mut root_path = match os::getenv("DXR_RUST_TEMP_FOLDER") {
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 75271804b79..d371a2589ff 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -30,7 +30,6 @@ use back::{link, abi};
 use driver::config;
 use driver::config::{NoDebugInfo, FullDebugInfo};
 use driver::session::Session;
-use driver::driver::OutputFilenames;
 use driver::driver::{CrateAnalysis, CrateTranslation};
 use lib::llvm::{ModuleRef, ValueRef, BasicBlockRef};
 use lib::llvm::{llvm, Vector};
@@ -2270,8 +2269,9 @@ pub fn write_metadata(cx: &CrateContext, krate: &ast::Crate) -> Vec<u8> {
                      }.as_slice());
     let llmeta = C_bytes(cx, compressed.as_slice());
     let llconst = C_struct(cx, [llmeta], false);
-    let name = format!("rust_metadata_{}_{}_{}", cx.link_meta.crateid.name,
-                       cx.link_meta.crateid.version_or_default(), cx.link_meta.crate_hash);
+    let name = format!("rust_metadata_{}_{}",
+                       cx.link_meta.crate_name,
+                       cx.link_meta.crate_hash);
     let llglobal = name.with_c_str(|buf| {
         unsafe {
             llvm::LLVMAddGlobal(cx.metadata_llmod, val_ty(llconst).to_ref(), buf)
@@ -2288,9 +2288,8 @@ pub fn write_metadata(cx: &CrateContext, krate: &ast::Crate) -> Vec<u8> {
 }
 
 pub fn trans_crate(krate: ast::Crate,
-                   analysis: CrateAnalysis,
-                   output: &OutputFilenames) -> (ty::ctxt, CrateTranslation) {
-    let CrateAnalysis { ty_cx: tcx, exp_map2, reachable, .. } = analysis;
+                   analysis: CrateAnalysis) -> (ty::ctxt, CrateTranslation) {
+    let CrateAnalysis { ty_cx: tcx, exp_map2, reachable, name, .. } = analysis;
 
     // Before we touch LLVM, make sure that multithreading is enabled.
     unsafe {
@@ -2310,8 +2309,7 @@ pub fn trans_crate(krate: ast::Crate,
         }
     }
 
-    let link_meta = link::build_link_meta(&krate,
-                                          output.out_filestem.as_slice());
+    let link_meta = link::build_link_meta(&tcx.sess, &krate, name);
 
     // Append ".rs" to crate name as LLVM module identifier.
     //
@@ -2321,7 +2319,7 @@ pub fn trans_crate(krate: ast::Crate,
     // crashes if the module identifier is same as other symbols
     // such as a function name in the module.
     // 1. http://llvm.org/bugs/show_bug.cgi?id=11479
-    let mut llmod_id = link_meta.crateid.name.clone();
+    let mut llmod_id = link_meta.crate_name.clone();
     llmod_id.push_str(".rs");
 
     let ccx = CrateContext::new(llmod_id.as_slice(), tcx, exp_map2,
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index ddcc4c4bfa1..7eb3fcce780 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -1496,7 +1496,7 @@ fn compile_unit_metadata(cx: &CrateContext) {
     });
 
     fn fallback_path(cx: &CrateContext) -> CString {
-        cx.link_meta.crateid.name.as_slice().to_c_str()
+        cx.link_meta.crate_name.as_slice().to_c_str()
     }
 }
 
@@ -3972,7 +3972,7 @@ impl NamespaceTreeNode {
 }
 
 fn crate_root_namespace<'a>(cx: &'a CrateContext) -> &'a str {
-    cx.link_meta.crateid.name.as_slice()
+    cx.link_meta.crate_name.as_slice()
 }
 
 fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc<NamespaceTreeNode> {
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index 6d719873c76..ff28f668c47 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -566,7 +566,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
 
         let ps = ccx.tcx.map.with_path(id, |path| {
             let abi = Some(ast_map::PathName(special_idents::clownshoe_abi.name));
-            link::mangle(path.chain(abi.move_iter()), None, None)
+            link::mangle(path.chain(abi.move_iter()), None)
         });
 
         // Compute the type that the function would have if it were just a
diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs
index 125fa6828c5..768deec8edc 100644
--- a/src/librustc/middle/trans/monomorphize.rs
+++ b/src/librustc/middle/trans/monomorphize.rs
@@ -129,9 +129,7 @@ pub fn monomorphic_fn(ccx: &CrateContext,
         hash_id.hash(&mut state);
         mono_ty.hash(&mut state);
 
-        exported_name(path,
-                      format!("h{}", state.result()).as_slice(),
-                      ccx.link_meta.crateid.version_or_default())
+        exported_name(path, format!("h{}", state.result()).as_slice())
     });
     debug!("monomorphize_fn mangled to {}", s);
 
diff --git a/src/librustc/middle/typeck/infer/test.rs b/src/librustc/middle/typeck/infer/test.rs
index 5ae469c41f2..ff9f855c987 100644
--- a/src/librustc/middle/typeck/infer/test.rs
+++ b/src/librustc/middle/typeck/infer/test.rs
@@ -37,7 +37,6 @@ use syntax::codemap;
 use syntax::codemap::{Span, CodeMap, DUMMY_SP};
 use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note};
 use syntax::ast;
-use syntax::crateid::CrateId;
 use util::ppaux::{ty_to_str, UserString};
 
 struct Env<'a> {
@@ -116,11 +115,8 @@ fn test_env(_test_name: &str,
     let krate_config = Vec::new();
     let input = driver::StrInput(source_string.to_owned());
     let krate = driver::phase_1_parse_input(&sess, krate_config, &input);
-    let krate_id = CrateId { path: "test".to_owned(),
-                             name: "test".to_owned(),
-                             version: None };
     let (krate, ast_map) =
-        driver::phase_2_configure_and_expand(&sess, krate, &krate_id)
+        driver::phase_2_configure_and_expand(&sess, krate, "test")
             .expect("phase 2 aborted");
 
     // run just enough stuff to build a tcx:
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 12c183132d6..1ddd97e2ed4 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -119,13 +119,7 @@ impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
 
         // Figure out the name of this crate
         let input = driver::FileInput(cx.src.clone());
-        let t_outputs = driver::build_output_filenames(&input,
-                                                       &None,
-                                                       &None,
-                                                       self.attrs.as_slice(),
-                                                       cx.sess());
-        let id = link::find_crate_id(self.attrs.as_slice(),
-                                     t_outputs.out_filestem.as_slice());
+        let name = link::find_crate_name(None, self.attrs.as_slice(), &input);
 
         // Clean the crate, translating the entire libsyntax AST to one that is
         // understood by rustdoc.
@@ -188,7 +182,7 @@ impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
         }
 
         Crate {
-            name: id.name.to_string(),
+            name: name.to_string(),
             module: Some(module),
             externs: externs,
             primitives: primitives,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 245b2d162a7..9ef671ef2fc 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -12,6 +12,7 @@ use rustc;
 use rustc::{driver, middle};
 use rustc::middle::{privacy, ty};
 use rustc::lint;
+use rustc::back::link;
 
 use syntax::ast;
 use syntax::parse::token;
@@ -115,13 +116,17 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<String>)
     }
 
     let krate = phase_1_parse_input(&sess, cfg, &input);
+
+    let name = link::find_crate_name(Some(&sess), krate.attrs.as_slice(),
+                                     &input);
+
     let (krate, ast_map)
-        = phase_2_configure_and_expand(&sess, krate, &from_str("rustdoc").unwrap())
+        = phase_2_configure_and_expand(&sess, krate, name.as_slice())
             .expect("phase_2_configure_and_expand aborted in rustdoc!");
 
     let driver::driver::CrateAnalysis {
         exported_items, public_items, ty_cx, ..
-    } = phase_3_run_analysis_passes(sess, &krate, ast_map);
+    } = phase_3_run_analysis_passes(sess, &krate, ast_map, name);
 
     debug!("crate: {:?}", krate);
     (DocContext {
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index d878313ee28..7d6f44f5d16 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -8,12 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![crate_id = "rustdoc#0.11.0"]
+#![crate_id = "rustdoc#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "rustdoc"]
 #![experimental]
 #![desc = "rustdoc, the Rust documentation extractor"]
 #![license = "MIT/ASL2"]
 #![crate_type = "dylib"]
 #![crate_type = "rlib"]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 #![feature(globs, struct_variant, managed_boxes, macro_rules, phase)]
 
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 7e7f10f7178..18f82331780 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -69,7 +69,7 @@ pub fn run(input: &str,
     }));
     let krate = driver::phase_1_parse_input(&sess, cfg, &input);
     let (krate, _) = driver::phase_2_configure_and_expand(&sess, krate,
-            &from_str("rustdoc-test").unwrap())
+                                                          "rustdoc-test")
         .expect("phase_2_configure_and_expand aborted in rustdoc!");
 
     let ctx = box(GC) core::DocContext {
diff --git a/src/librustrt/lib.rs b/src/librustrt/lib.rs
index fabef24e06a..1a67f6d86ba 100644
--- a/src/librustrt/lib.rs
+++ b/src/librustrt/lib.rs
@@ -8,7 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![crate_id = "rustrt#0.11.0"]
+#![crate_id = "rustrt#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "rustrt"]
 #![license = "MIT/ASL2"]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
@@ -20,6 +21,7 @@
 #![feature(linkage, lang_items, unsafe_destructor)]
 #![no_std]
 #![experimental]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 #[phase(plugin, link)] extern crate core;
 extern crate alloc;
diff --git a/src/librustuv/lib.rs b/src/librustuv/lib.rs
index c13263680aa..a9e6a6a4a9a 100644
--- a/src/librustuv/lib.rs
+++ b/src/librustuv/lib.rs
@@ -34,7 +34,8 @@ via `close` and `delete` methods.
 
 */
 
-#![crate_id = "rustuv#0.11.0"]
+#![crate_id = "rustuv#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "rustuv"]
 #![experimental]
 #![license = "MIT/ASL2"]
 #![crate_type = "rlib"]
@@ -47,6 +48,7 @@ via `close` and `delete` methods.
 #![feature(macro_rules, unsafe_destructor)]
 #![deny(unused_result, unused_must_use)]
 #![allow(visible_private_types)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 #[cfg(test)] extern crate green;
 #[cfg(test)] extern crate debug;
diff --git a/src/libsemver/lib.rs b/src/libsemver/lib.rs
index fc8aa8ac257..31a065a1449 100644
--- a/src/libsemver/lib.rs
+++ b/src/libsemver/lib.rs
@@ -28,7 +28,8 @@
 //! An example version number with all five components is
 //! `0.8.1-rc.3.0+20130922.linux`.
 
-#![crate_id = "semver#0.11.0"]
+#![crate_id = "semver#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "semver"]
 #![experimental]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
@@ -36,6 +37,7 @@
 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 use std::char;
 use std::cmp;
diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs
index a2a50413236..f635c3f4150 100644
--- a/src/libserialize/lib.rs
+++ b/src/libserialize/lib.rs
@@ -14,7 +14,8 @@
 Core encoding and decoding interfaces.
 */
 
-#![crate_id = "serialize#0.11.0"]
+#![crate_id = "serialize#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "serialize"]
 #![experimental]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
@@ -24,6 +25,7 @@ Core encoding and decoding interfaces.
        html_root_url = "http://doc.rust-lang.org/0.11.0/",
        html_playground_url = "http://play.rust-lang.org/")]
 #![feature(macro_rules, managed_boxes, default_type_params, phase)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 // test harness access
 #[cfg(test)]
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 0e6f848fce8..928a1088d0e 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -94,7 +94,8 @@
 //! all the standard macros, such as `assert!`, `fail!`, `println!`,
 //! and `format!`, also available to all Rust code.
 
-#![crate_id = "std#0.11.0"]
+#![crate_id = "std#0.11.0"] // NOTE: remove after stage0 snap
+#![crate_name = "std"]
 #![unstable]
 #![comment = "The Rust standard library"]
 #![license = "MIT/ASL2"]
@@ -107,6 +108,7 @@
 
 #![feature(macro_rules, globs, managed_boxes, linkage)]
 #![feature(default_type_params, phase, lang_items, unsafe_destructor)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 // Don't link to std. We are std.
 #![no_std]
diff --git a/src/libsync/lib.rs b/src/libsync/lib.rs
index 4f6d1a261c4..c0d62caaa6b 100644
--- a/src/libsync/lib.rs
+++ b/src/libsync/lib.rs
@@ -17,7 +17,8 @@
 //! use this crate specifically. Instead, its functionality is reexported
 //! through `std::sync`.
 
-#![crate_id = "sync#0.11.0"]
+#![crate_id = "sync#0.11.0"] // NOTE: remove after stage0 snap
+#![crate_name = "sync"]
 #![experimental]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
@@ -30,6 +31,7 @@
 #![feature(phase, globs, macro_rules, unsafe_destructor)]
 #![deny(missing_doc)]
 #![no_std]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 #[phase(plugin, link)] extern crate core;
 extern crate alloc;
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index a037c0ac07e..3b2ee4e2a61 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -18,7 +18,6 @@ use diagnostic::SpanHandler;
 use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
 use parse::token::InternedString;
 use parse::token;
-use crateid::CrateId;
 
 use std::collections::HashSet;
 use std::collections::BitvSet;
@@ -271,11 +270,8 @@ pub fn sort_meta_items(items: &[Gc<MetaItem>]) -> Vec<Gc<MetaItem>> {
     }).collect()
 }
 
-pub fn find_crateid(attrs: &[Attribute]) -> Option<CrateId> {
-    match first_attr_value_str_by_name(attrs, "crate_id") {
-        None => None,
-        Some(id) => from_str::<CrateId>(id.get()),
-    }
+pub fn find_crate_name(attrs: &[Attribute]) -> Option<InternedString> {
+    first_attr_value_str_by_name(attrs, "crate_name")
 }
 
 #[deriving(PartialEq)]
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index cf69277594f..673ae31ef77 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -452,7 +452,7 @@ impl<'a> ExtCtxt<'a> {
     pub fn mod_pop(&mut self) { self.mod_path.pop().unwrap(); }
     pub fn mod_path(&self) -> Vec<ast::Ident> {
         let mut v = Vec::new();
-        v.push(token::str_to_ident(self.ecfg.crate_id.name.as_slice()));
+        v.push(token::str_to_ident(self.ecfg.crate_name.as_slice()));
         v.extend(self.mod_path.iter().map(|a| *a));
         return v;
     }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index b30b62c8901..752b3a09e65 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -19,7 +19,6 @@ use attr;
 use attr::AttrMetaMethods;
 use codemap;
 use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
-use crateid::CrateId;
 use ext::base::*;
 use fold;
 use fold::*;
@@ -985,7 +984,7 @@ fn new_span(cx: &ExtCtxt, sp: Span) -> Span {
 
 pub struct ExpansionConfig {
     pub deriving_hash_type_parameter: bool,
-    pub crate_id: CrateId,
+    pub crate_name: String,
 }
 
 pub struct ExportedMacros {
@@ -1184,7 +1183,7 @@ mod test {
         // should fail:
         let cfg = ::syntax::ext::expand::ExpansionConfig {
             deriving_hash_type_parameter: false,
-            crate_id: from_str("test").unwrap(),
+            crate_name: "test".to_str(),
         };
         expand_crate(&sess,cfg,vec!(),vec!(),crate_ast);
     }
@@ -1201,7 +1200,7 @@ mod test {
             Vec::new(), &sess);
         let cfg = ::syntax::ext::expand::ExpansionConfig {
             deriving_hash_type_parameter: false,
-            crate_id: from_str("test").unwrap(),
+            crate_name: "test".to_str(),
         };
         expand_crate(&sess,cfg,vec!(),vec!(),crate_ast);
     }
@@ -1217,7 +1216,7 @@ mod test {
             Vec::new(), &sess);
         let cfg = ::syntax::ext::expand::ExpansionConfig {
             deriving_hash_type_parameter: false,
-            crate_id: from_str("test").unwrap(),
+            crate_name: "test".to_str(),
         };
         expand_crate(&sess, cfg, vec!(), vec!(), crate_ast);
     }
@@ -1254,7 +1253,7 @@ mod test {
         // the cfg argument actually does matter, here...
         let cfg = ::syntax::ext::expand::ExpansionConfig {
             deriving_hash_type_parameter: false,
-            crate_id: from_str("test").unwrap(),
+            crate_name: "test".to_str(),
         };
         expand_crate(&ps,cfg,vec!(),vec!(),crate_ast)
     }
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index ce63d2bb731..6df91c66a25 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -18,7 +18,8 @@ This API is completely unstable and subject to change.
 
 */
 
-#![crate_id = "syntax#0.11.0"]
+#![crate_id = "syntax#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "syntax"]
 #![experimental]
 #![license = "MIT/ASL2"]
 #![crate_type = "dylib"]
@@ -30,6 +31,7 @@ This API is completely unstable and subject to change.
 #![feature(macro_rules, globs, managed_boxes, default_type_params, phase)]
 #![feature(quote, unsafe_destructor)]
 #![allow(deprecated)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 extern crate serialize;
 extern crate term;
diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs
index 56694e28b66..cdd067cef5b 100644
--- a/src/libterm/lib.rs
+++ b/src/libterm/lib.rs
@@ -38,7 +38,8 @@
 //! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx
 //! [ti]: https://en.wikipedia.org/wiki/Terminfo
 
-#![crate_id = "term#0.11.0"]
+#![crate_id = "term#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "term"]
 #![experimental]
 #![comment = "Simple ANSI color library"]
 #![license = "MIT/ASL2"]
@@ -48,6 +49,7 @@
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/0.11.0/",
        html_playground_url = "http://play.rust-lang.org/")]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 #![feature(macro_rules, phase)]
 
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 02f7ebc6d21..1eb13fd660e 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -23,7 +23,8 @@
 // running tests while providing a base that other test frameworks may
 // build off of.
 
-#![crate_id = "test#0.11.0"]
+#![crate_id = "test#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "test"] // NOTE: remove after stage0
 #![experimental]
 #![comment = "Rust internal test library only used by rustc"]
 #![license = "MIT/ASL2"]
@@ -32,6 +33,7 @@
 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 #![feature(asm, macro_rules, phase)]
 
diff --git a/src/libtime/lib.rs b/src/libtime/lib.rs
index 0e4de41959a..873cc7af7b6 100644
--- a/src/libtime/lib.rs
+++ b/src/libtime/lib.rs
@@ -10,7 +10,8 @@
 
 //! Simple time handling.
 
-#![crate_id = "time#0.11.0"]
+#![crate_id = "time#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "time"]
 #![experimental]
 
 #![crate_type = "rlib"]
@@ -21,6 +22,7 @@
        html_root_url = "http://doc.rust-lang.org/0.11.0/",
        html_playground_url = "http://play.rust-lang.org/")]
 #![feature(phase)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 #[cfg(test)] extern crate debug;
 #[cfg(test)] #[phase(plugin, link)] extern crate log;
diff --git a/src/liburl/lib.rs b/src/liburl/lib.rs
index c1adc5d84e6..e835e5b26cf 100644
--- a/src/liburl/lib.rs
+++ b/src/liburl/lib.rs
@@ -10,7 +10,8 @@
 
 //! Types/fns concerning URLs (see RFC 3986)
 
-#![crate_id = "url#0.11.0"]
+#![crate_id = "url#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "url"]
 #![experimental]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
@@ -20,6 +21,7 @@
        html_root_url = "http://doc.rust-lang.org/0.11.0/",
        html_playground_url = "http://play.rust-lang.org/")]
 #![feature(default_type_params)]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 use std::collections::HashMap;
 use std::fmt;
diff --git a/src/libuuid/lib.rs b/src/libuuid/lib.rs
index 297afe4aa59..426b350cab9 100644
--- a/src/libuuid/lib.rs
+++ b/src/libuuid/lib.rs
@@ -54,7 +54,8 @@ Examples of string representations:
 
 */
 
-#![crate_id = "uuid#0.11.0"]
+#![crate_id = "uuid#0.11.0"] // NOTE: remove after stage0
+#![crate_name = "uuid"]
 #![experimental]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
@@ -63,6 +64,7 @@ Examples of string representations:
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/0.11.0/",
        html_playground_url = "http://play.rust-lang.org/")]
+#![allow(unused_attribute)] // NOTE: remove after stage0
 
 #![feature(default_type_params)]
 
diff --git a/src/test/auxiliary/crateresolve1-1.rs b/src/test/auxiliary/crateresolve1-1.rs
index eddedfa36bb..e26ea7c4fa6 100644
--- a/src/test/auxiliary/crateresolve1-1.rs
+++ b/src/test/auxiliary/crateresolve1-1.rs
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![crate_id="crateresolve1#0.1"]
-
+// compile-flags:-C extra-filename=-1
+#![crate_name = "crateresolve1"]
 #![crate_type = "lib"]
 
 pub fn f() -> int { 10 }
diff --git a/src/test/auxiliary/crateresolve1-2.rs b/src/test/auxiliary/crateresolve1-2.rs
index 48042de0bad..715171b143a 100644
--- a/src/test/auxiliary/crateresolve1-2.rs
+++ b/src/test/auxiliary/crateresolve1-2.rs
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![crate_id="crateresolve1#0.2"]
-
+// compile-flags:-C extra-filename=-2
+#![crate_name = "crateresolve1"]
 #![crate_type = "lib"]
 
 pub fn f() -> int { 20 }
diff --git a/src/test/auxiliary/crateresolve1-3.rs b/src/test/auxiliary/crateresolve1-3.rs
index c126560fe3e..f733b5b908a 100644
--- a/src/test/auxiliary/crateresolve1-3.rs
+++ b/src/test/auxiliary/crateresolve1-3.rs
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![crate_id="crateresolve1#0.3"]
-
+// compile-flags:-C extra-filename=-3
+#![crate_name = "crateresolve1"]
 #![crate_type = "lib"]
 
 pub fn f() -> int { 30 }
diff --git a/src/test/auxiliary/crateresolve2-1.rs b/src/test/auxiliary/crateresolve2-1.rs
deleted file mode 100644
index f436e7c95d1..00000000000
--- a/src/test/auxiliary/crateresolve2-1.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2012 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.
-
-#![crate_id="crateresolve2#0.1"]
-
-#![crate_type = "lib"]
-
-pub fn f() -> int { 10 }
diff --git a/src/test/auxiliary/extern-crosscrate-source.rs b/src/test/auxiliary/extern-crosscrate-source.rs
index e26f8effb47..5c83b327912 100644
--- a/src/test/auxiliary/extern-crosscrate-source.rs
+++ b/src/test/auxiliary/extern-crosscrate-source.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![crate_id="externcallback#0.1"]
+#![crate_name="externcallback"]
 #![crate_type = "lib"]
 
 extern crate libc;
diff --git a/src/test/compile-fail/bad-crate-id.rs b/src/test/compile-fail/bad-crate-id.rs
index 43956752cd9..883bfd035f4 100644
--- a/src/test/compile-fail/bad-crate-id.rs
+++ b/src/test/compile-fail/bad-crate-id.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-extern crate foo = ""; //~ ERROR: malformed crate id
-extern crate bar = "#a"; //~ ERROR: malformed crate id
+extern crate foo = ""; //~ ERROR: crate name must not be empty
 
 fn main() {}
diff --git a/src/test/auxiliary/crateresolve2-2.rs b/src/test/compile-fail/bad-crate-id2.rs
index 1f92ce5943c..22e98b61c61 100644
--- a/src/test/auxiliary/crateresolve2-2.rs
+++ b/src/test/compile-fail/bad-crate-id2.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,8 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![crate_id="crateresolve2#0.2"]
+extern crate bar = "#a"; //~ ERROR: invalid character `#` in crate name: `#a`
 
-#![crate_type = "lib"]
+fn main() {}
 
-pub fn f() -> int { 20 }
diff --git a/src/test/compile-fail/crateresolve2.rs b/src/test/compile-fail/crateresolve2.rs
deleted file mode 100644
index c5e9d128152..00000000000
--- a/src/test/compile-fail/crateresolve2.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2012 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.
-
-// aux-build:crateresolve2-1.rs
-// aux-build:crateresolve2-2.rs
-// aux-build:crateresolve2-3.rs
-// error-pattern:using multiple versions of crate `crateresolve2`
-
-extern crate crateresolve2 = "crateresolve2#0.1";
-
-mod m {
-    pub extern crate crateresolve2 = "crateresolve2#0.2";
-}
-
-fn main() {
-    let x: int = false;
-}
diff --git a/src/test/compile-fail/crateresolve5.rs b/src/test/compile-fail/crateresolve5.rs
deleted file mode 100644
index 8b4801466b9..00000000000
--- a/src/test/compile-fail/crateresolve5.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2012-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.
-
-// aux-build:crateresolve5-1.rs
-// aux-build:crateresolve5-2.rs
-
-extern crate cr5_1 = "crateresolve5#0.1";
-extern crate cr5_2 = "crateresolve5#0.2";
-
-
-fn main() {
-    // Nominal types from two multiple versions of a crate are different types
-    assert!(cr5_1::nominal() == cr5_2::nominal()); //~ ERROR mismatched types: expected
-}
diff --git a/src/test/compile-fail/issue-11908-1.rs b/src/test/compile-fail/issue-11908-1.rs
deleted file mode 100644
index dbedf355a56..00000000000
--- a/src/test/compile-fail/issue-11908-1.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.
-
-// aux-build:issue-11908-1.rs
-// ignore-android this test is incompatible with the android test runner
-// error-pattern: multiple dylib candidates for `url` found
-
-// This test ensures that if you have the same rlib or dylib at two locations
-// in the same path that you don't hit an assertion in the compiler.
-//
-// Note that this relies on `liburl` to be in the path somewhere else,
-// and then our aux-built libraries will collide with liburl (they have
-// the same version listed)
-
-extern crate url;
-
-fn main() {}
diff --git a/src/test/run-make/bootstrap-from-c-with-green/Makefile b/src/test/run-make/bootstrap-from-c-with-green/Makefile
index 3b28af9b0e8..c7753a67464 100644
--- a/src/test/run-make/bootstrap-from-c-with-green/Makefile
+++ b/src/test/run-make/bootstrap-from-c-with-green/Makefile
@@ -6,7 +6,6 @@ TARGET_RPATH_DIR:=$(TARGET_RPATH_DIR):$(TMPDIR)
 
 all:
 	$(RUSTC) lib.rs
-	ln -nsf $(call DYLIB,boot-*) $(call DYLIB,boot)
 	$(CC) main.c -o $(call RUN_BINFILE,main) $(call RPATH_LINK_SEARCH,$(HOST_LIB_DIR)) -lboot
 	$(call RUN,main)
 	$(call REMOVE_DYLIBS,boot)
diff --git a/src/test/run-make/bootstrap-from-c-with-green/lib.rs b/src/test/run-make/bootstrap-from-c-with-green/lib.rs
index 69c65ef8b03..7f17018c486 100644
--- a/src/test/run-make/bootstrap-from-c-with-green/lib.rs
+++ b/src/test/run-make/bootstrap-from-c-with-green/lib.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![crate_id="boot#0.1"]
+#![crate_name="boot"]
 #![crate_type="dylib"]
 
 extern crate rustuv;
diff --git a/src/test/run-make/bootstrap-from-c-with-native/Makefile b/src/test/run-make/bootstrap-from-c-with-native/Makefile
index 3b28af9b0e8..c7753a67464 100644
--- a/src/test/run-make/bootstrap-from-c-with-native/Makefile
+++ b/src/test/run-make/bootstrap-from-c-with-native/Makefile
@@ -6,7 +6,6 @@ TARGET_RPATH_DIR:=$(TARGET_RPATH_DIR):$(TMPDIR)
 
 all:
 	$(RUSTC) lib.rs
-	ln -nsf $(call DYLIB,boot-*) $(call DYLIB,boot)
 	$(CC) main.c -o $(call RUN_BINFILE,main) $(call RPATH_LINK_SEARCH,$(HOST_LIB_DIR)) -lboot
 	$(call RUN,main)
 	$(call REMOVE_DYLIBS,boot)
diff --git a/src/test/run-make/c-link-to-rust-dylib/Makefile b/src/test/run-make/c-link-to-rust-dylib/Makefile
index e743004a9cb..a5b4430ab6a 100644
--- a/src/test/run-make/c-link-to-rust-dylib/Makefile
+++ b/src/test/run-make/c-link-to-rust-dylib/Makefile
@@ -4,7 +4,6 @@ HOST_LIB_DIR=$(TMPDIR)/../../../stage$(RUST_BUILD_STAGE)/lib
 
 all:
 	$(RUSTC) foo.rs
-	ln -s $(call DYLIB,foo-*) $(call DYLIB,foo)
 	$(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(call RPATH_LINK_SEARCH,$(HOST_LIB_DIR)) -Wl,-rpath,$(TMPDIR)
 	$(call RUN,bar)
 	$(call REMOVE_DYLIBS,foo)
diff --git a/src/test/run-make/c-link-to-rust-staticlib/Makefile b/src/test/run-make/c-link-to-rust-staticlib/Makefile
index 40b6feac678..8a6d6e4dd6d 100644
--- a/src/test/run-make/c-link-to-rust-staticlib/Makefile
+++ b/src/test/run-make/c-link-to-rust-staticlib/Makefile
@@ -10,7 +10,6 @@ endif
 ifneq ($(shell uname),FreeBSD)
 all:
 	$(RUSTC) foo.rs
-	ln -s $(call STATICLIB,foo-*) $(call STATICLIB,foo)
 	$(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(EXTRAFLAGS) -lstdc++
 	$(call RUN,bar)
 	rm $(call STATICLIB,foo*)
diff --git a/src/test/run-make/crate-data-smoke/Makefile b/src/test/run-make/crate-data-smoke/Makefile
index a44481b4b7f..23d155fe23d 100644
--- a/src/test/run-make/crate-data-smoke/Makefile
+++ b/src/test/run-make/crate-data-smoke/Makefile
@@ -1,10 +1,9 @@
 -include ../tools.mk
 
 all:
-	[ `$(RUSTC) --crate-id crate.rs` = "foo#0.11.0" ]
-	[ `$(RUSTC) --crate-name crate.rs` = "foo" ]
-	[ `$(RUSTC) --crate-file-name crate.rs` = "foo" ]
-	[ `$(RUSTC) --crate-file-name --crate-type=lib --test crate.rs` = "foo" ]
-	[ `$(RUSTC) --crate-file-name --test lib.rs` = "mylib" ]
-	$(RUSTC) --crate-file-name lib.rs
-	$(RUSTC) --crate-file-name rlib.rs
+	[ `$(RUSTC) --print-crate-name crate.rs` = "foo" ]
+	[ `$(RUSTC) --print-file-name crate.rs` = "foo" ]
+	[ `$(RUSTC) --print-file-name --crate-type=lib --test crate.rs` = "foo" ]
+	[ `$(RUSTC) --print-file-name --test lib.rs` = "mylib" ]
+	$(RUSTC) --print-file-name lib.rs
+	$(RUSTC) --print-file-name rlib.rs
diff --git a/src/test/run-make/crate-data-smoke/crate.rs b/src/test/run-make/crate-data-smoke/crate.rs
index 9faa7c01628..305b3dc70a6 100644
--- a/src/test/run-make/crate-data-smoke/crate.rs
+++ b/src/test/run-make/crate-data-smoke/crate.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![crate_id = "foo#0.11.0"]
+#![crate_name = "foo"]
 
 // Querying about the crate metadata should *not* parse the entire crate, it
 // only needs the crate attributes (which are guaranteed to be at the top) be
diff --git a/src/test/run-make/crate-data-smoke/lib.rs b/src/test/run-make/crate-data-smoke/lib.rs
index b40e055b3cb..639a5d0387b 100644
--- a/src/test/run-make/crate-data-smoke/lib.rs
+++ b/src/test/run-make/crate-data-smoke/lib.rs
@@ -8,5 +8,5 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![crate_id = "mylib"]
+#![crate_name = "mylib"]
 #![crate_type = "lib"]
diff --git a/src/test/run-make/crate-data-smoke/rlib.rs b/src/test/run-make/crate-data-smoke/rlib.rs
index 94b8371e537..4e093748600 100644
--- a/src/test/run-make/crate-data-smoke/rlib.rs
+++ b/src/test/run-make/crate-data-smoke/rlib.rs
@@ -8,5 +8,5 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![crate_id = "mylib"]
+#![crate_name = "mylib"]
 #![crate_type = "rlib"]
diff --git a/src/test/run-make/dep-info/lib.rs b/src/test/run-make/dep-info/lib.rs
index 4255b1d934d..7c15785bbb2 100644
--- a/src/test/run-make/dep-info/lib.rs
+++ b/src/test/run-make/dep-info/lib.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![crate_id="foo#0.1"]
+#![crate_name = "foo"]
 
 pub mod foo;
 pub mod bar;
diff --git a/src/test/run-make/extern-flag-disambiguates/Makefile b/src/test/run-make/extern-flag-disambiguates/Makefile
new file mode 100644
index 00000000000..9b86bf97549
--- /dev/null
+++ b/src/test/run-make/extern-flag-disambiguates/Makefile
@@ -0,0 +1,24 @@
+-include ../tools.mk
+
+# Attempt to build this dependency tree:
+#
+#	A.1   A.2
+#	 |\    |
+#	 | \   |
+#        B  \  C
+#         \ | /
+#          \|/
+#           D
+#
+# Note that A.1 and A.2 are crates with the same name.
+
+all:
+	$(RUSTC) -C metadata=1 -C extra-filename=-1 a.rs
+	$(RUSTC) -C metadata=2 -C extra-filename=-2 a.rs
+	$(RUSTC) b.rs --extern a=$(TMPDIR)/liba-1.rlib
+	$(RUSTC) c.rs --extern a=$(TMPDIR)/liba-2.rlib
+	$(RUSTC) --cfg before d.rs --extern a=$(TMPDIR)/liba-1.rlib
+	$(call RUN,d)
+	$(RUSTC) --cfg after  d.rs --extern a=$(TMPDIR)/liba-1.rlib
+	$(call RUN,d)
+
diff --git a/src/test/run-make/extern-flag-disambiguates/a.rs b/src/test/run-make/extern-flag-disambiguates/a.rs
new file mode 100644
index 00000000000..11b9ba6fce3
--- /dev/null
+++ b/src/test/run-make/extern-flag-disambiguates/a.rs
@@ -0,0 +1,16 @@
+// 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.
+
+#![crate_name = "a"]
+#![crate_type = "rlib"]
+
+static FOO: uint = 3;
+
+pub fn token() -> &'static uint { &FOO }
diff --git a/src/test/compile-fail/issue-11908-2.rs b/src/test/run-make/extern-flag-disambiguates/b.rs
index 8b916aad653..3156cf0ba72 100644
--- a/src/test/compile-fail/issue-11908-2.rs
+++ b/src/test/run-make/extern-flag-disambiguates/b.rs
@@ -8,14 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// aux-build:issue-11908-2.rs
-// no-prefer-dynamic
-// ignore-android this test is incompatible with the android test runner
-// error-pattern: multiple rlib candidates for `url` found
+#![crate_name = "b"]
+#![crate_type = "rlib"]
 
-// see comments in issue-11908-1 for what's going on here
+extern crate a;
 
-extern crate url;
-
-fn main() {}
+static FOO: uint = 3;
 
+pub fn token() -> &'static uint { &FOO }
+pub fn a_token() -> &'static uint { a::token() }
diff --git a/src/test/run-make/extern-flag-disambiguates/c.rs b/src/test/run-make/extern-flag-disambiguates/c.rs
new file mode 100644
index 00000000000..d3bbc762ef2
--- /dev/null
+++ b/src/test/run-make/extern-flag-disambiguates/c.rs
@@ -0,0 +1,19 @@
+// 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.
+
+#![crate_name = "c"]
+#![crate_type = "rlib"]
+
+extern crate a;
+
+static FOO: uint = 3;
+
+pub fn token() -> &'static uint { &FOO }
+pub fn a_token() -> &'static uint { a::token() }
diff --git a/src/test/run-pass/crateresolve8.rs b/src/test/run-make/extern-flag-disambiguates/d.rs
index f04e383cb3d..d850daffc39 100644
--- a/src/test/run-pass/crateresolve8.rs
+++ b/src/test/run-make/extern-flag-disambiguates/d.rs
@@ -1,4 +1,4 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,13 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// aux-build:crateresolve8-1.rs
+#[cfg(before)] extern crate a;
+extern crate b;
+extern crate c;
+#[cfg(after)] extern crate a;
 
-#![crate_id="crateresolve8#0.1"]
+fn t(a: &'static uint) -> uint { a as *const _ as uint }
 
-extern crate crateresolve8 = "crateresolve8#0.1";
-//extern crate crateresolve8(vers = "0.1");
-
-pub fn main() {
-    assert_eq!(crateresolve8::f(), 20);
+fn main() {
+    assert!(t(a::token()) == t(b::a_token()));
+    assert!(t(a::token()) != t(c::a_token()));
 }
diff --git a/src/test/run-make/extern-flag-fun/Makefile b/src/test/run-make/extern-flag-fun/Makefile
new file mode 100644
index 00000000000..ca5aa052a7b
--- /dev/null
+++ b/src/test/run-make/extern-flag-fun/Makefile
@@ -0,0 +1,16 @@
+-include ../tools.mk
+
+all:
+	$(RUSTC) bar.rs --crate-type=rlib
+	$(RUSTC) bar.rs --crate-type=rlib -C extra-filename=-a
+	$(RUSTC) foo.rs --extern hello && exit 1 || exit 0
+	$(RUSTC) foo.rs --extern bar=no-exist && exit 1 || exit 0
+	$(RUSTC) foo.rs --extern bar=foo.rs && exit 1 || exit 0
+	$(RUSTC) foo.rs \
+		--extern bar=$(TMPDIR)/libbar.rlib \
+		--extern bar=$(TMPDIR)/libbar-a.rlib \
+		&& exit 1 || exit 0
+	$(RUSTC) foo.rs \
+		--extern bar=$(TMPDIR)/libbar.rlib \
+		--extern bar=$(TMPDIR)/libbar.rlib
+	$(RUSTC) foo.rs --extern bar=$(TMPDIR)/libbar.rlib
diff --git a/src/test/run-make/extern-flag-fun/bar.rs b/src/test/run-make/extern-flag-fun/bar.rs
new file mode 100644
index 00000000000..2152aa79c33
--- /dev/null
+++ b/src/test/run-make/extern-flag-fun/bar.rs
@@ -0,0 +1,10 @@
+// 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.
+
diff --git a/src/test/auxiliary/issue-11908-1.rs b/src/test/run-make/extern-flag-fun/foo.rs
index 8a48e483029..52741668640 100644
--- a/src/test/auxiliary/issue-11908-1.rs
+++ b/src/test/run-make/extern-flag-fun/foo.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// no-prefer-dynamic
+extern crate bar;
 
-#![crate_id = "url#0.11.0"]
-#![crate_type = "dylib"]
+fn main() {}
diff --git a/src/test/run-make/issue-11908/Makefile b/src/test/run-make/issue-11908/Makefile
new file mode 100644
index 00000000000..663a9f7125e
--- /dev/null
+++ b/src/test/run-make/issue-11908/Makefile
@@ -0,0 +1,23 @@
+# This test ensures that if you have the same rlib or dylib at two locations
+# in the same path that you don't hit an assertion in the compiler.
+#
+# Note that this relies on `liburl` to be in the path somewhere else,
+# and then our aux-built libraries will collide with liburl (they have
+# the same version listed)
+
+-include ../tools.mk
+
+all:
+	mkdir $(TMPDIR)/other
+	$(RUSTC) foo.rs --crate-type=dylib
+	mv $(call DYLIB,foo) $(TMPDIR)/other
+	$(RUSTC) foo.rs --crate-type=dylib
+	$(RUSTC) bar.rs -L $(TMPDIR)/other 2>&1 | \
+		grep "multiple dylib candidates"
+	rm -rf $(TMPDIR)
+	mkdir -p $(TMPDIR)/other
+	$(RUSTC) foo.rs --crate-type=rlib
+	mv $(TMPDIR)/libfoo.rlib $(TMPDIR)/other
+	$(RUSTC) foo.rs --crate-type=rlib
+	$(RUSTC) bar.rs -L $(TMPDIR)/other 2>&1 | \
+		grep "multiple rlib candidates"
diff --git a/src/test/compile-fail/use-meta.rc b/src/test/run-make/issue-11908/bar.rs
index 9cb84c5400a..6316cfa3bba 100644
--- a/src/test/compile-fail/use-meta.rc
+++ b/src/test/run-make/issue-11908/bar.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,6 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern:can't find crate for `std`
+extern crate foo;
 
-extern crate std = "std#bogus";
+fn main() {}
diff --git a/src/test/run-make/issue-11908/foo.rs b/src/test/run-make/issue-11908/foo.rs
new file mode 100644
index 00000000000..0858d3c4e47
--- /dev/null
+++ b/src/test/run-make/issue-11908/foo.rs
@@ -0,0 +1,11 @@
+// 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.
+
+#![crate_name = "foo"]
diff --git a/src/test/run-make/lto-smoke-c/Makefile b/src/test/run-make/lto-smoke-c/Makefile
index 9b44c3e582a..6c7e9aa1d59 100644
--- a/src/test/run-make/lto-smoke-c/Makefile
+++ b/src/test/run-make/lto-smoke-c/Makefile
@@ -5,6 +5,5 @@ CC := $(CC:-g=)
 
 all:
 	$(RUSTC) foo.rs -Z lto
-	ln -s $(call STATICLIB,foo-*) $(call STATICLIB,foo)
 	$(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(EXTRACFLAGS) -lstdc++
 	$(call RUN,bar)
diff --git a/src/test/run-make/lto-syntax-extension/lib.rs b/src/test/run-make/lto-syntax-extension/lib.rs
index fbe967786e2..04d3ae67207 100644
--- a/src/test/run-make/lto-syntax-extension/lib.rs
+++ b/src/test/run-make/lto-syntax-extension/lib.rs
@@ -8,4 +8,4 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[crate_type = "rlib"];
+#![crate_type = "rlib"]
diff --git a/src/test/run-make/manual-crate-name/Makefile b/src/test/run-make/manual-crate-name/Makefile
new file mode 100644
index 00000000000..1d1419997a2
--- /dev/null
+++ b/src/test/run-make/manual-crate-name/Makefile
@@ -0,0 +1,5 @@
+-include ../tools.mk
+
+all:
+	$(RUSTC) --crate-name foo bar.rs
+	rm $(TMPDIR)/libfoo.rlib
diff --git a/src/test/auxiliary/issue-11908-2.rs b/src/test/run-make/manual-crate-name/bar.rs
index 0deece53451..04d3ae67207 100644
--- a/src/test/auxiliary/issue-11908-2.rs
+++ b/src/test/run-make/manual-crate-name/bar.rs
@@ -8,7 +8,4 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// no-prefer-dynamic
-
-#![crate_id = "url#0.11.0"]
 #![crate_type = "rlib"]
diff --git a/src/test/run-make/metadata-flag-frobs-symbols/Makefile b/src/test/run-make/metadata-flag-frobs-symbols/Makefile
new file mode 100644
index 00000000000..09e6ae0bbf7
--- /dev/null
+++ b/src/test/run-make/metadata-flag-frobs-symbols/Makefile
@@ -0,0 +1,10 @@
+-include ../tools.mk
+
+all:
+	$(RUSTC) foo.rs -C metadata=a -C extra-filename=-a
+	$(RUSTC) foo.rs -C metadata=b -C extra-filename=-b
+	$(RUSTC) bar.rs \
+		--extern foo1=$(TMPDIR)/libfoo-a.rlib \
+		--extern foo2=$(TMPDIR)/libfoo-b.rlib \
+		-Z print-link-args
+	$(call RUN,bar)
diff --git a/src/test/run-make/metadata-flag-frobs-symbols/bar.rs b/src/test/run-make/metadata-flag-frobs-symbols/bar.rs
new file mode 100644
index 00000000000..44b9e2f874a
--- /dev/null
+++ b/src/test/run-make/metadata-flag-frobs-symbols/bar.rs
@@ -0,0 +1,18 @@
+// 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.
+
+extern crate foo1;
+extern crate foo2;
+
+fn main() {
+    let a = foo1::foo();
+    let b = foo2::foo();
+    assert!(a as *const _ != b as *const _);
+}
diff --git a/src/test/run-make/metadata-flag-frobs-symbols/foo.rs b/src/test/run-make/metadata-flag-frobs-symbols/foo.rs
new file mode 100644
index 00000000000..ed04eed8cf7
--- /dev/null
+++ b/src/test/run-make/metadata-flag-frobs-symbols/foo.rs
@@ -0,0 +1,16 @@
+// 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.
+
+#![crate_name = "foo"]
+#![crate_type = "rlib"]
+
+static FOO: uint = 3;
+
+pub fn foo() -> &'static uint { &FOO }
diff --git a/src/test/run-make/multiple-versions/Makefile b/src/test/run-make/multiple-versions/Makefile
new file mode 100644
index 00000000000..e60c16ae0f6
--- /dev/null
+++ b/src/test/run-make/multiple-versions/Makefile
@@ -0,0 +1,9 @@
+-include ../tools.mk
+
+all:
+	$(RUSTC) foo.rs -C metadata=a -C extra-filename=-1 --crate-type=rlib
+	$(RUSTC) foo.rs -C metadata=b -C extra-filename=-2 --crate-type=rlib
+	$(RUSTC) bar.rs \
+		--extern foo1=$(TMPDIR)/libfoo-1.rlib \
+		--extern foo2=$(TMPDIR)/libfoo-2.rlib \
+		2>&1 | grep "using multiple versions of crate .foo."
diff --git a/src/test/auxiliary/crateresolve2-3.rs b/src/test/run-make/multiple-versions/bar.rs
index fe064b7e5e6..262193a0810 100644
--- a/src/test/auxiliary/crateresolve2-3.rs
+++ b/src/test/run-make/multiple-versions/bar.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,8 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![crate_id="crateresolve2#0.3"]
+extern crate foo1;
+extern crate foo2;
 
-#![crate_type = "lib"]
-
-pub fn f() -> int { 30 }
+fn main() {}
diff --git a/src/test/run-make/multiple-versions/foo.rs b/src/test/run-make/multiple-versions/foo.rs
new file mode 100644
index 00000000000..2661b1f4eb4
--- /dev/null
+++ b/src/test/run-make/multiple-versions/foo.rs
@@ -0,0 +1,11 @@
+// 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.
+
+pub fn foo() {}
diff --git a/src/test/run-make/output-type-permutations/foo.rs b/src/test/run-make/output-type-permutations/foo.rs
index 020fbc3299b..bb5796bd873 100644
--- a/src/test/run-make/output-type-permutations/foo.rs
+++ b/src/test/run-make/output-type-permutations/foo.rs
@@ -8,6 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![crate_id = "bar"]
+#![crate_name = "bar"]
 
 fn main() {}
diff --git a/src/test/run-make/weird-output-filenames/Makefile b/src/test/run-make/weird-output-filenames/Makefile
index debd89d9929..5d6e629ffc1 100644
--- a/src/test/run-make/weird-output-filenames/Makefile
+++ b/src/test/run-make/weird-output-filenames/Makefile
@@ -1,9 +1,12 @@
 -include ../tools.mk
 
 all:
-	$(RUSTC) foo.rs -o $(TMPDIR)/.foo
-	rm $(TMPDIR)/.foo
-	$(RUSTC) foo.rs -o $(TMPDIR)/.foo.bar
-	rm $(TMPDIR)/.foo.bar
-	$(RUSTC) foo.rs -o $(TMPDIR)/+foo+bar
-	rm $(TMPDIR)/$(call BIN,+foo+bar)
+	cp foo.rs $(TMPDIR)/.foo.rs
+	$(RUSTC) $(TMPDIR)/.foo.rs 2>&1 \
+		| grep "invalid character.*in crate name:"
+	cp foo.rs $(TMPDIR)/.foo.bar
+	$(RUSTC) $(TMPDIR)/.foo.bar 2>&1 \
+		| grep "invalid character.*in crate name:"
+	cp foo.rs $(TMPDIR)/+foo+bar
+	$(RUSTC) $(TMPDIR)/+foo+bar 2>&1 \
+		| grep "invalid character.*in crate name:"
diff --git a/src/test/run-pass/crateresolve1.rs b/src/test/run-pass/crateresolve1.rs
deleted file mode 100644
index 61e269bf9e3..00000000000
--- a/src/test/run-pass/crateresolve1.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2012-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.
-
-// aux-build:crateresolve1-1.rs
-// aux-build:crateresolve1-2.rs
-// aux-build:crateresolve1-3.rs
-
-extern crate crateresolve1 = "crateresolve1#0.2";
-
-pub fn main() {
-    assert_eq!(crateresolve1::f(), 20);
-}
diff --git a/src/test/run-pass/crateresolve2.rs b/src/test/run-pass/crateresolve2.rs
deleted file mode 100644
index 5ed1f37c7b9..00000000000
--- a/src/test/run-pass/crateresolve2.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2012-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.
-
-// aux-build:crateresolve2-1.rs
-// aux-build:crateresolve2-2.rs
-// aux-build:crateresolve2-3.rs
-
-mod a {
-    extern crate crateresolve2 = "crateresolve2#0.1";
-    pub fn f() { assert!(crateresolve2::f() == 10); }
-}
-
-mod b {
-    extern crate crateresolve2 = "crateresolve2#0.2";
-    pub fn f() { assert!(crateresolve2::f() == 20); }
-}
-
-mod c {
-    extern crate crateresolve2 = "crateresolve2#0.3";
-    pub fn f() { assert!(crateresolve2::f() == 30); }
-}
-
-pub fn main() {
-    a::f();
-    b::f();
-    c::f();
-}
diff --git a/src/test/run-pass/crateresolve3.rs b/src/test/run-pass/crateresolve3.rs
deleted file mode 100644
index cee9e6991c4..00000000000
--- a/src/test/run-pass/crateresolve3.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2012-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.
-
-// aux-build:crateresolve3-1.rs
-// aux-build:crateresolve3-2.rs
-
-// verify able to link with crates with same name but different versions
-// as long as no name collision on invoked functions.
-
-mod a {
-    extern crate crateresolve3 = "crateresolve3#0.1";
-    pub fn f() { assert!(crateresolve3::f() == 10); }
-}
-
-mod b {
-    extern crate crateresolve3 = "crateresolve3#0.2";
-    pub fn f() { assert!(crateresolve3::g() == 20); }
-}
-
-pub fn main() {
-    a::f();
-    b::f();
-}
diff --git a/src/test/run-pass/crateresolve4.rs b/src/test/run-pass/crateresolve4.rs
deleted file mode 100644
index c6896152226..00000000000
--- a/src/test/run-pass/crateresolve4.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2012-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.
-
-// aux-build:crateresolve4a-1.rs
-// aux-build:crateresolve4a-2.rs
-// aux-build:crateresolve4b-1.rs
-// aux-build:crateresolve4b-2.rs
-
-pub mod a {
-    extern crate crateresolve4b = "crateresolve4b#0.1";
-    pub fn f() { assert!(crateresolve4b::f() == 20); }
-}
-
-pub mod b {
-    extern crate crateresolve4b = "crateresolve4b#0.2";
-    pub fn f() { assert!(crateresolve4b::g() == 10); }
-}
-
-pub fn main() {
-    a::f();
-    b::f();
-}
diff --git a/src/test/run-pass/crateresolve5.rs b/src/test/run-pass/crateresolve5.rs
deleted file mode 100644
index 3f74731090b..00000000000
--- a/src/test/run-pass/crateresolve5.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2012-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.
-
-// aux-build:crateresolve5-1.rs
-// aux-build:crateresolve5-2.rs
-
-extern crate cr5_1 = "crateresolve5#0.1";
-extern crate cr5_2 = "crateresolve5#0.2";
-
-pub fn main() {
-    // Structural types can be used between two versions of the same crate
-    assert!(cr5_1::struct_nameval().name == cr5_2::struct_nameval().name);
-    assert!(cr5_1::struct_nameval().val == cr5_2::struct_nameval().val);
-    // Make sure these are actually two different crates
-    assert!(cr5_1::f() == 10 && cr5_2::f() == 20);
-}
diff --git a/src/test/run-pass/extern-crosscrate.rs b/src/test/run-pass/extern-crosscrate.rs
index 3faf5744199..5dc25c85325 100644
--- a/src/test/run-pass/extern-crosscrate.rs
+++ b/src/test/run-pass/extern-crosscrate.rs
@@ -10,7 +10,7 @@
 
 //aux-build:extern-crosscrate-source.rs
 
-extern crate externcallback = "externcallback#0.1";
+extern crate externcallback;
 
 fn fact(n: uint) -> uint {
     unsafe {
diff --git a/src/test/run-pass/use.rs b/src/test/run-pass/use.rs
index 3f152cc1061..dfed3916405 100644
--- a/src/test/run-pass/use.rs
+++ b/src/test/run-pass/use.rs
@@ -15,13 +15,11 @@
 #![no_std]
 extern crate std;
 extern crate zed = "std";
-extern crate bar = "std#0.11.0";
 
 
 use std::str;
 use x = zed::str;
 mod baz {
-    pub use bar::str;
     pub use x = std::str;
 }