]> git.proxmox.com Git - rustc.git/blame - src/librustc/metadata/loader.rs
Imported Upstream version 0.7
[rustc.git] / src / librustc / metadata / loader.rs
CommitLineData
223e47cc
LB
1// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
223e47cc
LB
11//! Finds crate binaries and loads their metadata
12
223e47cc
LB
13
14use lib::llvm::{False, llvm, mk_object_file, mk_section_iter};
15use metadata::decoder;
16use metadata::encoder;
17use metadata::filesearch::FileSearch;
18use metadata::filesearch;
19use syntax::codemap::span;
20use syntax::diagnostic::span_handler;
970d7e83 21use syntax::parse::token;
223e47cc
LB
22use syntax::parse::token::ident_interner;
23use syntax::print::pprust;
24use syntax::{ast, attr};
25
970d7e83
LB
26use std::cast;
27use std::io;
28use std::option;
29use std::os::consts::{macos, freebsd, linux, android, win32};
30use std::ptr;
31use std::str;
32use std::uint;
33use std::vec;
34use extra::flate;
223e47cc
LB
35
36pub enum os {
37 os_macos,
38 os_win32,
39 os_linux,
40 os_android,
41 os_freebsd
42}
43
44pub struct Context {
45 diag: @span_handler,
46 filesearch: @FileSearch,
47 span: span,
48 ident: ast::ident,
49 metas: ~[@ast::meta_item],
970d7e83 50 hash: @str,
223e47cc
LB
51 os: os,
52 is_static: bool,
53 intr: @ident_interner
54}
55
970d7e83 56pub fn load_library_crate(cx: &Context) -> (~str, @~[u8]) {
223e47cc
LB
57 match find_library_crate(cx) {
58 Some(ref t) => return (/*bad*/copy *t),
59 None => {
60 cx.diag.span_fatal(
61 cx.span, fmt!("can't find crate for `%s`",
970d7e83 62 token::ident_to_str(&cx.ident)));
223e47cc
LB
63 }
64 }
65}
66
970d7e83 67fn find_library_crate(cx: &Context) -> Option<(~str, @~[u8])> {
223e47cc
LB
68 attr::require_unique_names(cx.diag, cx.metas);
69 find_library_crate_aux(cx, libname(cx), cx.filesearch)
70}
71
970d7e83 72fn libname(cx: &Context) -> (~str, ~str) {
223e47cc
LB
73 if cx.is_static { return (~"lib", ~".rlib"); }
74 let (dll_prefix, dll_suffix) = match cx.os {
75 os_win32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
76 os_macos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
77 os_linux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
78 os_android => (android::DLL_PREFIX, android::DLL_SUFFIX),
79 os_freebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
80 };
81
970d7e83 82 (str::to_owned(dll_prefix), str::to_owned(dll_suffix))
223e47cc
LB
83}
84
85fn find_library_crate_aux(
970d7e83 86 cx: &Context,
223e47cc
LB
87 (prefix, suffix): (~str, ~str),
88 filesearch: @filesearch::FileSearch
89) -> Option<(~str, @~[u8])> {
90 let crate_name = crate_name_from_metas(cx.metas);
970d7e83 91 let prefix = prefix + crate_name + "-";
223e47cc
LB
92
93 let mut matches = ~[];
970d7e83 94 filesearch::search(filesearch, |path| -> Option<()> {
223e47cc 95 debug!("inspecting file %s", path.to_str());
970d7e83
LB
96 match path.filename() {
97 Some(ref f) if f.starts_with(prefix) && f.ends_with(suffix) => {
98 debug!("%s is a candidate", path.to_str());
99 match get_metadata_section(cx.os, path) {
100 Some(cvec) =>
101 if !crate_matches(cvec, cx.metas, cx.hash) {
102 debug!("skipping %s, metadata doesn't match",
103 path.to_str());
104 None
105 } else {
106 debug!("found %s with matching metadata", path.to_str());
107 matches.push((path.to_str(), cvec));
108 None
109 },
110 _ => {
111 debug!("could not load metadata for %s", path.to_str());
112 None
113 }
223e47cc 114 }
223e47cc 115 }
970d7e83
LB
116 _ => {
117 debug!("skipping %s, doesn't look like %s*%s", path.to_str(),
118 prefix, suffix);
119 None
120 }
121 }});
223e47cc 122
970d7e83
LB
123 match matches.len() {
124 0 => None,
125 1 => Some(matches[0]),
126 _ => {
127 cx.diag.span_err(
128 cx.span, fmt!("multiple matching crates for `%s`", crate_name));
129 cx.diag.handler().note("candidates:");
130 for matches.iter().advance |&(ident, data)| {
131 cx.diag.handler().note(fmt!("path: %s", ident));
132 let attrs = decoder::get_crate_attributes(data);
133 note_linkage_attrs(cx.intr, cx.diag, attrs);
134 }
135 cx.diag.handler().abort_if_errors();
136 None
137 }
223e47cc 138 }
223e47cc
LB
139}
140
970d7e83
LB
141pub fn crate_name_from_metas(metas: &[@ast::meta_item]) -> @str {
142 for metas.iter().advance |m| {
143 match m.node {
144 ast::meta_name_value(s, ref l) if s == @"name" =>
145 match l.node {
146 ast::lit_str(s) => return s,
147 _ => ()
148 },
149 _ => ()
223e47cc 150 }
223e47cc 151 }
970d7e83 152 fail!("expected to find the crate name")
223e47cc
LB
153}
154
155pub fn note_linkage_attrs(intr: @ident_interner,
156 diag: @span_handler,
157 attrs: ~[ast::attribute]) {
970d7e83
LB
158 let r = attr::find_linkage_metas(attrs);
159 for r.iter().advance |mi| {
160 diag.handler().note(fmt!("meta: %s", pprust::meta_item_to_str(*mi,intr)));
223e47cc
LB
161 }
162}
163
164fn crate_matches(crate_data: @~[u8],
165 metas: &[@ast::meta_item],
970d7e83 166 hash: @str) -> bool {
223e47cc
LB
167 let attrs = decoder::get_crate_attributes(crate_data);
168 let linkage_metas = attr::find_linkage_metas(attrs);
169 if !hash.is_empty() {
170 let chash = decoder::get_crate_hash(crate_data);
171 if chash != hash { return false; }
172 }
173 metadata_matches(linkage_metas, metas)
174}
175
176pub fn metadata_matches(extern_metas: &[@ast::meta_item],
177 local_metas: &[@ast::meta_item]) -> bool {
178
179 debug!("matching %u metadata requirements against %u items",
970d7e83 180 local_metas.len(), extern_metas.len());
223e47cc 181
970d7e83 182 for local_metas.iter().advance |needed| {
223e47cc
LB
183 if !attr::contains(extern_metas, *needed) {
184 return false;
185 }
186 }
187 return true;
188}
189
190fn get_metadata_section(os: os,
191 filename: &Path) -> Option<@~[u8]> {
192 unsafe {
193 let mb = str::as_c_str(filename.to_str(), |buf| {
194 llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
195 });
196 if mb as int == 0 { return option::None::<@~[u8]>; }
197 let of = match mk_object_file(mb) {
198 option::Some(of) => of,
199 _ => return option::None::<@~[u8]>
200 };
201 let si = mk_section_iter(of.llof);
202 while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
203 let name_buf = llvm::LLVMGetSectionName(si.llsi);
970d7e83
LB
204 let name = str::raw::from_c_str(name_buf);
205 debug!("get_metadata_section: name %s", name);
206 if name == read_meta_section_name(os) {
223e47cc
LB
207 let cbuf = llvm::LLVMGetSectionContents(si.llsi);
208 let csz = llvm::LLVMGetSectionSize(si.llsi) as uint;
209 let mut found = None;
970d7e83
LB
210 let cvbuf: *u8 = cast::transmute(cbuf);
211 let vlen = encoder::metadata_encoding_version.len();
212 debug!("checking %u bytes of metadata-version stamp",
213 vlen);
214 let minsz = uint::min(vlen, csz);
215 let mut version_ok = false;
216 do vec::raw::buf_as_slice(cvbuf, minsz) |buf0| {
217 version_ok = (buf0 ==
218 encoder::metadata_encoding_version);
219 }
220 if !version_ok { return None; }
223e47cc 221
970d7e83
LB
222 let cvbuf1 = ptr::offset(cvbuf, vlen);
223 debug!("inflating %u bytes of compressed metadata",
224 csz - vlen);
225 do vec::raw::buf_as_slice(cvbuf1, csz-vlen) |bytes| {
226 let inflated = flate::inflate_bytes(bytes);
227 found = Some(@(inflated));
228 }
229 if found != None {
230 return found;
223e47cc
LB
231 }
232 }
233 llvm::LLVMMoveToNextSection(si.llsi);
234 }
235 return option::None::<@~[u8]>;
236 }
237}
238
239pub fn meta_section_name(os: os) -> ~str {
240 match os {
241 os_macos => ~"__DATA,__note.rustc",
242 os_win32 => ~".note.rustc",
243 os_linux => ~".note.rustc",
244 os_android => ~".note.rustc",
245 os_freebsd => ~".note.rustc"
246 }
247}
248
970d7e83
LB
249pub fn read_meta_section_name(os: os) -> ~str {
250 match os {
251 os_macos => ~"__note.rustc",
252 os_win32 => ~".note.rustc",
253 os_linux => ~".note.rustc",
254 os_android => ~".note.rustc",
255 os_freebsd => ~".note.rustc"
256 }
257}
258
223e47cc
LB
259// A diagnostic function for dumping crate metadata to an output stream
260pub fn list_file_metadata(intr: @ident_interner,
261 os: os,
262 path: &Path,
263 out: @io::Writer) {
264 match get_metadata_section(os, path) {
265 option::Some(bytes) => decoder::list_crate_metadata(intr, bytes, out),
266 option::None => {
970d7e83 267 out.write_str(fmt!("could not find metadata in %s.\n", path.to_str()))
223e47cc
LB
268 }
269 }
270}