Включить дополнительные файлы в сборку, используя 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>
Надеюсь это поможет.