使用Microsoft.Build.Evaluation

时间:2015-08-01 08:20:26

标签: visual-studio-2013 msbuild

我正在使用小型C#控制台应用程序中的Microsoft.Build.Evaluation工具对csproj文件进行一些内省和分析。我想找到参考项目的实际位置,使用与MSBuild本身相同的启发式方法,即here描述的位置。我正准备将构建工件自动转换为包,类似于JetBrains博客上列出的内容here

我能找到的唯一例子是HintPath是正确的,例如this project,我知道有些HintPath当前不正确,我不想信任它们。这个项目非常接近我正在尝试做的事情,增加的复杂性是我想使用真正的解析行为来查找依赖项。

我有一个用于我的csproj的Microsoft.Build.Evaluation.Project对象的实例,我看不到任何可用的方法可以为我提供分辨率。我认为我希望的是Reference或ProjectItem的神奇Resolve()方法,有点像this method

我可以通过将自己的搜索限制为此构建系统使用的一组有限输出路径来找到替代方案,但是如果可以的话,我想挂钩到MSBuild。

1 个答案:

答案 0 :(得分:5)

参考分辨率是MSBuild最棘手的部分之一。程序集的定位逻辑是在一组标准任务中实现的: ResolveAssemblyReferenceResolveNativeReference等。逻辑是如何工作非常复杂,你可以看到只是通过查看这些任务的可能参数的数量。

但是,您无需知道查找引用文件位置的确切逻辑。有一些标准目标称为“ResolveAssemblyReferences”,“ResolveProjectReferences”,还有一些更专门用于本机引用,COM引用。这些目标作为正常构建的一部分执行。如果您只是单独执行这些目标,您可以找到返回值,这正是您所需要的。 IDE使用相同的机制来获取引用的位置,用于智能感知,内省等。

以下是如何在代码中执行此操作:

using Microsoft.Build.BuildEngine;
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;
using System;
using System.Collections.Generic;

class Program
{
    static int Main(string[] args)
    {
        if (args.Length < 1)
        {
            Console.WriteLine("Usage: GetReferences.exe <projectFileName>");
            return -1;
        }

        string projectFileName = args[0];

        ConsoleLogger logger = new ConsoleLogger(LoggerVerbosity.Normal);
        BuildManager manager = BuildManager.DefaultBuildManager;

        ProjectInstance projectInstance = new ProjectInstance(projectFileName);
        var result = manager.Build(
            new BuildParameters()
            {
                DetailedSummary = true,
                Loggers = new List<ILogger>() { logger }
            },
            new BuildRequestData(projectInstance, new string[] 
            { 
                "ResolveProjectReferences",
                "ResolveAssemblyReferences"
            }));

        PrintResultItems(result, "ResolveProjectReferences");
        PrintResultItems(result, "ResolveAssemblyReferences");

        return 0;
    }

    private static void PrintResultItems(BuildResult result, string targetName)
    {
        var buildResult = result.ResultsByTarget[targetName];
        var buildResultItems = buildResult.Items;

        if (buildResultItems.Length == 0)
        {
            Console.WriteLine("No refereces detected in target {0}.", targetName);
            return;
        }

        foreach (var item in buildResultItems)
        {
            Console.WriteLine("{0} reference: {1}", targetName, item.ItemSpec);
        }
    }
}

请注意,调用引擎以调用项目中的特定目标。您的项目通常不会构建,但某些目标可能会被先决条件目标调用。

只需编译它并打印所有依赖项的子集。如果对项目使用COM引用或本机依赖项,​​则可能存在更多依赖项。应该很容易修改样本以获得这些。

相关问题