Проблема статического связывания VS2010 - PullRequest
10 голосов
/ 22 июня 2011

моя компания недавно обновилась с VS2005 до VS2010. У нас есть огромный проект, который использует много модулей, которые статически связаны в исполняемый файл. Но в VS2010 есть некоторые проблемы со связыванием.

Чтобы объяснить нашу проблему, мы создали минимальный пример проекта, который составлен так, как показано на этом рисунке:

minimal library example

Существует приложение, использующее одну функцию из библиотеки A. Библиотека A вызывает одну функцию из каждой библиотеки B и библиотеки C. Эти две библиотеки вызывают функцию, предоставляемую библиотекой D.

Для Exe 1 в Framework and References мы устанавливаем все на false за исключением Зависимости библиотеки ссылок , которая установлена ​​в true. Добавлена ​​только ссылка на библиотека A . Для каждой из библиотек все настройки имеют значение false. Библиотека A получает ссылки только на B и C , а также на эти две ссылки на получение только D . Библиотека D не имеет ссылок.

При сборке приложения оно работает без проблем. Приложение замечает, что библиотека A использует библиотеки B и C, которые используют библиотеку D, поэтому оно знает, что должно также связать эти библиотеки. LIBS без проблем связаны в exe.

Теперь мы что-то изменим, скажем, в библиотеке D . Просто небольшая разница, только одна буква. Теперь мы пытаемся снова построить приложение, оно замечает изменение и перекомпилирует библиотеку D , но: оно больше не связывается с ним. В результате возникают ошибки связывания в библиотеке B и C , поскольку они используют библиотеку D . Сначала нужно выполнить Перестроить , чтобы заставить завершить строительство и , а затем , все снова связано.

Это происходит как для минимального примера, так и для нашего основного проекта. Конечно, мы можем добавить каждую из библиотек в качестве дополнительной зависимости для exe, но было бы неплохо, если бы она работала так же, как и при первом создании проекта, и продолжала работать после изменений в коде. Мы заметили, что при установке Использовать входы зависимостей библиотеки до true , он снова работает, но затем он связывает не файлы * .lib, а файлы * .obj, который не является что мы хотим, конечно.

Кто-нибудь сталкивался с подобным опытом или у кого-нибудь есть решение этой проблемы? Это глючное поведение VS2010?

ТИА.

p.s .: Все библиотеки и исполняемые файлы являются родными C ++.


Редактировать: (Временное решение взято с этого сайта )

В файле %ProgramsFile%\MSBuild\Microsoft.cpp\v4.0\Microsoft.CPPBuild.Targets есть строка

<Target Name="GetResolvedLinkLibs" Returns="@(LibFullPath)" DependsOnTargets="$(CommonBuildOnlyTargets)">

Если вы измените эту строку на

<Target Name="GetResolvedLinkLibs" Returns="@(LibFullPath)" DependsOnTargets="$(CommonBuildOnlyTargets);ResolvedLinkLib">

ссылка работает правильно, и все необходимые библиотеки связаны неявно. Выходные данные компоновщика показывают не только lib_a.lib, но и все другие связанные цепочки libs, lib_b, lib_c, lib_d без добавления их вручную в качестве зависимостей в исполняемый файл.

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

Ответы [ 4 ]

0 голосов
/ 09 мая 2017

Мы снова начинаем видеть эту проблему после перехода на Visual Studio 2015 (а также в VS2017). Кажется, проблема существует только в следующей конфигурации:

Project (EXE)
  --> Static Library A (Reference)
    --> Static Library B (Specified in Linker->Additional Dependencies)
      --> Static Library C (Not in solution, specified in Linker->Additional Dependencies)

В решении есть несколько других проектов, использующих A и B. Когда что-то в проекте B или C изменяется, многие из этих проектов выдают предупреждения LNK4099. В нашем случае решение заключается в следующем:

Генерация кода> Выходные файлы> Имя файла базы данных программы: $ (TargetDir) $ (TargetName) .pdb

Библиотекарь> Общие> Выходной файл: $ (TargetDir) $ (TargetName) $ (TargetExt)

$ (TargetDir) использует абсолютный путь по сравнению со значением по умолчанию $ (OutDir) , которое в нашем случае было относительным. Кажется, что правильный путь теряется с несколькими уровнями косвенности.

Одна интересная вещь: если вы переключите количество потоков компиляции на 1, это не произойдет (может быть, какое-то состояние гонки в Visual Studio?).

0 голосов
/ 22 июня 2011

Вы довольно заблудились в этом диалоговом окне, если возитесь с Framework и References , это настройки, которые применяются только к управляемому коду.Термин «ссылка» относится только к сборкам .NET.Компоновщик не поддерживает хранение скомпилированного управляемого кода в .lib.Я буду работать исходя из того, что вы действительно меняете настройки компоновщика.Если вы вносите изменения в библиотеку D, вам также необходимо изменить ее заголовочный файл.Что само по себе будет достаточно для восстановления B и C, поскольку один или несколько файлов их исходного кода должны #include этот заголовок.

Единственное, что Зависимости библиотеки ссылок делает автоматически.lib зависимость, то же самое, что Linker + Input, настройка дополнительных зависимостей.Это, однако, требует от вас явно установить зависимости проекта.Щелкните правой кнопкой мыши проект B, выберите Project Dependencies и отметьте D. Повторите для C. Повторите для A и отметьте B и C. Повторите для EXE и отметьте A.

Это редко то, что вы хотите, это делаетБиблиотека D встроена в библиотеки B и C.И B и C встраиваются в A. Теперь EXE-файл зависит только от A. Он работает, но делает файлы .lib излишне громоздкими. И у вас есть проблема, которую вы описываете, если вы не устанавливаете зависимости проекта должным образом, перестройка D не приводит к перекомпоновке B и C.

Что вы должны сделатьне установлены зависимости между .libs, у них их нет.Каждый может быть построен без присутствия других .libs..Lib - это не что иное, как пакет файлов .obj.Все, что требуется, - это сделать все 4 .lib проектов зависимостями проекта EXE.Это гарантирует, что они созданы до того, как компоновщик попытается связать EXE.

0 голосов
/ 22 июня 2011

Я только знаю, что у меня были подобные ситуации из-за неправильного использования библиотек с с тем же именем , но с другой архитектурой . допустим, у меня есть Dll (назовем его mydll.dll) для x86, и я импортирую его в мой проект, и он будет работать. Если я сделаю то же самое с x64 dll (то же имя mydll.dll), это будет работать. Но если я хочу включить обе библиотеки, переименовать его в mydllx86.dll / mydllx64.dll запрещено. Теперь я могу включить обе библиотеки в Visual Studio . Но при его компиляции или перезапуске Visual Studio одна из обеих библиотек больше не будет доступна .

В этом случае, возможно, мне полезно взглянуть на библиотечную архитектуру и используемые пространства имен / имена Api.

Привет

...