基于 Sdk 的项目进行编译的时候,会使用 Sdk 中附带的 props 文件和 targets 文件对项目进行编译。Microsoft.NET.Sdk.WindowsDesktop 的 Sdk 包含 WPF 项目的编译过程。
而本文介绍 WPF 项目的编译过程,包含 WPF 额外为编译过程添加的那些扩展编译目标,以及这些扩展的编译目标如何一步步完成 WPF 项目的过程。
本文内容
提前准备
在阅读本文之前,你可能需要提前了解编译过程到底是怎样的。可以阅读:
如果你不明白上面文章中的一些术语(例如 Target / Task),可能不能理解本文后面的内容。
另外,除了本文所涉及的内容之外,你也可以自己探索编译过程:
WPF 的编译代码都在 Microsoft.WinFx.targets 文件中,你可以通过上面这一篇博客找到这个文件。接下来,我们会一一介绍这个文件里面的编译目标(Target),然后统一说明这些 Target 是如何协同工作,将 WPF 程序编译出来的。
Microsoft.WinFx.targets 的源码可以查看:
Target
WPF 在编译期间会执行以下这些 Target,当然 Target 里面实际用于执行任务的是 Task。
知道 Target 名称的话,你可以扩展 WPF 的编译过程;而知道 Task 名称的话,可以帮助理解编译过程实际做的事情。
本文都会列举出来。
FileClassification
- Target 名称:
FileClassification
- Task 名称:
FileClassifier
用于将资源嵌入到程序集。如果资源没有本地化,则嵌入到主程序集;如果有本地化,则嵌入到附属程序集。
在 WPF 项目中,这个 Target 是一定会执行的;但里面的 Task 则是有 Resource
类型的编译项的时候才会执行。
GenerateTemporaryTargetAssembly
Target 名称和 Task 名称相同,都是 GenerateTemporaryTargetAssembly
。
只要项目当中包含任何一个生成类型为 Page 的 XAML 文件,则会执行此 Target。
关于生成临时程序集的原因比较复杂,可以阅读本文后面的 WPF 程序的编译过程部分来了解。
MarkupCompilePass1
Target 名称和 Task 名称相同,都是 MarkupCompilePass1
。
将非本地化的 XAML 文件编译成二进制格式。
MarkupCompilePass2
Target 名称和 Task 名称相同,都是 MarkupCompilePass2
。
对 XAML 文件进行第二轮编译,而这一次会引用同一个程序集中的类型。
DesignTimeMarkupCompilation
这是一个仅在有设计器执行时才会执行的 Target,当这个编译目标执行时,将会直接调用 MarkupCompilePass1
。
实际上,如果在 Visual Studio 中编译项目,则会调用到这个 Target。而判断是否在 Visual Studio 中编译的方法可以参见:
<Target Name="DesignTimeMarkupCompilation">
<!-- Only if we are not actually performing a compile i.e. we are in design mode -->
<CallTarget Condition="'$(BuildingProject)' != 'true'"
Targets="MarkupCompilePass1" />
</Target>
MergeLocalizationDirectives
Target 名称和 Task 名称相同,都是 MergeLocalizationDirectives
。
将本地化属性和一个或多个 XAML 二进制格式文件的注释合并到整个程序集的单一文件中。
<Target Name="MergeLocalizationDirectives"
Condition="'@(GeneratedLocalizationFiles)' !=''"
Inputs="@(GeneratedLocalizationFiles)"
Outputs="$(IntermediateOutputPath)$(AssemblyName).loc"
>
<MergeLocalizationDirectives GeneratedLocalizationFiles="@(GeneratedLocalizationFiles)"
OutputFile="$(IntermediateOutputPath)$(AssemblyName).loc"/>
<!--
Add the merged loc file into _NoneWithTargetPath so that it will be copied to the
output directory
-->
<CreateItem Condition="Exists('$(IntermediateOutputPat