Включить дополнительные файлы в сборку, используя MSBuild ProjectReference?

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

Я искал в Microsoft.Common.targets способ включить эти файлы в выходные данные собственного файла проекта библиотеки, поэтому любой проект, имеющий ссылку ProjectReference на библиотеку, автоматически получит файлы при выполнении сборки. Я еще ничего не получил, но мне любопытнее, если это возможно. Похоже, что так и должно быть, и цель _CopyFilesMarkedCopyLocal даже учитывает неиспользуемый в противном случае элемент метаданных%(DestinationSubDirectory), который позволит настраивать размещение этих файлов, что было бы идеально.

Я считаю, что мне не хватает, чтобы построить проект A, который зависит от проекта B, часть, которая добавляет выходные данные проекта B в элементы для сборки проекта A.

РЕДАКТИРОВАТЬ: Комментарий Лео, я не заметил, что файлы, помеченные CopyToOutputDirectory, также копируются в выходные каталоги зависимых проектов, потому что мы используем ItemGroups с именами, отличными от Content, EmbeddedResource, None и т. Д. Копать глубже, целью, которая их использует, является GetCopyToOutputDirectoryItems и кажется, что он рекурсивно вызывает задачу MSBuild для определения выходных данных проекта, поэтому я должен иметь возможность определить некоторую настраиваемую цель, которая может быть импортирована в наши проекты, которая добавляет наши пользовательские ItemGroups в цель GetCopyToOutputDirectoryItems, так что нам не нужно использовать Содержание / Нет и т. Д.

Однако целью, которая выполняет копирование, является _CopyOutOfDateSourceItemsToOutputDirectoryAlways, который, к сожалению, не учитывает%(DestinationSubDirectory), и поэтому все эти файлы копируются непосредственно в $(OutDir).

Моя новая цель - посмотреть, есть ли какой-нибудь способ добавить пользовательские файлы в ReferenceCopyLocalPaths ItemGroup зависимых проектов, чтобы они вместо этого копировались целью _CopyFilesMarkedCopyLocal, которая использует%(DestinationSubDirectory).

1 ответ

Добавляет настраиваемое действие сборки для ItemGroups в цель _CopyOutOfDateSourceItemsToOutputDirectoryAlways

Приведенный выше заголовок должен быть ближе к цели bwerks. В качестве теста мы могли узнать, что пользовательское действие сборки для ItemGroups не будет скопировано в выходной каталог, поэтому нам нужно наше пользовательское действие сборки для цели _CopyOutOfDateSourceItemsToOutputDirectoryAlways,

Для этого откройте файл Microsoft.Common.CurrentVersion.targets в папке MSBuild 15.0 C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets(Убедитесь, что у вас достаточно прав и создайте резервную копию), найдите цель _CopyOutOfDateSourceItemsToOutputDirectoryAlways:

<Copy
    SourceFiles = "@(_SourceItemsToCopyToOutputDirectoryAlways)"
    DestinationFiles = "@(_SourceItemsToCopyToOutputDirectoryAlways->'$(OutDir)%(TargetPath)')"
    ...
        >

  <Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>

</Copy>

Тогда мы могли бы знать, исходный файл копии @(_SourceItemsToCopyToOutputDirectoryAlways), поиск _SourceItemsToCopyToOutputDirectoryAlways это в целях, вы найдете:

<ItemGroup>
  <_SourceItemsToCopyToOutputDirectoryAlways KeepMetadata="$(_GCTODIKeepMetadata)" Include="@(ContentWithTargetPath->'%(FullPath)')" Condition="'%(ContentWithTargetPath.CopyToOutputDirectory)'=='Always'"/>
  <_SourceItemsToCopyToOutputDirectory       KeepMetadata="$(_GCTODIKeepMetadata)" Include="@(ContentWithTargetPath->'%(FullPath)')" Condition="'%(ContentWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"/>
</ItemGroup>

Может знать, исходный файл @(ContentWithTargetPath), продолжая искать ContentWithTargetPath в цели, наконец, мы получили следующее:

<AssignTargetPath Files="@(Content)" RootFolder="$(MSBuildProjectDirectory)">
  <Output TaskParameter="AssignedFiles" ItemName="ContentWithTargetPath" />
</AssignTargetPath>

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

Теперь перейдите к нашему пользовательскому действию сборки, нам просто нужно добавить наше пользовательское действие сборки в ItemName="ContentWithTargetPath"так что добавьте следующее в файл Microsoft.Common.CurrentVersion.targets:

<AssignTargetPath Files="@(MyBuildAction)" RootFolder="$(MSBuildProjectDirectory)">
  <Output TaskParameter="AssignedFiles" ItemName="ContentWithTargetPath" />
</AssignTargetPath>

Сохрани это.

Для файла в файле проекта .csproj:

  <ItemGroup>
    <MyBuildAction Include="TextFile1.txt">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </MyBuildAction>
  </ItemGroup>

введите описание изображения здесь

Надеюсь это поможет.

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