Reputation:
In Python I can do this:
import ctypes
import ctypes.util
my_lib = ctypes.cdll.LoadLibrary (ctypes.util.find_library ('my_lib') or 'my_lib32')
a = my_lib.some_function(33)
b = my_lib.some_function2(33)
c = my_lib.SOME_CONST_123
And since I need to convert this type of Python code to Haskell, I wonder can I do the same thing in Haskell? I know I can something like this throug FFI. But it's not exactly what I can do in Python because as far as I am concerned in Haskell I'd have to declare the functions first like the following:
foreign import ccall "my_lib.h some_function"
some_function :: CDouble -> CDouble
Is that true, is there an easier way?
Upvotes: 4
Views: 214
Reputation: 8409
The ctypes library in Python is basically a wrapper around the C library libffi
which is a library that let's us invoke arbitrary functions in the process's address space given information at runtime instead of compile-time.
The same library can be used in Haskell together with the dynamic linker to achieve the same effect:
import Foreign.LibFFI
import System.Posix.DynamicLinker
example :: IO ()
example = do
dlopen "mylib.so" [RTLD_LAZY]
fn <- dlsym Default "some_function"
fn2 <- dlsym Default "some_function2"
a <- callFFI fn retCInt [argCInt 33]
b <- callFFI fn2 retCInt [argCInt 33]
return ()
This isn't ideal for a lot of reasons, and I wouldn't recommend building a large set of bindings like this for the same reason that many Python developers frown on using ctypes for bindings except as a last resort. For one it will have some overhead (roughly the same overhead that ctypes has) for each function call. As compared to a ccall unsafe
FFI function from Haskell which has basically no overhead and is as cheap as a native C function call.
Second, instead of having arguments with nice simple Haskell types like Int
and Float
arguments to functions are now all in a giant libffi sum type Arg
that's opaque to the type system and is quite easy to introduce subtle bugs.
If you can link the C library at compile-time and forward declare the functions, either using the regular Haskell FFI ( -XForeignFunctionInterface
) and/or tools like c2hs it will make life much easier.
Upvotes: 4