import nitni
import ffi
import naive_interpreter
-import debugger_socket # To linearize `ToolContext::init`
+import pkgconfig
redef class ToolContext
# * Must use the nested foreign code block of the FFI.
# * Must not have callbacks.
# * Must be implemented in C.
+ # * Must not have a parameter or return typed with a Nit standard class.
fun supported_by_dynamic_ffi: Bool
do
+ # If the user specfied `is light_ffi`, it must be supported
+ var nats = get_annotations("light_ffi")
+ if nats.not_empty then return true
+
var n_extern_code_block = n_extern_code_block
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
- var mtype = mparam.mtype
- if not mtype.is_cprimitive then
+ 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
end
# External compiler used to generate the foreign code library
- private var c_compiler = "gcc"
+ private var c_compiler = "cc"
end
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
+ # Compiler options specific to this module
+ var ldflags_array = mmodule.ldflags[""]
+ if ldflags_array.has("-lrt") and system("sh -c 'uname -s 2>/dev/null || echo not' | grep Darwin >/dev/null") == 0 then
+ # Remove -lrt on OS X
+ ldflags_array.remove "-lrt"
end
+ var ldflags = ldflags_array.join(" ")
- var ldflags = mmodule.ldflags[""].join(" ")
- # TODO pkgconfig
+ # Protect pkg-config
+ var pkgconfigs = mmodule.pkgconfigs
+ var pkg_cflags = ""
+ if not pkgconfigs.is_empty then
+
+ # Check if the pkgconfig packages are available
+ v.modelbuilder.toolcontext.check_pkgconfig_packages pkgconfigs
+ if not v.modelbuilder.toolcontext.check_errors then return false
+
+ pkg_cflags = "`pkg-config --cflags {pkgconfigs.join(" ")}`"
+ ldflags += " `pkg-config --libs {pkgconfigs.join(" ")}`"
+ end
# Compile each source file to an object file (or equivalent)
var object_files = new Array[String]
for f in srcs do
- f.compile(v, mmodule, object_files)
+ f.compile(v, mmodule, object_files, pkg_cflags)
end
# Link everything in a shared library
- # TODO customize the compiler
var cmd = "{v.c_compiler} -Wall -shared -o {foreign_code_lib_path} {object_files.join(" ")} {ldflags}"
- if sys.system(cmd) != 0 then
+ if system(cmd) != 0 then
v.fatal "FFI Error: Failed to link native code using `{cmd}`"
return false
end
redef class ExternFile
# Compile this source file
private fun compile(v: NaiveInterpreter, mmodule: MModule,
- object_files: Array[String]): Bool is abstract
+ object_files: Array[String], pkg_cflags: String): Bool is abstract
end
redef class ExternCFile
- redef fun compile(v, mmodule, object_files)
+ redef fun compile(v, mmodule, object_files, pkg_cflags)
do
var compile_dir = v.compile_dir
- var cflags = mmodule.cflags[""].join(" ")
+ var cflags = mmodule.cflags[""].join(" ") + " " + pkg_cflags
var obj = compile_dir / filename.basename(".c") + ".o"
- var cmd = "{v.c_compiler} -Wall -c -fPIC -I {compile_dir} -g -o {obj} {filename} {cflags}"
+ var cmd = "{v.c_compiler} -Wall -c -fPIC -I {compile_dir} -g -o {obj} {compile_dir / filename} {cflags}"
if sys.system(cmd) != 0 then
v.fatal "FFI Error: Failed to compile C code using `{cmd}`"
return false