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.

2034 lines
100 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 "baseprojectdatacollector.h"
  9. #include "utlsortvector.h"
  10. #ifdef WIN32
  11. #include <direct.h>
  12. #define mkdir(dir, mode) _mkdir(dir)
  13. #define getcwd _getcwd
  14. #define snprintf _snprintf
  15. typedef unsigned __int64 uint64_t;
  16. typedef unsigned __int16 uint16_t;
  17. typedef unsigned __int8 uint8_t;
  18. typedef signed __int16 int16_t;
  19. #else
  20. #include <stdint.h>
  21. #endif
  22. #ifndef STEAM
  23. bool Q_StrSubstInPlace( char *pchInOut, int cchInOut, const char *pMatch, const char *pReplaceWith, bool bCaseSensitive )
  24. {
  25. char *pchT = (char *)stackalloc( cchInOut );
  26. if ( Q_StrSubst( pchInOut, pMatch, pReplaceWith, pchT, cchInOut, bCaseSensitive ) )
  27. {
  28. Q_strncpy( pchInOut, pchT, cchInOut );
  29. return true;
  30. }
  31. return false;
  32. }
  33. #endif
  34. static const char *k_pchProjects = "Projects";
  35. static const char *k_pchLegacyTarget = "build with make";
  36. static const char *k_rgchConfigNames[] = { "Debug", "Release", "Profile", "Retail" };
  37. static const char *g_pOption_GameOutputFile = "$GameOutputFile";
  38. static const char *g_pOption_SystemLibraries = "$SystemLibraries";
  39. static const char *g_pOption_SystemFrameworks = "$SystemFrameworks";
  40. static const char *g_pOption_LocalFrameworks = "$LocalFrameworks";
  41. static const char *g_pOption_CommandLine = "$CommandLine";
  42. static const char *g_pOption_Outputs = "$Outputs";
  43. static const char *g_pOption_ExtraCompilerFlags = "$GCC_ExtraCompilerFlags";
  44. static const char *g_pOption_ExtraLinkerFlags = "$GCC_ExtraLinkerFlags";
  45. // stupid and evil - remove when we can
  46. static const char *g_pOption_ForceIncludes = "$ForceIncludes";
  47. static const char *k_rgchXCConfigFiles[] = { "debug.xcconfig", "release.xcconfig", "base.xcconfig" };
  48. static int k_oidBuildConfigList = 0xc0de;
  49. static int k_rgOidBuildConfigs[] = { 0x1c0de, 0x1c0e0 };
  50. // we assume (and assert) that the order of this vector is the same as the order of the projects vector
  51. extern CUtlVector<CBaseProjectDataCollector*> g_vecPGenerators;
  52. class CSolutionGenerator_XCode : public IBaseSolutionGenerator
  53. {
  54. public:
  55. virtual void GenerateSolutionFile( const char *pSolutionFilename, CUtlVector<CDependency_Project*> &projects );
  56. private:
  57. void XcodeFileTypeFromFileName( const char *pszFileName, char *pchOutBuf, int cchOutBuf );
  58. void XcodeProductTypeFromFileName( const char *pszFileName, char *pchOutBuf, int cchOutBuf );
  59. void EmitBuildSettings( const char *pszProjectName, const char *pszProjectDir, CUtlDict<CFileConfig *,int> *pDictFiles, KeyValues *pKV, bool bIsDebug );
  60. void WriteFilesFolder( uint64_t oid, const char *pFolderName, const char *pExtensions, const CUtlDict<CFileConfig *,int> &files );
  61. void Write( const char *pMsg, ... );
  62. FILE *m_fp;
  63. int m_nIndent;
  64. // deprecated
  65. void GenerateSolutionFileOld( const char *pSolutionFilename, CUtlVector<CDependency_Project*> &projects );
  66. };
  67. enum EOIDType
  68. {
  69. EOIDTypeProject = 0x00001d00,
  70. EOIDTypeGroup,
  71. EOIDTypeFileReference,
  72. EOIDTypeBuildFile,
  73. EOIDTypeSourcesBuildPhase,
  74. EOIDTypeFrameworksBuildPhase,
  75. EOIDTypeCopyFilesBuildPhase,
  76. EOIDTypeHeadersBuildPhase,
  77. EOIDTypeShellScriptBuildPhase,
  78. EOIDTypeNativeTarget,
  79. EOIDTypeAggregateTarget,
  80. EOIDTypeTargetDependency,
  81. EOIDTypeContainerItemProxy,
  82. EOIDTypeBuildConfiguration,
  83. EOIDTypeConfigurationList,
  84. };
  85. uint64_t makeoid( const void *obj, EOIDType type, int16_t ordinal = 0 )
  86. {
  87. return (uint64_t)obj + ((uint64_t)type << 32) + ((uint64_t)(ordinal+1) << 52);
  88. }
  89. static const char* UsePOSIXSlashes( const char *pStr )
  90. {
  91. int len = Q_strlen( pStr ) + 2;
  92. static char str[MAX_PATH*2];
  93. V_strncpy( str, pStr, len );
  94. V_FixSlashes( str, '/' );
  95. return str;
  96. }
  97. static bool NeedsBuildFileEntry( const char *pszFileName )
  98. {
  99. const char *pchExtension = V_GetFileExtension( V_UnqualifiedFileName( pszFileName ) );
  100. if ( !pchExtension )
  101. return false;
  102. else if ( ! Q_stricmp( pchExtension, "cpp" ) || ! Q_stricmp( pchExtension, "cxx" ) || ! Q_stricmp( pchExtension, "cc" ) || ! Q_stricmp( pchExtension, "c" ) || ! Q_stricmp( pchExtension, "m" ) || ! Q_stricmp( pchExtension, "mm" ) || ! Q_stricmp( pchExtension, "cc" ) )
  103. return true;
  104. else if ( ! Q_stricmp( pchExtension, "a" ) || ! Q_stricmp( pchExtension, "dylib" ) )
  105. return true;
  106. return false;
  107. }
  108. static bool IsSourceFile( const char *pszFileName )
  109. {
  110. const char *pchExtension = V_GetFileExtension( V_UnqualifiedFileName( pszFileName ) );
  111. if ( !pchExtension )
  112. return false;
  113. else if ( ! Q_stricmp( pchExtension, "cpp" ) || ! Q_stricmp( pchExtension, "cc" ) || ! Q_stricmp( pchExtension, "cxx" ) || ! Q_stricmp( pchExtension, "c" ) || ! Q_stricmp( pchExtension, "m" ) || ! Q_stricmp( pchExtension, "mm" ) || ! Q_stricmp( pchExtension, "cc" ) )
  114. return true;
  115. return false;
  116. }
  117. static bool AppearsInSourcesBuildPhase( const char *pszFileName )
  118. {
  119. return IsSourceFile( pszFileName );
  120. }
  121. static bool IsStaticLibrary( const char *pszFileName )
  122. {
  123. const char *pchExtension = V_GetFileExtension( V_UnqualifiedFileName( pszFileName ) );
  124. if ( !pchExtension )
  125. return false;
  126. else if ( ! Q_stricmp( pchExtension, "a" ) )
  127. return true;
  128. return false;
  129. }
  130. static bool IsDynamicLibrary( const char *pszFileName )
  131. {
  132. const char *pchExtension = V_GetFileExtension( V_UnqualifiedFileName( pszFileName ) );
  133. if ( !pchExtension )
  134. return false;
  135. else if ( ! Q_stricmp( pchExtension, "dylib" ) )
  136. return true;
  137. return false;
  138. }
  139. void ResolveAdditionalProjectDependencies( CDependency_Project *pCurProject, CUtlVector<CDependency_Project*> &projects, CUtlVector<CDependency_Project*> &additionalProjectDependencies )
  140. {
  141. for ( int i=0; i < pCurProject->m_AdditionalProjectDependencies.Count(); i++ )
  142. {
  143. const char *pLookingFor = pCurProject->m_AdditionalProjectDependencies[i].String();
  144. int j;
  145. for ( j=0; j < projects.Count(); j++ )
  146. {
  147. if ( V_stricmp( projects[j]->m_ProjectName.String(), pLookingFor ) == 0 )
  148. break;
  149. }
  150. if ( j == projects.Count() )
  151. g_pVPC->VPCError( "Project %s lists '%s' in its $AdditionalProjectDependencies, but there is no project by that name.", pCurProject->GetName(), pLookingFor );
  152. additionalProjectDependencies.AddToTail( projects[j] );
  153. }
  154. }
  155. void CSolutionGenerator_XCode::WriteFilesFolder( uint64_t oid, const char *pFolderName, const char *pExtensions, const CUtlDict<CFileConfig *,int> &files )
  156. {
  157. CUtlVector<char*> extensions;
  158. V_SplitString( pExtensions, ";", extensions );
  159. Write( "%024llX /* %s */ = {\n", oid, pFolderName );
  160. ++m_nIndent;
  161. Write( "isa = PBXGroup;\n" );
  162. Write( "children = (\n" );
  163. ++m_nIndent;
  164. for ( int i=files.First(); i != files.InvalidIndex(); i=files.Next( i ) )
  165. {
  166. const char *pFileName = files[i]->GetName();
  167. // Make sure this file's extension is one of the extensions they're asking for.
  168. bool bValidExt = false;
  169. const char *pFileExtension = V_GetFileExtension( V_UnqualifiedFileName( pFileName ) );
  170. if ( pFileExtension )
  171. {
  172. for ( int iExt=0; iExt < extensions.Count(); iExt++ )
  173. {
  174. const char *pTestExt = extensions[iExt];
  175. if ( pTestExt[0] == '*' && pTestExt[1] == '.' && V_stricmp( pTestExt+2, pFileExtension ) == 0 )
  176. {
  177. bValidExt = true;
  178. break;
  179. }
  180. }
  181. }
  182. if ( bValidExt )
  183. {
  184. Write( "%024llX /* %s */,\n", makeoid( files[i]->GetName(), EOIDTypeFileReference ), UsePOSIXSlashes( pFileName ) );
  185. }
  186. }
  187. --m_nIndent;
  188. Write( ");\n" );
  189. Write( "name = \"%s\";\n", pFolderName );
  190. Write( "sourceTree = \"<group>\";\n" );
  191. --m_nIndent;
  192. Write( "};\n" );
  193. }
  194. void CSolutionGenerator_XCode::XcodeFileTypeFromFileName( const char *pszFileName, char *pchOutBuf, int cchOutBuf )
  195. {
  196. const char *pchExtension = V_GetFileExtension( V_UnqualifiedFileName( pszFileName ) );
  197. if ( !pchExtension )
  198. snprintf( pchOutBuf, cchOutBuf, "compiled.mach-o.executable" );
  199. else if ( ! Q_stricmp( pchExtension, "cpp" ) || ! Q_stricmp( pchExtension, "cxx" ) || ! Q_stricmp( pchExtension, "cc" ) || ! Q_stricmp( pchExtension, "h" ) || ! Q_stricmp( pchExtension, "hxx" ) || ! Q_stricmp( pchExtension, "cc" ) )
  200. snprintf( pchOutBuf, cchOutBuf, "sourcecode.cpp.%s", pchExtension );
  201. else if ( ! Q_stricmp( pchExtension, "c" ) )
  202. snprintf( pchOutBuf, cchOutBuf, "sourcecode.cpp.cpp" );
  203. else if ( ! Q_stricmp( pchExtension, "m" ) || ! Q_stricmp( pchExtension, "mm" ) )
  204. snprintf( pchOutBuf, cchOutBuf, "sourcecode.objc.%s", pchExtension );
  205. else if ( ! Q_stricmp( pchExtension, "a" ) )
  206. snprintf( pchOutBuf, cchOutBuf, "archive.ar" );
  207. else if ( ! Q_stricmp( pchExtension, "dylib" ) )
  208. {
  209. const char *pszLibName = V_UnqualifiedFileName( pszFileName );
  210. if ( pszLibName[0] == 'l' && pszLibName[1] == 'i' && pszLibName[2] == 'b' )
  211. snprintf( pchOutBuf, cchOutBuf, "compiled.mach-o.dylib" );
  212. else
  213. snprintf( pchOutBuf, cchOutBuf, "compiled.mach-o.bundle" );
  214. }
  215. else if ( ! Q_stricmp( pchExtension, "pl" ) )
  216. snprintf( pchOutBuf, cchOutBuf, "text.script.perl" );
  217. else
  218. snprintf( pchOutBuf, cchOutBuf, "text.plain" );
  219. }
  220. void CSolutionGenerator_XCode::XcodeProductTypeFromFileName( const char *pszFileName, char *pchOutBuf, int cchOutBuf )
  221. {
  222. const char *pchExtension = V_GetFileExtension( V_UnqualifiedFileName( pszFileName ) );
  223. if ( !pchExtension )
  224. snprintf( pchOutBuf, cchOutBuf, "com.apple.product-type.tool" );
  225. else if ( ! Q_stricmp( pchExtension, "a" ) )
  226. snprintf( pchOutBuf, cchOutBuf, "com.apple.product-type.library.static" );
  227. else if ( ! Q_stricmp( pchExtension, "dylib" ) )
  228. {
  229. snprintf( pchOutBuf, cchOutBuf, "com.apple.product-type.library.dynamic" );
  230. #if 0
  231. const char *pszLibName = V_UnqualifiedFileName( pszFileName );
  232. if ( pszLibName[0] != 'l' || pszLibName[1] != 'i' || pszLibName[2] != 'b' )
  233. snprintf( pchOutBuf, cchOutBuf, "com.apple.product-type.bundle" );
  234. #endif
  235. }
  236. else
  237. snprintf( pchOutBuf, cchOutBuf, "com.apple.product-type.unknown" );
  238. }
  239. void CSolutionGenerator_XCode::EmitBuildSettings( const char *pszProjectName, const char *pszProjectDir, CUtlDict<CFileConfig *,int> *pDictFiles, KeyValues *pKV, bool bIsDebug )
  240. {
  241. if ( !pKV )
  242. {
  243. Write( "PRODUCT_NAME = \"%s\";\n", pszProjectName );
  244. return;
  245. }
  246. CUtlString sOutputFile = V_UnqualifiedFileName( UsePOSIXSlashes( pKV->GetString( g_pOption_GameOutputFile, "" ) ) );
  247. if ( !sOutputFile.Length() )
  248. sOutputFile = V_UnqualifiedFileName( UsePOSIXSlashes( pKV->GetString( g_pOption_OutputFile, "" ) ) );
  249. if ( sOutputFile.Length() )
  250. {
  251. char sFilename[MAX_PATH];
  252. V_StripExtension( sOutputFile, sFilename, sizeof(sFilename) );
  253. Write( "PRODUCT_NAME = \"%s\";\n", sFilename );
  254. if ( Q_strlen( pKV->GetString( g_pOption_ExtraLinkerFlags, "" ) ) )
  255. Write( "OTHER_LDFLAGS = \"%s\";\n", pKV->GetString( g_pOption_ExtraLinkerFlags ) );
  256. CUtlString sOtherCompilerCFlags = "OTHER_CFLAGS = \"$(OTHER_CFLAGS) ";
  257. CUtlString sOtherCompilerCPlusFlags = "OTHER_CPLUSPLUSFLAGS = \"$(OTHER_CPLUSPLUSFLAGS) ";
  258. if ( Q_strlen( pKV->GetString( g_pOption_ExtraCompilerFlags, "" ) ) )
  259. {
  260. sOtherCompilerCFlags += pKV->GetString( g_pOption_ExtraCompilerFlags );
  261. sOtherCompilerCPlusFlags += pKV->GetString( g_pOption_ExtraCompilerFlags );
  262. }
  263. if ( Q_strlen( pKV->GetString( g_pOption_ForceIncludes, "" ) ) )
  264. {
  265. CSplitString outStrings( pKV->GetString( g_pOption_ForceIncludes ), (const char**)g_IncludeSeparators, Q_ARRAYSIZE(g_IncludeSeparators) );
  266. for ( int i=0; i < outStrings.Count(); i++ )
  267. {
  268. if ( V_strlen( outStrings[i] ) > 2 )
  269. {
  270. //char sIncludeDir[ MAX_PATH ];
  271. char szIncludeLine[ MAX_PATH ];
  272. /*Q_snprintf( sIncludeDir, sizeof( sIncludeDir ), "%s/%s", pszProjectDir, outStrings[i] );
  273. V_FixSlashes( sIncludeDir, '/' );
  274. Q_RemoveDotSlashes( sIncludeDir );
  275. #ifdef STEAM
  276. Q_StripPrecedingAndTrailingWhitespace( sIncludeDir );
  277. #endif */
  278. V_snprintf( szIncludeLine, sizeof(szIncludeLine), " -include %s", UsePOSIXSlashes( outStrings[i] ) );
  279. sOtherCompilerCFlags += szIncludeLine;
  280. sOtherCompilerCPlusFlags += szIncludeLine;
  281. }
  282. }
  283. }
  284. sOtherCompilerCFlags += "\";\n" ;
  285. sOtherCompilerCPlusFlags += "\";\n" ;
  286. Write( sOtherCompilerCFlags );
  287. Write( sOtherCompilerCPlusFlags );
  288. if ( IsDynamicLibrary( sOutputFile ) )
  289. {
  290. if ( sFilename[0] != 'l' || sFilename[1] != 'i' || sFilename[2] == 'b' )
  291. {
  292. //if ( !pKV->GetString( g_pOption_LocalFrameworks, NULL ) )
  293. // Write( "OTHER_LDFLAGS = \"-flat_namespace\";\n" );
  294. // Write( "MACH_O_TYPE = mh_bundle;\n" );
  295. // Write( "EXECUTABLE_EXTENSION = dylib;\n" );
  296. // Write( "OTHER_LDFLAGS = \"-flat_namespace -undefined suppress\";\n" );
  297. }
  298. Write( "MACH_O_TYPE = mh_dylib;\n" );
  299. Write( "LD_DYLIB_INSTALL_NAME = \"@loader_path/%s.dylib\";\n", sFilename );
  300. }
  301. if ( IsStaticLibrary( sOutputFile ) )
  302. {
  303. Write( "DEBUG_INFORMATION_FORMAT = stabs;\n" );
  304. }
  305. }
  306. else
  307. Write( "PRODUCT_NAME = \"%s\";\n", pszProjectName );
  308. // add our header search paths
  309. CSplitString outStrings( pKV->GetString( g_pOption_AdditionalIncludeDirectories ), (const char**)g_IncludeSeparators, Q_ARRAYSIZE(g_IncludeSeparators) );
  310. if ( outStrings.Count() )
  311. {
  312. char sIncludeDir[MAX_PATH];
  313. // start the iquote list with the project directory
  314. Q_snprintf( sIncludeDir, sizeof( sIncludeDir ), "%s", pszProjectDir );
  315. V_FixSlashes( sIncludeDir, '/' );
  316. Q_RemoveDotSlashes( sIncludeDir );
  317. #ifdef STEAM
  318. Q_StripPrecedingAndTrailingWhitespace( sIncludeDir );
  319. #endif
  320. Write( "USER_HEADER_SEARCH_PATHS = (\n" );
  321. ++m_nIndent;
  322. #ifdef STEAM
  323. Write( "\"%s\",\n", sIncludeDir );
  324. #endif
  325. for ( int i=0; i < outStrings.Count(); i++ )
  326. {
  327. Q_snprintf( sIncludeDir, sizeof( sIncludeDir ), "%s/%s", pszProjectDir, outStrings[i] );
  328. V_FixSlashes( sIncludeDir, '/' );
  329. Q_RemoveDotSlashes( sIncludeDir );
  330. #ifdef STEAM
  331. Q_StripPrecedingAndTrailingWhitespace( sIncludeDir );
  332. #endif
  333. Write( "\"%s\",\n", sIncludeDir );
  334. }
  335. --m_nIndent;
  336. Write( ");\n" );
  337. }
  338. // add local frameworks we link against to the compiler framework search paths
  339. CSplitString localFrameworks( pKV->GetString( g_pOption_LocalFrameworks ), (const char**)g_IncludeSeparators, Q_ARRAYSIZE(g_IncludeSeparators) );
  340. if ( localFrameworks.Count() )
  341. {
  342. Write( "FRAMEWORK_SEARCH_PATHS = (\n" );
  343. ++m_nIndent;
  344. {
  345. Write( "\"$(inherited)\",\n" );
  346. for ( int i=0; i < localFrameworks.Count(); i++ )
  347. {
  348. char rgchFrameworkPath[MAX_PATH];
  349. Q_snprintf( rgchFrameworkPath, sizeof( rgchFrameworkPath ), "%s/%s", pszProjectDir, localFrameworks[i] );
  350. rgchFrameworkPath[ Q_strlen( rgchFrameworkPath ) - Q_strlen( V_UnqualifiedFileName( localFrameworks[i] ) ) ] = '\0';
  351. Q_RemoveDotSlashes( rgchFrameworkPath );
  352. Write( "\"%s\",\n", rgchFrameworkPath );
  353. }
  354. }
  355. --m_nIndent;
  356. Write( ");\n" );
  357. }
  358. // add our needed preprocessor definitions
  359. CSplitString preprocessorDefines( pKV->GetString( g_pOption_PreprocessorDefinitions ), (const char**)g_IncludeSeparators, Q_ARRAYSIZE(g_IncludeSeparators) );
  360. if ( preprocessorDefines.Count() )
  361. {
  362. Write( "GCC_PREPROCESSOR_DEFINITIONS = (\n" );
  363. ++m_nIndent;
  364. {
  365. Write( "\"$(GCC_PREPROCESSOR_DEFINITIONS)\",\n" );
  366. for ( int i=0; i < preprocessorDefines.Count(); i++ )
  367. {
  368. Write( "\"%s\",\n", preprocessorDefines[i] );
  369. }
  370. }
  371. --m_nIndent;
  372. Write( ");\n" );
  373. }
  374. if ( pDictFiles )
  375. {
  376. CUtlMap<const char *, bool> searchPaths;
  377. searchPaths.SetLessFunc( StringLessThan );
  378. // libraries we consume (specified in our files list)
  379. for ( int i=pDictFiles->First(); i != pDictFiles->InvalidIndex(); i=pDictFiles->Next(i) )
  380. {
  381. const char *pFileName = (*pDictFiles)[i]->m_Filename.String();
  382. if ( IsStaticLibrary( pFileName ) || IsDynamicLibrary( pFileName ) )
  383. {
  384. char rgchLibPath[MAX_PATH];
  385. Q_snprintf( rgchLibPath, sizeof( rgchLibPath ), "%s/%s", pszProjectDir, pFileName );
  386. Q_RemoveDotSlashes( rgchLibPath );
  387. V_StripFilename( rgchLibPath );
  388. int nIndex = searchPaths.Find( rgchLibPath );
  389. if ( nIndex == searchPaths.InvalidIndex() )
  390. {
  391. char *pszLibPath = new char[Q_strlen( rgchLibPath )+1];
  392. Q_strncpy( pszLibPath, rgchLibPath, Q_strlen( rgchLibPath )+1 );
  393. nIndex = searchPaths.Insert( pszLibPath );
  394. }
  395. }
  396. }
  397. // add the library path we know we need to reference
  398. Write( "LIBRARY_SEARCH_PATHS = (\n" );
  399. ++m_nIndent;
  400. {
  401. Write( "\"$(inherited)\",\n" );
  402. FOR_EACH_DICT_FAST( searchPaths, iSearchPath )
  403. {
  404. Write( "\"%s\",\n", searchPaths.Key(iSearchPath) );
  405. delete[] searchPaths.Key(iSearchPath);
  406. }
  407. }
  408. --m_nIndent;
  409. Write( ");\n" );
  410. }
  411. }
  412. class CStringLess
  413. {
  414. public:
  415. bool Less( const char *lhs, const char *rhs, void *pCtx )
  416. {
  417. return ( strcmp( lhs, rhs ) < 0 ? true : false );
  418. }
  419. };
  420. void CSolutionGenerator_XCode::GenerateSolutionFile( const char *pSolutionFilename, CUtlVector<CDependency_Project*> &projects )
  421. {
  422. Assert( projects.Count() == g_vecPGenerators.Count() );
  423. FOR_EACH_VEC( projects, iProject )
  424. {
  425. AssertFatal( !Q_strcmp( projects[iProject]->m_ProjectName, g_vecPGenerators[iProject]->GetProjectName() ) );
  426. }
  427. char sPbxProjFile[MAX_PATH];
  428. sprintf( sPbxProjFile, "%s.xcodeproj", pSolutionFilename );
  429. mkdir( sPbxProjFile, 0777 );
  430. sprintf( sPbxProjFile, "%s.xcodeproj/project.pbxproj", pSolutionFilename );
  431. m_fp = fopen( sPbxProjFile, "wt" );
  432. m_nIndent = 0;
  433. Msg( "\nWriting master XCode project %s.xcodeproj.\n\n", pSolutionFilename );
  434. /** header **/
  435. Write( "// !$*UTF8*$!\n{\n" );
  436. ++m_nIndent;
  437. {
  438. /**
  439. **
  440. ** preamble
  441. **
  442. **/
  443. Write( "archiveVersion = 1;\n" );
  444. Write( "classes = {\n" );
  445. Write( "};\n" );
  446. Write( "objectVersion = 44;\n" );
  447. Write( "objects = {\n" );
  448. {
  449. /**
  450. **
  451. ** buildfiles - any file that's involved in, or the output of, a build phase
  452. **
  453. **/
  454. Write( "\n/* Begin PBXBuildFile section */" );
  455. ++m_nIndent;
  456. {
  457. FOR_EACH_VEC( g_vecPGenerators, iGenerator )
  458. {
  459. // poke into the project we're looking @ in the dependency projects vector to figure out it's location on disk
  460. char rgchProjectDir[MAX_PATH]; rgchProjectDir[0] = '\0';
  461. V_strncpy( rgchProjectDir, projects[iGenerator]->m_ProjectFilename.String(), sizeof( rgchProjectDir ) );
  462. V_StripFilename( rgchProjectDir );
  463. // the files this project references
  464. for ( int i=g_vecPGenerators[iGenerator]->m_Files.First(); i != g_vecPGenerators[iGenerator]->m_Files.InvalidIndex(); i=g_vecPGenerators[iGenerator]->m_Files.Next(i) )
  465. {
  466. char rgchFilePath[MAX_PATH];
  467. Q_snprintf( rgchFilePath, sizeof( rgchFilePath ), "%s/%s", rgchProjectDir, g_vecPGenerators[iGenerator]->m_Files[i]->m_Filename.String() );
  468. Q_RemoveDotSlashes( rgchFilePath );
  469. CFileConfig *pFileConfig = g_vecPGenerators[iGenerator]->m_Files[i];
  470. const char *pFileName = pFileConfig->m_Filename.String();
  471. bool bExcluded = true;
  472. for( int iConfig = 0; iConfig < Q_ARRAYSIZE(k_rgchConfigNames); iConfig++ )
  473. {
  474. bExcluded &= ( pFileConfig->IsExcludedFrom( k_rgchConfigNames[iConfig] ) );
  475. }
  476. if ( bExcluded )
  477. continue;
  478. if ( AppearsInSourcesBuildPhase( g_vecPGenerators[iGenerator]->m_Files[i]->m_Filename.String() ) )
  479. {
  480. Write( "\n" );
  481. Write( "%024llX /* %s in Sources */ = {isa = PBXBuildFile; fileRef = %024llX /* %s */; };", makeoid( pFileName, EOIDTypeBuildFile ), V_UnqualifiedFileName( pFileName ), makeoid( pFileName, EOIDTypeFileReference ), V_UnqualifiedFileName( pFileName ) );
  482. }
  483. if ( IsDynamicLibrary( pFileName ) )
  484. {
  485. Write( "\n" );
  486. Write( "%024llX /* %s in Frameworks */ = {isa = PBXBuildFile; fileRef = %024llX /* %s */; };", makeoid( pFileName, EOIDTypeBuildFile ), V_UnqualifiedFileName( pFileName ), makeoid( pFileName, EOIDTypeFileReference ), V_UnqualifiedFileName( pFileName ) );
  487. }
  488. if ( IsStaticLibrary( pFileName ) )
  489. {
  490. const char *pszLibPfx = "lib";
  491. const char *pszLibName = V_UnqualifiedFileName( pFileName );
  492. if ( pszLibName[0] == 'l' && pszLibName[1] == 'i' && pszLibName[2] == 'b' )
  493. pszLibPfx = "";
  494. Write( "\n" );
  495. Write( "%024llX /* %s%s in Frameworks */ = {isa = PBXBuildFile; fileRef = %024llX /* %s%s */; };", makeoid( pFileName, EOIDTypeBuildFile ), pszLibPfx, V_UnqualifiedFileName( pFileName ), makeoid( pFileName, EOIDTypeFileReference ), pszLibPfx, V_UnqualifiedFileName( pFileName ) );
  496. }
  497. }
  498. // system libraries we link against
  499. KeyValues *pKV = g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[0]->m_pKV;
  500. CSplitString libs( pKV->GetString( g_pOption_SystemLibraries ), (const char**)g_IncludeSeparators, Q_ARRAYSIZE(g_IncludeSeparators) );
  501. for ( int i=0; i < libs.Count(); i++ )
  502. {
  503. Write( "\n" );
  504. Write( "%024llX /* lib%s.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = %024llX /* lib%s.dylib */; };",
  505. makeoid( pKV->GetString( g_pOption_SystemLibraries ), EOIDTypeBuildFile, i ), libs[i],
  506. makeoid( pKV->GetString( g_pOption_SystemLibraries ), EOIDTypeFileReference, i ), libs[i] );
  507. }
  508. // system frameworks we link against
  509. CSplitString sysFrameworks( pKV->GetString( g_pOption_SystemFrameworks ), (const char**)g_IncludeSeparators, Q_ARRAYSIZE(g_IncludeSeparators) );
  510. for ( int i=0; i < sysFrameworks.Count(); i++ )
  511. {
  512. Write( "\n" );
  513. Write( "%024llX /* %s.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = %024llX /* %s.framework */; };",
  514. makeoid( pKV->GetString( g_pOption_SystemFrameworks ), EOIDTypeBuildFile, i ), sysFrameworks[i],
  515. makeoid( pKV->GetString( g_pOption_SystemFrameworks ), EOIDTypeFileReference, i ), sysFrameworks[i] );
  516. }
  517. // local frameworks we link against
  518. CSplitString localFrameworks( pKV->GetString( g_pOption_LocalFrameworks ), (const char**)g_IncludeSeparators, Q_ARRAYSIZE(g_IncludeSeparators) );
  519. for ( int i=0; i < localFrameworks.Count(); i++ )
  520. {
  521. char rgchFrameworkName[MAX_PATH];
  522. V_StripExtension( V_UnqualifiedFileName( localFrameworks[i] ), rgchFrameworkName, sizeof( rgchFrameworkName ) );
  523. Write( "\n" );
  524. Write( "%024llX /* %s.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = %024llX /* %s.framework */; };",
  525. makeoid( pKV->GetString( g_pOption_LocalFrameworks ), EOIDTypeBuildFile, i ), rgchFrameworkName,
  526. makeoid( pKV->GetString( g_pOption_LocalFrameworks ), EOIDTypeFileReference, i ), rgchFrameworkName );
  527. }
  528. // look at everyone who depends on us, and emit a build file pointing at our output file for each of them
  529. CDependency_Project *pCurProject = projects[iGenerator];
  530. const char *pszOutputFile = pKV->GetString( g_pOption_GameOutputFile, "" );
  531. CUtlString sOutputFile = V_UnqualifiedFileName( UsePOSIXSlashes( pszOutputFile ) );
  532. if ( !sOutputFile.Length() || IsStaticLibrary( sOutputFile ) )
  533. {
  534. pszOutputFile = pKV->GetString( g_pOption_OutputFile, "" );
  535. sOutputFile = V_UnqualifiedFileName( UsePOSIXSlashes( pszOutputFile ) );
  536. }
  537. if ( sOutputFile.Length() && ( IsStaticLibrary( sOutputFile ) || IsDynamicLibrary( sOutputFile ) ) )
  538. {
  539. for ( int iTestProject=0; iTestProject < projects.Count(); iTestProject++ )
  540. {
  541. if ( iGenerator == iTestProject )
  542. continue;
  543. CDependency_Project *pTestProject = projects[iTestProject];
  544. CUtlVector<CDependency_Project*> additionalProjectDependencies;
  545. ResolveAdditionalProjectDependencies( pTestProject, projects, additionalProjectDependencies );
  546. int dependsOnFlags = k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse;
  547. if ( pTestProject->DependsOn( pCurProject, dependsOnFlags ) || additionalProjectDependencies.Find( pCurProject ) != additionalProjectDependencies.InvalidIndex() )
  548. {
  549. Write( "\n" );
  550. Write( "%024llX /* (lib)%s */ = {isa = PBXBuildFile; fileRef = %024llX /* (lib)%s - depended on by %s */; };",
  551. makeoid( pszOutputFile, EOIDTypeBuildFile, iTestProject ),
  552. sOutputFile.String(),
  553. makeoid( pszOutputFile, EOIDTypeFileReference ),
  554. sOutputFile.String(),
  555. pTestProject->m_ProjectName.String() );
  556. }
  557. }
  558. }
  559. // and our output file
  560. if ( sOutputFile.Length() )
  561. {
  562. Write( "\n" );
  563. Write( "%024llX /* %s in Products */ = {isa = PBXBuildFile; fileRef = %024llX /* %s */; };",
  564. makeoid( pKV->GetString( g_pOption_GameOutputFile, NULL ) ? pKV->GetString( g_pOption_GameOutputFile, NULL ) : pKV->GetString( g_pOption_OutputFile, NULL ), EOIDTypeBuildFile, -1 ),
  565. sOutputFile.String(),
  566. makeoid( pKV->GetString( g_pOption_GameOutputFile, NULL ) ? pKV->GetString( g_pOption_GameOutputFile, NULL ) : pKV->GetString( g_pOption_OutputFile, NULL ), EOIDTypeFileReference ),
  567. sOutputFile.String() );
  568. }
  569. }
  570. }
  571. --m_nIndent;
  572. Write( "\n/* End PBXBuildFile section */\n" );
  573. /**
  574. **
  575. ** file references - any file that appears in the project browser
  576. **
  577. **/
  578. Write( "\n/* Begin PBXFileReference section */" );
  579. ++m_nIndent;
  580. {
  581. // include the xcconfig files
  582. for( int iConfig = 0; iConfig < Q_ARRAYSIZE(k_rgchXCConfigFiles); iConfig++ )
  583. {
  584. char rgchFilePath[MAX_PATH];
  585. Q_snprintf( rgchFilePath, sizeof( rgchFilePath ), "%s.xcodeproj/../devtools/%s", pSolutionFilename, k_rgchXCConfigFiles[iConfig] );
  586. Q_RemoveDotSlashes( rgchFilePath );
  587. Write( "\n" );
  588. Write( "%024llX /* %s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = \"%s\"; path = \"%s\"; sourceTree = \"<absolute>\"; };",
  589. makeoid( k_rgchXCConfigFiles[iConfig], EOIDTypeFileReference ),
  590. k_rgchXCConfigFiles[iConfig],
  591. k_rgchXCConfigFiles[iConfig],
  592. rgchFilePath
  593. );
  594. }
  595. FOR_EACH_VEC( g_vecPGenerators, iGenerator )
  596. {
  597. // find the project we're looking @ in the dependency projects vector to figure out it's location on disk
  598. char rgchProjectDir[MAX_PATH]; rgchProjectDir[0] = '\0';
  599. V_strncpy( rgchProjectDir, projects[iGenerator]->m_ProjectFilename.String(), sizeof( rgchProjectDir ) );
  600. V_StripFilename( rgchProjectDir );
  601. for ( int i=g_vecPGenerators[iGenerator]->m_Files.First(); i != g_vecPGenerators[iGenerator]->m_Files.InvalidIndex(); i=g_vecPGenerators[iGenerator]->m_Files.Next(i) )
  602. {
  603. char rgchFilePath[MAX_PATH];
  604. Q_snprintf( rgchFilePath, sizeof( rgchFilePath ), "%s/%s", rgchProjectDir, g_vecPGenerators[iGenerator]->m_Files[i]->m_Filename.String() );
  605. Q_RemoveDotSlashes( rgchFilePath );
  606. const char *pFileName = V_UnqualifiedFileName( g_vecPGenerators[iGenerator]->m_Files[i]->m_Filename.String() );
  607. char rgchFileType[MAX_PATH];
  608. XcodeFileTypeFromFileName( pFileName, rgchFileType, sizeof( rgchFileType ) );
  609. Write( "\n" );
  610. Write( "%024llX /* %s */ = {isa = PBXFileReference; fileEncoding = 4; explicitFileType = \"%s\"; name = \"%s\"; path = \"%s\"; sourceTree = \"<absolute>\"; };",
  611. makeoid( g_vecPGenerators[iGenerator]->m_Files[i]->m_Filename.String(), EOIDTypeFileReference ),
  612. pFileName,
  613. rgchFileType,
  614. pFileName,
  615. rgchFilePath );
  616. }
  617. KeyValues *pKV = g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[0]->m_pKV;
  618. // system libraries we link against
  619. CSplitString libs( pKV->GetString( g_pOption_SystemLibraries ), (const char**)g_IncludeSeparators, Q_ARRAYSIZE(g_IncludeSeparators) );
  620. for ( int i=0; i < libs.Count(); i++ )
  621. {
  622. Write( "\n" );
  623. Write( "%024llX /* lib%s.dylib */ = {isa = PBXFileReference; lastKnownFileType = \"compiled.mach-o.dylib\"; name = \"lib%s.dylib\"; path = \"usr/lib/lib%s.dylib\"; sourceTree = SDKROOT; };",
  624. makeoid( pKV->GetString( g_pOption_SystemLibraries ), EOIDTypeFileReference, i ), libs[i], libs[i], libs[i] );
  625. }
  626. // system frameworks we link against
  627. CSplitString sysFrameworks( pKV->GetString( g_pOption_SystemFrameworks ), (const char**)g_IncludeSeparators, Q_ARRAYSIZE(g_IncludeSeparators) );
  628. for ( int i=0; i < sysFrameworks.Count(); i++ )
  629. {
  630. Write( "\n" );
  631. Write( "%024llX /* %s.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = %s.framework; path = System/Library/Frameworks/%s.framework; sourceTree = SDKROOT; };",
  632. makeoid( pKV->GetString( g_pOption_SystemFrameworks ), EOIDTypeFileReference, i ), sysFrameworks[i], sysFrameworks[i], sysFrameworks[i] );
  633. }
  634. // local frameworks we link against
  635. CSplitString localFrameworks( pKV->GetString( g_pOption_LocalFrameworks ), (const char**)g_IncludeSeparators, Q_ARRAYSIZE(g_IncludeSeparators) );
  636. for ( int i=0; i < localFrameworks.Count(); i++ )
  637. {
  638. char rgchFrameworkName[MAX_PATH];
  639. V_StripExtension( V_UnqualifiedFileName( localFrameworks[i] ), rgchFrameworkName, sizeof( rgchFrameworkName ) );
  640. char rgchFrameworkPath[MAX_PATH];
  641. Q_snprintf( rgchFrameworkPath, sizeof( rgchFrameworkPath ), "%s/%s", rgchProjectDir, localFrameworks[i] );
  642. Q_RemoveDotSlashes( rgchFrameworkPath );
  643. Write( "\n" );
  644. Write( "%024llX /* %s.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = %s.framework; path = \"%s\"; sourceTree = \"<absolute>\"; };",
  645. makeoid( pKV->GetString( g_pOption_LocalFrameworks ), EOIDTypeFileReference, i ), rgchFrameworkName, rgchFrameworkName, rgchFrameworkPath );
  646. }
  647. // include the output files (build products)
  648. const char *pszOutputFile = pKV->GetString( g_pOption_GameOutputFile, "" );
  649. CUtlString sOutputFile = V_UnqualifiedFileName( UsePOSIXSlashes( pszOutputFile ) );
  650. if ( !sOutputFile.Length() || IsStaticLibrary( sOutputFile ) )
  651. {
  652. pszOutputFile = pKV->GetString( g_pOption_OutputFile, "" );
  653. sOutputFile = V_UnqualifiedFileName( UsePOSIXSlashes( pszOutputFile ) );
  654. }
  655. if ( sOutputFile.Length() )
  656. {
  657. char rgchFileType[MAX_PATH];
  658. XcodeFileTypeFromFileName( sOutputFile, rgchFileType, sizeof( rgchFileType ) );
  659. Write( "\n" );
  660. if ( IsStaticLibrary( sOutputFile ) )
  661. {
  662. const char *pszLibPfx = "lib";
  663. const char *pszLibName = sOutputFile;
  664. if ( pszLibName[0] == 'l' && pszLibName[0] == 'i' && pszLibName[0] == 'b' )
  665. pszLibPfx = "";
  666. Write( "%024llX /* %s%s */ = {isa = PBXFileReference; explicitFileType = \"%s\"; includeInIndex = 0; path = \"%s%s\"; sourceTree = BUILT_PRODUCTS_DIR; };",
  667. makeoid( pszOutputFile, EOIDTypeFileReference ), pszLibPfx, sOutputFile.String(), rgchFileType, pszLibPfx, sOutputFile.String() );
  668. }
  669. else
  670. Write( "%024llX /* %s */ = {isa = PBXFileReference; explicitFileType = \"%s\"; includeInIndex = 0; path = \"%s\"; sourceTree = BUILT_PRODUCTS_DIR; };",
  671. makeoid( pszOutputFile, EOIDTypeFileReference ), sOutputFile.String(), rgchFileType, sOutputFile.String() );
  672. }
  673. // and the gameoutputfile
  674. CUtlString sGameOutputFile = UsePOSIXSlashes( pKV->GetString( g_pOption_GameOutputFile, "" ) );
  675. if ( sGameOutputFile.Length() )
  676. {
  677. char rgchFilePath[MAX_PATH];
  678. Q_snprintf( rgchFilePath, sizeof( rgchFilePath ), "%s/%s", rgchProjectDir, sGameOutputFile.String() );
  679. Q_RemoveDotSlashes( rgchFilePath );
  680. char rgchFileType[MAX_PATH];
  681. XcodeFileTypeFromFileName( sGameOutputFile, rgchFileType, sizeof( rgchFileType ) );
  682. Write( "\n" );
  683. Write( "%024llX /* %s */ = {isa = PBXFileReference; explicitFileType = \"%s\"; includeInIndex = 0; path = \"%s\"; sourceTree = \"<absolute>\"; };",
  684. makeoid( pKV->GetString( g_pOption_GameOutputFile, "" ), EOIDTypeFileReference ), V_UnqualifiedFileName( sGameOutputFile ), rgchFileType, rgchFilePath );
  685. }
  686. }
  687. }
  688. --m_nIndent;
  689. Write( "\n/* End PBXFileReference section */\n" );
  690. /**
  691. **
  692. ** groups - the file hierarchy displayed in the project
  693. **
  694. **/
  695. Write( "\n/* Begin PBXGroup section */\n" );
  696. ++m_nIndent;
  697. {
  698. FOR_EACH_VEC( g_vecPGenerators, iGenerator )
  699. {
  700. CUtlVector<char*> folderNames;
  701. V_SplitString( "Source Files;Header Files;Resources;VPC Files", ";", folderNames );
  702. static const char* folderExtensions[] =
  703. {
  704. "*.c;*.C;*.cc;*.cpp;*.cp;*.cxx;*.c++;*.prg;*.pas;*.dpr;*.asm;*.s;*.bas;*.java;*.cs;*.sc;*.e;*.cob;*.html;*.tcl;*.py;*.pl;*.m;*.mm",
  705. "*.h;*.H;*.hh;*.hpp;*.hxx;*.inc;*.sh;*.cpy;*.if",
  706. "*.plist;*.strings;*.xib;*.rc;*.proto",
  707. "*.vpc"
  708. };
  709. FOR_EACH_VEC( folderNames, iFolder )
  710. {
  711. WriteFilesFolder( makeoid( g_vecPGenerators[iGenerator]->m_ProjectName, EOIDTypeGroup, iFolder+1 ), folderNames[iFolder], folderExtensions[iFolder], g_vecPGenerators[iGenerator]->m_Files );
  712. }
  713. Write( "%024llX /* %s */ = {\n", makeoid( g_vecPGenerators[iGenerator], EOIDTypeGroup ), g_vecPGenerators[iGenerator]->GetProjectName().String() );
  714. ++m_nIndent;
  715. {
  716. Write( "isa = PBXGroup;\n" );
  717. Write( "children = (\n" );
  718. ++m_nIndent;
  719. {
  720. FOR_EACH_VEC( folderNames, iFolder )
  721. {
  722. Write( "%024llX /* %s */,\n", makeoid( g_vecPGenerators[iGenerator]->m_ProjectName, EOIDTypeGroup, iFolder+1 ), folderNames[iFolder] );
  723. }
  724. KeyValues *pKV = g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[0]->m_pKV;
  725. // system libraries we link against
  726. CSplitString libs( pKV->GetString( g_pOption_SystemLibraries ), (const char**)g_IncludeSeparators, Q_ARRAYSIZE(g_IncludeSeparators) );
  727. for ( int i=0; i < libs.Count(); i++ )
  728. {
  729. Write( "%024llX /* lib%s.dylib (system library) */,\n", makeoid( pKV->GetString( g_pOption_SystemLibraries ), EOIDTypeFileReference, i ), libs[i] );
  730. }
  731. // system frameworks we link against
  732. CSplitString sysFrameworks( pKV->GetString( g_pOption_SystemFrameworks ), (const char**)g_IncludeSeparators, Q_ARRAYSIZE(g_IncludeSeparators) );
  733. for ( int i=0; i < sysFrameworks.Count(); i++ )
  734. {
  735. Write( "%024llX /* %s.framework (system framework) */,\n", makeoid( pKV->GetString( g_pOption_SystemFrameworks ), EOIDTypeFileReference, i ), sysFrameworks[i] );
  736. }
  737. // local frameworks we link against
  738. CSplitString localFrameworks( pKV->GetString( g_pOption_LocalFrameworks ), (const char**)g_IncludeSeparators, Q_ARRAYSIZE(g_IncludeSeparators) );
  739. for ( int i=0; i < localFrameworks.Count(); i++ )
  740. {
  741. char rgchFrameworkName[MAX_PATH];
  742. V_StripExtension( V_UnqualifiedFileName( localFrameworks[i] ), rgchFrameworkName, sizeof( rgchFrameworkName ) );
  743. Write( "%024llX /* %s.framework (local framework) */,\n", makeoid( pKV->GetString( g_pOption_LocalFrameworks ), EOIDTypeFileReference, i ), rgchFrameworkName );
  744. }
  745. // libraries we consume (specified in our files list)
  746. for ( int i=g_vecPGenerators[iGenerator]->m_Files.First(); i != g_vecPGenerators[iGenerator]->m_Files.InvalidIndex(); i=g_vecPGenerators[iGenerator]->m_Files.Next(i) )
  747. {
  748. CUtlString sFileName = V_UnqualifiedFileName( UsePOSIXSlashes( g_vecPGenerators[iGenerator]->m_Files[i]->m_Filename.String() ) );
  749. bool bInclude = IsDynamicLibrary( sFileName );
  750. if ( IsStaticLibrary( sFileName ) )
  751. {
  752. bInclude = true;
  753. FOR_EACH_VEC( g_vecPGenerators, iGenerator2 )
  754. {
  755. // don't include static libs generated by other projects - we'll pull them out of the built products tree
  756. KeyValues *pKV = g_vecPGenerators[iGenerator2]->m_BaseConfigData.m_Configurations[0]->m_pKV;
  757. CUtlString sOutputFile = V_UnqualifiedFileName( UsePOSIXSlashes( pKV->GetString( g_pOption_OutputFile, "" ) ) );
  758. if ( !Q_stricmp( sFileName, sOutputFile ) )
  759. {
  760. bInclude = false;
  761. break;
  762. }
  763. }
  764. }
  765. if ( bInclude )
  766. Write( "%024llX /* %s in Frameworks (explicit) */,\n", makeoid( g_vecPGenerators[iGenerator]->m_Files[i]->m_Filename.String(), EOIDTypeFileReference ), sFileName.String() );
  767. }
  768. CUtlString sOutputFile = V_UnqualifiedFileName( UsePOSIXSlashes( pKV->GetString( g_pOption_OutputFile, "" ) ) );
  769. if ( sOutputFile.Length() )
  770. Write( "%024llX /* %s */,\n", makeoid( pKV->GetString( g_pOption_OutputFile, "" ), EOIDTypeFileReference ), sOutputFile.String() );
  771. }
  772. --m_nIndent;
  773. Write( ");\n" );
  774. Write( "name = \"%s\";\n", g_vecPGenerators[iGenerator]->GetProjectName().String() );
  775. Write( "sourceTree = \"<group>\";\n" );
  776. }
  777. --m_nIndent;
  778. Write( "};\n" );
  779. }
  780. // root group - the top of the displayed hierarchy
  781. Write( "%024llX = {\n", makeoid( &projects, EOIDTypeGroup ) );
  782. ++m_nIndent;
  783. {
  784. Write( "isa = PBXGroup;\n" );
  785. Write( "children = (\n" );
  786. // sort the projects by name before we emit the list
  787. CUtlSortVector< CUtlString, CStringLess > vecSortedProjectNames;
  788. FOR_EACH_VEC( g_vecPGenerators, iGen )
  789. {
  790. // fprintf( stderr, "inserting %s (%p)\n", g_vecPGenerators[iGen]->GetProjectName().String(), &g_vecPGenerators[iGen]->GetProjectName() );
  791. vecSortedProjectNames.Insert( g_vecPGenerators[iGen]->GetProjectName() );
  792. }
  793. ++m_nIndent;
  794. {
  795. FOR_EACH_VEC( vecSortedProjectNames, iProjectName )
  796. {
  797. // fprintf( stderr, "looking for %s\n", vecSortedProjectNames[iProjectName].String() );
  798. // and each project's group (of groups)
  799. FOR_EACH_VEC( g_vecPGenerators, iGenerator )
  800. {
  801. if ( strcmp( g_vecPGenerators[iGenerator]->m_ProjectName.String(), vecSortedProjectNames[iProjectName] ) )
  802. {
  803. // fprintf( stderr, " skipping '%s' (%p) != '%s' (%p) (%d, %d)\n", g_vecPGenerators[iGenerator]->GetProjectName().String(), g_vecPGenerators[iGenerator]->GetProjectName().String(), vecSortedProjectNames[iProjectName].String(), vecSortedProjectNames[iProjectName].String(), iGenerator, iProjectName );
  804. continue;
  805. }
  806. // fprintf( stderr, "emitting %s (%d, %d)\n", g_vecPGenerators[iGenerator]->GetProjectName().String(), iGenerator, iProjectName );
  807. Write( "%024llX /* %s */,\n", makeoid( g_vecPGenerators[iGenerator], EOIDTypeGroup ), g_vecPGenerators[iGenerator]->GetProjectName().String() );
  808. break;
  809. }
  810. }
  811. // add the build config (.xcconfig) files
  812. for( int iConfig = 0; iConfig < Q_ARRAYSIZE(k_rgchXCConfigFiles); iConfig++ )
  813. {
  814. Write( "%024llX /* %s */, \n", makeoid( k_rgchXCConfigFiles[iConfig], EOIDTypeFileReference ), k_rgchXCConfigFiles[iConfig] );
  815. }
  816. }
  817. --m_nIndent;
  818. Write( ");\n" );
  819. Write( "sourceTree = \"<group>\";\n" );
  820. }
  821. --m_nIndent;
  822. Write( "};" );
  823. }
  824. m_nIndent--;
  825. Write( "\n/* End PBXGroup section */\n" );
  826. /**
  827. **
  828. ** the sources build phases - each target that compiles source references on of these, it in turn references the source files to be compiled
  829. **
  830. **/
  831. Write( "\n/* Begin PBXSourcesBuildPhase section */" );
  832. ++m_nIndent;
  833. FOR_EACH_VEC( projects, iProject )
  834. {
  835. Write( "\n" );
  836. Write( "%024llX /* Sources */ = {\n", makeoid( projects[iProject], EOIDTypeSourcesBuildPhase ) );
  837. ++m_nIndent;
  838. {
  839. Write( "isa = PBXSourcesBuildPhase;\n" );
  840. Write( "buildActionMask = 2147483647;\n" );
  841. Write( "files = (\n" );
  842. ++m_nIndent;
  843. {
  844. for ( int i=g_vecPGenerators[iProject]->m_Files.First(); i != g_vecPGenerators[iProject]->m_Files.InvalidIndex(); i=g_vecPGenerators[iProject]->m_Files.Next(i) )
  845. {
  846. const char *pFileName = g_vecPGenerators[iProject]->m_Files[i]->m_Filename.String();
  847. if ( AppearsInSourcesBuildPhase( pFileName ) )
  848. {
  849. Write( "%024llX /* %s in Sources */,\n", makeoid( pFileName, EOIDTypeBuildFile ), V_UnqualifiedFileName( UsePOSIXSlashes( pFileName ) ) );
  850. }
  851. }
  852. }
  853. --m_nIndent;
  854. Write( ");\n");
  855. Write( "runOnlyForDeploymentPostprocessing = 0;\n" );
  856. }
  857. --m_nIndent;
  858. Write( "};" );
  859. }
  860. --m_nIndent;
  861. Write( "\n/* End PBXSourcesBuildPhase section */\n" );
  862. /**
  863. **
  864. ** the frameworks build phases - each target that links libraries (static, dyamic, framework) has one of these, it references the linked thing
  865. **
  866. **/
  867. Write( "\n/* Begin PBXFrameworksBuildPhase section */" );
  868. ++m_nIndent;
  869. FOR_EACH_VEC( projects, iProject )
  870. {
  871. Write( "\n" );
  872. Write( "%024llX /* Frameworks */ = {\n", makeoid( projects[iProject], EOIDTypeFrameworksBuildPhase ) );
  873. ++m_nIndent;
  874. {
  875. Write( "isa = PBXFrameworksBuildPhase;\n" );
  876. Write( "buildActionMask = 2147483647;\n" );
  877. Write( "files = (\n" );
  878. ++m_nIndent;
  879. {
  880. // libraries we consume (specified in our files list)
  881. for ( int i=g_vecPGenerators[iProject]->m_Files.First(); i != g_vecPGenerators[iProject]->m_Files.InvalidIndex(); i=g_vecPGenerators[iProject]->m_Files.Next(i) )
  882. {
  883. const char *pFileName = g_vecPGenerators[iProject]->m_Files[i]->m_Filename.String();
  884. if ( IsStaticLibrary( UsePOSIXSlashes( pFileName ) ) || IsDynamicLibrary( UsePOSIXSlashes( pFileName ) ) )
  885. {
  886. CUtlString sFileName = V_UnqualifiedFileName( UsePOSIXSlashes( g_vecPGenerators[iProject]->m_Files[i]->m_Filename.String() ) );
  887. bool bInclude = true;
  888. FOR_EACH_VEC( g_vecPGenerators, iGenerator )
  889. {
  890. // don't include libs generated by other projects - we'll pull them out of the built products tree
  891. KeyValues *pKV = g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[0]->m_pKV;
  892. CUtlString sOutputFile = V_UnqualifiedFileName( UsePOSIXSlashes( pKV->GetString( g_pOption_OutputFile, "" ) ) );
  893. if ( !Q_stricmp( sFileName, sOutputFile ) )
  894. {
  895. bInclude = false;
  896. break;
  897. }
  898. }
  899. if ( bInclude )
  900. Write( "%024llX /* %s in Frameworks (explicit) */,\n", makeoid( pFileName, EOIDTypeBuildFile ), V_UnqualifiedFileName( UsePOSIXSlashes( pFileName ) ) );
  901. }
  902. }
  903. // libraries from projects we depend on
  904. CDependency_Project *pCurProject = projects[iProject];
  905. CUtlVector<CDependency_Project*> additionalProjectDependencies;
  906. ResolveAdditionalProjectDependencies( pCurProject, projects, additionalProjectDependencies );
  907. for ( int iTestProject=projects.Count()-1; iTestProject >= 0; --iTestProject )
  908. {
  909. if ( iProject == iTestProject )
  910. continue;
  911. CDependency_Project *pTestProject = projects[iTestProject];
  912. int dependsOnFlags = k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse;
  913. if ( pCurProject->DependsOn( pTestProject, dependsOnFlags ) || additionalProjectDependencies.Find( pTestProject ) != additionalProjectDependencies.InvalidIndex() )
  914. {
  915. KeyValues *pKV = g_vecPGenerators[iTestProject]->m_BaseConfigData.m_Configurations[0]->m_pKV;
  916. const char *pszOutputFile = pKV->GetString( g_pOption_GameOutputFile, "" );
  917. CUtlString sOutputFile = V_UnqualifiedFileName( UsePOSIXSlashes( pszOutputFile ) );
  918. if ( !sOutputFile.Length() || IsStaticLibrary( sOutputFile ) )
  919. {
  920. pszOutputFile = pKV->GetString( g_pOption_OutputFile, "" );
  921. sOutputFile = V_UnqualifiedFileName( UsePOSIXSlashes( pszOutputFile ) );
  922. }
  923. if ( sOutputFile.Length() && ( IsStaticLibrary( sOutputFile ) || IsDynamicLibrary( sOutputFile ) ) )
  924. {
  925. Write( "%024llX /* (lib)%s (dependency) */,\n", makeoid( pszOutputFile, EOIDTypeBuildFile, iProject ), sOutputFile.String() );
  926. }
  927. }
  928. }
  929. KeyValues *pKV = g_vecPGenerators[iProject]->m_BaseConfigData.m_Configurations[0]->m_pKV;
  930. // local frameworks we link against
  931. CSplitString localFrameworks( pKV->GetString( g_pOption_LocalFrameworks ), (const char**)g_IncludeSeparators, Q_ARRAYSIZE(g_IncludeSeparators) );
  932. for ( int i=0; i < localFrameworks.Count(); i++ )
  933. {
  934. char rgchFrameworkName[MAX_PATH];
  935. V_StripExtension( V_UnqualifiedFileName( localFrameworks[i] ), rgchFrameworkName, sizeof( rgchFrameworkName ) );
  936. Write( "%024llX /* %s in Frameworks (local framework) */,\n", makeoid( pKV->GetString( g_pOption_LocalFrameworks ), EOIDTypeBuildFile, i ), rgchFrameworkName );
  937. }
  938. // system frameworks we link against
  939. CSplitString sysFrameworks( pKV->GetString( g_pOption_SystemFrameworks ), (const char**)g_IncludeSeparators, Q_ARRAYSIZE(g_IncludeSeparators) );
  940. for ( int i=0; i < sysFrameworks.Count(); i++ )
  941. {
  942. Write( "%024llX /* %s in Frameworks (system framework) */,\n", makeoid( pKV->GetString( g_pOption_SystemFrameworks ), EOIDTypeBuildFile, i ), sysFrameworks[i] );
  943. }
  944. // system libraries we link against
  945. CSplitString libs( pKV->GetString( g_pOption_SystemLibraries ), (const char**)g_IncludeSeparators, Q_ARRAYSIZE(g_IncludeSeparators) );
  946. for ( int i=0; i < libs.Count(); i++ )
  947. {
  948. Write( "%024llX /* %s in Frameworks (system library) */,\n", makeoid( pKV->GetString( g_pOption_SystemLibraries ), EOIDTypeBuildFile, i ), libs[i] );
  949. }
  950. }
  951. --m_nIndent;
  952. Write( ");\n");
  953. Write( "runOnlyForDeploymentPostprocessing = 0;\n" );
  954. }
  955. --m_nIndent;
  956. Write( "};" );
  957. }
  958. --m_nIndent;
  959. Write( "\n/* End PBXFrameworksBuildPhase section */\n" );
  960. /**
  961. **
  962. ** the shell script (pre/post build step) build phases - each target that generates a "gameoutputfile" has one of these,
  963. ** to p4 edit the target and copy the build result there.
  964. **
  965. **/
  966. Write( "\n/* Begin PBXShellScriptBuildPhase section */" );
  967. ++m_nIndent;
  968. {
  969. FOR_EACH_VEC( g_vecPGenerators, iGenerator )
  970. {
  971. char rgchProjectDir[MAX_PATH]; rgchProjectDir[0] = '\0';
  972. V_strncpy( rgchProjectDir, projects[iGenerator]->m_ProjectFilename.String(), sizeof( rgchProjectDir ) );
  973. V_StripFilename( rgchProjectDir );
  974. char sInputFiles[8192]; sInputFiles[0] = '\0';
  975. char sCommands[8192]; sCommands[0] = '\0';
  976. char sOutputFiles[8192]; sOutputFiles[0] = '\0';
  977. // we don't have an output file - wander the list of files, looking for custom build steps
  978. // if we find any, magic up a shell script to run them
  979. for ( int i=g_vecPGenerators[iGenerator]->m_Files.First(); i != g_vecPGenerators[iGenerator]->m_Files.InvalidIndex(); i=g_vecPGenerators[iGenerator]->m_Files.Next(i) )
  980. {
  981. CFileConfig *pFileConfig = g_vecPGenerators[iGenerator]->m_Files[i];
  982. CSpecificConfig *pFileSpecificData = pFileConfig->GetOrCreateConfig( g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[1]->GetConfigName(),
  983. g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[1] );
  984. CUtlString sCustomBuildCommandLine = pFileSpecificData->GetOption( g_pOption_CommandLine );
  985. CUtlString sOutputFile = pFileSpecificData->GetOption( g_pOption_Outputs );
  986. if ( sOutputFile.Length() && sCustomBuildCommandLine.Length() )
  987. {
  988. char sInFile[MAX_PATH];
  989. Q_snprintf( sInFile, sizeof( sInFile ), "%s/%s", rgchProjectDir, UsePOSIXSlashes( pFileConfig->m_Filename.String() ) );
  990. Q_snprintf( sInputFiles, sizeof( sInputFiles ), "%s%s%s", sInputFiles, sInputFiles[0] ? ";" : "", UsePOSIXSlashes( pFileConfig->m_Filename.String() ) );
  991. char sCommand[8192];
  992. CBaseProjectDataCollector::DoStandardVisualStudioReplacements( sCustomBuildCommandLine, sInFile, sCommand, sizeof( sCommand ) );
  993. Q_StrSubstInPlace( sCommand, sizeof( sCommand ), "$(OBJ_DIR)", rgchProjectDir, false );
  994. Q_snprintf( sCommands, sizeof( sCommands ), "%s%s;\\n", sCommands, sCommand );
  995. char sOutFile[MAX_PATH];
  996. CBaseProjectDataCollector::DoStandardVisualStudioReplacements( sOutputFile, sInFile, sOutFile, sizeof( sOutFile ) );
  997. Q_StrSubstInPlace( sOutFile, sizeof( sOutFile ), "$(OBJ_DIR)", rgchProjectDir, false );
  998. Q_snprintf( sOutputFiles, sizeof( sOutputFiles ), "%s%s%s", sOutputFiles, sOutFile[0] ? ";" : "", sOutFile );
  999. }
  1000. }
  1001. if ( Q_strlen( sCommands ) )
  1002. {
  1003. Write( "\n" );
  1004. Write( "%024llX /* ShellScript */ = {\n", makeoid( projects[iGenerator], EOIDTypeShellScriptBuildPhase, 0 ) );
  1005. ++m_nIndent;
  1006. {
  1007. Write( "isa = PBXShellScriptBuildPhase;\n" );
  1008. Write( "buildActionMask = 2147483647;\n" );
  1009. Write( "files = (\n" );
  1010. Write( ");\n" );
  1011. Write( "inputPaths = (\n" );
  1012. ++m_nIndent;
  1013. {
  1014. CSplitString inFiles( sInputFiles, ";" );
  1015. for ( int i = 0; i < inFiles.Count(); i ++ )
  1016. {
  1017. char rgchFilePath[MAX_PATH];
  1018. Q_snprintf( rgchFilePath, sizeof( rgchFilePath ), "%s/%s", rgchProjectDir, inFiles[i] );
  1019. Q_RemoveDotSlashes( rgchFilePath );
  1020. Write( "\"%s\",\n", rgchFilePath );
  1021. }
  1022. }
  1023. --m_nIndent;
  1024. Write( ");\n" );
  1025. Write( "outputPaths = (\n" );
  1026. ++m_nIndent;
  1027. {
  1028. CSplitString outFiles( sOutputFiles, ";" );
  1029. for ( int i = 0; i < outFiles.Count(); i ++ )
  1030. {
  1031. char rgchFilePath[MAX_PATH];
  1032. Q_snprintf( rgchFilePath, sizeof( rgchFilePath ), "%s/%s", rgchProjectDir, outFiles[i] );
  1033. Q_RemoveDotSlashes( rgchFilePath );
  1034. Write( "\"%s\",\n", rgchFilePath );
  1035. }
  1036. }
  1037. --m_nIndent;
  1038. Write( ");\n");
  1039. Write( "runOnlyForDeploymentPostprocessing = 0;\n" );
  1040. Write( "shellPath = /bin/bash;\n" );
  1041. Write( "shellScript = \"cd %s;\\n"
  1042. "%s\";\n", rgchProjectDir, sCommands );
  1043. }
  1044. --m_nIndent;
  1045. Write( "};" );
  1046. }
  1047. KeyValues *pDebugKV = g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[0]->m_pKV;
  1048. CUtlString sDebugOutputFile = UsePOSIXSlashes( pDebugKV->GetString( g_pOption_GameOutputFile, "" ) );
  1049. KeyValues *pReleaseKV = g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[1]->m_pKV;
  1050. CUtlString sReleaseOutputFile = UsePOSIXSlashes( pReleaseKV->GetString( g_pOption_GameOutputFile, "" ) );
  1051. if ( !sDebugOutputFile.Length() || !sReleaseOutputFile.Length() )
  1052. {
  1053. sDebugOutputFile = UsePOSIXSlashes( pDebugKV->GetString( g_pOption_OutputFile, "" ) );
  1054. sReleaseOutputFile = UsePOSIXSlashes( pReleaseKV->GetString( g_pOption_OutputFile, "" ) );
  1055. }
  1056. if ( sDebugOutputFile.Length() || sReleaseOutputFile.Length() )
  1057. {
  1058. char rgchDebugFilePath[MAX_PATH];
  1059. Q_snprintf( rgchDebugFilePath, sizeof( rgchDebugFilePath ), "%s/%s", rgchProjectDir, sDebugOutputFile.String() );
  1060. Q_RemoveDotSlashes( rgchDebugFilePath );
  1061. char rgchReleaseFilePath[MAX_PATH];
  1062. Q_snprintf( rgchReleaseFilePath, sizeof( rgchReleaseFilePath ), "%s/%s", rgchProjectDir, sReleaseOutputFile.String() );
  1063. Q_RemoveDotSlashes( rgchReleaseFilePath );
  1064. Write( "\n" );
  1065. Write( "%024llX /* ShellScript */ = {\n", makeoid( projects[iGenerator], EOIDTypeShellScriptBuildPhase, 1 ) );
  1066. ++m_nIndent;
  1067. {
  1068. Write( "isa = PBXShellScriptBuildPhase;\n" );
  1069. Write( "buildActionMask = 2147483647;\n" );
  1070. Write( "files = (\n" );
  1071. Write( ");\n" );
  1072. Write( "inputPaths = (\n" );
  1073. ++m_nIndent;
  1074. {
  1075. Write( "\"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}\",\n" );
  1076. }
  1077. --m_nIndent;
  1078. Write( ");\n" );
  1079. Write( "outputPaths = (\n" );
  1080. ++m_nIndent;
  1081. {
  1082. Q_StrSubstInPlace( rgchDebugFilePath, sizeof( rgchDebugFilePath ), "/lib/osx32/debug/", "/lib/osx32/${BUILD_STYLE}/", false );
  1083. Q_StrSubstInPlace( rgchReleaseFilePath, sizeof( rgchReleaseFilePath ), "/lib/osx32/release/", "/lib/osx32/${BUILD_STYLE}/", false );
  1084. Write( "\"%s\",\n", rgchDebugFilePath );
  1085. if ( Q_strcmp( rgchDebugFilePath, rgchReleaseFilePath ) )
  1086. Write( "\"%s\",\n", rgchReleaseFilePath );
  1087. }
  1088. --m_nIndent;
  1089. Write( ");\n");
  1090. Write( "runOnlyForDeploymentPostprocessing = 0;\n" );
  1091. Write( "shellPath = /bin/bash;\n" );
  1092. Write( "shellScript = "
  1093. "\"if [ \\\"$BUILD_STYLE\\\" == \\\"Release\\\" ]; then\\n"
  1094. " OUTPUTFILE=%s\\n"
  1095. " POST_BUILD_COMMAND=%s\\n"
  1096. "else\\n"
  1097. " OUTPUTFILE=%s\\n"
  1098. " POST_BUILD_COMMAND=%s\\n"
  1099. "fi\\n"
  1100. "if [ \\\"$POST_BUILD_COMMAND\\\" != \\\"\\\" ]; then\\n"
  1101. " ${POST_BUILD_COMMAND}\\n"
  1102. "fi\\n"
  1103. "if [ -x \\\"$OUTPUTFILE\\\" -o -x \\\"$OUTPUTFILE.dSYM\\\" ]; then\\n"
  1104. " p4 edit \\\"$OUTPUTFILE...\\\" | grep -v \\\"also opened\\\"\\n"
  1105. "fi\\n"
  1106. "if [ -d \\\"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}.dSYM\\\" ]; then\\n"
  1107. " cp -R \\\"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}.dSYM\\\" \\\"${OUTPUTFILE}.dSYM\\\"\\n"
  1108. "fi\\n"
  1109. "cp -v \\\"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}\\\" \\\"$OUTPUTFILE\\\"\";\n",
  1110. rgchReleaseFilePath, pReleaseKV->GetString( g_pOption_CommandLine, "" ),
  1111. rgchDebugFilePath, pDebugKV->GetString( g_pOption_CommandLine, "" ) );
  1112. }
  1113. --m_nIndent;
  1114. Write( "};" );
  1115. }
  1116. }
  1117. }
  1118. --m_nIndent;
  1119. Write( "\n/* End PBXShellScriptBuildPhase section */\n" );
  1120. /**
  1121. **
  1122. ** nativetargets section - build targets, which ultimately reference build phases
  1123. **
  1124. **/
  1125. Write( "\n/* Begin PBXNativeTarget section */" );
  1126. ++m_nIndent;
  1127. FOR_EACH_VEC( projects, iProject )
  1128. {
  1129. KeyValues *pKV = g_vecPGenerators[iProject]->m_BaseConfigData.m_Configurations[0]->m_pKV;
  1130. CUtlString sOutputFile = UsePOSIXSlashes( pKV->GetString( g_pOption_GameOutputFile, "" ) );
  1131. if ( !sOutputFile.Length() )
  1132. sOutputFile = UsePOSIXSlashes( pKV->GetString( g_pOption_OutputFile, "" ) );
  1133. if ( !sOutputFile.Length() )
  1134. continue;
  1135. Write( "\n" );
  1136. Write( "%024llX /* %s */ = {\n", makeoid( projects[iProject], EOIDTypeNativeTarget ), projects[iProject]->m_ProjectName.String() );
  1137. ++m_nIndent;
  1138. {
  1139. Write( "isa = PBXNativeTarget;\n" );
  1140. Write( "buildConfigurationList = %024llX /* Build configuration list for PBXNativeTarget \"%s\" */;\n", makeoid( projects[iProject], EOIDTypeConfigurationList ), projects[iProject]->m_ProjectName.String() );
  1141. Write( "buildPhases = (\n" );
  1142. ++m_nIndent;
  1143. {
  1144. Write( "%024llX /* ShellScript */,\n", makeoid( projects[iProject], EOIDTypeShellScriptBuildPhase, 0 ) );
  1145. Write( "%024llX /* Sources */,\n", makeoid( projects[iProject], EOIDTypeSourcesBuildPhase ) );
  1146. Write( "%024llX /* Frameworks */,\n", makeoid( projects[iProject], EOIDTypeFrameworksBuildPhase ) );
  1147. Write( "%024llX /* ShellScript */,\n", makeoid( projects[iProject], EOIDTypeShellScriptBuildPhase, 1 ) );
  1148. }
  1149. --m_nIndent;
  1150. Write( ");\n" );
  1151. Write( "buildRules = (\n" );
  1152. ++m_nIndent;
  1153. {
  1154. }
  1155. --m_nIndent;
  1156. Write( ");\n" );
  1157. Write( "dependencies = (\n" );
  1158. ++m_nIndent;
  1159. {
  1160. // these dependencies point to the dependency objects, which reference other projects through the container item proxy objects
  1161. CDependency_Project *pCurProject = projects[iProject];
  1162. CUtlVector<CDependency_Project*> additionalProjectDependencies;
  1163. ResolveAdditionalProjectDependencies( pCurProject, projects, additionalProjectDependencies );
  1164. for ( int iTestProject=0; iTestProject < projects.Count(); iTestProject++ )
  1165. {
  1166. if ( iProject == iTestProject )
  1167. continue;
  1168. CDependency_Project *pTestProject = projects[iTestProject];
  1169. int dependsOnFlags = k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse;
  1170. if ( pCurProject->DependsOn( pTestProject, dependsOnFlags ) || additionalProjectDependencies.Find( pTestProject ) != additionalProjectDependencies.InvalidIndex() )
  1171. {
  1172. Write( "%024llX /* %s */,\n", makeoid( projects[iProject], EOIDTypeTargetDependency, (uint16_t)iTestProject ), pTestProject->GetName() );
  1173. }
  1174. }
  1175. }
  1176. --m_nIndent;
  1177. Write( ");\n" );
  1178. Write( "productName = \"%s\";\n", projects[iProject]->m_ProjectName.String() );
  1179. Write( "name = \"%s\";\n", projects[iProject]->m_ProjectName.String() );
  1180. if ( sOutputFile.Length() )
  1181. Write( "productReference = %024llX /* %s */;\n", makeoid( pKV->GetString( g_pOption_GameOutputFile, NULL ) ? pKV->GetString( g_pOption_GameOutputFile, NULL ) : pKV->GetString( g_pOption_OutputFile, "" ), EOIDTypeFileReference ), V_UnqualifiedFileName( sOutputFile ) );
  1182. char rgchProductType[MAX_PATH];
  1183. XcodeProductTypeFromFileName( V_UnqualifiedFileName( sOutputFile ), rgchProductType, sizeof( rgchProductType ) );
  1184. Write( "productType = \"%s\";\n", rgchProductType );
  1185. }
  1186. --m_nIndent;
  1187. Write( "};" );
  1188. }
  1189. --m_nIndent;
  1190. Write( "\n/* End PBXNativeTarget section */\n" );
  1191. /**
  1192. **
  1193. ** aggregate targets - for targets that have no output files (i.e. are scripts)
  1194. ** and the "all" target
  1195. **
  1196. **/
  1197. Write( "\n/* Begin PBXAggregateTarget section */\n" );
  1198. ++m_nIndent;
  1199. {
  1200. Write( "%024llX /* All */ = {\n", makeoid( this, EOIDTypeAggregateTarget ) );
  1201. ++m_nIndent;
  1202. {
  1203. Write( "isa = PBXAggregateTarget;\n" );
  1204. Write( "buildConfigurationList = %024llX /* Build configuration list for PBXAggregateTarget \"All\" */;\n", makeoid( this, EOIDTypeConfigurationList, 1 ) );
  1205. Write( "buildPhases = (\n" );
  1206. Write( ");\n" );
  1207. Write( "dependencies = (\n" );
  1208. ++m_nIndent;
  1209. {
  1210. FOR_EACH_VEC( projects, iProject )
  1211. {
  1212. // note the sneaky -1 ordinal here, is we can later generate a dependency block for the target thats not tied to any other targets dependency.
  1213. Write( "%024llX /* PBXProjectDependency */,\n", makeoid( projects[iProject], EOIDTypeTargetDependency, -1 ) );
  1214. }
  1215. }
  1216. --m_nIndent;
  1217. Write( ");\n" );
  1218. Write( "name = All;\n" );
  1219. Write( "productName = All;\n" );
  1220. }
  1221. --m_nIndent;
  1222. Write( "};\n" );
  1223. FOR_EACH_VEC( projects, iProject )
  1224. {
  1225. KeyValues *pKV = g_vecPGenerators[iProject]->m_BaseConfigData.m_Configurations[0]->m_pKV;
  1226. CUtlString sOutputFile = UsePOSIXSlashes( pKV->GetString( g_pOption_GameOutputFile, "" ) );
  1227. if ( !sOutputFile.Length() )
  1228. sOutputFile = UsePOSIXSlashes( pKV->GetString( g_pOption_OutputFile, "" ) );
  1229. if ( sOutputFile.Length() )
  1230. continue;
  1231. // NOTE: the use of EOIDTypeNativeTarget here is intentional - a project will never appear as both, and this makes things link up without
  1232. // having to special case in dependencies and aggregate targets
  1233. Write( "%024llX /* %s */ = {\n", makeoid( projects[iProject], EOIDTypeNativeTarget ), projects[iProject]->m_ProjectName.String() );
  1234. ++m_nIndent;
  1235. {
  1236. Write( "isa = PBXAggregateTarget;\n" );
  1237. Write( "buildConfigurationList = %024llX /* Build configuration list for PBXAggregateTarget \"%s\" */;\n", makeoid( projects[iProject], EOIDTypeConfigurationList ), projects[iProject]->m_ProjectName.String() );
  1238. Write( "buildPhases = (\n" );
  1239. ++m_nIndent;
  1240. {
  1241. Write( "%024llX /* ShellScript */,\n", makeoid( projects[iProject], EOIDTypeShellScriptBuildPhase ) );
  1242. }
  1243. --m_nIndent;
  1244. Write( ");\n" );
  1245. Write( "buildRules = (\n" );
  1246. ++m_nIndent;
  1247. {
  1248. }
  1249. --m_nIndent;
  1250. Write( ");\n" );
  1251. Write( "dependencies = (\n" );
  1252. ++m_nIndent;
  1253. {
  1254. // these dependencies point to the dependency objects, which reference other projects through the container item proxy objects
  1255. CDependency_Project *pCurProject = projects[iProject];
  1256. CUtlVector<CDependency_Project*> additionalProjectDependencies;
  1257. ResolveAdditionalProjectDependencies( pCurProject, projects, additionalProjectDependencies );
  1258. for ( int iTestProject=0; iTestProject < projects.Count(); iTestProject++ )
  1259. {
  1260. if ( iProject == iTestProject )
  1261. continue;
  1262. CDependency_Project *pTestProject = projects[iTestProject];
  1263. int dependsOnFlags = k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse;
  1264. if ( pCurProject->DependsOn( pTestProject, dependsOnFlags ) || additionalProjectDependencies.Find( pTestProject ) != additionalProjectDependencies.InvalidIndex() )
  1265. {
  1266. Write( "%024llX /* %s */,\n", makeoid( projects[iProject], EOIDTypeTargetDependency, (uint16_t)iTestProject ), pTestProject->GetName() );
  1267. }
  1268. }
  1269. }
  1270. --m_nIndent;
  1271. Write( ");\n" );
  1272. Write( "name = \"%s\";\n", projects[iProject]->m_ProjectName.String() );
  1273. Write( "productName = \"%s\";\n", projects[iProject]->m_ProjectName.String() );
  1274. }
  1275. --m_nIndent;
  1276. Write( "};" );
  1277. }
  1278. }
  1279. --m_nIndent;
  1280. Write( "\n/* End PBXAggregateTarget section */\n" );
  1281. /**
  1282. **
  1283. ** project section - the top-level object that ties all the bits (targets, groups, ...) together
  1284. **
  1285. **/
  1286. Write( "\n/* Begin PBXProject section */\n" );
  1287. ++m_nIndent;
  1288. Write( "%024llX /* project object */ = {\n", makeoid( this, EOIDTypeProject ) );
  1289. ++m_nIndent;
  1290. {
  1291. Write( "isa = PBXProject;\n" );
  1292. Write( "attributes = {\n" );
  1293. ++m_nIndent;
  1294. {
  1295. Write( "BuildIndependentTargetsInParallel = YES;\n" );
  1296. }
  1297. --m_nIndent;
  1298. Write( "};\n" );
  1299. Write( "buildConfigurationList = %024llX /* Build configuration list for PBXProject \"%s\" */;\n", makeoid( this, EOIDTypeConfigurationList ), V_UnqualifiedFileName( UsePOSIXSlashes( pSolutionFilename ) ) );
  1300. Write( "compatibilityVersion = \"Xcode 3.0\";\n" );
  1301. Write( "hasScannedForEncodings = 0;\n" );
  1302. Write( "mainGroup = %024llX;\n", makeoid( &projects, EOIDTypeGroup ) );
  1303. Write( "productRefGroup = %024llX /* Products */;\n", makeoid( this, EOIDTypeGroup ) );
  1304. Write( "projectDirPath = \"\";\n" );
  1305. Write( "projectRoot = \"\";\n" );
  1306. Write( "targets = (\n" );
  1307. ++m_nIndent;
  1308. {
  1309. Write( "%024llX /* All */,\n", makeoid( this, EOIDTypeAggregateTarget ) );
  1310. // sort the projects by name before we emit the list
  1311. CUtlSortVector< CUtlString, CStringLess > vecSortedProjectNames;
  1312. FOR_EACH_VEC( g_vecPGenerators, iGen )
  1313. {
  1314. vecSortedProjectNames.Insert( g_vecPGenerators[iGen]->GetProjectName() );
  1315. }
  1316. FOR_EACH_VEC( vecSortedProjectNames, iProjectName )
  1317. {
  1318. FOR_EACH_VEC( projects, iProject )
  1319. {
  1320. if ( strcmp( projects[iProject]->m_ProjectName.String(), vecSortedProjectNames[iProjectName] ) )
  1321. {
  1322. continue;
  1323. }
  1324. Write( "%024llX /* %s */,\n", makeoid( projects[iProject], EOIDTypeNativeTarget ), projects[iProject]->m_ProjectName.String() );
  1325. }
  1326. }
  1327. }
  1328. --m_nIndent;
  1329. Write( ");\n" );
  1330. }
  1331. --m_nIndent;
  1332. Write( "};" );
  1333. Write( "\n/* End PBXProject section */\n" );
  1334. /**
  1335. **
  1336. ** container item proxies (no clue, I just work here...) - they sit between projects when expressing dependencies
  1337. **
  1338. **/
  1339. Write( "\n/* Begin PBXContainerItemProxy section */" );
  1340. {
  1341. FOR_EACH_VEC( projects, iProject )
  1342. {
  1343. // for the aggregate target
  1344. Write( "\n" );
  1345. Write( "%024llX /* PBXContainerItemProxy */ = {\n", makeoid( projects[iProject], EOIDTypeContainerItemProxy, -1 ) );
  1346. ++m_nIndent;
  1347. {
  1348. Write( "isa = PBXContainerItemProxy;\n" );
  1349. // it looks like if you cross ref between xcodeprojs, this is the oid for the other xcode proj
  1350. Write( "containerPortal = %024llX; /* Project object */\n", makeoid( this, EOIDTypeProject ) );
  1351. Write( "proxyType = 1;\n" );
  1352. Write( "remoteGlobalIDString = %024llX;\n", makeoid( projects[iProject], EOIDTypeNativeTarget ) );
  1353. Write( "remoteInfo = \"%s\";\n", projects[iProject]->m_ProjectName.String() );
  1354. }
  1355. --m_nIndent;
  1356. Write( "};" );
  1357. // for each project, figure out what projects it depends on, and spit out a containeritemproxy for that dependency
  1358. // of particular note is that there are many item proxies for a given project, so we make their oids with the ordinal
  1359. // of the project they depend on - this must be consistent within the generated solution
  1360. CDependency_Project *pCurProject = projects[iProject];
  1361. CUtlVector<CDependency_Project*> additionalProjectDependencies;
  1362. ResolveAdditionalProjectDependencies( pCurProject, projects, additionalProjectDependencies );
  1363. for ( int iTestProject=0; iTestProject < projects.Count(); iTestProject++ )
  1364. {
  1365. if ( iProject == iTestProject )
  1366. continue;
  1367. CDependency_Project *pTestProject = projects[iTestProject];
  1368. int dependsOnFlags = k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse;
  1369. if ( pCurProject->DependsOn( pTestProject, dependsOnFlags ) || additionalProjectDependencies.Find( pTestProject ) != additionalProjectDependencies.InvalidIndex() )
  1370. {
  1371. Write( "\n" );
  1372. Write( "%024llX /* PBXContainerItemProxy */ = {\n", makeoid( projects[iProject], EOIDTypeContainerItemProxy, (uint16_t)iTestProject ) );
  1373. ++m_nIndent;
  1374. {
  1375. Write( "isa = PBXContainerItemProxy;\n" );
  1376. // it looks like if you cross ref between xcodeprojs, this is the oid for the other xcode proj
  1377. Write( "containerPortal = %024llX; /* Project object */\n", makeoid( this, EOIDTypeProject ) );
  1378. Write( "proxyType = 1;\n" );
  1379. Write( "remoteGlobalIDString = %024llX;\n", makeoid( projects[iTestProject], EOIDTypeNativeTarget ) );
  1380. Write( "remoteInfo = \"%s\";\n", projects[iTestProject]->m_ProjectName.String() );
  1381. }
  1382. --m_nIndent;
  1383. Write( "};" );
  1384. }
  1385. }
  1386. }
  1387. }
  1388. Write( "\n/* End PBXContainerItemProxy section */\n" );
  1389. /**
  1390. **
  1391. ** target dependencies - referenced by each project, in turn references the proxy container objects to express dependencies between targets
  1392. **
  1393. **/
  1394. Write( "\n/* Begin PBXTargetDependency section */" );
  1395. FOR_EACH_VEC( projects, iProject )
  1396. {
  1397. Write( "\n" );
  1398. Write( "%024llX /* PBXTargetDependency */ = {\n", makeoid( projects[iProject], EOIDTypeTargetDependency, -1 ) );
  1399. ++m_nIndent;
  1400. {
  1401. Write( "isa = PBXTargetDependency;\n" );
  1402. Write( "target = %024llX /* %s */;\n", makeoid( projects[iProject], EOIDTypeNativeTarget ), projects[iProject]->m_ProjectName.String() );
  1403. Write( "targetProxy = %024llX /* PBXContainerItemProxy */;\n", makeoid( projects[iProject], EOIDTypeContainerItemProxy, -1 ) );
  1404. }
  1405. --m_nIndent;
  1406. Write( "};" );
  1407. CDependency_Project *pCurProject = projects[iProject];
  1408. CUtlVector<CDependency_Project*> additionalProjectDependencies;
  1409. ResolveAdditionalProjectDependencies( pCurProject, projects, additionalProjectDependencies );
  1410. for ( int iTestProject=0; iTestProject < projects.Count(); iTestProject++ )
  1411. {
  1412. if ( iProject == iTestProject )
  1413. continue;
  1414. CDependency_Project *pTestProject = projects[iTestProject];
  1415. int dependsOnFlags = k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse;
  1416. if ( pCurProject->DependsOn( pTestProject, dependsOnFlags ) || additionalProjectDependencies.Find( pTestProject ) != additionalProjectDependencies.InvalidIndex() )
  1417. {
  1418. // project_t *pTestProjectT = &g_projects[ pTestProject->m_iProjectIndex ];
  1419. Write( "\n" );
  1420. Write( "%024llX /* PBXTargetDependency */ = {\n", makeoid( projects[iProject], EOIDTypeTargetDependency, (uint16_t)iTestProject ) );
  1421. ++m_nIndent;
  1422. {
  1423. Write( "isa = PBXTargetDependency;\n" );
  1424. Write( "target = %024llX /* %s */;\n", makeoid( projects[iProject], EOIDTypeNativeTarget ), projects[iProject]->m_ProjectName.String() );
  1425. Write( "targetProxy = %024llX /* PBXContainerItemProxy */;\n", makeoid( projects[iProject], EOIDTypeContainerItemProxy, (uint16_t)iTestProject ) );
  1426. }
  1427. --m_nIndent;
  1428. Write( "};" );
  1429. }
  1430. }
  1431. }
  1432. --m_nIndent;
  1433. Write( "\n/* End PBXTargetDependency section */\n" );
  1434. /**
  1435. **
  1436. ** build configurations - each target (and the project) has a set of build configurations (one release, one debug), each with their own set of build settings
  1437. ** the "baseConfigurationReference" points back to the appropriate .xcconfig file that gets referenced by the project and has all the non-target specific settings
  1438. **
  1439. **/
  1440. Write( "\n/* Begin XCBuildConfiguration section */" );
  1441. ++m_nIndent;
  1442. {
  1443. // project and aggregate "all" target
  1444. for( int iConfig = 0; iConfig < Q_ARRAYSIZE(k_rgchConfigNames); iConfig++ )
  1445. {
  1446. bool bIsDebug = V_stristr( k_rgchConfigNames[iConfig], "debug" ) != NULL;
  1447. Write( "\n" );
  1448. Write( "%024llX /* %s */ = {\n", makeoid( (uint8_t*)this + (uint64_t)&k_rgOidBuildConfigs[iConfig], EOIDTypeBuildConfiguration ), k_rgchConfigNames[iConfig] );
  1449. ++m_nIndent;
  1450. {
  1451. Write( "isa = XCBuildConfiguration;\n" );
  1452. Write( "baseConfigurationReference = %024llX /* %s */;\n", makeoid( k_rgchXCConfigFiles[iConfig], EOIDTypeFileReference ), k_rgchXCConfigFiles[iConfig] );
  1453. Write( "buildSettings = {\n" );
  1454. ++m_nIndent;
  1455. {
  1456. EmitBuildSettings( "All", NULL, NULL, NULL, bIsDebug );
  1457. }
  1458. --m_nIndent;
  1459. Write( "};\n" );
  1460. Write( "name = \"%s\";\n", k_rgchConfigNames[iConfig] );
  1461. }
  1462. --m_nIndent;
  1463. Write( "};" );
  1464. Write( "\n" );
  1465. Write( "%024llX /* %s */ = {\n", makeoid( (uint8_t*)this + (uint64_t)&k_rgOidBuildConfigs[iConfig], EOIDTypeBuildConfiguration, 1 ), k_rgchConfigNames[iConfig] );
  1466. ++m_nIndent;
  1467. {
  1468. Write( "isa = XCBuildConfiguration;\n" );
  1469. Write( "baseConfigurationReference = %024llX /* %s */;\n", makeoid( k_rgchXCConfigFiles[iConfig], EOIDTypeFileReference ), k_rgchXCConfigFiles[iConfig] );
  1470. Write( "buildSettings = {\n" );
  1471. ++m_nIndent;
  1472. {
  1473. EmitBuildSettings( "All", NULL, NULL, NULL, bIsDebug );
  1474. }
  1475. --m_nIndent;
  1476. Write( "};\n" );
  1477. Write( "name = \"%s\";\n", k_rgchConfigNames[iConfig] );
  1478. }
  1479. --m_nIndent;
  1480. Write( "};" );
  1481. }
  1482. FOR_EACH_VEC( projects, iProject )
  1483. {
  1484. CFileConfig& pcurrentConfigData = g_vecPGenerators[iProject]->m_BaseConfigData;
  1485. for ( int iConfig = 0; iConfig < Q_ARRAYSIZE(k_rgchConfigNames); iConfig++ )
  1486. {
  1487. if ( pcurrentConfigData.m_Configurations.IsValidIndex( iConfig ) )
  1488. {
  1489. bool bIsDebug = V_stristr( k_rgchConfigNames[iConfig], "debug" ) != NULL;
  1490. Write( "\n" );
  1491. Write( "%024llX /* %s */ = {\n", makeoid( ( uint8_t* ) projects[iProject] + ( uint64_t ) & k_rgchConfigNames[iConfig], EOIDTypeBuildConfiguration ),
  1492. k_rgchConfigNames[iConfig] );
  1493. ++m_nIndent;
  1494. {
  1495. Write( "isa = XCBuildConfiguration;\n" );
  1496. Write( "baseConfigurationReference = %024llX /* %s */;\n", makeoid( k_rgchXCConfigFiles[iConfig], EOIDTypeFileReference ), k_rgchXCConfigFiles[iConfig] );
  1497. Write( "buildSettings = {\n" );
  1498. ++m_nIndent;
  1499. {
  1500. KeyValues *pKV = pcurrentConfigData.m_Configurations[iConfig]->m_pKV;
  1501. char rgchProjectDir[MAX_PATH];
  1502. V_strncpy( rgchProjectDir, projects[iProject]->m_ProjectFilename.String(), sizeof( rgchProjectDir ) );
  1503. V_StripFilename( rgchProjectDir );
  1504. EmitBuildSettings( projects[iProject]->m_ProjectName, rgchProjectDir, &( g_vecPGenerators[iProject]->m_Files ), pKV, bIsDebug );
  1505. }
  1506. --m_nIndent;
  1507. Write( "};\n" );
  1508. Write( "name = \"%s\";\n", k_rgchConfigNames[iConfig] );
  1509. }
  1510. --m_nIndent;
  1511. Write( "};" );
  1512. }
  1513. }
  1514. }
  1515. }
  1516. --m_nIndent;
  1517. Write( "\n/* End XCBuildConfiguration section */\n" );
  1518. /**
  1519. **
  1520. ** configuration lists - aggregates the build configurations above into sets, which are referenced by the individual targets.
  1521. **
  1522. **/
  1523. Write( "\n/* Begin XCConfigurationList section */\n" );
  1524. ++m_nIndent;
  1525. {
  1526. Write( "%024llX /* Build configuration list for PBXProject \"%s\" */ = {\n", makeoid( this, EOIDTypeConfigurationList ), V_UnqualifiedFileName( UsePOSIXSlashes( pSolutionFilename ) ) );
  1527. ++m_nIndent;
  1528. {
  1529. Write( "isa = XCConfigurationList;\n" );
  1530. Write( "buildConfigurations = (\n" );
  1531. ++m_nIndent;
  1532. for( int iConfig = 0; iConfig < Q_ARRAYSIZE(k_rgchConfigNames); iConfig++ )
  1533. {
  1534. Write( "%024llX /* %s */,\n", makeoid( (uint8_t*)this + (uint64_t)&k_rgOidBuildConfigs[iConfig], EOIDTypeBuildConfiguration ), k_rgchConfigNames[iConfig] );
  1535. }
  1536. --m_nIndent;
  1537. Write( ");\n" );
  1538. Write( "defaultConfigurationIsVisible = 0;\n" );
  1539. Write( "defaultConfigurationName = \"%s\";\n", k_rgchConfigNames[0] );
  1540. }
  1541. --m_nIndent;
  1542. Write( "};\n" );
  1543. Write( "%024llX /* Build configuration list for PBXAggregateTarget \"All\" */ = {\n", makeoid( this, EOIDTypeConfigurationList, 1 ) );
  1544. ++m_nIndent;
  1545. {
  1546. Write( "isa = XCConfigurationList;\n" );
  1547. Write( "buildConfigurations = (\n" );
  1548. ++m_nIndent;
  1549. for( int iConfig = 0; iConfig < Q_ARRAYSIZE(k_rgchConfigNames); iConfig++ )
  1550. {
  1551. Write( "%024llX /* %s */,\n", makeoid( (uint8_t*)this + (uint64_t)&k_rgOidBuildConfigs[iConfig], EOIDTypeBuildConfiguration, 1 ), k_rgchConfigNames[iConfig] );
  1552. }
  1553. --m_nIndent;
  1554. Write( ");\n" );
  1555. Write( "defaultConfigurationIsVisible = 0;\n" );
  1556. Write( "defaultConfigurationName = \"%s\";\n", k_rgchConfigNames[0] );
  1557. }
  1558. --m_nIndent;
  1559. Write( "};" );
  1560. FOR_EACH_VEC( projects, iProject )
  1561. {
  1562. Write( "\n" );
  1563. Write( "%024llX /* Build configuration list for PBXNativeTarget \"%s\" */ = {\n", makeoid( projects[iProject], EOIDTypeConfigurationList ), projects[iProject]->m_ProjectName.String() );
  1564. ++m_nIndent;
  1565. {
  1566. Write( "isa = XCConfigurationList;\n" );
  1567. Write( "buildConfigurations = (\n" );
  1568. ++m_nIndent;
  1569. for( int iConfig = 0; iConfig < Q_ARRAYSIZE(k_rgchConfigNames); iConfig++ )
  1570. {
  1571. if (g_vecPGenerators[iProject]->m_BaseConfigData.m_Configurations.IsValidIndex(iConfig))
  1572. {
  1573. Write( "%024llX /* %s */,\n", makeoid( (uint8_t*)projects[iProject] + (uint64_t)&k_rgchConfigNames[iConfig], EOIDTypeBuildConfiguration ), k_rgchConfigNames[iConfig] );
  1574. }
  1575. }
  1576. --m_nIndent;
  1577. Write( ");\n" );
  1578. Write( "defaultConfigurationIsVisible = 0;\n" );
  1579. Write( "defaultConfigurationName = \"%s\";\n", k_rgchConfigNames[0] );
  1580. }
  1581. --m_nIndent;
  1582. Write( "};" );
  1583. }
  1584. }
  1585. --m_nIndent;
  1586. Write( "\n/* End XCConfigurationList section */\n" );
  1587. }
  1588. Write( "};\n" ); // objects = { ...
  1589. /**
  1590. **
  1591. ** root object in the graph
  1592. **
  1593. **/
  1594. Write( "rootObject = %024llX /* Project object */;\n", makeoid( this, EOIDTypeProject ) );
  1595. }
  1596. --m_nIndent;
  1597. Write( "}\n" );
  1598. fclose( m_fp );
  1599. }
  1600. void CSolutionGenerator_XCode::GenerateSolutionFileOld( const char *pSolutionFilename, CUtlVector<CDependency_Project*> &projects )
  1601. {
  1602. char sPbxProjFile[MAX_PATH];
  1603. sprintf( sPbxProjFile, "%s.xcodeproj", pSolutionFilename );
  1604. mkdir( sPbxProjFile, 0777 );
  1605. sprintf( sPbxProjFile, "%s.xcodeproj/project.pbxproj", pSolutionFilename );
  1606. m_fp = fopen( sPbxProjFile, "wt" );
  1607. m_nIndent = 0;
  1608. Msg( "\nWriting master XCode project %s.xcodeproj.\n\n", pSolutionFilename );
  1609. /** preamble **/
  1610. Write( "// !$*UTF8*$!\n{\n" );
  1611. ++m_nIndent;
  1612. Write( "archiveVersion = 1;\n" );
  1613. Write( "classes = {\n" );
  1614. Write( "};\n" );
  1615. Write( "objectVersion = 42;\n" );
  1616. Write( "objects = {\n" );
  1617. /** file references **/
  1618. Write( "\n/* Begin PBXFileReference section */\n" );
  1619. ++m_nIndent;
  1620. FOR_EACH_VEC( projects, iProject )
  1621. {
  1622. char sDir[MAX_PATH];
  1623. V_strncpy( sDir, projects[iProject]->m_ProjectFilename.String(), sizeof( sDir ) );
  1624. V_StripFilename( sDir );
  1625. char sFilename[MAX_PATH];
  1626. V_StripExtension( V_UnqualifiedFileName( projects[iProject]->m_ProjectFilename.String() ), sFilename, sizeof(sFilename) );
  1627. Write( "%024X /* %s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = \"wrapper.pb-project\"; name = \"%s\"; path = %s/%s.xcodeproj; sourceTree = \"<group>\"; };\n",
  1628. iProject,
  1629. sFilename,
  1630. sFilename,
  1631. sDir, sFilename
  1632. );
  1633. }
  1634. --m_nIndent;
  1635. Write( "/* End PBXFileReference section */\n" );
  1636. /** groups **/
  1637. Write( "\n/* Begin PBXGroup section */\n" );
  1638. ++m_nIndent;
  1639. Write( "%024X /* %s */ = {\n", k_pchProjects, k_pchProjects );
  1640. ++m_nIndent;
  1641. Write( "isa = PBXGroup;\n" );
  1642. Write( "children = (\n" );
  1643. ++m_nIndent;
  1644. FOR_EACH_VEC( projects, iProject )
  1645. {
  1646. char sFilename[MAX_PATH];
  1647. V_StripExtension( V_UnqualifiedFileName( projects[iProject]->m_ProjectFilename.String() ), sFilename, sizeof(sFilename) );
  1648. Write( "%024X /* %s */,\n", iProject, sFilename );
  1649. }
  1650. --m_nIndent;
  1651. Write( ");\n" );
  1652. Write( "name = %s;\n", k_pchProjects );
  1653. Write( "sourceTree = \"<group>\";\n" );
  1654. --m_nIndent;
  1655. Write( "};\n" );
  1656. Write( "%024X = {\n", &projects );
  1657. ++m_nIndent;
  1658. Write( "isa = PBXGroup;\n" );
  1659. Write( "children = (\n" );
  1660. ++m_nIndent;
  1661. Write( "%024X /* %s */,\n", k_pchProjects, k_pchProjects );
  1662. --m_nIndent;
  1663. Write( ");\n" );
  1664. Write( "sourceTree = \"<group>\";\n" );
  1665. --m_nIndent;
  1666. Write( "};" );
  1667. Write( "\n/* End PBXGroup section */\n" );
  1668. /** write legacy project section **/
  1669. Write( "\n/* Begin PBXLegacyTarget section */\n" );
  1670. ++m_nIndent;
  1671. Write( "%024X /* build with make */ = {\n", k_pchLegacyTarget );
  1672. ++m_nIndent;
  1673. Write( "isa = PBXLegacyTarget;\n");
  1674. Write( "buildArgumentsString = \"-f %s.mak $(ACTION) MAKE_VERBOSE=1\";\n", V_UnqualifiedFileName( pSolutionFilename ) );
  1675. Write( "buildConfigurationList = %024X /* Build configuration list for PBXLegacyTarget \"build with make\" */;\n", k_oidBuildConfigList );
  1676. Write( "buildPhases = (\n" );
  1677. Write( ");\n" );
  1678. Write( "buildToolPath = /usr/bin/make;\n" );
  1679. char rgchSolutionDir[MAX_PATH];
  1680. V_ExtractFilePath( pSolutionFilename, rgchSolutionDir, sizeof( rgchSolutionDir ) );
  1681. Write( "buildWorkingDirectory = %s;\n", rgchSolutionDir );
  1682. Write( "dependencies = (\n" );
  1683. Write( ");\n");
  1684. Write( "name = \"build with make\";\n" );
  1685. Write( "passBuildSettingsInEnvironment = 1;\n" );
  1686. Write( "productName = \"build with make\";\n" );
  1687. --m_nIndent;
  1688. Write( "};" );
  1689. --m_nIndent;
  1690. Write( "\n/* End PBXLegacyTarget section */\n" );
  1691. /** project section **/
  1692. Write( "\n/* Begin PBXProject section */\n" );
  1693. Write( "%024X /* Project object */ = {\n", this );
  1694. ++m_nIndent;
  1695. Write( "isa = PBXProject;\n" );
  1696. Write( "buildConfigurationList = %024X /* Build configuration list for PBXProject \"%s\" */;\n", k_oidBuildConfigList+1, V_UnqualifiedFileName( pSolutionFilename ) );
  1697. Write( "compatibilityVersion = \"Xcode 2.4\";\n" );
  1698. Write( "hasScannedForEncodings = 0;\n" );
  1699. Write( "mainGroup = %024X;\n", &projects );
  1700. Write( "projectDirPath = \"\";\n" );
  1701. Write( "projectRoot = \"\";\n" );
  1702. Write( "targets = (\n" );
  1703. ++m_nIndent;
  1704. Write( "%024X /* build with make */, \n", k_pchLegacyTarget );
  1705. --m_nIndent;
  1706. Write( ");\n" );
  1707. --m_nIndent;
  1708. Write( "};" );
  1709. Write( "\n/* End PBXProject section */\n" );
  1710. /** build configurations **/
  1711. ++m_nIndent;
  1712. Write( "\n/* Begin XCBuildConfiguration section */" );
  1713. for( int iConfig = 0; iConfig < Q_ARRAYSIZE(k_rgchConfigNames); iConfig++ )
  1714. {
  1715. Write( "\n" );
  1716. Write( "%024X /* %s */ = {\n", k_rgOidBuildConfigs[iConfig], k_rgchConfigNames[iConfig] );
  1717. ++m_nIndent;
  1718. Write( "isa = XCBuildConfiguration;\n" );
  1719. Write( "buildSettings = {\n" );
  1720. ++m_nIndent;
  1721. Write( "COPY_PHASE_STRIP = %s;\n", ( V_strstr( k_rgchConfigNames[iConfig], "release" ) ? "YES" : "NO" ) );
  1722. --m_nIndent;
  1723. Write( "};\n" );
  1724. Write( "name = %s;\n", k_rgchConfigNames[iConfig] );
  1725. --m_nIndent;
  1726. Write( "};" );
  1727. }
  1728. for( int iConfig = 0; iConfig < Q_ARRAYSIZE(k_rgchConfigNames); iConfig++ )
  1729. {
  1730. Write( "\n" );
  1731. Write( "%024X /* %s */ = {\n", k_rgOidBuildConfigs[iConfig]+Q_ARRAYSIZE(k_rgOidBuildConfigs)+1, k_rgchConfigNames[iConfig] );
  1732. ++m_nIndent;
  1733. Write( "isa = XCBuildConfiguration;\n" );
  1734. Write( "buildSettings = {\n" );
  1735. ++m_nIndent;
  1736. Write( "CFG = %s;\n", k_rgchConfigNames[iConfig] );
  1737. Write( "PRODUCT_NAME = \"build with make\";\n" );
  1738. --m_nIndent;
  1739. Write( "};\n" );
  1740. Write( "name = %s;\n", k_rgchConfigNames[iConfig] );
  1741. --m_nIndent;
  1742. Write( "};" );
  1743. }
  1744. Write( "\n/* End XCBuildConfiguration section */\n" );
  1745. Write( "%024X /* Build configuration list for PBXLegacyTarget \"build with make\" */ = {\n", k_oidBuildConfigList );
  1746. ++m_nIndent;
  1747. Write( "isa = XCConfigurationList;\n" );
  1748. Write( "buildConfigurations = (\n" );
  1749. ++m_nIndent;
  1750. for( int iConfig = 0; iConfig < Q_ARRAYSIZE(k_rgchConfigNames); iConfig++ )
  1751. {
  1752. Write( "%024X /* %s */,\n", k_rgOidBuildConfigs[iConfig]+Q_ARRAYSIZE(k_rgOidBuildConfigs)+1, k_rgchConfigNames[iConfig] );
  1753. }
  1754. --m_nIndent;
  1755. Write( ");\n" );
  1756. Write( "defaultConfigurationIsVisible = 0;\n" );
  1757. Write( "defaultConfigurationName = %s;\n", k_rgchConfigNames[0] );
  1758. --m_nIndent;
  1759. Write( "};" );
  1760. Write( "\n/* Begin XCBuildConfigurationList section */\n" );
  1761. Write( "%024X /* Build configuration list for PBXProject \"%s\" */ = {\n", k_oidBuildConfigList+1, V_UnqualifiedFileName( pSolutionFilename ) );
  1762. ++m_nIndent;
  1763. Write( "isa = XCConfigurationList;\n" );
  1764. Write( "buildConfigurations = (\n" );
  1765. ++m_nIndent;
  1766. for( int iConfig = 0; iConfig < Q_ARRAYSIZE(k_rgchConfigNames); iConfig++ )
  1767. {
  1768. Write( "%024X /* %s */,\n", k_rgOidBuildConfigs[iConfig], k_rgchConfigNames[iConfig] );
  1769. }
  1770. --m_nIndent;
  1771. Write( ");\n" );
  1772. Write( "defaultConfigurationIsVisible = 0;\n" );
  1773. Write( "defaultConfigurationName = %s;\n", k_rgchConfigNames[0] );
  1774. --m_nIndent;
  1775. Write( "};\n" );
  1776. Write( "\n/* End XCBuildConfigurationList section */\n" );
  1777. --m_nIndent;
  1778. /** postamble **/
  1779. --m_nIndent;
  1780. Write( "};\n" );
  1781. Write( "rootObject = %024X /* Project object */;\n", this );
  1782. --m_nIndent;
  1783. Write( "}\n" );
  1784. fclose( m_fp );
  1785. }
  1786. void CSolutionGenerator_XCode::Write( const char *pMsg, ... )
  1787. {
  1788. char sOut[8192];
  1789. va_list marker;
  1790. va_start( marker, pMsg );
  1791. V_vsnprintf( sOut, sizeof( sOut ), pMsg, marker );
  1792. va_end( marker );
  1793. for ( int i=0; i < m_nIndent; i++ )
  1794. fprintf( m_fp, "\t" );
  1795. fprintf( m_fp, "%s", sOut );
  1796. }
  1797. static CSolutionGenerator_XCode g_SolutionGenerator_XCode;
  1798. IBaseSolutionGenerator* GetSolutionGenerator_XCode()
  1799. {
  1800. return &g_SolutionGenerator_XCode;
  1801. }