di.di
```D
extern(C):

struct b_real {
        double val;
}
```
breal.d
```D
import di;

extern(C) b_real* alcb_real(double x) {
        auto rp = new b_real;
        rp.val = x;
        return rp;
}
```
cmain.c
```C
#include <stdio.h>

struct b_real {
        double val;
};

struct b_real* alcb_real(double x);

int cmain() {
        struct b_real *rp  = alcb_real(3.142);
        printf("%f\n", rp->val);
        return 0;
}
```
dmain.d
```D
extern(C) int cmain();
int main() { return cmain(); }
```
Linkage problem.
```
$ gdc -c breal.d
$ gdc -c dmain.d
$ gdc -c cmain.c #forwards .c files to gcc
$ #gdc -c di.d #copy di.di to di.d for a working build
$ gdc -o breal breal.o dmain.o cmain.o #di.o
/usr/bin/ld: breal.o:(.data.rel.ro+0x28):
 undefined reference to `initializer for di.b_real'
/usr/bin/ld: breal.o:(.data.rel.ro+0x30):
undefined reference to `di.b_real.__xtoHash(ref const(di.b_real))'
/usr/bin/ld: breal.o:(.data.rel.ro+0x38):
undefined reference to `di.b_real.__xopEquals(ref const(di.b_real)) const'
collect2: error: ld returned 1 exit status

```
I ran into a real world version of this with a big C project, with a D interface file containing the equivalent of a few metres of C header file content. (gdc is *great* especially when moving a gcc built C project towards D incrementally.)

Allocating storage to be used by C (but with clever safe use of D's garbage collector unlike the above) led to this linkage problem only when the C struct contained a double.

This is apparently a bug, as D interface files containing only simple type definitions to replace C header files in D source like di.di are supposed to behave like header files.

It seems gdc is falling between treating the definition of a struct in a D interface file as C struct (simple data), and as a D struct (with default machinery) and achieving neither at link time if a struct contains a double.

gdc (GCC) 14.2.1 20250405

Reply via email to