After checking (most recent) tag v3.2.1:
% sh autogen.sh
% ./configure CC=i686-pc-mingw32-gcc
% make check
All tests appear to fail.
Using CC=gcc, tests seem to work properly. Unfortunately I need the resulting build to have no cygwin dependencies, since I'm building a JNI DLL.
I tried building libffi
using MSYS2 environment and mingw-w64
and I hit the same wall:
a) all tests seem to fail when I run make check
b) when I try to compile the libffi
Hello World example with -lffi
,
the linker complains about unresolved references to all ffi-related symbols (the symbols are indeed included in libffi.a
, but probably due to circular dependencies and the order of object files, the linker fails to collect all the symbols)
Fortunately, if I drop -lffi
and instead include all object files (*.o
) created by libffi make
operation, the created executable runs just fine.
Here's a link to the libffi Hello World example I used: http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Closure-Example.html
[EDIT]
After some additional experiments, I managed to compile the program by replacing -lffi
with -Wl,--whole-archive,-lffi,--no-whole-archive
. This way, the linker would include all object files from libffi.a
and everything would work just fine.
Here's the Hello World example (hello.c
) with detailed steps I used, in case someone finds this info useful:
/*
* Steps for building libffi on Windows and running this Hello World example:
*
* 1. Download and install the latest version of MSYS2
* a) download the latest (64-bit or 32-bit) installer from http://msys2.github.io
* b) run the installer accepting default settings
* c) execute the following commands to update the system core
* pacman -Sy pacman
* pacman -Syu
* pacman -Su
* d) restart MSYS2, if requested to do so
* e) execute the following command to install development tools
* for 64-bit gcc:
* pacman --needed -S base-devel dejagnu mingw-w64-x86_64-gcc
* for 32-bit gcc:
* pacman --needed -S base-devel dejagnu mingw-w64-i686-gcc
* f) restart MSYS2
* 2. Download and compile the latest version of libffi
* a) download the latest source code bundle from https://github.com/libffi/libffi/releases
* b) unpack the source code bundle in MSYS2 tmp directory (e.g. C:\msys64\tmp)
* c) execute the following MSYS2 commands to compile libffi (adapt the version number):
* cd /tmp/libffi-3.2.1
* ./autogen.sh
* ./configure --prefix=/tmp/out --enable-static --disable-shared
* make
* d) optionally, execute the following command to run the tests:
* make check
* e) copy the distributable files to the configured /tmp/out directory
* make install
* the following files are needed for the next step:
* /tmp/out/lib/libffi.a
* /tmp/out/lib/libffi-3.2.1/include/ffi.h
* /tmp/out/lib/libffi-3.2.1/include/ffitarget.h
* 3. Compile this example
* a) copy this file to MSYS2 tmp directory (e.g. C:\msys64\tmp\hello.c)
* b) execute the following MSYS2 command to compile the example:
* gcc -I /tmp/out/lib/libffi-3.2.1/include -L /tmp/out/lib -lffi -o /tmp/hello /tmp/hello.c
* c) run the example (/tmp/hello.exe), the output should be:
* Hello World!
*
* Troubleshooting
*
* If the tests seem to fail and the compilation in step 3b) above reports undefined references to 'ffi_*' symbols,
* try compiling using the following command instead:
* gcc -I /tmp/out/lib/libffi-3.2.1/include -L /tmp/out/lib -Wl,--whole-archive,-lffi,--no-whole-archive -o /tmp/hello /tmp/hello.c
* Another alternative is to try linking the original libffi object files (*.o) and drop -lffi as follows:
* For 64-bit version:
* export SRC=/tmp/libffi-3.2.1/x86_64-w64-mingw32/src
* gcc -I /tmp/out/lib/libffi-3.2.1/include -o /tmp/hello /tmp/hello.c $SRC/prep_cif.o $SRC/types.o $SRC/raw_api.o $SRC/java_raw_api.o $SRC/closures.o $SRC/x86/ffi.o $SRC/x86/win64.o
* For 32-bit version:
* export SRC=/tmp/libffi-3.2.1/i686-w64-mingw32/src
* gcc -I /tmp/out/lib/libffi-3.2.1/include -o /tmp/hello /tmp/hello.c $SRC/prep_cif.o $SRC/types.o $SRC/raw_api.o $SRC/java_raw_api.o $SRC/closures.o $SRC/x86/ffi.o $SRC/x86/win32.o
*/
#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; /* The call interface */
ffi_type* args[1]; /* The array of pointers to function argument types */
ffi_closure* closure; /* The allocated closure writable address */
void* bound_puts; /* The allocated closure executable address */
int rc; /* The function invocation return code */
/* Allocate closure (writable address) and bound_puts (executable address) */
closure = ffi_closure_alloc(sizeof(ffi_closure), &bound_puts);
if (closure) {
/* Initialize the array of pointers to function argument types */
args[0] = &ffi_type_pointer;
/* Initialize the call interface describing the function prototype */
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;
}