Visual Studio 2010 奇怪的“警告LNK4042”

Visual Studio 2010's strange "warning LNK4042"

提问人:Matthieu M. 提问时间:9/12/2010 最后编辑:James McNellisMatthieu M. 更新时间:5/25/2022 访问量:47131

问:

我刚刚被Visual Studio 2010(C++)的一些重要警告打了(相当严重)。

编译给出了以下输出:

1 Debug\is.obj:警告 LNK4042:多次指定对象;忽略的额外内容
1 Debug\make.obj : warning LNK4042: object specified than once;extras ignored
1 Debug\view.obj : warning LNK4042: object specified than once;忽略的额外内容
1 Identity.obj:错误 LNK2019:函数 (?identity@0test@@YAXXZ) 中引用的未解析的外部符号 (?view@identity@test@@YAXXZ) 1 identity.obj:错误 LNK2019:函数 (?identity@0test@@YAXXZ) 中引用的未解析的外部符号 (?make@identity@test@@YAXXZ) 1 range.obj:错误 LNK2019:函数 (?range@0test@@YAXXZ) 中引用的未解析的外部符号 (?is@range@test@@YAXXZ)

void __cdecl test::identity::view(void)void __cdecl test::identity::identity(void)void __cdecl test::identity::make(void)void __cdecl test::identity::identity(void)void __cdecl test::range::is(void)void __cdecl test::range::range(void)

链接器错误总是调试起来很痛苦...但是有未解决的参考资料,所以我检查了......但来源是格式良好的......最后它击中了我:

我的文件夹层次结构如下所示:

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

解决方案中的层次结构也是如此(我总是对其进行设置,使其模仿“真实”文件夹结构)。

诊断输出:

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

以及一个警告,指出已将 传递给链接器两次,并且将忽略其中一次。.obj

不再搜索:Visual 整齐地扁平化了我的文件夹层次结构,因此无法整齐地编译源代码。

目前,我只是在考虑重命名文件,这应该涵盖了这个问题......

...但是有没有办法让Visual Studio不扁平化文件层次结构?

++ 工作室 可视化 -C 可视化-C++-2010

评论

3赞 GManNickG 1/22/2011
刚刚得到了同样的事情,我们必须手动“修复”它真的很烦人。很高兴你在我面前问。:)
5赞 GManNickG 1/22/2011
我很久以前就放弃了 SO 搜索。:)谷歌。
42赞 Adrian McCarthy 7/22/2014
我刚刚在 VS 2013 中解决了一个类似的问题。对我来说,问题在于头文件被编译为一个独立的 C++ 文件。因此,我最终得到了两个同名的目标文件:一个用于 foo.cpp,一个用于 foo.h。解决方案是转到 foo.h 的正确页面,将“配置属性”->“常规”>“项类型”更改为“C/C++ 标头”,然后进行干净的构建。
2赞 trenki 3/17/2015
@AdrianMcCarthy我遇到了同样的问题,你的建议解决了它。
3赞 Dustin Biser 10/31/2016
@AdrianMcCarthy的评论是解决方案。一定是由于“添加>”新建项“向导自动设置了文件的项目类型。

答:

9赞 Hans Passant 9/12/2010 #1

右键单击“解决方案资源管理器”窗口、“属性”、“C/C++”、“输出文件”、“对象文件名”设置中的 .cpp 文件。默认值是 ,这就是进行扁平化的原因。所有 .obj 文件都将进入 $(IntDir),即调试配置中的“Debug”目录。$(IntDir)\

您可以更改设置,比如 .或者从一组中选择所有文件(使用 Shift+Click),然后将设置更改为,$(IntDir)\is2.obj$(IntDir)\identity\

或者,您可以更改 .cpp 文件名,以便 .obj 文件不会相互覆盖。在两个目录中拥有完全相同名称的文件有点奇怪。

或者,您可以创建多个项目,例如为 identity 和 range 中的文件创建 .lib 项目。例如,通常在 makefile 项目中完成。但是,除非使用项目属性表,否则管理编译和链接设置会更加麻烦。

评论

0赞 Matthieu M. 9/12/2010
谢谢,我已经重命名了文件,因为这是更简单的方法。难道就没有办法要求 Visual 保留我在项目中精心构建的层次结构吗?我知道几个文件使用相同的文件名很奇怪,但我更喜欢按子目录对事物进行聚类,而不是在我的文件前面加上前缀......将它们放在子目录中并以子目录名称为前缀是多余的!
0赞 Hans Passant 9/12/2010
您可以同时更改多个文件的设置。按住 CTRL 键,同时单击以选择它们。上次尝试使用“$(IntDir)\$(ParentName)”很麻烦。
0赞 Matthieu M. 9/13/2010
@Hans:我想我会继续使用不同的名称,我对解决方案不太满意,但由于它仅适用于单元测试部分,我想我会忍受它。
0赞 James McNellis 9/13/2010
是否可以在属性表中设置每个文件?我知道您可以在属性表中为整个项目设置它,但我不知道是否可以根据正在编译的文件的路径进行设置。(我的猜测是否定的,但我是一个彻头彻尾的 MSBuild 菜鸟)$(IntDir)
0赞 Hans Passant 9/13/2010
@James,项目属性表具有项目范围,它们会影响所有文件。
102赞 M. Tibbits 9/17/2010 #2

只是想交叉发布我认为是答案的东西,如果你打开整个项目的属性,并将下面的值更改为以下内容:C/C++ -> Output Files -> "Object File Name"

$(IntDir)/%(RelativeDir)/

在 VS 2010 下,我相信这将消除所有目标文件的歧义(因为我相信 Windows 不会让您在任何疯狂的情况下在同一目录中拥有两个同名的文件)。请在此处查看详细信息。

评论

0赞 Matthieu M. 9/17/2010
啊!现在,这是我一回到家就需要尝试的事情:D
7赞 n1ckp 5/11/2011
补充一点:似乎 %(RelativeDir) 不会剥离任何 ../..(不是说它应该,但似乎也没有其他选择)所以你可能必须添加“假”目录才能让你的文件在“正确”的目录中构建。例如,我有$(IntDir)/a/a/%(RelativeDir)/,这样它就可以在$(IntDir)中构建,因为有两个../ 在我的.cpp路径中(我认为路径相对于 $(ProjectDir) 而言)。另请注意,%(RelativeDir) 与 % 在一起,$(IntDir) 与 $ 在一起(答案是正确的,只是通过快速阅读,可能会遗漏这一事实)。
2赞 Navin 5/11/2013
嗯......我想知道为什么默认情况下没有设置。好吧,我想我会把它添加到每个项目中(如果没有这个修复程序,几乎没有任何东西可以编译)
0赞 Thomas Young 5/18/2015
这在 Visual Studio 2012 update 1 中有效,但由于我修补到 update 4,VS 似乎不想再为对象文件创建中间目录了。:((见 stackoverflow.com/questions/30212698。)
0赞 Learning 5/11/2017
在CLI中使用时该怎么办?cl.exe
159赞 Andrey Levichev 6/14/2011 #3

我在链接器警告LNK4042遇到了类似的问题:多次指定对象; extras 被忽略。就我而言,Visual Studio 试图编译具有相同名称的头文件和源文件 - 和 .发生这种情况是因为我将文件重命名为 并且 Visual Studio 感到困惑。我通过查看目录中的编译器日志注意到了这个问题。要解决此问题,只需从项目中删除文件,然后再次添加它。MyClass.hMyClass.cpp.cpp.hDebug.h

评论

39赞 Thomas Eding 6/8/2012
或者,可以在解决方案资源管理器中右键单击该文件,并将“项类型”设置为“C/C++ 标头”而不是“C/C++ 编译器”。foo.h
0赞 Yaur 4/1/2014
或者,您也可以从 vcxproj 文件中删除该行<ClCompile Include="foo.h" />
4赞 T.E.D. 7/16/2014
@Yaur - 或者更好的是,将其更改为条目CLInclude
3赞 Knasterbax 1/12/2013 #4

我在stdafx.cpp上遇到了这个问题。不知何故,stdafx.cpp 被复制了,所以有第二个 StdAfx.cpp(注意不同的情况)。

在我删除了StdAfx.cpp后,一切正常!

使用 VS 2010。

评论

0赞 Nicholas Betsworth 10/19/2015
有一个类似的问题,但不是文件被复制,而是在 ClCompile ItemGroup 中列出两次的同一个文件。
4赞 user1222064 3/6/2013 #5

或者,除了删除和创建新文件外,还可以更改编译/包含设置。

转到您的项目.vcxproj文件,使用编辑器打开它,找到htmllike行。<ItemGroup>

它应该看起来像这样:

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

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

假设您的实现文件是.cpp的,您的声明是 .hpp。如果有多个声明文件,请确保在第一部分之间列出所有实现文件,对于多个声明文件,请确保在第二部分之间列出所有实现文件。

3赞 Csimbi 3/20/2013 #6

我在 C/C++ -> 输出文件 -> “对象文件名” 下使用 $(IntDir)\%(Directory)\。

评论

0赞 user1593842 1/28/2018
虽然与公认的答案基本相同,但使用 %(Directory) 而不是 %(RelativeDir) 更安全一些。正如 n1ckp 在已接受的答案注释中所指出的,根据项目在磁盘上的确切结构,相对目录最终可能会将您的 .obj 文件放在意想不到的位置。
8赞 Phạm Mạnh 1/2/2015 #7

右键单击头文件 -> 属性 -> ItemType(选择 C/C++ Header)。对 Cpp 文件执行相同的操作,但选择 C/C++ 编译器(它对我有用)

评论

0赞 McLeary 11/30/2017
这是我最不想找的东西。非常感谢。
2赞 Bill Kotsias 3/16/2017 #8

我曾经在同一个项目中拥有具有相同文件名.c.cpp 文件。这些文件到处都是文件夹,其他人提供的解决方案造成了混乱,文件夹地狱(在我的情况下)。即使是发布版本也会覆盖调试版本!

一个好的(不完美的)解决方案是使用 $(ParentName),但由于某种任何人都无法理解的原因,它已从 Visual Studio (2015+) 的更高版本中删除。

我现在成功使用的是: $(IntDir)%(文件名)%(扩展名).obj

这至少将 .c 构建的目标文件与.cpp分开。

0赞 lfree 4/30/2021 #9

我想指出一个可能的原因,为什么 a 会从 :ItemType.h fileC/C++ headerC/C++ compiler

  1. 在 VS(此处为 2019)的窗口中,右键单击项目名称,选择Solution ExplorerAdd -> New Item;
  2. 选择模板,但在名称输入区域输入,然后单击添加;C++ File (.cpp)something.hOK
  3. 然后,如果文件包含在多个文件中,则会遇到警告。LNK4042something.h.cpp
0赞 TomServo 11/9/2021 #10

我刚刚克服了类似的错误消息,以及以下过程的更多内容。症状:每次调用特定标头中定义的每个函数时都会出现一个链接器错误,对于标头中定义的每个函数,输出末尾会出现一个链接器错误。

然后我想起了当我最初创建此标头时,我不小心选择了“add->new item->c++ file”,尽管我将其命名为“whatever.h”,但似乎 Visual Studio 认为它们都是同一种文件,因为我使用了不正确的操作来添加一个。检查生成输出日志使这一点显而易见。

解决方案(使用 VS Community 2019)

  1. 首先备份项目(为了安全起见)。
  2. 右键单击有问题的头文件,然后选择“从项目中排除”(这不会删除它们;VS 项目只会忽略它们)。
  3. 对匹配的 .c 或 .cpp 文件执行相同的操作。
  4. 在项目上执行 Build->Clean
  5. 对项目执行生成>重建 --当然会有错误---
  6. 右键单击“头文件->添加->现有项”,然后选择 .h 文件
  7. 右键单击“源文件”->“添加”->现有项,选择 .c 或 .cpp 文件
  8. 对项目执行 Build-Rebuild >Rebuild。

这为我彻底清理了它,减轻了我许多令人恼火的链接器错误,包括从这个问题的标题中LNK4042。

0赞 Halük Uzuner 5/25/2022 #11

我解决了它,在我的项目中更改文件名。有两个名为 main.c 和 main.cpp 的文件。我换了其中一个并工作了。