【问题标题】:Resolve actual Reference path using Microsoft.Build.Evaluation使用 Microsoft.Build.Evaluation 解析实际参考路径
【发布时间】:2015-08-01 08:20:26
【问题描述】:

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

上概述的内容

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

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

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

【问题讨论】:

    标签: visual-studio-2013 msbuild


    【解决方案1】:

    参考解析是 MSBuild 中最棘手的部分之一。如何定位程序集的逻辑在一组标准任务中实现: ResolveAssemblyReferenceResolveNativeReference 等。其工作原理的逻辑非常复杂,您只需查看这些任务的可能参数数量即可看出这一点。

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

    以下是您可以在代码中执行此操作的方法:

    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 引用或本机依赖项,​​则可能会有更多依赖项。应该很容易修改示例以获取这些示例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-21
      • 2019-01-13
      • 2012-11-20
      • 2017-04-09
      • 2011-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多