Подтвердить что ты не робот

Является ли "Копировать локальное" транзитивным для ссылок на проект?

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

Первый, я прочитал Что такое наилучшая практика для "Копировать локальную" и с ссылками на проекты? (также this), и мне все равно придется попробовать это, но получение общей обратной связи по этому поводу представляется необходимым, поскольку docs на этом материале ужасны, и я только на VS2010 и, возможно, они что-то изменили в более новых версиях, которые будут приятно знать.

Второй, меня интересуют только ссылки проекта по этому вопросу, так как я читал, что сборки из GAC обрабатываются по-разному, и GAC не имеет отношения к моей проблеме.

Третий, прочитав предложенный обман, но тем более приятный ответ здесь by @Albireo, также показалось бы, что это важно различать зависимости файлов, где зависимость ссылается на файл сборки dll и зависимые от проекта зависимости (то есть, о чем я спрашиваю), где зависимость ссылается на проект и неявно выходной файл этого проекта.

Во всяком случае, здесь ситуация, несколько своеобразная, я думаю, но все же:

  • 2 исполняемых проекта С#
  • n Проекты сборки cll dll
  • 2 исполняемых файла имеют разные выходные каталоги, поскольку они будут разворачиваться отдельно и таким образом они также будут раздельными на машине разработчика.
  • 2 исполняемых файла имеют зависимости от некоторых сборок DLL (которые могут зависеть друг от друга)
  • Существует три выходных каталога:
    • /x1 для исполняемого проекта 1
    • /x2 для исполняемого проекта 2
    • /lib для всех сборок dll

Все сборки DLL имеют Copy Local для для своих ссылок на проект, так как все они строятся в одном каталоге.

2 исполняемые проекты установили Copy Local в true для всех ссылок на проект сборки DLL, ссылки на которые они ссылаются напрямую, так что библиотеки DLL будут скопированы в /x1 /x2 соответственно.

Вопрос теперь есть. к DLL, которые напрямую не ссылаются на исполняемый проект, но только транзитно через ссылочную сборку: Собираются ли сборки, которые только ссылаются транзитно через другую сборку, копируются в выходную папку исполняемого файла, когда "Скопировать локальный" установлено на true на первой сборке?

Пример:

  • x1.csproj (например, Output = x1/one.exe)
    • Ссылка: dlA.csproj (например, Output = lib/a.dll) с Copy Local = *true*
    • (без ссылки на b.dll)
  • dlA.csproj (например, Output = lib/a.dll)
    • Ссылка: dlB.csproj (например, Output = lib/b.dll) с Copy Local = **false**
    • (нет прямой ссылки на c.dll)
  • dlC.csproj (например, Output = lib/c.dll)
    • (никаких дополнительных ссылок)

Таким образом, мы имеем логическую зависимость от one.exe -> a.dll -> b.dll -> c.dll, где только a.dll, очевидно, копируется в выходной каталог one.exe. Будут ли скопированы и другие две библиотеки DLL в выходной каталог? Является ли это документированным где-нибудь?


И, да, я попробовал. И, да, кажется, это работает, но я еще не слишком сильно это сделал, и в любом случае может быть что-то еще, что я, возможно, пропустил. (И также есть вопрос по любым официальным документам.)

4b9b3361

Ответ 1

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

Не совсем, нет.

MSBuild все равно, ссылается ли ссылка на другой проект в решении или на DLL.

Если ProjectA зависит от ProjectB для сборки ProjectA ProjectB должно быть уже построено (и обновлено), MSBuild затем вытащит свою DLL (а не его код С#) и свяжет ее с ProjectA.

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

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

Будут ли скопированы и другие две библиотеки DLL в выходной каталог?

Если какой-либо элемент из зависимости используется непосредственно из проекта, на который ссылается сборка, эта ссылка будет скопирована.

Примером может служить этот макет решения:

  • MySolution
    • MySolution.ConsoleApplication
    • MySolution.FirstDependency
    • MySolution.SecondDependency
    • MySolution.ThirdDependency
    • MySolution.FourthDependency

С этой цепочкой зависимостей:

  • MySolution.ConsoleApplication
    • MySolution.FirstDependency
      • MySolution.SecondDependency
        • MySolution.ThirdDependency
        • MySolution.FourthDependency

Если вы создадите это решение, вы заметите, что в каталоге вывода MySolution.ConsoleApplication будут DLL для MySolution.FirstDependency, MySolution.SecondDependency и MySolution.ThirdDependency, но нет библиотеки DLL для MySolution.FourthDependency.

Почему так? Когда MSBuild создает MySolution.SecondDependency, он замечает, что существует зависимость, объявленная в MySolution.FourthDependency, но поскольку она не может найти никакого использования какого-либо элемента из MySolution.FourthDependency в коде MySolution.SecondDependency, он решает выполнить некоторую "оптимизацию" и omits MySolution.FourthDependency сборка с выхода.

Эта же проблема укусила меня в прошлом, когда я добавил через NuGet AutoMapper "глубокую зависимость": добавление AutoMapper добавляет две ссылки на сборку, AutoMapper и AutoMapper.Net4, где вторая сборка загружается первым путем отражения когда ему нужно выполнить определенное действие над новыми объектами коллекции, представленными .NET Framework 4. Поскольку вторая сборка загружается через отражение, MSBuild считает ее неиспользованной и не пытается ее скопировать.

Итак, да, они будут скопированы до тех пор, пока вы используете их напрямую, а не через отражение.

Является ли это документированным где-нибудь?

Такое поведение, похоже, является "функцией" MSBuild, мне удалось найти сообщение в блоге от некоторых людей из Microsoft, когда я столкнулся с этой проблемой, но я не могу найти ее снова на данный момент.

Ответ 2

Это очень прямолинейно, не имеет ничего общего с Copy Local. MSBuild просматривает метаданные сборки, чтобы узнать, какие зависимости для сборки. Так вы можете, запустите ildasm.exe на сборке и дважды щелкните манифест. Обязательно попробуйте это, чтобы получить представление. Вы увидите директивы .assembly. Вставляемый компилятором при его сборке, будут перечислены только ссылочные сборки, которые вы фактически использовали в вашем коде.

Если MSBuild может найти такую ​​сборку в том же каталоге, она автоматически ее скопирует. Если нет, то он молча пропустит копию.

Из этого вы можете вывести режимы сбоев. Он не может копировать неуправляемые библиотеки DLL, они не отображаются в метаданных. Он не может копировать сборки, у которых есть косвенная зависимость, через Assembly.Load/From(), они также не отображаются в метаданных. Он не может скопировать сборки, которые еще не были созданы, проблема с порядком сборки. И он не может копировать сборки, для которых свойство Copy Local установлено значение False. Обычно это допустимый выбор, если сборка присутствует в GAC, не требуется копирование.

Для таких случаев вам нужно помочь, XCOPY в событии после сборки получает задание.