Thread overview
Request Assistance Calling D from C++: weird visibility issue inside struct and namespace
Nov 08, 2017
Andrew Edwards
Nov 08, 2017
Nicholas Wilson
Nov 08, 2017
Andrew Edwards
Nov 08, 2017
evilrat
Nov 08, 2017
Andrew Edwards
Nov 09, 2017
Andrew Edwards
Nov 08, 2017
MGW
Nov 09, 2017
Andrew Edwards
November 08, 2017
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
November 08, 2017
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.
November 08, 2017
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

November 08, 2017
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

November 08, 2017
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
November 08, 2017
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
November 08, 2017
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
November 09, 2017
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.
November 09, 2017
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