Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to include FFI in OS X?

I'm having trouble building this project with the FFI extension enabled. To isolate the problem, I'm trying to compile this example (included in full below).

I'm using OS X 10.13.2, Xcode 9.2 with Command Line Tools installed (confirmed that /usr/include/ffi/ffi.h exists). I modified the example so the include line reads include <ffi/ffi.h>.

Invoking the compiler with no options, I get the following:

$ gcc closure.test.c
closure.test.c:23:13: warning: implicit declaration of function 'ffi_closure_alloc' is invalid in C99 [-Wimplicit-function-declaration]
  closure = ffi_closure_alloc(sizeof(ffi_closure), &bound_puts);
            ^
closure.test.c:23:11: warning: incompatible integer to pointer conversion assigning to 'ffi_closure *' (aka 'struct ffi_closure *') from
      'int' [-Wint-conversion]
  closure = ffi_closure_alloc(sizeof(ffi_closure), &bound_puts);
          ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
closure.test.c:35:15: warning: implicit declaration of function 'ffi_prep_closure_loc' is invalid in C99 [-Wimplicit-function-declaration]
          if (ffi_prep_closure_loc(closure, &cif, puts_binding,
              ^
closure.test.c:45:3: warning: implicit declaration of function 'ffi_closure_free' is invalid in C99 [-Wimplicit-function-declaration]
  ffi_closure_free(closure);
  ^
4 warnings generated.
Undefined symbols for architecture x86_64:
  "_ffi_closure_alloc", referenced from:
      _main in closure-7b0e9b.o
  "_ffi_closure_free", referenced from:
      _main in closure-7b0e9b.o
  "_ffi_prep_cif", referenced from:
      _main in closure-7b0e9b.o
  "_ffi_prep_closure_loc", referenced from:
      _main in closure-7b0e9b.o
  "_ffi_type_pointer", referenced from:
      _main in closure-7b0e9b.o
  "_ffi_type_sint32", referenced from:
      _main in closure-7b0e9b.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

What options/modifications do I need to correct this?

Source of closure.test.c:

#include <stdio.h>
#include <ffi.h>

/* Acts like puts with the file given at time of enclosure. */
void puts_binding(ffi_cif *cif, void *ret, void* args[],
                  void *stream)
{
  *(ffi_arg *)ret = fputs(*(char **)args[0], (FILE *)stream);
}

typedef int (*puts_t)(char *);

int main()
{
  ffi_cif cif;
  ffi_type *args[1];
  ffi_closure *closure;

  void *bound_puts;
  int rc;

  /* Allocate closure and bound_puts */
  closure = ffi_closure_alloc(sizeof(ffi_closure), &bound_puts);

  if (closure)
    {
      /* Initialize the argument info vectors */
      args[0] = &ffi_type_pointer;

      /* Initialize the cif */
      if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
                       &ffi_type_sint, args) == FFI_OK)
        {
          /* Initialize the closure, setting stream to stdout */
          if (ffi_prep_closure_loc(closure, &cif, puts_binding,
                                   stdout, bound_puts) == FFI_OK)
            {
              rc = ((puts_t)bound_puts)("Hello World!");
              /* rc now holds the result of the call to fputs */
            }
        }
    }

  /* Deallocate both closure, and bound_puts */
  ffi_closure_free(closure);

  return 0;
}
like image 631
rgchris Avatar asked Dec 10 '22 08:12

rgchris


2 Answers

Well, seems like you can fix it doing this:

$ cd
$ git clone https://github.com/libffi/libffi
$ cd libffi/
$ ./autogen.sh
$ ./configure
$ make
$ make install

This will build libffi from source and it will work even if you have libffi installed from brew, because this new version will be installed under /usr/local and not in Cellar.

Then you don't need to change the #include, keep it like #include <ffi.h>, open a terminal to the folder your isolated c source is and issue gcc -o ffi -lffi ffi.c (assuming it's the source file you have).

teixeira: ~/etudes_c $ ./ffi
Hello World!
like image 102
Niloct Avatar answered Dec 27 '22 20:12

Niloct


brew install libffi worked for me with one additional step. When you run brew info libffi you'll see the following:

# For compilers to find libffi you may need to set:
  export LDFLAGS="-L/opt/homebrew/opt/libffi/lib"
  export CPPFLAGS="-I/opt/homebrew/opt/libffi/include"

# For pkg-config to find libffi you may need to set:
  export PKG_CONFIG_PATH="/opt/homebrew/opt/libffi/lib/pkgconfig"

Exporting these env vars allowed rvm to work correctly.

like image 40
Stuart Mclean Avatar answered Dec 27 '22 19:12

Stuart Mclean