flan/lib/build.ml

53 lines
1.8 KiB
OCaml

(** Driver: typed IR → an executable, via LLVM IR text and clang.
The release path from plan.org, Compilation:
{v flan → typed IR → .ll → clang --target={native,wasm32} v}
Not the dev path — that one never invokes the clang driver, because the
driver *is* the cost (52ms of the measured 68), and goes llc + ld -shared +
dlopen instead for ~16ms. Nothing at milestone 2 needs it yet. *)
let clang = try Sys.getenv "FLAN_CLANG" with Not_found -> "clang"
let write path contents =
let ch = open_out path in
output_string ch contents;
close_out ch
(* One temporary directory per build, so the .ll is findable by name when
something is wrong with it. *)
let workdir () =
let d =
Filename.concat (Filename.get_temp_dir_name ())
(Printf.sprintf "flan-%d" (Unix.getpid ()))
in
(try Unix.mkdir d 0o700 with Unix.Unix_error (Unix.EEXIST, _, _) -> ());
d
type opts = {
target : string option; (* None is the host; "wasm32-wasi" is the other *)
opt : string;
keep : bool; (* leave the .ll behind *)
}
let default = { target = None; opt = "-O2"; keep = false }
let executable ?(opts = default) (p : Tast.program) ~out =
let dir = workdir () in
let ll = Filename.concat dir (Filename.basename out ^ ".ll") in
let rt = Filename.concat dir "flan_rt.c" in
write ll (Emit.program p);
write rt Runtime_src.source;
let cmd =
String.concat " "
([ Filename.quote clang; opts.opt; "-Wno-override-module" ]
@ (match opts.target with None -> [] | Some t -> [ "--target=" ^ t ])
@ [ Filename.quote ll; Filename.quote rt; "-o"; Filename.quote out ])
in
let code = Sys.command cmd in
if code <> 0 then
failwith (Printf.sprintf "%s failed (exit %d); the IR is at %s" clang code ll);
if not opts.keep then (try Sys.remove ll; Sys.remove rt with Sys_error _ -> ());
out