Dziwne „ostrzeżenie LNK4042” programu Visual Studio 2010

82

Właśnie uderzyło mnie (raczej nie) w głowę jakieś nietrywialne ostrzeżenie ze strony Visual Studio 2010 (C ++).

Kompilacja dała następujący wynik:

1 Debug \ is.obj: ostrzeżenie LNK4042: obiekt określony więcej niż raz; dodatki ignorowane
1 Debugowanie \ make.obj: ostrzeżenie LNK4042: obiekt określony więcej niż raz; dodatki ignorowane
1 Debugowanie \ view.obj: ostrzeżenie LNK4042: obiekt określony więcej niż raz; dodatki zignorowane
1 identity.obj: błąd LNK2019: nierozwiązany symbol zewnętrzny void __cdecl test::identity::view(void)(? view @ identity @ test @@ YAXXZ), do którego odwołuje się funkcja void __cdecl test::identity::identity(void)(? identity @ 0test @@ YAXXZ)
1 identity.obj: błąd LNK2019: nierozwiązany symbol zewnętrzny void __cdecl test::identity::make(void)(? make @ identity @ test @@ YAXXZ), do którego odwołuje się funkcja void __cdecl test::identity::identity(void)(? identity @ 0test @@ YAXXZ)
1 zakres.obj: błąd LNK2019: nierozwiązany symbol zewnętrzny void __cdecl test::range::is(void)(? is @ zakres @ test @@ YAXXZ), do którego odwołuje się funkcja void __cdecl test::range::range(void)(? zakres @ 0test @@ YAXXZ)

Błędy konsolidatora są zawsze trudne do debugowania ... ale były nierozwiązane odniesienia, więc sprawdziłem ... ale źródło jest dobrze sformułowane ... iw końcu dotarło do mnie:

Moja hierarchia folderów wygląda następująco:

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

tak samo jak hierarchia w rozwiązaniu (zawsze konfiguruję ją tak, aby naśladowała „prawdziwą” strukturę folderów).

Oraz wyjścia diagnostyczne:

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

Wraz z ostrzeżeniem, które mówi, że .objzostał przekazany dwukrotnie do konsolidatora i ten zostanie zignorowany.

Nie szukaj więcej: Visual porządnie spłaszczył moją hierarchię folderów i dlatego nie jest w stanie starannie skompilować źródła.

W tej chwili myślę po prostu o zmianie nazw plików, które powinno rozwiązać problem ...

... ale czy istnieje sposób, aby program Visual Studio NIE spłaszczył hierarchii plików?

Matthieu M.
źródło
3
Właśnie dostałem to samo, naprawdę denerwujące, że musimy to „naprawić” ręcznie. Cieszę się, że zapytałeś przede mną. :)
GManNickG
5
Z poszukiwań SO zrezygnowałem już dawno temu. :) Google.
GManNickG
39
Właśnie rozwiązałem podobny problem w VS 2013. Dla mnie problem polegał na tym, że plik nagłówkowy był kompilowany tak, jakby był samodzielnym plikiem C ++. W rezultacie otrzymałem dwa pliki obiektowe o tej samej nazwie: jeden dla foo.cpp i jeden dla foo.h. Rozwiązaniem było przejście do odpowiednich stron dla foo.h i zmiana właściwości konfiguracyjnych -> ogólne -> typ elementu na „nagłówek C / C ++” i wykonanie czystej kompilacji.
Adrian McCarthy
1
@AdrianMcCarthy Miałem ten sam problem i Twoja sugestia go rozwiązała.
trenki
1
Komentarz @AdrianMcCarthy jest rozwiązaniem. Musi wynikać z tego, że kreator Dodaj -> „Nowy element” automatycznie ustawia typ elementu pliku.
Dustin Biser

Odpowiedzi:

99

Chciałem tylko zamieścić coś, co uważam za odpowiedź, jeśli otworzysz właściwości dla całego projektu i zmienisz wartość poniżej C/C++ -> Output Files -> "Object File Name"na następującą:

$ (IntDir) /% (RelativeDir) /

Uważam, że w VS 2010 ujednoznaczni to wszystkie pliki obiektowe (uważam, że Windows w żadnych szalonych okolicznościach nie pozwoli ci mieć dwóch plików o tych samych nazwach w tym samym katalogu). Sprawdź również szczegóły tutaj .

M. Tibbits
źródło
Ach! To jest coś, czego będę musiał spróbować, gdy tylko wrócę do domu: D
Matthieu M.
7
Dodam tylko: wygląda na to, że% (RelativeDir) nie usuwaj żadnych ../ .. (nie tak, że powinno, ale nie ma też żadnej alternatywy) w swojej ścieżce, więc być może będziesz musiał dodać "fałszywy" katalog aby Twoje pliki były budowane w „poprawnym” katalogu. Przykład, mam $ (IntDir) / a / a /% (RelativeDir) / tylko po to, aby można było budować w $ (IntDir) z powodu dwóch ../ w ścieżce mojego .cpp (ścieżki są względne do $ (ProjectDir ), Myślę). Zwróć również uwagę, że% (RelativeDir) zawiera%, a $ (IntDir) zawiera $ (odpowiedź jest prawidłowa, wystarczy, że czytając szybko, można przeoczyć ten fakt).
n1ckp
2
Hm ... Zastanawiam się, dlaczego nie jest to ustawione domyślnie. Cóż, myślę, że po prostu dodam to do każdego projektu (prawie nic nie kompiluje się bez tej poprawki)
Navin
To zadziałało w Visual Studio 2012 Update 1, ale ponieważ załatałem aktualizację 4, VS nie chce już tworzyć pośrednich katalogów dla plików obiektów. :( (Zobacz stackoverflow.com/questions/30212698. )
Thomas Young
Jak to zrobić, gdy używam cl.exew CLI?
Nauka
145

Miałem podobny problem z ostrzeżeniem konsolidatora LNK4042: obiekt określony więcej niż raz; dodatki ignorowane . W moim przypadku program Visual Studio próbował skompilować zarówno pliki nagłówkowe, jak i pliki źródłowe o tej samej nazwie - MyClass.hi MyClass.cpp. Stało się tak, ponieważ zmieniłem nazwę .cpppliku na .hi program Visual Studio się pomylił. Zauważyłem problem, patrząc na dzienniki kompilatora w Debugkatalogu. Aby rozwiązać problem, po prostu usuń .hplik z projektu, a następnie dodaj go ponownie.

Andrey Levichev
źródło
2
dzięki za opublikowanie tego! stara procedura usuwania pliku i dodania go z powrotem załatwiła mi sprawę. Na tym naprawdę zaczynałam walić głową w ścianę.
Wes
3
Dzięki @AndreyLevichev - ta odpowiedź również rozwiązała problem dla mnie. W pliku projektu jest całkiem jasne, że plik .h znajduje się w grupie „ClCompile” zamiast w grupie „ClInclude”
jglouie
35
Możesz też kliknąć prawym przyciskiem myszy foo.hplik w eksploratorze rozwiązań i ustawić „Typ elementu” na „Nagłówek C / C ++” zamiast „Kompilator C / C ++”.
Thomas Eding
+1 za to. Nigdy nie znalazłbym swojego problemu, gdybym nie widział twojego komentarza.
crocboy
2
@Yaur - Albo jeszcze lepiej, zmień to na CLIncludewpis
TED
8

Kliknij prawym przyciskiem myszy plik .cpp w oknie Eksplorator rozwiązań, właściwości, C / C ++, pliki wyjściowe, ustawienie nazwy pliku obiektu. Domyślnie to $(IntDir)\właśnie powoduje spłaszczanie. Cały plik .obj trafi do $ (IntDir), katalogu „Debug” w konfiguracji debugowania.

Na przykład możesz zmienić to ustawienie $(IntDir)\is2.obj. Lub wybierz wszystkie pliki z jednej grupy (użyj Shift + kliknięcie) i zmień ustawienie na, powiedzmy,$(IntDir)\identity\

Możesz też zmienić nazwę pliku .cpp, aby pliki .obj nie nadpisywały się nawzajem. Posiadanie plików o dokładnie tej samej nazwie w dwóch katalogach jest trochę dziwne.

Lub możesz tworzyć wiele projektów, tworząc, powiedzmy, projekty .lib dla plików w tożsamości i zakresie. Często jest to wykonywane na przykład w projektach makefile. To jednak sprawia, że ​​zarządzanie ustawieniami kompilacji i łączenia jest bardziej kłopotliwe, chyba że używasz arkuszy właściwości projektu.

Hans Passant
źródło
Dzięki, już zmieniłem nazwy plików, ponieważ był to łatwiejszy sposób. Czy nie ma sposobu, aby poprosić Visual o zachowanie hierarchii, którą tak starannie zbudowałem w projekcie? Wiem, że posiadanie tej samej nazwy pliku dla kilku plików jest dziwne, ale wolę grupować elementy według podkatalogów, zamiast dodawać przedrostki do moich plików ... i niepotrzebne jest umieszczanie ich w podkatalogu i poprzedzanie ich nazwą podkatalogu!
Matthieu M.,
Możesz zmieniać ustawienia wielu plików jednocześnie. Przytrzymaj klawisz CTRL podczas klikania, aby je zaznaczyć. Używanie `$ (IntDir) \ $ (ParentName)` było problemem, kiedy ostatnio tego próbowałem.
Hans Passant
@Hans: myślę, że będę wtedy używać różnych nazw, nie jestem zadowolony z rozwiązania, ale ponieważ jest to tylko dla części testowej, myślę, że będę z tym żyć.
Matthieu M.,
Czy można ustawić $(IntDir)poszczególne pliki w arkuszu właściwości? Wiem, że możesz ustawić to dla całego projektu w arkuszu właściwości, ale nie wiem, czy możesz to ustawić na podstawie ścieżki kompilowanego pliku. (Domyślam się, że nie, ale jestem kompletnym noobem MSBuild)
James McNellis
@James, arkusze właściwości projektu mają zakres projektu, mają wpływ na wszystkie pliki.
Hans Passant
7

Kliknij prawym przyciskiem myszy plik nagłówkowy -> Właściwość -> ItemType (wybierz nagłówek C / C ++ ). Zrób to samo z plikiem Cpp, ale wybierz kompilator C / C ++ (to działa dla mnie)

Phạm Mạnh
źródło
To była ostatnia rzecz, jakiej bym szukał. Wielkie dzięki.
McLeary
4

Używam $ (IntDir) \% (Directory) \ w C / C ++ -> Output Files -> "Object File Name".

Csimbi
źródło
Chociaż zasadniczo taka sama jak zaakceptowana odpowiedź, użycie% (Directory) zamiast% (RelativeDir) jest nieco bezpieczniejsze. Jak zauważył n1ckp w komentarzach do zaakceptowanej odpowiedzi, w zależności od tego, jak dokładnie twój projekt jest skonstruowany na dysku, katalog względny może w końcu umieścić twoje pliki .obj w nieoczekiwanych miejscach.
user1593842
4

Alternatywnie do usunięcia i utworzenia nowego pliku możesz zmienić ustawienia kompilacji / dołączania.

Przejdź do pliku project.vcxproj , otwórz go w edytorze, znajdź linię podobną do html <ItemGroup>.

Powinien wyglądać mniej więcej tak:

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

i

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

Zakładając, że pliki implementacji to .cpp, a deklaracje to .hpp. Upewnij się, że wszystkie pliki implementacji są wymienione między pierwszą sekcją, jeśli masz więcej niż jedną, a także drugą sekcją dla wielu plików deklaracji.

user1222064
źródło
3

Miałem ten problem z stdafx.cpp. W jakiś sposób stdafx.cpp został zduplikowany, więc był drugi StdAfx.cpp (pamiętaj o innym przypadku).

Po usunięciu StdAfx.cpp wszystko działało dobrze!

Korzystanie z VS 2010.

Knasterbax
źródło
Wystąpił podobny problem, ale zamiast zduplikowania pliku był to ten sam plik wymieniony dwukrotnie w ClCompile ItemGroup.
Nicholas Betsworth
2

Kiedyś miałem w tym samym projekcie pliki .c i .cpp z tymi samymi nazwami plików . Pliki były w folderach wszędzie, a rozwiązania dostarczone przez innych stworzyły bałagan i folder piekło (w moim przypadku). Nawet kompilacje wydania nadpisałyby kompilacje debugowania !

Dobrym (nie idealnym) rozwiązaniem byłoby użycie $ (ParentName), ale z jakiegoś niezrozumiałego powodu zostało ono usunięte z późniejszych wersji programu Visual Studio (2015+).

Teraz z powodzeniem używam: $ (IntDir)% (Filename)% (Extension) .obj

co przynajmniej oddziela skompilowane pliki obiektów .c od .cpp .

Bill Kotsias
źródło