Thread overview
[Issue 1830] New: duplicated constants + extern(Windows) = Link error: Previous Definition Different
Feb 13, 2008
d-bugmail
Feb 13, 2008
d-bugmail
Feb 13, 2008
d-bugmail
Feb 13, 2008
d-bugmail
Feb 13, 2008
d-bugmail
Mar 04, 2008
d-bugmail
February 13, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=1830

           Summary: duplicated constants + extern(Windows) =  Link error:
                    Previous Definition Different
           Product: D
           Version: 1.025
          Platform: PC
        OS/Version: Windows
            Status: NEW
          Keywords: link-failure
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: bugzilla@digitalmars.com
        ReportedBy: wbaxter@gmail.com


If two modules define the same constants it's usually OK.  But if those constants are extern(windows) then they will create linker errors.

---link_main.d---
module link_main;
import link_a;
import link_b;
void main()
{
}

---link_a.d---
module link_a;

extern(Windows):
const uint FOO = cast(uint)-1;


---link_b.d---
module link_b;

extern(Windows):
const uint FOO = cast(uint)-1;

---

Build with
  dmd link_main link_a link_b

And you get:
"""
f:\usr\pkg\d\dmd\bin\..\..\dm\bin\link.exe
link_main+link_a+link_b,,,user32+kernel32/noi;
OPTLINK (R) for Win32  Release 7.50B1
Copyright (C) Digital Mars 1989 - 2001  All Rights Reserved

link_b.obj(link_b)  Offset 000E0H Record Type 0091
 Error 1: Previous Definition Different : _FOO
--- errorlevel 1
"""

If you remove the extern(Windows) lines, it links fine.

This is causing trouble when linking apps that import more than one Windows API wrapper since most of them stick an extern(Windows): at the top of the file, which ends up covering all the constants as well as functions.   I'm not even sure if extern(Windows) has meaning for constants like that, but it certainly appears to influence how the linker handles them.


-- 

February 13, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=1830





------- Comment #1 from wbaxter@gmail.com  2008-02-12 23:58 -------
Issue 1629 may be related.


-- 

February 13, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=1830


torhu@yahoo.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |INVALID




------- Comment #2 from torhu@yahoo.com  2008-02-13 17:04 -------
I believe this has to be fixed in the libraries that define constants as
'extern (Windows)'.  Either don't use 'extern (Windows):', or use enums instead
for manifest constants.  If the whole file is 'extern (Windows):', another
option might be to put the constants in 'extern (D)' blocks.

'extern (Windows)' gives the variables C name mangling.  Which I believe is correct.  Also see issue 1306.


-- 

February 13, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=1830


wbaxter@gmail.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
         Resolution|INVALID                     |




------- Comment #3 from wbaxter@gmail.com  2008-02-13 17:12 -------
A) Why should the name mangling affect whether the linker says it is a multiply-defined symbol?

B) The error message says specifically "previous definition different" which is simply untrue.  The previous definition was identical.

C) Your workaround #1 is self-contradictory - you say change extern(Windows) to
extern(D), but then later say extern(Windows) is correct for these symbols.

D) Your workaround #2 (change const to enum) requires a change to Phobos, meaning that at the very least this is a bug against Phobos whose std.c.windows.windows module uses const rather than enum.


-- 

February 13, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=1830





------- Comment #4 from torhu@yahoo.com  2008-02-13 17:52 -------
(In reply to comment #3)
> A) Why should the name mangling affect whether the linker says it is a multiply-defined symbol?

The regular D name mangling convention adds the module name to the beginning of the mangled symbol, and the type at the end.

If FOO in your module was extern (D), it would be mangled as '_D6link_a3FOOk'. For the other module, _D6link_b3FOOk.  So there is no conflict when linking.

With C name mangling on Windows, it's just _FOO in both cases.  That's why the linker complains.

To work around this, you can avoid linking with both modules.  Since they only define an integer constant, you don't even need to link with any of them.  Try it. :)

Compiling one or both module into .lib files will work too, at least for your sample and other simple cases.

> 
> B) The error message says specifically "previous definition different" which is simply untrue.  The previous definition was identical.
> 

Might be a linker bug, I don't know.  I doesn't matter if they identical or not, they can't have the same mangled name.

> C) Your workaround #1 is self-contradictory - you say change extern(Windows) to
> extern(D), but then later say extern(Windows) is correct for these symbols.
> 
No, I just meant that C mangling is correct when using extern (Windows).

> D) Your workaround #2 (change const to enum) requires a change to Phobos, meaning that at the very least this is a bug against Phobos whose std.c.windows.windows module uses const rather than enum.
> 

I'll agree with that.  The title is probably wrong then.


-- 

March 04, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=1830


bugzilla@digitalmars.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|REOPENED                    |RESOLVED
         Resolution|                            |WONTFIX




------- Comment #5 from bugzilla@digitalmars.com  2008-03-04 01:57 -------
The problem is that the names for link_a.FOO and link_b.FOO are mangled the same when using extern(Windows), and are mangled differently when using extern(D), as the module name is part of the mangled name for D mangling.

This is not fixable, as it is inherent with how Windows name mangling must work.

The linker message means that there are two definitions of FOO. It doesn't matter to the linker that they have the same contents - the linker doesn't know that. The names collide.


--