//====== Copyright 1996-2005, Valve Corporation, All rights reserved. ======= // // Purpose: // //============================================================================= #include "vpc.h" #include "dependencies.h" #include "utlgraph.h" class CSolutionGenerator_CodeLite : public IBaseSolutionGenerator { public: CSolutionGenerator_CodeLite() { m_nIndent = 0; m_fp = NULL; } virtual void GenerateSolutionFile( const char *pSolutionFilename, CUtlVector &projects ) { char szSolutionName[MAX_PATH]; V_FileBase( pSolutionFilename, szSolutionName, MAX_PATH ); char szSolutionFileBaseName[MAX_PATH]; // Default extension. char szTmpSolutionFilename[MAX_PATH]; if ( !V_GetFileExtension( pSolutionFilename ) ) { V_strncpy( szSolutionFileBaseName, pSolutionFilename, sizeof( szSolutionFileBaseName ) ); V_snprintf( szTmpSolutionFilename, sizeof( szTmpSolutionFilename ), "%s.workspace", pSolutionFilename ); pSolutionFilename = szTmpSolutionFilename; } else { V_StripExtension( pSolutionFilename, szSolutionFileBaseName, sizeof( szSolutionFileBaseName ) ); } Msg( "\nWriting CodeLite workspace %s.\n\n", pSolutionFilename ); // Write the file. m_fp = fopen( pSolutionFilename, "wt" ); if ( !m_fp ) g_pVPC->VPCError( "Can't open %s for writing.", pSolutionFilename ); Write( "\n" ); Write( "\n", szSolutionName, szSolutionFileBaseName ); ++m_nIndent; Write( "\n", szSolutionFileBaseName); for ( int i=0; i < projects.Count(); i++ ) { CDependency_Project *pCurProject = projects[i]; project_t *pProjectT = &g_pVPC->m_Projects[ pCurProject->m_iProjectIndex ]; char szProjectFileBaseName[MAX_PATH]; V_StripExtension( pCurProject->m_ProjectFilename.String(), szProjectFileBaseName, sizeof( szProjectFileBaseName ) ); Write( "\n", pProjectT->name.String(), szProjectFileBaseName ); } Write( "\n" ); ++m_nIndent; Write( "\n" ); ++m_nIndent; Write( "\n" ); for ( int i=0; i < projects.Count(); i++ ) { CDependency_Project *pCurProject = projects[i]; project_t *pProjectT = &g_pVPC->m_Projects[ pCurProject->m_iProjectIndex ]; Write( "\n", pProjectT->name.String() ); } --m_nIndent; Write( "\n" ); Write( "\n" ); ++m_nIndent; Write( "\n" ); for ( int i=0; i < projects.Count(); i++ ) { CDependency_Project *pCurProject = projects[i]; project_t *pProjectT = &g_pVPC->m_Projects[ pCurProject->m_iProjectIndex ]; Write( "\n", pProjectT->name.String() ); } --m_nIndent; Write( "\n" ); --m_nIndent; Write( "\n" ); --m_nIndent; Write( "\n" ); fclose( m_fp ); WriteBuildOrderProject( szSolutionFileBaseName, projects ); } void WriteBuildOrderProject( const char *pszSolutionFileBaseName, CUtlVector &projects ) { // write out a project with no files to encode the build order (dependencies) char szProjectFileName[MAX_PATH]; V_snprintf( szProjectFileName, sizeof( szProjectFileName ), "%s.project", pszSolutionFileBaseName ); m_nIndent = 0; m_fp = fopen( szProjectFileName, "wt" ); if ( !m_fp ) g_pVPC->VPCError( "Can't open %s for writing.", szProjectFileName ); Write( "\n" ); Write( "\n" ); { ++m_nIndent; Write( "\n" ); Write( "\n" ); Write( "\n" ); { ++m_nIndent; Write( "\n" ); ++m_nIndent; Write( "\n" ); ++m_nIndent; Write( "\n" ); --m_nIndent; Write( "\n" ); Write( "\n" ); ++m_nIndent; Write( "\n" ); --m_nIndent; Write( "\n" ); Write( "\n" ); --m_nIndent; Write( "\n" ); Write( "\n" ); #if 0 ++m_nIndent; Write( "\n" ); ++m_nIndent; Write( "" ); --m_nIndent; --m_nIndent; #endif Write( "\n" ); Write( "\n" ); #if 0 ++m_nIndent; Write( "\n" ); ++m_nIndent; Write( "" ); --m_nIndent; --m_nIndent; #endif Write( "\n" ); --m_nIndent; } Write( "\n" ); --m_nIndent; CUtlGraph dependencyGraph; // walk the project list building a dependency graph for ( int i=0; i < projects.Count(); i++ ) { CDependency_Project *pCurProject = projects[i]; CUtlVector additionalProjectDependencies; ResolveAdditionalProjectDependencies( pCurProject, projects, additionalProjectDependencies ); //project_t *pProjectT = &g_projects[ pCurProject->m_iProjectIndex ]; //printf( "%s depends on\n", pProjectT->name.String() ); for ( int iTestProject=0; iTestProject < projects.Count(); iTestProject++ ) { if ( i == iTestProject ) continue; // do I depend on anyone? CDependency_Project *pTestProject = projects[iTestProject]; int dependsOnFlags = k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse; if ( pCurProject->DependsOn( pTestProject, dependsOnFlags ) || additionalProjectDependencies.Find( pTestProject ) != additionalProjectDependencies.InvalidIndex() ) { // add an edge from this project to the one it depends on dependencyGraph.AddEdge( i, iTestProject, 1 ); //printf( " %s -> %s\n", projects[ i ]->m_ProjectName.String(), // projects[ iTestProject ]->m_ProjectName.String() ); } } } Write( "\n" ); ++m_nIndent; CUtlVector visitedList; for( int i = 0; i < projects.Count(); i++ ) { TraverseFrom( projects, dependencyGraph, visitedList, i ); } --m_nIndent; Write( "\n" ); Write( "\n" ); ++m_nIndent; visitedList.Purge(); for( int i = 0; i < projects.Count(); i++ ) { TraverseFrom( projects, dependencyGraph, visitedList, i ); } --m_nIndent; Write( "\n" ); } Write( "\n" ); fclose( m_fp ); } void TraverseFrom( CUtlVector &projects, CUtlGraph &dependencyGraph, CUtlVector &visitedList, int root ) { CUtlGraphVisitor visitor( dependencyGraph ); if ( visitedList.Find( root ) != visitedList.InvalidIndex() ) return; // this project has no dependencies, just emit it if ( !visitor.Begin( root ) ) { Write( "\n", projects[ root ]->m_ProjectName.String() ); visitedList.AddToTail( root ); return; } // printf( "considering %i (%s)\n", root, projects[ root ]->m_ProjectName.String() ); while ( visitor.Advance() ) { // printf( "%i (%s) depends on %i (%s)\n", root, projects[ root ]->m_ProjectName.String(), visitor.CurrentNode(), projects[ visitor.CurrentNode() ]->m_ProjectName.String() ); TraverseFrom( projects, dependencyGraph, visitedList, visitor.CurrentNode() ); } Write( "\n", projects[ root ]->m_ProjectName.String() ); visitedList.AddToTail( root ); // printf( "emitting %i (%s)\n", root, projects[ root ]->m_ProjectName.String() ); } void ResolveAdditionalProjectDependencies( CDependency_Project *pCurProject, CUtlVector &projects, CUtlVector &additionalProjectDependencies ) { for ( int i=0; i < pCurProject->m_AdditionalProjectDependencies.Count(); i++ ) { const char *pLookingFor = pCurProject->m_AdditionalProjectDependencies[i].String(); int j; for ( j=0; j < projects.Count(); j++ ) { if ( V_stricmp( projects[j]->m_ProjectName.String(), pLookingFor ) == 0 ) break; } if ( j == projects.Count() ) g_pVPC->VPCError( "Project %s lists '%s' in its $AdditionalProjectDependencies, but there is no project by that name in the selected projects.", pCurProject->GetName(), pLookingFor ); additionalProjectDependencies.AddToTail( projects[j] ); } } const char* FindInFile( const char *pFilename, const char *pFileData, const char *pSearchFor ) { const char *pPos = V_stristr( pFileData, pSearchFor ); if ( !pPos ) g_pVPC->VPCError( "Can't find ProjectGUID in %s.", pFilename ); return pPos + V_strlen( pSearchFor ); } void Write( const char *pMsg, ... ) { char sOut[8192]; va_list marker; va_start( marker, pMsg ); V_vsnprintf( sOut, sizeof( sOut ), pMsg, marker ); va_end( marker ); for ( int i=0; i < m_nIndent; i++ ) fprintf( m_fp, " " ); fprintf( m_fp, "%s", sOut ); } FILE *m_fp; int m_nIndent; }; static CSolutionGenerator_CodeLite g_SolutionGenerator_CodeLite; IBaseSolutionGenerator* GetSolutionGenerator_CodeLite() { return &g_SolutionGenerator_CodeLite; }