Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

240 lines
7.7 KiB

  1. //====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "vpc.h"
  7. #include "p4lib/ip4.h"
  8. // fix filenames that have double backslashes at the start
  9. // (Perforce will return this if the root of a clientspec is e.g. "D:\")
  10. static const char* FixPerforceFilename( const char *filename )
  11. {
  12. if ( filename && Q_strlen( filename ) > 2 && !Q_strnicmp( filename + 1, ":\\\\", 3 ) )
  13. {
  14. // strip out the first backslash
  15. static char newFilename[MAX_PATH];
  16. Q_snprintf( newFilename, sizeof(newFilename), "%c:%s",
  17. filename[0],
  18. &filename[3]
  19. );
  20. return newFilename;
  21. }
  22. return filename;
  23. }
  24. static void GetChangelistFilenames( CUtlVector<int> &changelists, CUtlVector<CUtlString> &changelistFilenames )
  25. {
  26. // P4 interface didn't initalize in main - abort
  27. if ( !p4 )
  28. {
  29. g_pVPC->VPCWarning( "P4SLN: Perforce interface not available. Unable to generate solution from the given Perforce changelist." );
  30. return;
  31. }
  32. CUtlVector<P4File_t> fileList;
  33. int changeListIndex = 0;
  34. if ( changelists.Count() )
  35. {
  36. changeListIndex = changelists[0];
  37. }
  38. if ( changeListIndex == -1 )
  39. {
  40. p4->GetOpenedFileList( fileList, false );
  41. }
  42. else if ( changeListIndex == 0 )
  43. {
  44. p4->GetOpenedFileList( fileList, true );
  45. }
  46. else
  47. {
  48. CUtlVector<P4File_t> partialFileList;
  49. FOR_EACH_VEC( changelists, i )
  50. {
  51. p4->GetFileListInChangelist( changelists[i], partialFileList );
  52. FOR_EACH_VEC( partialFileList, j )
  53. {
  54. fileList.AddToTail( partialFileList[j] );
  55. }
  56. }
  57. }
  58. // If -1 is in the changelist index, then include all.
  59. bool bIncludeAllChangelists = ( changelists.Find( -1 ) != changelists.InvalidIndex() );
  60. for ( int i=0; i < fileList.Count(); i++ )
  61. {
  62. if ( bIncludeAllChangelists || changelists.Find( fileList[i].m_iChangelist ) != changelists.InvalidIndex() )
  63. {
  64. const char *pFilename = p4->String( fileList[i].m_sLocalFile );
  65. const char *pNewFilename = FixPerforceFilename( pFilename );
  66. changelistFilenames.AddToTail( pNewFilename );
  67. }
  68. }
  69. }
  70. static void AddAdditionalDependencies( CUtlVector<CDependency_Project*> &projects, CUtlVector<CDependency_Project*> &allProjects )
  71. {
  72. for ( int nProject=0; nProject < projects.Count(); nProject++ )
  73. {
  74. CDependency_Project *pCurProject = projects[nProject];
  75. // Look at all the $AdditionalProjectDependencies projects for this one.
  76. for ( int nDependency=0; nDependency < pCurProject->m_AdditionalProjectDependencies.Count(); nDependency++ )
  77. {
  78. const char *pLookingFor = pCurProject->m_AdditionalProjectDependencies[nDependency].String();
  79. // Search for a match in allProjects.
  80. int nFound = CDependency_Project::FindByProjectName( allProjects, pLookingFor );
  81. if ( nFound == -1 )
  82. {
  83. g_pVPC->VPCError( "P4SLN: Project %s lists '%s' in its $AdditionalProjectDependencies, but there is no project by that name.", pCurProject->GetName(), pLookingFor );
  84. }
  85. else
  86. {
  87. // Got a match.
  88. CDependency_Project *pFound = allProjects[nFound];
  89. int nTest = projects.Find( pFound );
  90. if ( nTest == projects.InvalidIndex() )
  91. {
  92. projects.AddToTail( pFound );
  93. }
  94. }
  95. }
  96. }
  97. }
  98. static void GetProjectsDependingOnFiles( CProjectDependencyGraph &dependencyGraph, CUtlVector<CUtlString> &filenames, CUtlVector<CDependency_Project*> &projects )
  99. {
  100. // Now figure out the projects that depend on each of these files.
  101. for ( int iFile=0; iFile < filenames.Count(); iFile++ )
  102. {
  103. CDependency *pFile = dependencyGraph.FindDependency( filenames[iFile].String() );
  104. if ( !pFile )
  105. {
  106. char szRelative[MAX_PATH];
  107. if ( !V_MakeRelativePath( filenames[iFile].String(), g_pVPC->GetSourcePath(), szRelative, sizeof( szRelative ) ) )
  108. {
  109. V_strncpy( szRelative, filenames[iFile].String(), sizeof( szRelative ) );
  110. }
  111. // This probably means their build commands on the command line didn't include
  112. // any projects that included this file.
  113. g_pVPC->VPCWarning( "%s is not found in the projects searched.", szRelative );
  114. continue;
  115. }
  116. // Now see which projects depend on this file.
  117. for ( int iProject=0; iProject < dependencyGraph.m_Projects.Count(); iProject++ )
  118. {
  119. CDependency_Project *pProject = dependencyGraph.m_Projects[iProject];
  120. if ( pProject->DependsOn( pFile, k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse | k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckAdditionalDependencies ) )
  121. {
  122. if ( projects.Find( pProject ) == -1 )
  123. projects.AddToTail( pProject );
  124. }
  125. }
  126. }
  127. //
  128. // Make sure that each of the dependent projects are members of the "everything" group
  129. //
  130. // Find the everything group
  131. groupTagIndex_t everythingIndex = VPC_Group_FindOrCreateGroupTag( "everything", false );
  132. if ( everythingIndex != INVALID_INDEX )
  133. {
  134. CUtlVector<int> doomedProjectIndices;
  135. CUtlVector<int> everythingProjectsIndices;
  136. FOR_EACH_VEC( g_pVPC->m_GroupTags[everythingIndex].groups, m )
  137. {
  138. FOR_EACH_VEC( g_pVPC->m_Groups[g_pVPC->m_GroupTags[everythingIndex].groups[m]].projects, n )
  139. {
  140. everythingProjectsIndices.AddToTail( g_pVPC->m_Groups[g_pVPC->m_GroupTags[everythingIndex].groups[m]].projects[n] );
  141. }
  142. }
  143. // Search for each dependency project in the everything group
  144. FOR_EACH_VEC( projects, j )
  145. {
  146. // If it wasn't in the everything group then mark it for removal
  147. if ( everythingProjectsIndices.InvalidIndex() == everythingProjectsIndices.Find( projects[j]->m_iProjectIndex ) )
  148. {
  149. doomedProjectIndices.AddToHead( j );
  150. }
  151. }
  152. // Remove the projects that aren't in the everything solution
  153. FOR_EACH_VEC( doomedProjectIndices, p )
  154. {
  155. projects.Remove( doomedProjectIndices[p] );
  156. }
  157. }
  158. }
  159. static void UpdateProjects( CUtlVector<CDependency_Project*> &projects )
  160. {
  161. for ( int iProject=0; iProject < projects.Count(); iProject++ )
  162. {
  163. Log_Msg( LOG_VPC, "\n" );
  164. CDependency_Project *pDependency = projects[iProject];
  165. pDependency->ExportProjectParameters();
  166. if ( g_pVPC->IsForceGenerate() || !g_pVPC->IsProjectCurrent( g_pVPC->GetOutputFilename() ) )
  167. {
  168. project_t *pProject = &g_pVPC->m_Projects[ pDependency->m_iProjectIndex ];
  169. g_pVPC->SetProjectName( pProject->name.String() );
  170. g_pVPC->SetLoadAddressName( pProject->name.String() );
  171. g_pVPC->ParseProjectScript( pDependency->m_szStoredScriptName, 0, false, true );
  172. }
  173. }
  174. }
  175. void GenerateSolutionForPerforceChangelist( CProjectDependencyGraph &dependencyGraph, CUtlVector<int> &changelists, IBaseSolutionGenerator *pGenerator, const char *pSolutionFilename )
  176. {
  177. // We want to check against ALL projects in projects.vgc.
  178. int nDepFlags = BUILDPROJDEPS_FULL_DEPENDENCY_SET | BUILDPROJDEPS_CHECK_ALL_PROJECTS;
  179. dependencyGraph.BuildProjectDependencies( nDepFlags );
  180. // Get the list of files from Perforce.
  181. CUtlVector<CUtlString> filenames;
  182. GetChangelistFilenames( changelists, filenames );
  183. // Get the list of projects that depend on these files.
  184. CUtlVector<CDependency_Project*> projects;
  185. GetProjectsDependingOnFiles( dependencyGraph, filenames, projects );
  186. // Add g_targetProjects, which will include any other projects that they added on the command line with +tier0 *engine syntax.
  187. CUtlVector<CDependency_Project*> commandLineProjects;
  188. dependencyGraph.TranslateProjectIndicesToDependencyProjects( g_pVPC->m_TargetProjects, commandLineProjects );
  189. for ( int i=0; i < commandLineProjects.Count(); i++ )
  190. {
  191. if ( projects.Find( commandLineProjects[i] ) == projects.InvalidIndex() )
  192. projects.AddToTail( commandLineProjects[i] );
  193. }
  194. // Make sure the latest .vcproj files are generated.
  195. UpdateProjects( projects );
  196. // List the projects.
  197. Msg( "Dependent projects: \n\n" );
  198. for ( int i=0; i < projects.Count(); i++ )
  199. Msg( "%s\n", projects[i]->GetName() );
  200. // Write the solution file.
  201. pGenerator->GenerateSolutionFile( pSolutionFilename, projects );
  202. }