Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate a C struct based on a complex Haskell type

Tags:

c

haskell

ffi

I am trying to use a Haskell library in my C code. The Haskell function I am trying to use has the type String -> IO [Reference] where Reference is a rather complex structure (see here for details).

Based on reading various pieces of documentation it seems that I would have to make this type an instance of Storable and also have a similar struct defined in my c code to be able to access it. This seems like a lot of very repetitive work for such a complex type. Is there a way to automate this? How would one go about doing such a thing?

like image 543
Jakub Hampl Avatar asked Jan 24 '13 11:01

Jakub Hampl


2 Answers

It depends on you actual use case, but... It could be easier to export Reference as opaque type (via Foreign.StablePtr), and export getter functions to access individual fields.

Please let me know if you need more details, and I'll expand the answer.

like image 55
Yuras Avatar answered Nov 12 '22 17:11

Yuras


I wrote a little tool (using Template Haskell), that does automagically marshal any data type that consists of primitive types (Int, Float, Double, Char, Bool), List of a marshallable type, and structs consisting of marshallable types into a corresponding C type.

  • Primitive types become their C counterparts: Int -> int, Float -> float. Bool becomes int.
  • "Structs" (data S = S ...) become pointers to a struct with marshalled members of the Haskell "struct".
  • Arrays ([S]) become pointers to a struct consisting of a pointer to an array of pointers to that type, and an int, telling how many elements are in there.

So this:

data Test = Test [MyStruct] Int
data MyStruct = MyStruct Int

would look like this in C:

struct MyStruct {
  int x;
}

struct ArrayStruct {
  MyStruct** array;
  int count;
}

struct Test {
  ArrayStruct* arr_str;
  int y;
}

Here is the tool: https://github.com/food2games/fieldmarshal

(It also has a C# part, but you will need HsFieldMarshal.) It consists of two files, you just have to copy them to your code. Usage:

$(makeStorable ''YourType)

Please note, that it doesn't do Storable code automatically for subtypes, so if you have this:

data Type1 = Type1 Int Float
data Type2 = Type2 Int Type1

than you have to generate Storable instances to each data type:

$(makeStorable ''Type1)
$(makeStorable ''Type2)

Also note, that you have to declare data types earlier than the Storable instance generation (it's because of TH). So this won't work:

$(makeStorable ''Wrong)
data Wrong = Wrong Int

This is absolutely not foolproof, it's enough for simple apps, but if you are working with a more complex code, things can get messed up pretty easily.

like image 27
user2028319 Avatar answered Nov 12 '22 15:11

user2028319