Binding to Libdb, FunPtrs

Hello, I'd like to use c2hs to create a binding for Sleepy Cat's LibDB. However, some difficulties crop up: - variadic functions. I realize I can't call them anyway, and I don't need to (they are just for primitive error reporting). But there are pointers to variadic functions in some structures, and I need c2hs to parse them and correctly calculate offsets. - lots of FunPtrs. The whole API is defined as structures with FunPtrs inside. c2hs will happily create get hooks for them, but won't generate the foreign import "dynamic" declarations. - defines. Am I right in assuming that c2hs does not recognize #define'd constant and so cannot reflect them in Haskell? I'm willing to dive into the code and fix this, I just want to make sure I don't (clumsily) duplicate any effort. As for the FunPtrs inside structs, I'm thinking of a new hook that combines a get hook and a fun (or call) hook. Does anyone have a better idea? Regards, Udo. -- Manchmal stehe ich nachts auf und installier's mir einfach... -- H0arry @ IRC

On Sun, 2006-04-23 at 00:43 +0200, Udo Stenzel wrote:
Hello,
I'd like to use c2hs to create a binding for Sleepy Cat's LibDB. However, some difficulties crop up:
- variadic functions. I realize I can't call them anyway, and I don't need to (they are just for primitive error reporting). But there are pointers to variadic functions in some structures, and I need c2hs to parse them and correctly calculate offsets.
- lots of FunPtrs. The whole API is defined as structures with FunPtrs inside. c2hs will happily create get hooks for them, but won't generate the foreign import "dynamic" declarations.
- defines. Am I right in assuming that c2hs does not recognize #define'd constant and so cannot reflect them in Haskell?
I'm willing to dive into the code and fix this, I just want to make sure I don't (clumsily) duplicate any effort. As for the FunPtrs inside structs, I'm thinking of a new hook that combines a get hook and a fun (or call) hook. Does anyone have a better idea?
Sounds good. Feel free to discuss these issues on this list and send in any darcs patches you make for review. Manuel may well have some comments on the issues you've brought up but he's often quite busy so you may like to start discussing/hacking the least controversial bits. Duncan

Duncan Coutts wrote:
Manuel may well have some comments on the issues you've brought up but he's often quite busy so you may like to start discussing/hacking the least controversial bits.
And so I did. Attached is a path that defers the error about variadic functions a bit. This was surprisingly simple, it basically worked on the first try. Now I can write get hooks for the "methods" in libdb, and if I manually write lots of foreign import dynamic declarations, I call call them. The next step is to generate them. I think, the easiest way is to extend the call and fun hooks to accept cids of the form struct->method, which would then create a dynamic import and act like a combination of get and call hooks. Libdb always passes the struct itself as the first argument to the method. This seems to be a fairly common convention. Do you think it deserves special support? Udo. -- <xinkeT> "Lord grant me the serenity to accept the things I cannot change, the courage to change the things I can, and the wisdom to hide the bodies of the people I had to kill because they pissed me off."

Udo Stenzel:
Duncan Coutts wrote:
Manuel may well have some comments on the issues you've brought up but he's often quite busy so you may like to start discussing/hacking the least controversial bits.
And so I did. Attached is a path that defers the error about variadic functions a bit. This was surprisingly simple, it basically worked on the first try. Now I can write get hooks for the "methods" in libdb, and if I manually write lots of foreign import dynamic declarations, I call call them.
Good work! I just added the patch to the public repo.
The next step is to generate them. I think, the easiest way is to extend the call and fun hooks to accept cids of the form struct->method, which would then create a dynamic import and act like a combination of get and call hooks. Libdb always passes the struct itself as the first argument to the method. This seems to be a fairly common convention. Do you think it deserves special support?
I actually looked at Sleepy Cat's LibDB myself at some point, but then never got around to doing anything about it. I remember their OOish set up. Your plan sounds reasonable. As for the struct as the first argument, I think it is a common pattern, but I it might be a bit awkward to implement. If it is, maybe leave it for a second round. Fun hooks share the `callImport' function with call hooks, which is what generates the import declaration (this is in c2hs/gen/GenBind.hs). The struct-method variant should also be able to share code like this (but I guess, you figured that out already anyway). In a previous message, you asked,
- defines. Am I right in assuming that c2hs does not recognize #define'd constant and so cannot reflect them in Haskell?
Correct. There is a plan to add some support for this to enum hooks, but I never got around to implement that. I currently suggest to use inline C in .chs file to bind #define'd enums. See c2hs/tests/Enum.chs for an example (the ThisThat definition). Thanks for the code! Manuel

Hello, I made so progress on the LibDB difficulties. Attached is patch that allows an access path instead of an identifier in call and fun hooks. The behaviour is unchanged if the access path happens to be a single identifier, otherwise the hook will behave as a get hook followed by a call via the extracted FunPtr. I decided to simply treat the "object" as an additional parameter. This way I can retain all the comfort of semi-automatic marshalling. For the "object oriented" calls this implies that the object has to be passed to the hook twice. It turns out that nothing special is required to get rid of this annoyance, I can just reuse the "one marshaller for two C parameters" feature. Here's what a typical declaration would look like, including auxillary definitions:
newtype Db k v = Db (Ptr ()) with2Db (Db p) k = k (p,p)
{# fun unsafe DB->close as ^ { with2Db* `Db k v'&, `Int' } -> `()' chk_db_close* #}
chk_db_close = throwIfNotNull "dbClose"
and this is what the call would look like:
dbClose db 0
The code is not perfect, yet. I cut-and-pasted some and a refactoring would be in order. However, I'd like to see how this extension works out by binding to more of Libdbs, first. Feel free to comment on any stupid ideas above. For the #defines, used mostly for flags, I'm going with the enum workaround found in the examples directory. That's good enough for now. BTW, Manuel, thanks for a very useful and quite hackable tool. Regards, Udo. -- The future isn't what it used to be. (It never was.)

Udo,
Attached is patch that allows an access path instead of an identifier in call and fun hooks. The behaviour is unchanged if the access path happens to be a single identifier, otherwise the hook will behave as a get hook followed by a call via the extracted FunPtr.
Thanks for that!
The code is not perfect, yet. I cut-and-pasted some and a refactoring would be in order. However, I'd like to see how this extension works out by binding to more of Libdbs, first. Feel free to comment on any stupid ideas above.
I pushed your patches to the main repository. Once you are sure that the feature works sufficiently well for you, can you please * update the documentation (doc/c2hs/c2hs.sgml) and * try to clean the code up. If you are having trouble with the latter, let me know and I'll have a look. Manuel
participants (3)
-
Duncan Coutts
-
Manuel M T Chakravarty
-
Udo Stenzel