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.

617 lines
18 KiB

  1. //====== Copyright � 1996-2004, Valve Corporation, All rights reserved. =====//
  2. //
  3. // Interface for makefiles to build differently depending on where they are run from
  4. //
  5. //===========================================================================//
  6. #include "movieobjects/dmemakefileutils.h"
  7. #include "movieobjects/dmemdlmakefile.h"
  8. #include "movieobjects/dmedccmakefile.h"
  9. #include "tier2/fileutils.h"
  10. #include "filesystem.h"
  11. //-----------------------------------------------------------------------------
  12. // Statics
  13. //-----------------------------------------------------------------------------
  14. IMPLEMENT_DMEMAKEFILE_UTIL_CLASS( CDmeMakefileUtils );
  15. //-----------------------------------------------------------------------------
  16. // Default implementation
  17. //-----------------------------------------------------------------------------
  18. static CDmeMakefileUtils s_MakefileUtils;
  19. IDmeMakefileUtils *GetDefaultDmeMakefileUtils()
  20. {
  21. return &s_MakefileUtils;
  22. }
  23. //-----------------------------------------------------------------------------
  24. // Constructor, destructor
  25. //-----------------------------------------------------------------------------
  26. CDmeMakefileUtils::CDmeMakefileUtils()
  27. {
  28. m_CompilationStep = NOT_COMPILING;
  29. m_hCompileProcess = NULL;
  30. m_nCurrentCompileTask = -1;
  31. m_nExitCode = 0;
  32. }
  33. CDmeMakefileUtils::~CDmeMakefileUtils()
  34. {
  35. }
  36. //-----------------------------------------------------------------------------
  37. // Here's where systems can access other interfaces implemented by this object
  38. //-----------------------------------------------------------------------------
  39. void *CDmeMakefileUtils::QueryInterface( const char *pInterfaceName )
  40. {
  41. if ( !V_strcmp( pInterfaceName, DMEMAKEFILE_UTILS_INTERFACE_VERSION ) )
  42. return (IDmeMakefileUtils*)this;
  43. return NULL;
  44. }
  45. //-----------------------------------------------------------------------------
  46. // Initialization.. set up messagemaps
  47. //-----------------------------------------------------------------------------
  48. InitReturnVal_t CDmeMakefileUtils::Init()
  49. {
  50. InitializeFuncMaps();
  51. return INIT_OK;
  52. }
  53. //-----------------------------------------------------------------------------
  54. // Looks for an appropriate method to compile this element with
  55. //-----------------------------------------------------------------------------
  56. CCompileFuncAdapterBase *CDmeMakefileUtils::DetermineCompileAdapter( CDmElement *pElement )
  57. {
  58. int nBestInheritanceDepth = -1;
  59. CCompileFuncAdapterBase *pBestAdapter = NULL;
  60. CompileFuncTree_t *pTree = GetCompileTree();
  61. while ( pTree )
  62. {
  63. CCompileFuncAdapterBase *pCurr = pTree->m_pFirstAdapter;
  64. for ( ; pCurr; pCurr = pCurr->m_pNext )
  65. {
  66. // Choose this factory if it's more derived than the previous best
  67. int nInheritanceDepth = pElement->GetInheritanceDepth( pCurr->m_ElementType );
  68. if ( nInheritanceDepth < 0 )
  69. continue;
  70. if ( nInheritanceDepth == 0 )
  71. {
  72. // Found exact match.. do it!
  73. return pCurr;
  74. }
  75. // Don't look for the best thingy if we're not the root
  76. if ( nBestInheritanceDepth >= 0 && ( nInheritanceDepth >= nBestInheritanceDepth ) )
  77. continue;
  78. nBestInheritanceDepth = nInheritanceDepth;
  79. pBestAdapter = pCurr;
  80. }
  81. pTree = pTree->m_pBaseAdapterTree;
  82. }
  83. // Return the closest match we could find
  84. return pBestAdapter;
  85. }
  86. //-----------------------------------------------------------------------------
  87. // Looks for an appropriate method to open this element with
  88. //-----------------------------------------------------------------------------
  89. COpenEditorFuncAdapterBase *CDmeMakefileUtils::DetermineOpenEditorAdapter( CDmElement *pElement )
  90. {
  91. int nBestInheritanceDepth = -1;
  92. COpenEditorFuncAdapterBase *pBestAdapter = NULL;
  93. OpenEditorFuncTree_t *pTree = GetOpenEditorTree();
  94. while ( pTree )
  95. {
  96. COpenEditorFuncAdapterBase *pCurr = pTree->m_pFirstAdapter;
  97. for ( ; pCurr; pCurr = pCurr->m_pNext )
  98. {
  99. // Choose this factory if it's more derived than the previous best
  100. int nInheritanceDepth = pElement->GetInheritanceDepth( pCurr->m_ElementType );
  101. if ( nInheritanceDepth < 0 )
  102. continue;
  103. // Found exact match.. do it!
  104. if ( nInheritanceDepth == 0 )
  105. return pCurr;
  106. if ( nBestInheritanceDepth >= 0 && ( nInheritanceDepth >= nBestInheritanceDepth ) )
  107. continue;
  108. nBestInheritanceDepth = nInheritanceDepth;
  109. pBestAdapter = pCurr;
  110. }
  111. pTree = pTree->m_pBaseAdapterTree;
  112. }
  113. return pBestAdapter;
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Opens a element in an external editor
  117. //-----------------------------------------------------------------------------
  118. void CDmeMakefileUtils::PerformOpenEditor( CDmElement *pElement )
  119. {
  120. COpenEditorFuncAdapterBase *pAdapter = DetermineOpenEditorAdapter( pElement );
  121. if ( pAdapter )
  122. {
  123. pAdapter->OpenEditor( pElement );
  124. }
  125. }
  126. //-----------------------------------------------------------------------------
  127. // Queues up a compilation task
  128. //-----------------------------------------------------------------------------
  129. void CDmeMakefileUtils::AddCompilationTask( CDmElement* pElement, CCompileFuncAdapterBase *pAdapter )
  130. {
  131. Assert( m_CompilationStep == BUILDING_STANDARD_DEPENDENCIES || m_CompilationStep == BUILDING_ALL_DEPENDENCIES );
  132. // Queue up the compilation task
  133. int j = m_CompileTasks.AddToTail();
  134. m_CompileTasks[j].m_hElement = pElement;
  135. m_CompileTasks[j].m_pAdapter = pAdapter;
  136. }
  137. void CDmeMakefileUtils::AddCompilationTask( CDmElement* pElement )
  138. {
  139. CCompileFuncAdapterBase *pAdapter = DetermineCompileAdapter( pElement );
  140. if ( pAdapter )
  141. {
  142. // Queue up the compilation task
  143. AddCompilationTask( pElement, pAdapter );
  144. }
  145. }
  146. //-----------------------------------------------------------------------------
  147. // Sets the compile process
  148. //-----------------------------------------------------------------------------
  149. void CDmeMakefileUtils::SetCompileProcess( IProcess *hProcess )
  150. {
  151. Assert( m_CompilationStep == PERFORMING_COMPILATION );
  152. m_hCompileProcess = hProcess;
  153. if ( m_hCompileProcess == NULL )
  154. {
  155. m_CompilationStep = AFTER_COMPILATION_FAILED;
  156. }
  157. }
  158. //-----------------------------------------------------------------------------
  159. // Default implementatations for compile dependencies
  160. //-----------------------------------------------------------------------------
  161. bool CDmeMakefileUtils::AddCompileDependencies( CDmeMakefile *pMakefile, bool bBuildAllDependencies )
  162. {
  163. if ( !pMakefile )
  164. return true;
  165. CUtlVector< CUtlString > outputs;
  166. int nCount = pMakefile->GetSourceCount();
  167. for ( int i = 0; i < nCount; ++i )
  168. {
  169. CDmeSource *pSource = pMakefile->GetSource( i );
  170. if ( !pSource )
  171. continue;
  172. CDmeMakefile *pDependentMakefile = pSource->GetDependentMakefile();
  173. if ( !pDependentMakefile )
  174. continue;
  175. bool bShouldBuildFile = bBuildAllDependencies;
  176. // Does the output files exist?
  177. int j = 0;
  178. if ( !bBuildAllDependencies )
  179. {
  180. pDependentMakefile->GetOutputs( outputs );
  181. int nOutputCount = outputs.Count();
  182. for ( j = 0; j < nOutputCount; ++j )
  183. {
  184. // If the file doesn't exist, we have to build it
  185. if ( !g_pFullFileSystem->FileExists( outputs[j] ) )
  186. break;
  187. bShouldBuildFile = true;
  188. break;
  189. }
  190. }
  191. if ( !bShouldBuildFile )
  192. continue;
  193. CCompileFuncAdapterBase *pAdapter = DetermineCompileAdapter( pDependentMakefile );
  194. if ( pAdapter )
  195. {
  196. // Add dependent makefiles first
  197. if ( !pAdapter->PerformCompilationStep( pDependentMakefile, bBuildAllDependencies ? BUILDING_ALL_DEPENDENCIES : BUILDING_STANDARD_DEPENDENCIES ) )
  198. return false;
  199. }
  200. // Queue up the compilation task
  201. AddCompilationTask( pDependentMakefile, pAdapter );
  202. }
  203. return true;
  204. }
  205. //-----------------------------------------------------------------------------
  206. // Default implementatations for precompilation step
  207. //-----------------------------------------------------------------------------
  208. bool CDmeMakefileUtils::PerformCompilationStep( CDmElement *pElement, CompilationStep_t step )
  209. {
  210. // Do nothing
  211. return true;
  212. }
  213. bool CDmeMakefileUtils::PerformCompilationStep( CDmeMakefile *pMakefile, CompilationStep_t step )
  214. {
  215. switch( step )
  216. {
  217. case BUILDING_ALL_DEPENDENCIES:
  218. return AddCompileDependencies( pMakefile, true );
  219. case BUILDING_STANDARD_DEPENDENCIES:
  220. return AddCompileDependencies( pMakefile, false );
  221. case BEFORE_COMPILATION:
  222. pMakefile->PreCompile();
  223. break;
  224. case AFTER_COMPILATION_SUCCEEDED:
  225. pMakefile->PostCompile();
  226. break;
  227. }
  228. return true;
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Starts the next compile task
  232. //-----------------------------------------------------------------------------
  233. void CDmeMakefileUtils::StartNextCompileTask( )
  234. {
  235. Assert( m_hCompileProcess == NULL );
  236. ++m_nCurrentCompileTask;
  237. if ( m_nCurrentCompileTask == m_CompileTasks.Count() )
  238. {
  239. PerformCompilationStep( AFTER_COMPILATION_SUCCEEDED );
  240. m_nCurrentCompileTask = -1;
  241. m_CompileTasks.RemoveAll();
  242. return;
  243. }
  244. m_hCompileProcess = NULL;
  245. // NOTE: PerformCompilationStep is expected to call SetCompileProcess to set m_hCompileProcess
  246. CompileInfo_t &info = m_CompileTasks[m_nCurrentCompileTask];
  247. bool bOk = info.m_pAdapter->PerformCompilationStep( info.m_hElement, PERFORMING_COMPILATION );
  248. if ( !bOk || ( m_hCompileProcess == NULL ) )
  249. {
  250. AbortCurrentCompilation();
  251. return;
  252. }
  253. }
  254. //-----------------------------------------------------------------------------
  255. // Performs the compilation step on all elements
  256. //-----------------------------------------------------------------------------
  257. bool CDmeMakefileUtils::PerformCompilationStep( CompilationStep_t step )
  258. {
  259. // Iterate through all elements and run a compilation step
  260. m_CompilationStep = step;
  261. int nCount = m_CompileTasks.Count();
  262. for ( int i = 0; i < nCount; ++i )
  263. {
  264. CompileInfo_t &info = m_CompileTasks[i];
  265. if ( info.m_hElement.Get() )
  266. {
  267. if ( !info.m_pAdapter->PerformCompilationStep( info.m_hElement, step ) )
  268. return false;
  269. }
  270. }
  271. return true;
  272. }
  273. //-----------------------------------------------------------------------------
  274. // Main entry point for compilation
  275. //-----------------------------------------------------------------------------
  276. void CDmeMakefileUtils::PerformCompile( CDmElement *pElement, bool bBuildAllDependencies )
  277. {
  278. if ( IsCurrentlyCompiling() )
  279. {
  280. AbortCurrentCompilation();
  281. }
  282. CCompileFuncAdapterBase *pAdapter = DetermineCompileAdapter( pElement );
  283. if ( !pAdapter )
  284. {
  285. m_CompilationStep = AFTER_COMPILATION_FAILED;
  286. return;
  287. }
  288. // Add dependent makefiles first
  289. m_CompilationStep = bBuildAllDependencies ? BUILDING_ALL_DEPENDENCIES : BUILDING_STANDARD_DEPENDENCIES;
  290. if ( !pAdapter->PerformCompilationStep( pElement, m_CompilationStep ) )
  291. {
  292. AbortCurrentCompilation();
  293. return;
  294. }
  295. // Queue up the compilation task
  296. AddCompilationTask( pElement, pAdapter );
  297. // Iterate through all elements and run a precompilation step
  298. // NOTE: This is where perforce integration should go
  299. if ( !PerformCompilationStep( BEFORE_COMPILATION ) )
  300. {
  301. AbortCurrentCompilation();
  302. return;
  303. }
  304. // Dequeue the first compile task and start it up
  305. m_CompilationStep = PERFORMING_COMPILATION;
  306. StartNextCompileTask();
  307. }
  308. //-----------------------------------------------------------------------------
  309. // Are we in the middle of compiling this makefile?
  310. //-----------------------------------------------------------------------------
  311. bool CDmeMakefileUtils::IsCurrentlyCompiling()
  312. {
  313. return ( m_CompilationStep != NOT_COMPILING );
  314. }
  315. //-----------------------------------------------------------------------------
  316. // Aborts any current compilation
  317. //-----------------------------------------------------------------------------
  318. void CDmeMakefileUtils::AbortCurrentCompilation()
  319. {
  320. if ( m_hCompileProcess != NULL )
  321. {
  322. m_hCompileProcess->Abort();
  323. m_hCompileProcess->Release();
  324. m_hCompileProcess = NULL;
  325. }
  326. if ( IsCurrentlyCompiling() )
  327. {
  328. PerformCompilationStep( AFTER_COMPILATION_FAILED );
  329. m_nCurrentCompileTask = -1;
  330. m_CompileTasks.RemoveAll();
  331. }
  332. }
  333. //-----------------------------------------------------------------------------
  334. // Returns the exit code of the failed compilation (if COMPILATION_FAILED occurred)
  335. //-----------------------------------------------------------------------------
  336. int CDmeMakefileUtils::GetExitCode()
  337. {
  338. return m_nExitCode;
  339. }
  340. //-----------------------------------------------------------------------------
  341. // Returns output from the compilation
  342. //-----------------------------------------------------------------------------
  343. int CDmeMakefileUtils::GetCompileOutputSize()
  344. {
  345. if ( m_hCompileProcess == NULL )
  346. return 0;
  347. return m_hCompileProcess->GetStdout()->GetNumBytesAvailable();
  348. }
  349. CompilationState_t CDmeMakefileUtils::UpdateCompilation( char *pOutputBuf, int nBufLen )
  350. {
  351. switch( m_CompilationStep )
  352. {
  353. case BUILDING_STANDARD_DEPENDENCIES:
  354. case BUILDING_ALL_DEPENDENCIES:
  355. case BEFORE_COMPILATION:
  356. return COMPILATION_NOT_COMPLETE;
  357. case AFTER_COMPILATION_FAILED:
  358. m_CompilationStep = NOT_COMPILING;
  359. return COMPILATION_FAILED;
  360. case AFTER_COMPILATION_SUCCEEDED:
  361. m_CompilationStep = NOT_COMPILING;
  362. return COMPILATION_SUCCESSFUL;
  363. }
  364. // This is the PERFORMING_COMPILATION case:
  365. // FIXME: Check return codes from compile process..
  366. // fail if compilation process had a problem
  367. if ( m_hCompileProcess == NULL )
  368. {
  369. if ( nBufLen > 0 )
  370. {
  371. pOutputBuf[0] = 0;
  372. }
  373. return COMPILATION_SUCCESSFUL;
  374. }
  375. if ( nBufLen > 0 )
  376. {
  377. CUtlString sOutput;
  378. m_hCompileProcess->GetStdout()->ReadAvailable( sOutput );
  379. V_strncpy( pOutputBuf, sOutput.String(), nBufLen );
  380. V_TranslateLineFeedsToUnix( pOutputBuf );
  381. }
  382. if ( !m_hCompileProcess->IsComplete() )
  383. return COMPILATION_NOT_COMPLETE;
  384. m_nExitCode = m_hCompileProcess->GetExitCode();
  385. bool bCompileSucceeded = ( m_nExitCode == 0 );
  386. m_hCompileProcess->Release();
  387. m_hCompileProcess = NULL;
  388. if ( !bCompileSucceeded )
  389. {
  390. AbortCurrentCompilation();
  391. return COMPILATION_NOT_COMPLETE;
  392. }
  393. StartNextCompileTask();
  394. if ( m_CompilationStep == PERFORMING_COMPILATION )
  395. return COMPILATION_NOT_COMPLETE;
  396. CompilationState_t retVal = ( m_CompilationStep == AFTER_COMPILATION_SUCCEEDED ) ? COMPILATION_SUCCESSFUL : COMPILATION_FAILED;
  397. m_CompilationStep = NOT_COMPILING;
  398. return retVal;
  399. }
  400. //-----------------------------------------------------------------------------
  401. // Type-specific compilation functions
  402. //-----------------------------------------------------------------------------
  403. bool CDmeMakefileUtils::PerformCompilationStep( CDmeMDLMakefile *pMakeFile, CompilationStep_t step )
  404. {
  405. if ( step != PERFORMING_COMPILATION )
  406. return PerformCompilationStep( static_cast<CDmeMakefile*>( pMakeFile ), step );
  407. char pBinDirectory[MAX_PATH];
  408. GetModSubdirectory( "..\\bin", pBinDirectory, sizeof(pBinDirectory) );
  409. Q_RemoveDotSlashes( pBinDirectory );
  410. char pStudioMDLCmd[MAX_PATH];
  411. #ifdef _DEBUG
  412. Q_snprintf( pStudioMDLCmd, sizeof(pStudioMDLCmd), "%s\\studiomdl.exe -allowdebug %s", pBinDirectory, pMakeFile->GetFileName() );
  413. #else
  414. Q_snprintf( pStudioMDLCmd, sizeof(pStudioMDLCmd), "%s\\studiomdl.exe %s", pBinDirectory, pMakeFile->GetFileName() );
  415. #endif
  416. IProcess *hProcess = g_pProcessUtils->StartProcess( pStudioMDLCmd, STARTPROCESS_CONNECTSTDPIPES );
  417. SetCompileProcess( hProcess );
  418. return true;
  419. }
  420. //-----------------------------------------------------------------------------
  421. // Exports a Maya file to a DMX file
  422. //-----------------------------------------------------------------------------
  423. bool CDmeMakefileUtils::PerformCompilationStep( CDmeMayaMakefile *pMakeFile, CompilationStep_t step )
  424. {
  425. if ( step != PERFORMING_COMPILATION )
  426. return PerformCompilationStep( static_cast<CDmeMakefile*>( pMakeFile ), step );
  427. // FIXME: Create batch export command here
  428. CUtlString mayaCommand;
  429. mayaCommand = "vsDmxIO -export";
  430. CUtlVector< CDmeHandle< CDmeSourceMayaFile > > sources;
  431. pMakeFile->GetSources( sources );
  432. if ( !sources.Count() )
  433. return false;
  434. CDmeSourceMayaFile *pDmeSourceDCCFile( sources[ 0 ].Get() );
  435. mayaCommand += " -selection";
  436. char pObjectId[128];
  437. UniqueIdToString( pMakeFile->GetId(), pObjectId, sizeof(pObjectId) );
  438. mayaCommand += " -makefileObjectId \\\"";
  439. mayaCommand += pObjectId;
  440. mayaCommand += "\\\"";
  441. mayaCommand += " -";
  442. mayaCommand += pDmeSourceDCCFile->m_ExportType.GetAttribute()->GetName();
  443. switch ( pDmeSourceDCCFile->m_ExportType.Get() )
  444. {
  445. case 1: // skeletal animation
  446. mayaCommand += " skeletalAnimation";
  447. mayaCommand += " -";
  448. mayaCommand += pDmeSourceDCCFile->m_FrameStart.GetAttribute()->GetName();
  449. mayaCommand += " ";
  450. mayaCommand += pDmeSourceDCCFile->m_FrameStart.Get();
  451. mayaCommand += " -";
  452. mayaCommand += pDmeSourceDCCFile->m_FrameEnd.GetAttribute()->GetName();
  453. mayaCommand += " ";
  454. mayaCommand += pDmeSourceDCCFile->m_FrameEnd.Get();
  455. mayaCommand += " -";
  456. mayaCommand += pDmeSourceDCCFile->m_FrameIncrement.GetAttribute()->GetName();
  457. mayaCommand += " ";
  458. mayaCommand += pDmeSourceDCCFile->m_FrameIncrement.Get();
  459. break;
  460. default: // Model
  461. mayaCommand += " model";
  462. break;
  463. }
  464. char pFileName[MAX_PATH];
  465. Q_strncpy( pFileName, pMakeFile->GetFileName(), sizeof( pFileName ) );
  466. Q_FixSlashes( pFileName, '/' );
  467. mayaCommand += " -filename \\\"";
  468. mayaCommand += pFileName;
  469. mayaCommand += "\\\"";
  470. const int rootObjectCount( pDmeSourceDCCFile->m_RootDCCObjects.Count() );
  471. for ( int rootObjectIndex( 0 ); rootObjectIndex < rootObjectCount; ++rootObjectIndex )
  472. {
  473. mayaCommand += " ";
  474. mayaCommand += pDmeSourceDCCFile->m_RootDCCObjects[ rootObjectIndex ];
  475. }
  476. char pSourcePath[MAX_PATH];
  477. pMakeFile->GetSourceFullPath( pDmeSourceDCCFile, pSourcePath, sizeof(pSourcePath) );
  478. // Maya wants forward slashes
  479. Q_FixSlashes( pSourcePath, '/' );
  480. char pMayaCommand[1024];
  481. Q_snprintf( pMayaCommand, sizeof(pMayaCommand), "mayabatch.exe -batch -file \"%s\" -command \"%s\"", pSourcePath, mayaCommand.Get() );
  482. IProcess *hProcess = g_pProcessUtils->StartProcess( pMayaCommand, STARTPROCESS_CONNECTSTDPIPES );
  483. SetCompileProcess( hProcess );
  484. return true;
  485. }
  486. //-----------------------------------------------------------------------------
  487. // Opens Maya with a particular file
  488. //-----------------------------------------------------------------------------
  489. void CDmeMakefileUtils::OpenEditor( CDmeSourceMayaFile *pDmeSourceDCCFile )
  490. {
  491. CDmeMayaMakefile *pMakefile = FindReferringElement< CDmeMayaMakefile >( pDmeSourceDCCFile, "sources" );
  492. if ( !pMakefile )
  493. return;
  494. char pSourcePath[MAX_PATH];
  495. pMakefile->GetSourceFullPath( pDmeSourceDCCFile, pSourcePath, sizeof(pSourcePath) );
  496. // Maya wants forward slashes
  497. Q_FixSlashes( pSourcePath, '/' );
  498. char pMayaCommand[1024];
  499. Q_snprintf( pMayaCommand, sizeof(pMayaCommand), "maya.exe -file \"%s\"", pSourcePath );
  500. g_pProcessUtils->StartProcess( pMayaCommand, STARTPROCESS_CONNECTSTDPIPES );
  501. }