問題描述
我有一個自定義 msbuild 任務,它正在生成一些輸出文件到 ProjectA 的輸出目錄 ($(TargetDir)).當前代碼是這樣的:
I have a custom msbuild task that is generating some output files to the output directory ($(TargetDir)) of a ProjectA. Current code is something like this:
<MyCustomTask ...>
<Output TaskParameter="OutputFiles" ItemName="FileWrites"/>
</MyCustomTask>
A ProjectB 正在引用 ProjectA 但問題是在構建 ProjectB 時,MyCustomTask 生成的文件不會復制到 ProjectB 的輸出目錄.
A ProjectB is referencing ProjectA but the problem is that when building ProjectB, generated files by MyCustomTask are not copied to the output directory of the ProjectB.
我們如何獲取動態生成的附加文件以作為 MSBuild 項目依賴項的一部分進行復制?
How can we get dynamically generated additional files to be copied as part of project dependency with MSBuild?
推薦答案
我終于設法從 Project B 自動執行復制,而無需修改它.IIya 離解決方案不遠,但事實是我無法靜態生成,因為使用 MyCustomTask 從 Project A 生成的文件列表是動態的.在深入了解 Microsoft.Common.targets
之后,我發現 ProjectB 將通過調用目標 GetCopyToOutputDirectoryItems
來獲取 Project A 的輸出列表.該目標依賴于 AssignTargetPaths
,而 AssignTargetPaths
本身又依賴于目標列表屬性 AssignTargetPathsDependsOn
.
I have finally managed to perform automatically the copy from Project B without having to modify it. IIya was not so far from the solution, but the fact is that I cannot generate statically as the list of files to generate from Project A with MyCustomTask is dynamic. After digging more into Microsoft.Common.targets
, I have found that ProjectB will get the list of output from Project A by calling the target GetCopyToOutputDirectoryItems
. This target is dependent from AssignTargetPaths
which itself is dependent on the target list property AssignTargetPathsDependsOn
.
因此,為了動態生成內容并通過標準項目依賴項自動復制此內容,我們需要在兩個不同的地方掛鉤 Project A:
So in order to generate dynamically content and to get this content being copied automatically through standard project dependency, we need to hook Project A at two different places:
- 在
AssignTargetPathsDependsOn
中,因為它由 Project B 在 Project A 上通過 GetCopyToOutputDirectoryItems 間接調用.當PrepareResource
被調用時,它也被 Project A 間接調用.在這里,我們只是輸出將生成(由Project A)或由Project B 使用的文件列表.AssignTargetPathsDependsOn 將調用一個自定義任務MyCustomTaskList
,它只負責輸出文件列表(但不生成它們),這個文件列表將使用CopyOutputDirectory
. - 在
BuildDependsOn
中以實際生成 Project A 中的內容.這將調用生成內容的MyCustomTask
.
- In
AssignTargetPathsDependsOn
as it is called indirectly by Project B on Project A through GetCopyToOutputDirectoryItems. And also it is indirectly called by Project A whenPrepareResource
is called. Here, we are just outputing the list of files that will be generated (by Project A) or consumed by Project B. AssignTargetPathsDependsOn will call a custom taskMyCustomTaskList
which is only responsible to output the list of files (but not to generate them), this list of files will create dynamic "Content" withCopyOutputDirectory
. - In
BuildDependsOn
in order to actually generate the content in Project A. This will callMyCustomTask
that will generate the content.
所有這些都是在 ProjectA 中這樣設置的:
All of this was setup like this in ProjectA:
<!-- In Project A -->
<!-- Task to generate the files -->
<UsingTask TaskName="MyCustomTask" AssemblyFile="$(PathToMyCustomTaskAssembly)"/>
<!-- Task to output the list of generated of files - It doesn't generate the file -->
<UsingTask TaskName="MyCustomTaskList" AssemblyFile="$(PathToMyCustomTaskAssembly)"/>
<!-- 1st PART : When Project A is built, It will generate effectively the files -->
<PropertyGroup>
<BuildDependsOn>
MyCustomTaskTarget;
$(BuildDependsOn);
</BuildDependsOn>
</PropertyGroup>
<Target Name="MyCustomTaskTarget">
<!-- Call MyCustomTask generate the files files that will be generated by MyCustomTask -->
<MyCustomTask
ProjectDirectory="$(ProjectDir)"
IntermediateDirectory="$(IntermediateOutputPath)"
Files="@(MyCustomFiles)"
RootNamespace="$(RootNamespace)"
>
</MyCustomTask>
</Target>
<!-- 2nd PART : When Project B is built, It will call GetCopyToOutputDirectoryItems on ProjectA so we need to generate this list when it is called -->
<!-- For this we need to override AssignTargetPathsDependsOn in order to generate the list of files -->
<!-- as GetCopyToOutputDirectoryItems ultimately depends on AssignTargetPathsDependsOn -->
<!-- Content need to be generated before AssignTargets, because AssignTargets will prepare all files to be copied later by GetCopyToOutputDirectoryItems -->
<!-- This part is also called from ProjectA when target 'PrepareResources' is called -->
<PropertyGroup>
<AssignTargetPathsDependsOn>
$(AssignTargetPathsDependsOn);
MyCustomTaskListTarget;
</AssignTargetPathsDependsOn>
</PropertyGroup>
<Target Name="MyCustomTaskListTarget">
<!-- Call MyCustomTaskList generating the list of files that will be generated by MyCustomTask -->
<MyCustomTaskList
ProjectDirectory="$(ProjectDir)"
IntermediateDirectory="$(IntermediateOutputPath)"
Files="@(MyCustomFiles)"
RootNamespace="$(RootNamespace)"
>
<Output TaskParameter="ContentFiles" ItemName="MyCustomContent"/>
</MyCustomTaskList>
<ItemGroup>
<!--Generate the lsit of content generated by MyCustomTask -->
<Content Include="@(MyCustomContent)" KeepMetadata="Link;CopyToOutputDirectory"/>
</ItemGroup>
</Target>
此方法適用于任何使用 Common.Targets 的 C# 項目(因此它適用于純桌面、WinRT XAML 應用程序或 Windows Phone 8 項目).
This method is working with anykind of C# projects that is using Common.Targets (so It is working with pure Desktop, WinRT XAML App or Windows Phone 8 projects).
這篇關于MSBuild 復制動態生成的文件作為項目依賴項的一部分的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!