“Cảnh báo LNK4042” kỳ lạ của Visual Studio 2010


81

Tôi vừa bị đánh (khá khó) bởi một số cảnh báo không nhỏ từ Visual Studio 2010 (C ++).

Việc biên dịch cho kết quả sau:

1 Gỡ lỗi \ is.obj: cảnh báo LNK4042: đối tượng được chỉ định nhiều lần; tính năng bổ sung bị bỏ qua
1 Gỡ lỗi \ make.obj: cảnh báo LNK4042: đối tượng được chỉ định nhiều lần; tính năng bổ sung bị bỏ qua
1 Gỡ lỗi \ view.obj: cảnh báo LNK4042: đối tượng được chỉ định nhiều lần; tính năng bổ sung đã bỏ qua
1 danh tính.obj: lỗi LNK2019: biểu tượng bên ngoài chưa được giải quyết void __cdecl test::identity::view(void)(? view @ Identity @ test @@ YAXXZ) được tham chiếu trong hàm void __cdecl test::identity::identity(void)(? Identity @ 0test @@ YAXXZ)
1 danh tính.obj: lỗi LNK2019: biểu tượng bên ngoài chưa được giải quyết void __cdecl test::identity::make(void)(? make @ Identity @ test @@ YAXXZ) được tham chiếu trong hàm void __cdecl test::identity::identity(void)(? Identity @ 0test @@ YAXXZ)
1 range.obj: lỗi LNK2019: biểu tượng bên ngoài chưa được giải quyết void __cdecl test::range::is(void)(? is @ range @ test @@ YAXXZ) được tham chiếu trong hàm void __cdecl test::range::range(void)(? range @ 0test @@ YAXXZ)

Lỗi trình liên kết luôn là một vấn đề khó khăn để gỡ lỗi ... nhưng có những tài liệu tham khảo chưa được giải quyết và vì vậy tôi đã kiểm tra ... nhưng nguồn được định dạng tốt ... và cuối cùng nó đã xảy ra với tôi:

Hệ thống phân cấp thư mục của tôi trông giống như sau:

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

và hệ thống phân cấp trong Giải pháp cũng vậy (tôi luôn thiết lập nó để nó bắt chước cấu trúc thư mục "thực").

Và kết quả chẩn đoán:

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

Cùng với một cảnh báo cho biết rằng liên kết .objđã được chuyển hai lần đến trình liên kết và một sẽ bị bỏ qua.

Không cần tìm kiếm nữa: Visual đã làm phẳng hệ thống phân cấp thư mục của tôi một cách gọn gàng, và do đó không thể biên dịch nguồn gọn gàng.

Hiện tại, tôi chỉ đơn giản là nghĩ đến việc đổi tên các tệp, điều đó sẽ giải quyết vấn đề ...

... nhưng có cách nào để Visual Studio KHÔNG làm phẳng hệ thống phân cấp tệp không?


3
Chỉ có một điều tương tự, thực sự khó chịu mà chúng tôi phải "sửa chữa" nó một cách thủ công. Rất vui vì bạn đã hỏi trước tôi. :)
GManNickG

5
Tôi đã từ bỏ việc tìm kiếm SO một thời gian dài trước đây. :) Google.
GManNickG

38
Tôi vừa giải quyết một vấn đề tương tự trong VS 2013. Đối với tôi, vấn đề là tệp tiêu đề đang được biên dịch như thể nó là một tệp C ++ độc lập. Vì vậy, tôi đã kết thúc với hai tệp đối tượng có cùng tên: một cho foo.cpp và một cho foo.h. Giải pháp là truy cập các trang thích hợp cho foo.h và thay đổi Thuộc tính cấu hình -> Chung -> Loại mục thành "tiêu đề C / C ++" và thực hiện một bản dựng sạch.
Adrian McCarthy

1
@AdrianMcCarthy Tôi gặp vấn đề tương tự và đề xuất của bạn đã giải quyết được nó.
trenki

1
Bình luận của @AdrianMcCarthy là giải pháp. Phải do Trình hướng dẫn Thêm -> "Mục mới" tự động thiết lập loại mục của tệp.
Dustin Biser,

Câu trả lời:


99

Tôi chỉ muốn đăng chéo những gì tôi tin là câu trả lời, nếu bạn mở thuộc tính cho toàn bộ dự án và thay đổi giá trị dưới C/C++ -> Output Files -> "Object File Name"thành như sau:

$ (IntDir) /% (RelativeDir) /

Trong VS 2010, tôi tin rằng điều này sẽ phân biệt tất cả các tệp đối tượng (vì tôi tin rằng cửa sổ sẽ không cho phép bạn trong bất kỳ trường hợp điên rồ nào có hai tệp có cùng tên trong cùng một thư mục). Vui lòng kiểm tra chi tiết tại đây .


Ah! Bây giờ của một cái gì đó tôi sẽ cần phải thử ngay sau khi tôi được trở về nhà: D
Matthieu M.

7
Chỉ cần thêm: có vẻ như% (RelativeDir) không loại bỏ bất kỳ ../ .. (không phải vậy nhưng dường như không có bất kỳ thay thế nào) trong đường dẫn của bạn, vì vậy bạn có thể phải thêm thư mục "giả mạo" để tạo tệp của bạn trong thư mục "đúng". Đơn giản, tôi có $ (IntDir) / a / a /% (RelativeDir) / để nó có thể xây dựng trong $ (IntDir) vì hai ../ trong đường dẫn .cpp của tôi (Đường dẫn liên quan đến $ (ProjectDir ), Tôi nghĩ). Cũng lưu ý rằng% (RelativeDir) là với% và $ (IntDir) là với $ (câu trả lời là đúng, chỉ cần đọc nhanh, thực tế đó có thể bị bỏ sót).
n1ckp

2
Hm ... Tôi tự hỏi tại sao điều này không được đặt theo mặc định. Chà, tôi đoán tôi sẽ chỉ thêm cái này vào mọi dự án (hầu như không có thứ gì được biên dịch mà không có bản sửa lỗi này)
Navin

Điều này đã hoạt động trong bản cập nhật 1 của Visual Studio 2012, nhưng vì tôi đã vá lỗi cho bản cập nhật 4, VS dường như không muốn tạo thư mục trung gian cho tệp đối tượng nữa. :( (Xem stackoverflow.com/questions/30212698. )
Thomas Young

Làm thế nào để làm khi tôi sử dụng cl.exetrong CLI?
Học

145

Tôi đã gặp sự cố tương tự với cảnh báo trình liên kết LNK4042: đối tượng được chỉ định nhiều lần; tính năng bổ sung bị bỏ qua . Trong trường hợp của tôi, Visual Studio đang cố gắng biên dịch cả tệp tiêu đề và tệp nguồn có cùng tên - MyClass.hMyClass.cpp. Nó xảy ra vì tôi đã đổi tên .cpptệp thành .hvà Visual Studio bị nhầm lẫn. Tôi nhận thấy vấn đề bằng cách xem nhật ký trình biên dịch trong Debugthư mục. Để giải quyết, chỉ cần xóa .htệp khỏi dự án sau đó thêm lại.


2
cảm ơn vì đã đăng bài này! quy trình xóa tệp cũ và thêm nó trở lại cũng đã thực hiện một mẹo nhỏ đối với tôi. Tôi thực sự bắt đầu đập đầu vào tường vì cái này.
Wes

3
Cảm ơn @AndreyLevichev - câu trả lời này cũng đã khắc phục sự cố cho tôi. Trong tệp dự án, khá rõ ràng rằng tệp .h nằm trong nhóm "ClCompile" thay vì nhóm "ClInclude"
jglouie

35
Hoặc bạn có thể nhấp chuột phải vào foo.htệp trong trình khám phá giải pháp của mình và đặt "Loại mục" thành "tiêu đề C / C ++" chứ không phải "trình biên dịch C / C ++".
Thomas Eding

+1 cho điều này. Tôi sẽ không bao giờ tìm thấy vấn đề của mình nếu tôi không nhìn thấy bình luận của bạn.
crocboy

2
@Yaur - Hoặc tốt hơn, hãy thay đổi nó thành một CLIncludemục nhập
TED

8

Bấm chuột phải vào tệp .cpp trong cửa sổ Giải pháp Explorer, Thuộc tính, C / C ++, Tệp đầu ra, Thiết đặt tên tệp đối tượng. Mặc định là $(IntDir)\, đó là những gì đang làm phẳng. Tất cả tệp .obj sẽ đi vào $ (IntDir), thư mục "Gỡ lỗi" trong cấu hình gỡ lỗi.

Bạn có thể thay đổi cài đặt, nói $(IntDir)\is2.obj. Hoặc chọn tất cả các tệp từ một nhóm (sử dụng Shift + Click) và thay đổi cài đặt thành, chẳng hạn$(IntDir)\identity\

Hoặc bạn có thể thay đổi tên tệp .cpp để các tệp .obj không ghi đè lẫn nhau. Việc có các tệp có cùng tên trong hai thư mục là một điều hơi kỳ lạ.

Hoặc bạn có thể tạo nhiều dự án, tạo dự án .lib cho các tệp trong danh tính và phạm vi. Thường được thực hiện trong các dự án makefile chẳng hạn. Tuy nhiên, điều đó làm cho việc quản lý cài đặt biên dịch và liên kết trở nên phức tạp hơn trừ khi bạn sử dụng các trang thuộc tính của dự án.


Cảm ơn, tôi đã đổi tên tệp vì đó là cách dễ dàng hơn. Không có cách nào để yêu cầu Visual duy trì hệ thống phân cấp mà tôi đã xây dựng rất cẩn thận trong Dự án? Tôi biết việc có cùng một tên tệp cho một số tệp là điều kỳ lạ, nhưng tôi thích phân cụm mọi thứ theo thư mục con hơn là đặt tiền tố vào tệp của mình ... và việc xác thực chúng trong một thư mục con và đặt tiền tố chúng bằng tên thư mục con là không cần thiết!
Matthieu M.

Bạn có thể thay đổi cài đặt cho nhiều tệp cùng một lúc. Giữ phím CTRL trong khi bạn nhấp để chọn chúng. Sử dụng `$ (IntDir) \ $ (ParentName) 'đã gặp sự cố vào lần cuối tôi thử điều đó.
Hans Passant

@Hans: đoán rằng tôi sẽ tiếp tục sử dụng các tên khác nhau, tôi không hài lòng với giải pháp này, nhưng vì nó chỉ dành cho phần kiểm tra đơn vị nên tôi đoán tôi sẽ sống với nó.
Matthieu M.

Có thể đặt $(IntDir)mỗi tệp trong một trang thuộc tính không? Tôi biết bạn có thể đặt nó cho toàn bộ dự án trong một trang thuộc tính, nhưng tôi không biết liệu bạn có thể đặt nó dựa trên đường dẫn của tệp đang được biên dịch hay không. (Dự đoán của tôi là không, nhưng tôi là một noob hoàn chỉnh của MSBuild)
James McNellis 12/09/10

@James, các trang thuộc tính của dự án có phạm vi dự án, chúng ảnh hưởng đến tất cả các tệp.
Hans Passant

6

Nhấp chuột phải vào tệp tiêu đề -> Thuộc tính -> Loại mục (chọn Tiêu đề C / C ++ ). Làm tương tự với tệp Cpp nhưng chọn Trình biên dịch C / C ++ (nó phù hợp với tôi)


Đây là điều cuối cùng tôi nghĩ đến việc tìm kiếm. Cảm ơn nhiều.
McLeary

4

Tôi sử dụng $ (IntDir) \% (Thư mục) \ trong C / C ++ -> Tệp đầu ra -> "Tên tệp đối tượng".


Trong khi về cơ bản giống với câu trả lời được chấp nhận, việc sử dụng% (Directory) thay vì% (RelativeDir) an toàn hơn một chút. Như đã lưu ý bởi n1ckp trong các nhận xét câu trả lời được chấp nhận, tùy thuộc vào cách cấu trúc chính xác dự án của bạn trên đĩa, dir tương đối có thể đặt các tệp .obj của bạn ở những vị trí không mong muốn.
user1593842

3

Tôi gặp sự cố này với stdafx.cpp. Bằng cách nào đó stdafx.cpp đã bị trùng lặp, vì vậy có một StdAfx.cpp thứ hai (lưu ý trường hợp khác).

Sau khi tôi gỡ bỏ StdAfx.cpp, mọi thứ đều hoạt động tốt!

Sử dụng VS 2010.


Đã gặp sự cố tương tự, nhưng thay vì tệp bị sao chép, nó là cùng một tệp được liệt kê hai lần trong ClCompile ItemGroup.
Nicholas Betsworth

3

Ngoài ra, để xóa và tạo một tệp mới, bạn có thể thay đổi cài đặt biên dịch / bao gồm.

Truy cập tệp project.vcxproj của bạn , mở nó bằng trình chỉnh sửa, tìm dòng html like <ItemGroup>.

Nó sẽ trông giống như sau:

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

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

Giả sử các tệp triển khai của bạn là .cpp và các khai báo của bạn là .hpp. Đảm bảo rằng tất cả các tệp triển khai của bạn được liệt kê giữa phần đầu tiên nếu bạn có nhiều tệp và tương tự như vậy cho phần thứ hai cho nhiều tệp khai báo.


2

Tôi đã từng có trong cùng một dự án các tệp .c.cppcùng tên tệp . Các tệp nằm trong các thư mục ở khắp nơi và các giải pháp do người khác cung cấp đã tạo ra một mớ hỗn độn và thư mục địa ngục (trong trường hợp của tôi). Ngay cả các bản dựng Phát hành cũng sẽ ghi đè các bản dựng Gỡ lỗi !

Một giải pháp tốt (không hoàn hảo) sẽ là sử dụng $ (ParentName), nhưng vì một số lý do ngoài tầm hiểu biết của bất kỳ ai, nó đã bị xóa khỏi các phiên bản sau của Visual Studio (2015+).

Những gì tôi sử dụng thành công bây giờ là: $ (IntDir)% (Tên tệp)% (Phần mở rộng) .obj

mà ít nhất tách các tệp đối tượng được xây dựng .c khỏi .cpp .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.