From e0d75707520e74b36e9b4bccac342feab138c1db Mon Sep 17 00:00:00 2001 From: Rudi Grinberg Date: Fri, 6 Apr 2018 11:39:25 +0800 Subject: [PATCH] Do not run compiled programs to extract #define's Running a program to extract a #define value doesn't work in a cross compilation environment. Nevertheless, we can extract #define constants by invoking the preprocessor directly using the -E flag and doing some parsing to extract values. As a consequence, we now ignore the link_flags argument. As we're not going to be linking any executables. We aren't removing the argument altogether since it's technically a breaking change. The user will instead see a deprecation warning when ~link_flags is provided. --- src/configurator/v1.ml | 87 +++++++++++++++++++++++++++++++---------- src/configurator/v1.mli | 2 +- 2 files changed, 67 insertions(+), 22 deletions(-) diff --git a/src/configurator/v1.ml b/src/configurator/v1.ml index c1782f41..0373a4f7 100644 --- a/src/configurator/v1.ml +++ b/src/configurator/v1.ml @@ -263,6 +263,36 @@ let compile_c_prog t ?(c_flags=[]) ?(link_flags=[]) code = in if ok then Ok exe_fname else Error () +let pp_c_prog t ?(c_flags=[]) code = + let c_flags = "-E" :: c_flags in + let dir = t.dest_dir ^/ sprintf "c-test-%d" (gen_id t) in + Unix.mkdir dir 0o777; + let base = dir ^/ "test" in + let c_fname = base ^ ".c" in + Io.write_file c_fname code; + logf t "preprocessing c program:"; + List.iter (String.split_lines code) ~f:(logf t " | %s"); + let run_ok args = + try + Ok ( + run_capture_exn t ~dir + (String.concat ~sep:" " + (t.c_compiler :: List.map args ~f:Filename.quote)) + ) + with e -> + Error e + in + if need_to_compile_and_link_separately t then + run_ok (c_flags @ ["-I"; t.stdlib_dir; "-c"; c_fname]) + else + run_ok + (List.concat + [ c_flags + ; [ "-I"; t.stdlib_dir + ; c_fname + ] + ]) + let c_test t ?c_flags ?link_flags code = match compile_c_prog t ?c_flags ?link_flags code with | Ok _ -> true @@ -284,42 +314,57 @@ module C_define = struct end let import t ?prelude ?c_flags ?link_flags ~includes vars = + Option.iter link_flags ~f:(fun link_flags -> + Format.eprintf + "Configurator.C_define.import: link_flags argument is always ignored@.\ + ~link_flags:[%a]" + (Format.pp_print_list + ~pp_sep:(fun fmt () -> Format.fprintf fmt " ;@,") + (fun fmt s -> Format.fprintf fmt "%S" s)) link_flags + ); let buf = Buffer.create 1024 in let pr fmt = Printf.bprintf buf (fmt ^^ "\n") in + let prefix = "--- configurator " in + let pr_cfg fmt = + Buffer.add_string buf prefix; + Printf.bprintf buf (fmt ^^ "\n") in let includes = "stdio.h" :: includes in List.iter includes ~f:(pr "#include <%s>"); pr ""; Option.iter prelude ~f:(pr "%s"); - pr "int main()"; - pr "{"; List.iter vars ~f:(fun (name, (kind : Type.t)) -> match kind with | Switch -> pr {|#if defined(%s)|} name; - pr {| printf("%s=b:true\n");|} name; + pr_cfg "%S=b:true" name; pr {|#else|}; - pr {| printf("%s=b:false\n");|} name; + pr_cfg "%S=b:false" name; pr {|#endif|} | Int -> - pr {| printf("%s=i:%%d\n", %s);|} name name + pr_cfg "%S=i:%s" name name; | String -> - pr {| printf("%s=s:%%s\n", %s);|} name name); - pr " return 0;"; - pr "}"; + pr_cfg "%S=s:%s" name name); let code = Buffer.contents buf in - match compile_c_prog t ?c_flags ?link_flags code with - | Error () -> die "failed to compile program" - | Ok exe -> - run_capture_exn t ~dir:(Filename.dirname exe) (command_line exe []) - |> String.split_lines - |> List.map ~f:(fun s -> - let var, data = String.lsplit2_exn s ~on:'=' in - (var, - match String.lsplit2_exn data ~on:':' with - | "b", s -> Value.Switch (bool_of_string s) - | "i", s -> Int (int_of_string s) - | "s", s -> String s - | _ -> assert false)) + match pp_c_prog t ?c_flags code with + | Error _ -> die "failed to compile program" + | Ok pped_lines -> + String.split_lines pped_lines + |> List.filter_map ~f:(fun l -> + try + Scanf.sscanf l "--- configurator %S=%[ibs]:%s" (fun name typ v -> + Some ( + ( name + , match typ with + | "b" -> Value.Switch (bool_of_string v) + | "i" -> Int (int_of_string v) + | "s" -> String v + | _ -> assert false) + ) + ) + with + | End_of_file + | Scanf.Scan_failure _ -> None + ) let gen_header_file t ~fname ?protection_var vars = let protection_var = diff --git a/src/configurator/v1.mli b/src/configurator/v1.mli index 28c59383..65abf615 100644 --- a/src/configurator/v1.mli +++ b/src/configurator/v1.mli @@ -48,7 +48,7 @@ module C_define : sig (** Define extra code be used with extracting values below. Note that the compiled code is never executed. *) -> ?c_flags: string list - -> ?link_flags:string list + -> ?link_flags:string list (** @deprecated, this argument is ignored *) -> includes: string list -> (string * Type.t ) list -> (string * Value.t) list