X-Git-Url: http://nitlanguage.org diff --git a/src/compiling/compiling_base.nit b/src/compiling/compiling_base.nit index f92e00b..24d4fcb 100644 --- a/src/compiling/compiling_base.nit +++ b/src/compiling/compiling_base.nit @@ -17,21 +17,110 @@ # Common things for NIT compilation and C generation package compiling_base -import syntax +import mmloader private import utils import primitive_info +import program +import compiling_writer redef class ToolContext - readable writable var _global: Bool = false readable writable var _compdir: nullable String = null readable writable var _clibdir: nullable String = null readable writable var _bindir: nullable String = null readable writable var _output_file: nullable String = null readable writable var _boost: Bool = false readable writable var _no_cc: Bool = false + readable writable var _cc_link: Bool = false + readable writable var _cc_libs: Array[String] = new Array[String] + readable writable var _cc_lib_paths: Array[String] = new Array[String] + readable writable var _cc_include_paths: Array[String] = new Array[String] 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.main_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 == 1 then + verbose = "-v" + else if tc.verbose_level >= 2 then + # We catch tc.verbose_level >= 2, since 3+ is not valid with gccx + verbose = "-vv" + end + + f.write("#!/bin/sh\n") + f.write("# This shell script is generated by NIT to compile the program {program.main_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.main_module.name}") + else + f.write(" -o {program.main_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. @@ -39,34 +128,47 @@ class CompilerVisitor # Add a line in the current declaration block fun add_decl(s: String) do - if _indent_level >= 8 then - _ctx.decls.add("\t\t" + s) - else - _ctx.decls.add(" " * _indent_level + s) - end + add_line_to(_decl_writer, s) end # Add a line in the current instr block fun add_instr(s: String) do + add_line_to(_writer, s) + end + + + fun add_indent(w: Writer) + do if _indent_level >= 8 then - _ctx.instrs.add("\t\t" + s) + w.add("\t\t") else - _ctx.instrs.add(" " * _indent_level + s) + for i in [0.._indent_level[ do + w.add(" ") + end end end + fun add_line_to(w: Writer, s: String) + do + add_indent(w) + w.add(s) + w.add("\n") + end + # Add a assignment between a variable and an expression fun add_assignment(v: String, s: String) do if v != s then - add_instr("{v} = {s};") + var w = _writer + add_indent(w) + w.add(v) + w.add(" = ") + w.add(s) + w.add(";\n") end end - # C outputs written outside the current C function. - readable writable var _out_contexts: Array[CContext] = new Array[CContext] - # Return a unique new number for the instance fun new_number: Int do @@ -88,55 +190,48 @@ class CompilerVisitor if _indent_level < 0 then _indent_level = 0 end - # Return a big string containing all decl and instr - redef fun to_s - do - var out = new Array[String] - out.append(_ctx.decls) - out.append(_ctx.instrs) - out.add("") - return out.join("\n") - end + # The processed mmmodule + readable var _mmmodule: MMModule + + # Where header decl are stored (public stuff) + readable writable var _header_writer: Writer + + # Where current instr are stored (current function declaration) + readable writable var _writer: Writer - # The processed module - readable var _module: MMModule + # Where current decl are stored (current function instructions) + readable writable var _decl_writer: Writer - # Where instr and decl are stored - readable writable var _ctx: CContext = new CContext + # Where body instr are stored (C functions body) + readable writable var _top_writer: Writer + + # Where body decl are stored (private C function proptypes and typedefs) + readable writable var _top_decl_writer: Writer # The current indent lever readable writable var _indent_level: Int = 0 - # The ToolContext info - readable var _tc: ToolContext + # 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, tc: ToolContext) + init(mod: MMModule, cp: CProgram) do - _module = module - _tc = tc - end -end - -# Where instr and decl are stored for a module -# Note that this class is as badly designed as CompilerVisitor -class CContext - readable var _decls: Array[String] = new Array[String] - readable var _instrs: Array[String] = new Array[String] + _mmmodule = mod + _cprogram = cp + _program = cp.program - fun append(c: CContext) - do - _instrs.append(c.decls) - _instrs.append(c.instrs) + var w = new Writer + _header_writer = w + _decl_writer = w + w = new Writer + _writer = w + _top_writer = w + _top_decl_writer = w.sub end - - fun merge(c: CContext) - do - _decls.append(c.decls) - _instrs.append(c.instrs) - end - - init do end end redef class MMGlobalProperty @@ -182,7 +277,7 @@ redef class MMLocalProperty do var cname = _cname_cache if cname == null then - cname = cmangle(module.name, local_class.name, name) + cname = cmangle(mmmodule.name, local_class.name, name) _cname_cache = cname end return cname