dune/src/utils.ml

215 lines
5.7 KiB
OCaml

open Import
let system_shell_exn =
let cmd, arg, os =
if Sys.win32 then
("cmd", "/c", "on Windows")
else
("sh", "-c", "")
in
let bin = lazy (Bin.which cmd) in
fun ~needed_to ->
match Lazy.force bin with
| Some path -> (path, arg)
| None ->
die "I need %s to %s but I couldn't find it :(\n\
Who doesn't have %s%s?!"
cmd needed_to cmd os
let bash_exn =
let bin = lazy (Bin.which "bash") in
fun ~needed_to ->
match Lazy.force bin with
| Some path -> path
| None ->
die "I need bash to %s but I couldn't find it :("
needed_to
let signal_name =
let table =
let open Sys in
[ sigabrt , "ABRT"
; sigalrm , "ALRM"
; sigfpe , "FPE"
; sighup , "HUP"
; sigill , "ILL"
; sigint , "INT"
; sigkill , "KILL"
; sigpipe , "PIPE"
; sigquit , "QUIT"
; sigsegv , "SEGV"
; sigterm , "TERM"
; sigusr1 , "USR1"
; sigusr2 , "USR2"
; sigchld , "CHLD"
; sigcont , "CONT"
; sigstop , "STOP"
; sigtstp , "TSTP"
; sigttin , "TTIN"
; sigttou , "TTOU"
; sigvtalrm , "VTALRM"
; sigprof , "PROF"
(* These ones are only available in OCaml >= 4.03 *)
; -22 , "BUS"
; -23 , "POLL"
; -24 , "SYS"
; -25 , "TRAP"
; -26 , "URG"
; -27 , "XCPU"
; -28 , "XFSZ"
]
in
fun n ->
match List.assoc n table with
| exception Not_found -> sprintf "%d\n" n
| s -> s
let jbuild_name_in ~dir =
match Path.extract_build_context dir with
| None ->
Path.to_string_maybe_quoted (Path.relative dir "jbuild")
| Some (ctx_name, dir) ->
sprintf "%s (context %s)"
(Path.to_string_maybe_quoted (Path.relative dir "jbuild"))
ctx_name
let describe_target fn =
match Path.extract_build_context fn with
| Some (".aliases", fn) ->
let name =
let fn = Path.to_string fn in
match String.rsplit2 fn ~on:'-' with
| None -> assert false
| Some (name, digest) ->
assert (String.length digest = 32);
name
in
sprintf "alias %s" (maybe_quoted name)
| _ ->
Path.to_string_maybe_quoted fn
let program_not_found ?context ?(in_the_tree=false) ?hint prog =
die "@{<error>Error@}: Program %s not found in%s PATH%s%a" (maybe_quoted prog)
(if in_the_tree then
" the tree or in"
else
"")
(match context with
| None -> ""
| Some name -> sprintf " (context: %s)" name)
(fun fmt -> function
| None -> ()
| Some h -> Format.fprintf fmt "@ Hint: %s" h)
hint
let library_not_found ?context ?hint lib =
die "@{<error>Error@}: Library %s not found%s%a" (maybe_quoted lib)
(match context with
| None -> ""
| Some name -> sprintf " (context: %s)" name)
(fun fmt -> function
| None -> ()
| Some h -> Format.fprintf fmt "@ Hint: %s" h)
hint
let g () =
if !Clflags.g then
["-g"]
else
[]
let find_module ~dir modules name =
String_map.find_exn name modules
~string_of_key:(sprintf "%S")
~desc:(fun _ ->
sprintf "<module name to module info in %s>"
(Path.to_string_maybe_quoted dir))
let find_deps ~dir dep_graph name =
String_map.find_exn name dep_graph
~string_of_key:(sprintf "%S")
~desc:(fun _ -> sprintf "<dependency graph in %s>"
(Path.to_string_maybe_quoted dir))
let obj_name_of_basename fn =
match String.index fn '.' with
| None -> fn
| Some i -> String.sub fn ~pos:0 ~len:i
module Cached_digest = struct
type file =
{ mutable digest : Digest.t
; mutable timestamp : float
; mutable timestamp_checked : bool
}
let cache = Hashtbl.create 1024
let file fn =
match Hashtbl.find cache fn with
| Some x ->
if x.timestamp_checked then
x.digest
else begin
let mtime = (Unix.stat (Path.to_string fn)).st_mtime in
if mtime <> x.timestamp then begin
let digest = Digest.file (Path.to_string fn) in
x.digest <- digest;
x.timestamp <- mtime;
end;
x.timestamp_checked <- true;
x.digest
end
| None ->
let digest = Digest.file (Path.to_string fn) in
Hashtbl.add cache ~key:fn
~data:{ digest
; timestamp = (Unix.stat (Path.to_string fn)).st_mtime
; timestamp_checked = true
};
digest
let remove fn =
match Hashtbl.find cache fn with
| None -> ()
| Some file -> file.timestamp_checked <- false
let db_file = "_build/.digest-db"
let dump () =
let module Pmap = Path.Map in
let sexp =
Sexp.List (
Hashtbl.fold cache ~init:Pmap.empty ~f:(fun ~key ~data acc ->
Pmap.add acc ~key ~data)
|> Path.Map.bindings
|> List.map ~f:(fun (path, file) ->
Sexp.List [ Atom (Path.to_string path)
; Atom (Digest.to_hex file.digest)
; Atom (Int64.to_string (Int64.bits_of_float file.timestamp))
]))
in
if Sys.file_exists "_build" then
Io.write_file db_file (Sexp.to_string sexp)
let load () =
if Sys.file_exists db_file then begin
let sexp = Sexp_lexer.Load.single db_file in
let bindings =
let open Sexp.Of_sexp in
list
(triple
Path.t
(fun s -> Digest.from_hex (string s))
(fun s -> Int64.float_of_bits (Int64.of_string (string s)))
) sexp
in
List.iter bindings ~f:(fun (path, digest, timestamp) ->
Hashtbl.add cache ~key:path
~data:{ digest
; timestamp
; timestamp_checked = false
});
end
end