Click here to Skip to main content
15,888,984 members
Articles / Programming Languages / C#

Tool for Converting VC++2005 Project to Linux Makefile

Rate me:
Please Sign up or sign in to vote.
4.86/5 (69 votes)
13 Jul 2012CPOL6 min read 2.2M   12.7K   160  
Convert .sln/.vcproj (VC++2005) to Linux makefile
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

namespace sln2mak
{
    class VcSlnInfo
    {
        #region Members
        /****************************************************************/
        private string                              m_MainProjectName       ;
        private string                              m_SlnFullPath           ;
        private Dictionary<string, string>          m_ProjGuidName          ;
        private Dictionary<string, string>          m_ProjNamePath          ;
        private Dictionary<string, string>          m_ProjMakFilePath       ;
        private Dictionary<string, string[]>        m_ProjDependencies      ;
        Dictionary<string, string>.KeyCollection    m_ProjPathCollection    ;
        private string                              m_MakefileFullPath      ;
        private StreamWriter                        m_MakefileWriter        ;        
        /****************************************************************/
        #endregion /* Members */

        #region LifeCycle
        /****************************************************************/
        /// <summary>
        /// Use this constructor when parsing .sln file
        /// </summary>
        /// <param name="MainProjName"></param>
        /// <param name="SlnFileName"></param>
        public VcSlnInfo (string MainProjName , string SlnFileName)
        {
            m_MainProjectName   = MainProjName  ;
            m_SlnFullPath       = SlnFileName   ;
            if (!(Path.GetDirectoryName(m_SlnFullPath).Equals("")))
            {
                m_MakefileFullPath = Path.GetDirectoryName(m_SlnFullPath) + "/Makefile";
            }
            else
            {
                m_MakefileFullPath = "Makefile";
            }

            Console.WriteLine("Creating file " + m_MakefileFullPath + "...");
            m_MakefileWriter    = new StreamWriter(m_MakefileFullPath) ;

            m_ProjGuidName      = new Dictionary<string, string>   () ;
            m_ProjNamePath      = new Dictionary<string, string>   () ;
            m_ProjMakFilePath   = new Dictionary<string, string>   () ;
            m_ProjDependencies  = new Dictionary<string, string[]> () ;            

            m_MakefileWriter.WriteLine ("# Makefile - {0}" , m_MainProjectName) ;
            m_MakefileWriter.WriteLine (                                      ) ;

            iInitDictionariesFromSlnFile () ;
        }

        /// <summary>
        /// Use this constructor when parsing .vcproj list of file and then creating Makefile
        /// </summary>
        /// <param name="MainProjName"></param>

        public VcSlnInfo (string MainProjNameFullPath)
        {
            m_MainProjectName   = Path.GetFileNameWithoutExtension(MainProjNameFullPath)    ;
            m_SlnFullPath       = ""                                                        ;
            if (Path.GetDirectoryName(MainProjNameFullPath).Equals(""))
            {
                m_MakefileFullPath = Path.GetDirectoryName(MainProjNameFullPath) + "/Makefile";
            }
            else
            {
                m_MakefileFullPath = "Makefile";
            }

            m_MakefileWriter    = new StreamWriter(m_MakefileFullPath) ;

            m_ProjGuidName      = new Dictionary<string , string>   () ;
            m_ProjNamePath      = new Dictionary<string , string>   () ;
            m_ProjMakFilePath   = new Dictionary<string , string>   () ;
            m_ProjDependencies  = new Dictionary<string , string[]> () ;

            m_MakefileWriter.WriteLine ("# Makefile - {0}", m_MainProjectName) ;
            m_MakefileWriter.WriteLine (                                     ) ;            
        }
        /****************************************************************/
        #endregion /* LifeCycle */

        #region Private Operations
        /****************************************************************/
        /// <summary>
        /// Parse sln and initialize dictionaries with projects names, pathes and makefile names
        /// </summary>        
        private void iInitDictionariesFromSlnFile ()
        {
            StreamReader    sr              ;
            Match           matchProjInfo   ;
            String          vcprojPath      ;
            String          makeFileName    ;
            string          line            ;


            sr = new StreamReader (m_SlnFullPath) ;


            //Find all .vcpoj files in .sln and add their info to dictionaries
            while ((line = sr.ReadLine()) != null)
            {
                matchProjInfo = Parser.ProjectRegex.Match(line);
                if (matchProjInfo.Success)
                {
                    //Key = Guid number, Value = ProjectName
                    m_ProjGuidName.Add(matchProjInfo.Groups[4].Value, matchProjInfo.Groups[2].Value);

                    //replace slashes for matching Linux OS
                    vcprojPath = matchProjInfo.Groups[3].Value.Replace("\\", "/");
                    //Key = ProjectName , Value = ProjectFullPath
                    m_ProjNamePath.Add(matchProjInfo.Groups[2].Value, vcprojPath);

                    //replace .vcproj extention to .mak for makefile name
                    makeFileName = vcprojPath;

                    makeFileName = makeFileName.Replace(".vcproj", ".mak");
                    // If we run with full path to .sln file...
                    if (!(Path.GetDirectoryName(m_SlnFullPath).Equals(""))) 
                    {
                        // Add full path to .mak file to dictionary
                        // to make possible to create it.
                        // Beginning of the path will be deleted before write to Makefile.
                        makeFileName = Path.GetDirectoryName(m_SlnFullPath) + "\\" + makeFileName;
                        makeFileName = makeFileName.Replace("\\", "/");
                    }

                    //Key = ProjectName , Value = MakeFileName
                    m_ProjMakFilePath.Add(matchProjInfo.Groups[2].Value, makeFileName);

                }

                if (line.StartsWith("Global"))
                {
                    sr.Close();
                    break;
                };
            }

            m_ProjPathCollection = m_ProjNamePath.Keys;

            foreach (string projectName in m_ProjPathCollection)
            {
                string[] dependencies = iInitProjectDependenciesFromSlnFile (projectName) ;
                m_ProjDependencies.Add(projectName, dependencies);
            }
        }

        /// <summary>
        /// Initialize solution(sln) dependencies
        /// </summary>
        private string[] iInitProjectDependenciesFromSlnFile( String projectName)
        {
            StreamReader sr;
            Regex regGuid;
            Match matchProjInfo;
            string line;
            String dependencies = "";


            //read file again from the start
            sr = new StreamReader(m_SlnFullPath);

            regGuid = new Regex(@"(.*)\{(.*)\} = \{(.*)\}");

            //create dependencies for the main project - projName            
            while ((line = sr.ReadLine()) != null)
            {
                matchProjInfo = Parser.ProjectRegex.Match(line);

                if (matchProjInfo.Success)
                {
                    if (matchProjInfo.Groups[2].Value.Equals(projectName))     //main project
                    {
                        //read main project dependencies within 'ProjectDependencies' section
                        if ((line = sr.ReadLine()).Equals("\tProjectSection(ProjectDependencies) = postProject"))
                        {
                            while (!(line = sr.ReadLine()).Equals("\tEndProjectSection"))
                            {
                                Match matchGuid = regGuid.Match(line);
                                //add main project dependencies to projDependencies string
                                if (matchGuid.Success)
                                {
                                    dependencies += m_ProjGuidName[matchGuid.Groups[2].Value] + " ";
                                }
                            }
                        }
                    }
                }
            }
            sr.Close();

            //return string array with split solution(sln) dependencies (no empty entries, delimiter is ' ')            
            return (dependencies.Split(new Char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
        }

        /// <summary>
        /// Print the default target rule --PHONY:all
        /// first for secondary(depended projects) then for main one
        /// </summary>
        /// <param name="projName">main project name</param>
        /// <param name="sw">StreamWriter pointer to Makefile</param>
        /// <param name="keyColl">Collection of project names</param>
        /// <param name="slnDependencies">main project dependencies</param>
        private void iPrintDefaultTargetRule ()
        {
            m_MakefileWriter.WriteLine(".PHONY: all");
            m_MakefileWriter.WriteLine("all: \\");

            //Print the default target rule
            //First add depended projects 
            foreach (string projectName in m_ProjPathCollection)
            {
                for (int d = 0; d < m_ProjDependencies[m_MainProjectName].Length; d++)
                {
                    if ((!(m_MainProjectName.Equals(projectName)                    )) &&
                        (projectName.Equals(m_ProjDependencies[m_MainProjectName][d]))   )
                    {
                        m_MakefileWriter.WriteLine(" \t{0} \\", projectName);
                    }
                }
            }

            //Then add main project_name to makefile
            foreach (string projectName in m_ProjPathCollection)
            {
                if (m_MainProjectName.Equals(projectName))
                {
                    m_MakefileWriter.WriteLine(" \t{0}", projectName);
                }
            }
            m_MakefileWriter.WriteLine();
            m_MakefileWriter.WriteLine();
        }
        
        /// <summary>
        /// Print the rules for each project target
        /// </summary>      
        private void iPrintTargetRules()
        {
            int j = 0;

            //Print the rules for main project first
            foreach (string projectName in m_ProjPathCollection)
            {
                if (m_MainProjectName.Equals(projectName))
                {
                    m_MakefileWriter.WriteLine(".PHONY: {0}", projectName);

                    int k = 0;
                    String pd_tmp = "";

                    for (int d = 0; d < m_ProjDependencies[m_MainProjectName].Length; d++)
                    {

                        pd_tmp = pd_tmp + " " + m_ProjDependencies[m_MainProjectName][d];
                        k++;                        
                    }

                    m_MakefileWriter.WriteLine("{0}:{1}", projectName, pd_tmp);

                    if (!(m_ProjMakFilePath[projectName].Equals("")))
                    {
                        Int32 stripStart = Path.GetDirectoryName(m_SlnFullPath).Length + 1;
                        Int32 stripLength = m_ProjMakFilePath[projectName].Length - stripStart - 4 - projectName.Length;
                        String projMakFilePath = m_ProjMakFilePath[projectName].Substring(stripStart, stripLength);
                        m_MakefileWriter.WriteLine("\tcd {0} && $(MAKE) -f {1}", projMakFilePath, projectName + ".mak");
                    }
                    m_MakefileWriter.WriteLine();
                }

            }
            //Print the rules for depended projects 
            foreach (string projectName in m_ProjPathCollection)
            {
                String pd_tmp = "";

                if (!(m_MainProjectName.Equals(projectName)))
                {
                    for (int k = 0; k < m_ProjDependencies[projectName].Length ; k++)
                    {
                        pd_tmp = pd_tmp + " " + m_ProjDependencies[projectName][k];
                    }                        

                    m_MakefileWriter.WriteLine(".PHONY: {0}", projectName);
                    m_MakefileWriter.WriteLine("{0}:{1}", projectName, pd_tmp /*m_ProjDependencies[projectName]*/);

                    if (!(m_ProjMakFilePath[projectName].Equals("")))
                    {
                        Int32 stripStart = Path.GetDirectoryName(m_SlnFullPath).Length + 1;
                        Int32 stripLength = m_ProjMakFilePath[projectName].Length - stripStart - 4 - projectName.Length;
                        String projMakFilePath = m_ProjMakFilePath[projectName].Substring(stripStart, stripLength);
                        m_MakefileWriter.WriteLine("\tcd {0} && $(MAKE) -f {1}", projMakFilePath, projectName+".mak");
                    }
                    m_MakefileWriter.WriteLine();
                }
                j++;
            }
        }

        /// <summary>
        /// Print the 'clean' or 'depends' target rule first for main project, then for all depended projects
        /// </summary>
        /// <param name="projName">main project name</param>
        /// <param name="sw">StreamWriter pointer to Makefile</param>
        /// <param name="keyColl">Collection of project names</param>
        /// <param name="mainProjDependencies">main project dependencies</param>
        private void iPrintClenOrDependsRules(string ruleString)
        {
            m_MakefileWriter.WriteLine(".PHONY: {0}", ruleString);
            m_MakefileWriter.WriteLine("{0}:", ruleString);

            //Print the 'depends' target rule for main project first
            foreach (string projectName in m_ProjPathCollection)
            {

                if (projectName.Equals(m_MainProjectName))
                {
                    if (!(m_ProjMakFilePath[m_MainProjectName].Equals("")))
                    {
                        Int32 stripStart = Path.GetDirectoryName(m_SlnFullPath).Length + 1;
                        Int32 stripLength = m_ProjMakFilePath[projectName].Length - stripStart - 4 - projectName.Length;
                        String projMakFilePath = m_ProjMakFilePath[m_MainProjectName].Substring(stripStart, stripLength);
                        m_MakefileWriter.WriteLine("\tcd {0} && $(MAKE) -f {1} {2}", projMakFilePath, m_MainProjectName + ".mak", ruleString);
                    }
                }
            }

            //Print the 'depends' target rule for depended projects 
            foreach (string projectName in m_ProjPathCollection)
            {
                if (!(m_MainProjectName.Equals(projectName)))
                {
                    for (int d = 0; d < m_ProjDependencies[m_MainProjectName].Length; d++)
                    {
                        if (!(m_ProjMakFilePath[projectName].Equals("")))
                        {
                            Int32 stripStart = Path.GetDirectoryName(m_SlnFullPath).Length + 1;
                            Int32 stripLength = m_ProjMakFilePath[projectName].Length - stripStart - 4 - projectName.Length;
                            String projMakFilePath = m_ProjMakFilePath[projectName].Substring(stripStart, stripLength);
                            m_MakefileWriter.WriteLine("\tcd {0} && $(MAKE) -f {1} {2}", projMakFilePath, projectName + ".mak", ruleString);
                        }
                    }
                }
            }
            m_MakefileWriter.WriteLine();
        }

        /// <summary>
        /// Call to ParseVsproj for all vcproj files in sln: main and main's depended projects
        /// </summary>
        private void iSendToParseVcprojFiles()
        {
            VcProjInfo vcProjInfo;



            // parse main project file.vcproj
            foreach (string projectName in m_ProjPathCollection)
            {
                if (projectName.Equals(m_MainProjectName))
                {
                    if (!(m_ProjMakFilePath[projectName].Equals("")))
                    {
                        if (Path.GetDirectoryName(m_SlnFullPath).Equals(""))
                        {
                            vcProjInfo = new VcProjInfo(m_ProjNamePath[projectName], m_ProjMakFilePath[projectName], m_ProjDependencies[projectName]);
                            vcProjInfo.ParseVcproj();
                        }
                        else
                        {
                            vcProjInfo = new VcProjInfo(Path.GetDirectoryName(m_SlnFullPath).Replace("\\", "/") + "\\" + m_ProjNamePath[projectName], m_ProjMakFilePath[projectName], m_ProjDependencies[projectName]);
                            vcProjInfo.ParseVcproj();
                        }
                    }
                }
            }

            // parse depended project files
            foreach (string projectName in m_ProjPathCollection)
            {

                for (int d = 0; d < m_ProjDependencies[m_MainProjectName].Length; d++)
                {
                    if ((!(m_MainProjectName.Equals(projectName)                    )) &&
                        (projectName.Equals(m_ProjDependencies[m_MainProjectName][d]))    )
                    {
                        if (!(m_ProjMakFilePath[projectName].Equals("")))
                        {                            
                            if (Path.GetDirectoryName(m_SlnFullPath).Equals(""))
                            {
                                vcProjInfo = new VcProjInfo(m_ProjNamePath[projectName], m_ProjMakFilePath[projectName], m_ProjDependencies[projectName]/*dependencies*/);
                                vcProjInfo.ParseVcproj();
                            }
                            else
                            {
                                vcProjInfo = new VcProjInfo(Path.GetDirectoryName(m_SlnFullPath).Replace("\\", "/") + "/" + m_ProjNamePath[projectName], m_ProjMakFilePath[projectName], m_ProjDependencies[projectName]/*dependencies*/);
                                vcProjInfo.ParseVcproj();
                            }

                        }
                    }
                }
            }
        }
        
        /****************************************************************/
        #endregion /* Private Operations */

        #region Public Operations
        /****************************************************************/
        /// <summary>
        /// Generates Makefile, call GenerateMakefile with true value
        /// It useful in case there is need in vcproj parsing. 
        /// Actually when application called with .sln argument
        /// this function will be called by parser
        /// </summary>
        public void GenerateMakefile ()
        {
            GenerateMakefile(true);
        }
        /// <summary>
        /// Generates Makefile, in case parseVcproj is true .vcproj parsing required
        /// </summary>
        /// <param name="parseVcproj">flag indicates if vcproj files should be parsed or not</param>
        public void GenerateMakefile (bool parseVcproj)
        {
            iPrintDefaultTargetRule  (         ) ;  //PHONY:all          
            iPrintTargetRules        (         ) ;  //PHONY:target
            iPrintClenOrDependsRules ("clean"  ) ;  //PHONY:clean
            iPrintClenOrDependsRules ("depends") ;  //PHONY:depends

            if (true == parseVcproj)
            {
                iSendToParseVcprojFiles  () ;
            }
            
            m_MakefileWriter.Close () ;
        }

        /// <summary>
        /// Initialize dictionaries with projects names, pathes and makefile names
        /// from previous parsing of .vcproj files list
        /// </summary>        
        public void InitDictionaries(Dictionary<string, string> projectNameGuid, string[] mainProjectDependencies)
        {
            string  makeFileName = "" ;
            int     numOfProject = 0  ;
            string  mainProjectFullPath = "";
           
            //Key = Guid number, Value = ProjectName
            m_ProjGuidName = projectNameGuid;

            Dictionary<string, string>.ValueCollection projectCollection= projectNameGuid.Values;

            foreach (string projectFullPath in projectCollection)
            {
                string projectName = Path.GetFileNameWithoutExtension(projectFullPath);

                if (0 != numOfProject)
                {
                    //Key = ProjectName , Value = ProjectFullPath
                    m_ProjNamePath.Add(projectName , projectFullPath);

                    //replace .vcproj extention to .mak for makefile name                    
                    makeFileName = projectFullPath.Replace(".vcproj", ".mak");  
                    makeFileName = makeFileName.Replace("\\", "/");

                    //Key = ProjectName , Value = MakeFileName
                    m_ProjMakFilePath.Add(projectName, makeFileName);

                    string[] dependencies = new string[0];
                    m_ProjDependencies.Add(projectName, dependencies);
                }
                else
                {
                    mainProjectFullPath = projectFullPath;

                    //Key = ProjectName , Value = ProjectFullPath
                    m_ProjNamePath.Add(projectName, projectFullPath);

                    //replace .vcproj extention to .mak for makefile name 
                    makeFileName = projectFullPath.Replace(".vcproj", ".mak");
                    makeFileName = makeFileName.Replace("\\", "/");

                    //Key = ProjectName , Value = MakeFileName
                    m_ProjMakFilePath.Add(projectName, makeFileName);

                    m_ProjDependencies.Add(projectName, mainProjectDependencies);
                }
                numOfProject++;
            }           
                                                     
            m_ProjPathCollection = m_ProjNamePath.Keys;            
        }

        /****************************************************************/
        #endregion /* Public Operations */

        #region Access Operations
        /****************************************************************/
        public Dictionary<string, string>.KeyCollection ProjectPathCollection  
        { 
            get {return m_ProjPathCollection;}
        }
        /****************************************************************/
        #endregion /* Access Operations */
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer EFC Real Solutions on Time,LTD
Israel Israel
Software developer at EFC Real Solutions on Time,LTD(Israel) in infrastructure team.
Developing Grid computing application for data communication simulations.
Writing Cross-Platform Software (Windows and Linux).

Comments and Discussions