Solve actual link path with Microsoft.Build.Evaluation

I am doing some introspection and analysis of csproj files with Microsoft.Build.Evaluation tools in a small C # console application. I want to find the actual location of the Reference elements using the same heuristics as MSBuild itself, i.e. the descriptions described here . I am heading towards auto converting build artifacts to packages, similar to what is described on the JetBrains blog here

The only examples I can find expect HintPath to be correct, such as this project , and I know there are some HintPaths that are not currently correct, I don't want to trust them. This project is very close to what I am trying to do, with an added complication that I want to use for real-resolution behavior to find dependencies.

I have an instance of a Microsoft.Build.Evaluation.Project object for my csproj and I don't see any methods available to it that could accomplish the resolution for me. I think what I hope is the magic Resolve () method for Reference or ProjectItem, a bit like this method .

Perhaps I can find an alternative, limiting my own search to the set of limited output paths used by this assembly, but I would like to connect to MSBuild if I can.

+3


source to share


1 answer


Reference resolution is one of the most difficult parts of MSBuild. The assembly layout logic is implemented within the standard set of tasks: ResolveAssemblyReference , ResolveNativeReference , etc. The logic is this: it works very hard, you can see it just by looking at the number of possible parameters for these tasks.

However, you don't need to know the exact logic to find the location of the linked files. There are standard tasks called "ResolveAssemblyReferences", "ResolveProjectReferences" and a few others that are more specialized for native references, COM references. These goals are accomplished as part of a regular build. If you just perform these goals separately, you can find out the return values ​​that are exactly what you need. The same mechanism is used by the IDE for getting a referee seat, for Intellisense, introspection, etc.

This is how you can do it in code:



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);
        }
    }
}

      

Please note: the engine is called to call specific targets in the project. Usually your project is not created, but some goals can be triggered by the desired goals.

Just compile it and print a subset of all dependencies. There may be more dependencies if you are using COM references or native dependencies for your project. It is also easy to change the pattern to achieve this.

+3


source







All Articles