www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - D and C++ undefined reference when namespace

reply Markus <contact markus-lanner.com> writes:
Hi

I got the following c++ code [lib.cpp]:
namespace ns_a
{
   class class_a {
   };
   void some_function(class_a*) {;}
}

and the following d code [main.d]:
extern (C++, namespace_a) {
     class class_a {}
     void some_function(class_a);
}
void main() {
     namespace_a.class_a instance_a;
     namespace_a.some_function(instance_a);
}

I'm compiling lib.cpp to a shared library by:
g++ -shared lib.cpp -o libissue.so
and I'm building and linking it with main.d by
dmd main.d -L-lissue -L-L.

Then I get the error:
main.o: In function `_Dmain':
main.d:(.text._Dmain[_Dmain]+0xa): undefined reference to 
`namespace_a::some_function(namespace_a::class_a*)'
collect2: error: ld returned 1 exit status
Error: linker exited with status 1

When I move the c++ class_a to another namespace (eg. to 
namespace_b), I'm able to compile and link!
readelf -Ws libissue.so | grep some_function
gives me
_ZN4ns_a13some_functionEPNS_7class_aE
so I don't see any issue. Any idea what I'm missing? I guess some 
linker flag when compiling libissue.so

Cheers,
Markus
Mar 08 2018
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/8/18 10:27 AM, Markus wrote:
 Hi
 
 I got the following c++ code [lib.cpp]:
 namespace ns_a
 {
    class class_a {
    };
    void some_function(class_a*) {;}
 }
 
 and the following d code [main.d]:
 extern (C++, namespace_a) {
did you mean ns_a? -Steve
Mar 08 2018
parent reply Markus <contact markus-lanner.com> writes:
On Thursday, 8 March 2018 at 16:19:40 UTC, Steven Schveighoffer 
wrote:
 On 3/8/18 10:27 AM, Markus wrote:
 Hi
 
 I got the following c++ code [lib.cpp]:
 namespace ns_a
 {
    class class_a {
    };
    void some_function(class_a*) {;}
 }
 
 and the following d code [main.d]:
 extern (C++, namespace_a) {
did you mean ns_a? -Steve
yes, that's clearly the issue in my first post. :) I failed when I made a minimal sample for this forum [lib.cpp]: namespace ns_a { class class_a { }; void some_function(class_a*) {;} } [other.d]: extern (C++, ns_a) { class class_a {} } [main.d]: import other; extern (C++, ns_a) { void some_function(class_a); } void main() { class_a instance_a; ns_a.some_function(instance_a); } compilation: g++ -shared lib.cpp -o libissue.so dmd main.d -L-lissue -L-L. error: main.o: In function `_Dmain': main.d:(.text._Dmain[_Dmain]+0xa): undefined reference to `ns_a::some_function(ns_a::class_a*)' collect2: error: ld returned 1 exit status Error: linker exited with status 1 symbols: nm --demangle libissue.so | some_function 000000000000059a T ns_a::some_function(ns_a::class_a*) It doesn't seem like an error, but it is. I still don't get it, whey I'm not allowed to split the namespace declarations.
Mar 08 2018
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/8/18 11:35 AM, Markus wrote:

 
 error:
 main.o: In function `_Dmain':
 main.d:(.text._Dmain[_Dmain]+0xa): undefined reference to 
 `ns_a::some_function(ns_a::class_a*)'
 collect2: error: ld returned 1 exit status
 Error: linker exited with status 1
 
 symbols:
 nm --demangle libissue.so | some_function
 000000000000059a T ns_a::some_function(ns_a::class_a*)
 
 It doesn't seem like an error, but it is.
 I still don't get it, whey I'm not allowed to split the namespace 
 declarations.
 
This is a linker error. Your D code is compiling just fine (in other words, the aforementioned issue is not happening to you), it's just not getting the definition from the dynamic library. When I do this locally on my mac, I get a similar error. When I nm the main.o file vs. the lib.o file, I see different mangled names. It appears that the D mangled name is not doing back references. This is probably why the change to another namespace for the function works (there isn't a back reference) In order to demonstrate this better, I did namespace thenamespace instead of ns_a. The symbol I see in the D file: U __ZN12thenamespace13some_functionEPN12thenamespace7class_aE And in the C++ file: T __ZN12thenamespace13some_functionEPNS_7class_aE Note the difference is instead of 12thenamespace, it's S_, which probably is a back reference. Googled... Yep, I'm right: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id I'd recommend filing a bug. -Steve
Mar 08 2018
parent reply Markus <contact markus-lanner.com> writes:
On Thursday, 8 March 2018 at 17:04:02 UTC, Steven Schveighoffer 
wrote:
 On 3/8/18 11:35 AM, Markus wrote:
 When I do this locally on my mac, I get a similar error. When I 
 nm the main.o file vs. the lib.o file, I see different mangled 
 names.

 It appears that the D mangled name is not doing back 
 references. This is probably why the change to another 
 namespace for the function works (there isn't a back reference)

 In order to demonstrate this better, I did namespace 
 thenamespace instead of ns_a.

 The symbol I see in the D file:
 U __ZN12thenamespace13some_functionEPN12thenamespace7class_aE

 And in the C++ file:
 T __ZN12thenamespace13some_functionEPNS_7class_aE

 Note the difference is instead of 12thenamespace, it's S_, 
 which probably is a back reference. Googled...

 Yep, I'm right: 
 https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id

 I'd recommend filing a bug.

 -Steve
You are right. $ dmd -c main.d $ nm main.o | grep some U _ZN4ns_a13some_functionEPN4ns_a7class_aE $ nm lib.o | grep some 0000000000000000 T _ZN4ns_a13some_functionEPNS_7class_aE But when i merge the main.d and other.d I get $ nm main.o | grep some U _ZN4ns_a13some_functionEPNS_7class_aE I tested dmd (2.079.0), gdc and ldc2. All got the same result. Which makes me think, that it's not a bug, but a "feature" :)
Mar 08 2018
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/8/18 1:56 PM, Markus wrote:
 
 You are right.
 $ dmd -c main.d
 $ nm main.o | grep some
                   U _ZN4ns_a13some_functionEPN4ns_a7class_aE
 $ nm lib.o | grep some
 0000000000000000 T _ZN4ns_a13some_functionEPNS_7class_aE
 
 But when i merge the main.d and other.d I get
 $ nm main.o | grep some
                   U _ZN4ns_a13some_functionEPNS_7class_aE
 
 I tested dmd (2.079.0), gdc and ldc2. All got the same result. Which 
 makes me think, that it's not a bug, but a "feature" :)
Ah interesting. What it looks like is that the symbol for the namespace is considered different between the two files in D-land, but they have the same name in C++-land. So it thinks it's not a back reference, but really it should be. -Steve
Mar 08 2018
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/8/18 1:56 PM, Markus wrote:
 I tested dmd (2.079.0), gdc and ldc2. All got the same result. Which 
 makes me think, that it's not a bug, but a "feature" :)
This is DEFINITELY a bug. -Steve
Mar 08 2018
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/8/18 2:01 PM, Steven Schveighoffer wrote:
 On 3/8/18 1:56 PM, Markus wrote:
 I tested dmd (2.079.0), gdc and ldc2. All got the same result. Which 
 makes me think, that it's not a bug, but a "feature" :)
This is DEFINITELY a bug.
https://issues.dlang.org/show_bug.cgi?id=18582 -Steve
Mar 08 2018
parent Markus <contact markus-lanner.com> writes:
On Thursday, 8 March 2018 at 21:14:36 UTC, Steven Schveighoffer 
wrote:
 On 3/8/18 2:01 PM, Steven Schveighoffer wrote:
 On 3/8/18 1:56 PM, Markus wrote:
 I tested dmd (2.079.0), gdc and ldc2. All got the same 
 result. Which makes me think, that it's not a bug, but a 
 "feature" :)
This is DEFINITELY a bug.
https://issues.dlang.org/show_bug.cgi?id=18582 -Steve
thanks for opening an issue. Markus
Mar 09 2018
prev sibling parent kinke <noone nowhere.com> writes:
On Thursday, 8 March 2018 at 18:56:04 UTC, Markus wrote:
 I tested dmd (2.079.0), gdc and ldc2. All got the same result. 
 Which makes me think, that it's not a bug, but a "feature" :)
C++ mangling is part of the DMD front-end shared by all 3 compilers, so no surprises there: https://github.com/dlang/dmd/blob/master/src/dmd/cppmangle.d
Mar 08 2018
prev sibling parent reply Markus <contact markus-lanner.com> writes:
On Thursday, 8 March 2018 at 15:27:31 UTC, Markus wrote:
 Hi

 I got the following c++ code [lib.cpp]:
 namespace ns_a
 {
   class class_a {
   };
   void some_function(class_a*) {;}
 }

 and the following d code [main.d]:
 extern (C++, namespace_a) {
     class class_a {}
     void some_function(class_a);
 }
 void main() {
     namespace_a.class_a instance_a;
     namespace_a.some_function(instance_a);
 }

 I'm compiling lib.cpp to a shared library by:
 g++ -shared lib.cpp -o libissue.so
 and I'm building and linking it with main.d by
 dmd main.d -L-lissue -L-L.

 Then I get the error:
 main.o: In function `_Dmain':
 main.d:(.text._Dmain[_Dmain]+0xa): undefined reference to 
 `namespace_a::some_function(namespace_a::class_a*)'
 collect2: error: ld returned 1 exit status
 Error: linker exited with status 1

 When I move the c++ class_a to another namespace (eg. to 
 namespace_b), I'm able to compile and link!
 readelf -Ws libissue.so | grep some_function
 gives me
 _ZN4ns_a13some_functionEPNS_7class_aE
 so I don't see any issue. Any idea what I'm missing? I guess 
 some linker flag when compiling libissue.so

 Cheers,
 Markus
https://forum.dlang.org/thread/mailman.2458.1448772039.22025.digitalmars-d puremagic.com seems to describe my issue. To quote Walter Wright
 D does not support C++ semantics. You cannot split namespaces 
 into multiple files in D, nor can you add symbols to an 
 existing namespace. For namespace NS, all the declarations in 
 NS have to be in one file and between the { }, just like any 
 other scope in D.
in my opinion, that's really annoying for C++ wrapper devs. I failed to describe my issue in the first post. there has to be another.d the function and class have to be in seperate d files. Sorry for the spam
Mar 08 2018
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/8/18 11:23 AM, Markus wrote:
 On Thursday, 8 March 2018 at 15:27:31 UTC, Markus wrote:
 Hi

 I got the following c++ code [lib.cpp]:
 namespace ns_a
 {
   class class_a {
   };
   void some_function(class_a*) {;}
 }

 and the following d code [main.d]:
 extern (C++, namespace_a) {
     class class_a {}
     void some_function(class_a);
 }
 void main() {
     namespace_a.class_a instance_a;
     namespace_a.some_function(instance_a);
 }

 I'm compiling lib.cpp to a shared library by:
 g++ -shared lib.cpp -o libissue.so
 and I'm building and linking it with main.d by
 dmd main.d -L-lissue -L-L.

 Then I get the error:
 main.o: In function `_Dmain':
 main.d:(.text._Dmain[_Dmain]+0xa): undefined reference to 
 `namespace_a::some_function(namespace_a::class_a*)'
 collect2: error: ld returned 1 exit status
 Error: linker exited with status 1

 When I move the c++ class_a to another namespace (eg. to namespace_b), 
 I'm able to compile and link!
 readelf -Ws libissue.so | grep some_function
 gives me
 _ZN4ns_a13some_functionEPNS_7class_aE
 so I don't see any issue. Any idea what I'm missing? I guess some 
 linker flag when compiling libissue.so

 Cheers,
 Markus
https://forum.dlang.org/thread/mailman.2458.1448772039.22025.digital ars-d puremagic.com seems to describe my issue. To quote Walter Wright
 D does not support C++ semantics. You cannot split namespaces into 
 multiple files in D, nor can you add symbols to an existing namespace. 
 For namespace NS, all the declarations in NS have to be in one file 
 and between the { }, just like any other scope in D.
in my opinion, that's really annoying for C++ wrapper devs.
Hm... that is over 2 years old. I would agree it would seem like a bad limitation. And the error message doesn't seem like a linker error, whereas yours does. If it gets to the linker, D hasn't complained about it. -Steve
Mar 08 2018