Compile user FFI code and a standardized API into a .so file

Returns true on success.

Property definitions

nitc :: on_demand_compiler $ AModule :: compile_foreign_lib
	# Compile user FFI code and a standardized API into a `.so` file
	#
	# Returns `true` on success.
	fun compile_foreign_lib(v: NaiveInterpreter): Bool
	do
		var mmodule = mmodule
		assert mmodule != null

		var compile_dir = v.compile_dir
		var foreign_code_lib_path = v.foreign_code_lib_path(mmodule)

		if not compile_dir.file_exists then compile_dir.mkdir(0o700)

		# Compile the common FFI part
		ensure_compile_ffi_wrapper
		for mclassdef in mmodule.mclassdefs do for mpropdef in mclassdef.mpropdefs do
			var anode = v.modelbuilder.mpropdef2node(mpropdef)
			if mpropdef isa MMethodDef and anode isa AMethPropdef and anode.supported_by_dynamic_ffi then
				anode.compile_ffi_method(mmodule)
			end
		end
		mmodule.finalize_ffi_wrapper(compile_dir, mmodule)

		# Compile the standard API and its implementation for the .so file
		var ccu = compile_foreign_lib_api(compile_dir)

		var srcs = [for file in ccu.files do new ExternCFile(file, ""): ExternFile]
		srcs.add_all mmodule.ffi_files

		# 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(" ")

		# 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, pkg_cflags)
		end

		# Link everything in a shared library
		var cmd = "{v.c_compiler} -Wall -shared -o {foreign_code_lib_path} {object_files.join(" ")} {ldflags}"
		if system(cmd) != 0 then
			v.fatal "FFI Error: Failed to link native code using `{cmd}`"
			return false
		end

		return true
	end
src/interpreter/dynamic_loading_ffi/on_demand_compiler.nit:100,2--164,4