digitalmars.D.learn - Wrapping multiple extern (C) declarations in a template
- aldanor (31/31) Dec 13 2014 I'm writing bindings to a rather big C library where the return
- Gary Willoughby (8/39) Dec 13 2014 Personally i wouldn't go this route. I would create foo.d as a C
- aldanor (22/29) Dec 13 2014 I've actually done it this way initially, as well, however there
- Gary Willoughby (7/28) Dec 13 2014 I don't think there is an easy way to do this. foo.d contains all
- Mike Parker (6/12) Dec 13 2014 Assuming the C library can be compiled as a shared library, you can
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (5/14) Dec 14 2014 You can also use `static import`. That way, the imported symbols
I'm writing bindings to a rather big C library where the return values of almost all functions indicate the possibility of an error (exception). Assuming there's a C header, "foo.h" with functions "f1", "f2", etc, I want to have a corresponding D module, "foo.d" which would provide the "f1", "f2" that wrap the C functions and throw exceptions if an error is encountered (which is implemented in an errorCheck template which checks the return value and then gets the exception info via C API). My current naive solution looks like this: /* foo.h */ int f1(...); int f2(...); *** foo.d *** private extern (C) nothrow { pragma(mangle, "f1") int c_f(...); public alias errorCheck!c_f1 f1; pragma(mangle, "f2") int c_f2(...); public alias errorCheck!c_f2 f2; } This way, one can "import foo" and use the same API as in C, but with proper exception handling. Since there is almost a thousand declarations, this leads to a lot of manual work and boilerplate. I guess the wrapping part itself (aliasing the wrapped functions) could be automated via a mixin template, but how would one go around repetitive pragma(mangle) (which I thought is needed so that private extern declarations have different names and don't clash with the wrapped ones )?
Dec 13 2014
On Saturday, 13 December 2014 at 16:34:42 UTC, aldanor wrote:I'm writing bindings to a rather big C library where the return values of almost all functions indicate the possibility of an error (exception). Assuming there's a C header, "foo.h" with functions "f1", "f2", etc, I want to have a corresponding D module, "foo.d" which would provide the "f1", "f2" that wrap the C functions and throw exceptions if an error is encountered (which is implemented in an errorCheck template which checks the return value and then gets the exception info via C API). My current naive solution looks like this: /* foo.h */ int f1(...); int f2(...); *** foo.d *** private extern (C) nothrow { pragma(mangle, "f1") int c_f(...); public alias errorCheck!c_f1 f1; pragma(mangle, "f2") int c_f2(...); public alias errorCheck!c_f2 f2; } This way, one can "import foo" and use the same API as in C, but with proper exception handling. Since there is almost a thousand declarations, this leads to a lot of manual work and boilerplate. I guess the wrapping part itself (aliasing the wrapped functions) could be automated via a mixin template, but how would one go around repetitive pragma(mangle) (which I thought is needed so that private extern declarations have different names and don't clash with the wrapped ones )?Personally i wouldn't go this route. I would create foo.d as a C to D translation only so it can be imported and used like in C. Then i would create another module which imports this to create your new OOP API adding features and excepions, etc. This allows the best of both worlds, keep the C api intact for use in D and create a new clean OOP API for whatever your needs are.
Dec 13 2014
Personally i wouldn't go this route. I would create foo.d as a C to D translation only so it can be imported and used like in C. Then i would create another module which imports this to create your new OOP API adding features and excepions, etc. This allows the best of both worlds, keep the C api intact for use in D and create a new clean OOP API for whatever your needs are.I've actually done it this way initially, as well, however there are certain problems. Let's say there's a "foo.d" that contains raw bindings to "foo.h" (enums, structs, extern variables, function declarations, a whole load of stuff) -- everything but the functions is already fine but all functions need to be wrapped. If I now want to have exactly the same module but with all function declarations wrapped as described above, I have to public import it in another module and then do some template magic. However, it wouldn't be possible to retain the same function names since they've been imported to the namespace (it's then also not possible to extern them as private initially since then you won't be able to import/wrap them in a different module). Hence the idea of mixing the wrapping template in the initial .d header. I guess another way would be to split each header into functions / non-functions part, and private import + wrap the first part and public import the second part into a D-ready module. It just sounds like a whole lot of boilerplate so I was hoping there would be some magic automated way of doing something similar (maybe creating a custom "import" template that "imports" non-functions via aliasing and wraps functions)...
Dec 13 2014
On Saturday, 13 December 2014 at 19:03:42 UTC, aldanor wrote:Let's say there's a "foo.d" that contains raw bindings to "foo.h" (enums, structs, extern variables, function declarations, a whole load of stuff) -- everything but the functions is already fine but all functions need to be wrapped. If I now want to have exactly the same module but with all function declarations wrapped as described above, I have to public import it in another module and then do some template magic. However, it wouldn't be possible to retain the same function names since they've been imported to the namespace (it's then also not possible to extern them as private initially since then you won't be able to import/wrap them in a different module). Hence the idea of mixing the wrapping template in the initial .d header. I guess another way would be to split each header into functions / non-functions part, and private import + wrap the first part and public import the second part into a D-ready module. It just sounds like a whole lot of boilerplate so I was hoping there would be some magic automated way of doing something similar (maybe creating a custom "import" template that "imports" non-functions via aliasing and wraps functions)...I don't think there is an easy way to do this. foo.d contains all the converted C code. Then bar.d *privately* imports foo.d and adds exceptions. I would use bar.d to improve the interface to the library not mearly wrapping functions (even though that's essentially what is happening). foo.d is the C interface. bar.d is your new OOP API complete with exceptions.
Dec 13 2014
On 12/14/2014 4:03 AM, aldanor wrote:However, it wouldn't be possible to retain the same function names since they've been imported to the namespace (it's then also not possible to extern them as private initially since then you won't be able to import/wrap them in a different module). Hence the idea of mixing the wrapping template in the initial .d header.Assuming the C library can be compiled as a shared library, you can load it dynamically. This will allow you to call the function names whatever you want. Declare them all as function pointers, import them privately in your wrapper module and give your wrapper functions names matching the C API.
Dec 13 2014
On Saturday, 13 December 2014 at 19:03:42 UTC, aldanor wrote:If I now want to have exactly the same module but with all function declarations wrapped as described above, I have to public import it in another module and then do some template magic. However, it wouldn't be possible to retain the same function names since they've been imported to the namespace (it's then also not possible to extern them as private initially since then you won't be able to import/wrap them in a different module). Hence the idea of mixing the wrapping template in the initial .d header.You can also use `static import`. That way, the imported symbols will only be accessible via their fully-qualified name (e.g. `mypackage.mybindings.foo` instead of `foo`) and won't pollute the module's namespace.
Dec 14 2014