digitalmars.D.learn - Passing opaque struct between functions/modules
- Sarath Kumar (53/53) Jan 23 2013 DMD v2.61; openSUSE 12.1
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (53/55) Jan 23 2013 I am assuming that you are interfacing with a C library. That library
- Sarath Kumar (3/31) Jan 24 2013 I don't know the contents of the struct as libA and libB are 3rd
- Mike Parker (5/55) Jan 24 2013 The error message here is deceiving. Declare the struct in one
- Sarath Kumar (8/12) Jan 24 2013 I can't import libA into libB. So, I had moved the forward
- Mike Parker (29/39) Jan 24 2013 The only potential bug I see here is in the error message. What
- Sarath Kumar (9/15) Jan 24 2013 It is a bug because even after casting, the compiler gives an
- Maxim Fomin (40/93) Jan 24 2013 You have hit one of the D problems regarding extern(). The first
DMD v2.61; openSUSE 12.1 Source: ------- libA.d: module libA; extern (C) { struct Opaque; Opaque* getObject(); void doSomething(Opaque *); } ---------- libB.d: module libB; extern (C) { struct Opaque; void doAction(Opaque *); } ----------- bug.d import libA, libB; int main(string[] args) { auto opaque = libA.getObject(); libA.doSomething(opaque); // this is okay libB.doAction(opaque); // but this is not, compiler error here return 0; } When I compile the above files, I get the below error. $ rdmd bug.d bug.d(7): Error: function libB.doAction (Opaque*) is not callable using argument types (Opaque*) bug.d(7): Error: cannot implicitly convert expression (opaque) of type Opaque* to Opaque* If I do an explicit cast, libB.Opaque*, for opaque in line 7, bug.d, I get completely different set of errors. $ rdmd bug.d libB.d(5): Error: struct libB.Opaque unknown size libB.d(5): Error: struct libB.Opaque no size yet for forward reference libB.d(5): Error: struct libB.Opaque unknown size libB.d(5): Error: struct libB.Opaque no size yet for forward reference libA.d(5): Error: struct libA.Opaque unknown size libA.d(5): Error: struct libA.Opaque no size yet for forward reference Can someone please tell me the right way to pass an opaque object between module's functions. -- Thanks, Sarath
Jan 23 2013
On 01/23/2013 08:33 AM, Sarath Kumar wrote:Can someone please tell me the right way to pass an opaque object between module's functions.I am assuming that you are interfacing with a C library. That library must have a D binding file. I am assuming that it is your libA.d: // libA.d module libA; extern (C) { struct Opaque; Opaque* getObject(); void doSomething(Opaque *); } There is also a library that implements the struct and the functions. Although you would have it in the C library, here is a D module to imitate it: // libA_impl.d // These are presumably defined in a C library. Simply imitating it with this // D module extern (C) { struct Opaque { int i; double d; } Opaque* getObject() { return new Opaque(42, 1.5); } void doSomething(Opaque *) {} } Here is the D module that makes use of that library by importing its D binding: // libB.d module libB; import libA; void doAction(Opaque* o) { doSomething(o); } void main() { Opaque* o = getObject(); doAction(o); } Here is how to build the program: $ dmd libA.d libB.d libA_impl.d -ofmy_prog Note that normally libA_impl.d would not be included. Instead, the C library would be used. For example, if we are talking about a libmy_c_lib.a: $ dmd libA.d libB.d -L-lmy_c_lib -ofmy_prog Yes, with the confusing -L in there. ;) Ali
Jan 23 2013
On Wednesday, 23 January 2013 at 17:14:31 UTC, Ali Çehreli wrote:On 01/23/2013 08:33 AM, Sarath Kumar wrote:I don't know the contents of the struct as libA and libB are 3rd party C libraries.Can someone please tell me the right way to pass an opaqueobjectbetween module's functions.I am assuming that you are interfacing with a C library. That library must have a D binding file. I am assuming that it is your libA.d: There is also a library that implements the struct and the functions. Although you would have it in the C library, here is a D module to imitate it: // libA_impl.d // These are presumably defined in a C library. Simply imitating it with this // D module extern (C) { struct Opaque { int i; double d; } Opaque* getObject() { return new Opaque(42, 1.5); } void doSomething(Opaque *) {} }
Jan 24 2013
On Wednesday, 23 January 2013 at 16:33:08 UTC, Sarath Kumar wrote:DMD v2.61; openSUSE 12.1 Source: ------- libA.d: module libA; extern (C) { struct Opaque; Opaque* getObject(); void doSomething(Opaque *); } ---------- libB.d: module libB; extern (C) { struct Opaque; void doAction(Opaque *); } ----------- bug.d import libA, libB; int main(string[] args) { auto opaque = libA.getObject(); libA.doSomething(opaque); // this is okay libB.doAction(opaque); // but this is not, compiler error here return 0; } When I compile the above files, I get the below error. $ rdmd bug.d bug.d(7): Error: function libB.doAction (Opaque*) is not callable using argument types (Opaque*) bug.d(7): Error: cannot implicitly convert expression (opaque) of type Opaque* to Opaque* If I do an explicit cast, libB.Opaque*, for opaque in line 7, bug.d, I get completely different set of errors. $ rdmd bug.d libB.d(5): Error: struct libB.Opaque unknown size libB.d(5): Error: struct libB.Opaque no size yet for forward reference libB.d(5): Error: struct libB.Opaque unknown size libB.d(5): Error: struct libB.Opaque no size yet for forward reference libA.d(5): Error: struct libA.Opaque unknown size libA.d(5): Error: struct libA.Opaque no size yet for forward reference Can someone please tell me the right way to pass an opaque object between module's functions.The error message here is deceiving. Declare the struct in one module only and then import it in every module that uses it. So, for example, keep the declaration in libA, remove it from libB and in libB add "import libA;".
Jan 24 2013
On Thursday, 24 January 2013 at 09:04:09 UTC, Mike Parker wrote:The error message here is deceiving. Declare the struct in one module only and then import it in every module that uses it. So, for example, keep the declaration in libA, remove it from libB and in libB add "import libA;".I can't import libA into libB. So, I had moved the forward declaration into a separate D file and did a public import into libA and libB. This works. But this is a workaround. I will file a bug. -- Thanks, Sarath
Jan 24 2013
On Thursday, 24 January 2013 at 09:39:39 UTC, Sarath Kumar wrote:On Thursday, 24 January 2013 at 09:04:09 UTC, Mike Parker wrote:The only potential bug I see here is in the error message. What you're seeing is a conflict that arises from D's name mangling. The doSomething in libA is expecting a parameter of type libA.Opaque* and getObject is returning the same, whereas the functions in libB are expecting a parameter of type libB.Opaque*. You can see this if you do the following: writeln(doSomething.mangleof); writeln(doAction.mangleof); This is why your code is failing when you call getAction, because you're passing it a libA.Opaque* returned from libA.getObject. The solution is to declare opaque struct in a single place and import it everywhere you need it. That's why your public imports work. I would suggest that you not use the public import in this case, but work out some other scenario. In Derelict (a collection of C bindings) for example, I tend to follow this pattern for any lib a bind to: types.d <- all type & constant declarations go here functions.d <- all function declarations go here, imports the types module Then I have a module named according to the C library's primary header that publicly imports both. For SDL2, for example: module derelict.sdl2.sdl; public { import derelict.sdl2.types; import derelict.sdl2.functions; } This way, all types are declared in a single location so there's no danger of mixing up different mangles of the same type.The error message here is deceiving. Declare the struct in one module only and then import it in every module that uses it. So, for example, keep the declaration in libA, remove it from libB and in libB add "import libA;".I can't import libA into libB. So, I had moved the forward declaration into a separate D file and did a public import into libA and libB. This works. But this is a workaround. I will file a bug.
Jan 24 2013
On Thursday, 24 January 2013 at 11:52:57 UTC, Mike Parker wrote:The only potential bug I see here is in the error message. What you're seeing is a conflict that arises from D's name mangling. The doSomething in libA is expecting a parameter of type libA.Opaque* and getObject is returning the same, whereas the functions in libB are expecting a parameter of type libB.Opaque*.It is a bug because even after casting, the compiler gives an error. The compiler wants to know the size of the opaque object, even though I'm dealing with a pointer only. As Maxim Fomin mentioned, the compiler is trying to create an instance of the object even when it is declared as extern (C) and it is a pointer. -- Thanks, Sarath
Jan 24 2013
On Wednesday, 23 January 2013 at 16:33:08 UTC, Sarath Kumar wrote:DMD v2.61; openSUSE 12.1 Source: ------- libA.d: module libA; extern (C) { struct Opaque; Opaque* getObject(); void doSomething(Opaque *); } ---------- libB.d: module libB; extern (C) { struct Opaque; void doAction(Opaque *); } ----------- bug.d import libA, libB; int main(string[] args) { auto opaque = libA.getObject(); libA.doSomething(opaque); // this is okay libB.doAction(opaque); // but this is not, compiler error here return 0; } When I compile the above files, I get the below error. $ rdmd bug.d bug.d(7): Error: function libB.doAction (Opaque*) is not callable using argument types (Opaque*) bug.d(7): Error: cannot implicitly convert expression (opaque) of type Opaque* to Opaque* If I do an explicit cast, libB.Opaque*, for opaque in line 7, bug.d, I get completely different set of errors. $ rdmd bug.d libB.d(5): Error: struct libB.Opaque unknown size libB.d(5): Error: struct libB.Opaque no size yet for forward reference libB.d(5): Error: struct libB.Opaque unknown size libB.d(5): Error: struct libB.Opaque no size yet for forward reference libA.d(5): Error: struct libA.Opaque unknown size libA.d(5): Error: struct libA.Opaque no size yet for forward reference Can someone please tell me the right way to pass an opaque object between module's functions. -- Thanks, SarathYou have hit one of the D problems regarding extern(). The first problem is that extern(C)-declared objects inside functions are still mangled, the other problem is that extern(C) Type var; still creates var object, unlike C does (except when Type is a function pointer). The following D program is compiled and linked: extern(C) int i; void main() { i = 0; } However, a C equivalent would result in linking error due to unresolved i reference. So, what you are really doing is unusable. By the way, doing this way you are actually defining two different structs, libA.Opaque and libB.Opaque. Compiler is right in this case, because these types are incompatible, but it should print full names to show the difference explicitly. If you are working with C library, you can use following scheme: ------main.d------------ extern extern(C) struct Opaque; extern extern(C) Opaque* getObject(); void main() { Opaque* ptr = getObject(); } -----struct.c----------- struct Opaque { int i; double d; }; struct Opaque op; struct Opaque* getObject() { return &op; } ------------------------ and if you are using D code, you should use .di files.
Jan 24 2013