On Sunday, 27 November 2016 at 12:59:32 UTC, Timoses wrote:
Why is it a linker problem? I'm not linking to the c interface but merely using D structs...

It is a linker problem because you didn't link to it... D structs have an initializer, even if they are used for interfacing with C. This is a small blob of data called something like `_D10neo4jTypes17neo4j_map_entry_t6__initZ`, or can be all zeroes, and is generated with the interface module.

So if you use the initializer from the interface module, but do not link it in, you get an undefined symbol.


Easiest fix: just link in that .d file and use the automatic features.


Why does your struct have an initializer data symbol instead of being all zeroes? I'm not entirely sure, but I think it is because the contents are structs and it didn't look inside those structs to see if they too are zeroes, it just assumed struct = fancy initialized. That's arguably an enhancement request, but I wouldn't call it a bug.

You can often bypass the initializer by using `=0` or `=void` in definitions, but not here... and that is arguably a bug, if you `=void` all fields, it should be free to zero initialize the whole thing, but it doesn't.



Why do you use the initializer? Look at each of these lines:


    neo4j_map_entry_t[] mapa2; // yes
neo4j_map_entry_t entry1 = { key: neo4j_string("prop1"), value: neo4j_string("testprop1")}; // yes neo4j_map_entry_t entry2 = { key: neo4j_string("prop2"), value: neo4j_string("testprop2")}; // yes
    neo4j_map_entry_t* mapp; // yes



Those work because nothing is default initialized: pointers and arrays start as null (and thus point to no actual struct data). The middle lines have you explicitly initializing it, so again, no default needed.

    // These don't
    neo4j_map_entry_t[2] mapa1; // no

This is basically the same as `neo4j_map_entry_y a;` done twice - you create a struct, which is default initialized, which references that data.

You can bypass this with `=void` at the end of that line.

    mapa2.length = 2; // no

This also default initializes the new items you add. Just don't use that length function if you don't want to link in the other .d file.

    mapa2 ~= entry1; // no

I think the implementation does length += 1, then copy arr[$-1] = entry1, so there's a temporary default in there.

There's arguably a better implementation possible so this one *could* work. But if it doesn't now, just avoid that function (try something like std.array.uninitializedArray perhaps).

neo4j_map_entry_t[] mapa3 = [{ key: neo4j_null, value: neo4j_null}]; // no

And I don't know with this one, since I don't know what neo4j_null is. Perhaps you just didn't do the extern symbol right, or perhaps it too is a little data blob that should be linked in.



But while this can be annoying, it isn't really a bug - it is D's auto initialize feature creating some data that you didn't link. Avoiding D-specific features and bypassing initialization with =void can skip it, but I recommend just linking in the module.

Reply via email to