www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Wrapping C code?

reply "CJS" <Prometheus85 hotmail.com> writes:
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
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
 alias context = XXXXaction;
Sorry, I meant: alias action = XXXXaction; Bye, bearophile
Mar 29 2014
parent reply "CJS" <Prometheus85 hotmail.com> writes:
On Saturday, 29 March 2014 at 19:16:34 UTC, bearophile wrote:
 alias context = XXXXaction;
Sorry, I meant: alias action = XXXXaction; Bye, bearophile
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?
Mar 29 2014
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
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
prev sibling parent reply "anonymous" <anonymous example.com> writes:
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
parent reply "CJS" <Prometheus85 hotmail.com> writes:
 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
parent "anonymous" <anonymous example.com> writes:
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
prev sibling parent Artur Skawina <art.08.09 gmail.com> writes:
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