Visual Studio 2010's strange "warning LNK4042"
Asked Answered
U

11

84

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 ?

Ultraconservative answered 12/9, 2010 at 14:24 Comment(8)
Just got this same thing, really annoying that we have to "fix" it manually. Glad you asked before me. :)Pilatus
@GMan: an I am surprised that you could find it at all :) Did you search using Google or the SO engine ?Ultraconservative
I gave up on the SO search a long time ago. :) Google.Pilatus
I just solved a similar problem in VS 2013. For me, the problem was that a header file was being compiled as though it was a standalone C++ file. So I ended up with two object files with the same name: one for foo.cpp and one for foo.h. The solution was to go to the proper pages for foo.h and change Configuration Properties -> General -> Item Type to "C/C++ header" and do a clean build.Extensometer
@AdrianMcCarthy I had the same issue and your suggestion solved it.Yvonneyvonner
@AdrianMcCarthy 's comment is the solution. Must be due to Add->"New Item" wizard automatically setting the file's item type.Wafer
Yep...I remember accidentally creating the file as a "Source File" then renaming it once I noticed it was .c. This clearly didn't inform the toolchain that I do not wish to compile it as an obj.Rondon
I just got hit by this and made sure the header was actually set to compile as a header in the properties successfully cleared this for me as well. Thanks!Conscientious
I
102

Just wanted to cross post 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.

Intermigration answered 16/9, 2010 at 23:29 Comment(7)
Ah! Now that's something I'll need to try as soon as I get back home :DUltraconservative
Just to add: it seems that %(RelativeDir) do not strip away any ../.. (not that it should but there do not seems to have any alternative either) in your path so you might have to add "fake" directory to get your files to build in the "correct" directory. Exemple, I have $(IntDir)/a/a/%(RelativeDir)/ just so it can build in $(IntDir) because of two ../ in the path of my .cpp (Paths are relative to the $(ProjectDir), I think). Also note that %(RelativeDir) is with a % and $(IntDir) is with a $ (the answer is correct, just that by reading fast, that fact may be missed).Mydriasis
Hm... I wonder why this isn't set by default. Well, I guess I'll just add this to every project (hardly anything compiles without this fix)Kept
This worked in Visual Studio 2012 update 1, but since I patched to update 4, VS doesn't seem to want to create intermediate directories for object files anymore. :( (See stackoverflow.com/questions/30212698.)Dulosis
How to do when I use cl.exe in CLI?Signature
No effect in VS2013Steven
Slashes are not needed, as the property and metadata have trailing slashes. BTW, you can find more information at MSBuild warning MSB8027.Stockjobber
R
161

I had a similar problem with linker warning LNK4042: object specified more than once; extras ignored. In my case Visual Studio was trying to compile both header and source files with the same name - MyClass.h and MyClass.cpp. It happened because I renamed .cpp file to .h and Visual Studio got confused. I noticed the problem by looking at the compiler logs in the Debug directory. To resolve just remove .h file from the project then add it again.

Rhoda answered 13/6, 2011 at 17:11 Comment(3)
Or you can right click on the foo.h file in your solution explorer and set "Item Type" to "C/C++ header" rather than "C/C++ compiler".Arroyo
As an alternative you can also remove the <ClCompile Include="foo.h" /> line from your vcxproj fileBallou
@Ballou - Or better yet, change it to a CLInclude entryBraddy
I
102

Just wanted to cross post 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.

Intermigration answered 16/9, 2010 at 23:29 Comment(7)
Ah! Now that's something I'll need to try as soon as I get back home :DUltraconservative
Just to add: it seems that %(RelativeDir) do not strip away any ../.. (not that it should but there do not seems to have any alternative either) in your path so you might have to add "fake" directory to get your files to build in the "correct" directory. Exemple, I have $(IntDir)/a/a/%(RelativeDir)/ just so it can build in $(IntDir) because of two ../ in the path of my .cpp (Paths are relative to the $(ProjectDir), I think). Also note that %(RelativeDir) is with a % and $(IntDir) is with a $ (the answer is correct, just that by reading fast, that fact may be missed).Mydriasis
Hm... I wonder why this isn't set by default. Well, I guess I'll just add this to every project (hardly anything compiles without this fix)Kept
This worked in Visual Studio 2012 update 1, but since I patched to update 4, VS doesn't seem to want to create intermediate directories for object files anymore. :( (See stackoverflow.com/questions/30212698.)Dulosis
How to do when I use cl.exe in CLI?Signature
No effect in VS2013Steven
Slashes are not needed, as the property and metadata have trailing slashes. BTW, you can find more information at MSBuild warning MSB8027.Stockjobber
D
9

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.

Duodiode answered 12/9, 2010 at 14:49 Comment(6)
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!Ultraconservative
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.Duodiode
@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.Ultraconservative
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)Conclusive
@James, project property sheets have project scope, they affect all files.Duodiode
@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.Conclusive
C
8

Right click on header file -> Property -> ItemType (select C/C++ Header). Do the same with Cpp file but select C/C++ Compiler (it's work for me)

Choosey answered 1/1, 2015 at 17:28 Comment(1)
This was the last thing I would think of looking for. Many thanks.Haeckel
J
4

Alternatively to deleting and making a new file you can change the compile/include settings.

Go to your project.vcxproj file, open it with an editor, find the html like line <ItemGroup>.

It should look something like:

<ItemGroup>
<ClCompile Include="implementation.cpp" />
</ItemGroup>

and

<ItemGroup>
<ClInclude Include="declaration.hpp" />
</ItemGroup>`

Assuming your implementation files are .cpp and your declarations are .hpp. Make sure your all your implementation files are listed between the first section if you have more then one and likewise for the second section for multiple declaration files.

Johst answered 5/3, 2013 at 21:16 Comment(0)
S
3

I had this problem with stdafx.cpp. Somehow stdafx.cpp got duplicated, so there was a second StdAfx.cpp (mind the different case).

After I removed the StdAfx.cpp everything worked fine!

Using VS 2010.

Screamer answered 11/1, 2013 at 17:55 Comment(1)
Had a similar issue, but instead of the file being duplicated, it was the same file listed twice in the ClCompile ItemGroup.Cyrillic
K
3

I use $(IntDir)\%(Directory)\ under C/C++ -> Output Files -> "Object File Name".

Kayak answered 19/3, 2013 at 23:15 Comment(1)
While essentially the same as the accepted answer, using %(Directory) instead of %(RelativeDir) is a little bit safer. As noted by n1ckp in the accepted answer comments, depending how exactly your project is structured on the disk, the relative dir may end up placing your .obj files on unexpected places.Iconolatry
K
2

I used to have in the same project .c and .cpp files with the same filenames. The files were in folders all over the place and the solutions provided by others created a mess, and folder hell (in my case). Even Release builds would overwrite Debug builds!

A good (not perfect) solution would be to use $(ParentName), but for some reason beyond anyone's grasp it has been removed from later versions of Visual Studio (2015+).

What I use succesfully now is: $(IntDir)%(Filename)%(Extension).obj

which at least separates .c built object files from .cpp.

Karly answered 16/3, 2017 at 15:31 Comment(0)
I
0

I'd like to point out one possible reason for why the ItemType of a .h file would change from C/C++ header to C/C++ compiler:

  1. In the Solution Explorer window of VS (2019 here), right click the project name, choose Add -> New Item;
  2. Select the C++ File (.cpp) template, but type something.h in the name input area, then click OK to add it;
  3. Then you'll encounter the LNK4042 warning if the something.h file be included within more than one .cpp files.
Immigrate answered 30/4, 2021 at 7:41 Comment(0)
F
0

I just overcame a similar error message, and lots more with the procedure below. Symptom: one linker error for every invocation of every function defined in a particular header, plus one at the end of output for every function defined in the header.

Then I remembered that when I had originally created this header, I accidentally had selected "add->new item->c++ file" and though I named it 'whatever.h', it seems Visual Studio considered them both the same kinds of files because of the incorrect action I used to add one. Examining the build output logs made this obvious.

SOLUTION (Using VS Community 2019)

  1. Back up project first (just to be safe).
  2. Right-click the offending header file and select "Exclude from project" (this will not delete them; the VS project will just ignore them).
  3. Do same for the matching .c or .cpp file.
  4. Do Build->Clean on project
  5. Do Build->Rebuild on project -- there of course will be errors---
  6. Right-click Header Files->Add->Existing Item, then select the .h file
  7. Right-click Source Files->Add->Existing Item, the select the .c or .cpp file
  8. Do Build->Rebuild on project.

This completely cleaned it up for me, relieving me of many irritating linker errors including LNK4042 from the title of this question.

Fustic answered 9/11, 2021 at 12:42 Comment(0)
F
0

I resolved it changing filenames in my project. There was two files named main.c and main.cpp. I changed one of them and worked.

Flosi answered 24/5, 2022 at 18:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.