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.
This commit is contained in:
parent
5a89767184
commit
e0d7570752
|
@ -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 =
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue