let command string =
  match Sys.command string with
  | 0 -> ()
  | _ as exit_code ->
      Format.eprintf "Command '%s' failed with exit code %d" string exit_code

let link_file (input_file : string) (output_file : string) (stdlib_dir : string)
    (compile_flags : string list) (stdlib_file : string)
    (target : string option) =
  (* args *)
  let target_args =
    match target with Some t -> [ "-target"; t ] | None -> []
  in
  (* compile stdlib *)
  let stdlib_basename = Filename.basename stdlib_file in
  let stdlib_file = Filename.concat stdlib_dir stdlib_file in
  let compiled_stdlib_file =
    Filename.concat
      (Filename.dirname input_file)
      (Filename.remove_extension stdlib_basename ^ ".ll")
  in
  let compile_stdlib_cmd =
    Filename.quote_command "clang"
      ([ stdlib_file; "-o"; compiled_stdlib_file; "-S"; "-emit-llvm" ]
      @ compile_flags @ target_args)
  in
  Format.printf "%s\n%!" compile_stdlib_cmd;
  command compile_stdlib_cmd;
  (* compile file with flags *)
  let base_file = Filename.remove_extension input_file in
  (* link file *)
  let linked_file = base_file ^ ".linked.ll" in
  let link_cmd =
    Filename.quote_command "llvm-link"
      [ compiled_stdlib_file; input_file; "-o"; linked_file; "-S" ]
  in
  Format.printf "%s\n%!" link_cmd;
  command link_cmd;
  (* compile the linked file to native code *)
  let compile_link_cmd =
    Filename.quote_command "clang"
      ([ linked_file; "-o"; output_file ] @ compile_flags @ target_args)
  in
  Format.printf "%s\n%!" compile_link_cmd;
  command compile_link_cmd
