www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Using C++ Classes From D: dmd cannot link, while ldc segfault

reply mw <mingwu gmail.com> writes:
Hi,

I'm following this example:

https://dlang.org/spec/cpp_interface.html#using_cpp_classes_from_d

and try to wrap a std::list

base.cpp
```cpp
#include <iostream>
#include <list>

using namespace std;

class Base
{
     public:
         virtual void print3i(int a, int b, int c) = 0;
};

class Derived : public Base
{
     public:
         int field;
         Derived(int field) : field(field) {}

         void print3i(int a, int b, int c)
         {
             cout << "a = " << a << endl;
             cout << "b = " << b << endl;
             cout << "c = " << c << endl;
         }

         int mul(int factor);
};

template<class T> class std_list : public std::list<T> {};
void getInts(std_list<int>* list);

int Derived::mul(int factor)
{
     return field * factor;
}

Derived *createInstance(int i)
{
     // get list of ints from D side
     std_list<int> list;
     list.push_back(911);
     ::getInts(&list);
     for (int i : list) {
             cout << "i = " << i << endl;
     }

     return new Derived(i);
}

void deleteInstance(Derived *&d)
{
     delete d;
     d = 0;
}
```

main.c
```
extern(C++)
{
     abstract class Base
     {
         void print3i(int a, int b, int c);
     }

     class Derived : Base
     {
         int field;
          disable this();
         override void print3i(int a, int b, int c);
         final int mul(int factor);
     }

     Derived createInstance(int i);
     void deleteInstance(ref Derived d);
}

extern(C++) {

class std_list(T) {
    disable this();
   void push_back(const ref T value);
}

void getInts(std_list!(int) list) {
   foreach (int i; 0 .. 10) {
     list.push_back(i);
   }
}

}

void main()
{
     import std.stdio;

     auto d1 = createInstance(5);
     writeln(d1.field);
     writeln(d1.mul(4));

     Base b1 = d1;
     b1.print3i(1, 2, 3);

     deleteInstance(d1);
     assert(d1 is null);

     auto d2 = createInstance(42);
     writeln(d2.field);

     deleteInstance(d2);
     assert(d2 is null);
}

```

Makefile
```
c2d:
	g++ -c -g -ggdb base.cpp
	ldmd2 -g main.d base.o -L-lstdc++ && ./main

```

if I use LCD (ldmd2), it segfaults:
```
$ make
g++ -c -g -ggdb base.cpp
ldmd2 -g main.d base.o -L-lstdc++ && ./main
Segmentation fault (core dumped)
```

and gdb shows it fails at: main.d:29 list.push_back(i);

if I use DMD, it cannot link:
```
$ make
g++ -c -g -ggdb base.cpp
dmd -g main.d base.o -L-lstdc++ && ./main
/usr/bin/ld: main.o:(.data._D4main__T8std_listTiZQm6__vtblZ+0x0): 
undefined reference to `std_list<int>::push_back(int const&)'
collect2: error: ld returned 1 exit status
Error: linker exited with status 1
```

Looks like something wrong with the push_back().

So, how to fix this DMD link error, and LDC segfaults?

Thanks.
Jun 18 2023
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
This is just a guess, but I think the problem is the vtable is incomplete.

Because of this the offsets are wrong. So you wouldn't be calling push_back.
Jun 18 2023
parent reply mw <mingwu gmail.com> writes:
On Monday, 19 June 2023 at 05:32:23 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
 This is just a guess, but I think the problem is the vtable is 
 incomplete.

 Because of this the offsets are wrong. So you wouldn't be 
 calling push_back.
So, you mean on the D side, it need to list all the fields and methods of the C++ class? ```d class std_list(T) { disable this(); void push_back(const ref T value); } ``` Then it will be very tedious, esp. for such library class std::list. Is there a tool that can automate this? Thanks.
Jun 18 2023
next sibling parent mw <mingwu gmail.com> writes:
On Monday, 19 June 2023 at 05:39:51 UTC, mw wrote:
 Then it will be very tedious, esp. for such library class 
 std::list.

 Is there a tool that can automate this?
A related question: basically I want to pass an array of objects from D side to the Cpp side, is there any example showing how to do this? On this page https://dlang.org/spec/cpp_interface.html#cpp-templates I did not find any information about passing array (containers) between D and Cpp. Thanks.
Jun 18 2023
prev sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 19/06/2023 5:39 PM, mw wrote:
 Then it will be very tedious, esp. for such library class std::list.
Yes, you would also need to verify it with every compiler you need (MSVC, vs linux gcc). There could be a reason why it isn't in https://github.com/dlang/dmd/tree/master/druntime/src/core/stdcpp
 Is there a tool that can automate this?
Not that I know of.
Jun 18 2023
parent reply mw <mingwu gmail.com> writes:
On Monday, 19 June 2023 at 05:46:13 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
 On 19/06/2023 5:39 PM, mw wrote:
 Then it will be very tedious, esp. for such library class 
 std::list.
Yes, you would also need to verify it with every compiler you need (MSVC, vs linux gcc). There could be a reason why it isn't in https://github.com/dlang/dmd/tree/master/druntime/src/core/stdcpp
Ha, I saw vector.d there, So I can use this vector.d as the D side of C++'s std::vector?
Jun 18 2023
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 19/06/2023 5:54 PM, mw wrote:
 Ha, I saw vector.d there, So I can use this vector.d as the D side of 
 C++'s std::vector?
Probably, I just don't know how well tested it is. But worth a go!
Jun 18 2023
parent reply mw <mingwu gmail.com> writes:
On Monday, 19 June 2023 at 05:56:54 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
 On 19/06/2023 5:54 PM, mw wrote:
 Ha, I saw vector.d there, So I can use this vector.d as the D 
 side of C++'s std::vector?
Probably, I just don't know how well tested it is. But worth a go!
``` import core.stdcpp.vector; extern(C++) { void getInts(core.stdcpp.vector.vector!(int) vec) { foreach (int i; 0 .. 10) { vec.push_back(i); } } } ``` dmd v2.104.0 failed: ``` /usr/include/dmd/druntime/import/core/stdcpp/vector.d(58): Error: undefined identifier `size`, did you mean alias `size_t`? /usr/include/dmd/druntime/import/core/stdcpp/vector.d(33): Error: template instance `core.stdcpp.vector.vector!(int, allocator!int)` error instantiating main.d(32): instantiated from here: `vector!int` ``` LDC - the LLVM D compiler (1.32.2): ``` main.d(32): Error: undefined identifier `vector` in module `core.stdcpp.vector`, did you mean enum member `MIctor`? ``` So what's wrong the LDC? how do I write `core.stdcpp.vector.vector` then?
Jun 18 2023
parent mw <mingwu gmail.com> writes:
If I use array:

```
extern(C++) {

void getInts(core.stdcpp.array.array!(int, 10) vec) {
   foreach (int i; 0 .. 10) {
     vec.at(i) = i;
   }
}

}
```

```
#include <array>
using namespace std;

void getInts(array<int,10>* vector);
```

Both DMD and LDC has link error:

base.cpp:42: undefined reference to `getInts(std::array<int, 
10ul>*)'
Jun 18 2023