From 0e21a05e6c0bc0bfa905291a916b38bdb9daf90d Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 15 May 2012 20:23:06 -0700 Subject: [PATCH] rustc: Extract loader mod from creader mod loader is a utility for locating crates and loading their metadata. creader is a compiler pass that loads metadata for all used libraries. --- src/rustc/driver/driver.rs | 2 +- src/rustc/metadata/creader.rs | 209 ++-------------------------------- src/rustc/metadata/loader.rs | 209 ++++++++++++++++++++++++++++++++++ src/rustc/rustc.rc | 2 + 4 files changed, 222 insertions(+), 200 deletions(-) create mode 100644 src/rustc/metadata/loader.rs diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index 6b76edbb5c7..a0a630bb10b 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -672,7 +672,7 @@ fn early_error(emitter: diagnostic::emitter, msg: str) -> ! { } fn list_metadata(sess: session, path: str, out: io::writer) { - metadata::creader::list_file_metadata(sess, path, out); + metadata::loader::list_file_metadata(sess, path, out); } #[cfg(test)] diff --git a/src/rustc/metadata/creader.rs b/src/rustc/metadata/creader.rs index bae50d13d17..2cc3f1a5a4a 100644 --- a/src/rustc/metadata/creader.rs +++ b/src/rustc/metadata/creader.rs @@ -1,20 +1,20 @@ -// Extracting metadata from crate files +#[doc = " + +Validates all used crates and native libraries and loads their metadata + +"]; import driver::session; import session::session; import syntax::{ast, ast_util}; -import lib::llvm::{False, llvm, mk_object_file, mk_section_iter}; import syntax::attr; import syntax::visit; import syntax::codemap::span; -import util::{filesearch}; -import io::writer_util; import std::map::{hashmap, int_hash}; import syntax::print::pprust; import common::*; export read_crates; -export list_file_metadata; // Traverses an AST, reading all the information about use'd crates and native // libraries necessary for later resolving, typechecking, linking, etc. @@ -59,10 +59,10 @@ fn warn_if_multiple_versions(sess: session::session, import either::*; if crate_cache.is_not_empty() { - let name = crate_name_from_metas(*crate_cache.last().metas); + let name = loader::crate_name_from_metas(*crate_cache.last().metas); let {lefts: matches, rights: non_matches} = partition(crate_cache.map {|entry| - let othername = crate_name_from_metas(*entry.metas); + let othername = loader::crate_name_from_metas(*entry.metas); if name == othername { left(entry) } else { @@ -79,7 +79,7 @@ fn warn_if_multiple_versions(sess: session::session, let attrs = [ attr::mk_attr(attr::mk_list_item("link", *match.metas)) ]; - note_linkage_attrs(sess, attrs); + loader::note_linkage_attrs(sess, attrs); } } @@ -148,195 +148,6 @@ fn visit_item(e: env, i: @ast::item) { } } -// A diagnostic function for dumping crate metadata to an output stream -fn list_file_metadata(sess: session::session, path: str, out: io::writer) { - alt get_metadata_section(sess, path) { - option::some(bytes) { decoder::list_crate_metadata(bytes, out); } - option::none { - out.write_str("could not find metadata in " + path + ".\n"); - } - } -} - -fn crate_matches(crate_data: @[u8], metas: [@ast::meta_item], hash: str) -> - bool { - let attrs = decoder::get_crate_attributes(crate_data); - let linkage_metas = attr::find_linkage_metas(attrs); - if hash.is_not_empty() { - let chash = decoder::get_crate_hash(crate_data); - if chash != hash { ret false; } - } - metadata_matches(linkage_metas, metas) -} - -fn metadata_matches(extern_metas: [@ast::meta_item], - local_metas: [@ast::meta_item]) -> bool { - - #debug("matching %u metadata requirements against %u items", - vec::len(local_metas), vec::len(extern_metas)); - - #debug("crate metadata:"); - for extern_metas.each {|have| - #debug(" %s", pprust::meta_item_to_str(*have)); - } - - for local_metas.each {|needed| - #debug("looking for %s", pprust::meta_item_to_str(*needed)); - if !attr::contains(extern_metas, needed) { - #debug("missing %s", pprust::meta_item_to_str(*needed)); - ret false; - } - } - ret true; -} - -fn default_native_lib_naming(sess: session::session, static: bool) -> - {prefix: str, suffix: str} { - if static { ret {prefix: "lib", suffix: ".rlib"}; } - alt sess.targ_cfg.os { - session::os_win32 { ret {prefix: "", suffix: ".dll"}; } - session::os_macos { ret {prefix: "lib", suffix: ".dylib"}; } - session::os_linux { ret {prefix: "lib", suffix: ".so"}; } - session::os_freebsd { ret {prefix: "lib", suffix: ".so"}; } - } -} - -fn crate_name_from_metas(metas: [@ast::meta_item]) -> str { - let name_items = attr::find_meta_items_by_name(metas, "name"); - alt vec::last_opt(name_items) { - some(i) { - alt attr::get_meta_item_value_str(i) { - some(n) { n } - // FIXME: Probably want a warning here since the user - // is using the wrong type of meta item - _ { fail } - } - } - none { fail "expected to find the crate name" } - } -} - -fn find_library_crate(sess: session::session, span: span, - metas: [@ast::meta_item], hash: str) - -> option<{ident: str, data: @[u8]}> { - - attr::require_unique_names(sess.diagnostic(), metas); - let metas = metas; - - let nn = default_native_lib_naming(sess, sess.opts.static); - let x = - find_library_crate_aux(sess, span, nn, - metas, hash, sess.filesearch); - if x != none || sess.opts.static { ret x; } - let nn2 = default_native_lib_naming(sess, true); - ret find_library_crate_aux(sess, span, nn2, metas, hash, - sess.filesearch); -} - -fn find_library_crate_aux(sess: session::session, - span: span, - nn: {prefix: str, suffix: str}, - metas: [@ast::meta_item], - hash: str, - filesearch: filesearch::filesearch) -> - option<{ident: str, data: @[u8]}> { - let crate_name = crate_name_from_metas(metas); - let prefix: str = nn.prefix + crate_name + "-"; - let suffix: str = nn.suffix; - - let mut matches = []; - filesearch::search(filesearch, { |path| - #debug("inspecting file %s", path); - let f: str = path::basename(path); - if !(str::starts_with(f, prefix) && str::ends_with(f, suffix)) { - #debug("skipping %s, doesn't look like %s*%s", path, prefix, - suffix); - option::none::<()> - } else { - #debug("%s is a candidate", path); - alt get_metadata_section(sess, path) { - option::some(cvec) { - if !crate_matches(cvec, metas, hash) { - #debug("skipping %s, metadata doesn't match", path); - option::none::<()> - } else { - #debug("found %s with matching metadata", path); - matches += [{ident: path, data: cvec}]; - option::none::<()> - } - } - _ { - #debug("could not load metadata for %s", path); - option::none::<()> - } - } - } - }); - - if matches.is_empty() { - none - } else if matches.len() == 1u { - some(matches[0]) - } else { - sess.span_err( - span, #fmt("multiple matching crates for `%s`", crate_name)); - sess.note("candidates:"); - for matches.each {|match| - sess.note(#fmt("path: %s", match.ident)); - let attrs = decoder::get_crate_attributes(match.data); - note_linkage_attrs(sess, attrs); - } - sess.abort_if_errors(); - none - } -} - -fn note_linkage_attrs(sess: session::session, attrs: [ast::attribute]) { - for attr::find_linkage_attrs(attrs).each {|attr| - sess.note(#fmt("meta: %s", pprust::attr_to_str(attr))); - } -} - -fn get_metadata_section(sess: session::session, - filename: str) -> option<@[u8]> unsafe { - let mb = str::as_c_str(filename, {|buf| - llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf) - }); - if mb as int == 0 { ret option::none::<@[u8]>; } - let of = alt mk_object_file(mb) { - option::some(of) { of } - _ { ret option::none::<@[u8]>; } - }; - let si = mk_section_iter(of.llof); - while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { - let name_buf = llvm::LLVMGetSectionName(si.llsi); - let name = unsafe { str::unsafe::from_c_str(name_buf) }; - if str::eq(name, sess.targ_cfg.target_strs.meta_sect_name) { - let cbuf = llvm::LLVMGetSectionContents(si.llsi); - let csz = llvm::LLVMGetSectionSize(si.llsi) as uint; - unsafe { - let cvbuf: *u8 = unsafe::reinterpret_cast(cbuf); - ret some(@vec::unsafe::from_buf(cvbuf, csz)); - } - } - llvm::LLVMMoveToNextSection(si.llsi); - } - ret option::none::<@[u8]>; -} - -fn load_library_crate(sess: session::session, ident: ast::ident, span: span, - metas: [@ast::meta_item], hash: str) - -> {ident: str, data: @[u8]} { - - - alt find_library_crate(sess, span, metas, hash) { - some(t) { ret t; } - none { - sess.span_fatal(span, #fmt["can't find crate for '%s'", ident]); - } - } -} - fn metas_with(ident: ast::ident, key: str, metas: [@ast::meta_item]) -> [@ast::meta_item] { let name_items = attr::find_meta_items_by_name(metas, key); @@ -355,7 +166,7 @@ fn metas_with_ident(ident: ast::ident, fn existing_match(e: env, metas: [@ast::meta_item], hash: str) -> option { let maybe_entry = e.crate_cache.find {|c| - metadata_matches(*c.metas, metas) && + loader::metadata_matches(*c.metas, metas) && (hash.is_empty() || c.hash == hash) }; @@ -369,7 +180,7 @@ fn resolve_crate(e: env, ident: ast::ident, metas: [@ast::meta_item], alt existing_match(e, metas, hash) { none { let cinfo = - load_library_crate(e.sess, ident, span, metas, hash); + loader::load_library_crate(e.sess, ident, span, metas, hash); let cfilename = cinfo.ident; let cdata = cinfo.data; diff --git a/src/rustc/metadata/loader.rs b/src/rustc/metadata/loader.rs new file mode 100644 index 00000000000..4ef60c4a8cc --- /dev/null +++ b/src/rustc/metadata/loader.rs @@ -0,0 +1,209 @@ +#[doc = " + +Finds crate binaries and loads their metadata + +"]; + +import driver::session; +import session::session; +import syntax::{ast, attr}; +import syntax::print::pprust; +import syntax::codemap::span; +import lib::llvm::{False, llvm, mk_object_file, mk_section_iter}; +import util::{filesearch}; +import io::writer_util; + +export load_library_crate; +export list_file_metadata; +export note_linkage_attrs; +export crate_name_from_metas; +export metadata_matches; + +fn load_library_crate(sess: session::session, ident: ast::ident, span: span, + metas: [@ast::meta_item], hash: str) + -> {ident: str, data: @[u8]} { + + + alt find_library_crate(sess, span, metas, hash) { + some(t) { ret t; } + none { + sess.span_fatal(span, #fmt["can't find crate for '%s'", ident]); + } + } +} + +fn find_library_crate(sess: session::session, span: span, + metas: [@ast::meta_item], hash: str) + -> option<{ident: str, data: @[u8]}> { + + attr::require_unique_names(sess.diagnostic(), metas); + let metas = metas; + + let nn = default_native_lib_naming(sess, sess.opts.static); + let x = + find_library_crate_aux(sess, span, nn, + metas, hash, sess.filesearch); + if x != none || sess.opts.static { ret x; } + let nn2 = default_native_lib_naming(sess, true); + ret find_library_crate_aux(sess, span, nn2, metas, hash, + sess.filesearch); +} + +fn default_native_lib_naming(sess: session::session, static: bool) -> + {prefix: str, suffix: str} { + if static { ret {prefix: "lib", suffix: ".rlib"}; } + alt sess.targ_cfg.os { + session::os_win32 { ret {prefix: "", suffix: ".dll"}; } + session::os_macos { ret {prefix: "lib", suffix: ".dylib"}; } + session::os_linux { ret {prefix: "lib", suffix: ".so"}; } + session::os_freebsd { ret {prefix: "lib", suffix: ".so"}; } + } +} + +fn find_library_crate_aux(sess: session::session, + span: span, + nn: {prefix: str, suffix: str}, + metas: [@ast::meta_item], + hash: str, + filesearch: filesearch::filesearch) -> + option<{ident: str, data: @[u8]}> { + let crate_name = crate_name_from_metas(metas); + let prefix: str = nn.prefix + crate_name + "-"; + let suffix: str = nn.suffix; + + let mut matches = []; + filesearch::search(filesearch, { |path| + #debug("inspecting file %s", path); + let f: str = path::basename(path); + if !(str::starts_with(f, prefix) && str::ends_with(f, suffix)) { + #debug("skipping %s, doesn't look like %s*%s", path, prefix, + suffix); + option::none::<()> + } else { + #debug("%s is a candidate", path); + alt get_metadata_section(sess, path) { + option::some(cvec) { + if !crate_matches(cvec, metas, hash) { + #debug("skipping %s, metadata doesn't match", path); + option::none::<()> + } else { + #debug("found %s with matching metadata", path); + matches += [{ident: path, data: cvec}]; + option::none::<()> + } + } + _ { + #debug("could not load metadata for %s", path); + option::none::<()> + } + } + } + }); + + if matches.is_empty() { + none + } else if matches.len() == 1u { + some(matches[0]) + } else { + sess.span_err( + span, #fmt("multiple matching crates for `%s`", crate_name)); + sess.note("candidates:"); + for matches.each {|match| + sess.note(#fmt("path: %s", match.ident)); + let attrs = decoder::get_crate_attributes(match.data); + note_linkage_attrs(sess, attrs); + } + sess.abort_if_errors(); + none + } +} + +fn crate_name_from_metas(metas: [@ast::meta_item]) -> str { + let name_items = attr::find_meta_items_by_name(metas, "name"); + alt vec::last_opt(name_items) { + some(i) { + alt attr::get_meta_item_value_str(i) { + some(n) { n } + // FIXME: Probably want a warning here since the user + // is using the wrong type of meta item + _ { fail } + } + } + none { fail "expected to find the crate name" } + } +} + +fn note_linkage_attrs(sess: session::session, attrs: [ast::attribute]) { + for attr::find_linkage_attrs(attrs).each {|attr| + sess.note(#fmt("meta: %s", pprust::attr_to_str(attr))); + } +} + +fn crate_matches(crate_data: @[u8], metas: [@ast::meta_item], hash: str) -> + bool { + let attrs = decoder::get_crate_attributes(crate_data); + let linkage_metas = attr::find_linkage_metas(attrs); + if hash.is_not_empty() { + let chash = decoder::get_crate_hash(crate_data); + if chash != hash { ret false; } + } + metadata_matches(linkage_metas, metas) +} + +fn metadata_matches(extern_metas: [@ast::meta_item], + local_metas: [@ast::meta_item]) -> bool { + + #debug("matching %u metadata requirements against %u items", + vec::len(local_metas), vec::len(extern_metas)); + + #debug("crate metadata:"); + for extern_metas.each {|have| + #debug(" %s", pprust::meta_item_to_str(*have)); + } + + for local_metas.each {|needed| + #debug("looking for %s", pprust::meta_item_to_str(*needed)); + if !attr::contains(extern_metas, needed) { + #debug("missing %s", pprust::meta_item_to_str(*needed)); + ret false; + } + } + ret true; +} + +fn get_metadata_section(sess: session::session, + filename: str) -> option<@[u8]> unsafe { + let mb = str::as_c_str(filename, {|buf| + llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf) + }); + if mb as int == 0 { ret option::none::<@[u8]>; } + let of = alt mk_object_file(mb) { + option::some(of) { of } + _ { ret option::none::<@[u8]>; } + }; + let si = mk_section_iter(of.llof); + while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { + let name_buf = llvm::LLVMGetSectionName(si.llsi); + let name = unsafe { str::unsafe::from_c_str(name_buf) }; + if str::eq(name, sess.targ_cfg.target_strs.meta_sect_name) { + let cbuf = llvm::LLVMGetSectionContents(si.llsi); + let csz = llvm::LLVMGetSectionSize(si.llsi) as uint; + unsafe { + let cvbuf: *u8 = unsafe::reinterpret_cast(cbuf); + ret some(@vec::unsafe::from_buf(cvbuf, csz)); + } + } + llvm::LLVMMoveToNextSection(si.llsi); + } + ret option::none::<@[u8]>; +} + +// A diagnostic function for dumping crate metadata to an output stream +fn list_file_metadata(sess: session::session, path: str, out: io::writer) { + alt get_metadata_section(sess, path) { + option::some(bytes) { decoder::list_crate_metadata(bytes, out); } + option::none { + out.write_str("could not find metadata in " + path + ".\n"); + } + } +} diff --git a/src/rustc/rustc.rc b/src/rustc/rustc.rc index 67e583eb5f9..69f225e5ed8 100644 --- a/src/rustc/rustc.rc +++ b/src/rustc/rustc.rc @@ -117,6 +117,7 @@ mod metadata { export decoder; export tyencode; export tydecode; + export loader; mod common; mod tyencode; @@ -126,6 +127,7 @@ mod metadata { mod creader; mod cstore; mod csearch; + mod loader; } mod driver {