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

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

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

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

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

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

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

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

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

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

Пример:

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

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


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

2 ответа

Решение

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

Не на самом деле нет.

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

Если ProjectA зависит от ProjectB строить ProjectAProjectB должен быть уже собран (и обновлен), MSBuild затем извлечет свою DLL (не код C#) и свяжет ее с ProjectA,

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

В противном случае вам придется вручную предварительно построить зависимость, найти ее 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 код он решает выполнить некоторую "оптимизацию" и пропускает MySolution.FourthDependency сборка с выхода.

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

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

Это где-то задокументировано?

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

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

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

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

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

Другие вопросы по тегам