www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Extern/scope issue

reply DLearner <bmqazwsx123 gmail.com> writes:
'Testmain' imports module 'testmod'.
Both are shown below.
I expected 1,1,2,2.
I got 1,0,2,1 - which speaks to scope/extern misunderstanding

Any ideas?
Best regards

Testmain:

int xvar;
import testmod;
void main() {
    import std.stdio;

    writeln("Entering: main");
    xvar = 1;
    writeln("xvar=", xvar);
    testsub();
    writeln("xvar=", xvar);

    writeln("Leaving: main");
}

Testmod:

void testsub() {

    extern(D) int xvar;
    import std.stdio;

    writeln("Entering: testsub");
    writeln("xvar=", xvar);
    xvar = 2;
    writeln("xvar=", xvar);
    writeln("Leaving: testsub");
}
Apr 03
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 03/04/2021 11:01 PM, DLearner wrote:
 'Testmain' imports module 'testmod'.
 Both are shown below.
 I expected 1,1,2,2.
 I got 1,0,2,1 - which speaks to scope/extern misunderstanding
 
 Any ideas?
 Best regards
 
 Testmain:
 
 int xvar;
TLS variable with D mangling, not a c global.
 import testmod;
 void main() {
    import std.stdio;
 
    writeln("Entering: main");
    xvar = 1;
    writeln("xvar=", xvar);
    testsub();
    writeln("xvar=", xvar);
 
    writeln("Leaving: main");
 }
 
 Testmod:
 
 void testsub() {
 
    extern(D) int xvar;
That is a regular variable. Setting the calling convention/mangling like that doesn't make any sense and shouldn't be allowed in context.
    import std.stdio;
 
    writeln("Entering: testsub");
    writeln("xvar=", xvar);
    xvar = 2;
    writeln("xvar=", xvar);
    writeln("Leaving: testsub");
 }
 
Apr 03
parent reply DLearner <bmqazwsx123 gmail.com> writes:
On Saturday, 3 April 2021 at 10:05:45 UTC, rikki cattermole wrote:
 On 03/04/2021 11:01 PM, DLearner wrote:
 [...]
TLS variable with D mangling, not a c global.
  [...]
That is a regular variable. Setting the calling convention/mangling like that doesn't make any sense and shouldn't be allowed in context.
 [...]
 TLS variable with D mangling, not a c global.
Does this mean D has no equivalent of C globals? What is the D way of doing this?
Apr 03
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 03/04/2021 11:17 PM, DLearner wrote:
 On Saturday, 3 April 2021 at 10:05:45 UTC, rikki cattermole wrote:
 On 03/04/2021 11:01 PM, DLearner wrote:
 [...]
TLS variable with D mangling, not a c global.
  [...]
That is a regular variable. Setting the calling convention/mangling like that doesn't make any sense and shouldn't be allowed in context.
 [...]
 TLS variable with D mangling, not a c global.
Does this mean D has no equivalent of C globals? What is the D way of doing this?
https://dlang.org/spec/attribute.html#gshared However, you should be using the module system for accessing globals, rather than redeclaring them.
Apr 03
next sibling parent reply DLearner <bmqazwsx123 gmail.com> writes:
Tried the following, same result (1,0,2,1):
testmain:
__gshared int xvar;
import testmod;

void main() {
    import std.stdio;

    writeln("Entering: main");
    xvar = 1;
    writeln("xvar=", xvar);
    testsub();
    writeln("xvar=", xvar);

    writeln("Leaving: main");
}

testmod:
void testsub() {
    __gshared int xvar;

    import std.stdio;

    writeln("Entering: testsub");
    writeln("xvar=", xvar);
    xvar = 2;
    writeln("xvar=", xvar);
    writeln("Leaving: testsub");
}
Apr 03
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
--- main.d
module main;

extern(C) __gshared int foo;

import std;
void main()
{
     import foo : func;
     func;

     writeln(foo);
}

--- foo.d
module foo;
extern extern(C) __gshared int foo;

void func() {
     foo++;
}

The __gshared is irrelevant to it working between modules, but it is 
relevant if you want C compatibility between threads (NOTE: extern(C) 
sets mangling, otherwise the module would be encoded in its name).
Apr 03
parent reply DLearner <bmqazwsx123 gmail.com> writes:
 The __gshared is irrelevant to it working between modules, but 
 it is relevant if you want C compatibility between threads 
 (NOTE: extern(C) sets mangling, otherwise the module would be 
 encoded in its name).
Solved: The following produces the expected result. However, changing extern(C) to extern(D) causes linker failures. To me, that is bizarre. Testmain: extern(C) int xvar; import testmod; void main() { import std.stdio; writeln("Entering: main"); xvar = 1; writeln("xvar=", xvar); testsub(); writeln("xvar=", xvar); writeln("Leaving: main"); } Testmod: extern extern(C) int xvar; void testsub() { import std.stdio; writeln("Entering: testsub"); writeln("xvar=", xvar); xvar = 2; writeln("xvar=", xvar); writeln("Leaving: testsub"); }
Apr 03
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 04/04/2021 2:34 AM, DLearner wrote:
 However, changing extern(C) to extern(D) causes linker failures.
 To me, that is bizarre.
extern(D) sets the ABI AND mangling. D mangling incorporates things like the module name.
Apr 03
parent reply DLearner <bmqazwsx123 gmail.com> writes:
On Saturday, 3 April 2021 at 13:38:25 UTC, rikki cattermole wrote:
 On 04/04/2021 2:34 AM, DLearner wrote:
 However, changing extern(C) to extern(D) causes linker 
 failures.
 To me, that is bizarre.
extern(D) sets the ABI AND mangling. D mangling incorporates things like the module name.
I'm sure you are correct, but extern(C) -> extern(D) in both references. So both source streams are aware of the convention used.
Apr 03
parent rikki cattermole <rikki cattermole.co.nz> writes:
On 04/04/2021 2:48 AM, DLearner wrote:
 On Saturday, 3 April 2021 at 13:38:25 UTC, rikki cattermole wrote:
 On 04/04/2021 2:34 AM, DLearner wrote:
 However, changing extern(C) to extern(D) causes linker failures.
 To me, that is bizarre.
extern(D) sets the ABI AND mangling. D mangling incorporates things like the module name.
I'm sure you are correct, but extern(C) -> extern(D) in both references. So both source streams are aware of the convention used.
https://dlang.org/spec/abi.html#name_mangling
Apr 03
prev sibling parent reply ag0aep6g <anonymous example.com> writes:
On 03.04.21 15:34, DLearner wrote:
 The following produces the expected result.
 However, changing extern(C) to extern(D) causes linker failures.
 To me, that is bizarre.
 Testmain:
 extern(C) int xvar;
[...]
 
 Testmod:
 extern extern(C) int xvar;
With `extern (C)`, those two `xvar`s refer to the same data. Without `extern (C)` (or with `extern (D)`), they are distinct variables with no relation to another. In D, you don't re-declare another module's symbols. You import the other module. ---- module testmain; import std.stdio: writeln; import testmod: testsub, xvar; void main() { xvar = 1; writeln(xvar); /* prints "1" */ testsub(); writeln(xvar); /* prints "2" */ } ---- ---- module testmod; int xvar; /* same as `extern (D) int xvar;` */ void testsub() { xvar = 2; } ----
Apr 03
parent DLearner <bmqazwsx123 gmail.com> writes:
On Saturday, 3 April 2021 at 13:50:27 UTC, ag0aep6g wrote:
 On 03.04.21 15:34, DLearner wrote:
 The following produces the expected result.
 However, changing extern(C) to extern(D) causes linker 
 failures.
 To me, that is bizarre.
 Testmain:
 extern(C) int xvar;
[...]
 
 Testmod:
 extern extern(C) int xvar;
With `extern (C)`, those two `xvar`s refer to the same data. Without `extern (C)` (or with `extern (D)`), they are distinct variables with no relation to another. In D, you don't re-declare another module's symbols. You import the other module. ---- module testmain; import std.stdio: writeln; import testmod: testsub, xvar; void main() { xvar = 1; writeln(xvar); /* prints "1" */ testsub(); writeln(xvar); /* prints "2" */ } ---- ---- module testmod; int xvar; /* same as `extern (D) int xvar;` */ void testsub() { xvar = 2; } ----
Thank you, your suggestions worked. No externs anywhere. For the record, the code is below. import itf; import testmod:testsub; void main() { import std.stdio; writeln("Entering: main"); xvar = 1; writeln("xvar=", xvar); testsub(); writeln("xvar=", xvar); writeln("Leaving: main"); } module itf; int xvar; module testmod; import itf; void testsub() { import std.stdio; writeln("Entering: testsub"); writeln("xvar=", xvar); xvar = 2; writeln("xvar=", xvar); writeln("Leaving: testsub"); }
Apr 03
prev sibling parent DLearner <bmqazwsx123 gmail.com> writes:
 https://dlang.org/spec/attribute.html#gshared

 However, you should be using the module system for accessing 
 globals, rather than redeclaring them.
If the module system is dumped, and evrything put into one file, works perfectly. With or without __gshared in from of 'int xvar'. int xvar; void main() { import std.stdio; writeln("Entering: main"); xvar = 1; writeln("xvar=", xvar); testsub(); writeln("xvar=", xvar); writeln("Leaving: main"); } void testsub() { import std.stdio; writeln("Entering: testsub"); writeln("xvar=", xvar); xvar = 2; writeln("xvar=", xvar); writeln("Leaving: testsub"); }
Apr 03
prev sibling parent reply z <z z.com> writes:
On Saturday, 3 April 2021 at 10:17:14 UTC, DLearner wrote:
 Does this mean D has no equivalent of C globals?
 What is the D way of doing this?
With __gshared. If the global is defined from within another language, apparently you'd have to do [extern(C) extern __gshared *name*](https://dlang.org/spec/interfaceToC.html#c-globals) It seems that the whole extern keyword can be confusing with variables: ```d //L is the language name extern(L) returnType functionName(parameters); // function implemented in another language or out of this module. extern(L) returnType functionName(parameters) {/*...*/}//extern only changes the name mangling and the calling rules in the resulting assembly code.(with D it does not change anything?) extern(L) variableType variableName; //what you did, declares a normal variable, except that the name mangling rule is that of the language you specified. extern(L) extern otherQualifiersIfAny variableType variableName; //appears to be a variable declared outside of the module, so at link time a .obj file will have to declare a variable with this symbol name or else the linker will error out. ``` It seems that case 4 is what you desired but i do not know if with this module hierarchy it can/will work with dub.(it should.) With the code as is you should be able to access both variables from main with `testmod.xvar` and simply `xvar`.(when name conflicts like this occur the most local is used by default, otherwise use the full name which should be `testmain.xvar` in this case.)
Apr 03
parent DLearner <bmqazwsx123 gmail.com> writes:
 extern(L) extern otherQualifiersIfAny variableType 
 variableName; //appears to be a variable declared outside of 
 the module, so at link time a .obj file will have to declare a 
 variable with this symbol name or else the linker will error 
 out.
 ```
 It seems that case 4 is what you desired but i do not know if 
 with this module hierarchy it can/will work with dub.(it 
 should.)
 With the code as is you should be able to access both variables 
 from main with `testmod.xvar` and simply `xvar`.(when name 
 conflicts like this occur the most local is used by default, 
 otherwise use the full name which should be `testmain.xvar` in 
 this case.)
I tried case 4, failed with link errors. I am not trying to establish two variables, just exactly the same one everywhere. That's why the desired test output is 1,1,2,2
Apr 03