digitalmars.D.learn - Wrapping C code?
- CJS (14/14) Mar 29 2014 I've been using a medium-sized C library. Most of the library
- bearophile (7/21) Mar 29 2014 If you give context a precise type (so no void*), you can use
- bearophile (4/5) Mar 29 2014 Sorry, I meant:
- CJS (5/10) Mar 29 2014 When you say define them in bulk at compile time, is there some
- bearophile (7/12) Mar 29 2014 You also need extern(C). So the code gets more complex, sorry.
- anonymous (6/11) Mar 29 2014 Well, you can write one. You can also let D generate that list:
- Artur Skawina (10/22) Mar 29 2014 The problem description is a little vague, at least w/o more context. If
I've been using a medium-sized C library. Most of the library calls look something like XXXXaction(context, arg1, arg2) Where XXXX is the name of the library, action is the action to take, and context is an opaque pointer defined by the library to keep all the state related to these actions. Is there a simple way to wrap this library so I could make calls that look like context.action(arg1, arg2)? I'm hoping for something with less manual work than having to wrap each individual function call. Especially since the types involved in the library can be somewhat complex and require trawling through multiple header files to find out the true definition.
Mar 29 2014
CJS:I've been using a medium-sized C library. Most of the library calls look something like XXXXaction(context, arg1, arg2) Where XXXX is the name of the library, action is the action to take, and context is an opaque pointer defined by the library to keep all the state related to these actions. Is there a simple way to wrap this library so I could make calls that look like context.action(arg1, arg2)? I'm hoping for something with less manual work than having to wrap each individual function call. Especially since the types involved in the library can be somewhat complex and require trawling through multiple header files to find out the true definition.If you give context a precise type (so no void*), you can use UFCS (uniform function call syntax) and define aliases like this: alias context = XXXXaction; You can define such aliases in bulk at compile-time in some way. Bye, bearophile
Mar 29 2014
alias context = XXXXaction;Sorry, I meant: alias action = XXXXaction; Bye, bearophile
Mar 29 2014
On Saturday, 29 March 2014 at 19:16:34 UTC, bearophile wrote:When you say define them in bulk at compile time, is there some convenient way to just give an array of actions and iterate over them to generate such statements? So that the only work that needs to be updated to add/remove actions is updating that list?alias context = XXXXaction;Sorry, I meant: alias action = XXXXaction; Bye, bearophile
Mar 29 2014
CJS:When you say define them in bulk at compile time, is there some convenient way to just give an array of actions and iterate over them to generate such statements? So that the only work that needs to be updated to add/remove actions is updating that list?You also need extern(C). So the code gets more complex, sorry. You need a list of the C functions with their signatures, and then you can import this list at compile time and generate the D names, and mix them in a module with mixin(code). Bye, bearophile
Mar 29 2014
On Saturday, 29 March 2014 at 19:25:37 UTC, CJS wrote:When you say define them in bulk at compile time, is there some convenient way to just give an array of actions and iterate over them to generate such statements? So that the only work that needs to be updated to add/remove actions is updating that list?Well, you can write one. You can also let D generate that list: __traits(allMembers, some_c_module) gives you all symbols in some_c_module. Iterate over them, generate alias declarations, mix those declarations in.
Mar 29 2014
Well, you can write one. You can also let D generate that list: __traits(allMembers, some_c_module) gives you all symbols in some_c_module. Iterate over them, generate alias declarations, mix those declarations in.I don't understand how that is possible. The C code I have available is a compiled library and its headers, so libfoo.a (or libfoo.so) and foo.h. I've compiled D calling C before by declaring the C function inside D code and then linking libfoo.a to the compiled D code. Can you provide a short example of how this would work?
Mar 29 2014
On Saturday, 29 March 2014 at 21:30:03 UTC, CJS wrote:[...]Well, you can write one. You can also let D generate that list: __traits(allMembers, some_c_module) gives you all symbols in some_c_module.I don't understand how that is possible. The C code I have available is a compiled library and its headers, so libfoo.a (or libfoo.so) and foo.h. I've compiled D calling C before by declaring the C function inside D code and then linking libfoo.a to the compiled D code. Can you provide a short example of how this would work?Maybe I worded that a bit misleading. You do need those declarations in D. There's no simple solution with just a C header. But there is a tool that translates C headers to D: dstep. I didn't use it myself yet, so I can't comment on its quality. Alternatively, make the declarations manually, as you did so far. Put them in a separate module. That's some_c_module (.d or .di), which looks something like this: --- module some_c_module; extern(C): /* or maybe extern(System) */ void XXXXaction(context, arg1, arg2); /* ... etc ... */ --- And here's one version how to generate aliases without the prefix: --- import std.algorithm: joiner, map, startsWith; import std.conv: to; import std.string: chompPrefix; string aliasPrefixAway(string symbol, string prefix) { return symbol.startsWith(prefix) && symbol != prefix ? "alias " ~ symbol.chompPrefix(prefix) ~ " = " ~ symbol ~ ";" : ""; } string aliasPrefixAway(string[] symbols, string prefix) { return symbols.map!(s => aliasPrefixAway(s, prefix)).joiner.to!string; } import some_c_module; mixin(aliasPrefixAway([__traits(allMembers, some_c_module)], "XXXX")); /* action is an alias of XXXXaction now. */ --- Most of that is just string fiddling, generating D code. The more interesting parts are __traits(allMembers, ...) and the string mixin.
Mar 29 2014
On 03/29/14 20:01, CJS wrote:I've been using a medium-sized C library. Most of the library calls look something like XXXXaction(context, arg1, arg2) Where XXXX is the name of the library, action is the action to take, and context is an opaque pointer defined by the library to keep all the state related to these actions. Is there a simple way to wrap this library so I could make calls that look like context.action(arg1, arg2)? I'm hoping for something with less manual work than having to wrap each individual function call. Especially since the types involved in the library can be somewhat complex and require trawling through multiple header files to find out the true definition.The problem description is a little vague, at least w/o more context. If you control D's view of that opaque structure then the simpliest solution would be something like: struct XXXXContext { auto ref opDispatch(string NAME, Args...)(Args args) { return mixin("XXXX"~NAME~"(&this, args)"); } } artur
Mar 29 2014