aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorfilliatr1999-12-03 14:23:32 +0000
committerfilliatr1999-12-03 14:23:32 +0000
commit4b0767cea7ed5185128601e9b809a1b34b233266 (patch)
treee53faa418ef2351a45fb05ab988457399acf1692 /scripts
parente46630571a54f90d6970d8f9746f24abd1380397 (diff)
coqmktop
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@196 85f007b7-540e-0410-9357-904b9bb8a0f7
Diffstat (limited to 'scripts')
-rw-r--r--scripts/.cvsignore2
-rw-r--r--scripts/coqmktop.ml321
2 files changed, 323 insertions, 0 deletions
diff --git a/scripts/.cvsignore b/scripts/.cvsignore
new file mode 100644
index 0000000000..52ba6cec1c
--- /dev/null
+++ b/scripts/.cvsignore
@@ -0,0 +1,2 @@
+coqmktop
+tolink.ml
diff --git a/scripts/coqmktop.ml b/scripts/coqmktop.ml
new file mode 100644
index 0000000000..6a244b9887
--- /dev/null
+++ b/scripts/coqmktop.ml
@@ -0,0 +1,321 @@
+
+(* $Id$ *)
+
+(* Ici, on trie la ligne de commande pour en extraire les options spécifiques
+ à coqmktop, puis on appelle "ocamlc" (ou "ocamlopt")
+ avec les autres options et la liste des fichiers à linker.
+
+ On essaye au maximum d'utiliser les modules Sys et Filename pour que la
+ portabilité soit maximale. *)
+
+open Unix
+
+(* Objects to link *)
+
+(* 1. Core objects *)
+let ocamlobjs = ["unix.cma"]
+let dynobjs = ["dynlink.cma"]
+let camlp4objs = ["gramlib.cma"]
+let configobjs = ["coq_config.cmo"]
+let launchobjs = ["usage.cmo"]
+let libobjs = ocamlobjs @ camlp4objs @ configobjs @ launchobjs
+
+let spaces = Str.regexp "[ \t\n]+"
+let split_cmo l = Str.split spaces l
+
+let lib = split_cmo Tolink.lib
+let kernel = split_cmo Tolink.kernel
+let library = split_cmo Tolink.library
+let pretyping = split_cmo Tolink.pretyping
+let parsing = split_cmo Tolink.parsing
+let proofs = split_cmo Tolink.proofs
+let tactics = split_cmo Tolink.tactics
+let toplevel = split_cmo Tolink.toplevel
+
+let core_objs =
+ libobjs @ lib @ kernel @ library @ pretyping @ parsing @
+ proofs @ tactics
+
+(* 3. Files only in coqsearchisos (if option -searchisos is used) *)
+let coqsearch = ["version_searchisos.cmo"; "cmd_searchisos_line.cmo"]
+
+(* 4. Toplevel objects *)
+let camlp4objs =
+ ["camlp4_top.cma"; "pa_o.cmo"; "pa_op.cmo"; "pa_extend.cmo";
+ "q_coqast.cmo" ]
+let topobjs = camlp4objs
+
+let gramobjs = ["g_zsyntax.cmo"; "g_natsyntax.cmo"]
+let notopobjs = gramobjs
+
+(* 5. High-level tactics objects *)
+let cmotacsobjs = [
+ "prolog.cmo"; "equality.cmo"; "inv.cmo"; "leminv.cmo";
+ "point.cmo"; "progmach.cmo"; "program.cmo"; "propre.cmo";
+ "tauto.cmo"; "gelim.cmo"; "eqdecide.cmo"]
+
+(* environment *)
+let src_coqtop = ref Coq_config.coqtop
+let notactics = ref false
+let opt = ref false
+let top = ref false
+let searchisos = ref false
+let echo = ref false
+
+let includes () =
+ List.fold_right
+ (fun d l -> "-I" :: List.fold_left Filename.concat !src_coqtop d :: l)
+ [ [ "config" ] ;
+ [ "scripts" ] ;
+ [ "lib" ] ;
+ [ "kernel" ] ;
+ [ "library" ] ;
+ [ "pretyping" ] ;
+ [ "parsing" ] ;
+ [ "proofs" ] ;
+ [ "tactics" ] ;
+ [ "toplevel" ]
+ ]
+ ["-I"; Coq_config.camlp4lib]
+
+(* Transform bytecode object file names in native object file names *)
+let native_suffix f =
+ if Filename.check_suffix f ".cmo" then
+ (Filename.chop_suffix f ".cmo") ^ ".cmx"
+ else if Filename.check_suffix f ".cma" then
+ (Filename.chop_suffix f ".cma") ^ ".cmxa"
+ else
+ failwith ("File "^f^" has not extension .cmo or .cma")
+
+(* Transforms a file name in the corresponding Caml module name. *)
+let rem_ext_regexpr = Str.regexp "\(.*\)\.\(cm..?\|ml\)"
+
+let module_of_file name =
+ let s = Str.replace_first rem_ext_regexpr "\1" (Filename.basename name) in
+ String.capitalize s
+
+(* Build the list of files to link and the list of modules names *)
+let files_to_link userfiles =
+ let dyn_objs = if not !opt then dynobjs else [] in
+ let command_objs = if !searchisos then coqsearch else [] in
+ let tactic_objs = if !notactics then [] else cmotacsobjs in
+ let toplevel_objs = if !top then topobjs else if !opt then notopobjs else []
+ in
+ let objs = core_objs @ dyn_objs @ toplevel @ command_objs @ tactic_objs @
+ toplevel_objs in
+ let tolink =
+ if !opt then
+ (List.map native_suffix objs) @ userfiles
+ else
+ objs @ userfiles
+ in
+ let modules = List.map module_of_file tolink in
+ (modules, tolink)
+
+(*Gives the list of all the directories under dir*)
+(*Uses Unix, sorry... But you can try to do the same thing without it.*)
+let all_subdirs dir =
+ let l = ref [] in
+ let add f = l := f :: !l in
+ let rec traverse dir =
+ Printf.printf "%s\n" dir;
+ let dirh =
+ try opendir dir with Unix_error _ -> invalid_arg "all_subdirs"
+ in
+ try
+ while true do
+ let f = readdir dirh in
+ if f <> "." && f <> ".." then
+ let file = Filename.concat dir f in
+ if (stat file).st_kind = S_DIR then begin
+ add file;
+ traverse file
+ end
+ done
+ with End_of_file ->
+ closedir dirh
+ in
+ traverse dir; List.rev !l
+
+(* usage *)
+let usage () =
+ prerr_endline "Usage: coqmktop <options> <ocaml options> files
+Options are:
+ -srcdir dir Specify where the Coq source files are
+ -notactics Do not link high level tactics
+ -o exec-file Specify the name of the resulting toplevel
+ -opt Compile in native code
+ -top Build Coq on a ocaml toplevel (incompatible with -opt)
+ -searchisos Build a toplevel for SearchIsos (implies -notactics)
+ -R dir Specify recursively directories for Ocaml\n";
+ exit 1
+
+(* parsing of the command line *)
+let parse_args () =
+ let rec parse (op,fl) = function
+ | [] -> List.rev op, List.rev fl
+ | "-srcdir" :: d :: rem -> src_coqtop := d ; parse (op,fl) rem
+ | "-srcdir" :: _ -> usage ()
+ | "-notactics" :: rem -> notactics := true ; parse (op,fl) rem
+ | "-opt" :: rem -> opt := true ; parse (op,fl) rem
+ | "-top" :: rem -> top := true ; parse (op,fl) rem
+ | "-searchisos" :: rem ->
+ searchisos := true; notactics := true; parse (op,fl) rem
+ | "-echo" :: rem -> echo := true ; parse (op,fl) rem
+ | ("-cclib"|"-ccopt"|"-I"|"-o" as o) :: rem' ->
+ begin
+ match rem' with
+ | a :: rem -> parse (a::o::op,fl) rem
+ | [] -> usage ()
+ end
+ | "-R" :: rem' ->
+ begin
+ match rem' with
+ | a :: rem ->
+ parse ((List.rev(List.flatten (List.map (fun d -> ["-I";d])
+ (all_subdirs a))))@op,fl) rem
+ | [] -> usage ()
+ end
+ | ("-compact"|"-g"|"-p" as o) :: rem -> parse (o::op,fl) rem
+ | ("-h"|"--help") :: _ -> usage ()
+ | f :: rem ->
+ if Filename.check_suffix f ".ml"
+ or Filename.check_suffix f ".cmx"
+ or Filename.check_suffix f ".cmo"
+ or Filename.check_suffix f ".cmxa"
+ or Filename.check_suffix f ".cma" then
+ parse (op,f::fl) rem
+ else begin
+ prerr_endline ("Don't know what to do with " ^ f);
+ exit 1
+ end
+ in
+ parse ([Coq_config.osdeplibs],[]) (List.tl (Array.to_list Sys.argv))
+
+let clean file =
+ let rm f = if Sys.file_exists f then Sys.remove f in
+ let basename = Filename.chop_suffix file ".ml" in
+ if not !echo then begin
+ rm file;
+ rm (basename ^ ".o");
+ rm (basename ^ ".cmi");
+ rm (basename ^ ".cmo");
+ rm (basename ^ ".cmx")
+ end
+
+(*Gives all modules in dir. Uses .cmi. Unix again sorry again*)
+let all_modules_in_dir dir=
+ try
+ let lst = ref []
+ and stg = ref ""
+ and dh = Unix.opendir dir in
+ try
+ while true do
+ let stg = Unix.readdir dh in
+ if (Filename.check_suffix stg ".cmi") then
+ lst := !lst @ [String.capitalize (Filename.chop_suffix stg ".cmi")]
+ done;
+ []
+ with End_of_file ->
+ Unix.closedir dh; !lst
+ with Unix.Unix_error (_,"opendir",_) ->
+ failwith ("all_modules_in_dir: directory "^dir^" not found")
+
+(*Gives a part of command line (corresponding to dir) for extract_crc*)
+let crc_cmd dir =
+ " -I "^dir^(List.fold_right (fun x y -> " "^x^y) (all_modules_in_dir dir)
+ "")
+
+(*Same as crc_cmd but recursively*)
+let rec_crc_cmd dir =
+ List.fold_right (fun x y -> x^y) (List.map crc_cmd (all_subdirs dir)) ""
+
+(*Creates another temporary file for Dynlink if needed*)
+let tmp_dynlink()=
+ let tmp = Filename.temp_file "coqdynlink" ".ml" in
+ let _ = Sys.command ("echo \"Dynlink.init();;\" > "^tmp) in
+ let _ = Sys.command (Coq_config.camllib^"/extract_crc"^(crc_cmd
+ Coq_config.camllib)^(crc_cmd Coq_config.camlp4lib)^(rec_crc_cmd
+ (Coq_config.coqtop^"/src"))^" >> "^tmp) in
+ let _ = Sys.command ("echo \";;\" >> "^tmp) in
+ let _ =
+ Sys.command ("echo \"Dynlink.add_available_units crc_unit_list;;\" >> "^
+ tmp)
+ in
+ tmp
+
+(*Initializes the kind of loading in the main program*)
+let declare_loading_string()=
+ if !opt then
+ "Mltop.set Mltop.Native;;\n"
+ else if not !top then
+ "Mltop.set Mltop.WithoutTop;;\n"
+ else
+ "Mltop.set (Mltop.WithTop {Mltop.load_obj=Topdirs.dir_load;
+ Mltop.use_file=Topdirs.dir_use;
+ Mltop.add_dir=Topdirs.dir_directory});;\n"
+
+(* create a temporary main file to link *)
+let create_tmp_main_file modules =
+ let main_name = Filename.temp_file "coqmain" ".ml" in
+ let oc = open_out main_name in
+ try
+ (* Add the pre-linked modules *)
+ output_string oc "List.iter Mltop.add_known_module [\"";
+ output_string oc (String.concat "\";\"" modules);
+ output_string oc "\"];;\n";
+ (*Initializes the kind of loading*)
+ output_string oc (declare_loading_string());
+ (* Start the right toplevel loop: Coq or Coq_searchisos *)
+ if !searchisos then
+ output_string oc "Cmd_searchisos_line.start();;\n"
+ else
+ output_string oc "Coqtop.start();;\n";
+ (* Start the Ocaml toplevel if it exists *)
+ if !top then
+ output_string oc "Printexc.catch Toploop.loop(); exit 1;;\n";
+ close_out oc;
+ main_name
+ with e ->
+ clean main_name; raise e
+
+(* main part *)
+let main () =
+ let (options, userfiles) = parse_args () in
+ (* which ocaml command to invoke *)
+ let prog =
+ if !opt then begin
+ (* native code *)
+ if !top then failwith "no custom toplevel in native code !";
+ "ocamlopt -linkall"
+ end else
+ (* bytecode *)
+ if !top then "ocamlmktop -custom -linkall" else "ocamlc -custom -linkall"
+ in
+ (* files to link *)
+ let (modules, tolink) = files_to_link userfiles in
+ (*file for dynlink *)
+ let dynlink=
+ if not (!opt || !top) then
+ [tmp_dynlink()]
+ else
+ []
+ in
+ (* the list of the loaded modules *)
+ let main_file = create_tmp_main_file modules in
+ try
+ let args = (includes ()) @ options @ tolink @ dynlink @ [ main_file ] in
+ (* Now, with the .cma, we MUST use the -linkall option *)
+ let command = String.concat " " ((prog^" -linkall")::args) in
+ if !echo then begin print_endline command; flush Pervasives.stdout end;
+ let retcode = Sys.command command in
+ clean main_file;
+ (* command gives the exit code in HSB, and signal in LSB !!! *)
+ if retcode > 255 then retcode lsr 8 else retcode
+ with e ->
+ clean main_file; raise e
+
+let retcode =
+ try Printexc.print main () with _ -> 1
+
+let _ = exit retcode