重新认识生成流程

      终于到了不得不讨论这个话题的时候. 重写团队基础生成流程, 是团队基础最富于弹性和扩展能力的地方, 也是实践最多优劣各异的地方. 这是MSBuild引擎的优秀能力: 给MSBuild引擎提供任意一个格式正确的生成脚本, MSBuild引擎都能搞解析生成脚本并形成可以顺序(或并行)执行的执行顺序流. 所以我们现在回过头来看, Team Build是什么? 我们试着从本质上归结一下:

      "在MSBuild引擎驱动下的, 以团队基础框架提供的包含一系列生成目标(Target)的默认生成脚本文件 - Microsoft.TeamFoundation.Build.targets - 为基础的, 可以被用户自定义生成脚本文件 - tfsbuild.proj - 所覆盖从而形成一条确定的可执行的生成流程."

      既然这样, 我们就可以从战略上藐视Team Build流程了 : 只要我们理解了本系列第一篇文章所讲默认的生成流程, 理解某一目标定义在了什么地方(Where), 这一步在整个流程中的什么时间点上(When), 做了什么(What), 为什么这么做(Why), 那么如果我们觉得这个目标的相关4W中有一项或者几项让我们很不爽, 那么我们就完全可以改掉它! 不要担心你的做法是错误的, 只要修改是符合MSBuild生成脚本格式的, 是考虑了上下文的, 那么就尽管去做.

      没错, 一个别扭的逻辑悖论让我们忍了很久了: "GET"的位置问题. 譬如上一篇我们提到了"Get"目标和我们自定义Task之间的时间逻辑问题: 我们要生成自己的版本号, 我们写了自己的Task来完成这个任务, 但是在重写版本号的时候, 我们的自定义任务居然还没到达本地位置!

 

如何调整流程

      Target这个概念是MSBuild的核心概念, 不单单用于Team Build, 包括我们平常在VS IDE里面点一下F6或者F5, 都是用到了MSBuild的这个概念(不信您随便找个项目文件用记事本打开看看第一行). 如果您对这个概念还有点不是很清楚的感觉的话, 我建议您一定看一下<MSDN Target Reference>, 然后再回来看这一节.

       我们的目标是调整微软提供的默认生成流程. 修改的需求, 基本上可以归类为:

  • 添加一个新的生成目标到合适的地方,

  • 遮蔽一个已有的生成目标,

  • 更改几个已有生成目标的执行顺序,

  • 更改已有生成目标的执行条件或内容

      修改, 需要修改的切口. 团队基础生成流程提供给我们的切口有两个: 需要修改的Target, 和它的DependsOnTargets属性.如果要修改一个生成目标的执行条件/对象或者执行的内容, 我们可以修改对应的Target本身; 如果调整几个Target的执行顺序, 那么我们可以修改它们的DependsOnTargets属性. 不管是修改Target本身还是它的DependsOnTargets属性, 我们修改的场所都是tfsbuild.proj文件. 值得强调的一点, MSbuild 只认识Target的名字(name属性), 或者DependsOnTargets属性指向的那个属性组的名字(PropertyGroup Name). 所谓重写, 就是相同名字的Target或者属性在tfsbuild.proj和Microsoft.TeamFoundation.Build.targets文件里的不同实现. MSbuild依赖于这些来构建生成流程. 如果您只想修改一个Target的执行条件, 那么最好不要修改这个Target的名字, 否则您得负责把这个改过名字的Target重新加入到生成流程的合适位置, 因为MSbuild不会记得它就是原来那个未修改的Target.

      下面我们分类根据Team Build写几个具体的例子来讲述怎么完成重写.

 

添加新的Target

      向默认的生成流程中添加新的生成目标, 首先需要一个写好的Target, 可以写在TFSBuild.proj文件里, 也可以在TFSBuild.proj文件中使用import标记引入定义在别处的Target. 比如, 我们在使用AssemblyInfo Task的时候, 直接将一个现成的Target拷贝到TFSBuild.proj文件里:

  • <!-- The target that acutally does all the work. The inputs are the same as the CoreCompileDependsOn target
  • (with the addition of @(AssemblyInfoFiles) to ensure that we only ever update the AssemblyInfo files if a
  • compile is actually going to take place. The outputs are the AssemblyInfoFiles that were passed in for update. -->
  • <Target Name="UpdateAssemblyInfoFiles"
  •         Inputs="$(MSBuildAllProjects);
  •               @(Compile);
  •               @(ManifestResourceWithNoCulture);
  •               $(ApplicationIcon);
  •               $(AssemblyOriginatorKeyFile);
  •               @(ManifestNonResxWithNoCultureOnDisk);
  •               @(ReferencePath);
  •               @(CompiledLicenseFile);
  •               @(EmbeddedDocumentation);                
  •               @(CustomAdditionalCompileInputs);
  •               @(AssemblyInfoFiles)"
  •         Outputs="@(AssemblyInfoFiles);@(IntermediateAssembly)">
  •   <AssemblyInfo AssemblyInfoFiles="@(AssemblyInfoFiles)"
  •                 AssemblyMajorVersion="$(AssemblyMajorVersion)"
  •                 AssemblyMinorVersion="$(AssemblyMinorVersion)"
  •                 AssemblyBuildNumber="$(AssemblyBuildNumber)"
  •                 AssemblyRevision="$(AssemblyRevision)"
  •                 AssemblyBuildNumberType="$(AssemblyBuildNumberType)"
  •                 AssemblyBuildNumberFormat="$(AssemblyBuildNumberFormat)"
  •                 AssemblyRevisionType="$(AssemblyRevisionType)"
  •                 AssemblyRevisionFormat="$(AssemblyRevisionFormat)"
  •                 AssemblyFileMajorVersion="$(AssemblyFileMajorVersion)"
  •                 AssemblyFileMinorVersion="$(AssemblyFileMinorVersion)"
  •                 AssemblyFileBuildNumber="$(AssemblyFileBuildNumber)"
  •                 AssemblyFileRevision="$(AssemblyFileRevision)"
  •                 AssemblyFileBuildNumberType="$(AssemblyFileBuildNumberType)"
  •                 AssemblyFileBuildNumberFormat="$(AssemblyFileBuildNumberFormat)"
  •                 AssemblyFileRevisionType="$(AssemblyFileRevisionType)"
  •                 AssemblyFileRevisionFormat="$(AssemblyFileRevisionFormat)"
  •                 ComVisible="$(AssemblyComVisible)"
  •                 AssemblyGuid="$(AssemblyGuid)"
  •                 AssemblyCompany="$(AssemblyCompany)"
  •                 AssemblyConfiguration="$(AssemblyConfiguration)"
  •                 AssemblyCopyright="$(AssemblyCopyright)"
  •                 AssemblyCulture="$(AssemblyCulture)"
  •                 AssemblyDescription="$(AssemblyDescription)"
  •                 AssemblyProduct="$(AssemblyProduct)"
  •                 AssemblyTitle="$(AssemblyTitle)"
  •                 AssemblyIncludeSigningInformation="$(AssemblyIncludeSigningInformation)"
  •                 AssemblyDelaySign="$(AssemblyDelaySign)"
  •                 AssemblyKeyFile="$(AssemblyKeyFile)"
  •                 AssemblyKeyName="$(AssemblyKeyName)">
  •     <Output TaskParameter="MaxAssemblyVersion" PropertyName="MaxAssemblyVersion"/>
  •     <Output TaskParameter="MaxAssemblyFileVersion" PropertyName="MaxAssemblyFileVersion"/>
  •   </AssemblyInfo>
  • </Target>
  • 相关文章:

    • 2021-12-26
    • 2021-08-11
    • 2021-09-28
    • 2021-05-23
    • 2021-08-13
    • 2021-05-31
    • 2021-10-07
    • 2022-12-23
    猜你喜欢
    • 2022-01-11
    • 2021-06-26
    • 2021-04-13
    • 2021-09-29
    • 2021-06-22
    相关资源
    相似解决方案