import typing
import auto_super_init
import frontend
+import common_ffi
# Add compiling options
redef class ToolContext
cc_paths.append(path_env.split_with(':'))
end
+ var compile_dir = toolcontext.opt_compile_dir.value
+ if compile_dir == null then compile_dir = ".nit_compile"
+ self.compile_dir = compile_dir
end
+ # The compilation directory
+ var compile_dir: String
+
protected fun write_and_make(compiler: AbstractCompiler)
do
var mainmodule = compiler.mainmodule
var time0 = get_time
self.toolcontext.info("*** WRITING C ***", 1)
- var compile_dir = toolcontext.opt_compile_dir.value
- if compile_dir == null then compile_dir = ".nit_compile"
-
compile_dir.mkdir
var cfiles = new Array[String]
compiler.files_to_copy.add "{cc_paths.first}/gc_chooser.c"
compiler.files_to_copy.add "{cc_paths.first}/gc_chooser.h"
+ # FFI
+ for m in compiler.mainmodule.in_importation.greaters do if mmodule2nmodule.keys.has(m) then
+ var amodule = mmodule2nmodule[m]
+ if m.uses_ffi or amodule.uses_legacy_ni then
+ compiler.finalize_ffi_for_module(amodule)
+ end
+ end
+
# Copy original .[ch] files to compile_dir
for src in compiler.files_to_copy do
var basename = src.basename("")
fun write_makefile(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String])
do
+ var mainmodule = compiler.mainmodule
+
var outname = self.toolcontext.opt_output.value
if outname == null then
- outname = "{compiler.mainmodule.name}"
+ outname = "{mainmodule.name}"
end
var orig_dir=".." # FIXME only works if `compile_dir` is a subdirectory of cwd
var outpath = orig_dir.join_path(outname).simplify_path
- var makename = "{compiler.mainmodule.name}.mk"
+ var makename = "{mainmodule.name}.mk"
var makepath = "{compile_dir}/{makename}"
var makefile = new OFStream.open(makepath)
for p in cc_paths do
cc_includes += " -I \"" + p + "\""
end
- if toolcontext.opt_no_stacktrace.value then
- makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS ?= -lm -lgc\n\n")
- else
- makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS ?= -lunwind -lm -lgc\n\n")
+
+ var linker_options = new HashSet[String]
+ for m in mainmodule.in_importation.greaters do if mmodule2nmodule.keys.has(m) then
+ var amod = mmodule2nmodule[m]
+ linker_options.add(amod.c_linker_options)
end
+
+ if not toolcontext.opt_no_stacktrace.value then linker_options.add("-lunwind")
+
+ makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS ?= -lm -lgc {linker_options.join(" ")}\n\n")
makefile.write("all: {outpath}\n\n")
var ofiles = new Array[String]
+ var dep_rules = new Array[String]
# Compile each generated file
for f in cfiles do
var o = f.strip_extension(".c") + ".o"
makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) $(CINCL) -D NONITCNI -c -o {o} {f}\n\n")
ofiles.add(o)
+ dep_rules.add(o)
end
# Compile each required extern body into a specific .o
for f in compiler.extern_bodies do
- var basename = f.filename.basename(".c")
- var o = "{basename}.extern.o"
- var ff = f.filename
- makefile.write("{o}: {ff}\n\t$(CC) $(CFLAGS) -D NONITCNI {f.cflags} -c -o {o} {ff}\n\n")
- ofiles.add(o)
+ if f isa ExternCFile then
+ var basename = f.filename.basename(".c")
+ var o = "{basename}.extern.o"
+ var ff = f.filename.basename("")
+ makefile.write("{o}: {ff}\n\t$(CC) $(CFLAGS) -D NONITCNI {f.cflags} -c -o {o} {ff}\n\n")
+ ofiles.add(o)
+ dep_rules.add(o)
+ else
+ var o = f.makefile_rule_name
+ var ff = f.filename.basename("")
+ makefile.write("{o}: {ff}\n")
+ makefile.write("\t{f.makefile_rule_content}\n")
+ dep_rules.add(f.makefile_rule_name)
+
+ if f isa ExternCppFile then ofiles.add(o)
+ end
end
# Link edition
# Binds the generated C function names to Nit function names
fun build_c_to_nit_bindings
do
- var compile_dir = modelbuilder.toolcontext.opt_compile_dir.value
- if compile_dir == null then compile_dir = ".nit_compile"
+ var compile_dir = modelbuilder.compile_dir
var stream = new OFStream.open("{compile_dir}/C_fun_names")
stream.write("%\{\n#include \"c_functions_hash.h\"\n%\}\n")
self.header.add_decl("#include \"gc_chooser.h\"")
compile_header_structs
+ compile_nitni_structs
# Signal handler function prototype
self.header.add_decl("void show_backtrace(int);")
- # Global variable used by the legacy native interface
+ # Global variable used by intern methods
self.header.add_decl("extern int glob_argc;")
self.header.add_decl("extern char **glob_argv;")
self.header.add_decl("extern val *glob_sys;")
end
- # Declaration of structures the live Nit types
+ # Declaration of structures for live Nit types
protected fun compile_header_structs is abstract
+ # Declaration of structures for nitni undelying the FFI
+ protected fun compile_nitni_structs is abstract
+
# Generate the main C function.
# This function:
# * allocate the Sys object if it exists
end
end
+ v.add_decl("void sig_handler(int signo)\{")
+ v.add_decl("printf(\"Caught signal : %s\\n\", strsignal(signo));")
+ v.add_decl("show_backtrace(signo);")
+ v.add_decl("\}")
+
v.add_decl("void show_backtrace (int signo) \{")
if not modelbuilder.toolcontext.opt_no_stacktrace.value then
v.add_decl("char* opt = getenv(\"NIT_NO_STACK\");")
v.add_decl("int main(int argc, char** argv) \{")
- v.add("signal(SIGABRT, show_backtrace);")
- v.add("signal(SIGFPE, show_backtrace);")
- v.add("signal(SIGILL, show_backtrace);")
- v.add("signal(SIGINT, show_backtrace);")
- v.add("signal(SIGTERM, show_backtrace);")
- v.add("signal(SIGSEGV, show_backtrace);")
+ v.add("signal(SIGABRT, sig_handler);")
+ v.add("signal(SIGFPE, sig_handler);")
+ v.add("signal(SIGILL, sig_handler);")
+ v.add("signal(SIGINT, sig_handler);")
+ v.add("signal(SIGTERM, sig_handler);")
+ v.add("signal(SIGSEGV, sig_handler);")
v.add("glob_argc = argc; glob_argv = argv;")
v.add("initialize_gc_option();")
v.add("\}")
end
- # List of additional .c files required to compile (native interface)
- var extern_bodies = new Array[ExternCFile]
+ # List of additional files required to compile (FFI)
+ var extern_bodies = new Array[ExternFile]
# List of source files to copy over to the compile dir
var files_to_copy = new Array[String]
if b == 0 then return "n/a"
return ((a*10000/b).to_f / 100.0).to_precision(2)
end
+
+ fun finalize_ffi_for_module(nmodule: AModule)
+ do
+ var visitor = new_visitor
+ nmodule.finalize_ffi(visitor, modelbuilder)
+ nmodule.finalize_nitni(visitor)
+ end
+
+ # Does this compiler support the FFI?
+ fun supports_ffi: Bool do return false
end
# A file unit (may be more than one file if
var maybenull = recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType
if maybenull then
self.add("if ({recv} == NULL) \{")
- self.add_abort("Reciever is null")
+ self.add_abort("Receiver is null")
self.add("\}")
end
end
var returnlabel: nullable String writable = null
end
-# An extern C file to compile
-class ExternCFile
- # The filename of the file
- var filename: String
- # Additionnal specific CC compiler -c flags
- var cflags: String
-end
-
redef class MType
# Return the C type associated to a given Nit static type
fun ctype: String do return "val*"
# Call the implicit super-init
var auto_super_inits = self.auto_super_inits
if auto_super_inits != null then
- var selfarg = [arguments.first]
+ var args = [arguments.first]
for auto_super_init in auto_super_inits do
- if auto_super_init.intro.msignature.arity == 0 then
- v.send(auto_super_init, selfarg)
- else
- v.send(auto_super_init, arguments)
+ args.clear
+ for i in [0..auto_super_init.msignature.arity+1[ do
+ args.add(arguments[i])
end
+ v.compile_callsite(auto_super_init, args)
end
end
v.stmt(self.n_block)
for a in self.n_args.n_exprs do
args.add(v.expr(a, null))
end
- if args.length == 1 then
- args = v.frame.arguments
- end
- var mproperty = self.mproperty
- if mproperty != null then
- if mproperty.intro.msignature.arity == 0 then
- args = [recv]
+ var callsite = self.callsite
+ if callsite != null then
+ # Add additionnals arguments for the super init call
+ if args.length == 1 then
+ for i in [0..callsite.mproperty.intro.msignature.arity[ do
+ args.add(v.frame.arguments[i+1])
+ end
end
# Super init call
- var res = v.send(mproperty, args)
+ var res = v.compile_callsite(callsite, args)
return res
end
+ if args.length == 1 then
+ args = v.frame.arguments
+ end
+
# stantard call-next-method
return v.supercall(v.frame.mpropdef.as(MMethodDef), recv.mtype.as(MClassType), args)
end
end
private var properties_cache: Map[MClass, Set[MProperty]] = new HashMap[MClass, Set[MProperty]]
end
+
+redef class AModule
+ # Does this module use the legacy native interface?
+ fun uses_legacy_ni: Bool is abstract
+
+ # Write FFI results to file
+ fun finalize_ffi(v: AbstractCompilerVisitor, modelbuilder: ModelBuilder) is abstract
+
+ # Write nitni results to file
+ fun finalize_nitni(v: AbstractCompilerVisitor) is abstract
+end