ffi-generate

Generate FFI Bindings from header file

npm install ffi-generate
1 downloads in the last day
17 downloads in the last week
44 downloads in the last month

npm install -g ffi-generate

Generate FFI Bindings

ffi-generate -f /path/to/myLibrary/header.h -l libmyLibrary

Will parse the given filename and print to standard out the resulting javascript suitable for use as a module.

  • f -- required -- The header file you wish to parse
  • l -- required -- The library FFI will use to dlopen
  • m -- optional -- The module name underwhich functions will be stored (uses library name otherwise)
  • p -- optional -- Only include functions whose name starts with the provided prefix
    • you can specify multiple -p on the command line to get multiple prefixes
  • x -- optional -- Restrict to only functions declared in the given header file
  • s -- optional -- Use StrictType type wrapper (experimental)
  • L -- optional -- If libclang.{so,dylib} is in a non-standard path use this which will rerun the process with [DY]LD_LIBRARY_PATH set

It may be necessary to pass additional flags to libclang so it can better parse the header (i.e. include paths). To pass options directly to libclang use -- so ffi-generate-node knows to stop parsing arguments, the rest will be passed to libclang without modification.

ffi-generate -f /usr/include/ImageMagick/wand/MagickWand.h -l libMagickWand -m wand -p Magick -- $(Magick-config --cflags)

Generate FFI Bindings Programatically

var exec = require('child_process').exec;
var path = require('path');
var fs = require('fs');
var jsb = require('beautifyjs');
var generate = require('lib/generateffi').generate;

exec('llvm-config --includedir', function (fail, out, err) {
  var includedir = out.replace(/\s+$/, '');
  var result = exports.generate({
    filename: path.join(includedir, 'clang-c', 'Index.h'),
    library: 'libclang',
    prefix: 'clang_', 
    includes: [includedir],
  });

  if (result.unmapped.length > 0) {
    console.log('----- UNMAPPED FUNCTIONS -----');
    console.log(result.unmapped);
    console.log('----- UNMAPPED FUNCTIONS -----');
  }

  fs.writeFileSync(path.join(__dirname, 'dynamic_clang.js'), jsb.js_beautify(result.serialized));
  var dynamic_clang = require(path.join(__dirname, 'dynamic_clang'));
  var ver = dynamic_clang.libclang.clang_getClangVersion();
  console.log(dynamic_clang.libclang.clang_getCString(ver));
  dynamic_clang.libclang.clang_disposeString(ver)
});
`

Input to the generate method

  • opts.filename -- required -- the full path to the header source file to parse
  • opts.library -- required -- the library ffi should use to dlopen
  • opts.module -- optional -- the name of the module that will be exported (otherwise uses library name)
  • opts.prefix -- optional -- restrict imported functions to a given prefix
  • opts.includes -- optional -- a set of directory paths to aid type expansion
  • opts.compiler_args -- optional -- a set of clang command line options passed to the parser
  • opts.single_file -- optional -- restricts functions to only those defined in the header file
    • this does not restrict dependent types

The result from generate is an object that has two properties

  • serialized - a string representation of the bindings suitable for writing to file
  • unmapped - a set of functions that failed to map -- most likely from failure to map a type to ffi type.
    • each element is an object with following properties
    • position - -1 means the return type, otherwise the argument
    • arg - name of the type that failed to map
    • name - the name of the function that failed
    • decl - the signature of the function that failed
npm loves you