Как запросить файл MSBUILD для получения списка поддерживаемых целей? - PullRequest
23 голосов
/ 14 января 2009

Можно ли как-нибудь спросить msbuild, какие цели сборки обеспечивали поддержку файла msbuild? Если нет способа сделать это в командной строке? Может быть, это можно сделать программно?

Нет ли способа сделать это, кроме синтаксического анализа msbuild XML?

Ответы [ 6 ]

18 голосов
/ 27 января 2009

Конечно, MS предоставляет API для этого, не разбирая xml самостоятельно. Посмотрите на microsoft.build.buildengine

Адаптировано из некоторого кода C # , найденного в msdn ... обычно его стоит изучить. Для компиляции необходимо обратиться к dll microsoft.build.engine. Замените версию фреймворка и путь ниже вашими значениями. Это сработало для файла примера проекта, хотя список может быть длиннее, чем вы ожидаете.

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);
    }
  }
}
17 голосов
/ 07 августа 2014

Мне понравилась идея использования 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 для печати их целей, а затем мы просто включаем это в DefaultDisplayPropertySet.

ПРИМЕЧАНИЕ: Вдобавок к этому потребовалось бы много логики, чтобы увидеть каждую цель , которая будет выполнена при создании какой-либо конкретной цели (для этого мы бы необходимо рекурсивно обрабатывать DependsOnTargets, и нам также нужно искать любые цели с этой целью в их BeforeTargets или AfterTargets (также рекурсивно), и это до того, как мы перейдем к задачам которые на самом деле могут просто вызывать цели, такие как CallTargets и MSBuild ... и все эти вещи могут зависеть от таких сложных условий, что невозможно сказать, что произойдет, не выполняя их на самом деле ;)

10 голосов
/ 31 марта 2012

Обновлено для .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);
    }
  }
}
2 голосов
/ 17 октября 2012

Я предлагаю вам использовать PowerShell:

Select-Xml `
    -XPath //b:Target `
    -Path path-to-build-file `
    -Namespace @{ b = 'http://schemas.microsoft.com/developer/msbuild/2003' } |
    Select-Object -ExpandProperty Node |
    Format-Table -Property Name, DependsOnTargets -AutoSize

Запрос XPath найдет все элементы Target и отобразит имя цели и зависимости в табличном формате. Вот пример, который выбирает 10 первых целей из Microsoft.Web.Publishing.targets:

PS C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web> Select-Xml `
    -XPath //b:Target `
    -Path Microsoft.Web.Publishing.targets `
    -Namespace @{ b = 'http://schemas.microsoft.com/developer/msbuild/2003' } |
    Select-Object -ExpandProperty Node |
    Sort-Object -Property Name |
    Select-Object -First 10 |
    Format-Table -Property Name, DependsOnTargets -AutoSize

Name                                    DependsOnTargets                       
----                                    ----------------                       
_CheckPublishToolsUpToDate                                                     
_CheckRemoteFx45                                                               
_CleanWPPIfNeedTo                                                              
_DetectDbDacFxProvider                                                         
_WPPCopyWebApplication                  $(_WPPCopyWebApplicationDependsOn)     
AddContentPathToSourceManifest          $(AddContentPathToSourceManifestDepe...
AddDeclareParametersItems               $(AddDeclareParametersItemsDependsOn)  
AddDeclareParametersItemsForContentPath $(AddDeclareParametersItemsForConten...
AddDeclareParametersItemsForIis6        $(AddDeclareParametersItemsForIis6De...
AddDeclareParametersItemsForIis7        $(AddDeclareParametersItemsForIis7De...
0 голосов
/ 27 марта 2019

Если вы строите из командной строки, вы можете сгенерировать файл метапроекта, установив переменную среды перед сборкой. Этот файл детализирует все, на что будет нацелен файл решения, а также обрисовывает их целевой порядок.

Это не совсем удобный для чтения файл диагностики, но он содержит всю информацию, которая вам, вероятно, нужна в формате XML.

например. от CMD и типичной установки VS2017; замените строку 1 любым используемым вами сборщиком инструментов загрузки

call "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Enterprise\Common7\Tools\VsDevCmd.bat"
set MSBuildEmitSolution=1
call MSBuild SolutionFile.sln /t:rebuild   

В качестве реального примера я создал файл SLN, начиная с проекта C # с именем mixed_proj, поэтому у меня есть mixed_proj.sln, mixed_proj.csproj, затем два проекта C ++, которые я добавил, ConsoleApplication1 DLL1.

Я установил порядок зависимости сборки, где ConsoleApplication1 собирается только после DLL1

Вот командная строка для его построения:

call "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Enterprise\Common7\Tools\VsDevCmd.bat"
set MSBuildEmitSolution=1
call MSBuild miced_proj.sln /t:rebuild 

Здесь - содержимое сгенерированного файла метапроекта ( слишком большой, чтобы вставить сюда )

0 голосов
/ 13 апреля 2017

Вот фрагмент кода для получения всех целей в порядке их выполнения.

    static void Main(string[] args)
    {
        Project project = new Project(@"build.core.xml");
        var orderedTargets = GetAllTargetsInOrderOfExecution(project.Targets, project.Targets["FinalTargetInTheDependencyChain"]).ToList();
        File.WriteAllText(@"orderedTargets.txt", orderedTargets.Select(x => x.Name).Aggregate((a, b) => a + "\r\n" + b));
    }

    /// <summary>
    /// Gets all targets in the order of their execution by traversing through the dependent targets recursively
    /// </summary>
    /// <param name="allTargetsInfo"></param>
    /// <param name="target"></param>
    /// <returns></returns>
    public static List<ProjectTargetInstance> GetAllTargetsInOrderOfExecution(IDictionary<string, ProjectTargetInstance> allTargetsInfo, ProjectTargetInstance target)
    {
        var orderedTargets = new List<ProjectTargetInstance>();

        var dependentTargets =
            target
            .DependsOnTargets
            .Split(';')
            .Where(allTargetsInfo.ContainsKey)
            .Select(x => allTargetsInfo[x])
            .ToList();

        foreach (var dependentTarget in dependentTargets)
        {
            orderedTargets = orderedTargets.Union(GetAllTargetsInOrderOfExecution(allTargetsInfo, dependentTarget)).ToList();
        }

        orderedTargets.Add(target);

        return orderedTargets;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...