From: Jean Privat Date: Fri, 5 Feb 2010 15:33:45 +0000 (-0500) Subject: compile: add class compiling::CProgram to manage generated files X-Git-Tag: v0.4~38 X-Git-Url: http://nitlanguage.org?ds=sidebyside compile: add class compiling::CProgram to manage generated files Signed-off-by: Jean Privat --- diff --git a/src/compiling/compiling.nit b/src/compiling/compiling.nit index 4f58fbf..0099b6b 100644 --- a/src/compiling/compiling.nit +++ b/src/compiling/compiling.nit @@ -49,76 +49,38 @@ redef class Program # Then execute the build.sh fun compile_prog_to_c do - var compdir = tc.compdir.as(not null) - compdir.mkdir - - var files = new Array[String] - var includes = new ArraySet[String] - files.add("$CLIBDIR/nit_main.c") - files.add("$CLIBDIR/gc.c") - files.add("$CLIBDIR/gc_static_objects_list.c") - tc.info("Generating C code",1) - for m in module.mhe.greaters_and_self do - files.add("{compdir}/{m.name}.{get_file_ending}.c") - tc.info("Generating C code for module: {m.name}",2) - m.compile_separate_module(self) - var native_name = m.location.file.strip_extension(".nit") - if (native_name + "_nit.h").file_exists then - includes.add("-I {native_name.dirname}") - end - native_name += "_nit.c" - if native_name.file_exists then files.add(native_name) - end + var cprogram = new CProgram(self) - tc.info("Generating main, tables and makefile ...",1) - files.add("{compdir}/{module.name}._tables.c") - compile_main + cprogram.compdir.mkdir - var fn = "{compdir}/{module.name}._build.sh" - var f = new OFStream.open(fn) - var verbose = "" + cprogram.files.add("$CLIBDIR/nit_main.c") + cprogram.files.add("$CLIBDIR/gc.c") + cprogram.files.add("$CLIBDIR/gc_static_objects_list.c") - if tc.verbose_level > 0 then - verbose = "-" - for i in [1..tc.verbose_level] do verbose = verbose + "v" - end + tc.info("Generating C code",1) + for m in module.mhe.greaters_and_self do m.compile_separate_module(cprogram) - f.write("#!/bin/sh\n") - f.write("# This shell script is generated by NIT to compile the program {module.name}.\n") - f.write("CLIBDIR=\"{tc.clibdir.as(not null)}\"\n") - f.write("{tc.bindir.as(not null)}/gccx {verbose} -d {compdir} -I $CLIBDIR {includes.join(" ")}") - if tc.output_file != null then - f.write(" -o {tc.output_file.as(not null)}") - else if tc.ext_prefix.is_empty then - f.write(" -o {module.name}") - else - f.write(" -o {module.name}_{tc.ext_prefix}") - end - if tc.boost then f.write(" -O") - if not tc.cc_link then f.write(" -x \"-c\"") - for l in tc.cc_libs do f.write(" -x \"-l {l}\"") - for lp in tc.cc_lib_paths do f.write(" -x \"-L {lp}\"") - for ip in tc.cc_include_paths do f.write(" -x \"-I {ip}\"") - f.write(" \"$@\" \\\n {files.join("\\\n ")}\n") - f.close + tc.info("Generating main, tables and makefile ...",1) + compile_main(cprogram) - if not tc.no_cc then - tc.info("Building",1) - sys.system("sh {fn}") - end + cprogram.generate_build_file + + if not tc.no_cc then cprogram.run_c_compiler end # Compile the main file - private fun compile_main + private fun compile_main(cprogram: CProgram) do - var v = new CompilerVisitor(module, self) + var v = new CompilerVisitor(module, cprogram) v.add_decl("#include ") compile_tables_to_c(v) compile_main_part(v) - var f = new OFStream.open("{tc.compdir.as(not null)}/{module.name}._tables.c") + var filename = "{cprogram.compdir}/{module.name}._tables.c" + cprogram.files.add(filename) + var f = new OFStream.open(filename) f.write("/* This C file is generated by NIT to compile program {module.name}. */\n") for m in module.mhe.greaters_and_self do - f.write("#include \"{m.name}.{get_file_ending}.h\"\n") + f.write("#include \"{cprogram.module_header_name(m)}\"\n") end v.header_writer.write_to_stream(f) v.writer.write_to_stream(f) @@ -128,28 +90,40 @@ end redef class MMModule # Compile the sep or glob files (of the current module only) - private fun compile_separate_module(program: Program) + private fun compile_separate_module(cprogram: CProgram) do - var tc = program.tc - var v = new CompilerVisitor(self, program) + var tc = cprogram.program.tc + tc.info("Generating C code for module: {name}",2) + var v = new CompilerVisitor(self, cprogram) v.add_decl("#include ") + var native_name = location.file.strip_extension(".nit") - native_name += ("_nit.h") - if native_name.file_exists then v.add_decl("#include <{native_name.basename("")}>") + var native_header = native_name + "_nit.h" + if native_header.file_exists then + v.add_decl("#include <{native_header.basename("")}>") + cprogram.include_dirs.add("-I {native_name.dirname}") + end + var native_body = native_name + "_nit.c" + if native_body.file_exists then cprogram.files.add(native_body) + declare_class_tables_to_c(v) compile_mod_to_c(v) - var f = new OFStream.open("{tc.compdir.as(not null)}/{name}.{program.get_file_ending}.h") + + var hfilename = cprogram.module_header_name(self) + var f = new OFStream.open("{cprogram.compdir}/{hfilename}") f.write("/* This C header file is generated by NIT to compile modules and programs that requires {name}. */\n") - f.write("#ifndef {name}{program.get_file_ending}\n") - f.write("#define {name}{program.get_file_ending}\n") - for m in mhe.direct_greaters do f.write("#include \"{m.name}.{program.get_file_ending}.h\"\n") + f.write("#ifndef {name}{cprogram.get_file_ending}\n") + f.write("#define {name}{cprogram.get_file_ending}\n") + for m in mhe.direct_greaters do f.write("#include \"{cprogram.module_header_name(m)}\"\n") v.header_writer.write_to_stream(f) f.write("#endif\n") f.close - f = new OFStream.open("{tc.compdir.as(not null)}/{name}.{program.get_file_ending}.c") + var cfilename = "{cprogram.compdir}/{name}.{cprogram.get_file_ending}.c" + cprogram.files.add(cfilename) + f = new OFStream.open("{cfilename}") f.write("/* This C file is generated by NIT to compile module {name}. */\n") - f.write("#include \"{name}.{program.get_file_ending}.h\"\n") + f.write("#include \"{hfilename}\"\n") v.top_writer.write_to_stream(f) f.close end diff --git a/src/compiling/compiling_base.nit b/src/compiling/compiling_base.nit index 9745021..e1c5040 100644 --- a/src/compiling/compiling_base.nit +++ b/src/compiling/compiling_base.nit @@ -37,6 +37,88 @@ redef class ToolContext readable writable var _ext_prefix: String = "" end +# A program that is compiled to C +class CProgram + init(p: Program) + do + _program = p + _compdir = p.tc.compdir.as(not null) + _build_file = "{compdir}/{program.module.name}._build.sh" + end + + # The Nit program compiled to C + readable var _program: Program + + # C files (full path) required to compile + readable var _files: Array[String] = new Array[String] + + # Includes paths (gcc -I) required to find the headers (.h) of native modules + readable var _include_dirs: ArraySet[String] = new ArraySet[String] + + # The path of the building script + readable var _build_file: String + + # The directory where all files are generated + readable var _compdir: String + + # Return the basename of the public header file (.h) of a module + fun module_header_name(m: MMModule): String + do + if _module_include.has_key(m) then + return _module_include[m] + end + var filename = "{m.name}.{get_file_ending}.h" + _module_include[m] = filename + return filename + end + + # Cache for module_header_name + var _module_include: Map[MMModule, String] = new HashMap[MMModule, String] + + # When we are using global compilation, we generate _glob files instead + # of _sep files so that we do not corrupt separate compilation + fun get_file_ending: String do return if program.tc.global then "_glob" else "_sep" + + # Generate the shell script that build the program by calling gccx + fun generate_build_file + do + var f = new OFStream.open(_build_file) + var verbose = "" + var tc = program.tc + + if tc.verbose_level > 0 then + verbose = "-" + for i in [1..tc.verbose_level] do verbose = verbose + "v" + end + + f.write("#!/bin/sh\n") + f.write("# This shell script is generated by NIT to compile the program {program.module.name}.\n") + f.write("CLIBDIR=\"{tc.clibdir.as(not null)}\"\n") + f.write("{tc.bindir.as(not null)}/gccx {verbose} -d {compdir} -I $CLIBDIR {include_dirs.join(" ")}") + if tc.output_file != null then + f.write(" -o {tc.output_file.as(not null)}") + else if tc.ext_prefix.is_empty then + f.write(" -o {program.module.name}") + else + f.write(" -o {program.module.name}_{tc.ext_prefix}") + end + if tc.boost then f.write(" -O") + if not tc.cc_link then f.write(" -x \"-c\"") + for l in tc.cc_libs do f.write(" -x \"-l {l}\"") + for lp in tc.cc_lib_paths do f.write(" -x \"-L {lp}\"") + for ip in tc.cc_include_paths do f.write(" -x \"-I {ip}\"") + f.write(" \"$@\" \\\n {files.join("\\\n ")}\n") + f.close + end + + # Invoke the build_file + fun run_c_compiler + do + program.tc.info("Building",1) + sys.system("sh {_build_file}") + end +end + # Class used to generate files. # Note that in fact it is not a visitor. # Note also that this class is unefficient and poorly designed thus requires love. @@ -130,11 +212,15 @@ class CompilerVisitor # The program we are compiling readable var _program: Program + # The cprogram associed with program + readable var _cprogram: CProgram + # Create a new CompilerVisitor based on a module - init(module: MMModule, p: Program) + init(module: MMModule, cp: CProgram) do _module = module - _program = p + _cprogram = cp + _program = cp.program var w = new Writer _header_writer = w diff --git a/src/program.nit b/src/program.nit index b08ee8c..542e914 100644 --- a/src/program.nit +++ b/src/program.nit @@ -49,10 +49,6 @@ class Program # Would be null if there is no main method readable var _main_class: nullable MMLocalClass = null - # When we are using global compilation, we generate _glob files instead - # of _sep files so that we do not corrupt separate compilation - fun get_file_ending: String do return if tc.global then "_glob" else "_sep" - # This method will ensure that all the metamodel is computed before we # start using all the classes private fun finish_processing_classes do