Копирование в $(OutputPath) зависимостей
От: Qbit86 Кипр
Дата: 26.09.11 07:40
Оценка:
Доброе утро!

Возникла проблема с копированием транзитивных зависимостей в выходную директорию при сборке посредством MSBuild.

Предположим, есть проект Core.csproj, который ссылается на библиотеку ThirdParty.dll;
есть проект Api.csproj, который ссылается на Core.csproj и не ссылается прямо на ThirdParty.dll;
есть проект Application.csproj, который ссылается на Api.csproj и не ссылается прямо на Core.csproj и ThirdParty.dll:
ThirdParty.dll ← Core.csproj ← Api.csproj ← Application.csproj

Для первых двух проектов выходной папкой установлена «$(SolutionDir)Bin\Common\$(Configuration)-$(Platform)\». Для последнего проекта установлена отдельная папка «$(SolutionDir)Bin\Application\$(Configuration)-$(Platform)\».

Ожидаемое поведение сборки: в выходную папку Application скопируются Application.exe, его явная зависимость Api.dll, неявные зависимости Core.dll и ThirdParty.dll.

Для тривиальных проектов всё происходит согласно ожиданиям. Но в каких-то более сложных случаях что-то нарушается, и в выходную директорию Application не копируются зависимости второго порядка. С чем это может быть связано, есть ли какие-то общие рекомендации, или это проблемы конкретных скриптов сборки?
Глаза у меня добрые, но рубашка — смирительная!
Re: Копирование в $(OutputPath) зависимостей
От: hardcase Пират http://nemerle.org
Дата: 26.09.11 08:15
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>С чем это может быть связано, есть ли какие-то общие рекомендации, или это проблемы конкретных скриптов сборки?


Возможно в одном из проектов стоит что-то типа:
<Reference Include="Core">
  <Private>False</Private>
</Reference>
/* иЗвиНите зА неРовнЫй поЧерК */
Re[2]: <Private>False</Private>
От: Qbit86 Кипр
Дата: 26.09.11 08:27
Оценка:
Здравствуйте, hardcase, Вы писали:

Q>>С чем это может быть связано, есть ли какие-то общие рекомендации, или это проблемы конкретных скриптов сборки?

H>Возможно в одном из проектов стоит что-то типа:
H><Reference Include="Core">
H>  <Private>False</Private>
H></Reference>


На Core идёт ссылка через ProjectReference.
Для ссылок на библиотеки указанное свойство private deployment'а не установлено (что соответствует Copy Local: true в IDE).
Глаза у меня добрые, но рубашка — смирительная!
Re[3]: <Private>False</Private>
От: hardcase Пират http://nemerle.org
Дата: 26.09.11 08:30
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>На Core идёт ссылка через ProjectReference.

Q>Для ссылок на библиотеки указанное свойство private deployment'а не установлено (что соответствует Copy Local: true в IDE).

Значит остается лишь внимательное изучение /verbosity:diagnostic логов msbuild-а.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[4]: 13782
От: Qbit86 Кипр
Дата: 26.09.11 08:35
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Значит остается лишь внимательное изучение /verbosity:diagnostic логов msbuild-а.


С этого я и начал, но там свыше 13К строчек :)
Глаза у меня добрые, но рубашка — смирительная!
Re: Run-time and build-time dependencies
От: Qbit86 Кипр
Дата: 26.09.11 10:53
Оценка:
Q>Возникла проблема с копированием транзитивных зависимостей в выходную директорию при сборке посредством MSBuild.

Я кое-что понял.

Неясно, как MSBuild трактует понятие «выходные файлы проекта». Есть выходные файлы разных таргетов (в т.ч. пользовательских), но что из них копировать вместе со сборкой?

По всей видимости, информация о том, что копировать, берётся не только из билд-скриптов, но и из манифеста сборки. Видимо, этим занимается таск ResolveAssemblyReference, фигурирующий в билд-логе.

Иными словами, вместо копирования build-time зависимостей мы получаем копирование явных (известных в момент сборки) run-time зависимостей.

Почему в тестовом солюшене копирование транзитивных зависимостей происходило, а в рабочем — нет? Дело в том, что аналогом проекта Application.csproj у меня является WPF приложение, а Api.csproj и Core.csproj — библиотеки кастомных контролов. В шаблоне контрола из Api.csproj используется контрол из Core.csproj. Но такого рода зависимость не зафиксирована явно; несмотря на то, что эта зависимость отражена в build time как ссылка на проект, в манифест сборки Api.dll ссылка на Core.dll не попадает (последняя сборка должна быть найдена и загружена в рантайме динамически).

Проверить это легко. В моём тестовом солюшене, где копирование транзитивных зависимостей происходило якобы корректно, стоило убрать использование классов из Core.dll (не убирая ссылки на проект Core), как сборки Core.dll и ThirdParty.dll перестали копироваться в папку Application. IL Dasm подтвердил версию насчёт манифеста.

Встретил попытку решения похожей проблемы, пусть тут полежит: http://blog.alexyakunin.com/2009/09/making-msbuild-visual-studio-to.html.

Интересен также пример поведения, в некотором смысле обратного.

Пусть в сборке Core.dll определён класс Core, в сборке Api.dll определён класс Api, наследующий Core, а в сборке Application.exe используется Api, и не используется явно Core. Тогда в манифесте сборки Application.exe будет указана сборка Api, и не будет указана сборка Core — для разрешения зависимостей в рантайме этого достаточно. А для компиляции — нет! То есть компилятор (вполне закономерно) потребует добавить ссылку на сборку Core.dll, даже если явного её использования нигде в коде нет (и в манифест она не попадёт).
Глаза у меня добрые, но рубашка — смирительная!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.