Сборка зависимостей и билда

273
04 февраля 2019, 19:10

Есть десктоп решение (4.6 и net standard 2.0), в котором буквально три уровня зависимостей - шаредная сборка (ядро), UI сборка и плагин (точнее их несколько, но они одинаковые с точки зрения зависимостей).

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

Сейчас сборка гарантируется частично beforebuild событием, но т.к. несвязанные проекты могут компилироваться в разном порядке, иногда приходится тупо два раза билдить. Плюс, сейчас оно сделано с использованием xcopy, а хочется кроссплатформенную сборку.

Насколько я понял, есть вариант с targets файлами, но по ним не нашел никакой толковой справки, кроме например статьи https://rsdn.org/article/devtools/msbuild-05.xml#EVGAE

Плюс, есть разные вещи типа Cake (C# Make), но фактически это отдельный инструмент, которым придётся учиться пользоваться, плюс непонятно опять, насколько эти решения кроссплатформенные.

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

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

Answer 1

В итоге, msbuild закрыл все мои задачи, хоть местами и смотрится неудобно.

Для плагинов написан простой отдельный таргет:

<Project>
  <!-- Copy plugin dll and pdb files to shared folder after compile -->
  <Target Name="CopyAfterCompile" AfterTargets="CopyFilesToOutputDirectory">
    <ItemGroup>
      <SourceFiles Include="$(TargetPath)" />
      <SourceFiles Include="$(TargetDir)$(TargetName).pdb" />
    </ItemGroup>
    <Copy SourceFiles="@(SourceFiles)" 
          DestinationFiles="@(SourceFiles->'$(ProjectDir)\..\Bin\$(ConfigurationName)\$(TargetFramework)\%(RecursiveDir)%(Filename)%(Extension)')" />
  </Target> 
</Project>

Такой таргет потом легко подключается к проекту плагина по имени файла, как <Import Project="..\Sites.props"/> и автоматически копирует сборку в нужную папку.

ПС: отдельно стоит заметить, что я тут ссылаюсь на TargetFramework, но он работает только для мультитаргетных проектов, например мои сделаны под net461 и netstandard2.0

Приложения в netstandard я собираю как self-contained, и тут добавление сборок подцепилось только к событию "публикации", несмотря на кучу других советов в гугле. Выглядит примерно так:

  <!-- Copy native libs - skiasharp and sqlite interops -->
  <Target Name="CopyNativeLibraries" AfterTargets="Publish">
    <PropertyGroup>
      <UserRoot>$(userprofile)</UserRoot>
      <UserRoot Condition="'$(userprofile)' == ''">$(HOME)</UserRoot>
    </PropertyGroup>
    <ItemGroup>
      <Library Include="$(UserRoot)\.nuget\packages\skiasharp\1.57.1\runtimes\osx\native\libSkiaSharp.dylib" />
      <Library Include="$(UserRoot)\.nuget\packages\skiasharp\1.57.1\runtimes\win7-x64\native\libSkiaSharp.dll" />
    </ItemGroup>
    <Copy SourceFiles="@(Library)" 
          DestinationFiles="@(Library->'$([System.IO.Path]::GetFullPath('$(PublishDir)'))\%(RecursiveDir)%(Filename)%(Extension)')" />
  </Target>

На самом деле, разработчик skiasharp уже исправил публикацию своих сборок, но оно пока не вышло в релиз. А вот для sqlite интеропов обновление уже вышло, поэтому тут осталась только skia.

ПС: переменная UserRoot пытается определить папку, в которой находится нугет. Оно не совсем кроссплатформ, но Linux и Windows в текущей реализации работают.

В целом, для анализа порядка выполнения таргетов и анализа того, что кругом происходит, достаточно запустить msbuild -v:diag с билдом или публикацией. В логе будут записаны и все обработанные таргеты и их порядок. Большой плюс msbuild по сравнению с тем же Cake, который я вспоминал в вопросе - у него уже есть куча вычисленных переменных и ими просто надо пользоваться. Более того, у него и жизненный цикл вполне логичный (по логам) и накидать свой таргет, завязанный на существующий - довольно легко.

READ ALSO
c# ms server ошибка подключения

c# ms server ошибка подключения

Я тут пытаюсь подключить к свою проекту, выдает ошибка

286
Анимированный gif на форме

Анимированный gif на форме

На форме1 (как форма-заставка) (c# winforms vs2010 net40) в picturebox находится анимированный файл gif

302
Кастомный маршалер

Кастомный маршалер

Судя по документации, не совсем ясно что должен вообще реализовывать интерфейс ICustomMarshaler

327
C# OpenGL Проблема при перетаскивании объектов

C# OpenGL Проблема при перетаскивании объектов

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

277