1(*quietdec := true;
2app load ["Mosml", "Process", "Path", "FileSys", "Timer", "Real", "Int",
3          "Bool", "OS"] ;
4open Mosml;
5*)
6val _ = PolyML.Compiler.prompt1:="";
7val _ = PolyML.Compiler.prompt2:="";
8val _ = PolyML.print_depth 0;
9
10(* utility functions *)
11fun warn s = TextIO.output(TextIO.stdErr, s ^ "\n")
12fun die s = (TextIO.output(TextIO.stdErr, s ^ "\n");
13             OS.Process.exit OS.Process.failure)
14
15val _ = if PolyML.Compiler.compilerVersionNumber < 551 then
16          die "Must be running PolyML with version >= 5.5.1\n"
17        else ()
18
19fun readdir s = let
20  val ds = OS.FileSys.openDir s
21  fun recurse acc =
22      case OS.FileSys.readDir ds of
23        NONE => acc
24      | SOME s => recurse (s::acc)
25in
26  recurse [] before OS.FileSys.closeDir ds
27end;
28
29fun mem x [] = false
30  | mem x (h::t) = x = h orelse mem x t
31
32fun frontlast [] = raise Fail "frontlast: failure"
33  | frontlast [h] = ([], h)
34  | frontlast (h::t) = let val (f,l) = frontlast t in (h::f, l) end;
35
36fun check_dir nm privs candidate = let
37  open OS.FileSys
38  val p = OS.Path.concat(candidate,nm)
39in
40  if access(p, privs) then SOME (OS.Path.dir (fullPath p)) else NONE
41end
42val check_poly = check_dir "poly" [OS.FileSys.A_EXEC]
43val check_libpoly = check_dir "libpolymain.a" [OS.FileSys.A_READ]
44fun check_polyc c =
45  Option.map (fn p => OS.Path.concat(p,"polyc"))
46             (check_dir "polyc" [OS.FileSys.A_EXEC] c)
47
48fun findpartial f [] = NONE
49  | findpartial f (h::t) =
50    case f h of NONE => findpartial f t | x => x
51
52(* sleeping, with an action every second *)
53fun delay limit action = let
54  fun loop cnt =
55      if cnt >= limit then ()
56      else (action cnt;
57            Posix.Process.sleep (Time.fromSeconds 1);
58            loop (cnt + 1))
59in
60  loop 0
61end;
62
63fun determining s =
64    (print (s^" "); delay 1 (fn _ => ()));
65
66(* action starts here *)
67print "\nHOL smart configuration.\n\n";
68
69val poly = ""
70val polyc = NONE : string option
71val polymllibdir = "";
72val DOT_PATH = SOME "";
73val MLTON = SOME "";
74val POLY_LDFLAGS = [] : string list;
75val POLY_LDFLAGS_STATIC = [] : string list;
76
77val _ = let
78  val override = "tools-poly/poly-includes.ML"
79in
80  if OS.FileSys.access (override, [OS.FileSys.A_READ]) then
81    (print ("[Using override file "^override^"]\n\n");
82     use override)
83  else ()
84end;
85
86print "Determining configuration parameters: ";
87
88val currentdir = OS.FileSys.getDir();
89
90fun dirify {arcs,isAbs,vol} =
91    OS.Path.toString {arcs = #1 (frontlast arcs), isAbs = isAbs, vol = vol};
92
93determining "holdir";
94
95val holdir = let
96  val cdir_files = readdir currentdir
97in
98  if mem "sigobj" cdir_files andalso mem "std.prelude" cdir_files then
99    currentdir
100  else if mem "smart-configure.sml" cdir_files andalso
101          mem "configure.sml" cdir_files
102  then dirify (OS.Path.fromString currentdir)
103  else die "\n\n*** Couldn't determine holdir; \
104            \please run me from the root HOL directory"
105end;
106
107val _ = let
108in
109  OS.FileSys.chDir (OS.Path.concat (holdir, "tools-poly"));
110  use "poly/Mosml.sml";
111  OS.FileSys.chDir currentdir
112end;
113
114val OS = let
115  val _ = determining "OS"
116  val {vol,...} = OS.Path.fromString currentdir
117in
118  if vol = "" then (* i.e. Unix *)
119    case Mosml.run "uname" ["-a"] "" of
120      Mosml.Success s => if String.isPrefix "Linux" s then
121                     "linux"
122                   else if String.isPrefix "SunOS" s then
123                     "solaris"
124                   else if String.isPrefix "Darwin" s then
125                     "macosx"
126                   else
127                     "unix"
128    | Mosml.Failure s => (print "\nRunning uname failed with message: ";
129                    print s;
130                    OS.Process.exit OS.Process.failure)
131  else "winNT"
132end
133
134fun which arg =
135  let
136    open OS.FileSys
137    val sepc = if OS = "winNT" then #";" else #":"
138    fun check p =
139      let
140        val fname = OS.Path.concat(p, arg)
141      in
142        if access (fname, [A_READ, A_EXEC]) then
143          SOME
144            (OS.Path.mkAbsolute{path = fname, relativeTo = OS.FileSys.getDir()})
145        else NONE
146      end
147  in
148    case OS.Process.getEnv "PATH" of
149        SOME path =>
150        let
151          val paths = (if OS = "winNT" then ["."] else []) @
152                      String.fields (fn c => c = sepc) path
153        in
154          findpartial check paths
155        end
156      | NONE => if OS = "winNT" then check "." else NONE
157  end
158
159val polyinstruction =
160    "Please write file tools-poly/poly-includes.ML to specify it \
161    \properly.\n\
162    \This file should include a line of the form\n\n\
163    \  val poly = \"path-to-poly\";"
164val (poly,polycopt) =
165    if poly = "" then let
166        val _ = determining "poly"
167        val nm = CommandLine.name()
168        val p as {arcs, isAbs, vol} = OS.Path.fromString nm
169        val cand =
170            if isAbs then SOME (dirify p)
171            else if length arcs > 1 then
172              SOME (OS.Path.mkAbsolute { path = dirify p,
173                                         relativeTo = OS.FileSys.getDir()})
174            else (* examine PATH variable *)
175              case OS.Process.getEnv "PATH" of
176                NONE => NONE
177              | SOME elist => let
178                  val sep = case OS of "winNT" => #";" | _ => #":"
179                  val search_these = String.fields (fn c => c = sep) elist
180                in
181                  findpartial check_poly search_these
182                end
183      in
184        case cand of
185          NONE => die
186                   ("\n\nYou ran poly on the commandline, but it doesn't seem \
187                    \to be in your PATH.\n\
188                    \I need to know where your poly executable is.\n" ^
189                    polyinstruction)
190        | SOME c => let
191          in
192            case check_poly c of
193              SOME p => (OS.Path.concat(p,"poly"), check_polyc p)
194            | NONE =>
195              die ("\n\nI tried to figure out where your poly executable is\
196                   \n\by examining your command-line.\n\
197                   \But directory "^c^
198                   "doesn't seem to contain a poly executable after \
199                   \all\n" ^
200                   polyinstruction)
201          end
202      end
203    else
204      case check_poly (OS.Path.dir poly) of
205        NONE => die ("\n\nYour overrides file specifies bogus location '"
206                     ^poly^
207                     "'\nas the location of the poly executable.\n"^
208                     polyinstruction)
209      | SOME p => (OS.Path.concat(p, "poly"), check_polyc p)
210
211val polyc =
212    case polycopt of
213        NONE => die ("Couldn't find polyc executable\n" ^ polyinstruction)
214      | SOME p => p
215
216val polylibsister = let
217  val p as {arcs,isAbs,vol} = OS.Path.fromString poly
218  val (dirname, _) = frontlast arcs
219  val (parent, probably_bin) = frontlast dirname
220  val _ = if probably_bin <> "bin" then
221            warn "\nSurprised that poly is not in a \"bin\" directory"
222          else ()
223in
224  OS.Path.toString { arcs = parent @ ["lib"], vol = vol, isAbs = isAbs }
225end
226
227val polylibinstruction =
228    "Please write file tools-poly/poly-includes.ML to specify it.\n\
229    \This file should include a line of the form\n\n\
230    \  val polymllibdir = \"path-to-dir-containing-libpolymain.a\";"
231
232val polymllibdir =
233    if polymllibdir = "" then let
234        val _ = determining "polymllibdir"
235      in
236        case check_libpoly polylibsister of
237          SOME c => c
238        | NONE => die ("\n\nLooked in poly's sister lib directory "^
239                       polylibsister ^
240                       "\nand couldn't find libpolymain.a\n" ^
241                       polylibinstruction)
242
243      end
244    else
245      case check_libpoly polymllibdir of
246        SOME c => c
247      | NONE => die ("\n\nYour overrides file specifies bogus location '"
248                     ^polymllibdir ^
249                     "'\nas the location of libpolymain.a\n" ^
250                     polylibinstruction);
251
252val DOT_PATH = if DOT_PATH = SOME "" then which "dot" else DOT_PATH;
253
254val dynlib_available = false;
255
256val MLTON = if MLTON = SOME "" then which "mlton" else MLTON;
257
258print "\n";
259
260fun verdict (prompt, value) =
261    if value = "" then
262      (print ("\n*** No value for "^prompt^
263              "!!  Write a tools-poly/poly-includes.ML file to fix this\n");
264       OS.Process.exit OS.Process.failure)
265    else
266      (print (StringCvt.padRight #" " 20 (prompt^":"));
267       print value;
268       print "\n");
269
270fun optverdict (prompt, optvalue) =
271  (print (StringCvt.padRight #" " 20 (prompt ^ ":"));
272   print (case optvalue of NONE => "NONE" | SOME p => "SOME "^p);
273   print "\n");
274
275verdict ("OS", OS);
276verdict ("poly", poly);
277verdict ("polyc", polyc);
278verdict ("polymllibdir", polymllibdir);
279verdict ("holdir", holdir);
280optverdict ("DOT_PATH", DOT_PATH);
281optverdict ("MLTON", MLTON);
282
283print "\nConfiguration will begin with above values.  If they are wrong\n";
284print "press Control-C.\n\n";
285
286delay 3
287      (fn n => print ("\rWill continue in "^Int.toString (3 - n)^" seconds."))
288      handle Interrupt => (print "\n"; OS.Process.exit OS.Process.failure);
289
290print "\n";
291
292val configfile = OS.Path.concat (OS.Path.concat (holdir, "tools-poly"), "configure.sml");
293
294
295use configfile handle Fail s => die s;
296