Как указать выходную папку для упомянутых пакетов nuget? - PullRequest
1 голос
/ 02 мая 2019

У меня есть проект с некоторыми ссылками на пакеты nuget.

В выходных папках (bin\Debug или bin\Release) все библиотеки, на которые есть ссылки, находятся рядом с исполняемым файлом.

Как указать выходную папку для библиотек?
Мне нужны все библиотеки nuget в bin\Release\Libs и исполняемые файлы в bin\Release.

Ответы [ 2 ]

2 голосов
/ 03 мая 2019

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

Исходя из вашего вопроса, я предполагаю, что вы используете традиционный проект, поскольку проекты в стиле SDK создают только сборку проекта в каталоге bin. Однако я предпочитаю проекты в стиле SDK, потому что пользователь может быстро и легко использовать dotnet cli для создания тестовых проектов, а csproj гораздо проще редактировать. Итак, я расскажу вам, как найти свое решение для проектов в стиле SDK, и вам нужно проделать что-то подобное с традиционным проектом.

Итак, мы хотим изменить место копирования файлов, а это значит, что нам нужно изменить некоторые элементы. Все в MSBuild выполняется в цели, поэтому нам нужно знать, когда нужно запускать нашу собственную цель, какие элементы изменять и, возможно, какие метаданные этих элементов нужно изменить. Я создал новый проект, добавил несколько ссылок NuGet, затем запустил dotnet msbuild -t:publish -bl и открыл файл msbuild.binlog.

Какие метаданные изменить

В поисках имени dll, полученного из пакета nuget, я нахожу сообщение, скопированное из ... в ..., поэтому я нажимаю на него, чтобы перейти к записи, и проследовать по дереву обратно к задача, которую я вижу, является встроенной задачей копирования. Целевой путь к задаче - Опубликовать -> _PublishBuildAlternative -> ComputeAndCopyFilesToPublisDirectory -> CopyFilesToPublishDIrectory -> _CopyResolvedFilesToPublishAlways. Двойной щелчок по заданию копирования я вижу

    <Copy SourceFiles = "@(_ResolvedFileToPublishAlways)"
          DestinationFiles="@(_ResolvedFileToPublishAlways->'$(PublishDir)%(RelativePath)')"
          OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
          Retries="$(CopyRetryCount)"
          RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
          UseHardlinksIfPossible="$(CreateHardLinksForPublishFilesIfPossible)"
          UseSymboliclinksIfPossible="$(CreateSymbolicLinksForPublishFilesIfPossible)">

Итак, я могу предположить, что мне нужно изменить метаданные RelativePath элемента _ResolvedFileToPublishAlways.

Какой предмет изменить

Примечание: MSBuild не имеет публичных / приватных модификаций, поэтому вместо этого обычно используется соглашение. Все, что начинается с подчеркивания, должно рассматриваться как деталь реализации, которая может меняться между выпусками, поэтому лучше использовать вещи, которые не начинаются с подчеркивания, и командам, которые поддерживают файл целей, следует стараться не нарушать совместимость.

Итак, поскольку _ResolvedFileToPublishAlways начинается с подчеркивания, давайте выясним, где оно было создано. В результате поиска он попадает в цель, в которой журнал сообщает, что она была добавлена, в цель с именем _ComputeResolvedFilesToPublishTypes и ее определение

.
  <Target Name="_ComputeResolvedFilesToPublishTypes">
    <ItemGroup>
      <_ResolvedFileToPublishPreserveNewest Include="@(ResolvedFileToPublish)"
                                             Condition="'%(ResolvedFileToPublish.CopyToPublishDirectory)'=='PreserveNewest'" />

      <_ResolvedFileToPublishAlways Include="@(ResolvedFileToPublish)"
                                     Condition="'%(ResolvedFileToPublish.CopyToPublishDirectory)'=='Always'" />
    </ItemGroup>
  </Target>

Итак, я вижу, что это просто копирование ResolvedFileToPublish элементов в новые имена элементов. Ища, где эти элементы созданы, он находится в цели с именем ComputeFilesToPublish и расширяя дерево, чтобы увидеть все созданные элементы и их метаданные, я собираюсь догадаться, что все элементы, которые я хочу изменить, имеют AssetType = runtime, что идеально подходит для условий, которые нам нужно использовать.

Когда запустить нашу цель

В идеале я бы бегал как раз перед CopyFilesToPublishDirectory, однако, глядя на его определение, я вижу

  <Target Name="CopyFilesToPublishDirectory"
          DependsOnTargets="_CopyResolvedFilesToPublishPreserveNewest;
                            _CopyResolvedFilesToPublishAlways" />

Проблема в том, что когда MSBuild выполняет цель, она запускается в следующем порядке:

  1. Любые цели, перечисленные в DependsOnTargets
  2. Любая цель, которая отображает текущую цель как BeforeTargets
  3. Текущая цель
  4. Любые цели, которые отображают текущую цель как AfterTargets

Итак, пока я хочу запустить BeforeTargets='CopyFilesToPublishDirectory', DependsOnTargets будет выполняться перед моей целью, поэтому я не могу этого сделать. Поэтому я выберу запускать AfterTargets="ComputeFilesToPublish". Есть другие цели, которые выполняются между ними, и одна из них звучит так, как будто она может добавить ResolvedFileToPublish элементов, но в моем текущем проекте цель не выполняется из-за условий, поэтому моя пользовательская цель может быть недостаточно общей для работы все проекты.

Написание нашей пользовательской цели

Итак, теперь мы знаем, когда наша цель будет работать, какие элементы она будет изменять и как мы будем изменять их метаданные.

  <Target Name="RedirectRuntimeFilesToBinDirectory" AfterTargets="ComputeFilesToPublish">
    <ItemGroup>
      <ResolvedFileToPublish Condition=" '%(ResolvedFileToPublish.AssetType)' == 'runtime' ">
        <RelativePath>lib\%(RelativePath)</RelativePath>
      </ResolvedFileToPublish>
    </ItemGroup>
  </Target>

К сожалению, в binlog не отображаются подробности об изменяемых метаданных, что является настоящей болью в заднице при попытке отладки проблем сборки и почему некоторые элементы имеют неожиданные значения, но в любом случае я теперь успешно изменилсяназначение зависимостей NuGet и, возможно, проект для ссылок проекта, в каталог lib\.

1 голос
/ 04 мая 2019

Благодать на зивкан расследование Я нашел ответ.Традиционный проект имеет цель CopyFilesToOutputDirectory, которая зависит от цели _CopyFilesMarkedCopyLocal.В этом последнем у нас есть задача Copy:

<Copy
    SourceFiles="@(ReferenceCopyLocalPaths)"
    DestinationFiles="@(ReferenceCopyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')"
    SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
    OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
    Retries="$(CopyRetryCount)"
    RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
    UseHardlinksIfPossible="$(CreateHardLinksForCopyLocalIfPossible)"
    UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyLocalIfPossible)"
    Condition="'$(UseCommonOutputDirectory)' != 'true'"
        >

И здесь я нашел метаданные DestinationSubDirectory, которые именно то, что мне нужно изменить.

Итак, наконец

Первый , нам нужно изменить файл csproj и добавить следующие строки:

  <ItemDefinitionGroup>
    <ReferenceCopyLocalPaths>
      <DestinationSubDirectory>lib\</DestinationSubDirectory>
    </ReferenceCopyLocalPaths>
  </ItemDefinitionGroup>

Второй ,нам нужно изменить файл app.config, чтобы сборка знала путь к библиотекам:

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="lib;libs" />
    </assemblyBinding>
  </runtime>

Вот и все.Все библиотеки, на которые есть ссылки, будут скопированы в подпапку lib

...