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.

254 lines
8.8 KiB

  1. //====== Copyright 1996-2005, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "vpc.h"
  7. #include "dependencies.h"
  8. extern void V_MakeAbsoluteCygwinPath( char *pOut, int outLen, const char *pRelativePath );
  9. extern void MakeFriendlyProjectName( char *pchProject )
  10. {
  11. int strLen = V_strlen( pchProject );
  12. for ( int j = 0; j < strLen; j++ )
  13. {
  14. if ( pchProject[j] == ' ' )
  15. pchProject[j] = '_';
  16. if ( pchProject[j] == '(' || pchProject[j] == ')' )
  17. {
  18. V_memmove( pchProject+j, pchProject+j+1, strLen - j );
  19. strLen--;
  20. }
  21. }
  22. }
  23. class CSolutionGenerator_Makefile : public IBaseSolutionGenerator
  24. {
  25. private:
  26. void GenerateProjectNames( CUtlVector<CUtlString> &projNames, CUtlVector<CDependency_Project*> &projects )
  27. {
  28. for ( int i=0; i < projects.Count(); i++ )
  29. {
  30. CDependency_Project *pCurProject = projects[i];
  31. char szFriendlyName[256];
  32. V_strncpy( szFriendlyName, pCurProject->m_ProjectName.String(), sizeof(szFriendlyName) );
  33. MakeFriendlyProjectName( szFriendlyName );
  34. projNames[ projNames.AddToTail() ] = szFriendlyName;
  35. }
  36. }
  37. public:
  38. virtual void GenerateSolutionFile( const char *pSolutionFilename, CUtlVector<CDependency_Project*> &projects )
  39. {
  40. // Default extension.
  41. char szTmpSolutionFilename[MAX_PATH];
  42. if ( !V_GetFileExtension( pSolutionFilename ) )
  43. {
  44. V_snprintf( szTmpSolutionFilename, sizeof( szTmpSolutionFilename ), "%s.mak", pSolutionFilename );
  45. pSolutionFilename = szTmpSolutionFilename;
  46. }
  47. Msg( "\nWriting master makefile %s.\n\n", pSolutionFilename );
  48. // Write the file.
  49. FILE *fp = fopen( pSolutionFilename, "wt" );
  50. if ( !fp )
  51. g_pVPC->VPCError( "Can't open %s for writing.", pSolutionFilename );
  52. fprintf( fp, "# VPC MASTER MAKEFILE\n\n\n" );
  53. fprintf( fp, "\nSHELL:=/bin/bash\n" );
  54. fprintf( fp, "# to control parallelism, set the MAKE_JOBS environment variable\n" );
  55. fprintf( fp, "ifeq ($(strip $(MAKE_JOBS)),)\n");
  56. fprintf( fp, "\tifeq ($(shell uname),Darwin)\n\t\tCPUS:=$(shell /usr/sbin/sysctl -n hw.ncpu)\n\tendif\n");
  57. fprintf( fp, "\tifeq ($(shell uname),Linux)\n\t\tCPUS:=$(shell grep processor /proc/cpuinfo | wc -l)\n\tendif\n");
  58. fprintf( fp, "\tMAKE_JOBS:=-j$(CPUS)\n" );
  59. fprintf( fp, "endif\n\n" );
  60. fprintf( fp, "ifeq ($(strip $(MAKE_JOBS)),)\n");
  61. fprintf( fp, "\tMAKE_JOBS:=-j8\n" );
  62. fprintf( fp, "endif\n\n" );
  63. // First, make a target with all the project names.
  64. fprintf( fp, "# All projects (default target)\n" );
  65. fprintf( fp, "all: \n" );
  66. fprintf( fp, "\t$(MAKE) -f $(lastword $(MAKEFILE_LIST)) $(MAKE_JOBS) all-targets\n\n" );
  67. fprintf( fp, "all-targets : " );
  68. CUtlVector<CUtlString> projNames;
  69. GenerateProjectNames( projNames, projects );
  70. for ( int i=0; i < projects.Count(); i++ )
  71. {
  72. fprintf( fp, "%s ", projNames[i].String() );
  73. }
  74. fprintf( fp, "\n\n\n# Individual projects + dependencies\n\n" );
  75. for ( int i=0; i < projects.Count(); i++ )
  76. {
  77. CDependency_Project *pCurProject = projects[i];
  78. CUtlVector<CDependency_Project*> additionalProjectDependencies;
  79. ResolveAdditionalProjectDependencies( pCurProject, projects, additionalProjectDependencies );
  80. fprintf( fp, "%s : ", projNames[i].String() );
  81. for ( int iTestProject=0; iTestProject < projects.Count(); iTestProject++ )
  82. {
  83. if ( i == iTestProject )
  84. continue;
  85. CDependency_Project *pTestProject = projects[iTestProject];
  86. int dependsOnFlags = k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse;
  87. if ( pCurProject->DependsOn( pTestProject, dependsOnFlags ) || additionalProjectDependencies.Find( pTestProject ) != additionalProjectDependencies.InvalidIndex() )
  88. {
  89. fprintf( fp, "%s ", projNames[iTestProject].String() );
  90. }
  91. }
  92. // Now add the code to build this thing.
  93. char sDirTemp[MAX_PATH], sDir[MAX_PATH];
  94. V_strncpy( sDirTemp, pCurProject->m_ProjectFilename.String(), sizeof( sDirTemp ) );
  95. V_StripFilename( sDirTemp );
  96. V_MakeAbsoluteCygwinPath( sDir, sizeof( sDir ), sDirTemp );
  97. const char *pFilename = V_UnqualifiedFileName( pCurProject->m_ProjectFilename.String() );
  98. fprintf( fp, "\n\t+cd %s && $(MAKE) -f %s $(CLEANPARAM)", sDir, pFilename );
  99. fprintf( fp, "\n\n" );
  100. }
  101. fprintf( fp, "# this is a bit over-inclusive, but the alternative (actually adding each referenced c/cpp/h file to\n" );
  102. fprintf( fp, "# the tags file) seems like more work than it's worth. feel free to fix that up if it bugs you. \n" );
  103. fprintf( fp, "TAGS:\n" );
  104. fprintf( fp, "\t@rm -f TAGS\n" );
  105. for ( int i=0; i < projects.Count(); i++ )
  106. {
  107. CDependency_Project *pCurProject = projects[i];
  108. char sDirTemp[MAX_PATH], sDir[MAX_PATH];
  109. V_strncpy( sDirTemp, pCurProject->m_ProjectFilename.String(), sizeof( sDirTemp ) );
  110. V_StripFilename( sDirTemp );
  111. V_MakeAbsoluteCygwinPath( sDir, sizeof( sDir ), sDirTemp );
  112. fprintf( fp, "\t@find %s -name \'*.cpp\' -print0 | xargs -0 etags --declarations --ignore-indentation --append\n", sDir );
  113. fprintf( fp, "\t@find %s -name \'*.h\' -print0 | xargs -0 etags --language=c++ --declarations --ignore-indentation --append\n", sDir );
  114. fprintf( fp, "\t@find %s -name \'*.c\' -print0 | xargs -0 etags --declarations --ignore-indentation --append\n", sDir );
  115. }
  116. fprintf( fp, "\n\n" );
  117. fprintf( fp, "\n# Mark all the projects as phony or else make will see the directories by the same name and think certain targets \n\n" );
  118. fprintf( fp, ".PHONY: TAGS showtargets regen showregen clean cleantargets relink " );
  119. for ( int i=0; i < projects.Count(); i++ )
  120. {
  121. fprintf( fp, "%s ", projNames[i].String() );
  122. }
  123. fprintf( fp, "\n\n\n" );
  124. fprintf( fp, "\n# The standard clean command to clean it all out.\n" );
  125. fprintf( fp, "\nclean: \n" );
  126. fprintf( fp, "\t$(MAKE) -f $(lastword $(MAKEFILE_LIST)) $(MAKE_JOBS) all-targets CLEANPARAM=clean\n\n\n" );
  127. fprintf( fp, "\n# clean targets, so we re-link next time.\n" );
  128. fprintf( fp, "\ncleantargets: \n" );
  129. fprintf( fp, "\t$(MAKE) -f $(lastword $(MAKEFILE_LIST)) $(MAKE_JOBS) all-targets CLEANPARAM=cleantargets\n\n\n" );
  130. fprintf( fp, "\n#relink\n" );
  131. fprintf( fp, "\nrelink: cleantargets \n" );
  132. fprintf( fp, "\t$(MAKE) -f $(lastword $(MAKEFILE_LIST)) $(MAKE_JOBS) all-targets\n\n\n" );
  133. // Create the showtargets target.
  134. fprintf( fp, "\n# Here's a command to list out all the targets\n\n" );
  135. fprintf( fp, "\nshowtargets: \n" );
  136. fprintf( fp, "\t@echo '-------------------' && \\\n" );
  137. fprintf( fp, "\techo '----- TARGETS -----' && \\\n" );
  138. fprintf( fp, "\techo '-------------------' && \\\n" );
  139. fprintf( fp, "\techo 'clean' && \\\n" );
  140. fprintf( fp, "\techo 'regen' && \\\n" );
  141. fprintf( fp, "\techo 'showregen' && \\\n" );
  142. for ( int i=0; i < projects.Count(); i++ )
  143. {
  144. fprintf( fp, "\techo '%s'", projNames[i].String() );
  145. if ( i != projects.Count()-1 )
  146. fprintf( fp, " && \\" );
  147. fprintf( fp, "\n" );
  148. }
  149. fprintf( fp, "\n\n" );
  150. // Create the regen target.
  151. fprintf( fp, "\n# Here's a command to regenerate this makefile\n\n" );
  152. fprintf( fp, "\nregen: \n" );
  153. fprintf( fp, "\t" );
  154. ICommandLine *pCommandLine = CommandLine();
  155. for ( int i=0; i < pCommandLine->ParmCount(); i++ )
  156. {
  157. fprintf( fp, "%s ", pCommandLine->GetParm( i ) );
  158. }
  159. fprintf( fp, "\n\n" );
  160. // Create the showregen target.
  161. fprintf( fp, "\n# Here's a command to list out all the targets\n\n" );
  162. fprintf( fp, "\nshowregen: \n" );
  163. fprintf( fp, "\t@echo " );
  164. for ( int i=0; i < pCommandLine->ParmCount(); i++ )
  165. {
  166. fprintf( fp, "%s ", pCommandLine->GetParm( i ) );
  167. }
  168. fprintf( fp, "\n\n" );
  169. fclose( fp );
  170. }
  171. void ResolveAdditionalProjectDependencies(
  172. CDependency_Project *pCurProject,
  173. CUtlVector<CDependency_Project*> &projects,
  174. CUtlVector<CDependency_Project*> &additionalProjectDependencies )
  175. {
  176. for ( int i=0; i < pCurProject->m_AdditionalProjectDependencies.Count(); i++ )
  177. {
  178. const char *pLookingFor = pCurProject->m_AdditionalProjectDependencies[i].String();
  179. int j;
  180. for ( j=0; j < projects.Count(); j++ )
  181. {
  182. if ( V_stricmp( projects[j]->m_ProjectName.String(), pLookingFor ) == 0 )
  183. break;
  184. }
  185. if ( j == projects.Count() )
  186. g_pVPC->VPCError( "Project %s lists '%s' in its $AdditionalProjectDependencies, but there is no project by that name.", pCurProject->GetName(), pLookingFor );
  187. additionalProjectDependencies.AddToTail( projects[j] );
  188. }
  189. }
  190. const char* FindInFile( const char *pFilename, const char *pFileData, const char *pSearchFor )
  191. {
  192. const char *pPos = V_stristr( pFileData, pSearchFor );
  193. if ( !pPos )
  194. g_pVPC->VPCError( "Can't find ProjectGUID in %s.", pFilename );
  195. return pPos + V_strlen( pSearchFor );
  196. }
  197. };
  198. static CSolutionGenerator_Makefile g_SolutionGenerator_Makefile;
  199. IBaseSolutionGenerator* GetSolutionGenerator_Makefile()
  200. {
  201. return &g_SolutionGenerator_Makefile;
  202. }