1quietdec := true; 2app load ["Mosml", "Process", "Path", "FileSys", "Timer", "Real", "Int", 3 "Bool", "OS", "CommandLine"] ; 4open Mosml; 5 6fun die s = (TextIO.output(TextIO.stdErr, s ^ "\n"); 7 OS.Process.exit OS.Process.failure) 8 9(* Thanks to Ken Friis Larsen for this very cute trick *) 10val version_string = 11 List.nth([], 1) handle Option => "2.01" | Subscript => "2.10"; 12 13val _ = if version_string = "2.01" then let 14 val _ = print "\n\nUsing Basis 2002 update for Moscow ML 2.01\n" 15 val _ = app load ["CharVector", "Math", "ListPair"] 16 infix ++ val op++ = OS.Path.concat 17 in 18 use ("tools" ++ "Holmake" ++ "basis2002.sml") 19 end 20 else (); 21 22structure FileSys = OS.FileSys 23structure Process = OS.Process 24structure Path = OS.Path 25 26(* utility functions *) 27fun readdir s = let 28 val ds = FileSys.openDir s 29 fun recurse acc = 30 case FileSys.readDir ds of 31 NONE => acc 32 | SOME s => recurse (s::acc) 33in 34 recurse [] before FileSys.closeDir ds 35end; 36 37fun mem x [] = false 38 | mem x (h::t) = x = h orelse mem x t 39 40fun frontlast [] = raise Fail "frontlast: failure" 41 | frontlast [h] = ([], h) 42 | frontlast (h::t) = let val (f,l) = frontlast t in (h::f, l) end; 43 44(* returns a function of type unit -> int, which returns time elapsed in 45 seconds since the call to start_timer() *) 46fun start_timer() = let 47 val timer = Timer.startRealTimer() 48in 49 fn () => let 50 val time_now = Timer.checkRealTimer timer 51 in 52 Real.floor (Time.toReal time_now) 53 end handle Time.Time => 0 54end 55 56(* busy loop sleeping *) 57fun delay limit action = let 58 val timer = start_timer() 59 fun loop last = let 60 val elapsed = timer() 61 in 62 if elapsed = last then loop last 63 else (action elapsed; if elapsed >= limit then () else loop elapsed) 64 end 65in 66 action 0; loop 0 67end; 68 69fun determining s = 70 (print (s^" "); delay 1 (fn _ => ())); 71 72(* action starts here *) 73print "\nHOL smart configuration.\n\n"; 74 75print "Determining configuration parameters: "; 76determining "OS"; 77 78val currentdir = FileSys.getDir() 79 80val OS = let 81 val {vol,...} = Path.fromString currentdir 82in 83 if vol = "" then (* i.e. Unix *) 84 case Mosml.run "uname" ["-a"] "" of 85 Success s => if String.isPrefix "Linux" s then 86 "linux" 87 else if String.isPrefix "SunOS" s then 88 "solaris" 89 else if String.isPrefix "Darwin" s then 90 "macosx" 91 else 92 "unix" 93 | Failure s => (print "\nRunning uname failed with message: "; 94 print s; 95 Process.exit Process.failure) 96 else "winNT" 97end; 98 99fun findpartial f [] = NONE 100 | findpartial f (h::t) = 101 case f h of NONE => findpartial f t | x => x 102 103fun which arg = 104 let 105 open OS.FileSys 106 val sepc = if OS = "winNT" then #";" else #":" 107 fun check p = 108 let 109 val fname = OS.Path.concat(p, arg) 110 in 111 if access (fname, [A_READ, A_EXEC]) then 112 SOME 113 (OS.Path.mkAbsolute{path = fname, relativeTo = OS.FileSys.getDir()}) 114 else NONE 115 end 116 in 117 case OS.Process.getEnv "PATH" of 118 SOME path => 119 let 120 val paths = (if OS = "winNT" then ["."] else []) @ 121 String.fields (fn c => c = sepc) path 122 in 123 findpartial check paths 124 end 125 | NONE => if OS = "winNT" then check "." else NONE 126 end 127 128val exe_ext = if OS = "winNT" then ".exe" else ""; 129determining "mosmldir"; 130 131fun check_mosml candidate = let 132 open FileSys 133in 134 access(Path.concat(candidate,"mosml"^exe_ext), [A_EXEC]) 135end 136 137fun mosml_from_loadpath () = let 138 val libdir = hd (!Meta.loadPath) 139 val () = print ("\nMosml library directory (from loadPath) is "^libdir) 140 val {arcs, isAbs, vol} = Path.fromString libdir 141 val _ = isAbs orelse 142 (print "\n\n*** ML library directory not specified with absolute"; 143 print "filename --- aborting\n"; 144 Process.exit Process.failure) 145 val arcs = case frontlast arcs of 146 (arcs, "lib") => arcs 147 | ([], ult) => [ult] 148 | (arcs,"mosml") => (* default since 2.10 *) 149 let val (arcs', pen) = frontlast arcs in 150 (if pen = "lib" then arcs' else arcs) 151 end 152 | (arcs, _) => 153 (print "\nMosml library directory (from loadPath) not .../lib -- weird!\n"; 154 arcs) 155 val candidate = 156 Path.toString {arcs = arcs @ ["bin"], isAbs = true, vol = vol} 157 val _ = print ("\nUsing "^candidate^" for mosml directory (from loadPath)\n") 158in 159 if check_mosml candidate then candidate 160 else (print "\nCan't find mosml -- hope you have it in a \ 161 \config-override file\n"; 162 "") 163end; 164 165fun dirify {arcs,isAbs,vol} = 166 OS.Path.toString {arcs = #1 (frontlast arcs), isAbs = isAbs, vol = vol} 167 168 169val mosmldir = let 170 val nm = CommandLine.name() 171 val p as {arcs, isAbs, vol} = OS.Path.fromString nm 172 val cand = 173 if isAbs then SOME (dirify p) 174 else if length arcs > 1 then 175 SOME (Path.mkAbsolute {path = dirify p, 176 relativeTo = OS.FileSys.getDir()}) 177 else (* examine PATH variable *) 178 case OS.Process.getEnv "PATH" of 179 NONE => NONE 180 | SOME elist => let 181 val sep = case OS of "winNT" => #";" | _ => #":" 182 val search_these = String.fields (fn c => c = sep) elist 183 in 184 List.find check_mosml search_these 185 end 186in 187 case cand of 188 NONE => mosml_from_loadpath () 189 | SOME c => if check_mosml c then c else mosml_from_loadpath () 190end; 191 192determining "holdir"; 193 194val holdir = let 195 val cdir_files = readdir currentdir 196in 197 if mem "sigobj" cdir_files andalso mem "std.prelude" cdir_files then 198 currentdir 199 else if mem "smart-configure.sml" cdir_files andalso 200 mem "configure.sml" cdir_files 201 then let 202 val {arcs, isAbs, vol} = Path.fromString currentdir 203 val (arcs', _) = frontlast arcs 204 in 205 Path.toString {arcs = arcs', isAbs = isAbs, vol = vol} 206 end 207 else (print "\n\n*** Couldn't determine holdir; "; 208 print "please run me from the root HOL directory\n"; 209 Process.exit Process.failure) 210end; 211 212determining "dynlib_available"; 213 214val dynlib_available = (load "Dynlib"; true) handle _ => false; 215 216print "\n"; 217 218val DOT_PATH = SOME ""; 219 220val _ = let 221 val override = Path.concat(holdir, "config-override") 222in 223 if FileSys.access (override, [FileSys.A_READ]) then 224 (print "\n[Using override file!]\n\n"; 225 use override) 226 else () 227end; 228 229val DOT_PATH = if DOT_PATH = SOME "" then which "dot" else DOT_PATH; 230 231fun verdict (prompt, value) = 232 (print (StringCvt.padRight #" " 20 (prompt^":")); 233 print value; 234 print "\n"); 235 236fun optverdict (prompt, optvalue) = 237 (print (StringCvt.padRight #" " 20 (prompt ^ ":")); 238 print (case optvalue of NONE => "NONE" | SOME p => "SOME "^p); 239 print "\n"); 240 241verdict ("OS", OS); 242verdict ("mosmldir", mosmldir); 243verdict ("holdir", holdir); 244verdict ("dynlib_available", Bool.toString dynlib_available); 245optverdict ("DOT_PATH", DOT_PATH); 246 247val _ = let 248 val mosml' = if OS = "winNT" then "mosmlc.exe" else "mosmlc" 249in 250 if FileSys.access (Path.concat(mosmldir, mosml'), [FileSys.A_EXEC]) then 251 () 252 else (print ("\nCouldn't find executable mosmlc in "^mosmldir^"\n"); 253 print ("Giving up - please use config-override file to fix\n"); 254 Process.exit Process.failure) 255end; 256 257print "\nConfiguration will begin with above values. If they are wrong\n"; 258print "press Control-C.\n\n"; 259 260delay 3 261 (fn n => print ("\rWill continue in "^Int.toString (3 - n)^" seconds.")) 262 handle Interrupt => (print "\n"; Process.exit Process.failure); 263 264print "\n"; 265 266val configfile = Path.concat (Path.concat (holdir, "tools"), "configure.sml"); 267 268 269use configfile; 270