rust/src/boot/driver/lib.ml

243 lines
6.8 KiB
OCaml

open Common;;
let log (sess:Session.sess) =
Session.log "lib"
sess.Session.sess_log_lib
sess.Session.sess_log_out
;;
let iflog (sess:Session.sess) (thunk:(unit -> unit)) : unit =
if sess.Session.sess_log_lib
then thunk ()
else ()
;;
(* FIXME (issue #67): move these to sess. *)
let ar_cache = Hashtbl.create 0 ;;
let sects_cache = Hashtbl.create 0;;
let meta_cache = Hashtbl.create 0;;
let die_cache = Hashtbl.create 0;;
let get_ar
(sess:Session.sess)
(filename:filename)
: Asm.asm_reader option =
htab_search_or_add ar_cache filename
begin
fun _ ->
let sniff =
match sess.Session.sess_targ with
Win32_x86_pe -> Pe.sniff
| MacOS_x86_macho -> Macho.sniff
| Linux_x86_elf -> Elf.sniff
in
sniff sess filename
end
;;
let get_sects
(sess:Session.sess)
(filename:filename) :
(Asm.asm_reader * ((string,(int*int)) Hashtbl.t)) option =
htab_search_or_add sects_cache filename
begin
fun _ ->
match get_ar sess filename with
None -> None
| Some ar ->
let get_sections =
match sess.Session.sess_targ with
Win32_x86_pe -> Pe.get_sections
| MacOS_x86_macho -> Macho.get_sections
| Linux_x86_elf -> Elf.get_sections
in
Some (ar, (get_sections sess ar))
end
;;
let get_meta
(sess:Session.sess)
(filename:filename)
: Session.meta option =
htab_search_or_add meta_cache filename
begin
fun _ ->
match get_sects sess filename with
None -> None
| Some (ar, sects) ->
match htab_search sects ".note.rust" with
Some (off, _) ->
ar.Asm.asm_seek off;
Some (Asm.read_rust_note ar)
| None -> None
end
;;
let get_dies_opt
(sess:Session.sess)
(filename:filename)
: (Dwarf.rooted_dies option) =
htab_search_or_add die_cache filename
begin
fun _ ->
match get_sects sess filename with
None -> None
| Some (ar, sects) ->
let debug_abbrev = Hashtbl.find sects ".debug_abbrev" in
let debug_info = Hashtbl.find sects ".debug_info" in
let abbrevs = Dwarf.read_abbrevs sess ar debug_abbrev in
let dies = Dwarf.read_dies sess ar debug_info abbrevs in
ar.Asm.asm_close ();
Hashtbl.remove ar_cache filename;
Some dies
end
;;
let get_dies
(sess:Session.sess)
(filename:filename)
: Dwarf.rooted_dies =
match get_dies_opt sess filename with
None ->
Printf.fprintf stderr "Error: bad crate file: %s\n%!" filename;
exit 1
| Some dies -> dies
;;
let get_file_mod
(sess:Session.sess)
(abi:Abi.abi)
(filename:filename)
(nref:node_id ref)
(oref:opaque_id ref)
: Ast.mod_items =
let dies = get_dies sess filename in
let items = Hashtbl.create 0 in
Dwarf.extract_mod_items nref oref abi items dies;
items
;;
let get_mod
(sess:Session.sess)
(abi:Abi.abi)
(meta:Ast.meta_pat)
(use_id:node_id)
(nref:node_id ref)
(oref:opaque_id ref)
(crate_item_cache:(crate_id, Ast.mod_items) Hashtbl.t)
: (filename * Ast.mod_items) =
let found = Queue.create () in
let suffix =
match sess.Session.sess_targ with
Win32_x86_pe -> ".dll"
| MacOS_x86_macho -> ".dylib"
| Linux_x86_elf -> ".so"
in
let rec meta_matches i f_meta =
if i >= (Array.length meta)
then true
else
match meta.(i) with
(* FIXME (issue #68): bind the wildcards. *)
(_, None) -> meta_matches (i+1) f_meta
| (k, Some v) ->
match atab_search f_meta k with
None -> false
| Some v' ->
if v = v'
then meta_matches (i+1) f_meta
else false
in
let file_matches file =
log sess "searching for metadata in %s" file;
match get_meta sess file with
None -> false
| Some f_meta ->
log sess "matching metadata in %s" file;
meta_matches 0 f_meta
in
iflog sess
begin
fun _ ->
log sess "searching for library matching:";
Array.iter
begin
fun (k,vo) ->
match vo with
None -> ()
| Some v ->
log sess "%s = %S" k v
end
meta;
end;
Queue.iter
begin
fun dir ->
let dh = Unix.opendir dir in
let rec scan _ =
try
let basename = Unix.readdir dh in
let file = dir ^ "/" ^ basename in
log sess "considering file %s" file;
if (Filename.check_suffix file suffix) &&
(file_matches file)
then
begin
log sess "matched against library %s" file;
let meta = get_meta sess file in
let crate_id =
match meta with
None -> Session.make_crate_id sess
| Some meta ->
iflog sess begin fun _ ->
Array.iter
(fun (k, v) -> log sess "%s = %S" k v)
meta
end;
htab_search_or_default
sess.Session.sess_crate_meta
meta
(fun () -> Session.make_crate_id sess)
in
Queue.add (file, crate_id) found;
end;
scan()
with
End_of_file -> ()
in
scan ()
end
sess.Session.sess_lib_dirs;
match Queue.length found with
0 -> Common.err (Some use_id) "unsatisfied 'use' clause"
| 1 ->
let (filename, crate_id) = Queue.pop found in
let items =
htab_search_or_default crate_item_cache crate_id
(fun () -> get_file_mod sess abi filename nref oref)
in
(filename, items)
| _ -> Common.err (Some use_id) "multiple crates match 'use' clause"
;;
let infer_lib_name
(sess:Session.sess)
(ident:filename)
: filename =
match sess.Session.sess_targ with
Win32_x86_pe -> ident ^ ".dll"
| MacOS_x86_macho -> "lib" ^ ident ^ ".dylib"
| Linux_x86_elf -> "lib" ^ ident ^ ".so"
;;
(*
* Local Variables:
* fill-column: 78;
* indent-tabs-mode: nil
* buffer-file-coding-system: utf-8-unix
* compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
* End:
*)