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.

346 lines
11 KiB

  1. //====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "vpc.h"
  7. #include "dependencies.h"
  8. #include "tier1/checksum_md5.h"
  9. class CVCProjInfo
  10. {
  11. public:
  12. CUtlString m_ProjectName;
  13. CUtlString m_ProjectGUID;
  14. };
  15. class CSolutionGenerator_Win32 : public IBaseSolutionGenerator
  16. {
  17. public:
  18. void GetVCPROJSolutionGUID( char (&szSolutionGUID)[256] )
  19. {
  20. HKEY hKey;
  21. int firstVer = 8;
  22. const int lastVer = 12; // Handle up to VS 12, AKA VS 2013
  23. if ( g_pVPC->Is2010() )
  24. {
  25. firstVer = 10;
  26. }
  27. for ( int vsVer = firstVer; vsVer <= lastVer; ++vsVer )
  28. {
  29. // Handle both VisualStudio and VCExpress (used by some SourceSDK customers)
  30. const char* productName[] =
  31. {
  32. "VisualStudio",
  33. "VCExpress",
  34. };
  35. for ( int productNumber = 0; productNumber < ARRAYSIZE(productName); ++productNumber )
  36. {
  37. char pRegKeyName[1000];
  38. V_snprintf( pRegKeyName, ARRAYSIZE(pRegKeyName), "Software\\Microsoft\\%s\\%d.0\\Projects", productName[ productNumber ], vsVer );
  39. LONG ret = RegOpenKeyEx( HKEY_LOCAL_MACHINE, pRegKeyName, 0, KEY_READ, &hKey );
  40. //if ( ret != ERROR_SUCCESS )
  41. // g_pVPC->VPCError( "Unable to open registry key %s.", pRegKeyName );
  42. for ( int i=0; i < 200; i++ )
  43. {
  44. char szKeyName[MAX_PATH];
  45. DWORD dwKeyNameSize = sizeof( szKeyName );
  46. ret = RegEnumKeyEx( hKey, i, szKeyName, &dwKeyNameSize, NULL, NULL, NULL, NULL );
  47. if ( ret == ERROR_NO_MORE_ITEMS )
  48. break;
  49. HKEY hSubKey;
  50. LONG ret = RegOpenKeyEx( hKey, szKeyName, 0, KEY_READ, &hSubKey );
  51. if ( ret == ERROR_SUCCESS )
  52. {
  53. DWORD dwType;
  54. char ext[MAX_PATH];
  55. DWORD dwExtLen = sizeof( ext );
  56. ret = RegQueryValueEx( hSubKey, "DefaultProjectExtension", NULL, &dwType, (BYTE*)ext, &dwExtLen );
  57. RegCloseKey( hSubKey );
  58. // VS 2012 and beyond has the DefaultProjectExtension as vcxproj instead of vcproj
  59. if ( ret == ERROR_SUCCESS && dwType == REG_SZ && ( V_stricmp( ext, "vcproj" ) == 0 || V_stricmp( ext, "vcxproj" ) == 0 ) )
  60. {
  61. V_strncpy( szSolutionGUID, szKeyName, ARRAYSIZE(szSolutionGUID) );
  62. RegCloseKey( hKey );
  63. return;
  64. }
  65. }
  66. }
  67. RegCloseKey( hKey );
  68. }
  69. }
  70. g_pVPC->VPCError( "Unable to find RegKey for .vcproj or .vcxproj files in solutions." );
  71. }
  72. virtual void GenerateSolutionFile( const char *pSolutionFilename, CUtlVector<CDependency_Project*> &projects )
  73. {
  74. // Default extension.
  75. char szTmpSolutionFilename[MAX_PATH];
  76. if ( !V_GetFileExtension( pSolutionFilename ) )
  77. {
  78. V_snprintf( szTmpSolutionFilename, sizeof( szTmpSolutionFilename ), "%s.sln", pSolutionFilename );
  79. pSolutionFilename = szTmpSolutionFilename;
  80. }
  81. Msg( "\nWriting solution file %s.\n\n", pSolutionFilename );
  82. char szSolutionGUID[256];
  83. GetVCPROJSolutionGUID( szSolutionGUID );
  84. CUtlVector<CVCProjInfo> vcprojInfos;
  85. GetProjectInfos( projects, vcprojInfos );
  86. // Write the file.
  87. FILE *fp = fopen( pSolutionFilename, "wt" );
  88. if ( !fp )
  89. g_pVPC->VPCError( "Can't open %s for writing.", pSolutionFilename );
  90. if ( g_pVPC->Is2013() )
  91. {
  92. fprintf( fp, "\xef\xbb\xbf\nMicrosoft Visual Studio Solution File, Format Version 12.00\n" ); // Format didn't change from VS 2012 to VS 2013
  93. fprintf( fp, "# Visual Studio 2013\n" );
  94. }
  95. else if ( g_pVPC->Is2012() )
  96. {
  97. fprintf( fp, "\xef\xbb\xbf\nMicrosoft Visual Studio Solution File, Format Version 12.00\n" );
  98. fprintf( fp, "# Visual Studio 2012\n" );
  99. }
  100. else if ( g_pVPC->Is2010() )
  101. {
  102. fprintf( fp, "\xef\xbb\xbf\nMicrosoft Visual Studio Solution File, Format Version 11.00\n" );
  103. fprintf( fp, "# Visual Studio 2010\n" );
  104. }
  105. else
  106. {
  107. fprintf( fp, "\xef\xbb\xbf\nMicrosoft Visual Studio Solution File, Format Version 9.00\n" );
  108. fprintf( fp, "# Visual Studio 2005\n" );
  109. }
  110. fprintf( fp, "#\n" );
  111. fprintf( fp, "# Automatically generated solution:\n" );
  112. fprintf( fp, "# devtools\\bin\\vpc " );
  113. for ( int k = 1; k < __argc; ++ k )
  114. fprintf( fp, "%s ", __argv[k] );
  115. fprintf( fp, "\n" );
  116. fprintf( fp, "#\n" );
  117. fprintf( fp, "#\n" );
  118. if ( !g_pVPC->Is2010() )
  119. {
  120. // if /slnItems <filename> is passed on the command line, build a Solution Items project
  121. const char *pSolutionItemsFilename = g_pVPC->GetSolutionItemsFilename();
  122. if ( pSolutionItemsFilename[0] != '\0' )
  123. {
  124. fprintf( fp, "Project(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Solution Items\", \"Solution Items\", \"{AAAAAAAA-8B4A-11D0-8D11-90A07D6D6F7D}\"\n" );
  125. fprintf( fp, "\tProjectSection(SolutionItems) = preProject\n" );
  126. WriteSolutionItems( fp );
  127. fprintf( fp, "\tEndProjectSection\n" );
  128. fprintf( fp, "EndProject\n" );
  129. }
  130. }
  131. for ( int i=0; i < projects.Count(); i++ )
  132. {
  133. CDependency_Project *pCurProject = projects[i];
  134. CVCProjInfo *pProjInfo = &vcprojInfos[i];
  135. // Get a relative filename for the vcproj file.
  136. const char *pFullProjectFilename = pCurProject->m_ProjectFilename.String();
  137. char szRelativeFilename[MAX_PATH];
  138. if ( !V_MakeRelativePath( pFullProjectFilename, g_pVPC->GetSourcePath(), szRelativeFilename, sizeof( szRelativeFilename ) ) )
  139. g_pVPC->VPCError( "Can't make a relative path (to the base source directory) for %s.", pFullProjectFilename );
  140. fprintf( fp, "Project(\"%s\") = \"%s\", \"%s\", \"{%s}\"\n", szSolutionGUID, pProjInfo->m_ProjectName.String(), szRelativeFilename, pProjInfo->m_ProjectGUID.String() );
  141. bool bHasDependencies = false;
  142. for ( int iTestProject=0; iTestProject < projects.Count(); iTestProject++ )
  143. {
  144. if ( i == iTestProject )
  145. continue;
  146. CDependency_Project *pTestProject = projects[iTestProject];
  147. if ( pCurProject->DependsOn( pTestProject, k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagRecurse ) ||
  148. pCurProject->DependsOn( pTestProject, k_EDependsOnFlagCheckAdditionalDependencies | k_EDependsOnFlagTraversePastLibs ) )
  149. {
  150. if ( !bHasDependencies )
  151. {
  152. fprintf( fp, "\tProjectSection(ProjectDependencies) = postProject\n" );
  153. bHasDependencies = true;
  154. }
  155. fprintf( fp, "\t\t{%s} = {%s}\n", vcprojInfos[iTestProject].m_ProjectGUID.String(), vcprojInfos[iTestProject].m_ProjectGUID.String() );
  156. }
  157. }
  158. if ( bHasDependencies )
  159. fprintf( fp, "\tEndProjectSection\n" );
  160. fprintf( fp, "EndProject\n" );
  161. }
  162. fclose( fp );
  163. }
  164. const char* FindInFile( const char *pFilename, const char *pFileData, const char *pSearchFor )
  165. {
  166. const char *pPos = V_stristr( pFileData, pSearchFor );
  167. if ( !pPos )
  168. {
  169. g_pVPC->VPCError( "Can't find %s in %s.", pSearchFor, pFilename );
  170. }
  171. return pPos + V_strlen( pSearchFor );
  172. }
  173. void GetProjectInfos( CUtlVector<CDependency_Project*> &projects, CUtlVector<CVCProjInfo> &vcprojInfos )
  174. {
  175. for ( int i=0; i < projects.Count(); i++ )
  176. {
  177. CDependency_Project *pCurProject = projects[i];
  178. const char *pFilename = pCurProject->m_ProjectFilename.String();
  179. CVCProjInfo vcprojInfo;
  180. char *pFileData;
  181. int nResult = Sys_LoadFile( pFilename, (void**)&pFileData, false );
  182. if ( nResult == -1 )
  183. g_pVPC->VPCError( "Can't open %s to get ProjectGUID.", pFilename );
  184. const char *pSearchFor;
  185. if ( g_pVPC->Is2010() )
  186. {
  187. pSearchFor = "<ProjectGuid>{";
  188. }
  189. else
  190. {
  191. pSearchFor = "ProjectGUID=\"{";
  192. }
  193. const char *pPos = FindInFile( pFilename, pFileData, pSearchFor );
  194. char szGuid[37];
  195. const char *pGuid = pPos;
  196. V_strncpy( szGuid, pGuid, sizeof( szGuid ) );
  197. vcprojInfo.m_ProjectGUID = szGuid;
  198. const char *pEnd;
  199. if ( g_pVPC->Is2010() )
  200. {
  201. pPos = FindInFile( pFilename, pFileData, "<ProjectName>" );
  202. pEnd = V_stristr( pPos, "<" );
  203. }
  204. else
  205. {
  206. pPos = FindInFile( pFilename, pFileData, "Name=\"" );
  207. pEnd = V_stristr( pPos, "\"" );
  208. }
  209. if ( !pEnd || (pEnd - pPos) > 1024 || (pEnd - pPos) <= 0 )
  210. g_pVPC->VPCError( "Can't find valid 'Name=' in %s.", pFilename );
  211. char szName[256];
  212. V_strncpy( szName, pPos, (pEnd - pPos) + 1 );
  213. vcprojInfo.m_ProjectName = szName;
  214. vcprojInfos.AddToTail( vcprojInfo );
  215. free( pFileData );
  216. }
  217. }
  218. // Parse g_SolutionItemsFilename, reading in filenames (including wildcards),
  219. // and add them to the Solution Items project we're already writing.
  220. void WriteSolutionItems( FILE *fp )
  221. {
  222. char szFullSolutionItemsPath[MAX_PATH];
  223. if ( V_IsAbsolutePath( g_pVPC->GetSolutionItemsFilename() ) )
  224. V_strncpy( szFullSolutionItemsPath, g_pVPC->GetSolutionItemsFilename(), sizeof( szFullSolutionItemsPath ) );
  225. else
  226. V_ComposeFileName( g_pVPC->GetStartDirectory(), g_pVPC->GetSolutionItemsFilename(), szFullSolutionItemsPath, sizeof( szFullSolutionItemsPath ) );
  227. g_pVPC->GetScript().PushScript( szFullSolutionItemsPath );
  228. int numSolutionItems = 0;
  229. while ( g_pVPC->GetScript().GetData() )
  230. {
  231. // read a line
  232. const char *pToken = g_pVPC->GetScript().GetToken( false );
  233. // strip out \r\n chars
  234. char *end = V_strstr( pToken, "\n" );
  235. if ( end )
  236. {
  237. *end = '\0';
  238. }
  239. end = V_strstr( pToken, "\r" );
  240. if ( end )
  241. {
  242. *end = '\0';
  243. }
  244. // bail on strings too small to be paths
  245. if ( V_strlen( pToken ) < 3 )
  246. continue;
  247. // compose an absolute path w/o any ../
  248. char szFullPath[MAX_PATH];
  249. if ( V_IsAbsolutePath( pToken ) )
  250. V_strncpy( szFullPath, pToken, sizeof( szFullPath ) );
  251. else
  252. V_ComposeFileName( g_pVPC->GetStartDirectory(), pToken, szFullPath, sizeof( szFullPath ) );
  253. if ( !V_RemoveDotSlashes( szFullPath ) )
  254. continue;
  255. if ( V_strstr( szFullPath, "*" ) != NULL )
  256. {
  257. // wildcard!
  258. char szWildcardPath[MAX_PATH];
  259. V_strncpy( szWildcardPath, szFullPath, sizeof( szWildcardPath ) );
  260. V_StripFilename( szWildcardPath );
  261. struct _finddata32_t data;
  262. intptr_t handle = _findfirst32( szFullPath, &data );
  263. if ( handle != -1L )
  264. {
  265. do
  266. {
  267. if ( ( data.attrib & _A_SUBDIR ) == 0 )
  268. {
  269. // not a dir, just a filename - add it
  270. V_ComposeFileName( szWildcardPath, data.name, szFullPath, sizeof( szFullPath ) );
  271. if ( V_RemoveDotSlashes( szFullPath ) )
  272. {
  273. fprintf( fp, "\t\t%s = %s\n", szFullPath, szFullPath );
  274. ++numSolutionItems;
  275. }
  276. }
  277. } while ( _findnext32( handle, &data ) == 0 );
  278. _findclose( handle );
  279. }
  280. }
  281. else
  282. {
  283. // just a file - add it
  284. fprintf( fp, "\t\t%s = %s\n", szFullPath, szFullPath );
  285. ++numSolutionItems;
  286. }
  287. }
  288. g_pVPC->GetScript().PopScript();
  289. Msg( "Found %d solution files in %s\n", numSolutionItems, g_pVPC->GetSolutionItemsFilename() );
  290. }
  291. };
  292. static CSolutionGenerator_Win32 g_SolutionGenerator_Win32;
  293. IBaseSolutionGenerator* GetSolutionGenerator_Win32()
  294. {
  295. return &g_SolutionGenerator_Win32;
  296. }