X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index 0fa3d4b..224de8b 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -349,7 +349,14 @@ class MakefileToolchain end var debug = toolcontext.opt_debug.value - makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g{ if not debug then " -O2 " else " "}-Wno-unused-value -Wno-switch -Wno-attributes -Wno-trigraphs\nCINCL =\nLDFLAGS ?= \nLDLIBS ?= -lm {linker_options.join(" ")}\n\n") + makefile.write """ +CC = ccache cc +CXX = ccache c++ +CFLAGS = -g {{{if not debug then "-O2" else ""}}} -Wno-unused-value -Wno-switch -Wno-attributes -Wno-trigraphs +CINCL = +LDFLAGS ?= +LDLIBS ?= -lm {{{linker_options.join(" ")}}} +\n""" makefile.write "\n# SPECIAL CONFIGURATION FLAGS\n" if platform.supports_libunwind then @@ -403,6 +410,18 @@ ifeq ($(uname_S),Darwin) LDLIBS := $(filter-out -lrt,$(LDLIBS)) endif +# Special configuration for Windows under mingw64 +ifeq ($(uname_S),MINGW64_NT-10.0) + # Use the pcreposix regex library + LDLIBS += -lpcreposix + + # Remove POSIX flag -lrt + LDLIBS := $(filter-out -lrt,$(LDLIBS)) + + # Silence warnings when storing Int, Char and Bool as pointer address + CFLAGS += -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast +endif + """ makefile.write("all: {outpath}\n") @@ -512,6 +531,8 @@ endif var res if self.toolcontext.verbose_level >= 3 then res = sys.system("{command} 2>&1") + else if is_windows then + res = sys.system("{command} 2>&1 >nul") else res = sys.system("{command} 2>&1 >/dev/null") end @@ -662,9 +683,14 @@ abstract class AbstractCompiler self.header.add_decl("#include \n") self.header.add_decl("#include \"gc_chooser.h\"") self.header.add_decl("#ifdef __APPLE__") + self.header.add_decl(" #include ") + self.header.add_decl(" #include ") self.header.add_decl(" #include ") self.header.add_decl(" #define be32toh(x) OSSwapBigToHostInt32(x)") self.header.add_decl("#endif") + self.header.add_decl("#ifdef _WIN32") + self.header.add_decl(" #define be32toh(val) _byteswap_ulong(val)") + self.header.add_decl("#endif") self.header.add_decl("#ifdef __pnacl__") self.header.add_decl(" #define be16toh(val) (((val) >> 8) | ((val) << 8))") self.header.add_decl(" #define be32toh(val) ((be16toh((val) << 16) | (be16toh((val) >> 16))))") @@ -675,6 +701,8 @@ abstract class AbstractCompiler self.header.add_decl(" #endif") self.header.add_decl(" #include ") self.header.add_decl(" #define PRINT_ERROR(...) (void)__android_log_print(ANDROID_LOG_WARN, \"Nit\", __VA_ARGS__)") + self.header.add_decl("#elif TARGET_OS_IPHONE") + self.header.add_decl(" #define PRINT_ERROR(...) syslog(LOG_ERR, __VA_ARGS__)") self.header.add_decl("#else") self.header.add_decl(" #define PRINT_ERROR(...) fprintf(stderr, __VA_ARGS__)") self.header.add_decl("#endif") @@ -779,6 +807,20 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); v.add "\}" end + # Hook to add specif piece of code before the the main C function. + # + # Is called by `compile_main_function` + fun compile_before_main(v: VISITOR) + do + end + + # Hook to add specif piece of code at the begin on the main C function. + # + # Is called by `compile_main_function` + fun compile_begin_main(v: VISITOR) + do + end + # Generate the main C function. # # This function: @@ -864,11 +906,17 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); v.add_decl("\}") v.add_decl("void sig_handler(int signo)\{") + v.add_decl "#ifdef _WIN32" + v.add_decl "PRINT_ERROR(\"Caught signal : %s\\n\", signo);" + v.add_decl "#else" v.add_decl("PRINT_ERROR(\"Caught signal : %s\\n\", strsignal(signo));") + v.add_decl "#endif" v.add_decl("show_backtrace();") # rethrows v.add_decl("signal(signo, SIG_DFL);") + v.add_decl "#ifndef _WIN32" v.add_decl("kill(getpid(), signo);") + v.add_decl "#endif" v.add_decl("\}") v.add_decl("void fatal_exit(int status) \{") @@ -876,12 +924,16 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); v.add_decl("exit(status);") v.add_decl("\}") + compile_before_main(v) + if no_main then v.add_decl("int nit_main(int argc, char** argv) \{") else v.add_decl("int main(int argc, char** argv) \{") end + compile_begin_main(v) + v.add "#if !defined(__ANDROID__) && !defined(TARGET_OS_IPHONE)" v.add("signal(SIGABRT, sig_handler);") v.add("signal(SIGFPE, sig_handler);") @@ -890,7 +942,9 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); v.add("signal(SIGTERM, sig_handler);") v.add("signal(SIGSEGV, sig_handler);") v.add "#endif" + v.add "#ifndef _WIN32" v.add("signal(SIGPIPE, SIG_IGN);") + v.add "#endif" v.add("glob_argc = argc; glob_argv = argv;") v.add("catchStack.cursor = -1;") @@ -1116,25 +1170,41 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ) { fun finalize_ffi_for_module(mmodule: MModule) do mmodule.finalize_ffi(self) end -# A file unit (may be more than one file if -# A file unit aim to be autonomous and is made or one or more `CodeWriter`s +# C code file generated from the `writers` and the `required_declarations` +# +# A file unit aims to be autonomous and is made or one or more `CodeWriter`s. class CodeFile + # Basename of the file, will be appended by `.h` and `.c` var name: String + + # `CodeWriter` used in sequence to fill the top of the body, then the bottom var writers = new Array[CodeWriter] + + # Required declarations keys + # + # See: `provide_declaration` var required_declarations = new HashSet[String] end -# Where to store generated lines +# Store generated lines +# +# Instances are added to `file.writers` at construction. class CodeWriter + # Parent `CodeFile` var file: CodeFile + + # Main lines of code (written at the bottom of the body) var lines = new Array[String] + + # Lines of code for declarations (written at the top of the body) var decl_lines = new Array[String] - # Add a line in the main part of the generated C + # Add a line in the main lines of code (to `lines`) fun add(s: String) do self.lines.add(s) - # Add a line in the - # (used for local or global declaration) + # Add a declaration line (to `decl_lines`) + # + # Used for local and global declaration. fun add_decl(s: String) do self.decl_lines.add(s) init @@ -1208,8 +1278,6 @@ abstract class AbstractCompilerVisitor fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable is abstract - fun calloc_array(ret_type: MType, arguments: Array[RuntimeVariable]) is abstract - fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable]): Bool do return false # Return an element of a native array. @@ -1220,6 +1288,16 @@ abstract class AbstractCompilerVisitor # The method is unsafe and is just a direct wrapper for the specific implementation of native arrays fun native_array_set(native_array: RuntimeVariable, index: Int, value: RuntimeVariable) is abstract + # Allocate `size` bytes with the low_level `nit_alloc` C function + # + # This method can be redefined to inject statistic or tracing code. + # + # `tag` if any, is used to mark the class of the allocated object. + fun nit_alloc(size: String, tag: nullable String): String + do + return "nit_alloc({size})" + end + # Evaluate `args` as expressions in the call of `mpropdef` on `recv`. # This method is used to manage varargs in signatures and returns the real array # of runtime variables to use in the call. @@ -1434,7 +1512,7 @@ abstract class AbstractCompilerVisitor end # Return a "const char*" variable associated to the classname of the dynamic type of an object - # NOTE: we do not return a `RuntimeVariable` "NativeString" as the class may not exist in the module/program + # NOTE: we do not return a `RuntimeVariable` "CString" as the class may not exist in the module/program fun class_name_string(value: RuntimeVariable): String is abstract # Variables handling @@ -1553,7 +1631,7 @@ abstract class AbstractCompilerVisitor fun int8_instance(value: Int8): RuntimeVariable do var t = mmodule.int8_type - var res = new RuntimeVariable("((int8_t){value.to_s})", t, t) + var res = new RuntimeVariable("INT8_C({value.to_s})", t, t) return res end @@ -1561,7 +1639,7 @@ abstract class AbstractCompilerVisitor fun int16_instance(value: Int16): RuntimeVariable do var t = mmodule.int16_type - var res = new RuntimeVariable("((int16_t){value.to_s})", t, t) + var res = new RuntimeVariable("INT16_C({value.to_s})", t, t) return res end @@ -1569,7 +1647,7 @@ abstract class AbstractCompilerVisitor fun uint16_instance(value: UInt16): RuntimeVariable do var t = mmodule.uint16_type - var res = new RuntimeVariable("((uint16_t){value.to_s})", t, t) + var res = new RuntimeVariable("UINT16_C({value.to_s})", t, t) return res end @@ -1577,7 +1655,7 @@ abstract class AbstractCompilerVisitor fun int32_instance(value: Int32): RuntimeVariable do var t = mmodule.int32_type - var res = new RuntimeVariable("((int32_t){value.to_s})", t, t) + var res = new RuntimeVariable("INT32_C({value.to_s})", t, t) return res end @@ -1585,7 +1663,7 @@ abstract class AbstractCompilerVisitor fun uint32_instance(value: UInt32): RuntimeVariable do var t = mmodule.uint32_type - var res = new RuntimeVariable("((uint32_t){value.to_s})", t, t) + var res = new RuntimeVariable("UINT32_C({value.to_s})", t, t) return res end @@ -1627,9 +1705,9 @@ abstract class AbstractCompilerVisitor return res end - # Generates a NativeString instance fully escaped in C-style \xHH fashion - fun native_string_instance(ns: NativeString, len: Int): RuntimeVariable do - var mtype = mmodule.native_string_type + # Generates a CString instance fully escaped in C-style \xHH fashion + fun c_string_instance(ns: CString, len: Int): RuntimeVariable do + var mtype = mmodule.c_string_type var nat = new_var(mtype) var byte_esc = new Buffer.with_cap(len * 4) for i in [0 .. len[ do @@ -1649,12 +1727,12 @@ abstract class AbstractCompilerVisitor self.add("if (likely({name}!=NULL)) \{") self.add("{res} = {name};") self.add("\} else \{") - var native_mtype = mmodule.native_string_type + var native_mtype = mmodule.c_string_type var nat = self.new_var(native_mtype) self.add("{nat} = \"{string.escape_to_c}\";") var byte_length = self.int_instance(string.byte_length) var unilen = self.int_instance(string.length) - self.add("{res} = {self.send(self.get_property("to_s_full", native_mtype), [nat, byte_length, unilen]).as(not null)};") + self.add("{res} = {self.send(self.get_property("to_s_unsafe", native_mtype), [nat, byte_length, unilen, value_instance(false), value_instance(false)]).as(not null)};") self.add("{name} = {res};") self.add("\}") return res @@ -2016,7 +2094,7 @@ redef class MClassType return "int32_t" else if mclass.name == "UInt32" then return "uint32_t" - else if mclass.name == "NativeString" then + else if mclass.name == "CString" then return "char*" else if mclass.name == "NativeArray" then return "val*" @@ -2058,7 +2136,7 @@ redef class MClassType return "i32" else if mclass.name == "UInt32" then return "u32" - else if mclass.name == "NativeString" then + else if mclass.name == "CString" then return "str" else if mclass.name == "NativeArray" then #return "{self.arguments.first.ctype}*" @@ -2527,7 +2605,7 @@ redef class AMethPropdef v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null))) return true end - else if cname == "NativeString" then + else if cname == "CString" then if pname == "[]" then v.ret(v.new_expr("(unsigned char)((int){arguments[0]}[{arguments[1]}])", ret.as(not null))) return true @@ -2551,13 +2629,14 @@ redef class AMethPropdef v.ret(v.new_expr("!{res}", ret.as(not null))) return true else if pname == "new" then - v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null))) + var alloc = v.nit_alloc(arguments[1].to_s, "CString") + v.ret(v.new_expr("(char*){alloc}", ret.as(not null))) return true else if pname == "fetch_4_chars" then - v.ret(v.new_expr("(long)*((uint32_t*)({arguments[0]} + {arguments[1]}))", ret.as(not null))) + v.ret(v.new_expr("*((uint32_t*)({arguments[0]} + {arguments[1]}))", ret.as(not null))) return true else if pname == "fetch_4_hchars" then - v.ret(v.new_expr("(long)be32toh(*((uint32_t*)({arguments[0]} + {arguments[1]})))", ret.as(not null))) + v.ret(v.new_expr("(uint32_t)be32toh(*((uint32_t*)({arguments[0]} + {arguments[1]})))", ret.as(not null))) return true end else if cname == "NativeArray" then @@ -2999,17 +3078,11 @@ redef class AMethPropdef end end if pname == "exit" then - v.add("exit({arguments[1]});") + v.add("exit((int){arguments[1]});") return true else if pname == "sys" then v.ret(v.new_expr("glob_sys", ret.as(not null))) return true - else if pname == "calloc_string" then - v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null))) - return true - else if pname == "calloc_array" then - v.calloc_array(ret.as(not null), arguments) - return true else if pname == "object_id" then v.ret(v.new_expr("(long){arguments.first}", ret.as(not null))) return true @@ -3674,7 +3747,7 @@ redef class AStringExpr var s = v.string_instance(value) if is_string then return s if is_bytestring then - var ns = v.native_string_instance(bytes.items, bytes.length) + var ns = v.c_string_instance(bytes.items, bytes.length) var ln = v.int_instance(bytes.length) var cs = to_bytes_with_copy assert cs != null @@ -3748,7 +3821,7 @@ redef class ASuperstringExpr v.native_array_set(a, i, e) end - # Fast join the native string to get the result + # Fast join the C string to get the result var res = v.send(v.get_property("native_to_s", a.mtype), [a]) assert res != null