diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs
index 202b963bd60..d21969476a7 100644
--- a/src/comp/back/link.rs
+++ b/src/comp/back/link.rs
@@ -279,7 +279,7 @@ mod write {
  */
 
 
-iter crate_export_metas(ast::crate c) -> @ast::meta_item {
+iter crate_export_metas(&ast::crate c) -> @ast::meta_item {
     for (@ast::crate_directive cdir in c.node.directives) {
         alt (cdir.node) {
             case (ast::cdir_meta(?v, ?mis)) {
@@ -293,12 +293,30 @@ iter crate_export_metas(ast::crate c) -> @ast::meta_item {
         }
     }
 }
-fn get_crate_meta(&session::session sess,
-                  &ast::crate c, str k, str default,
-                  bool warn_default) -> str {
+
+
+iter crate_local_metas(&ast::crate c) -> @ast::meta_item {
+    for (@ast::crate_directive cdir in c.node.directives) {
+        alt (cdir.node) {
+            case (ast::cdir_meta(?v, ?mis)) {
+                if (v == ast::local_meta) {
+                    for (@ast::meta_item mi in mis) {
+                        put mi;
+                    }
+                }
+            }
+            case (_) {}
+        }
+    }
+}
+
+
+fn get_crate_meta_export(&session::session sess,
+                         &ast::crate c, str k, str default,
+                         bool warn_default) -> str {
     let vec[@ast::meta_item] v = [];
     for each (@ast::meta_item mi in crate_export_metas(c)) {
-        if (mi.node.name == k) {
+        if (mi.node.key == k) {
             v += [mi];
         }
     }
@@ -323,7 +341,7 @@ fn get_crate_meta(&session::session sess,
 fn crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str {
     fn lteq(&@ast::meta_item ma,
             &@ast::meta_item mb) -> bool {
-        ret ma.node.name <= mb.node.name;
+        ret ma.node.key <= mb.node.key;
     }
 
     fn len_and_str(&str s) -> str {
@@ -332,8 +350,8 @@ fn crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str {
 
     let vec[mutable @ast::meta_item] v = [mutable];
     for each (@ast::meta_item mi in crate_export_metas(crate)) {
-        if (mi.node.name != "name" &&
-            mi.node.name != "vers") {
+        if (mi.node.key != "name" &&
+            mi.node.key != "vers") {
             v += [mutable mi];
         }
     }
@@ -341,7 +359,7 @@ fn crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str {
     sha.reset();
     for (@ast::meta_item m_ in v) {
         auto m = m_;
-        sha.input_str(len_and_str(m.node.name));
+        sha.input_str(len_and_str(m.node.key));
         sha.input_str(len_and_str(m.node.value));
     }
     ret truncated_sha1_result(sha);
@@ -352,13 +370,13 @@ fn crate_meta_name(&session::session sess, &ast::crate crate,
     auto os = str::split(fs::basename(output), '.' as u8);
     assert vec::len(os) >= 2u;
     vec::pop(os);
-    ret get_crate_meta(sess, crate, "name", str::connect(os, "."),
-                       sess.get_opts().shared);
+    ret get_crate_meta_export(sess, crate, "name", str::connect(os, "."),
+                              sess.get_opts().shared);
 }
 
 fn crate_meta_vers(&session::session sess, &ast::crate crate) -> str {
-    ret get_crate_meta(sess, crate, "vers", "0.0",
-                       sess.get_opts().shared);
+    ret get_crate_meta_export(sess, crate, "vers", "0.0",
+                              sess.get_opts().shared);
 }
 
 fn truncated_sha1_result(sha1 sha) -> str {
diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs
index b36a956464c..fd0fd7f0193 100644
--- a/src/comp/front/ast.rs
+++ b/src/comp/front/ast.rs
@@ -97,7 +97,7 @@ type crate_directive = spanned[crate_directive_];
 
 
 type meta_item = spanned[meta_item_];
-type meta_item_ = rec(ident name, str value);
+type meta_item_ = rec(ident key, str value);
 
 type block = spanned[block_];
 type block_ = rec(vec[@stmt] stmts,
diff --git a/src/comp/front/creader.rs b/src/comp/front/creader.rs
index e0be9606384..d9dad04db92 100644
--- a/src/comp/front/creader.rs
+++ b/src/comp/front/creader.rs
@@ -500,24 +500,75 @@ fn get_metadata_section(str filename) -> option::t[vec[u8]] {
 }
 
 
-fn load_crate(session::session sess,
-              int cnum,
-              ast::ident ident,
-              vec[str] library_search_paths) {
-    auto filename = parser::default_native_name(sess, ident);
-    for (str library_search_path in library_search_paths) {
-        auto path = fs::connect(library_search_path, filename);
-        alt (get_metadata_section(path)) {
-            case (option::some(?cvec)) {
-                sess.set_external_crate(cnum, rec(name=ident, data=cvec));
-                ret;
-            }
-            case (_) {}
+fn metadata_matches(&vec[u8] data,
+                    &vec[@ast::meta_item] metas) -> bool {
+    ret true;
+}
+
+fn find_library_crate(&session::session sess,
+                      &ast::ident ident,
+                      &vec[@ast::meta_item] metas,
+                      &vec[str] library_search_paths)
+    -> option::t[tup(str, vec[u8])] {
+
+    let str crate_name = ident;
+    for (@ast::meta_item mi in metas) {
+        if (mi.node.key == "name") {
+            crate_name = mi.node.value;
+            break;
         }
     }
+    auto nn = parser::default_native_lib_naming(sess);
+    let str prefix = nn.prefix + crate_name;
 
-    log_err #fmt("can't open crate '%s' (looked for '%s' in lib search path)",
-                 ident, filename);
+    // FIXME: we could probably use a 'glob' function in std::fs but it will
+    // be much easier to write once the unsafe module knows more about FFI
+    // tricks. Currently the glob(3) interface is a bit more than we can
+    // stomach from here, and writing a C++ wrapper is more work than just
+    // manually filtering fs::list_dir here.
+
+    for (str library_search_path in library_search_paths) {
+
+        for (str path in fs::list_dir(library_search_path)) {
+
+            let str f = fs::basename(path);
+            if (! (str::starts_with(f, prefix) &&
+                   str::ends_with(f, nn.suffix))) {
+                log #fmt("skipping %s, doesn't look like %s*%s",
+                         path, prefix, nn.suffix);
+                cont;
+            }
+
+            alt (get_metadata_section(path)) {
+                case (option::some(?cvec)) {
+                    if (!metadata_matches(cvec, metas)) {
+                        log #fmt("skipping %s, metadata doesn't match", path);
+                        cont;
+                    }
+                    log #fmt("found %s with matching metadata", path);
+                    ret some(tup(path, cvec));
+                }
+                case (_) {}
+            }
+        }
+    }
+    ret none;
+}
+
+fn load_library_crate(&session::session sess,
+                      &int cnum,
+                      &ast::ident ident,
+                      &vec[@ast::meta_item] metas,
+                      &vec[str] library_search_paths) {
+    alt (find_library_crate(sess, ident, metas, library_search_paths)) {
+        case (some(?t)) {
+            sess.set_external_crate(cnum, rec(name=ident,
+                                              data=t._1));
+            ret;
+        }
+        case (_) {}
+    }
+    log_err #fmt("can't find crate for '%s'", ident);
     fail;
 }
 
@@ -535,8 +586,8 @@ fn visit_view_item(env e, &@ast::view_item i) {
             auto cnum;
             if (!e.crate_cache.contains_key(ident)) {
                 cnum = e.next_crate_num;
-                load_crate(e.sess, cnum, ident,
-                           e.library_search_paths);
+                load_library_crate(e.sess, cnum, ident, meta_items,
+                                   e.library_search_paths);
                 e.crate_cache.insert(ident, e.next_crate_num);
                 e.next_crate_num += 1;
             } else {
diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs
index d3a8fa9a329..666df9d8eb3 100644
--- a/src/comp/front/parser.rs
+++ b/src/comp/front/parser.rs
@@ -1992,20 +1992,26 @@ fn parse_native_mod_items(&parser p, &str native_name,
             items=items);
 }
 
-fn default_native_name(session::session sess, str id) -> str {
+fn default_native_lib_naming(session::session sess)
+    -> rec(str prefix, str suffix) {
     alt (sess.get_targ_cfg().os) {
         case (session::os_win32) {
-            ret id + ".dll";
+            ret rec(prefix="", suffix=".dll");
         }
         case (session::os_macos) {
-            ret "lib" + id + ".dylib";
+            ret rec(prefix="lib", suffix=".dylib");
         }
         case (session::os_linux) {
-            ret "lib" + id + ".so";
+            ret rec(prefix="lib", suffix=".so");
         }
     }
 }
 
+fn default_native_name(session::session sess, str id) -> str {
+    auto n = default_native_lib_naming(sess);
+    ret n.prefix + id + n.suffix;
+}
+
 fn parse_item_native_mod(&parser p) -> @ast::item {
     auto lo = p.get_last_lo_pos();
     auto abi = ast::native_abi_cdecl;
@@ -2194,7 +2200,7 @@ fn parse_meta_item(&parser p) -> @ast::meta_item {
         case (token::LIT_STR(?s)) {
             auto hi = p.get_hi_pos();
             p.bump();
-            ret @spanned(lo, hi, rec(name = ident,
+            ret @spanned(lo, hi, rec(key = ident,
                                      value = p.get_str(s)));
         }
         case (_) {
diff --git a/src/comp/middle/metadata.rs b/src/comp/middle/metadata.rs
index 8322de5bc90..b6ce15a8ba8 100644
--- a/src/comp/middle/metadata.rs
+++ b/src/comp/middle/metadata.rs
@@ -14,6 +14,7 @@ import middle::trans;
 import middle::ty;
 import middle::ty::path_to_str;
 import back::x86;
+import back::link;
 import util::common;
 import pretty::ppaux::lit_to_str;
 
@@ -46,6 +47,12 @@ const uint tag_index_buckets_bucket = 0x13u;
 const uint tag_index_buckets_bucket_elt = 0x14u;
 const uint tag_index_table = 0x15u;
 
+const uint tag_meta_export = 0x16u;
+const uint tag_meta_local = 0x17u;
+const uint tag_meta_item = 0x18u;
+const uint tag_meta_item_key = 0x19u;
+const uint tag_meta_item_value = 0x20u;
+
 // Type encoding
 
 // Compact string representation for ty.t values. API ty_str & parse_from_str.
@@ -709,12 +716,41 @@ fn write_int(&io::writer writer, &int n) {
 }
 
 
+fn encode_meta_items(&ebml::writer ebml_w, &ast::crate crate) {
+
+    fn encode_meta_item(&ebml::writer ebml_w, &ast::meta_item mi) {
+        ebml::start_tag(ebml_w, tag_meta_item);
+        ebml::start_tag(ebml_w, tag_meta_item_key);
+        ebml_w.writer.write(str::bytes(mi.node.key));
+        ebml::end_tag(ebml_w);
+        ebml::start_tag(ebml_w, tag_meta_item_value);
+        ebml_w.writer.write(str::bytes(mi.node.value));
+        ebml::end_tag(ebml_w);
+        ebml::end_tag(ebml_w);
+    }
+
+    ebml::start_tag(ebml_w, tag_meta_export);
+    for each (@ast::meta_item mi in link::crate_export_metas(crate)) {
+        encode_meta_item(ebml_w, *mi);
+    }
+    ebml::end_tag(ebml_w);
+
+    ebml::start_tag(ebml_w, tag_meta_local);
+    for each (@ast::meta_item mi in link::crate_local_metas(crate)) {
+        encode_meta_item(ebml_w, *mi);
+    }
+    ebml::end_tag(ebml_w);
+}
+
 fn encode_metadata(&@trans::crate_ctxt cx, &@ast::crate crate)
         -> ValueRef {
     auto string_w = io::string_writer();
     auto buf_w = string_w.get_writer().get_buf_writer();
     auto ebml_w = ebml::create_writer(buf_w);
 
+    // Encode the meta items
+    encode_meta_items(ebml_w, *crate);
+
     // Encode and index the paths.
     ebml::start_tag(ebml_w, tag_paths);
     auto paths_index = encode_item_paths(ebml_w, crate);
diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs
index 20fe17c48c0..a7cbffeca6b 100644
--- a/src/comp/pretty/pprust.rs
+++ b/src/comp/pretty/pprust.rs
@@ -1000,7 +1000,7 @@ fn print_view_item(&ps s, &@ast::view_item item) {
                 popen(s);
                 fn print_meta(&ps s, &@ast::meta_item item) {
                     ibox(s, indent_unit);
-                    word_space(s, item.node.name);
+                    word_space(s, item.node.key);
                     word_space(s, "=");
                     print_string(s, item.node.value);
                     end(s);