(************************************************************ readlib.ml Created : Tue Feb 25 01:58:27 2003 Last modified: Thu Mar 06 21:51:55 2003 Compile: ocamlc str.cma unix.cma readlib.ml -o readlib # FTP Directory: sources/ocaml # ************************************************************) (** cma ファイルに入れられたコンパイルユニット名を出力する like objdump cf) bytecomp/{emitcode.mli,bytelibrarian.ml} 最高に参考になったのは Bytelink.check_consistency seek_in がミソ コンパイルするには emitcode.cmi が必要。これはocamlのbytecomp ないに (ビルド後) できてる 複数ファイルを扱うように変更。 いま扱っているファイル名を出力するように変更。 目的のモジュール名からそれを含んでいるライブラリファイル名を 求める。名前が衝突してて一致してたら....知りません (笑) 実行例) Xmamewo:~/test> ./readlib -find Balloon /usr/local/lib/ocaml/labltk/jpflib.cma @author Takashi Masuyama *) let cma_magic_number = "Caml1999A006" let magic_number_length = String.length cma_magic_number let read ic = let buf = String.make magic_number_length '\000' in let _ = input ic buf 0 magic_number_length in let i = input_binary_int ic in let _ = seek_in ic i in let toc = (input_value ic : Emitcode.library) in toc.Emitcode.lib_units; ;; let read_compile_unit_name filename = let ic = open_in filename in let result = List.iter (fun x -> print_endline x.Emitcode.cu_name) (read ic) in close_in ic; result ;; let read_imports filename = let ic = open_in filename in let result = List.iter (fun x -> print_endline x.Emitcode.cu_name; List.iter (fun (x,_) -> print_endline ("\t"^x)) x.Emitcode.cu_imports) (read ic) in close_in ic; result ;; let find_module_from_libraries library_files module_name = let open_and_read filename = let input = open_in filename in let result = read input in close_in input; result in let file_and_unit_list = List.map (fun x -> (x, open_and_read x)) library_files in List.map fst (List.filter (fun (_, l) -> try ignore (List.find (fun x -> module_name = x.Emitcode.cu_name) l); true with Not_found -> false) file_and_unit_list) type mode_t = IMPORT | UNITS | FIND let get_matched_files pred path = let dir = Unix.opendir path in let rec iter lst = try let filename = Unix.readdir dir in iter (if pred filename then (Filename.concat path filename)::lst else lst) with End_of_file -> lst in let result = iter [] in Unix.closedir dir; result let cma_file_regexp = Str.regexp ".*\\.cma$" let get_cma_files path = get_matched_files (fun x -> Str.string_match cma_file_regexp x 0) path let _ = let mode = ref UNITS in let files = ref [] in let print_filename = ref false in let specs = [ ("-import", Arg.Unit(fun () -> mode := IMPORT), "print included compile unit names and libraries each unit depends on"); ("-unit", Arg.Unit(fun () -> mode := UNITS), "print included compile unit names"); ("-find", Arg.Unit(fun () -> mode := FIND), "find all library files which include a specified moudule"); ("-printfilename", Arg.Set(print_filename), "print treating filename")] in let usage_line = Sys.argv.(0) ^ " [file]" in let _ = Arg.parse specs (fun x -> files := x::!files) usage_line in let path_list = ["/usr/local/lib/ocaml"; "/usr/local/lib/ocaml/labltk"] in let f = match !mode with UNITS -> read_compile_unit_name | IMPORT -> read_imports | FIND -> let library_files = List.fold_left (fun l x -> ((get_cma_files x) @ l)) [] path_list in (fun x -> (List.iter print_endline (find_module_from_libraries library_files x))) in (* let iter_file filename =*) (* let ic = open_in filename in*) (* (if !mode = UNITS then read_imports else read_compile_unit_name) ic;*) (* close_in ic in*) List.iter (fun x -> if !print_filename then print_endline (x^":"); f x) (List.rev !files)