Commit 0a154cfa authored by Erwan Jahier's avatar Erwan Jahier
Browse files

Update the lus2lic plugin.

parent 9b7c23af
......@@ -487,15 +487,8 @@ let usage_out = Util.usage_out
(***********************************************************************)
let rec speclist =
[
"--reactive-program", Arg.String (fun str -> parse_rp_string str),
"<string>.";
"-rp", Arg.String (fun str -> parse_rp_string str),
("<string> " ^ rp_help);
"--sut", Arg.String
let old_speclist = [
"--sut", Arg.String
(fun file -> args.sut <- file),
"<string>\tFile name of the system under test [works with --old-mode only!].";
"-sut", Arg.String
......@@ -569,6 +562,19 @@ let rec speclist =
),
"<string> (lv4, lv6, or scade)\t Compiler used for the oracle [works with --old-mode only!].";
"--direct", Arg.Unit (fun () -> args.direct_mode <- true),
"\tSet the direct mode.\n" ;
"--old-mode", Arg.Unit (fun () -> args.direct_mode <- false),
"\tUnset the direct mode.\n"
]
let rec speclist =
[
"--reactive-program", Arg.String (fun str -> parse_rp_string str),
"<string>.";
"-rp", Arg.String (fun str -> parse_rp_string str),
("<string> " ^ rp_help);
"--cov-file", Arg.String (fun s -> args.cov_file <- s),
"<string>\tfile name coverage info will be put into";
......@@ -769,10 +775,6 @@ let rec speclist =
"--no-local-var", Arg.Unit (fun () -> args.display_local_var <- false),
"\tDo not display environment local variables in sim2chro.\n" ;
"--direct", Arg.Unit (fun () -> args.direct_mode <- true),
"\tSet the direct mode.\n" ;
"--old-mode", Arg.Unit (fun () -> args.direct_mode <- false),
"\tUnset the direct mode.\n" ;
"--ocaml-version", Arg.Unit (fun _ -> (print_string (Sys.ocaml_version) ; exit 0)),
"\t\tDisplay the version ocaml version lurette was compiled with and exit." ;
......
(* Time-stamp: <modified the 08/07/2015 (at 17:53) by Erwan Jahier> *)
(* Time-stamp: <modified the 18/09/2015 (at 15:45) by Erwan Jahier> *)
open Lxm
open Lv6errors
......@@ -14,10 +14,10 @@ let info msg =
let (doit : Lv6MainArgs.t -> AstV6.pack_or_model list -> Lv6Id.idref option -> LicPrg.t) =
fun opt srclist main_node ->
(* let t0 = Sys.time() in *)
info "Start compiling to lic...\n";
let syntax_tab = AstTab.create srclist in
(* Pour chaque package, on a un solveur de rfrences
(* let t0 = Sys.time() in *)
info "Start compiling to lic...\n";
let syntax_tab = AstTab.create srclist in
(* Pour chaque package, on a un solveur de rfrences
globales, pour les types, const et node :
- les rfrences pointes (p::n) sont recherches
directement dans la syntax_tab puisqu'il n'y a pas
......@@ -26,48 +26,49 @@ let (doit : Lv6MainArgs.t -> AstV6.pack_or_model list -> Lv6Id.idref option -> L
. dans le pack lui-mme
. dans un des packs dclars "uses", avec
priorit dans l'ordre
*)
*)
let lic_tab = LicTab.create syntax_tab in
Verbose.exe ~flag:dbg (fun () -> AstTab.dump syntax_tab);
let lic_tab = LicTab.create syntax_tab in
Verbose.exe ~flag:dbg (fun () -> AstTab.dump syntax_tab);
info "Compiling into lic...\n";
let lic_tab = match main_node with
| None -> LicTab.compile_all lic_tab
| Some main_node ->
if opt.Lv6MainArgs.compile_all_items then
LicTab.compile_all lic_tab
else
LicTab.compile_node lic_tab main_node
in
info "Converting to lic_prg...\n";
let zelic = LicTab.to_lic_prg lic_tab in
info "Compiling into lic...\n";
let lic_tab = match main_node with
| None -> LicTab.compile_all lic_tab
| Some main_node ->
if opt.Lv6MainArgs.compile_all_items then
LicTab.compile_all lic_tab
else
LicTab.compile_node lic_tab main_node
in
info "Converting to lic_prg...\n";
let zelic = LicTab.to_lic_prg lic_tab in
if opt.Lv6MainArgs.print_interface then zelic else (
info "Check safety and memory declarations...\n";
if Lv6MainArgs.global_opt.Lv6MainArgs.kcg then
L2lCheckKcgKeyWord.doit zelic
else
L2lCheckMemSafe.doit zelic;
L2lCheckKcgKeyWord.doit zelic
else
L2lCheckMemSafe.doit zelic;
let zelic =
if not opt.Lv6MainArgs.optim_ite then zelic else (
info "Optimizing if/then/else...\n";
L2lOptimIte.doit zelic)
in
let zelic =
(* limination polymorphisme surcharge *)
(* limination polymorphisme surcharge *)
info "Removing polymorphism...\n";
L2lRmPoly.doit zelic
in
let zelic = if not opt.Lv6MainArgs.inline_iterator then zelic else (
info "Inlining iterators...\n";
(* to be done before array expansion otherwise they won't be expanded *)
L2lExpandMetaOp.doit zelic
)
info "Inlining iterators...\n";
(* to be done before array expansion otherwise they won't be expanded *)
L2lExpandMetaOp.doit zelic
)
in
let zelic =
if Lv6MainArgs.global_opt.Lv6MainArgs.kcg && not opt.Lv6MainArgs.inline_iterator then
L2lExpandMetaOp.doit_boolred zelic
L2lExpandMetaOp.doit_boolred zelic
else
zelic
zelic
in
let zelic =
if
......@@ -85,12 +86,12 @@ let (doit : Lv6MainArgs.t -> AstV6.pack_or_model list -> Lv6Id.idref option -> L
if opt.Lv6MainArgs.expand_node_call <> [] || opt.Lv6MainArgs.expand_nodes then (
let mn:Lv6Id.idref =
match main_node with
| None ->
(match LicPrg.choose_node zelic with
| None -> assert false
| Some(nk,_) -> Lv6Id.idref_of_long (fst nk)
)
| Some mn -> mn
| None ->
(match LicPrg.choose_node zelic with
| None -> assert false
| Some(nk,_) -> Lv6Id.idref_of_long (fst nk)
)
| Some mn -> mn
in
let ids_to_expand = (List.map Lv6Id.idref_of_string opt.Lv6MainArgs.expand_node_call) in
let long_match_idref (p,n) idref =
......@@ -101,14 +102,14 @@ let (doit : Lv6MainArgs.t -> AstV6.pack_or_model list -> Lv6Id.idref option -> L
let nodes_to_keep: Lic.node_key list =
LicPrg.fold_nodes
(fun (long,sargs) _ acc ->
if opt.Lv6MainArgs.expand_nodes then
(if long_match_idref long mn then (long,sargs)::acc else acc)
else if
List.exists (long_match_idref long) ids_to_expand
then
acc
else
(long,sargs)::acc
if opt.Lv6MainArgs.expand_nodes then
(if long_match_idref long mn then (long,sargs)::acc else acc)
else if
List.exists (long_match_idref long) ids_to_expand
then
acc
else
(long,sargs)::acc
)
zelic
[]
......@@ -124,8 +125,8 @@ let (doit : Lv6MainArgs.t -> AstV6.pack_or_model list -> Lv6Id.idref option -> L
(* Array and struct expansion: to do after polymorphism elimination
and after node expansion *)
let zelic = if not opt.Lv6MainArgs.expand_arrays then zelic else (
info "Expanding arrays...\n";
L2lExpandArrays.doit zelic)
info "Expanding arrays...\n";
L2lExpandArrays.doit zelic)
in
(* alias des types array XXX fait partir lic2soc en boucle
cause des soc key qui ne sont plus cohrentes entre elles
......@@ -134,7 +135,7 @@ let (doit : Lv6MainArgs.t -> AstV6.pack_or_model list -> Lv6Id.idref option -> L
info "Aliasing arrays...\n";
let zelic = L2lAliasType.doit zelic in
*)
*)
(* Currently only works in this mode *)
if Lv6MainArgs.global_opt.Lv6MainArgs.ec then (
info "Check loops...\n";
......@@ -144,7 +145,7 @@ let (doit : Lv6MainArgs.t -> AstV6.pack_or_model list -> Lv6Id.idref option -> L
L2lCheckOutputs.doit zelic;
info "Lic Compilation done!\n";
zelic
)
let test_lex ( lexbuf ) = (
let tk = ref (Lv6lexer.lexer lexbuf) in
......
(** Time-stamp: <modified the 15/01/2015 (at 13:38) by Erwan Jahier> *)
(** Time-stamp: <modified the 09/09/2015 (at 11:23) by Erwan Jahier> *)
val f: LicPrg.t -> Lic.node_key -> Soc.key * Soc.tbl
......@@ -9,3 +9,5 @@ exception Polymorphic
(* raises the Polymorphic exception if Lic.type_ is polymorphic *)
val lic_to_data_type: Lic.type_ -> Data.t
val soc_profile_of_node: Lic.node_exp -> Soc.var list * Soc.var list
......@@ -102,7 +102,6 @@ let token_code tk = (
| TK_EQ lxm -> ("TK_EQ" , lxm)
| TK_ENUM lxm -> ("TK_ENUM" , lxm)
| TK_FALSE lxm -> ("TK_FALSE" , lxm)
| TK_FIELD lxm -> ("TK_FIELD" , lxm)
| TK_FUNCTION lxm -> ("TK_FUNCTION" , lxm)
| TK_GT lxm -> ("TK_GT" , lxm)
| TK_GTE lxm -> ("TK_GTE" , lxm)
......@@ -208,7 +207,6 @@ rule lexer = parse
| "<=" { TK_LTE ( Lxm.make lexbuf ) }
| "<>" { TK_NEQ ( Lxm.make lexbuf ) }
| ">=" { TK_GTE ( Lxm.make lexbuf ) }
| ".%" { TK_FIELD ( Lxm.make lexbuf ) }
| ".." { TK_CDOTS ( Lxm.make lexbuf ) }
| "**" { TK_POWER ( Lxm.make lexbuf ) }
(* parentheses des params statiques ... bof *)
......
......@@ -44,7 +44,6 @@ open Lv6parserUtils
%token <Lxm.t> TK_ELSE
%token <Lxm.t> TK_ENUM
%token <Lxm.t> TK_FALSE
%token <Lxm.t> TK_FIELD
%token <Lxm.t> TK_FUNCTION
%token <Lxm.t> TK_GT
%token <Lxm.t> TK_GTE
......@@ -121,8 +120,8 @@ open Lv6parserUtils
%left TK_POWER
%left TK_WHEN
%nonassoc TK_INT TK_REAL
%nonassoc TK_UMINUS TK_PRE TK_CURRENT TK_DIESE TK_NOR
%left TK_HAT TK_FIELD TK_DOT
%nonassoc TK_UMINUS TK_PRE TK_CURRENT TK_DIESE TK_NOR /* TK_DIESE TK_NOR useless ? */
%left TK_HAT TK_DOT
%right TK_OPEN_BRACKET TK_OPEN_BRACE TK_SEMICOL
%right TK_COMA
%right TK_FBY
......@@ -204,7 +203,7 @@ Provides:
{ Some (List.rev $2) }
;
ProvideList: Provide TK_SEMICOL /* ebnf:print=expand */
ProvideList: /* ebnf:print=expand */ Provide TK_SEMICOL
{ [$1] }
| ProvideList Provide TK_SEMICOL
{ $2::$1 }
......
(** Automatically generated from Makefile *)
let tool = "lus2lic"
let branch = "master"
let commit = "554"
let sha_1 = "4302bd0cb469f1969b9bef4c060d8ea7fb233179"
let commit = "622"
let sha_1 = "953ed8bb2db2ee412fb4a3d1ab70b205cc1299bb"
let str = (branch ^ "." ^ commit ^ " (" ^ sha_1 ^ ")")
let maintainer = "jahier@imag.fr"
(* Time-stamp: <modified the 17/08/2015 (at 16:14) by Erwan Jahier> *)
(* Time-stamp: <modified the 18/09/2015 (at 15:49) by Erwan Jahier> *)
open Verbose
open AstV6
......@@ -10,13 +10,15 @@ open Format
open Lv6MainArgs
let my_exit opt i =
if opt.rif || opt.print_interface then
if opt.rif then
output_string opt.oc "\nq\n"
else if opt.print_interface then
output_string opt.oc "\n"
else
output_string opt.oc "\nbye\n";
flush opt.oc;
close_out opt.oc;
if Sys.file_exists opt.outfile then Sys.remove opt.outfile;
if i>0 && Sys.file_exists opt.outfile then Sys.remove opt.outfile;
exit i
let rec first_pack_in =
......@@ -39,42 +41,37 @@ let find_a_node opt =
let (gen_rif_interface : LicPrg.t -> Lv6Id.idref option -> Lv6MainArgs.t -> unit) =
fun lic_prg main_node opt ->
let msk, zesoc, main_node =
match main_node with
| None -> (
let name = find_a_node opt in
let main_node = Lv6Id.to_idref name in
let nk = (Lic.node_key_of_idref main_node) in
if LicPrg.node_exists lic_prg nk then (
output_string stdout ("WARNING: No main node is specified. I'll try with "
^ name ^"\n");
flush stdout;
let msk, zesoc = Lic2soc.f lic_prg nk in
msk, zesoc, main_node
) else (
print_string ("Error: no node is specified.\nbye\n");
flush stdout;
my_exit opt 2
)
)
| Some main_node ->
let msk, zesoc = Lic2soc.f lic_prg (Lic.node_key_of_idref main_node) in
msk, zesoc, main_node
in
let my_type_to_string t =
let str = Data.type_to_string t in
let idref = Lv6Id.idref_of_string str in
(idref.Lv6Id.id_id)
in
let soc = try Soc.SocMap.find msk zesoc with Not_found -> assert false in
let invars,outvars=soc.Soc.profile in
let invars = SocVar.expand_profile false false invars in
let outvars = SocVar.expand_profile true false outvars in
let invars_str = List.map (fun (n,t) -> n^":"^(my_type_to_string t)) invars in
let outvars_str = List.map (fun (n,t) -> n^":"^(my_type_to_string t)) outvars in
print_string ("#inputs "^ (String.concat " " invars_str) ^"\n");
print_string ("#outputs "^ (String.concat " " outvars_str) ^"\n");
flush stdout
let nk =
match main_node with
| None -> (
let name = find_a_node opt in
let main_node = Lv6Id.to_idref name in
let nk = (Lic.node_key_of_idref main_node) in
if LicPrg.node_exists lic_prg nk then nk else (
output_string opt.oc ("Error: no node is specified.\nbye\n");
flush opt.oc;
my_exit opt 2
)
)
| Some main_node -> Lic.node_key_of_idref main_node
in
let invars,outvars =
match LicPrg.find_node lic_prg nk with
| None -> assert false
| Some node_def -> Lic2soc.soc_profile_of_node node_def
in
let my_type_to_string t =
let str = Data.type_to_string t in
let idref = Lv6Id.idref_of_string str in
(idref.Lv6Id.id_id)
in
let invars = SocVar.expand_profile true false invars in
let outvars = SocVar.expand_profile true false outvars in
let invars_str = List.map (fun (n,t) -> n^":"^(my_type_to_string t)) invars in
let outvars_str = List.map (fun (n,t) -> n^":"^(my_type_to_string t)) outvars in
output_string opt.oc ("#inputs "^ (String.concat " " invars_str) ^"\n");
output_string opt.oc ("#outputs "^ (String.concat " " outvars_str) ^"\n");
flush opt.oc
(* Generates a lutin env and a lustre oracle for the node *)
......
(* Time-stamp: <modified the 13/05/2015 (at 09:38) by Erwan Jahier> *)
(* Time-stamp: <modified the 23/09/2015 (at 10:04) by Erwan Jahier> *)
(* let put (os: out_channel) (fmt:('a, unit, string, unit) format4) : 'a = *)
......@@ -431,17 +431,16 @@ int main(){" ^ (
close_out oc
let (gen_loop_file : Soc.t -> out_channel -> Soc.tbl -> unit) =
fun soc oc stbl ->
let base = (string_of_soc_key soc.key) in
let (gen_loop_file : Soc.t -> string -> out_channel -> Soc.tbl -> unit) =
fun soc base oc stbl ->
let putc s = output_string oc s in
let ctx = get_ctx_name soc.key in
let step = Soc2cDep.step_name soc.key "step" in
let (n,_,_) = soc.key in
let n = id2s n in
let inputs,outputs = soc.profile in
let inputs_io = SocVar.expand_profile true false inputs in
let outputs_io = SocVar.expand_profile true false outputs in
let inputs_io = SocVar.expand_profile true false inputs in
let outputs_io = SocVar.expand_profile true false outputs in
let inputs_exp = SocVar.expand_profile true true inputs in
let outputs_exp= SocVar.expand_profile true true outputs in
Lv6util.entete oc "/*" "*/";
......@@ -635,45 +634,143 @@ int main(){
}
"
let (gen_loop_file4ogensim : Soc.t -> string -> out_channel -> Soc.tbl -> unit) =
fun soc base oc stbl ->
let putc s = output_string oc s in
let ctx = get_ctx_name soc.key in
let step = Soc2cDep.step_name soc.key "step" in
let (n,_,_) = soc.key in
let n = id2s n in
let inputs,outputs = soc.profile in
let inputs_io = SocVar.expand_profile true false inputs in
let outputs_io = SocVar.expand_profile true false outputs in
let inputs_exp = SocVar.expand_profile true true inputs in
let outputs_exp= SocVar.expand_profile true true outputs in
let define_define i (var_name,_) =
putc (Printf.sprintf "#define _%s\t 0xe%07X\n" var_name ((i+1)*8));
in
Lv6util.entete oc "/*" "*/";
putc ("#include \""^base ^".h\"
#define tickBegin 0xe0000000
");
List.iteri define_define (inputs_io@ outputs_io);
putc (
"/* Main procedure *************************/
int main(){" ^ (
match io_transmit_mode () with
| Lv6MainArgs.Stack ->
let to_c_decl (n,t) = ((Soc2cUtil.data_type_to_c t n)^ ";\n ") in
let inputs_t = List.map to_c_decl inputs in
let outputs_t = List.map to_c_decl outputs in
let inputs_decl = Printf.sprintf "\n %s" (String.concat "" inputs_t) in
let outputs_decl = Printf.sprintf "%s" (String.concat "" outputs_t) in
let ctx_decl = if SocUtils.is_memory_less soc then "" else
ctx^"_type* ctx = "^ ctx^"_new_ctx(NULL);\n"
in
inputs_decl ^ outputs_decl ^ ctx_decl
| Lv6MainArgs.Heap -> ("
/* Context allocation */
" ^ (if SocUtils.is_memory_less soc then ctx^"_type* ctx = &"^ctx^";\n"
else ctx^"_type* ctx = "^ ctx^"_new_ctx(NULL);")
)
| Lv6MainArgs.HeapStack -> ("
/* Context allocation */
" ^ (if SocUtils.is_memory_less soc then ctx^""
else ctx^"_type* ctx ;\n"^ ctx^"_reset(ctx);")
)
));
let to_rif_decl (n,t) = ("\\\""^n^"\\\":" ^(type_to_string t)) in
let inputs_t = List.map to_rif_decl inputs_io in
let outputs_t = List.map to_rif_decl outputs_io in
let inputs_decl = Printf.sprintf "#inputs %s" (String.concat " " inputs_t) in
let outputs_decl = Printf.sprintf "#outputs %s" (String.concat " " outputs_t) in
putc ("
/* Main loop */
while(1){
// notify the simulator that it is time to load the inputs from Lurette
// to the specified address
*((unsigned int*)tickBegin) = 0;
// load inputs from the memory locations
");
List.iter2
(fun (id,t) (id_flat,_) ->
let t = Soc2cUtil.data_type_to_c t "" in
let str =
Printf.sprintf " %s = *((%s*)_%s);\n" id t id_flat
in
putc str
)
inputs_exp inputs_io;
assert (io_transmit_mode () = Lv6MainArgs.Stack);
let i = fst (List.split inputs) in
let o = List.map (fun (n,t) -> match t with Data.Array(_,_) -> n | _ ->"&"^n) outputs in
let io = String.concat "," (i@o) in
let io = if SocUtils.is_memory_less soc then io else if io = "" then "ctx" else io^",ctx" in
putc (" " ^ step^"("^io^");
// now write the output to the memory which will be output to Lurette
");
List.iter2
(fun (id,t) (id_flat,_) ->
let t = Soc2cUtil.data_type_to_c t "" in
let str = Printf.sprintf " *((%s*)_%s) = %s;\n" t id id_flat in
putc str
)
outputs_io outputs_exp;
putc "}\n return 1;
}
"
(****************************************************************************)
(* The entry point for lus2lic --to-c *)
let (f : Lv6MainArgs.t -> Soc.key -> Soc.tbl -> LicPrg.t -> unit) =
fun args msoc stbl licprg ->
let socs = Soc.SocMap.bindings stbl in
let socs = snd (List.split socs) in
(* XXX que fait-on pour les soc predef ? *)
(* let _, socs = List.partition is_predef socs in *)
let base =
if args.Lv6MainArgs.outfile = "" then
string_of_soc_key msoc
let socs = Soc.SocMap.bindings stbl in
let socs = snd (List.split socs) in
(* XXX que fait-on pour les soc predef ? *)
(* let _, socs = List.partition is_predef socs in *)
let base =
if args.Lv6MainArgs.outfile = "" then
string_of_soc_key msoc
else
Filename.basename (
Filename.basename (
try Filename.chop_extension args.Lv6MainArgs.outfile
with Invalid_argument _ -> args.Lv6MainArgs.outfile)
in
let hfile = base ^ ".h" in
let cfile = base ^ ".c" in
let ext_cfile = Printf.sprintf "%s_ext.c" base in
let ext_hfile = Printf.sprintf "%s_ext.h" base in
let loopfile = base^"_loop.c" in
let occ = open_out cfile in
let och = open_out hfile in
let ocl = open_out loopfile in
try
let putc s = output_string occ s in
let puth s = output_string och s in
let main_soc = Soc.SocMap.find msoc stbl in
in
let hfile = base ^ ".h" in
let cfile = base ^ ".c" in
let ext_cfile = Printf.sprintf "%s_ext.c" base in
let ext_hfile = Printf.sprintf "%s_ext.h" base in
let loopfile = base^"_loop.c" in
let occ = open_out cfile in
let och = open_out hfile in
let ocl = open_out loopfile in
try
let putc s = output_string occ s in
let puth s = output_string och s in
let main_soc = Soc.SocMap.find msoc stbl in
(* Generate ext files if necessary *)
let needs_cfile, needs_hfile =
Soc2cExtern.gen_files main_soc stbl licprg ext_cfile ext_hfile hfile
in
Lv6util.entete occ "/*" "*/" ;
Lv6util.entete och "/*" "*/";
gen_loop_file main_soc ocl stbl;
if args.Lv6MainArgs.gen_wcet then gen_main_wcet_file main_soc base stbl;
output_string och "
let needs_cfile, needs_hfile =
Soc2cExtern.gen_files main_soc stbl licprg ext_cfile ext_hfile hfile
in
Lv6util.entete occ "/*" "*/" ;
Lv6util.entete och "/*" "*/";
if args.Lv6MainArgs.gen_wcet then
gen_loop_file4ogensim main_soc base ocl stbl
else
gen_loop_file main_soc base ocl stbl;
if args.Lv6MainArgs.gen_wcet then gen_main_wcet_file main_soc base stbl;
output_string och "
#include <stdlib.h>
#include <string.h>
......@@ -723,32 +820,105 @@ typedef float _float;
Printf.printf "%s has been generated.\n" hfile;
Printf.printf "%s has been generated.\n" cfile;
flush stdout;
let execfile = if args.Lv6MainArgs.outfile = "" then "a.out"
let node = args.main_node in
let execfile = if args.Lv6MainArgs.outfile = "" then (node^"4otawa.out")
else args.Lv6MainArgs.outfile
in
let cflags = try Sys.getenv "CFLAGS" with Not_found -> "" in
let main_file,gcc =
if args.Lv6MainArgs.gen_wcet then base^"_main.c","arm-elf-gcc -g" else loopfile,"gcc"
let ocsh = open_out (node ^".sh") in
let main_file, ogensim_main_file, gcc =
if args.Lv6MainArgs.gen_wcet then
base^"_main.c",base^"_loop.c","arm-elf-gcc --specs=linux.specs -g"
else
loopfile, "I am a dead string...", "gcc"
in
let gcc =
let ogensim_exe = node^"4ogensim.out" in
let gcc, gcc_ogensim =
if needs_cfile then
Printf.sprintf "%s -o %s %s %s %s %s" gcc execfile cfile cflags ext_cfile main_file