Home

Awesome

c2ffi-ruby

This is a bridge between c2ffi and ruby-ffi. It reads the JSON output produced by c2ffi and produces very readable Ruby. Example:

#define FOO (1 << 2)

#define QUUX "abc"

const int BAR = FOO + 10;
const char *Quux = QUUX;

extern int SomeExtern;

void blah(char *x[]);

extern char *foo;

typedef struct my_point {
  int x;
  int y;
  int odd_value[BAR + 1];
} my_point_t;

typedef struct {
  int a, b;
} anonymous_t;

typedef struct some_struct {
  struct _some_internal_struct {
    struct {
      double x;
    } a;
    int x;
    char c;

    enum {
      X, Y, Z
    } m;
  } s;

  int blah;
} some_struct_t;

union my_union {
  char c;
  int i;
  double d;
};

enum some_values {
  a_value,
  another_value,
  yet_another_value
};

void do_something(my_point_t *p, int x, int y);
require 'ffi'

module Example
  extend FFI::Library
  ffi_lib "ex1", "ex2"

  BAR = 14

  QUUX = "abc"

  attach_variable :SomeExtern, :SomeExtern, :int

  attach_function 'blah', [
    :pointer,
  ], :void

  attach_variable :foo, :foo, :string

  class My_Point < FFI::Union
    layout \
      :x, :int,
      :y, :int,
      :odd_value, [:int, 15]
  end

  My_Point_T = My_Point

  class Anon_Type_0 < FFI::Union
    layout \
      :a, :int,
      :b, :int
  end

  Anonymous_T = Anon_Type_0

  class Anon_Type_1 < FFI::Union
    layout \
      :x, :double
  end

  enum :anon_type_2, [
    :X, 0,
    :Y, 1,
    :Z, 2,
  ]

  class C_Some_Internal_Struct < FFI::Union
    layout \
      :a, Anon_Type_1,
      :x, :int,
      :c, :char,
      :m, :anon_type_2
  end

  class Some_Struct < FFI::Union
    layout \
      :s, C_Some_Internal_Struct,
      :blah, :int
  end

  Some_Struct_T = Some_Struct

  class My_Union < FFI::Union
    layout \
      :c, :char,
      :i, :int,
      :d, :double
  end

  enum :some_values, [
    :a_value, 0,
    :another_value, 1,
    :yet_another_value, 2,
  ]

  attach_function 'do_something', [
    :pointer,
    :int,
    :int,
  ], :void

  QUUX = "abc"

  FOO = 4
end

Usage

First, produce a spec file using c2ffi:

$ cd example/simple/
$ c2ffi -M macros.h -o example.spec example.h
$ c2ffi -o macros.spec macros.h

Now you can generate a file manually with the included tool, bin/c2ffi-ruby, as follows:

$ c2ffi-ruby -M Example -l ex1,ex2 -o simple.rb *.spec

This produces the simple.rb file, as included. Realistically, you should integrate this into your build process; you can either use this tool, or call C2FFI::Parser.parse directly.

C2FFI::Parser.parse(module_name, lib_or_libs, spec_array, io = $stdout)

Note that C2FFI::Parser doesn't actually parse JSON, but rather takes an array of hashes. In theory, you could use this to produce output for any input format that is parsed in a similar manner.