# This file is part of NIT ( http://www.nitlanguage.org ).
#
-# Copyright 2012-2013 Alexis Laferrière <alexis.laf@xymus.net>
+# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# See the License for the specific language governing permissions and
# limitations under the License.
-# This module implements the FFI with different languages
+# Full FFI support, independent of the compiler
+#
+# The full FFI support all the features of the light FFI and more:
+#
+# * More foreign languages: **C++, Java and Objective-C**.
+# * **Callbacks** to Nit from foreign codes.
+# The callbacks are declared in Nit using the `import` annotation on extern methods.
+# They are then generated on demand for the target foreign language.
+# * **Static Nit types** in C for precise typing and static typing errors in C.
+# * **Propagating public code blocks** at the module level (C Header).
+# This allows to use extern classes in foreign code in other modules
+# without having to import the related headers.
+# This is optional in C as it is easy to find the correct importation.
+# However it is important in Java and other complex FFIs.
+# * **Reference pinning** of Nit objects from foreign code.
+# This ensure that objects referenced from foreign code are not liberated by the GC.
+# * FFI **annotations**:
+# * `cflags`, `ldflags` and `cppflags` pass arguments to the C and C++
+# compilers and linker.
+# * `pkgconfig` calls the `pkg-config` program to get the arguments
+# to pass to the C copiler and linker.
+# * `extra_java_files` adds Java source file to the compilation chain.
module ffi
+import modelbuilder
+
+import nitni
+
+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
+import objc
+intrude import light_ffi
-redef class MMSrcModule
- redef fun compile_separate_module(cprogram: CProgram)
+redef class MModule
+ # Complete the compilation of the FFI code
+ redef fun finalize_ffi_wrapper(compdir, mainmodule)
do
- super
-
- if is_extern_hybrid then
- var visitor = new FFIVisitor( cprogram.program.tc, self )
- # TODO use cprogram to add generated files?
+ 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
- # actually compile stub
- accept_ffi_visitor( visitor )
+ language.compile_to_files(self, compdir)
+ end
- # write to file
- if uses_ffi then
- visitor.compile
- end
+ # include dependancies FFI
+ for mod in header_dependencies do
+ if mod.uses_ffi then ffi_ccu.header_custom.add("#include \"{mod.c_name}._ffi.h\"\n")
end
+
+ super
end
end
-redef class MMLocalClass
- super FFIVisited
-end
-redef class FFIVisitor
- fun compile
+redef class VerifyNitniCallbacksPhase
+ redef fun process_npropdef(npropdef)
do
- var compdir = tc.compdir.as(not null)
- var base_name = "{mmmodule.cname}._ffi"
- var c_file = "{base_name}.c"
- var h_file = "{base_name}.h"
+ super
- # header comments
- var module_info = "/*\n\tExtern implementation of Nit module {mmmodule.name}\n*/\n"
+ if not npropdef isa AMethPropdef then return
- # header file guard
- var guard = "{mmmodule.cname.to_s.to_upper}_NIT_H"
+ var code_block = npropdef.n_extern_code_block
+ if code_block == null then return
- # .h
- var stream = new OFStream.open( "{compdir}/{h_file}" )
- stream.write( module_info )
- stream.write( "#include <{mmmodule.name}._nitni.h>\n\n" )
- stream.write( "#ifndef {guard}\n" )
- stream.write( "#define {guard}\n\n" )
- compilation_unit.header_c_base.write_to_stream( stream )
- compilation_unit.header_custom.write_to_stream( stream )
- compilation_unit.header_c_types.write_to_stream( stream )
- compilation_unit.header_decl.write_to_stream( stream )
- stream.write( "#endif\n" )
- stream.close
+ var lang = code_block.language
+ assert lang != null
- # .c
- stream = new OFStream.open( "{compdir}/{c_file}" )
- stream.write( module_info )
- stream.write( "#include \"{h_file}\"\n" )
- compilation_unit.body_decl.write_to_stream( stream )
- compilation_unit.body_custom.write_to_stream( stream )
- compilation_unit.body_impl.write_to_stream( stream )
- stream.close
+ # Associate callbacks used by an extern method to its foreign language
+ for callback in npropdef.foreign_callbacks.all do
+ 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
end
end