www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - link errors when using extern (C) structs

reply DanielG <simpletangent gmail.com> writes:
I'm wrapping a C library which has a lot of structs defined, and 
I keep running into issues where dmd complains that .init isn't 
defined ("Symbol Undefined __xxxxxxx__initZ" etc).

I'm struggling to narrow it down to a simple example that 
demonstrates it - I actually made something that's kind of 
minimal, but it goes from working to breaking depending on 
whether the file extension is .di or .d, for the file containing 
the extern (C)'ed struct definitions. Also it seems to depend (in 
the .di case) on whether the C structs use double vs. int values 
for their fields. (int fields work with either file extension)

But simply changing the file extension in my real project, of the 
header files translated by dstep, seems to have no effect.

In short, it seems that for certain C structs I cannot use them 
as a field in a D struct even with a manually-specified default 
value - I get link errors no matter what (init/toHash/opEquals). 
How can I get around that?

Am I supposed to be doing something with C structs to avoid these 
kinds of errors in my D code? I've searched the forum but nothing 
really jumps out at me as relevant.
Oct 27 2018
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Sunday, 28 October 2018 at 03:28:20 UTC, DanielG wrote:
 I'm wrapping a C library which has a lot of structs defined, 
 and I keep running into issues where dmd complains that .init 
 isn't defined ("Symbol Undefined __xxxxxxx__initZ" etc).

 I'm struggling to narrow it down to a simple example that 
 demonstrates it - I actually made something that's kind of 
 minimal, but it goes from working to breaking depending on 
 whether the file extension is .di or .d, for the file 
 containing the extern (C)'ed struct definitions. Also it seems 
 to depend (in the .di case) on whether the C structs use double 
 vs. int values for their fields. (int fields work with either 
 file extension)
That is because the default initialiser for double is double.nan which is non-zero and therefore the default initialiser of a struct containing a double will have a non-zero default initialiser. This lives as a __xxxxxxx__initZ symbol somewhere in your program. The .di or .d is because in the case of .di the compiler assumes the symbols exist somewhere already and it doesn't need to (and can't because it would create duplicates) emit them to the object files.
 But simply changing the file extension in my real project, of 
 the header files translated by dstep, seems to have no effect.

 In short, it seems that for certain C structs I cannot use them 
 as a field in a D struct even with a manually-specified default 
 value - I get link errors no matter what 
 (init/toHash/opEquals). How can I get around that?

 Am I supposed to be doing something with C structs to avoid 
 these kinds of errors in my D code? I've searched the forum but 
 nothing really jumps out at me as relevant.
For the __initZ symbols struct Foo { double bar; } write struct Foo { double bar = 0.0; // The bitpattern of 0.0 is 0 } and have only zero initialiser for you structs, which means they don't need to be stored. the opEquals stems from the fact that for structs containing floats equality comparison cannot be implemented with bitwise compare. The easiest solution is to just use .d for the extension, very rarely are .di files useful.
Oct 27 2018
parent reply DanielG <simpletangent gmail.com> writes:
On Sunday, 28 October 2018 at 03:39:41 UTC, Nicholas Wilson wrote:
 write struct Foo {
     double bar = 0.0; // The bitpattern of 0.0 is 0
 }
Thank you for your response. Can you elaborate on 'write struct...'? Is that special syntax? I assumed so, but dmd doesn't like it. I also checked to see if you meant "(manually re-write it as...)", but updating the struct definition in the generated .d header with field values doesn't seem to solve the __initZ issue, either. And redefining it in the client .d module just shadows the header definition, so ...
Oct 27 2018
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Sunday, 28 October 2018 at 04:23:27 UTC, DanielG wrote:
 On Sunday, 28 October 2018 at 03:39:41 UTC, Nicholas Wilson 
 wrote:
 write struct Foo {
     double bar = 0.0; // The bitpattern of 0.0 is 0
 }
Thank you for your response. Can you elaborate on 'write struct...'? Is that special syntax?
Nope thats me not proofreading my posts properly, sorry.
  I also checked to see if you meant "(manually re-write it 
 as...)", but updating the struct definition in the generated .d 
 header with field values doesn't seem to solve the __initZ 
 issue, either.
Hmm thats, odd unless there are other fields with initialisers that are forcing its emission.
 And redefining it in the client .d module just shadows the
 header definition, so ...
Try not using the .di files at all. I've never had any use for them personally. Wrapping a C library, all thats required is definitions of the functions and types declared by the headers. this can be done with a .d file.
Oct 27 2018
parent reply DanielG <simpletangent gmail.com> writes:
For the benefit of anybody who encounters a problem like this in 
the future ... originally I had my C library "header" files 
(renamed from .di to .d after the feedback from Nicholas) in a 
special 'headers/' subdir, used as an import path in dub.json. I 
simply moved those files to the source folder and everything 
started magically working.

And thanks again, Nicholas!
Oct 27 2018
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Sunday, 28 October 2018 at 06:59:31 UTC, DanielG wrote:
 For the benefit of anybody who encounters a problem like this 
 in the future ... originally I had my C library "header" files 
 (renamed from .di to .d after the feedback from Nicholas) in a 
 special 'headers/' subdir, used as an import path in dub.json. 
 I simply moved those files to the source folder and everything 
 started magically working.

 And thanks again, Nicholas!
Oh yeah, I didn't think to mention that you need to compile them for them to fix your missing symbols problem. No problems.
Oct 28 2018
parent reply DanielG <simpletangent gmail.com> writes:
On Sunday, 28 October 2018 at 08:38:56 UTC, Nicholas Wilson wrote:
 Oh yeah, I didn't think to mention that you need to compile 
 them for them to fix your missing symbols problem.
Wait, wut? Do modules that get pulled in from dub's "importPaths" not get compiled in the same way? The dstep-generated files were working for the most part -- standalone C functions had no problem -- it was only those structs that I was having problems with. But now that they're in the default /source folder, I don't get the linker errors anymore. <shrug>
Oct 28 2018
parent rikki cattermole <rikki cattermole.co.nz> writes:
On 28/10/2018 11:11 PM, DanielG wrote:
 
 Wait, wut? Do modules that get pulled in from dub's "importPaths" not 
 get compiled in the same way?
No. They just get -I'd.
Oct 28 2018