C Foreign Function Interface

You are viewing an old version of this entry, click here to see latest version.

Introduction

This tutorial demonstrates how to call external C/C++ code from a haxe application. In many ways, the system is similar to the neko C Foreign Function Interface, with the main difference being that the "value" types are treaded as "opaque".

The "value" Type

All arguments and return data used for communicating between the Haxe compiled code and the native library code are declared as type "value". On the Neko target, this is a very particular data structure, and the type of element that is referred to by it can be determined by looking directly at the bits in the value variable. This means that in order for the C++ traget to be able to use the Neko ndll files directly, it would have to convert to and from these Neko values for each CFFI call. For efficiency reasons, the C++ target does not do this. Instead, as far as the external library is concerned, the value type is a generic pointer to an unknown type.

The Haxe C++ code actually knows that the value type is a pointer to its "hx::Object" structure, from which all classes derive, so the conversion for classes is very simple and fast. For the "non-class" types (Int, Bool, Float, String) the conversion requires the value to be "boxed" inside an object in order to be passed to/from the CFFI. This is exactly the same procedure that is used for passing "Dynamic" objects within the Haxe C++ code. As a consequence of this, passing non-class objects to C++ CFFI incurs a small overhead per call. The special case is the "null" value, which is encoded as the null pointer and is very fast - if your functions have nothing better to return, your should return the null value (alloc_null()).

Since the actual type of "value" variables is not known by the external code, it is very easy for this external code work with neko too. When the external code requests the "integer value of this variable", val_int(x), the external code calls a function that will ultimately call the Neko version of val_int, if the ndll is loaded into a Neko VM, or the C++ version if it is loaded into a C++ program. This extra function call represents a small overhead when running Neko code like this, however the benefits of being able to use the same ndll on both Neko and C++ targets usually makes this trade-off worth while.

One ndll to bring them all and in the darkness bind them

The C++ ndll files use a technique similar to the windows "delay load" dll binding, along with some macro magic, to allow them to be built without needing to linked against a specific dll or library file. The host application (neko or the hxcpp binary) must provide a single export symbol, "hx_cffi", which the ndll file will query for function pointers (this is done by all hxcpp applications). If this is not found, then it is assumed that the executable is neko, and tries to load the dll "nekoapi.dll". This dll exports the "hx_cffi" symbol and is linked against the standard neko cffi library, which requires the neko.dll file to be in the process, This nekoapi library provides the translation from the opaque pointers to the neko values. There is no complex logic the determine the location of this nekoapi file, so it generally must be in your library search path (executable search path on windows). The best way to ensure this is to place it next the neko.dso (neko.dll) that is being used.

The C++ FFI is available when you "#include <hx/CFFI.h>", which is distributed with the hxcpp haxelib module.

When you build an ndll file using the C++ FFI,

version #8183, modified 2010-03-08 05:52:21 by gamehaxe