Thread overview
DMD: can't get extern __gshared to work right (vs. LDC)
Feb 07, 2019
DanielG
Feb 08, 2019
DanielG
Feb 08, 2019
Kagamin
Feb 08, 2019
DanielG
Feb 08, 2019
rikki cattermole
Feb 08, 2019
DanielG
Feb 18, 2019
DanielG
Feb 18, 2019
rikki cattermole
February 07, 2019
macOS 12, DMD 2.084.0 / LDC 1.14.0-beta1

I have a C API that exports some global variables, declared like so:

.h file:
=====
extern "C" {
#define PUBLIC_API __attribute__((visibility("default")))
struct __opaqueHandle; typedef __opaqueHandle* opaqueHandle_t;
PUBLIC_API extern const opaqueHandle_t kSomeGlobalValue;
}

.cpp file:
======
const opaqueHandle_t kSomeGlobalValue = (opaqueHandle_t) kSomeInternalPointer;

.d file:
====
extern (C):
export extern __gshared opaqueHandle_t kSomeGlobalValue;


I have no issues linking against the resulting .dylib with a C/C++ program, nor issues with DMD on Windows with the same code. However with DMD on macOS, the value is coming through incorrectly. It looks like a valid pointer value (vs. pure garbage), but it's still incorrect. LDC2 works fine, no issues.

Is there some extra flag I need to pass to DMD on Mac to get it to see this global properly? It links fine, no errors, but the value is still wrong. I should also mention that this dylib exports functions, too, and they are working fine even with DMD. It's just the globals I'm having problems with.
February 08, 2019
Follow-up:

The problem on DMD macOS is the "export" keyword. It ended up in my code during a similar-ish problem last year, when I was having trouble linking against DLL global variables on Windows.

If I remove the "export" keyword in the D interface, it will work on macOS but break on Windows. (To reiterate: WITHOUT "export" on Windows, it refuses to link. WITH "export" on Mac, it seems to link but with incorrect results)

Is this correct behavior?
February 08, 2019
On Friday, 8 February 2019 at 05:28:30 UTC, DanielG wrote:
> Is this correct behavior?

It's correct for Windows: address of imported data is not known at link time and must use dynamic linkage. AFAIK, export attribute doesn't do much on posix platforms.
February 08, 2019
On Friday, 8 February 2019 at 07:52:26 UTC, Kagamin wrote:
> AFAIK, export attribute doesn't do much on posix platforms.

I created a minimal example and it definitely segfaults at runtime in the presence of "export" (on Mac, haven't tested linux). So it's required for Windows and silently evil for Mac...

Any reason I shouldn't file a DMD bug for this?
February 08, 2019
On 08/02/2019 9:14 PM, DanielG wrote:
> On Friday, 8 February 2019 at 07:52:26 UTC, Kagamin wrote:
>> AFAIK, export attribute doesn't do much on posix platforms.
> 
> I created a minimal example and it definitely segfaults at runtime in the presence of "export" (on Mac, haven't tested linux). So it's required for Windows and silently evil for Mac...
> 
> Any reason I shouldn't file a DMD bug for this?

File, inconsistent behavior is inconsistent. Not good.
February 08, 2019
On Friday, 8 February 2019 at 09:19:12 UTC, rikki cattermole wrote:
> File, inconsistent behavior is inconsistent. Not good.

done: https://issues.dlang.org/show_bug.cgi?id=19660


February 18, 2019
In the meantime, while I'm waiting for this bug to be noticed by anybody with the skills to address it, what would be the most elegant way of working around it?

Obviously I could do a:

version(Windows) {
  export extern __gshared ...
} else {
  extern __gshared ...
}

But what's the minimal way of toggling the presence of "export" in a declaration? Using mixins feels kind of gross for this, but if that's the only option ...

Almost makes me long for the C preprocessor :P

February 19, 2019
On 19/02/2019 6:26 AM, DanielG wrote:
> In the meantime, while I'm waiting for this bug to be noticed by anybody with the skills to address it, what would be the most elegant way of working around it?
> 
> Obviously I could do a:
> 
> version(Windows) {
>    export extern __gshared ...
> } else {
>    extern __gshared ...
> }
> 
> But what's the minimal way of toggling the presence of "export" in a declaration? Using mixins feels kind of gross for this, but if that's the only option ...
> 
> Almost makes me long for the C preprocessor :P

Because you need two different versions to choose between them, either set a per module version or use static if with enum's.

But yeah, I would do that. Of course a mixin template with a code string (q{ ... }) would be cleaner. After all, ``export { mixin(str); }`` would work well.