X-Git-Url: http://nitlanguage.org diff --git a/src/interpreter/dynamic_loading_ffi/on_demand_compiler.nit b/src/interpreter/dynamic_loading_ffi/on_demand_compiler.nit index 415da3f..e826f05 100644 --- a/src/interpreter/dynamic_loading_ffi/on_demand_compiler.nit +++ b/src/interpreter/dynamic_loading_ffi/on_demand_compiler.nit @@ -20,6 +20,16 @@ import c_tools import nitni import ffi import naive_interpreter +import pkgconfig +import debugger_socket # To linearize `ToolContext::init` + +redef class ToolContext + + # --compile-dir + var opt_compile_dir = new OptionString("Directory used to generate temporary files", "--compile-dir") + + init do option_context.add_option opt_compile_dir +end redef class AMethPropdef # Does this method definition use the FFI and is it supported by the interpreter? @@ -30,16 +40,44 @@ redef class AMethPropdef fun supported_by_dynamic_ffi: Bool do var n_extern_code_block = n_extern_code_block - return n_extern_calls == null and n_extern_code_block != null and - n_extern_code_block.is_c + if not (n_extern_calls == null and n_extern_code_block != null and + n_extern_code_block.is_c) then return false + + for mparam in mpropdef.msignature.mparameters do + if not mparam.mtype.is_cprimitive then + return false + end + end + + var return_mtype = mpropdef.msignature.return_mtype + if return_mtype != null and not return_mtype.is_cprimitive then + return false + end + + return true end end redef class NaiveInterpreter + redef fun start(mainmodule) + do + super + + # Delete temporary files + var compile_dir = compile_dir + if compile_dir.file_exists then compile_dir.rmdir + end + # Where to store generated C and extracted code - # - # TODO make customizable and delete when execution completes - private var compile_dir = "nit_compile" + private var compile_dir: String is lazy do + # Prioritize the user supplied directory + var opt = modelbuilder.toolcontext.opt_compile_dir.value + if opt != null then return opt + return "/tmp/niti_ffi_{process_id}" + end + + # Identifier for this process, unique between running interpreters + private fun process_id: Int `{ return getpid(); `} # Path of the compiled foreign code library # @@ -66,7 +104,7 @@ redef class AModule var compile_dir = v.compile_dir var foreign_code_lib_path = v.foreign_code_lib_path(mmodule) - compile_dir.mkdir + if not compile_dir.file_exists then compile_dir.mkdir(0o700) # Compile the common FFI part ensure_compile_ffi_wrapper @@ -84,13 +122,29 @@ redef class AModule var srcs = [for file in ccu.files do new ExternCFile(file, ""): ExternFile] srcs.add_all mmodule.ffi_files - if mmodule.pkgconfigs.not_empty then - fatal(v, "NOT YET IMPLEMENTED annotation `pkgconfig`") - return false - end - + # Compiler options specific to this module var ldflags = mmodule.ldflags[""].join(" ") - # TODO pkgconfig + + # Protect pkg-config + var pkgconfigs = mmodule.pkgconfigs + var pkg_command = "" + if not pkgconfigs.is_empty then + var cmd = "which pkg-config >/dev/null" + if system(cmd) != 0 then + v.fatal "FFI Error: Command `pkg-config` not found. Please install it" + return false + end + + for p in pkgconfigs do + cmd = "pkg-config --exists '{p}'" + if system(cmd) != 0 then + v.fatal "FFI Error: package {p} is not found by `pkg-config`. Please install it." + return false + end + end + + pkg_command = "`pkg-config --cflags --libs {pkgconfigs.join(" ")}`" + end # Compile each source file to an object file (or equivalent) var object_files = new Array[String] @@ -99,9 +153,8 @@ redef class AModule end # Link everything in a shared library - # TODO customize the compiler - var cmd = "{v.c_compiler} -Wall -shared -Wl,-soname,{mmodule.name}.so -g -o {foreign_code_lib_path} {object_files.join(" ")} {ldflags}" - if sys.system(cmd) != 0 then + var cmd = "{v.c_compiler} -Wall -shared -o {foreign_code_lib_path} {object_files.join(" ")} {ldflags} {pkg_command}" + if system(cmd) != 0 then v.fatal "FFI Error: Failed to link native code using `{cmd}`" return false end @@ -134,6 +187,11 @@ typedef union nit_call_arg { int value_Bool; uint32_t value_Char; uint8_t value_Byte; + int8_t value_Int8; + int16_t value_Int16; + uint16_t value_UInt16; + int32_t value_Int32; + uint32_t value_UInt32; double value_Float; void* value_Pointer; } nit_call_arg; @@ -248,7 +306,7 @@ redef class MMethodDef for param in msignature.mparameters do params.add param.mtype.cname_blind # Declare the implementation function as extern - var impl_cname = mproperty.build_cname(mclassdef.mclass.mclass_type, + var impl_cname = mproperty.build_cname(mclassdef.bound_mtype, mclassdef.mmodule, "___impl", long_signature) ecc.body_decl.add "extern {c_return_type} {impl_cname}({params.join(", ")});\n"