hxcpp-interop-testbench
hxcpp-interop-testbench copied to clipboard
Minimal working example projects to call C++ code from Haxe.
hxcpp-interop-testbench
This repository demonstrates using the various tools available to Haxe to directly interoperate with C++.
Introduction
- A native library is one which is built as a
dll(on Windows), a.so(on Linux), or.dylib(on Mac) file, which contains machine language for the target architecture, which is then linked with the target application. - A foreign function interface (FFI) is a set of code which allows for executing external code from within a given language.
- Haxe's foreign function interfaces allow for executing code from native libraries, without recompiling the runtime itself.
- This means that Haxe can access and execute code from a DLL in any language, however setup for this is very different between targets and only
hxcppworks with this out-of-the-box.
- A target native library is one which is built as a library for a specific programming language, and thus only work when building to that target.
- You can use Haxe's
externkeyword to include these libraries in your project, and these are essential for operating on code outside of Haxe. - For example, when building for the Java target,
jarfiles can be used as a target native library, and when building for the NodeJS target,jsfiles from NPM packages can be used.
- You can use Haxe's
Examples
Each sample provides a minimum example project, providing a simple addition function to demonstrate how to allow the C++ code to receive and return values. The sample libraries are made for pure Haxe; they do not require any additional libraries (such as Lime) to properly build, but should be fully compatible with them.
This library contains six examples:
| Name | Requires Separate DLL | Ease of Use† | Supports Other Targets | Supports Haxelibs |
|---|---|---|---|---|
extern |
NO | 1/5 | ❌ | ✅ |
extern-embedded |
NO | 4/5 | ❌ | ✅ |
function-code |
NO | 4/5 | ✅ | ✅ |
cffi-legacy |
YES | 2/5 | ❌ | ✅ |
cffi-prime |
YES | 3/5 | ❌ | ✅ |
ammer |
NO | 5/5 | ✅†† | ❌ |
† This is metric is based on my personal opinion on the amount of effort required to work with each method.
†† The current version of ammer is targeted at hxcpp and hashlink, with more targets in development.
extern: C++ Extern Project- Requires the target application to use the
hxcpptarget, and does not support other targets. - C++ code is placed into a separate folder from the Haxe code for organization.
- Links with the source code at build time, and doesn't require a DLL or a separate compilation step.
- Compiled project MAY run without any
testinterop.ndllfile.
- Compiled project MAY run without any
- Linked library cannot be updated without recompiling the executable.
- Requires the target application to use the
extern-embedded: C++ Embedded Externs- Requires the target application to use the
hxcpptarget, and does not support other targets. - C++ code is embedded into the Haxe code.
- Results in cleaner code on smaller projects but unmaintainable code on larger projects.
- Embedded into source code at build time, and doesn't require a DLL or separate compilation step.
- Compiled project MAY run without any
testinterop.ndllfile.
- Compiled project MAY run without any
- Linked library cannot be updated without recompiling the executable.
- Requires the target application to use the
function-code: functionCode annotation- Embeds the string directly into the compiled application, replacing any haxe expressions in the function's method body.
- Easier to sort out functions than
extern-embeddedbut harder to make them call each other. - Works on
C++andC#targets. - NOT working on
Pythontargets (thefunctionCodeannotation is ignored)- It would be cool if you could use compiler defines to choose which language-specific code to use but guess not.
cffi-legacyCFFI Legacy- Values must be boxed to be sent between C++ and Haxe, and functions are weakly typed (only checked at runtime).
- Links with the built native library at runtime, thus the
ndllfile must be included with the EXE when distributing.- Compiled project CANNOT run without the
testinterop.ndllfile in a nearby directory. - NDLL file can be updated or replaced after building without modifying the executable.
- Compiled project CANNOT run without the
- Complex configuration required to use with other targets (
hashlink,neko,python,lua, etc).
cffi-primeCFFI Prime- Modern upgrade to Haxe CFFI.
- Values do not need to be boxed and functions are strongly typed (checked at compilation time).
- Links with the built native library at runtime, thus the
ndllfile must be included with the EXE when distributing.- Compiled project CANNOT run without the
testinterop.ndllfile in a nearby directory. - NDLL file can be updated or replaced after building without modifying the executable.
- Compiled project CANNOT run without the
- Complex configuration required to use with other targets (
hashlink,neko,python,lua, etc).
- ammer
- Utilizes a library by Aurel300
- Vastly simplified linking process
- No additional configuration needed to link against
hashlinkandlua(other targets in development) - Complex configuration required to use linked code as a haxelib (library packaging in development)
Useful Resources
- https://github.com/snowkit/hxcpp-guide/issues/1
- https://community.haxe.org/t/some-questions-about-the-ammer-library-ffi-haxelib-externs/2271
- https://github.com/Aurel300/ammer
- https://github.com/larsiusprime/steamwrap