Callbacks are great language construct, no matter which language, but adding data to each callback is sometimes necessary. While in C++ you can provide a std::function callback which can include user data and even use lambda with captured variables, in C its a bit different.
#include <functional> int test_function(int n1) { printf("value %d", n1); return n1; } int main() { auto f1 = std::bind(&test_function, 42 ); f1(); int n1 = 42; auto f2 = [=]() {return n1; }; f2(); return 0; }
Since you can't create a function at runtime, Many C APIs provide a way to include data pointer and this pointer is passed to the callback.
typedef void (fn)(int value, void* data); int function(fn* f, void* v) { f(1, v); return 0; }
APIs that do not provide userdata void * pointer are a bit trickier to call with user data. To overcome this problem, the developer can use something called Closures. C closures are not part of the language
To actually generate these functions, these libraries needs to know the CPU architecture and compiler used because they need to implement a compatible call.
In the end, I couldn't get the project working on Visual Studio, I've then proceeded to try libffi with Visual Studio as well and after fixing and workarounding more than a dozen errors I gave up.
I have no doubt that these two projects work in more than one environment, but perhaps because its not very simple to build and use might point to a weak link, it works by creating assembly code that encapsulates the userdata and the function pointer, completely ignoring the compiler (though it should use the same calling conventions though a provided generator). On top of that, because its not using the compiler directly, its cross-platform-ness is not as robust across compilers and CPU architectures as portable C should be. To strengthen my point, libffi for example, supports only 64bit visual c++ builds according to the build scripts.
I'm not sure if its my own fault for not being able to compile these libraries successfully on Windows/Visual Studio but in any case I see it as an important lesson about C API Design, no matter how ridiculous it might look at first, if you're expecting a callback, a void * user data should be provided as well.
I'm including my build batch for libffi/Windows, if anyone is successful using any of these libraries, share your knowledge, if you find a different method to implement closures in a cross-platform way, even better.
set CYG_ROOT=%CD%/cygwin
set CYG_CACHE=%CD%/cygwin/var/cache/setup
set CYG_MIRROR=http://mirrors.kernel.org/sourceware/cygwin/
rem libffi is not supported on x64/visual c++
rem set VCVARS_PLATFORM=x86
rem set BUILD=x86-pc-cygwin
rem set HOST=x86-pc-winnt
set VCVARS_PLATFORM=amd64
set BUILD=x86_64-pc-cygwin
set HOST=x86_64-pc-winnt
curl -O http://cygwin.com/setup-x86.exe
setup-x86.exe -qnNdO -R "%CYG_ROOT%" -s "%CYG_MIRROR%" -l "%CYG_CACHE%" -P dejagnu
setup-x86.exe -qnNdO -R "%CYG_ROOT%" -s "%CYG_MIRROR%" -l "%CYG_CACHE%" -P Devel,autoconf,automake,make,libtool
%CYG_ROOT%/bin/bash -lc "cygcheck -dc cygwin"
rem %comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"" x86
%comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"" amd64
%CYG_ROOT%\bin\sh -lc "(cd $OLDPWD; ./autogen.sh;)"
%CYG_ROOT%\bin\sh -lc "(cd $OLDPWD; ./configure CC=''$PWD'/msvcc.sh' CXX=''$PWD'/msvcc.sh' CXXCPP=''$PWD'/msvcc.sh' LD=link CPP='cl -nologo -EP' --build=$BUILD --host=$HOST; cp src/x86/ffitarget.h include; make;)"
rem %CYG_ROOT%\bin\sh -lc "(cd $OLDPWD; ./configure CC='./msvcc.sh -m64' CXX='./msvcc.sh -m64' LD=link CPP='cl -nologo -EP' --build=$BUILD --host=$HOST; cp src/x86/ffitarget.h include; make;)"
I have no doubt that these two projects work in more than one environment, but perhaps because its not very simple to build and use might point to a weak link, it works by creating assembly code that encapsulates the userdata and the function pointer, completely ignoring the compiler (though it should use the same calling conventions though a provided generator). On top of that, because its not using the compiler directly, its cross-platform-ness is not as robust across compilers and CPU architectures as portable C should be. To strengthen my point, libffi for example, supports only 64bit visual c++ builds according to the build scripts.
I'm not sure if its my own fault for not being able to compile these libraries successfully on Windows/Visual Studio but in any case I see it as an important lesson about C API Design, no matter how ridiculous it might look at first, if you're expecting a callback, a void * user data should be provided as well.
I'm including my build batch for libffi/Windows, if anyone is successful using any of these libraries, share your knowledge, if you find a different method to implement closures in a cross-platform way, even better.
set CYG_ROOT=%CD%/cygwin
set CYG_CACHE=%CD%/cygwin/var/cache/setup
set CYG_MIRROR=http://mirrors.kernel.org/sourceware/cygwin/
rem libffi is not supported on x64/visual c++
rem set VCVARS_PLATFORM=x86
rem set BUILD=x86-pc-cygwin
rem set HOST=x86-pc-winnt
set VCVARS_PLATFORM=amd64
set BUILD=x86_64-pc-cygwin
set HOST=x86_64-pc-winnt
curl -O http://cygwin.com/setup-x86.exe
setup-x86.exe -qnNdO -R "%CYG_ROOT%" -s "%CYG_MIRROR%" -l "%CYG_CACHE%" -P dejagnu
setup-x86.exe -qnNdO -R "%CYG_ROOT%" -s "%CYG_MIRROR%" -l "%CYG_CACHE%" -P Devel,autoconf,automake,make,libtool
%CYG_ROOT%/bin/bash -lc "cygcheck -dc cygwin"
rem %comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"" x86
%comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"" amd64
%CYG_ROOT%\bin\sh -lc "(cd $OLDPWD; ./autogen.sh;)"
%CYG_ROOT%\bin\sh -lc "(cd $OLDPWD; ./configure CC=''$PWD'/msvcc.sh' CXX=''$PWD'/msvcc.sh' CXXCPP=''$PWD'/msvcc.sh' LD=link CPP='cl -nologo -EP' --build=$BUILD --host=$HOST; cp src/x86/ffitarget.h include; make;)"
rem %CYG_ROOT%\bin\sh -lc "(cd $OLDPWD; ./configure CC='./msvcc.sh -m64' CXX='./msvcc.sh -m64' LD=link CPP='cl -nologo -EP' --build=$BUILD --host=$HOST; cp src/x86/ffitarget.h include; make;)"
0 comments:
Post a Comment