Дивне "попередження LNK4042" Visual Studio 2010


81

Мене щойно побили (досить важко) по голові якесь нетривіальне попередження від Visual Studio 2010 (C ++).

Компіляція дала такий результат:

1 Налагодження \ is.obj: попередження LNK4042: об'єкт вказано більше одного разу; додаткові дані проігноровано
1 Налагодження \ make.obj: попередження LNK4042: об'єкт вказано більше одного разу; додаткові дані проігноровано
1 Налагодження \ view.obj: попередження LNK4042: об'єкт вказано більше одного разу; додатки проігноровано
1 identity.obj: помилка LNK2019: невирішений зовнішній символ void __cdecl test::identity::view(void)(? view @ identity @ test @@ YAXXZ), на який посилається функція void __cdecl test::identity::identity(void)(? identity @ 0test @@ YAXXZ)
1 identity.obj: помилка LNK2019: невирішений зовнішній символ void __cdecl test::identity::make(void)(? make @ identity @ test @@ YAXXZ), на який посилається функція void __cdecl test::identity::identity(void)(? identity @ 0test @@ YAXXZ)
1 range.obj: помилка LNK2019: невирішений зовнішній символ void __cdecl test::range::is(void)(? is @ range @ test @@ YAXXZ) посилається на функцію void __cdecl test::range::range(void)(? range @ 0test @@ YAXXZ)

Помилки Linker - це завжди біль для налагодження ... але були невирішені посилання, і тому я перевірив ... але джерело добре сформовано ... і нарешті це мене вразило:

Моя ієрархія папок виглядає так:

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 НЕ вирівняти ієрархію файлів?


3
Щойно отримав це саме, дуже дратує те, що нам доводиться "виправляти" це вручну. Радий, що ти запитав переді мною. :)
GManNickG

5
Я давно відмовився від пошуку SO. :) Google.
GManNickG

38
Я щойно вирішив подібну проблему у VS 2013. Для мене проблема полягала в тому, що файл заголовка компілювався так, ніби це був автономний файл C ++. Тож у мене вийшло два об’єктні файли з однаковим ім’ям: один для foo.cpp та другий для foo.h. Рішенням було перейти на відповідні сторінки для foo.h і змінити Властивості конфігурації -> Загальне -> Тип елемента на "Заголовок C / C ++" і виконати чисту збірку.
Адріан Маккарті

1
@AdrianMcCarthy У мене була та сама проблема, і ваша пропозиція вирішила її.
тренки

1
Коментар @AdrianMcCarthy - це рішення. Має бути завдяки майстру Add -> "New Item", який автоматично встановлює тип елемента файлу.
Дастін Бісер,

Відповіді:


99

Просто хотів перекреслити публікацію, на яку, на мою думку, буде відповідь, якщо ви відкриєте властивості для всього проекту, а значення зміни C/C++ -> Output Files -> "Object File Name"буде таким:

$ (IntDir) /% (RelativeDir) /

В рамках VS 2010, я вважаю, це призведе до неоднозначності всіх об’єктних файлів (оскільки я вважаю, що Windows за жодних обставин не дозволить вам мати два файли з однаковими іменами в одному каталозі). Будь ласка, також ознайомтеся з деталями тут .


Ах! Зараз це те, що мені потрібно буде спробувати, як тільки я повернусь додому: D
Matthieu M.

7
Просто додати: здається,% (RelativeDir) не забирає жодного ../ .. (не те, що він повинен, але, здається, не має жодної альтернативи) у вашому шляху, тому вам, можливо, доведеться додати "фальшивий" каталог щоб ваші файли були вбудовані в "правильний" каталог. Приклад, у мене $ (IntDir) / a / a /% (RelativeDir) / просто для того, щоб він міг вбудувати в $ (IntDir) через два ../ на шляху до мого .cpp (Шляхи відносно $ (ProjectDir) ), Я думаю). Також зауважте, що% (RelativeDir) - з%, а $ (IntDir) - з $ (відповідь правильна, просто, швидко читаючи, цей факт можна пропустити).
n1ckp

2
Хм ... Цікаво, чому це не встановлено за замовчуванням. Ну, я гадаю, я просто додам це до кожного проекту (навряд чи щось компілюється без цього виправлення)
Navin

Це працювало в Visual Studio 2012 оновлення 1, але оскільки я виправив оновлення 4, VS, схоже, більше не хоче створювати проміжні каталоги для об’єктних файлів. :( (Див. Stackoverflow.com/questions/30212698. )
Томас Янг

Як це робити, коли я використовую cl.exeв CLI?
Навчання

145

У мене була подібна проблема з попередженням компонувальника LNK4042: об’єкт зазначено більше одного разу; статисти ігноруються . У моєму випадку Visual Studio намагався скомпілювати і заголовки, і вихідні файли з однаковим ім'ям - MyClass.hі MyClass.cpp. Це сталося тому, що я перейменував .cppфайл на, .hі Visual Studio заплутався. Я помітив проблему, переглянувши журнали компілятора в Debugкаталозі. Щоб вирішити проблему, просто видаліть .hфайл із проекту, а потім додайте його знову.


2
дякую за розміщення цього! старий видалити файл і додати його назад рутина зробила трюк і для мене. На цьому я справді починав битися головою об стіну.
Вес,

3
Дякую @AndreyLevichev - ця відповідь вирішила проблему і для мене. У файлі проекту досить ясно, що файл .h знаходиться у групі "ClCompile" замість групи "ClInclude"
jglouie

35
Або ви можете клацнути правою кнопкою миші на foo.hфайлі у вашому провіднику рішень і встановити для "Тип елемента" значення "Заголовок C / C ++", а не "Компілятор C / C ++".
Томас Едінг,

+1 за це. Я б ніколи не знайшов своєї проблеми, якби не бачив вашого коментаря.
крокбой

2
@Yaur - Або ще краще, змінити його на CLIncludeзапис
TED

8

Клацніть правою кнопкою миші файл .cpp у вікні Solution Explorer, Властивості, C / C ++, Вихідні файли, Ім'я файлу об’єкта. За замовчуванням це $(IntDir)\те, що робить згладжування. Весь файл .obj потрапить до $ (IntDir), каталогу "Налагодження" у конфігурації налагодження.

Скажімо, ви можете змінити налаштування $(IntDir)\is2.obj. Або виберіть усі файли з однієї групи (використовуйте Shift + Click) і змініть параметр на, скажімо,$(IntDir)\identity\

Або ви можете змінити ім'я файлу .cpp, щоб файли .obj не перезаписували один одного. Наявність файлів із точно однаковою назвою у двох каталогах трохи дивно.

Або ви можете створити кілька проектів, створивши, скажімо, проекти .lib для файлів, що мають ідентичність та діапазон. Наприклад, зазвичай це робиться в проектах makefile. Однак це робить управління налаштуваннями компіляції та посилання більш клопотною, якщо ви не використовуєте таблиці властивостей проекту.


Дякую, я вже перейменував файли, оскільки це був простіший шлях. Чи не можна попросити Visual зберегти ієрархію, яку я так ретельно побудував у Проекті? Я знаю, що однакові назви файлів для декількох файлів дивні, але я волію кластеризувати речі за підкаталогом, а не за префіксом моїх файлів ... і зайвим є як розміщення їх у підкаталозі, так і префікс до імені підкаталогу!
Matthieu M.

Ви можете змінити параметри для кількох файлів одночасно. Утримуючи клавішу CTRL, клацніть, щоб вибрати їх. Використання `$ (IntDir) \ $ (ParentName)` було проблемою, коли я востаннє це намагався.
Ганс Пасант,

@Hans: гадаю, тоді я продовжуватиму використовувати різні імена, я не настільки задоволений рішенням, але оскільки це стосується лише частини модульного тестування, я думаю, я буду жити з ним.
Matthieu M.

Чи можна встановити $(IntDir)окремий файл у аркуші властивостей? Я знаю, що ви можете встановити його для всього проекту в аркуші властивостей, але я не знаю, чи можете ви встановити його на основі шляху до компільованого файлу. (Моє припущення - ні, але я повний MSBuild noob)
Джеймс МакНеліс

@James, аркуші властивостей проекту мають обсяг проекту, вони впливають на всі файли.
Ганс Пассант,

7

Клацніть правою кнопкою миші на файлі заголовка -> Властивість -> Тип елемента (виберіть Заголовок C / C ++ ). Зробіть те саме з файлом Cpp, але виберіть компілятор C / C ++ (це працює для мене)


Це було останнє, що я міг би подумати шукати. Дуже дякую.
McLeary

4

Я використовую $ (IntDir) \% (Directory) \ під C / C ++ -> Вихідні файли -> "Ім'я файлу об'єкта".


Хоча по суті те саме, що прийнята відповідь, використання% (Каталог) замість% (RelativeDir) є трохи безпечнішим. Як зазначає n1ckp у коментарях до прийнятих відповідей, залежно від того, як саме ваш проект структурований на диску, відносний каталог може в кінцевому підсумку розмістити ваші .obj-файли в несподіваних місцях.
user1593842

4

Крім видалення та створення нового файлу ви можете змінити налаштування компіляції / включення.

Перейдіть до свого файлу project.vcxproj , відкрийте його за допомогою редактора, знайдіть рядок, подібний до html <ItemGroup>.

Це має виглядати приблизно так:

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

і

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

Припускаючи, що ваші файли реалізації - .cpp, а ваші декларації - .hpp. Переконайтеся, що всі ваші файли реалізації перелічені між першим розділом, якщо у вас більше одного, а також для другого розділу для декількох файлів декларацій.


3

У мене була ця проблема зі stdafx.cpp. Якось stdafx.cpp дублюється, тож був другий StdAfx.cpp (майте на увазі інший випадок).

Після того, як я видалив StdAfx.cpp, все працювало нормально!

Використовуючи VS 2010.


Виникла подібна проблема, але замість того, щоб файл дублювався, це був той самий файл, перерахований двічі у групі елементів ClCompile.
Ніколас Бетсворт,

2

Раніше я мав у одному проекті файли .c та .cpp з однаковими іменами файлів . Файли були скрізь у папках, і рішення, надані іншими, створювали безлад і папку (у моєму випадку). Навіть збірки Release замінять збірки налагодження !

Хорошим (не ідеальним) рішенням було б використання $ (ParentName), але з якихось причин невідомо, його було видалено з пізніших версій Visual Studio (2015+).

Зараз я успішно використовую: $ (IntDir)% (Filename)% (Extension) .obj

який принаймні відокремлює вбудовані файли .c від .cpp .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.