有没有办法问msbuild什么构建目标提供msbuild文件支持?如果在命令提示符下无法执行此操作?可能是以编程方式完成的吗?
除了解析msbuild XML之外,还有办法吗?
当然,MS提供了api,无需自己解析xml.查找microsoft.build.buildengine
改编自msdn上的一些C#代码 ...通常值得探索.需要引用microsoft.build.engine dll才能进行编译.用您的值替换下面的框架版本和路径.这适用于示例项目文件,尽管列表可能比您预期的要长.
using System; using Microsoft.Build.BuildEngine; class MyTargets { static void Main(string[] args) { Engine.GlobalEngine.BinPath = @"C:\Windows\Microsoft.NET\Framework\v2.0.NNNNN"; Project project = new Project(); project.Load(@"c:\path\to\my\project.proj"); foreach (Target target in project.Targets) { Console.WriteLine("{0}", target.Name); } } }
我喜欢使用PowerShell的想法,但纯XML解决方案不起作用,因为它只输出在该项目文件中定义的目标,而不是导入.当然,每个人一直指的C#代码都很简单,而.Net 4.5则是两行(首先你应该考虑添加到你的个人资料中):
Add-Type -As Microsoft.Build New-Object Microsoft.Build.Evaluation.Project $Project | Select -Expand Targets
由于输出非常详细,您可能希望限制您正在查看的内容:
New-Object Microsoft.Build.Evaluation.Project $Project | Select -Expand Targets | Format-Table Name, DependsOnTargets -Wrap
当您加载这样的构建时,GlobalProjectCollection
只要您将PowerShell窗口保持打开状态,它们就会一直存在,并且在卸载它们之前无法重新打开它们.要卸载它们:
[Microsoft.Build.Evaluation.ProjectCollection]::GlobalProjectCollection.UnloadAllProjects()
考虑到这一点,在一个可以接受部分和相对路径甚至管道项目文件作为输入的函数中包装它可能是值得的:
Add-Type -As Microsoft.Build Update-TypeData -DefaultDisplayPropertySet Name, DependsOnTargets -TypeName Microsoft.Build.Execution.ProjectTargetInstance function Get-Target { param( # Path to project file (supports pipeline input and wildcards) [Parameter(ValueFromPipelineByPropertyName=$true, ValueFromPipeline=$true, Position=1)] [Alias("PSPath")] [String]$Project, # Filter targets by name. Supports wildcards [Parameter(Position=2)] [String]$Name = "*" ) begin { # People do funny things with parameters # Lets make sure they didn't pass a Project file as the name ;) if(-not $Project -and $Name -ne "*") { $Project = Resolve-Path $Name if($Project) { $Name = "*" } } if(-not $Project) { $Project = Get-Item *.*proj } } process { Write-Host "Project: $_ Target: $Name" Resolve-Path $Project | % { # Unroll the ReadOnlyDictionary to get the values so we can filter ... (New-Object Microsoft.Build.Evaluation.Project "$_").Targets.Values.GetEnumerator() } | Where { $_.Name -like $Name } } end { [microsoft.build.evaluation.projectcollection]::globalprojectcollection.UnloadAllProjects() } }
而现在你甚至不需要手动格式表...
显然,您可以使用Update-TypeData向输出添加任何内容,例如,如果您想查看条件,或者可能是BeforeTargets或AfterTargets ......
你甚至可以提取嵌套信息.例如,您可以Update-TypeData
使用以下两个替换上面的调用:
Update-TypeData -MemberName CallTargets -MemberType ScriptProperty -Value { $this.Children | ? Name -eq "CallTarget" | %{ $_.Parameters["Targets"] } } -TypeName Microsoft.Build.Execution.ProjectTargetInstance Update-TypeData -DefaultDisplayPropertySet Name, DependsOnTargets, CallTargets -TypeName Microsoft.Build.Execution.ProjectTargetInstance
你看到第一个添加了一个计算的CallTargets属性,它枚举直接子节点并查找CallTarget任务来打印它们的目标,然后我们只包括那个ind DefaultDisplayPropertySet
.
注意:在构建任何特定目标时,要查看将要执行的每个目标需要很多逻辑(为此,我们必须递归处理DependsOnTargets,我们还需要查找在他们的 BeforeTargets或AfterTargets中(也是递归地)具有此目标的任何目标,并且在我们到达实际上只能调用目标的任务之前,例如CallTargets 和MSBuild ......并且所有这些事情都可能依赖于如此复杂的条件没有实际执行它就不可能知道会发生什么;)
已针对.NET Framework 4进行了更新,因为上述内容已被弃用.导入microsoft.build.dll和代码如下:
using System; using Microsoft.Build.Evaluation; class MyTargets { static void Main(string[] args) { Project project = new Project(args[0]); foreach (string target in project.Targets.Keys) { Console.WriteLine("{0}", target); } } }