X-Git-Url: http://nitlanguage.org diff --git a/src/common_ffi/common_ffi.nit b/src/common_ffi/common_ffi.nit index 44179db..cb9c244 100644 --- a/src/common_ffi/common_ffi.nit +++ b/src/common_ffi/common_ffi.nit @@ -19,108 +19,114 @@ # to wrap foreign code in Nit methods. module common_ffi -import parser import modelbuilder import nitni -import ffi_base +intrude import ffi_base import extern_classes import header_dependency import pkgconfig import c_compiler_options import c import cpp +import java +import extra_java_files redef class MModule # Does this module uses the FFI? var uses_ffi: Bool = false -end -redef class AModule # C compilation unit for the FFI files private var ffi_ccu: nullable CCompilationUnit = null # Foreign language used in this AModule private var present_languages = new HashSet[FFILanguage] - # Callbacks used locally - var ffi_callbacks = new HashMap[FFILanguage, Set[NitniCallback]] + # Complete the compilation of the FFI code + fun finalize_ffi_wrapper(compdir: String, mainmodule: MModule) + do + for language in ffi_callbacks.keys do + for callback in ffi_callbacks[language] do + language.compile_callback(callback, self, mainmodule, ffi_ccu.as(not null)) + end + + language.compile_to_files(self, compdir) + end + + # include dependancies FFI + for mod in header_dependencies do + if mod.uses_ffi then ffi_ccu.header_custom.add("#include \"{mod.name}._ffi.h\"\n") + end + + ffi_ccu.write_as_impl(self, compdir) + for filename in ffi_ccu.files do ffi_files.add(new ExternCFile(filename, c_compiler_options)) + end + + # Avoid the compile a ffi propdef more than once + # See `AMethPropdef::compile_ffi_method` + # FIXME find a better way + private var compiled_ffi_methods = new HashSet[AMethPropdef] +end + +redef class AModule # Ensures all of the general foreign code of the module has been analyzed. # Manages header blocks, extern class types and foreign dependancies between modules fun ensure_compile_ffi_wrapper do - if ffi_ccu != null then return + var mmodule = mmodule + if mmodule == null or mmodule.ffi_ccu != null then return # ready extern code compiler var ffi_ccu = new CCompilationUnit - self.ffi_ccu = ffi_ccu + mmodule.ffi_ccu = ffi_ccu # generate code for block in n_extern_code_blocks do var language = block.language assert language != null - present_languages.add(language) - language.compile_module_block(block, ffi_ccu, self) + mmodule.present_languages.add(language) + language.compile_module_block(block, ffi_ccu, mmodule) end ffi_ccu.header_c_base.add( "#include \"{mmodule.name}._nitni.h\"\n" ) + ffi_ccu.body_decl.add("#ifdef ANDROID\n") + ffi_ccu.body_decl.add(" #include \n") + ffi_ccu.body_decl.add(" #define PRINT_ERROR(...) (void)__android_log_print(ANDROID_LOG_WARN, \"Nit\", __VA_ARGS__)\n") + ffi_ccu.body_decl.add("#else\n") + ffi_ccu.body_decl.add(" #define PRINT_ERROR(...) fprintf(stderr, __VA_ARGS__)\n") + ffi_ccu.body_decl.add("#endif\n") + for nclassdef in n_classdefs do # Does it declares an extern type? if nclassdef isa AStdClassdef and nclassdef.n_extern_code_block != null then mmodule.uses_ffi = true var language = nclassdef.n_extern_code_block.language assert language != null - present_languages.add(language) + mmodule.present_languages.add(language) nclassdef.n_extern_code_block.language.compile_extern_class( - nclassdef.n_extern_code_block.as(not null), nclassdef, ffi_ccu, self) + nclassdef.n_extern_code_block.as(not null), nclassdef, ffi_ccu, mmodule) end end end - - # Complete the compilation of the FFI code - fun finalize_ffi_wrapper(compdir: String, mainmodule: MModule) - do - ensure_compile_ffi_wrapper - - for language in present_languages do if ffi_callbacks.keys.has(language) then - for callback in ffi_callbacks[language] do - language.compile_callback(callback, self, mainmodule, ffi_ccu.as(not null)) - end - - language.compile_to_files(self, compdir) - end - - # include dependancies FFI - for mod in mmodule.header_dependencies do - if mod.uses_ffi then ffi_ccu.header_custom.add("#include \"{mod.name}._ffi.h\"\n") - end - - ffi_ccu.write_as_impl(self, compdir) - for filename in ffi_ccu.files do ffi_files.add(new ExternCFile(filename, mmodule.c_compiler_options)) - end end -redef class AExternPropdef - private var ffi_has_been_compiled = false - +redef class AMethPropdef # Compile the necessary wrapper around this extern method or constructor - fun compile_ffi_method(amodule: AModule) + fun compile_ffi_method(mmodule: MModule) do assert n_extern_code_block != null - if ffi_has_been_compiled then return - ffi_has_been_compiled = true - - amodule.ensure_compile_ffi_wrapper + if mmodule.compiled_ffi_methods.has(self) then return + mmodule.compiled_ffi_methods.add self var language = n_extern_code_block.language assert language != null - amodule.present_languages.add(language) + mmodule.present_languages.add(language) n_extern_code_block.language.compile_extern_method( - n_extern_code_block.as(not null), self, amodule.ffi_ccu.as(not null), amodule) + n_extern_code_block.as(not null), self, mmodule.ffi_ccu.as(not null), mmodule) end end @@ -139,7 +145,7 @@ redef class VerifyNitniCallbacksPhase # Associate callbacks used by an extern method to its foreign language for callback in npropdef.foreign_callbacks.all do - var map = npropdef.parent.parent.as(AModule).ffi_callbacks + var map = npropdef.mpropdef.mclassdef.mmodule.ffi_callbacks if not map.keys.has(lang) then map[lang] = new HashSet[NitniCallback] map[lang].add(callback) end