diff options
author | Sébastien Hinderer <Sebastien.Hinderer@inria.fr> | 2020-06-17 09:29:56 +0200 |
---|---|---|
committer | Sébastien Hinderer <Sebastien.Hinderer@inria.fr> | 2020-06-18 11:16:55 +0200 |
commit | bdd9ca391e3a56253d7480b07bb1a8aac361904c (patch) | |
tree | 438b71b4bc6a4e11fa9a4056cbbca722bce5fed3 /tools/ocamlcmt.ml | |
parent | 41e4dc1dc8e156dd10a63124ce061ac1588d0aef (diff) | |
download | ocaml-bdd9ca391e3a56253d7480b07bb1a8aac361904c.tar.gz |
Add the $(EXE) suffix to all programs at build rather than install time
This commit touches neither boot/ocamlc nor boot/ocamllex
It has the side-effect of fixing the cleanup rules which did not use the
$(EXE) extension when removing a file although it was produced with the
$(EXE) extension.
Diffstat (limited to 'tools/ocamlcmt.ml')
-rw-r--r-- | tools/ocamlcmt.ml | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/tools/ocamlcmt.ml b/tools/ocamlcmt.ml new file mode 100644 index 0000000000..359b28aa4b --- /dev/null +++ b/tools/ocamlcmt.ml @@ -0,0 +1,200 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Fabrice Le Fessant, INRIA Saclay *) +(* *) +(* Copyright 2012 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +let gen_annot = ref false +let gen_ml = ref false +let print_info_arg = ref false +let target_filename = ref None +let save_cmt_info = ref false + +let arg_list = Arg.align [ + "-o", Arg.String (fun s -> target_filename := Some s), + "<file> Dump to file <file> (or stdout if -)"; + "-annot", Arg.Set gen_annot, + " Generate the corresponding .annot file"; + "-save-cmt-info", Arg.Set save_cmt_info, + " Encapsulate additional cmt information in annotations"; + "-src", Arg.Set gen_ml, + " Convert .cmt or .cmti back to source code (without comments)"; + "-info", Arg.Set print_info_arg, " : print information on the file"; + "-args", Arg.Expand Arg.read_arg, + "<file> Read additional newline separated command line arguments \n\ + \ from <file>"; + "-args0", Arg.Expand Arg.read_arg0, + "<file> Read additional NUL separated command line arguments from \n\ + \ <file>"; + "-I", Arg.String (fun s -> + Clflags.include_dirs := s :: !Clflags.include_dirs), + "<dir> Add <dir> to the list of include directories"; + ] + +let arg_usage = + "ocamlcmt [OPTIONS] FILE.cmt : read FILE.cmt and print related information" + +let dummy_crc = String.make 32 '-' + +let print_info cmt = + let oc = match !target_filename with + | None -> stdout + | Some filename -> open_out filename + in + let open Cmt_format in + Printf.fprintf oc "module name: %s\n" cmt.cmt_modname; + begin match cmt.cmt_annots with + Packed (_, list) -> + Printf.fprintf oc "pack: %s\n" (String.concat " " list) + | Implementation _ -> Printf.fprintf oc "kind: implementation\n" + | Interface _ -> Printf.fprintf oc "kind: interface\n" + | Partial_implementation _ -> + Printf.fprintf oc "kind: implementation with errors\n" + | Partial_interface _ -> Printf.fprintf oc "kind: interface with errors\n" + end; + Printf.fprintf oc "command: %s\n" + (String.concat " " (Array.to_list cmt.cmt_args)); + begin match cmt.cmt_sourcefile with + None -> () + | Some name -> + Printf.fprintf oc "sourcefile: %s\n" name; + end; + Printf.fprintf oc "build directory: %s\n" cmt.cmt_builddir; + List.iter (Printf.fprintf oc "load path: %s\n%!") cmt.cmt_loadpath; + begin + match cmt.cmt_source_digest with + None -> () + | Some digest -> + Printf.fprintf oc "source digest: %s\n" (Digest.to_hex digest); + end; + begin + match cmt.cmt_interface_digest with + None -> () + | Some digest -> + Printf.fprintf oc "interface digest: %s\n" (Digest.to_hex digest); + end; + List.iter (fun (name, crco) -> + let crc = + match crco with + None -> dummy_crc + | Some crc -> Digest.to_hex crc + in + Printf.fprintf oc "import: %s %s\n" name crc; + ) (List.sort compare cmt.cmt_imports); + Printf.fprintf oc "%!"; + begin match !target_filename with + | None -> () + | Some _ -> close_out oc + end; + () + +let generate_ml target_filename filename cmt = + let (printer, ext) = + match cmt.Cmt_format.cmt_annots with + | Cmt_format.Implementation typedtree -> + (fun ppf -> Pprintast.structure ppf + (Untypeast.untype_structure typedtree)), + ".ml" + | Cmt_format.Interface typedtree -> + (fun ppf -> Pprintast.signature ppf + (Untypeast.untype_signature typedtree)), + ".mli" + | _ -> + Printf.fprintf stderr "File was generated with an error\n%!"; + exit 2 + in + let target_filename = match target_filename with + None -> Some (filename ^ ext) + | Some "-" -> None + | Some _ -> target_filename + in + let oc = match target_filename with + None -> None + | Some filename -> Some (open_out filename) in + let ppf = match oc with + None -> Format.std_formatter + | Some oc -> Format.formatter_of_out_channel oc in + printer ppf; + Format.pp_print_flush ppf (); + match oc with + None -> flush stdout + | Some oc -> close_out oc + +(* Save cmt information as faked annotations, attached to + Location.none, on top of the .annot file. Only when -save-cmt-info is + provided to ocaml_cmt. +*) +let record_cmt_info cmt = + let location_none = { + Location.none with Location.loc_ghost = false } + in + let location_file file = { + Location.none with + Location.loc_start = { + Location.none.Location.loc_start with + Lexing.pos_fname = file }} + in + let record_info name value = + let ident = Printf.sprintf ".%s" name in + Stypes.record (Stypes.An_ident (location_none, ident, + Annot.Idef (location_file value))) + in + let open Cmt_format in + List.iter (fun dir -> record_info "include" dir) cmt.cmt_loadpath; + record_info "chdir" cmt.cmt_builddir; + (match cmt.cmt_sourcefile with + None -> () | Some file -> record_info "source" file) + +let main () = + Clflags.annotations := true; + + Arg.parse_expand arg_list (fun filename -> + if + Filename.check_suffix filename ".cmt" || + Filename.check_suffix filename ".cmti" + then begin + let open Cmt_format in + Compmisc.init_path (); + let cmt = read_cmt filename in + if !gen_annot then begin + if !save_cmt_info then record_cmt_info cmt; + let target_filename = + match !target_filename with + | None -> Some (filename ^ ".annot") + | Some "-" -> None + | Some _ as x -> x + in + Envaux.reset_cache (); + List.iter Load_path.add_dir cmt.cmt_loadpath; + Cmt2annot.gen_annot target_filename + ~sourcefile:cmt.cmt_sourcefile + ~use_summaries:cmt.cmt_use_summaries + cmt.cmt_annots + end; + if !gen_ml then generate_ml !target_filename filename cmt; + if !print_info_arg || not (!gen_ml || !gen_annot) then print_info cmt; + end else begin + Printf.fprintf stderr + "Error: the file's extension must be .cmt or .cmti.\n%!"; + Arg.usage arg_list arg_usage + end + ) arg_usage + + +let () = + try + main () + with x -> + Printf.eprintf "Exception in main ()\n%!"; + Location.report_exception Format.err_formatter x; + Format.fprintf Format.err_formatter "@."; + exit 2 |