views:

200

answers:

2

I've just been beaten (rather hardly) on the head by some non-trivial warning from Visual Studio 2010 (C++).

The compilation gave the following output:

1 Debug\is.obj : warning LNK4042: object specified more than once; extras ignored
1 Debug\make.obj : warning LNK4042: object specified more than once; extras ignored
1 Debug\view.obj : warning LNK4042: object specified more than once; extras ignored
1 identity.obj : error LNK2019: unresolved external symbol void __cdecl test::identity::view(void) (?view@identity@test@@YAXXZ) referenced in function void __cdecl test::identity::identity(void) (?identity@0test@@YAXXZ)
1 identity.obj : error LNK2019: unresolved external symbol void __cdecl test::identity::make(void) (?make@identity@test@@YAXXZ) referenced in function void __cdecl test::identity::identity(void) (?identity@0test@@YAXXZ)
1 range.obj : error LNK2019: unresolved external symbol void __cdecl test::range::is(void) (?is@range@test@@YAXXZ) referenced in function void __cdecl test::range::range(void) (?range@0test@@YAXXZ)

Linker errors are always a pain to debug... but there were unresolved references, and so I checked... but the source is well-formed... and finally it hit me:

My folder hierarchy looks like so:

src/
  identity/
    is.cpp
    make.cpp
    view.cpp
  range/
    is.cpp
    make.cpp
    view.cpp

and so does the hierarchy in the Solution (I always set it up so that it mimicks the "real" folder structure).

And the diagnostic outputs:

Debug\is.obj
Debug\make.obj
Debug\view.obj

Along with a warning which says that the .obj has been passed twice to the linker and that one will be ignored.

Search no more: Visual has neatly flatten my folder hierarchy, and therefore is unable to neatly compile the source.

At the moment, I am simply thinking of renaming the files, that should cover the issue...

... but is there a way to have Visual Studio NOT flatten the file hierarchy ?

+6  A: 

Right-click the .cpp file in the Solution Explorer window, Properties, C/C++, Output Files, Object File Name setting. The default is $(IntDir)\, that's what is doing the flattening. All the .obj file will go into $(IntDir), the "Debug" directory in the debug configuration.

You can change the setting, say $(IntDir)\is2.obj. Or select all the files from one group (use Shift+Click) and change the setting to, say, $(IntDir)\identity\

Or you can change the .cpp filename so that .obj files don't overwrite each other. Having files with the exact same name in two directories is a bit odd.

Or you can create multiple projects, creating, say, .lib projects for the files in identity and range. Commonly done in makefile projects for example. That does however make managing the compile and link settings more of a hassle unless you use project property sheets.

Hans Passant
Thanks, I have renamed the files already since it was the easier way to go. Is there no way to ask Visual to preserve the hierarchy I so carefully built in the Project ? I know having the same filename for several files is strange, but I prefer to cluster things by subdirectory rather than prefixing my files... and it's redundant to both puth them in a subdirectory and prefix them by the subdirectory name!
Matthieu M.
You can change settings for multiple files at the same time. Hold down the CTRL key while you click to select them. Using `$(IntDir)\$(ParentName)\` was trouble the last time I tried that.
Hans Passant
@Hans: guess I'll keep using different names then, I am not that happy with the solution, but since it's only for the unit test part I guess I'll live with it.
Matthieu M.
Is it possible to set `$(IntDir)` per-file in a property sheet? I know you can set it for the whole project in a property sheet, but I don't know whether you can set it based on the path of the file being compiled. (My guess is no, but I'm a complete MSBuild noob)
James McNellis
@James, project property sheets have project scope, they affect all files.
Hans Passant
@Hans: That's what I thought. That's kind of a shame; it would be really nice to be able to set a property conditionally for certain files. Thanks.
James McNellis
+1  A: 

Just wanted to cross posted what I believe to be the answer, if you open the properties for the entire project, and the change the value under C/C++ -> Output Files -> "Object File Name" to be the following:

$(IntDir)/%(RelativeDir)/

Under VS 2010, I believe this will disambiguate all of the object files (as I believe windows won't let you under any crazy circumstances have two files with the same names in the same directory). Please also check out the details here.

M. Tibbits
Ah! Now that's something I'll need to try as soon as I get back home :D
Matthieu M.