www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - extern(C) and mangling type names

reply Mike Parker <aldacron gmail.com> writes:
```
module mang;
extern(C):
     struct Foo;
     void bar();
     int x;

pragma(msg, Foo.mangleof);
pragma(msg, bar.mangleof);
pragma(msg, x.mangleof);
```

Obviously, x and bar are seen by the linker and mangling is 
turned off for them. I've always believed it was the same for 
type declarations as well. Alas, that is not the case.

The use case I'm looking at here is forward references (opaque 
types). Works fine when binding to C libraries. Or even with 
other D modules when written like this:


```
module ec1;
extern(C):
     struct Foo;
     Foo* newFoo(int x);
     void printFoo(Foo* f);

module ec2;
extern(C):
     struct Foo { int x; }
     Foo* newFoo(int x) { return new Foo(x); }
     void printFoo(Foo* f) { import std.stdio; writeln(f.x); }

module ec3;
void main() {
     import ec1;
     Foo* f = newFoo(30);
     printFoo(f);
}
```

This compiles and runs. Now change ec1 and ec3 like so:

```
module ec1;
extern(C) struct Foo;

module ec3;
void main() {
     import ec1, ec2;
     Foo* f = newFoo(30);
     printFoo(f);
}
```

This produces the following errors:

ec3.d(4): Error: ec1.Foo at ec1.d(2) conflicts with ec2.Foo at 
ec2.d(3)
ec3.d(4): Error: cannot implicitly convert expression 
(newFoo(30)) of type Foo* to Foo*
ec3.d(5): Error: function ec2.printFoo (Foo* f) is not callable 
using argument types (Foo*)

IMO, extern(C) should turn off mangling for Foo. It would make 
forward references useful outside of the specific case of C 
bindings.

Consider the situation where you want to call a user-defined 
function (not a function pointer or a delegate). It's easy to do 
by providing an extern(C) prototype and requiring the user to use 
extern(C) in the implementation. The same thing should be 
possible for types.

My specific use case is a binding to a C library that makes use 
of specific types from X11, Wayland and elsewhere. I don't want 
to force a specific binding upon the user, so I need to declare 
the relevant types in a way that is binding-neutral. One option, 
of course, is to use void*, which has a lack of type safety and 
requires casting all over the place. Another is to wrap the 
declarations up in mixin templates and have the user mix them 
where they've imported the specific binding. Less onerous than 
void*, but still not ideal.

So, should extern(C) turn off mangling for types?
Feb 14 2017
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 2/14/2017 7:40 PM, Mike Parker wrote:
 So, should extern(C) turn off mangling for types?
In C, it is common to have opaque types like `struct Foo;` all over the place, and maybe `struct Foo { ... };` appear in multiple times. This works in C. It doesn't work in D, even if the name is set as `extern (C)`. That's because there is no C symbol table in the compiler, it's still a D symbol and follows D lookup rules. Thus, repeatedly declaring `struct Foo` will result in collisions. The solution is to declare `struct Foo` in one file, and have the others import that file.
Feb 14 2017
parent Mike Parker <aldacron gmail.com> writes:
On Wednesday, 15 February 2017 at 04:49:07 UTC, Walter Bright 
wrote:
 On 2/14/2017 7:40 PM, Mike Parker wrote:
 So, should extern(C) turn off mangling for types?
In C, it is common to have opaque types like `struct Foo;` all over the place, and maybe `struct Foo { ... };` appear in multiple times. This works in C. It doesn't work in D, even if the name is set as `extern (C)`. That's because there is no C symbol table in the compiler, it's still a D symbol and follows D lookup rules. Thus, repeatedly declaring `struct Foo` will result in collisions.
OK, the 'C symbol table' vs. 'D symbol table' bit clarifies it for me. I had a misunderstanding about extern(C)'s application. So with this, my understanding now is that extern(C) only comes into play when the mangled name is generated for the object file. Until that time, the compiler only sees the fully-qualified name. Since types don't go to the object file, there's no effect. I was under the mistaken impression that this behaved as I wanted the types to: module ec1; extern(C) void bar(); pragma(msg, bar.mangleof); module ec2; extern(C) void bar() { import std.stdio; writeln("bar"); } pragma(msg, bar.mangleof); module ec3; void main() { import ec1, ec2; bar(); } But that is obviously not the case (as I would have discovered had I tried it out): ec3.d(4): Error: ec2.bar at ec2.d(2) conflicts with ec1.bar at ec1.d(2)
 The solution is to declare `struct Foo` in one file, and have 
 the others import that file.
Yes, as I've long been doing with some of the bindings in Derelict. Unfortunately, that's not a solution for the specific use case that prompted this post. I'll either have to resort to using aliases to void* or template mixins.
Feb 14 2017
prev sibling next sibling parent reply Timothee Cour via Digitalmars-d <digitalmars-d puremagic.com> writes:
looks like a dup of this:
http://forum.dlang.org/thread/mailman.445.1487070970.31550.digitalmars-d puremagic.com
pragma(mangle,"name") for a type?




On Tue, Feb 14, 2017 at 7:40 PM, Mike Parker via Digitalmars-d <
digitalmars-d puremagic.com> wrote:

 ```
 module mang;
 extern(C):
     struct Foo;
     void bar();
     int x;

 pragma(msg, Foo.mangleof);
 pragma(msg, bar.mangleof);
 pragma(msg, x.mangleof);
 ```

 Obviously, x and bar are seen by the linker and mangling is turned off for
 them. I've always believed it was the same for type declarations as well.
 Alas, that is not the case.

 The use case I'm looking at here is forward references (opaque types).
 Works fine when binding to C libraries. Or even with other D modules when
 written like this:


 ```
 module ec1;
 extern(C):
     struct Foo;
     Foo* newFoo(int x);
     void printFoo(Foo* f);

 module ec2;
 extern(C):
     struct Foo { int x; }
     Foo* newFoo(int x) { return new Foo(x); }
     void printFoo(Foo* f) { import std.stdio; writeln(f.x); }

 module ec3;
 void main() {
     import ec1;
     Foo* f = newFoo(30);
     printFoo(f);
 }
 ```

 This compiles and runs. Now change ec1 and ec3 like so:

 ```
 module ec1;
 extern(C) struct Foo;

 module ec3;
 void main() {
     import ec1, ec2;
     Foo* f = newFoo(30);
     printFoo(f);
 }
 ```

 This produces the following errors:

 ec3.d(4): Error: ec1.Foo at ec1.d(2) conflicts with ec2.Foo at ec2.d(3)
 ec3.d(4): Error: cannot implicitly convert expression (newFoo(30)) of type
 Foo* to Foo*
 ec3.d(5): Error: function ec2.printFoo (Foo* f) is not callable using
 argument types (Foo*)

 IMO, extern(C) should turn off mangling for Foo. It would make forward
 references useful outside of the specific case of C bindings.

 Consider the situation where you want to call a user-defined function (not
 a function pointer or a delegate). It's easy to do by providing an
 extern(C) prototype and requiring the user to use extern(C) in the
 implementation. The same thing should be possible for types.

 My specific use case is a binding to a C library that makes use of
 specific types from X11, Wayland and elsewhere. I don't want to force a
 specific binding upon the user, so I need to declare the relevant types in
 a way that is binding-neutral. One option, of course, is to use void*,
 which has a lack of type safety and requires casting all over the place.
 Another is to wrap the declarations up in mixin templates and have the user
 mix them where they've imported the specific binding. Less onerous than
 void*, but still not ideal.

 So, should extern(C) turn off mangling for types?
Feb 14 2017
parent Chris Wright <dhasenan gmail.com> writes:
On Tue, 14 Feb 2017 20:51:43 -0800, Timothee Cour via Digitalmars-d wrote:

Please configure your newsreader to use plain text. It appends HTML 
garbage to the end of your post.
Feb 15 2017
prev sibling next sibling parent Timothee Cour via Digitalmars-d <digitalmars-d puremagic.com> writes:
I should've said 'related', not actually a dup. Walter, could you please
shed some light on this other thread?

Any workaround in the meantime would be highly appreciated

http://forum.dlang.org/thread/mailman.445.1487070970.31550.digitalmars-d puremagic.com
pragma(mangle,"name") for a type?




On Tue, Feb 14, 2017 at 8:51 PM, Timothee Cour <thelastmammoth gmail.com>
wrote:

 looks like a dup of this:
 http://forum.dlang.org/thread/mailman.445.1487070970.31550.
 digitalmars-d puremagic.com pragma(mangle,"name") for a type?




 On Tue, Feb 14, 2017 at 7:40 PM, Mike Parker via Digitalmars-d <
 digitalmars-d puremagic.com> wrote:

 ```
 module mang;
 extern(C):
     struct Foo;
     void bar();
     int x;

 pragma(msg, Foo.mangleof);
 pragma(msg, bar.mangleof);
 pragma(msg, x.mangleof);
 ```

 Obviously, x and bar are seen by the linker and mangling is turned off
 for them. I've always believed it was the same for type declarations as
 well. Alas, that is not the case.

 The use case I'm looking at here is forward references (opaque types).
 Works fine when binding to C libraries. Or even with other D modules when
 written like this:


 ```
 module ec1;
 extern(C):
     struct Foo;
     Foo* newFoo(int x);
     void printFoo(Foo* f);

 module ec2;
 extern(C):
     struct Foo { int x; }
     Foo* newFoo(int x) { return new Foo(x); }
     void printFoo(Foo* f) { import std.stdio; writeln(f.x); }

 module ec3;
 void main() {
     import ec1;
     Foo* f = newFoo(30);
     printFoo(f);
 }
 ```

 This compiles and runs. Now change ec1 and ec3 like so:

 ```
 module ec1;
 extern(C) struct Foo;

 module ec3;
 void main() {
     import ec1, ec2;
     Foo* f = newFoo(30);
     printFoo(f);
 }
 ```

 This produces the following errors:

 ec3.d(4): Error: ec1.Foo at ec1.d(2) conflicts with ec2.Foo at ec2.d(3)
 ec3.d(4): Error: cannot implicitly convert expression (newFoo(30)) of
 type Foo* to Foo*
 ec3.d(5): Error: function ec2.printFoo (Foo* f) is not callable using
 argument types (Foo*)

 IMO, extern(C) should turn off mangling for Foo. It would make forward
 references useful outside of the specific case of C bindings.

 Consider the situation where you want to call a user-defined function
 (not a function pointer or a delegate). It's easy to do by providing an
 extern(C) prototype and requiring the user to use extern(C) in the
 implementation. The same thing should be possible for types.

 My specific use case is a binding to a C library that makes use of
 specific types from X11, Wayland and elsewhere. I don't want to force a
 specific binding upon the user, so I need to declare the relevant types in
 a way that is binding-neutral. One option, of course, is to use void*,
 which has a lack of type safety and requires casting all over the place.
 Another is to wrap the declarations up in mixin templates and have the user
 mix them where they've imported the specific binding. Less onerous than
 void*, but still not ideal.

 So, should extern(C) turn off mangling for types?
Feb 14 2017
prev sibling parent reply Kagamin <spam here.lot> writes:
On Wednesday, 15 February 2017 at 03:40:32 UTC, Mike Parker wrote:
 My specific use case is a binding to a C library that makes use 
 of specific types from X11, Wayland and elsewhere.
If X11.Foo is implicitly convertible to forward reference Foo and forward reference Foo is implicitly convertible to Wayland.Foo, then X11.Foo is implicitly convertible to Wayland.Foo.
Feb 15 2017
parent reply Mike Parker <aldacron gmail.com> writes:
On Wednesday, 15 February 2017 at 10:59:25 UTC, Kagamin wrote:
 On Wednesday, 15 February 2017 at 03:40:32 UTC, Mike Parker 
 wrote:
 My specific use case is a binding to a C library that makes 
 use of specific types from X11, Wayland and elsewhere.
If X11.Foo is implicitly convertible to forward reference Foo and forward reference Foo is implicitly convertible to Wayland.Foo, then X11.Foo is implicitly convertible to Wayland.Foo.
Not quite what I meant. I want to use X11 types without forcing the user to choose between Tom's X11 bindings and Jerry's. The user should be able to use either. Ditto for multiple Wayland bindings. So, for example: version(UseX11) { struct Display; alias EGLNativeWindowType = Display*; } else version(UseWayland) { struct wl_display; EGLNativeWindowType = wgl_display*; } Then when compiling with UseX11, the user can import tom.x11 or jerry.x11, whichever he prefers. It's so tantalizingly close to being possible. My earlier example compiles and runs when using type inference: module ec3; void main() { import ec1, ec2; auto f = newFoo(30); printFoo(f); } My intuition is screaming at me. If this works, then shouldn't it also work when I declare the type myself? And if I add `alias MyFoo = Foo*` to ec1, then the first error, the one about conflicts, goes away, but I still get the latter two errors related to the function call. Why? I'm still returning an ec2.Foo* and assigning it to an ec1.Foo*. An alias is just a synonym. The types haven't changed.
Feb 15 2017
parent reply Kagamin <spam here.lot> writes:
On Wednesday, 15 February 2017 at 12:00:51 UTC, Mike Parker wrote:
 version(UseX11) {
     struct Display;
     alias EGLNativeWindowType = Display*;
 }
 else version(UseWayland) {
     struct wl_display;
     EGLNativeWindowType = wgl_display*;
 }
If you use void* for Display*, why do you need casts? What do you cast it to?
Feb 15 2017
parent Mike Parker <aldacron gmail.com> writes:
On Wednesday, 15 February 2017 at 12:32:42 UTC, Kagamin wrote:
 On Wednesday, 15 February 2017 at 12:00:51 UTC, Mike Parker 
 wrote:
 version(UseX11) {
     struct Display;
     alias EGLNativeWindowType = Display*;
 }
 else version(UseWayland) {
     struct wl_display;
     EGLNativeWindowType = wgl_display*;
 }
If you use void* for Display*, why do you need casts? What do you cast it to?
In this case I don't of course. Shouldn't have mentioned it in that context.
Feb 15 2017