Thread overview
Bug: Importing but not linking doesn't create module constructors
Aug 22, 2004
Brad Beveridge
Re: Importing but not linking doesn't create module constructors
Aug 22, 2004
Walter
Aug 22, 2004
Brad Beveridge
Aug 23, 2004
Regan Heath
Aug 23, 2004
Brad Beveridge
Aug 23, 2004
Regan Heath
Aug 24, 2004
brad.beveridge
Aug 24, 2004
Regan Heath
Aug 24, 2004
rad.beveridge
Aug 24, 2004
Regan Heath
August 22, 2004
Hi all, I think I have found a slight bug.  If I have a wrapper d file that simply wraps some C functions, but also has a static module constructor - ie
--- file wrap.d ---
static this()
{
    printf("Wrap ctor\n");
}

-- file main.d --
import wrap;

//version=broken;

version(broken)
{
    static this()
    {
        printf("ctorTest\n");
    }
}

int main(char [][]a)
{
    return 0;
}

Right - if I compile main.d and don't link it with wrap.o then there is no
problems, and no output.  I think that this is wrong, I should get an
unresolved symbol for the wrap module's static constructor.
If I compile main.d with a static constructor, then there is the link error
that I describe above.
If I link wrap.o with main.o then everything is correct as expected.
I think that this is a bug because you can import wrapper files that may do
critical setup in their static constructor.  If you are in a C frame of
mind & think of the wrap.d file as a header file, and don't actually link
wrap.o - and you have no static constructors of your own - then the
imported file's static constructor will not get linked or called - and the
linker doesn't complain.
I am using DMD 0.100 on linux.

Cheers
Brad
August 22, 2004
"Brad Beveridge" <brad.beveridge@somewhere.com> wrote in message news:cg975q$2uoc$1@digitaldaemon.com...
> Hi all, I think I have found a slight bug.  If I have a wrapper d file
that
> simply wraps some C functions, but also has a static module constructor - ie
> --- file wrap.d ---
> static this()
> {
>     printf("Wrap ctor\n");
> }
>
> -- file main.d --
> import wrap;
>
> //version=broken;
>
> version(broken)
> {
>     static this()
>     {
>         printf("ctorTest\n");
>     }
> }
>
> int main(char [][]a)
> {
>     return 0;
> }
>
> Right - if I compile main.d and don't link it with wrap.o then there is no
> problems, and no output.  I think that this is wrong, I should get an
> unresolved symbol for the wrap module's static constructor.
> If I compile main.d with a static constructor, then there is the link
error
> that I describe above.
> If I link wrap.o with main.o then everything is correct as expected.
> I think that this is a bug because you can import wrapper files that may
do
> critical setup in their static constructor.  If you are in a C frame of
> mind & think of the wrap.d file as a header file, and don't actually link
> wrap.o - and you have no static constructors of your own - then the
> imported file's static constructor will not get linked or called - and the
> linker doesn't complain.
> I am using DMD 0.100 on linux.

Importing a module is not enough to get it linked in, you must actually reference something in it. It must be that way, because that's the only way to generate extern references to data in D.


August 22, 2004
Walter wrote:

> 
> "Brad Beveridge" <brad.beveridge@somewhere.com> wrote in message news:cg975q$2uoc$1@digitaldaemon.com...
>> Hi all, I think I have found a slight bug.  If I have a wrapper d file
> that
>> simply wraps some C functions, but also has a static module constructor - ie
>> --- file wrap.d ---
>> static this()
>> {
>>     printf("Wrap ctor\n");
>> }
>>
>> -- file main.d --
>> import wrap;
>>
>> //version=broken;
>>
>> version(broken)
>> {
>>     static this()
>>     {
>>         printf("ctorTest\n");
>>     }
>> }
>>
>> int main(char [][]a)
>> {
>>     return 0;
>> }
>>
>> Right - if I compile main.d and don't link it with wrap.o then there is
>> no
>> problems, and no output.  I think that this is wrong, I should get an
>> unresolved symbol for the wrap module's static constructor.
>> If I compile main.d with a static constructor, then there is the link
> error
>> that I describe above.
>> If I link wrap.o with main.o then everything is correct as expected.
>> I think that this is a bug because you can import wrapper files that may
> do
>> critical setup in their static constructor.  If you are in a C frame of
>> mind & think of the wrap.d file as a header file, and don't actually link
>> wrap.o - and you have no static constructors of your own - then the
>> imported file's static constructor will not get linked or called - and
>> the linker doesn't complain.
>> I am using DMD 0.100 on linux.
> 
> Importing a module is not enough to get it linked in, you must actually reference something in it. It must be that way, because that's the only way to generate extern references to data in D.

That makes sense, but doesn't it also make sense that when you import a module, it should require the static constructor for that module - if it has one - to be resolved?  I think it is inconsistant that having other static module constructors requries imported module constructors to be resolved, but if no modules have static constructors then the imports don't need to be linked.  Thoughts?

Cheers
Brad
August 23, 2004
On Sun, 22 Aug 2004 20:46:26 +1200, Brad Beveridge <brad.beveridge@somewhere.com> wrote:
> Walter wrote:
>
>>
>> "Brad Beveridge" <brad.beveridge@somewhere.com> wrote in message
>> news:cg975q$2uoc$1@digitaldaemon.com...
>>> Hi all, I think I have found a slight bug.  If I have a wrapper d file
>> that
>>> simply wraps some C functions, but also has a static module constructor -
>>> ie
>>> --- file wrap.d ---
>>> static this()
>>> {
>>>     printf("Wrap ctor\n");
>>> }
>>>
>>> -- file main.d --
>>> import wrap;
>>>
>>> //version=broken;
>>>
>>> version(broken)
>>> {
>>>     static this()
>>>     {
>>>         printf("ctorTest\n");
>>>     }
>>> }
>>>
>>> int main(char [][]a)
>>> {
>>>     return 0;
>>> }
>>>
>>> Right - if I compile main.d and don't link it with wrap.o then there is
>>> no
>>> problems, and no output.  I think that this is wrong, I should get an
>>> unresolved symbol for the wrap module's static constructor.
>>> If I compile main.d with a static constructor, then there is the link
>> error
>>> that I describe above.
>>> If I link wrap.o with main.o then everything is correct as expected.
>>> I think that this is a bug because you can import wrapper files that may
>> do
>>> critical setup in their static constructor.  If you are in a C frame of
>>> mind & think of the wrap.d file as a header file, and don't actually link
>>> wrap.o - and you have no static constructors of your own - then the
>>> imported file's static constructor will not get linked or called - and
>>> the linker doesn't complain.
>>> I am using DMD 0.100 on linux.
>>
>> Importing a module is not enough to get it linked in, you must actually
>> reference something in it. It must be that way, because that's the only
>> way to generate extern references to data in D.
>
> That makes sense, but doesn't it also make sense that when you import a
> module, it should require the static constructor for that module - if it
> has one - to be resolved?

No, the static constructor is presumably to initialise things in the module, if the program does not refer to anything in the module, why initialise it?

> I think it is inconsistant that having other
> static module constructors requries imported module constructors to be
> resolved, but if no modules have static constructors then the imports don't
> need to be linked.  Thoughts?

I don't understand this last paragraph, pls explain...

Regan

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
August 23, 2004
Regan Heath wrote:

> On Sun, 22 Aug 2004 20:46:26 +1200, Brad Beveridge <brad.beveridge@somewhere.com> wrote:
>> Walter wrote:
>>
>>>
>>> "Brad Beveridge" <brad.beveridge@somewhere.com> wrote in message news:cg975q$2uoc$1@digitaldaemon.com...
>>>> Hi all, I think I have found a slight bug.  If I have a wrapper d file
>>> that
>>>> simply wraps some C functions, but also has a static module
>>>> constructor -
>>>> ie
>>>> --- file wrap.d ---
>>>> static this()
>>>> {
>>>>     printf("Wrap ctor\n");
>>>> }
>>>>
>>>> -- file main.d --
>>>> import wrap;
>>>>
>>>> //version=broken;
>>>>
>>>> version(broken)
>>>> {
>>>>     static this()
>>>>     {
>>>>         printf("ctorTest\n");
>>>>     }
>>>> }
>>>>
>>>> int main(char [][]a)
>>>> {
>>>>     return 0;
>>>> }
>>>>
>>>> Right - if I compile main.d and don't link it with wrap.o then there is
>>>> no
>>>> problems, and no output.  I think that this is wrong, I should get an
>>>> unresolved symbol for the wrap module's static constructor.
>>>> If I compile main.d with a static constructor, then there is the link
>>> error
>>>> that I describe above.
>>>> If I link wrap.o with main.o then everything is correct as expected.
>>>> I think that this is a bug because you can import wrapper files that
>>>> may
>>> do
>>>> critical setup in their static constructor.  If you are in a C frame of
>>>> mind & think of the wrap.d file as a header file, and don't actually
>>>> link
>>>> wrap.o - and you have no static constructors of your own - then the
>>>> imported file's static constructor will not get linked or called - and
>>>> the linker doesn't complain.
>>>> I am using DMD 0.100 on linux.
>>>
>>> Importing a module is not enough to get it linked in, you must actually reference something in it. It must be that way, because that's the only way to generate extern references to data in D.
>>
>> That makes sense, but doesn't it also make sense that when you import a module, it should require the static constructor for that module - if it has one - to be resolved?
> 
> No, the static constructor is presumably to initialise things in the module, if the program does not refer to anything in the module, why initialise it?
> 
>> I think it is inconsistant that having other
>> static module constructors requries imported module constructors to be
>> resolved, but if no modules have static constructors then the imports
>> don't
>> need to be linked.  Thoughts?
> 
> I don't understand this last paragraph, pls explain...
> 
> Regan
> 
I was trying to say that by importing a module you are implicitly making
reference to the static constructor.  If that statement is true (which I
don't know) then the linker should require that the imported module be
linked.  At the moment it is valid to import a module & use functions from
it - ie this is how you wrap a library.  Now, what happens if that module
also does some important library setup in a static constructor?  Well, if
you don't link the wrapper then that static constructor will not get
called, and the linker will not complain.
The inconsistancy arises in the following case:
1.  I have the two files (code above), the wrapper exports a static module
constructor but since I don't link it doesn't get called.
  * I think this is the first bug, if you import a module then that module's
constructor should be resolved.
2.  If I add a static constructor to one of my other modules (uncomment
version=broken), THEN the imported (but not linked) wrap module's
constructor is required and the linker does actually complain about not
resolving the symbol.

I think that the behaviour described in 2 is correct, except that you shouldn't need a module ctor in your own modules to force wrap's ctor to come into play.

Cheers
Brad
August 23, 2004
On Mon, 23 Aug 2004 17:39:07 +1200, Brad Beveridge <brad.beveridge@somewhere.com> wrote:
> Regan Heath wrote:
>
>> On Sun, 22 Aug 2004 20:46:26 +1200, Brad Beveridge
>> <brad.beveridge@somewhere.com> wrote:
>>> Walter wrote:
>>>
>>>>
>>>> "Brad Beveridge" <brad.beveridge@somewhere.com> wrote in message
>>>> news:cg975q$2uoc$1@digitaldaemon.com...
>>>>> Hi all, I think I have found a slight bug.  If I have a wrapper d file
>>>> that
>>>>> simply wraps some C functions, but also has a static module
>>>>> constructor -
>>>>> ie
>>>>> --- file wrap.d ---
>>>>> static this()
>>>>> {
>>>>>     printf("Wrap ctor\n");
>>>>> }
>>>>>
>>>>> -- file main.d --
>>>>> import wrap;
>>>>>
>>>>> //version=broken;
>>>>>
>>>>> version(broken)
>>>>> {
>>>>>     static this()
>>>>>     {
>>>>>         printf("ctorTest\n");
>>>>>     }
>>>>> }
>>>>>
>>>>> int main(char [][]a)
>>>>> {
>>>>>     return 0;
>>>>> }
>>>>>
>>>>> Right - if I compile main.d and don't link it with wrap.o then there is
>>>>> no
>>>>> problems, and no output.  I think that this is wrong, I should get an
>>>>> unresolved symbol for the wrap module's static constructor.
>>>>> If I compile main.d with a static constructor, then there is the link
>>>> error
>>>>> that I describe above.
>>>>> If I link wrap.o with main.o then everything is correct as expected.
>>>>> I think that this is a bug because you can import wrapper files that
>>>>> may
>>>> do
>>>>> critical setup in their static constructor.  If you are in a C frame of
>>>>> mind & think of the wrap.d file as a header file, and don't actually
>>>>> link
>>>>> wrap.o - and you have no static constructors of your own - then the
>>>>> imported file's static constructor will not get linked or called - and
>>>>> the linker doesn't complain.
>>>>> I am using DMD 0.100 on linux.
>>>>
>>>> Importing a module is not enough to get it linked in, you must actually
>>>> reference something in it. It must be that way, because that's the only
>>>> way to generate extern references to data in D.
>>>
>>> That makes sense, but doesn't it also make sense that when you import a
>>> module, it should require the static constructor for that module - if it
>>> has one - to be resolved?
>>
>> No, the static constructor is presumably to initialise things in the
>> module, if the program does not refer to anything in the module, why
>> initialise it?
>>
>>> I think it is inconsistant that having other
>>> static module constructors requries imported module constructors to be
>>> resolved, but if no modules have static constructors then the imports
>>> don't
>>> need to be linked.  Thoughts?
>>
>> I don't understand this last paragraph, pls explain...
>>
>> Regan
>>
> I was trying to say that by importing a module you are implicitly making
> reference to the static constructor.  If that statement is true (which I
> don't know) then the linker should require that the imported module be
> linked.

Ahh.. I see, I don't think that statement is true, by saying import foo, all you're saying is use foo for lookup name resolution, you're not causing any symbols to be imported, including the static constructor.

When you use foo.bar you're importing the bar symbol, and thus the foo module, and thus the static constructor.

> At the moment it is valid to import a module & use functions from
> it - ie this is how you wrap a library.  Now, what happens if that module
> also does some important library setup in a static constructor?  Well, if
> you don't link the wrapper then that static constructor will not get
> called, and the linker will not complain.
> The inconsistancy arises in the following case:
> 1.  I have the two files (code above), the wrapper exports a static module
> constructor but since I don't link it doesn't get called.

It doesn't get called because you're not using anything from the wrap module.
Try this code:

--- file wrap.d ---
static this()
{
  printf("Wrap ctor\n");
}

void fooBar()
{
  printf("fooBar called\n");
}

-- file main.d --
import wrap;

//version=broken;

version(broken)
{
  static this()
  {
    printf("ctorTest\n");
  }
}

int main(char[][] a)  //modified this from 'char [][]a' <- this is c style :)
{
  fooBar();
  return 0;
}

>   * I think this is the first bug, if you import a module then that module's
> constructor should be resolved.

I think it's working correctly (assuming my code above does what I think it does) in that if you do not use something from the module, it does not get initialized.

> 2.  If I add a static constructor to one of my other modules (uncomment
> version=broken), THEN the imported (but not linked) wrap module's
> constructor is required and the linker does actually complain about not
> resolving the symbol.
>
> I think that the behaviour described in 2 is correct, except that you
> shouldn't need a module ctor in your own modules to force wrap's ctor to
> come into play.

I think #2 is the bug. By adding that ctor to main.d you're not creating a dependency on wrap.d so it's a bug to require it.

Regan

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
August 24, 2004
<SNIP>
>> I was trying to say that by importing a module you are implicitly making reference to the static constructor.  If that statement is true (which I don't know) then the linker should require that the imported module be linked.
>
>Ahh.. I see, I don't think that statement is true, by saying import foo, all you're saying is use foo for lookup name resolution, you're not causing any symbols to be imported, including the static constructor.
>
>When you use foo.bar you're importing the bar symbol, and thus the foo module, and thus the static constructor.
>
>> At the moment it is valid to import a module & use functions from
>> it - ie this is how you wrap a library.  Now, what happens if that module
>> also does some important library setup in a static constructor?  Well, if
>> you don't link the wrapper then that static constructor will not get
>> called, and the linker will not complain.
>> The inconsistancy arises in the following case:
>> 1.  I have the two files (code above), the wrapper exports a static
>> module
>> constructor but since I don't link it doesn't get called.
>
>It doesn't get called because you're not using anything from the wrap
>module.
>Try this code:
>
>--- file wrap.d ---
>static this()
>{
>   printf("Wrap ctor\n");
>}
>
>void fooBar()
>{
>   printf("fooBar called\n");
>}
>
>-- file main.d --
>import wrap;
>
>//version=broken;
>
>version(broken)
>{
>   static this()
>   {
>     printf("ctorTest\n");
>   }
>}
>
>int main(char[][] a)  //modified this from 'char [][]a' <- this is c style
>:)
>{
>   fooBar();
>   return 0;
>}
>
>>   * I think this is the first bug, if you import a module then that
>> module's
>> constructor should be resolved.
>
>I think it's working correctly (assuming my code above does what I think it does) in that if you do not use something from the module, it does not get initialized.
>
>> 2.  If I add a static constructor to one of my other modules (uncomment version=broken), THEN the imported (but not linked) wrap module's constructor is required and the linker does actually complain about not resolving the symbol.
>>
>> I think that the behaviour described in 2 is correct, except that you shouldn't need a module ctor in your own modules to force wrap's ctor to come into play.
>
>I think #2 is the bug. By adding that ctor to main.d you're not creating a dependency on wrap.d so it's a bug to require it.
>
>Regan
>
>-- 
>Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
OK - now what happens when I use symbols from wrap.d, ie - call functions - but
wrap.d is simply defining C functions that get linked from a regular C file?
The linker is resolved for those functions and no static constructor gets
called.  Imagine the case where you wrap a C library, and have a static module
constructor that you intend to get called that should setup the library.
Currently it is valid to import that wrapper & unknowingly not call the static
module constuctor - which I am sure is at best a subtle bug.
If you are curious why I am worrying about this - the SDL.d file does exactly
the above, wraps a C header & has a module ctor to help startup the library.

Brad


August 24, 2004
On Tue, 24 Aug 2004 00:18:03 +0000 (UTC), <brad.beveridge@somewhere.co> wrote:

<snip>

> OK - now what happens when I use symbols from wrap.d, ie - call functions - but
> wrap.d is simply defining C functions that get linked from a regular C file?

I don't know. What happens?

> The linker is resolved for those functions and no static constructor gets
> called.  Imagine the case where you wrap a C library, and have a static module
> constructor that you intend to get called that should setup the library.
>
> Currently it is valid to import that wrapper & unknowingly not call the static
> module constuctor - which I am sure is at best a subtle bug.

So you're saying that in the above described example it does in fact link but fails to compile and/or execute the static ctor.

I agree it is definately a bug, but, the bug could be one of two things, either:

- it should call the static ctor in this case.
- the static ctor in this case should be illegal.

> If you are curious why I am worrying about this - the SDL.d file does exactly
> the above, wraps a C header & has a module ctor to help startup the library.

What does the ctor do? Basically I want to know why it's in a static ctor in that particular file and not somewhere else. This will determine exactly what the bug is, once we have that worked out we can post a concise yet complete code segment that reproduces the bug in the digitalmars.d.bugs NG. :)

Regan

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
August 24, 2004
><snip>
>
>> OK - now what happens when I use symbols from wrap.d, ie - call
>> functions - but
>> wrap.d is simply defining C functions that get linked from a regular C
>> file?
>
>I don't know. What happens?
Everything compiles and links (and generally runs) fine, except that the static constructor in wrap.d never gets compiled or linked.  I believe that importing a module should imply "I want this module's constructor to get called", and it is not that case right now.

>
>> The linker is resolved for those functions and no static constructor gets
>> called.  Imagine the case where you wrap a C library, and have a static
>> module
>> constructor that you intend to get called that should setup the library.
>>
>> Currently it is valid to import that wrapper & unknowingly not call the
>> static
>> module constuctor - which I am sure is at best a subtle bug.
>
>So you're saying that in the above described example it does in fact link but fails to compile and/or execute the static ctor.
Exactly.

>
>I agree it is definately a bug, but, the bug could be one of two things, either:
>
>- it should call the static ctor in this case.
>- the static ctor in this case should be illegal.
>
>> If you are curious why I am worrying about this - the SDL.d file does
>> exactly
>> the above, wraps a C header & has a module ctor to help startup the
>> library.
>
>What does the ctor do? Basically I want to know why it's in a static ctor in that particular file and not somewhere else. This will determine exactly what the bug is, once we have that worked out we can post a concise yet complete code segment that reproduces the bug in the digitalmars.d.bugs NG. :)
In the SDL case it calls (I think) SDL_Init(SDL_PARACHUTE).  But for any given
library that you wrap, you may want to have library specific initialisation in
that wrapper module's constructor.
I don't think that I have been very clear in my description of this bug, if
someone could rephrase it..... :)

Brad


August 24, 2004
On Tue, 24 Aug 2004 02:12:39 +0000 (UTC), <rad.beveridge@somewhere.co> wrote:
>>> OK - now what happens when I use symbols from wrap.d, ie - call
>>> functions - but
>>> wrap.d is simply defining C functions that get linked from a regular C
>>> file?
>>
>> I don't know. What happens?
> Everything compiles and links (and generally runs) fine, except that the static
> constructor in wrap.d never gets compiled or linked.

There is definately a bug in it.

> I believe that importing a
> module should imply "I want this module's constructor to get called", and it is
> not that case right now.

I don't agree with that idea. An import statement simply tells the compiler where to look for name resolution, it does not import any symbols, the use of a symbol imports it.

Consider this:

--wrap.d--
static this() {
  SDL_Init(SDL_PARACHUTE)
}

extern (C) {
  SDL_Thing();
}

--main.d--
void main()
{
}

now, as main.d does not call SDL_Thing(); there is no point in doing the SDL_Init call, basically the module isn't being used, so why link it in.

The bug, as I see it, is: due to the symbols being defined as extern (C) the linker does not realise they're in use and are part of the module, so does not link the static constructor.

I reckon you re-post this to the digitalmars.D.bugs NG, make sure you include the call to the extern C declared function in the module with the static this which is being ignored.

In the meantime you could move the static constructor from where it is and put it in your main.d file. One could argue that was where it belonged anyway. If on the other hand you we're wrapping a class interface round it then it would likely belong where it is, at the same time you wouldn't have this bug (I reckon) as you'd be using a D class from that module and the linker would notice and compile/execute the static constructor.

>>> If you are curious why I am worrying about this - the SDL.d file does
>>> exactly
>>> the above, wraps a C header & has a module ctor to help startup the
>>> library.
>>
>> What does the ctor do? Basically I want to know why it's in a static ctor
>> in that particular file and not somewhere else. This will determine
>> exactly what the bug is, once we have that worked out we can post a
>> concise yet complete code segment that reproduces the bug in the
>> digitalmars.d.bugs NG. :)
> In the SDL case it calls (I think) SDL_Init(SDL_PARACHUTE).  But for any given
> library that you wrap, you may want to have library specific initialisation in
> that wrapper module's constructor.

I agree. I was just checking.

> I don't think that I have been very clear in my description of this bug, if
> someone could rephrase it..... :)

I understand what you're saying, I know what you want to happen, I know what is happening, I'm just thoughroughly exploring the entire thing. It's not my job, I know, I just can't help it, besides, if the result is that we have a concise bug report that takes Walter less time to fix, everyone is happy.

Regan

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/