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