locked
How to extract build-order from solution? RRS feed

  • Question

  • Hello, All

    I have made VSPackage and own project type. After I have made test solution with several projects and configured build order. Now I want to write code which can extract build order from test solution. How can I do it?

    Thanks
    Thursday, February 11, 2010 5:50 PM

Answers

  • Hello,

    As I know, there is no a way(method/property) to get the Build Order directly, the only one we can get is BuildDependencies:

    EnvDTE.SolutionBuild build = _applicationObject.DTE.Solution.SolutionBuild;

    EnvDTE.BuildDependencies dependencies = build.BuildDependencies;

    string sProj = string.Empty;

    foreach (BuildDependency dependency in dependencies)

    {

        Array prjs = dependency.RequiredProjects as Array;

        foreach (Project prj in prjs)

        {

            sProj += prj.Name;

            sProj += "\n";

        }

    }

    MessageBox.Show(sProj);

    So I'm thinking maybe we could calculate out the build order base on the dependencies:

    1. If there is no dependency between the projects, the build order is the same as the order of projects in solution(up-to-down or down-to-up, it's down-to-up from Solution Explorer), assume this default order is array A.
    2. If the projects has dependencies, all the dependent projects will be move-up to the top of array A according to their position in array A.
    3. So we could get all the dependent projects as above code did, and store them in an array B.
    4. Start from the bottom of array A to check if the current project is a member of array B, if yes, move it to the top of array A, it's to say:

    pCurrent = arrayA.bottom;
    pTop = arrayA.top
    while(pCurrent != pTop)
    {
        if(pCurrent IsMemberOf arrayB)
        {
            pCurrent.ToTop();
        }
        pCurrent--;
    }

    Not sure if it helps.

    Sincerely,
    Wesley


    Please mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Marked as answer by Xaba Xaba Monday, February 15, 2010 5:23 PM
    • Edited by Wesley Yao Tuesday, February 16, 2010 3:47 AM typo
    Monday, February 15, 2010 9:54 AM

All replies

  • Hello,

    As I know, there is no a way(method/property) to get the Build Order directly, the only one we can get is BuildDependencies:

    EnvDTE.SolutionBuild build = _applicationObject.DTE.Solution.SolutionBuild;

    EnvDTE.BuildDependencies dependencies = build.BuildDependencies;

    string sProj = string.Empty;

    foreach (BuildDependency dependency in dependencies)

    {

        Array prjs = dependency.RequiredProjects as Array;

        foreach (Project prj in prjs)

        {

            sProj += prj.Name;

            sProj += "\n";

        }

    }

    MessageBox.Show(sProj);

    So I'm thinking maybe we could calculate out the build order base on the dependencies:

    1. If there is no dependency between the projects, the build order is the same as the order of projects in solution(up-to-down or down-to-up, it's down-to-up from Solution Explorer), assume this default order is array A.
    2. If the projects has dependencies, all the dependent projects will be move-up to the top of array A according to their position in array A.
    3. So we could get all the dependent projects as above code did, and store them in an array B.
    4. Start from the bottom of array A to check if the current project is a member of array B, if yes, move it to the top of array A, it's to say:

    pCurrent = arrayA.bottom;
    pTop = arrayA.top
    while(pCurrent != pTop)
    {
        if(pCurrent IsMemberOf arrayB)
        {
            pCurrent.ToTop();
        }
        pCurrent--;
    }

    Not sure if it helps.

    Sincerely,
    Wesley


    Please mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Marked as answer by Xaba Xaba Monday, February 15, 2010 5:23 PM
    • Edited by Wesley Yao Tuesday, February 16, 2010 3:47 AM typo
    Monday, February 15, 2010 9:54 AM
  • Thanks a lot! I have wrote following class for create build order list:

    class BuildOrder
    {
        private readonly Dictionary<Guid, OAProject> projects = new Dictionary<Guid, OAProject>();
    
        private readonly Dictionary<Guid, List<Guid>> dependencies = new Dictionary<Guid, List<Guid>>();
    
        private readonly List<Guid> buildOrder = new List<Guid>();
    
        public BuildOrder(EnvDTE.Solution solution)
        {
            // Create projects dictionary
            foreach (OAProject project in solution.Projects)
                projects.Add(project.Project.ProjectIDGuid, project);
    
            // Simplified model for project dependencies
            foreach (EnvDTE.BuildDependency buildDependency in solution.SolutionBuild.BuildDependencies)
            {
                var leftProject = (OAProject)buildDependency.Project;
                
                var leftProjectId = leftProject.Project.ProjectIDGuid;
    
                List<Guid> rightProjectIds = new List<Guid>();
                foreach (OAProject requiredProject in (object[]) buildDependency.RequiredProjects)
                    rightProjectIds.Add(requiredProject.Project.ProjectIDGuid);
    
                dependencies.Add(leftProjectId, rightProjectIds);
            }
    
            GenerateBuildOrderList();
        }
    
        private void GenerateBuildOrderList()
        {
            var topProjects = SelectTopProjects();
    
            foreach (Guid topProject in topProjects)
                GenerateBuildOrderList(topProject);
        }
    
        private void GenerateBuildOrderList(Guid project)
        {
            if (buildOrder.Contains(project))
                return;
    
            if (dependencies.ContainsKey(project))
            {
                foreach (var rightProject in dependencies[project])
                    GenerateBuildOrderList(rightProject);
            }
    
            buildOrder.Add(project);
        }
    
        private List<Guid> SelectTopProjects()
        {
            var result = new List<Guid>();
    
            foreach (Guid leftProject in dependencies.Keys)
            {
                bool notContains = true;
                foreach (var rightProjects in dependencies.Values)
                    notContains &= !rightProjects.Contains(leftProject);
    
                if (notContains && !result.Contains(leftProject))
                    result.Add(leftProject);
            }
    
            return result;
        }
    
        public List<OAProject> ProjectsBuildOrder
        {
            get
            {
                var result = new List<OAProject>();
    
                foreach (Guid projectId in buildOrder)
                    result.Add(projects[projectId]);
    
                return result;
            }
        }
    }
    
    Tuesday, February 16, 2010 12:00 PM
  • I don't think this works.

    Say We have Parojecs A, B, and C.  But project A Depends on C.  Correct build order could be CBA, CAB, or BCA

    First Pass:
    A
    B
    C

    C is not in "ArrayB"

    Next Pass:
    A
    B
    C

    B is not in "ArrayB"


    Next Pass:
    A
    B
    C

    A is in "ArrayB", but already at the top.  As you can see the build order doesn't change. 

    I was upset to learn VS SDK didn't expose the build order, then I was excited to find this post, then disappointed again when I couldn't get it to work.  What a roller coaster.  I think I am going to just parse the build output logs to show me the build order.  It seems like a more robust solution than trying to reverse engineer some hidden logic. 

    The code listed in "Xaba Xaba" below did not produce the identical build order of some of my solutions.  It was probably a correct build order, but I need the exact one that VisualStudio will give.
    Thursday, March 11, 2010 12:49 PM
  • This post helped me really. It gave me a good idea how to go with this problem, but this type OAProject got me a litlle bit confused. IF I am not wrong, it should be a selfmade simplified Container for a project with a few properties like Name and Guid (ProjectIDGuid). Or Maybe a more complete version like the EnvDTE.Project-interface

    Or was there a more in depth-thinking going on?

    Best regards from someone trying to get things strait

     :)

    Thursday, July 16, 2020 10:11 AM