www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Bug: Importing but not linking doesn't create module constructors

reply Brad Beveridge <brad.beveridge somewhere.com> writes:
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
Aug 21 2004
parent reply "Walter" <newshound digitalmars.com> writes:
"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

 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

 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

 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.
Aug 22 2004
parent reply Brad Beveridge <brad.beveridge somewhere.com> writes:
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

 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

 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

 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
Aug 22 2004
parent reply Regan Heath <regan netwin.co.nz> writes:
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

 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

 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

 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/
Aug 22 2004
parent reply Brad Beveridge <brad.beveridge somewhere.com> writes:
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

 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

 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

 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

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
Aug 22 2004
parent reply Regan Heath <regan netwin.co.nz> writes:
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

 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

 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

 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

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/
Aug 23 2004
parent reply brad.beveridge somewhere.co writes:
<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/

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
Aug 23 2004
parent reply Regan Heath <regan netwin.co.nz> writes:
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/
Aug 23 2004
parent reply rad.beveridge somewhere.co writes:
<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?

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.

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. :)

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
Aug 23 2004
parent Regan Heath <regan netwin.co.nz> writes:
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?

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. :)

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/
Aug 23 2004