Visual Studio 2010s seltsame "Warnung LNK4042"

80

Ich bin gerade (ziemlich kaum) von einer nicht trivialen Warnung aus Visual Studio 2010 (C ++) auf den Kopf geschlagen worden.

Die Zusammenstellung ergab folgende Ausgabe:

1 Debug \ is.obj: Warnung LNK4042: Objekt mehr als einmal angegeben; Extras ignoriert
1 Debug \ make.obj: Warnung LNK4042: Objekt mehr als einmal angegeben; Extras ignoriert
1 Debug \ view.obj: Warnung LNK4042: Objekt mehr als einmal angegeben; Extras ignoriert
1 identity.obj: Fehler LNK2019: ungelöstes externes Symbol void __cdecl test::identity::view(void)(? view @ identity @ test @@ YAXXZ), auf das in der Funktion verwiesen wird void __cdecl test::identity::identity(void)(? identity @ 0test @@ YAXXZ)
1 identity.obj: Fehler LNK2019: ungelöstes externes Symbol void __cdecl test::identity::make(void)(? make @ identity @ test @@ YAXXZ) in der Funktion referenziert void __cdecl test::identity::identity(void)(? identity @ 0test @@ YAXXZ)
1 range.obj: Fehler LNK2019: ungelöstes externes Symbol void __cdecl test::range::is(void)(? is @ range @ test @@ YAXXZ), auf das in der Funktion verwiesen wird void __cdecl test::range::range(void)(? range @ 0test) YAXXZ)

Linker-Fehler sind immer ein Problem beim Debuggen ... aber es gab ungelöste Referenzen, und so habe ich nachgesehen ... aber die Quelle ist wohlgeformt ... und schließlich hat es mich getroffen:

Meine Ordnerhierarchie sieht folgendermaßen aus:

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

und die Hierarchie in der Lösung auch (ich habe sie immer so eingerichtet, dass sie die "echte" Ordnerstruktur nachahmt).

Und die Diagnoseausgänge:

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

Zusammen mit einer Warnung, die besagt, dass das .objzweimal an den Linker übergeben wurde und dass einer ignoriert wird.

Suchen Sie nicht mehr: Visual hat meine Ordnerhierarchie sauber reduziert und kann daher die Quelle nicht sauber kompilieren.

Im Moment denke ich nur daran, die Dateien umzubenennen, die das Problem abdecken sollten ...

... aber gibt es eine Möglichkeit, dass Visual Studio die Dateihierarchie NICHT reduziert?

Matthieu M.
quelle
3
Ich habe gerade das Gleiche bekommen, was wirklich ärgerlich ist, dass wir es manuell "reparieren" müssen. Ich bin froh, dass du vor mir gefragt hast. :)
GManNickG
5
Ich habe die SO-Suche vor langer Zeit aufgegeben. :) Google.
GManNickG
37
Ich habe gerade ein ähnliches Problem in VS 2013 gelöst. Für mich bestand das Problem darin, dass eine Header-Datei so kompiliert wurde, als wäre es eine eigenständige C ++ - Datei. Am Ende hatte ich zwei Objektdateien mit demselben Namen: eine für foo.cpp und eine für foo.h. Die Lösung bestand darin, zu den richtigen Seiten für foo.h zu wechseln und die Konfigurationseigenschaften -> Allgemein -> Elementtyp in "C / C ++ - Header" zu ändern und einen sauberen Build durchzuführen.
Adrian McCarthy
1
@AdrianMcCarthy Ich hatte das gleiche Problem und Ihr Vorschlag löste es.
Trenki
1
@AdrianMcCarthys Kommentar ist die Lösung. Muss daran liegen, dass der Assistent Hinzufügen -> "Neues Element" den Elementtyp der Datei automatisch festlegt.
Dustin Biser

Antworten:

99

Ich wollte nur die Antwort kreuzen, die meiner Meinung nach die Antwort ist, wenn Sie die Eigenschaften für das gesamte Projekt öffnen und den Wert C/C++ -> Output Files -> "Object File Name"wie folgt ändern :

$ (IntDir) /% (RelativeDir) /

Ich glaube, dass dies unter VS 2010 alle Objektdateien eindeutig macht (da ich glaube, dass Windows es Ihnen unter verrückten Umständen nicht erlaubt, zwei Dateien mit demselben Namen im selben Verzeichnis zu haben). Bitte überprüfen Sie auch die Details hier .

M. Tibbits
quelle
Ah! Das muss ich versuchen, sobald ich wieder zu Hause bin: D
Matthieu M.
7
Nur um hinzuzufügen: Es scheint, dass% (RelativeDir) keine ../ .. (nicht, dass es sollte, aber es scheint auch keine Alternative zu geben) in Ihrem Pfad entfernen, so dass Sie möglicherweise "gefälschtes" Verzeichnis hinzufügen müssen damit Ihre Dateien im "richtigen" Verzeichnis erstellt werden. Zum Beispiel habe ich $ (IntDir) / a / a /% (RelativeDir) /, nur damit es $ (IntDir) aufgrund von zwei ../ im Pfad meiner .cpp einbauen kann (Pfade sind relativ zu $ ​​(ProjectDir) ), Ich denke). Beachten Sie auch, dass% (RelativeDir) mit einem% und $ (IntDir) mit einem $ ist (die Antwort ist richtig, nur dass beim schnellen Lesen diese Tatsache möglicherweise übersehen wird).
n1ckp
2
Hm ... ich frage mich, warum dies nicht standardmäßig eingestellt ist. Nun, ich denke, ich werde dies einfach zu jedem Projekt hinzufügen (kaum etwas wird ohne dieses
Navin
Dies funktionierte in Visual Studio 2012 Update 1, aber seit ich auf Update 4 gepatcht habe, scheint VS keine Zwischenverzeichnisse mehr für Objektdateien erstellen zu wollen. :( (Siehe stackoverflow.com/questions/30212698. )
Thomas Young
Wie gehe ich vor, wenn ich cl.exein CLI verwende?
Lernen
143

Ich hatte ein ähnliches Problem mit der Linker-Warnung LNK4042: Objekt mehr als einmal angegeben; Extras ignoriert . In meinem Fall hat Visual Studio versucht, sowohl Header- als auch Quelldateien mit demselben Namen zu kompilieren - MyClass.hund MyClass.cpp. Es ist passiert, weil ich die .cppDatei in umbenannt habe .hund Visual Studio verwirrt war. Ich habe das Problem beim Betrachten der Compiler-Protokolle im DebugVerzeichnis bemerkt . Zum Auflösen entfernen Sie einfach die .hDatei aus dem Projekt und fügen Sie sie erneut hinzu.

Andrey Levichev
quelle
2
Danke, dass du das gepostet hast! Die alte Routine zum Entfernen der Datei und zum Zurücksetzen hat den Trick auch für mich erledigt. Ich fing wirklich an, meinen Kopf gegen die Wand zu schlagen.
Wes
3
Danke @AndreyLevichev - diese Antwort hat das Problem auch für mich behoben. In der Projektdatei ist ziemlich klar, dass sich eine .h-Datei in der Gruppe "ClCompile" anstelle der Gruppe "ClInclude" befindet
jglouie
35
Oder Sie können mit der rechten Maustaste auf die foo.hDatei in Ihrem Lösungs-Explorer klicken und "Elementtyp" auf "C / C ++ - Header" anstatt auf "C / C ++ - Compiler" setzen.
Thomas Eding
+1 dafür. Ich hätte mein Problem nie gefunden, wenn ich Ihren Kommentar nicht gesehen hätte.
Crocboy
2
@ Yaur - Oder noch besser, ändern Sie es in einen CLIncludeEintrag
TED
8

Klicken Sie mit der rechten Maustaste auf die CPP-Datei im Projektmappen-Explorer, Eigenschaften, C / C ++, Ausgabedateien, Objektdateiname. Die Standardeinstellung ist $(IntDir)\, dass dies die Abflachung bewirkt. Die gesamte OBJ-Datei wird in $ (IntDir), dem Verzeichnis "Debug" in der Debug-Konfiguration, abgelegt.

Sie können beispielsweise die Einstellung ändern $(IntDir)\is2.obj. Oder wählen Sie alle Dateien aus einer Gruppe aus (verwenden Sie Umschalt + Klicken) und ändern Sie die Einstellung beispielsweise in$(IntDir)\identity\

Oder Sie können den .cpp-Dateinamen so ändern, dass sich .obj-Dateien nicht gegenseitig überschreiben. Dateien mit genau demselben Namen in zwei Verzeichnissen zu haben, ist etwas seltsam.

Sie können auch mehrere Projekte erstellen, z. B. .lib-Projekte für die Dateien in Identität und Bereich. Wird beispielsweise häufig in Makefile-Projekten durchgeführt. Das macht das Verwalten der Kompilierungs- und Verknüpfungseinstellungen jedoch schwieriger, es sei denn, Sie verwenden Projekteigenschaftenblätter.

Hans Passant
quelle
Vielen Dank, ich habe die Dateien bereits umbenannt, da dies der einfachere Weg war. Gibt es keine Möglichkeit, Visual zu bitten, die Hierarchie beizubehalten, die ich so sorgfältig im Projekt erstellt habe? Ich weiß, dass es seltsam ist, denselben Dateinamen für mehrere Dateien zu haben, aber ich bevorzuge es, Dinge nach Unterverzeichnis zu gruppieren, anstatt meinen Dateien ein Präfix zu geben ... und es ist überflüssig, sie in ein Unterverzeichnis zu setzen und ihnen den Namen des Unterverzeichnisses voranzustellen!
Matthieu M.
Sie können die Einstellungen für mehrere Dateien gleichzeitig ändern. Halten Sie die STRG-Taste gedrückt, während Sie klicken, um sie auszuwählen. Die Verwendung von "$ (IntDir) \ $ (ParentName)" war ein Problem, als ich das das letzte Mal versuchte.
Hans Passant
@Hans: Ich denke, ich werde dann weiterhin andere Namen verwenden. Ich bin nicht so zufrieden mit der Lösung, aber da es nur für den Unit-Test-Teil ist, werde ich wohl damit leben.
Matthieu M.
Ist es möglich, $(IntDir)pro Datei in einem Eigenschaftenblatt festzulegen? Ich weiß, dass Sie es für das gesamte Projekt in einem Eigenschaftenblatt festlegen können, aber ich weiß nicht, ob Sie es basierend auf dem Pfad der zu kompilierenden Datei festlegen können. (Meine Vermutung ist nein, aber ich bin ein kompletter MSBuild-Neuling)
James McNellis
@James, Projekteigenschaftenblätter haben Projektumfang, sie wirken sich auf alle Dateien aus.
Hans Passant
6

Klicken Sie mit der rechten Maustaste auf Header-Datei -> Eigenschaft -> ItemType (wählen Sie C / C ++ - Header ). Machen Sie dasselbe mit der Cpp-Datei, aber wählen Sie C / C ++ Compiler (es funktioniert für mich)

Phạm Mạnh
quelle
Dies war das Letzte, wonach ich suchen würde. Danke vielmals.
McLeary
4

Ich verwende $ (IntDir) \% (Directory) \ unter C / C ++ -> Ausgabedateien -> "Object File Name".

Csimbi
quelle
Die Verwendung von% (Verzeichnis) anstelle von% (RelativeDir) ist zwar im Wesentlichen mit der akzeptierten Antwort identisch, jedoch etwas sicherer. Wie von n1ckp in den akzeptierten Antwortkommentaren angegeben, kann es sein, dass das relative Verzeichnis Ihre OBJ-Dateien an unerwarteten Stellen platziert, je nachdem, wie genau Ihr Projekt auf der Festplatte strukturiert ist.
user1593842
3

Ich hatte dieses Problem mit stdafx.cpp. Irgendwie wurde stdafx.cpp dupliziert, also gab es eine zweite StdAfx.cpp (beachten Sie den anderen Fall).

Nachdem ich die StdAfx.cpp entfernt hatte, funktionierte alles einwandfrei!

Verwenden von VS 2010.

Knasterbax
quelle
Hatte ein ähnliches Problem, aber anstatt die Datei zu duplizieren, war es dieselbe Datei, die zweimal in der ClCompile ItemGroup aufgeführt wurde.
Nicholas Betsworth
3

Alternativ zum Löschen und Erstellen einer neuen Datei können Sie die Einstellungen zum Kompilieren / Einschließen ändern.

Gehen Sie zu Ihrer Datei project.vcxproj , öffnen Sie sie mit einem Editor und suchen Sie die HTML-ähnliche Zeile <ItemGroup>.

Es sollte ungefähr so ​​aussehen:

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

und

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

Angenommen, Ihre Implementierungsdateien sind .cpp und Ihre Deklarationen sind .hpp. Stellen Sie sicher, dass alle Ihre Implementierungsdateien zwischen dem ersten Abschnitt aufgelistet sind, wenn Sie mehr als eine haben, und ebenfalls für den zweiten Abschnitt für mehrere Deklarationsdateien.

user1222064
quelle
2

Früher habe ich in den gleichen Projekt haben .c und CPP - Dateien mit den gleichen Dateinamen . Die Dateien befanden sich überall in Ordnern, und die von anderen bereitgestellten Lösungen verursachten ein Durcheinander und die Hölle der Ordner (in meinem Fall). Selbst Release- Builds würden Debug- Builds überschreiben !

Eine gute (nicht perfekte) Lösung wäre die Verwendung von $ (ParentName). Aus irgendeinem Grund wurde es jedoch aus späteren Versionen von Visual Studio (2015+) entfernt.

Was ich jetzt erfolgreich benutze, ist: $ (IntDir)% (Dateiname)% (Erweiterung) .obj

Dies trennt zumindest die von .c erstellten Objektdateien von .cpp .

Bill Kotsias
quelle