我有一个类库,其中包含几个依赖的文件,并且这些文件必须打包为与依赖此库的任何项目一起部署。现在,这意味着除了将库添加为MSBuild PrjectReference之外,我还必须自定义这些依赖项目中的每一个,以确保它们复制文件。添加更多文件后,必须更新所有项目。
我一直在通过Microsoft.Common.targets寻找一种将这些文件包含在库自己的项目文件的输出中的方法,因此,对库具有ProjectReference的任何项目在进行构建时都会自动获取文件。我还没有任何工作,但是如果可以的话,我更好奇。看起来应该是这样,并且_CopyFilesMarkedCopyLocal目标甚至尊重未使用的%(DestinationSubDirectory)元数据项,该项允许对这些文件进行自定义放置,这是完美的。
我相信我缺少的是,对于构建依赖于项目B的项目A,需要将项目B的项目输出添加到项目A的构建项目中。
编辑:Leo的评论,我没有注意到标有CopyToOutputDirectory的文件也被复制到从属项目输出目录中,因为我们使用ItemGroups而不是Content,EmbeddedResource,None等名称。更深入地讲,使用这些目标的目标是GetCopyToOutputDirectoryItems,并且它似乎以递归方式调用MSBuild任务来确定项目输出,因此我应该能够定义一些可以导入到我们的项目中的自定义目标,从而将我们的自定义ItemGroups添加到GetCopyToOutputDirectoryItems目标中,这样我们就不必使用Content / None等。
但是,尽管复制的目标是_CopyOutOfDateSourceItemsToOutputDirectoryAlways,但不幸的是它不遵守%(DestinationSubDirectory),因此所有这些文件都直接复制到$(OutDir)。
我的新目标是查看是否有某种方法可以将自定义文件添加到依赖项目的ReferenceCopyLocalPaths ItemGroup中,以便由_CopyFilesMarkedCopyLocal目标(而不使用%(DestinationSubDirectory))进行复制。
答案 0 :(得分:1)
在_CopyOutOfDateSourceItemsToOutputDirectoryAlways目标中为ItemGroups添加自定义生成操作
上面的标题应该更接近bwerks的目标。作为测试,我们可以知道ItemGroups的自定义构建操作不会复制到Output目录,因此我们需要将自定义构建操作复制到目标_CopyOutOfDateSourceItemsToOutputDirectoryAlways
。
要完成此操作,请打开MSBuild 15.0文件夹Microsoft.Common.CurrentVersion.targets
中的文件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>
希望这会有所帮助。