(* *********************************************************************) (* *) (* The Compcert verified compiler *) (* *) (* Xavier Leroy, INRIA Paris-Rocquencourt *) (* *) (* Copyright Institut National de Recherche en Informatique et en *) (* Automatique. All rights reserved. This file is distributed *) (* under the terms of the GNU General Public License as published by *) (* the Free Software Foundation, either version 2 of the License, or *) (* (at your option) any later version. This file is also distributed *) (* under the terms of the INRIA Non-Commercial License Agreement. *) (* *) (* *********************************************************************) open Printf open Commandline open Clflags (* Location of the compatibility library *) let stdlib_path = ref Configuration.stdlib_path (* Invocation of external tools *) let command ?stdout args = if !option_v then begin eprintf "+ %s" (String.concat " " args); begin match stdout with | None -> () | Some f -> eprintf " > %s" f end; prerr_endline "" end; let argv = Array.of_list args in assert (Array.length argv > 0); try let fd_out = match stdout with | None -> Unix.stdout | Some f -> Unix.openfile f [Unix.O_WRONLY; Unix.O_CREAT; Unix.O_TRUNC] 0o666 in let pid = Unix.create_process argv.(0) argv Unix.stdin fd_out Unix.stderr in let (_, status) = Unix.waitpid [] pid in if stdout <> None then Unix.close fd_out; match status with | Unix.WEXITED rc -> rc | Unix.WSIGNALED n | Unix.WSTOPPED n -> eprintf "Command '%s' killed on a signal.\n" argv.(0); -1 with Unix.Unix_error(err, fn, param) -> eprintf "Error executing '%s': %s: %s %s\n" argv.(0) fn (Unix.error_message err) param; -1 let safe_remove file = try Sys.remove file with Sys_error _ -> () (* Printing of error messages *) let print_error oc msg = let print_one_error = function | Errors.MSG s -> output_string oc (Camlcoq.camlstring_of_coqstring s) | Errors.CTX i -> output_string oc (Camlcoq.extern_atom i) | Errors.POS i -> fprintf oc "%ld" (Camlcoq.P.to_int32 i) in List.iter print_one_error msg; output_char oc '\n' (* Determine names for output files. We use -o option if specified and if this is the final destination file (not a dump file). Otherwise, we generate a file in the current directory. *) let output_filename ?(final = false) source_file source_suffix output_suffix = match !option_o with | Some file when final -> file | _ -> Filename.basename (Filename.chop_suffix source_file source_suffix) ^ output_suffix (* From C to preprocessed C *) let preprocess ifile ofile = let output = if ofile = "-" then None else Some ofile in let cmd = List.concat [ Configuration.prepro; ["-D__COMPCERT__"]; (if Configuration.has_runtime_lib then ["-I" ^ !stdlib_path] else []); List.rev !prepro_options; [ifile] ] in if command ?stdout:output cmd <> 0 then begin if ofile <> "-" then safe_remove ofile; eprintf "Error during preprocessing.\n"; exit 2 end (* From preprocessed C to Csyntax *) let parse_c_file sourcename ifile = Sections.initialize(); (* Simplification options *) let simplifs = "b" (* blocks: mandatory *) ^ (if !option_fstruct_return then "s" else "") ^ (if !option_fbitfields then "f" else "") ^ (if !option_fpacked_structs then "p" else "") in (* Parsing and production of a simplified C AST *) let ast = match Parse.preprocessed_file simplifs sourcename ifile with | None -> exit 2 | Some p -> p in (* Save C AST if requested *) if !option_dparse then begin let ofile = output_filename sourcename ".c" ".parsed.c" in let oc = open_out ofile in Cprint.program (Format.formatter_of_out_channel oc) ast; close_out oc end; (* Conversion to Csyntax *) let csyntax = match Timing.time "CompCert C generation" C2C.convertProgram ast with | None -> exit 2 | Some p -> p in flush stderr; (* Save CompCert C AST if requested *) if !option_dcmedium then begin let ofile = output_filename sourcename ".c" ".compcert.c" in let oc = open_out ofile in PrintCsyntax.print_program (Format.formatter_of_out_channel oc) csyntax; close_out oc end; csyntax (* From CompCert C AST to Clight *) let compile_c_ast sourcename csyntax ofile = let clight = match SimplExpr.transl_program csyntax with | Errors.OK p -> begin match SimplLocals.transf_program p with | Errors.OK p' -> p' | Errors.Error msg -> print_error stderr msg; exit 2 end | Errors.Error msg -> print_error stderr msg; exit 2 in (* Dump Clight in C syntax if requested *) if !option_dclight then begin let ofile = Filename.chop_suffix sourcename ".c" ^ ".light.c" in let oc = open_out ofile in PrintClight.print_program (Format.formatter_of_out_channel oc) clight; close_out oc end; (* Print Clight in Coq syntax *) let oc = open_out ofile in ExportClight.print_program (Format.formatter_of_out_channel oc) clight; close_out oc (* From C source to Clight *) let compile_c_file sourcename ifile ofile = compile_c_ast sourcename (parse_c_file sourcename ifile) ofile (* Processing of a .c file *) let process_c_file sourcename = let prefixname = Filename.chop_suffix sourcename ".c" in if !option_E then begin preprocess sourcename "-" end else begin let preproname = Filename.temp_file "compcert" ".i" in preprocess sourcename preproname; compile_c_file sourcename preproname (prefixname ^ ".v") end (* Command-line parsing *) let explode_comma_option s = match Str.split (Str.regexp ",") s with | [] -> assert false | hd :: tl -> tl let usage_string = "The CompCert Clight generator Usage: clightgen [options] Recognized source files: .c C source file Processing options: -E Preprocess only, send result to standard output Preprocessing options: -I Add to search path for #include files -D= Define preprocessor symbol -U Undefine preprocessor symbol -Wp, Pass option to the preprocessor Language support options (use -fno- to turn off -f) : -fbitfields Emulate bit fields in structs [off] -flongdouble Treat 'long double' as 'double' [off] -fstruct-return Emulate returning structs and unions by value [off] -fvararg-calls Emulate calls to variable-argument functions [on] -fpacked-structs Emulate packed structs [off] -fall Activate all language support options above -fnone Turn off all language support options above Tracing options: -dparse Save C file after parsing and elaboration in .parse.c -dc Save generated Compcert C in .compcert.c -dclight Save generated Clight in .light.c General options: -v Print external commands before invoking them " let print_usage_and_exit _ = printf "%s" usage_string; exit 0 let language_support_options = [ option_fbitfields; option_flongdouble; option_fstruct_return; option_fvararg_calls; option_funprototyped; option_fpacked_structs; option_finline_asm ] let set_all opts = List.iter (fun r -> r := true) opts let unset_all opts = List.iter (fun r -> r := false) opts let cmdline_actions = let f_opt name ref = [Exact("-f" ^ name), Set ref; Exact("-fno-" ^ name), Unset ref] in [ (* Getting help *) Exact "-help", Self print_usage_and_exit; Exact "--help", Self print_usage_and_exit; (* Processing options *) Exact "-E", Set option_E; (* Preprocessing options *) Exact "-I", String(fun s -> prepro_options := s :: "-I" :: !prepro_options); Prefix "-I", Self(fun s -> prepro_options := s :: !prepro_options); Exact "-D", String(fun s -> prepro_options := s :: "-D" :: !prepro_options); Prefix "-D", Self(fun s -> prepro_options := s :: !prepro_options); Exact "-U", String(fun s -> prepro_options := s :: "-U" :: !prepro_options); Prefix "-U", Self(fun s -> prepro_options := s :: !prepro_options); Prefix "-Wp,", Self (fun s -> prepro_options := List.rev_append (explode_comma_option s) !prepro_options); (* Language support options -- more below *) Exact "-fall", Self (fun _ -> set_all language_support_options); Exact "-fnone", Self (fun _ -> unset_all language_support_options); (* Tracing options *) Exact "-dparse", Set option_dparse; Exact "-dc", Set option_dcmedium; Exact "-dclight", Set option_dclight; (* General options *) Exact "-v", Set option_v; Exact "-stdlib", String(fun s -> stdlib_path := s); ] (* -f options: come in -f and -fno- variants *) (* Language support options *) @ f_opt "longdouble" option_flongdouble @ f_opt "struct-return" option_fstruct_return @ f_opt "bitfields" option_fbitfields @ f_opt "vararg-calls" option_fvararg_calls @ f_opt "unprototyped" option_funprototyped @ f_opt "packed-structs" option_fpacked_structs @ f_opt "inline-asm" option_finline_asm @ [ (* Catch options that are not handled *) Prefix "-", Self (fun s -> eprintf "Unknown option `%s'\n" s; exit 2); (* File arguments *) Suffix ".c", Self (fun s -> process_c_file s); ] let _ = Gc.set { (Gc.get()) with Gc.minor_heap_size = 524288; (* 512k *) Gc.major_heap_increment = 4194304 (* 4M *) }; Printexc.record_backtrace true; Machine.config := begin match Configuration.arch with | "powerpc" -> Machine.ppc_32_bigendian | "arm" -> Machine.arm_littleendian | "ia32" -> Machine.x86_32 | _ -> assert false end; Builtins.set C2C.builtins; CPragmas.initialize(); parse_cmdline cmdline_actions