www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Request Assistance Calling D from C++: weird visibility issue inside

reply Andrew Edwards <edwards.ac gmail.com> writes:
I'm having a little bit of problem calling D code from C++ and 
would appreciate some assistance. First, given the following C++ 
program wich compiles, links, and runs without any problem:

     ======================
     // example.h
     SOME_API void foo(const char* str);

     // example.cpp
     #include "example.h"
     namespace SomeApi {}
     struct SomeStruct {}
     int main() {
         foo("do great things");
         return 0;
     }
     void foo(const char* str) {
         // doing great things;
     }
     ======================

Modify example.cpp to:

     ======================
     // example.cpp
     #include "example.h"
     namespace SomeApi {}
     struct SomeStruct {}
     void call_cpp() {
         foo("do great things");
         return;
     }
     ======================

Then create example.d:

     ======================
     void main() {
         call_cpp();
     }

     extern (C++) void foo(const char* str) {
         // doing great things;
     }
     ======================

Compile and link and you have D program calling, calling C++, 
which in turn calls D.

My problem is that I've encountered an issue where this does not 
work: when the function is being called from a namespace or local 
scope in C++, the linker cannot find the definition. For example:

     void SomeApi::CallFromNamespace() {
         foo("do great things");
     }

or
     void SomeStruct::CallFromStruct() {
         foo("do great things");
     }

In a last-ditch effort, I placed all of these definitions into 
dexample.d and, it compiled, but still filed to linking:

     extern (C) void foo(const char* str) {
         // doing great things;
     }

     extern (C++) void foo(const char* str) {
         // doing great things;
     }

     extern (C++, SOME_API) void foo(const char* str) {
         // doing great things;
     }

     extern (D) void foo(const char* str) {
         // doing great things;
     }

     extern void foo(const char* str) {
         // doing great things;
     }

     void foo(const char* str) {
         // doing great things;
     }

===============
Linker error returned:
===============

Undefined symbols for architecture x86_64:
   "foo()", referenced from:
       SomeStruct::CallFromStruct() in example.o
       SomeApi::CallFromNamespace() in example.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to 
see invocation)
make: *** [dexample] Error 1

Using DMD v2.077.0 on macOS High Sierra

-Andrew
Nov 07
next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Wednesday, 8 November 2017 at 06:34:27 UTC, Andrew Edwards 
wrote:
 I'm having a little bit of problem calling D code from C++ and 
 would appreciate some assistance. First, given the following 
 C++ program wich compiles, links, and runs without any problem:
Try using `nm` on the C++ object to find out what it thinks the mangling should be. Check that against the mangling DMD produces.
Nov 07
parent Andrew Edwards <edwards.ac gmail.com> writes:
On Wednesday, 8 November 2017 at 07:06:39 UTC, Nicholas Wilson 
wrote:
 On Wednesday, 8 November 2017 at 06:34:27 UTC, Andrew Edwards 
 wrote:
 I'm having a little bit of problem calling D code from C++ and 
 would appreciate some assistance. First, given the following 
 C++ program wich compiles, links, and runs without any problem:
Try using `nm` on the C++ object to find out what it thinks the mangling should be. Check that against the mangling DMD produces.
Tried it, and it works. Solution: nm dexample | grep foo -> returns the __C++__mangling Use it to define the function as such: pragma(mangle, "__C++__mangling") extern (C++) void foo(const char* str) { // doing great things; } Thank you so much. -Andrew
Nov 07
prev sibling next sibling parent reply evilrat <evilrat666 gmail.com> writes:
On Wednesday, 8 November 2017 at 06:34:27 UTC, Andrew Edwards 
wrote:
 Modify example.cpp to:

     ======================
     // example.cpp
     #include "example.h"
     namespace SomeApi {}
     struct SomeStruct {}
     void call_cpp() {
         foo("do great things");
         return;
     }
     ======================
 Compile and link and you have D program calling, calling C++, 
 which in turn calls D.

 My problem is that I've encountered an issue where this does 
 not work: when the function is being called from a namespace or 
 local scope in C++, the linker cannot find the definition. For 
 example:
just using fully qualified name didn't make it? void call_cpp() { ::foo("do great things"); // calling global foo return; }
 In a last-ditch effort, I placed all of these definitions into 
 dexample.d and, it compiled, but still filed to linking:
Are you sure you put it in a namespace in C++ too? otherwise there might be some name mangling incompatibility that probably worth filling a bug report
Nov 07
parent reply Andrew Edwards <edwards.ac gmail.com> writes:
On Wednesday, 8 November 2017 at 07:30:34 UTC, evilrat wrote:
 On Wednesday, 8 November 2017 at 06:34:27 UTC, Andrew Edwards

 just using fully qualified name didn't make it?

 void call_cpp() {
     ::foo("do great things"); // calling global foo
     return;
 }
No, it did not.
 Are you sure you put it in a namespace in C++ too?
Yes. That wasn't the issue
 otherwise there might be some name mangling incompatibility 
 that probably worth filling a bug report
That's the one. Thanks to the hint form, Nicholas Wilson, I was able to track it down and resolve it with a call to pragma(mangle). -Andrew
Nov 07
parent reply Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Wednesday, 8 November 2017 at 07:55:02 UTC, Andrew Edwards 
wrote:
 On Wednesday, 8 November 2017 at 07:30:34 UTC, evilrat wrote:
 On Wednesday, 8 November 2017 at 06:34:27 UTC, Andrew Edwards

 just using fully qualified name didn't make it?

 void call_cpp() {
     ::foo("do great things"); // calling global foo
     return;
 }
No, it did not.
 Are you sure you put it in a namespace in C++ too?
Yes. That wasn't the issue
 otherwise there might be some name mangling incompatibility 
 that probably worth filling a bug report
That's the one. Thanks to the hint form, Nicholas Wilson, I was able to track it down and resolve it with a call to pragma(mangle). -Andrew
Walter has recently been working on improving the C++ mangling, so be sure to test the latest dmd nightly build and if that doesn't work be sure to file bug report(s). https://github.com/dlang/dmd/pull/7250 https://github.com/dlang/dmd/pull/7259 https://github.com/dlang/dmd/pull/7272
Nov 08
parent Andrew Edwards <edwards.ac gmail.com> writes:
On Wednesday, 8 November 2017 at 08:42:01 UTC, Petar Kirov 
[ZombineDev] wrote:
 Walter has recently been working on improving the C++ mangling, 
 so be sure to test the latest dmd nightly build and if that 
 doesn't work be sure to file bug report(s).

 https://github.com/dlang/dmd/pull/7250
 https://github.com/dlang/dmd/pull/7259
 https://github.com/dlang/dmd/pull/7272
Done: https://issues.dlang.org/show_bug.cgi?id=17975
Nov 08
prev sibling parent reply MGW <mgw yandex.ru> writes:
On Wednesday, 8 November 2017 at 06:34:27 UTC, Andrew Edwards 
wrote:
 I'm having a little bit of problem calling D code from C++ and 
 would appreciate some assistance. First, given the following 
 C++ program wich compiles, links, and runs without any problem:
The useful material. https://www.youtube.com/watch?v=HTgJaRRfLPk
Nov 08
parent Andrew Edwards <edwards.ac gmail.com> writes:
On Wednesday, 8 November 2017 at 15:12:05 UTC, MGW wrote:
 The useful material.
 https://www.youtube.com/watch?v=HTgJaRRfLPk
Useful indeed, thank you.
Nov 08