| author | wenzelm | 
| Tue, 13 Aug 2024 18:53:24 +0200 | |
| changeset 80701 | 39cd50407f79 | 
| parent 80462 | 7a1f9e571046 | 
| child 82706 | e9b9af6da795 | 
| permissions | -rw-r--r-- | 
| 65477 | 1 | /* Title: Pure/ML/ml_process.scala | 
| 62544 | 2 | Author: Makarius | 
| 3 | ||
| 62586 | 4 | The raw ML process. | 
| 62544 | 5 | */ | 
| 6 | ||
| 7 | package isabelle | |
| 8 | ||
| 9 | ||
| 73897 | 10 | import java.util.{Map => JMap, HashMap}
 | 
| 62573 | 11 | |
| 12 | ||
| 75393 | 13 | object ML_Process {
 | 
| 80124 | 14 | def make_shasum(ancestors: List[SHA1.Shasum]): SHA1.Shasum = | 
| 15 |     if (ancestors.isEmpty) SHA1.shasum_meta_info(SHA1.digest(Path.explode("$POLYML_EXE")))
 | |
| 16 | else SHA1.flat_shasum(ancestors) | |
| 77650 | 17 | |
| 77414 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 18 | def session_heaps( | 
| 78178 | 19 | store: Store, | 
| 77414 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 20 | session_background: Sessions.Background, | 
| 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 21 | logic: String = "" | 
| 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 22 |   ): List[Path] = {
 | 
| 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 23 | val logic_name = Isabelle_System.default_logic(logic) | 
| 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 24 | |
| 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 25 | session_background.sessions_structure.selection(logic_name). | 
| 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 26 | build_requirements(List(logic_name)). | 
| 79674 | 27 | map(name => store.get_session(name).the_heap) | 
| 77414 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 28 | } | 
| 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 29 | |
| 76729 | 30 | def apply( | 
| 31 | options: Options, | |
| 76657 | 32 | session_background: Sessions.Background, | 
| 77414 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 33 | session_heaps: List[Path], | 
| 71639 
ec84f542e411
clarified signature of ML_Process vs. Isabelle_Process: proper support for "isabelle build -P -b";
 wenzelm parents: 
71598diff
changeset | 34 | use_prelude: List[String] = Nil, | 
| 
ec84f542e411
clarified signature of ML_Process vs. Isabelle_Process: proper support for "isabelle build -P -b";
 wenzelm parents: 
71598diff
changeset | 35 | eval_main: String = "", | 
| 62544 | 36 | args: List[String] = Nil, | 
| 62556 
c115e69f457f
more abstract Session.start, without prover command-line;
 wenzelm parents: 
62548diff
changeset | 37 | modes: List[String] = Nil, | 
| 80224 
db92e0b6a11a
clarified signature: prefer symbolic isabelle.Path over physical java.io.File;
 wenzelm parents: 
80124diff
changeset | 38 | cwd: Path = Path.current, | 
| 73897 | 39 | env: JMap[String, String] = Isabelle_System.settings(), | 
| 62557 | 40 | redirect: Boolean = false, | 
| 76655 | 41 | cleanup: () => Unit = () => () | 
| 75393 | 42 |   ): Bash.Process = {
 | 
| 79656 
10e560f2f580
more robust default: Scala imposes explicit "threads" value on ML, both the Poly/ML RTS and Isabelle/ML;
 wenzelm parents: 
79654diff
changeset | 43 | val ml_options = options.standard_ml() | 
| 
10e560f2f580
more robust default: Scala imposes explicit "threads" value on ML, both the Poly/ML RTS and Isabelle/ML;
 wenzelm parents: 
79654diff
changeset | 44 | |
| 62637 
0189fe0f6452
support for Poly/ML heap hierarchy, which saves a lot of disk space;
 wenzelm parents: 
62634diff
changeset | 45 | val eval_init = | 
| 77414 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 46 |       if (session_heaps.isEmpty) {
 | 
| 62544 | 47 | List( | 
| 62912 | 48 | """ | 
| 49 | fun chapter (_: string) = (); | |
| 50 | fun section (_: string) = (); | |
| 51 | fun subsection (_: string) = (); | |
| 52 | fun subsubsection (_: string) = (); | |
| 53 | fun paragraph (_: string) = (); | |
| 54 | fun subparagraph (_: string) = (); | |
| 55 | val ML_file = PolyML.use; | |
| 56 | """, | |
| 62544 | 57 | if (Platform.is_windows) | 
| 58 | "fun exit 0 = OS.Process.exit OS.Process.success" + | |
| 59 | " | exit 1 = OS.Process.exit OS.Process.failure" + | |
| 60 | " | exit rc = OS.Process.exit (RunCall.unsafeCast (Word8.fromInt rc))" | |
| 62560 | 61 | else | 
| 62 | "fun exit rc = Posix.Process.exit (Word8.fromInt rc)", | |
| 62629 
1815513a57f1
clarified prompt: "ML" usually means Isabelle/ML;
 wenzelm parents: 
62614diff
changeset | 63 | "PolyML.Compiler.prompt1 := \"Poly/ML> \"", | 
| 
1815513a57f1
clarified prompt: "ML" usually means Isabelle/ML;
 wenzelm parents: 
62614diff
changeset | 64 | "PolyML.Compiler.prompt2 := \"Poly/ML# \"") | 
| 62544 | 65 | } | 
| 77413 | 66 |       else {
 | 
| 62637 
0189fe0f6452
support for Poly/ML heap hierarchy, which saves a lot of disk space;
 wenzelm parents: 
62634diff
changeset | 67 | List( | 
| 
0189fe0f6452
support for Poly/ML heap hierarchy, which saves a lot of disk space;
 wenzelm parents: 
62634diff
changeset | 68 | "(PolyML.SaveState.loadHierarchy " + | 
| 77414 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 69 | ML_Syntax.print_list( | 
| 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 70 | ML_Syntax.print_string_bytes)(session_heaps.map(File.platform_path)) + | 
| 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 71 | "; PolyML.print_depth 0)") | 
| 77413 | 72 | } | 
| 62544 | 73 | |
| 74 | val eval_modes = | |
| 75 | if (modes.isEmpty) Nil | |
| 66782 | 76 |       else List("Print_Mode.add_modes " + ML_Syntax.print_list(ML_Syntax.print_string_bytes)(modes))
 | 
| 62544 | 77 | |
| 73897 | 78 | |
| 62544 | 79 | // options | 
| 77414 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 80 |     val eval_options = if (session_heaps.isEmpty) Nil else List("Options.load_default ()")
 | 
| 62544 | 81 |     val isabelle_process_options = Isabelle_System.tmp_file("options")
 | 
| 78161 | 82 | File.restrict(File.path(isabelle_process_options)) | 
| 79656 
10e560f2f580
more robust default: Scala imposes explicit "threads" value on ML, both the Poly/ML RTS and Isabelle/ML;
 wenzelm parents: 
79654diff
changeset | 83 | File.write(isabelle_process_options, YXML.string_of_body(ml_options.encode)) | 
| 62544 | 84 | |
| 76655 | 85 | // session resources | 
| 77414 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 86 |     val eval_init_session = if (session_heaps.isEmpty) Nil else List("Resources.init_session_env ()")
 | 
| 72637 | 87 |     val init_session = Isabelle_System.tmp_file("init_session")
 | 
| 78161 | 88 | File.restrict(File.path(init_session)) | 
| 80462 
7a1f9e571046
clarified signature: more explicit XML.Body types, more uniform Symbol.encode_yxml;
 wenzelm parents: 
80225diff
changeset | 89 | File.write(init_session, YXML.string_of_body(new Resources(session_background).init_session_xml)) | 
| 65431 
4a3e6cda3b94
provide session base for "isabelle build" and "isabelle console" ML process;
 wenzelm parents: 
65420diff
changeset | 90 | |
| 
4a3e6cda3b94
provide session base for "isabelle build" and "isabelle console" ML process;
 wenzelm parents: 
65420diff
changeset | 91 | // process | 
| 62544 | 92 | val eval_process = | 
| 71639 
ec84f542e411
clarified signature of ML_Process vs. Isabelle_Process: proper support for "isabelle build -P -b";
 wenzelm parents: 
71598diff
changeset | 93 | proper_string(eval_main).getOrElse( | 
| 77414 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 94 |         if (session_heaps.isEmpty) {
 | 
| 79656 
10e560f2f580
more robust default: Scala imposes explicit "threads" value on ML, both the Poly/ML RTS and Isabelle/ML;
 wenzelm parents: 
79654diff
changeset | 95 |           "PolyML.print_depth " + ML_Syntax.print_int(ml_options.int("ML_print_depth"))
 | 
| 71639 
ec84f542e411
clarified signature of ML_Process vs. Isabelle_Process: proper support for "isabelle build -P -b";
 wenzelm parents: 
71598diff
changeset | 96 | } | 
| 
ec84f542e411
clarified signature of ML_Process vs. Isabelle_Process: proper support for "isabelle build -P -b";
 wenzelm parents: 
71598diff
changeset | 97 | else "Isabelle_Process.init ()") | 
| 62544 | 98 | |
| 62601 
a937889f0086
create ISABELLE_TMP in Scala (despite odd/obsolete chmod in d84b4d39bce1);
 wenzelm parents: 
62600diff
changeset | 99 | // ISABELLE_TMP | 
| 
a937889f0086
create ISABELLE_TMP in Scala (despite odd/obsolete chmod in d84b4d39bce1);
 wenzelm parents: 
62600diff
changeset | 100 |     val isabelle_tmp = Isabelle_System.tmp_dir("process")
 | 
| 71881 | 101 | |
| 75393 | 102 |     val ml_runtime_options = {
 | 
| 79654 | 103 |       val ml_options0 = Word.explode(Isabelle_System.getenv("ML_OPTIONS"))
 | 
| 69702 | 104 | val ml_options1 = | 
| 79654 | 105 |         if (ml_options0.exists(_.containsSlice("gcthreads"))) ml_options0
 | 
| 79656 
10e560f2f580
more robust default: Scala imposes explicit "threads" value on ML, both the Poly/ML RTS and Isabelle/ML;
 wenzelm parents: 
79654diff
changeset | 106 |         else ml_options0 ::: List("--gcthreads", ml_options.threads().toString)
 | 
| 69702 | 107 | val ml_options2 = | 
| 79654 | 108 |         if (!Platform.is_windows || ml_options0.exists(_.containsSlice("codepage"))) ml_options1
 | 
| 69702 | 109 |         else ml_options1 ::: List("--codepage", "utf8")
 | 
| 72112 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
71881diff
changeset | 110 |       ml_options2 ::: List("--exportstats")
 | 
| 64274 | 111 | } | 
| 112 | ||
| 62545 
8ebffdaf2ce2
Bash.process always uses a closed script instead of an open argument list, for extra robustness on Windows, where quoting is not well-defined;
 wenzelm parents: 
62544diff
changeset | 113 | // bash | 
| 
8ebffdaf2ce2
Bash.process always uses a closed script instead of an open argument list, for extra robustness on Windows, where quoting is not well-defined;
 wenzelm parents: 
62544diff
changeset | 114 | val bash_args = | 
| 64274 | 115 | ml_runtime_options ::: | 
| 72637 | 116 |       (eval_init ::: eval_modes ::: eval_options ::: eval_init_session).flatMap(List("--eval", _)) :::
 | 
| 71639 
ec84f542e411
clarified signature of ML_Process vs. Isabelle_Process: proper support for "isabelle build -P -b";
 wenzelm parents: 
71598diff
changeset | 117 |       use_prelude.flatMap(List("--use", _)) ::: List("--eval", eval_process) ::: args
 | 
| 62546 | 118 | |
| 73897 | 119 | val bash_env = new HashMap(env) | 
| 120 |     bash_env.put("ISABELLE_PROCESS_OPTIONS", File.standard_path(isabelle_process_options))
 | |
| 75590 
99b7638d9177
clarified session resources for bootstrap, notably for Scala functions;
 wenzelm parents: 
75394diff
changeset | 121 |     bash_env.put("ISABELLE_INIT_SESSION", File.standard_path(init_session))
 | 
| 73897 | 122 |     bash_env.put("ISABELLE_TMP", File.standard_path(isabelle_tmp))
 | 
| 123 |     bash_env.put("POLYSTATSDIR", isabelle_tmp.getAbsolutePath)
 | |
| 124 | ||
| 79656 
10e560f2f580
more robust default: Scala imposes explicit "threads" value on ML, both the Poly/ML RTS and Isabelle/ML;
 wenzelm parents: 
79654diff
changeset | 125 |     val process_policy = ml_options.string("process_policy")
 | 
| 77480 | 126 | val process_prefix = if_proper(process_policy, process_policy + " ") | 
| 77320 | 127 | |
| 77482 | 128 | Bash.process(process_prefix + "\"$POLYML_EXE\" -q " + Bash.strings(bash_args), | 
| 62614 | 129 | cwd = cwd, | 
| 73897 | 130 | env = bash_env, | 
| 62614 | 131 | redirect = redirect, | 
| 75394 | 132 |       cleanup = { () =>
 | 
| 133 | isabelle_process_options.delete | |
| 134 | init_session.delete | |
| 135 | Isabelle_System.rm_tree(isabelle_tmp) | |
| 136 | cleanup() | |
| 137 | }) | |
| 62544 | 138 | } | 
| 62586 | 139 | |
| 140 | ||
| 62835 
1a9ce1b13b20
prefer internal tool -- assuming that ISABELLE_TMP_PREFIX is created properly by Isabelle_System.isabelle_tmp_prefix;
 wenzelm parents: 
62712diff
changeset | 141 | /* Isabelle tool wrapper */ | 
| 62586 | 142 | |
| 72763 | 143 |   val isabelle_tool = Isabelle_Tool("process", "raw ML process (batch mode)",
 | 
| 75394 | 144 | Scala_Project.here, | 
| 145 |     { args =>
 | |
| 146 | var dirs: List[Path] = Nil | |
| 147 | var eval_args: List[String] = Nil | |
| 148 |       var logic = Isabelle_System.getenv("ISABELLE_LOGIC")
 | |
| 149 | var modes: List[String] = Nil | |
| 150 | var options = Options.init() | |
| 62586 | 151 | |
| 75394 | 152 |       val getopts = Getopts("""
 | 
| 62634 
aa3b47b32100
less physical "logic" argument, with option -l like "isabelle console" etc.;
 wenzelm parents: 
62633diff
changeset | 153 | Usage: isabelle process [OPTIONS] | 
| 62586 | 154 | |
| 155 | Options are: | |
| 62677 | 156 | -T THEORY load theory | 
| 62639 | 157 | -d DIR include session directory | 
| 62586 | 158 | -e ML_EXPR evaluate ML expression on startup | 
| 159 | -f ML_FILE evaluate ML file on startup | |
| 62634 
aa3b47b32100
less physical "logic" argument, with option -l like "isabelle console" etc.;
 wenzelm parents: 
62633diff
changeset | 160 | -l NAME logic session name (default ISABELLE_LOGIC=""" + quote(logic) + """) | 
| 62586 | 161 | -m MODE add print mode for output | 
| 162 | -o OPTION override Isabelle system OPTION (via NAME=VAL or NAME) | |
| 163 | ||
| 62634 
aa3b47b32100
less physical "logic" argument, with option -l like "isabelle console" etc.;
 wenzelm parents: 
62633diff
changeset | 164 | Run the raw Isabelle ML process in batch mode. | 
| 62586 | 165 | """, | 
| 75394 | 166 | "T:" -> (arg => | 
| 167 |           eval_args = eval_args ::: List("--eval", "use_thy " + ML_Syntax.print_string_bytes(arg))),
 | |
| 168 | "d:" -> (arg => dirs = dirs ::: List(Path.explode(arg))), | |
| 169 |         "e:" -> (arg => eval_args = eval_args ::: List("--eval", arg)),
 | |
| 170 |         "f:" -> (arg => eval_args = eval_args ::: List("--use", arg)),
 | |
| 171 | "l:" -> (arg => logic = arg), | |
| 172 | "m:" -> (arg => modes = arg :: modes), | |
| 173 | "o:" -> (arg => options = options + arg)) | |
| 62586 | 174 | |
| 75394 | 175 | val more_args = getopts(args) | 
| 176 | if (args.isEmpty || more_args.nonEmpty) getopts.usage() | |
| 62586 | 177 | |
| 78178 | 178 | val store = Store(options) | 
| 76657 | 179 | val session_background = Sessions.background(options, logic, dirs = dirs).check_errors | 
| 77414 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 180 | val session_heaps = ML_Process.session_heaps(store, session_background, logic = logic) | 
| 75394 | 181 | val result = | 
| 77414 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 182 | ML_Process(options, session_background, session_heaps, args = eval_args, modes = modes) | 
| 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77413diff
changeset | 183 | .result( | 
| 75394 | 184 | progress_stdout = Output.writeln(_, stdout = true), | 
| 185 | progress_stderr = Output.writeln(_)) | |
| 72557 | 186 | |
| 75394 | 187 | sys.exit(result.rc) | 
| 188 | }) | |
| 62544 | 189 | } |