import c_tools
private import annotation
import mixin
+import counter
# Add compiling options
redef class ToolContext
protected fun write_and_make(compiler: AbstractCompiler)
do
var platform = compiler.target_platform
- var toolchain = platform.toolchain(toolcontext)
+ var toolchain = platform.toolchain(toolcontext, compiler)
compile_dir = toolchain.compile_dir
- toolchain.write_and_make compiler
+ toolchain.write_and_make
end
end
redef class Platform
# The specific tool-chain associated to the platform
- fun toolchain(toolcontext: ToolContext): Toolchain do return new MakefileToolchain(toolcontext)
+ fun toolchain(toolcontext: ToolContext, compiler: AbstractCompiler): Toolchain
+ do
+ return new MakefileToolchain(toolcontext, compiler)
+ end
end
+# Build toolchain for a specific target program, varies per `Platform`
class Toolchain
+
+ # Toolcontext
var toolcontext: ToolContext
+ # Compiler of the target program
+ var compiler: AbstractCompiler
+
+ # Directory where to generate all C files
fun compile_dir: String
do
var compile_dir = toolcontext.opt_compile_dir.value
return compile_dir
end
- fun write_and_make(compiler: AbstractCompiler) is abstract
+ # Write all C files and compile them
+ fun write_and_make is abstract
end
+# Default toolchain using a Makefile
class MakefileToolchain
super Toolchain
- redef fun write_and_make(compiler)
+ redef fun write_and_make
do
var compile_dir = compile_dir
compile_dir.mkdir
var cfiles = new Array[String]
- write_files(compiler, compile_dir, cfiles)
+ write_files(compile_dir, cfiles)
# Generate the Makefile
- write_makefile(compiler, compile_dir, cfiles)
+ write_makefile(compile_dir, cfiles)
var time1 = get_time
self.toolcontext.info("*** END WRITING C: {time1-time0} ***", 2)
time0 = time1
self.toolcontext.info("*** COMPILING C ***", 1)
- compile_c_code(compiler, compile_dir)
+ compile_c_code(compile_dir)
time1 = get_time
self.toolcontext.info("*** END COMPILING C: {time1-time0} ***", 2)
end
- fun write_files(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String])
+ # Write all source files to the `compile_dir`
+ fun write_files(compile_dir: String, cfiles: Array[String])
do
var platform = compiler.target_platform
if self.toolcontext.opt_stacktrace.value == "nitstack" and platform.supports_libunwind then compiler.build_c_to_nit_bindings
self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
end
- fun makefile_name(mainmodule: MModule): String do return "{mainmodule.c_name}.mk"
+ # Get the name of the Makefile to use
+ fun makefile_name: String do return "{compiler.mainmodule.c_name}.mk"
- fun default_outname(mainmodule: MModule): String
+ # Get the default name of the executable to produce
+ fun default_outname: String
do
+ var mainmodule = compiler.mainmodule
+
# Search a non fictive module
var res = mainmodule.name
while mainmodule.is_fictive do
do
var res = self.toolcontext.opt_output.value
if res != null then return res
- res = default_outname(mainmodule)
+ res = default_outname
var dir = self.toolcontext.opt_dir.value
if dir != null then return dir.join_path(res)
return res
end
- fun write_makefile(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String])
+ # Write the Makefile
+ fun write_makefile(compile_dir: String, cfiles: Array[String])
do
var mainmodule = compiler.mainmodule
var platform = compiler.target_platform
# 2. copy the binary at the right place in the `all` goal.
outpath = mainmodule.c_name
end
- var makename = makefile_name(mainmodule)
+ var makename = makefile_name
var makepath = "{compile_dir}/{makename}"
var makefile = new FileWriter.open(makepath)
makepath.file_copy_to "{compile_dir}/Makefile"
end
- fun compile_c_code(compiler: AbstractCompiler, compile_dir: String)
+ # The C code is generated, compile it to an executable
+ fun compile_c_code(compile_dir: String)
do
- var makename = makefile_name(compiler.mainmodule)
+ var makename = makefile_name
var makeflags = self.toolcontext.opt_make_flags.value
if makeflags == null then makeflags = ""
self.header.add_decl("#include <stdlib.h>")
self.header.add_decl("#include <stdio.h>")
self.header.add_decl("#include <string.h>")
+ self.header.add_decl("#include <sys/types.h>\n")
+ self.header.add_decl("#include <unistd.h>\n")
self.header.add_decl("#include \"gc_chooser.h\"")
self.header.add_decl("#ifdef ANDROID")
self.header.add_decl(" #include <android/log.h>")
end
fun finalize_ffi_for_module(mmodule: MModule) do mmodule.finalize_ffi(self)
-
- # Division facility
- # Avoid division by zero by returning the string "n/a"
- fun div(a,b:Int):String
- do
- if b == 0 then return "n/a"
- return ((a*10000/b).to_f / 100.0).to_precision(2)
- end
end
# A file unit (may be more than one file if
else if pname == "atoi" then
v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
return true
+ else if pname == "fast_cstring" then
+ v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", 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)))
return true
var a = v.native_array_instance(type_string, v.int_instance(array.length))
v.add_decl("static {a.mtype.ctype} {varonce};")
+
+ # Pre-fill the array with the literal string parts.
+ # So they do not need to be filled again when reused
+ for i in [0..array.length[ do
+ var ne = array[i]
+ if not ne isa AStringFormExpr then continue
+ var e = v.expr(ne, null)
+ v.native_array_set(a, i, e)
+ end
+
v.add("\} else \{")
# Take the native-array from the store.
# The point is to prevent that some recursive execution use (and corrupt) the same native array
var to_s_method = v.get_property("to_s", v.object_type)
for i in [0..array.length[ do
var ne = array[i]
+ if ne isa AStringFormExpr then continue
var e = v.expr(ne, null)
# Skip the `to_s` if the element is already a String
if not e.mcasttype.is_subtype(v.compiler.mainmodule, null, type_string) then