以编程方式运行MSBuild Task并访问输出

本文关键字:访问 输出 Task MSBuild 编程 方式 运行 | 更新日期: 2023-09-27 18:21:58

我正在尝试运行MSBuild任务,在本例中为ResolveAssemblyReferences,并访问该任务的输出,如ResolvedFiles。下面是加载项目(使用VS2013创建的默认F#项目)并运行任务的简短F#脚本。将日志详细信息设置为Diagnostic后,我可以看到任务成功运行,并正确解析了所有程序集。

#r @"C:'Program Files (x86)'MSBuild'12.0'bin'Microsoft.Build.dll"
#r @"C:'Program Files (x86)'MSBuild'12.0'bin'Microsoft.Build.Framework.dll"
open System
open Microsoft.Build
let p = new Evaluation.Project("d:/dev/fsharptest/Test/Test.fsproj")
let log = Logging.ConsoleLogger()
log.Verbosity <- Framework.LoggerVerbosity.Diagnostic
p.Build([|"ResolveProjectReferences";"ResolveAssemblyReferences"|],
        Seq.singleton (log :> Framework.ILogger) )
for i in p.AllEvaluatedProperties do
  printfn "%s: %s" i.Name i.EvaluatedValue

但是,计算的属性和项都不包含ResolveAssemblyReferences的任何输出,这正是我所追求的。文件Microsoft.Common.CurrentVersion.targets作为ResolveAssemblyReferences <Output TaskParameter="ResolvedFiles" ItemName="ReferencePath"/>的一个输出,但我无法访问此值。

我该怎么处理它?

以编程方式运行MSBuild Task并访问输出

事实证明Evaluation.ProjectExecution.ProjectInstance是相当不同的。我尝试使用前者,但后者最接近于我以前使用的过时的BuildEngine.Project类。以下代码片段返回给定项目文件的完全解析引用:

#r @"C:'Program Files (x86)'MSBuild'12.0'bin'Microsoft.Build.dll"
#r @"C:'Program Files (x86)'MSBuild'12.0'bin'Microsoft.Build.Framework.dll"
open System
open Microsoft.Build
let p = new Execution.ProjectInstance(@"d:'dev'fsharptest'Test'Test.fsproj")
p.Build([|"ResolveReferences"|], new Collections.Generic.HashSet<_>())
for i in p.GetItems("ReferencePath") do
  printfn "%s" i.EvaluatedInclude

事实上,以这种方式可以获得所讨论的目标的任意输出。

我认为问题在于,您最终运行的Task的某些任意Output参数并不是MSBuild任务本身返回的参数。它收集您直接指定的任务的"目标退货"。

然而,我不知道您的语法在这里是如何工作的:您给出的是Task名称而不是Targets?

但根据我所读的内容(Kretzler书中的第37条),您可以定义一个Target来运行所需的Task,并将任务输出连接到目标的Return属性。然后,MSBuild任务被告知运行该目标,它将作为自己的返回属性传递。

我想应该是这样的:

<Target Name="ResolveAssemblyReferences" ⋯
   Returns="@(ReferencePath)" >

因此,如果您从该Target中调用的Task正在填充名为ReferencePath的项数组作为其输出参数,那么您将发布与Target的返回值相同的项数组。

如果在构建脚本中的任何位置都不使用Returns,则Outputs将自动作为返回。

如果你不能编辑ResolveAssemblyReferences,那么我说你可以创建一个依赖于它的新目标。由于ReferencePath在任务完成后是全局的,新目标仍然会看到它们并可以返回它。

如果所有其他操作都失败了,请让您的生成脚本将项列表写入一个文件,然后您可以从其他程序加载该文件,而不必担心MSBuild返回的内容。