Связывать библиотеки с зависимостями в Visual C ++ без получения LNK4006 - PullRequest
20 голосов
/ 19 февраля 2009

У меня есть набор статически скомпилированных библиотек с довольно глубокими зависимостями между библиотеками. Например, исполняемый файл X использует библиотеки A и B, A использует библиотеку C, а B использует библиотеки C и D:

X -> A
     A -> C
X -> B
     B -> C
     B -> D

Когда я связываю X с A и B, я не хочу получать ошибки, если C и D также не были добавлены в список библиотек - тот факт, что A и B используют эти библиотеки внутри, является деталью реализации, которую X не нужно знать о. Кроме того, когда новые зависимости добавляются в любом месте дерева зависимостей, файл проекта любой программы, использующей A или B, должен быть перенастроен. Для дерева глубоких зависимостей список необходимых библиотек может стать очень длинным и сложным для обслуживания.

Итак, я использую настройку «Дополнительные зависимости» раздела Библиотекаря в проекте A, добавляя C.lib. И в том же разделе проекта B я добавляю C.lib и D.lib. В результате библиотекарь связывает C.lib с A.lib, а C.lib и D.lib с B.lib.

Однако, когда я связываю X, и A.lib, и B.lib содержат свою собственную копию C.lib. Это приводит к тоннам предупреждений в соответствии с

A.lib (c.obj): предупреждение LNK4006 «символ» (_symbol) уже определен в B.lib (c.obj); второе определение игнорируется.

Как я могу сделать это без предупреждения? Есть ли способ просто отключить предупреждение или есть лучший способ?

РЕДАКТИРОВАТЬ : я видел более одного ответа, предполагающего, что из-за отсутствия лучшей альтернативы я просто отключаю предупреждение. Ну, это часть проблемы: я даже не знаю, как это отключить!

Ответы [ 9 ]

11 голосов
/ 27 февраля 2009

Насколько я знаю, вы не можете отключить предупреждения компоновщика. Однако некоторые из них можно игнорировать, используя параметр командной строки, например, linker. / Игнорировать: 4006

Поместите его в свойства вашего проекта в настройке компоновщика-> командной строки (не помню точное местоположение).

Также прочитайте это:

Ссылка / игнорировать

MSDN Forum - скрытие предупреждений LNK

Wacek

8 голосов
/ 26 февраля 2009

Обновление Если вы можете собрать все вовлеченные проекты в одном решении, попробуйте следующее:

  • Поместите весь проект в одну слн.
  • Удалите все ссылки на статические библиотеки из свойств компоновщика или библиотеки.
  • В контекстном меню для каждого проекта в обозревателе решений имеется опция «Зависимости проекта ...». Используйте его, чтобы определить зависимости между проектом.

Это должно работать. Это не отменяет ничего, что я говорил ранее, базовая модель построения программ на C / C ++ остается прежней. VS (по крайней мере 2005 и новее) достаточно умен, чтобы добавить все необходимые статические библиотеки в командную строку компоновщика. Вы можете увидеть это в свойствах проекта.

Конечно, этот метод не поможет, если вам нужно использовать уже скомпилированные статические библиотеки. Затем вам нужно добавить их все в exe или dll проект, который прямо или косвенно их использует.


Не думаю, что с этим можно что-то сделать. Вы должны удалить ссылки на другие статические библиотеки из проектов статических библиотек и добавить все необходимые проекты статических библиотек в качестве зависимостей проектов exe или dll. Вам просто придется смириться с тем, что любой проект, включающий A.lib или B.lib, также должен включать C.lib.

В качестве альтернативы вы можете превратить свои библиотеки в dll, которые обеспечивают более богатую модель.

Статически скомпилированные библиотеки просто не являются реальными библиотеками с информацией о зависимостях и т. Д., Как библиотеки DLL. Посмотрите, как при их создании вам не нужно предоставлять библиотеки, от которых они зависят? Заголовки - это все, что нужно. Увидеть? Вы даже не можете сказать, что статические библиотеки зависят от чего-либо.

Статическая библиотека - это просто архив скомпилированного и еще не связанного объектного кода. Это не единое целое. Каждый объектный файл компилируется отдельно и остается отдельной сущностью внутри библиотеки. Связывание происходит при сборке exe или dll. Вот когда вам нужно предоставить весь объектный код. Вот когда происходит разрешение всех символов и зависимостей.

Если вы добавите другие статические библиотеки в зависимости от статических библиотек, библиотекарь просто скопирует весь код вместе. Затем, при сборке exe, компоновщик выдаст вам множество предупреждений о повторяющихся символах. Возможно, вы сможете заблокировать эти предупреждения (я не знаю, как), но будьте осторожны. Это может скрывать реальные проблемы, такие как настоящие дубликаты символов с разными определениями. И если у вас есть статические данные, определенные в библиотеках, они, вероятно, все равно не будут работать.

3 голосов
/ 27 февраля 2009

Microsoft (R) инкрементный компоновщик версии 9.00.x ( link.exe ) знает аргумент / игнорировать: 4006

3 голосов
/ 24 февраля 2009

Вы можете создать одну библиотеку, которая содержит A, B, C & D и затем связать X с этим.

Поскольку это библиотека, в конечный исполняемый файл будут включены только те объектные модули, на которые действительно есть ссылки.

1 голос
/ 20 июля 2011

Обратите внимание, что одним из способов получения этого предупреждения является определение функции-члена в заголовке без встроенного оператора:

// Foo.h

class Foo
{
    void someFunction();
};

void Foo:someFunction() // Warning!  - should be "inline void Foo::someFunction()"
{
    // do stuff
}
0 голосов
/ 15 августа 2010

Бедный flodin кажется разочарованным тем, что никто не объяснит, как отключить предупреждения компоновщика. Ну, у меня была похожая проблема, и в течение многих лет я просто жил с фактом, что несколько сотен предупреждений были показаны. Однако теперь, благодаря информации из Link / ignore , я понял, как отключить предупреждения компоновщика.

Я использую Visual Studio 2008. В Project -> Настройки -> Свойства конфигурации -> Библиотекарь -> Командная строка -> Дополнительные параметры я добавил «/ ignore: 4006» (без кавычек). Теперь мои предупреждения исчезли!

0 голосов
/ 26 февраля 2009

Это может не исправить ошибку ссылки, но может помочь с проблемой дерева зависимостей.

Что я делаю, это просто использую #pragma, чтобы включить библиотеку в файл .cpp, который нуждается в этом. Например:

#pragma comment(lib:"wsock32") 

Как я уже сказал, я не уверен, что он сохранит символы в этом объектном файле, я должен был бы создать пример, чтобы попробовать его.

0 голосов
/ 19 февраля 2009

Я думаю, что лучшим способом действий здесь будет игнорирование / отключение предупреждений компоновщика (LNK4006), поскольку C.lib должен быть частью как A.Lib, так и B.lib, и A.Lib не нужно знать, что Сам B.lib использует C.Lib.

0 голосов
/ 19 февраля 2009

Проблема в том, что вы не локализуете символы библиотеки C. Таким образом, у вас есть нарушение ODR, когда вы связываете в A и B. Вы должны иметь способ сделать их частными. По умолчанию все символы экспортируются. Один из способов сделать это - иметь специальный файл определения компоновщика для A и B, в котором явно указано, какие файлы необходимо экспортировать.

[1] ODR = Одно правило определения.

...