Team Fortress 2 Source Code as on 22/4/2020
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.

628 lines
19 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Describes an asset: something that is compiled from sources,
  4. // in potentially multiple steps, to a compiled resource
  5. //
  6. //=============================================================================
  7. #include "movieobjects/dmemdlmakefile.h"
  8. #include "movieobjects/idmemakefileutils.h"
  9. #include "datamodel/dmelementfactoryhelper.h"
  10. #include "tier2/fileutils.h"
  11. #include "tier3/tier3.h"
  12. #include "filesystem.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. //-----------------------------------------------------------------------------
  16. // Hook into element factories
  17. //-----------------------------------------------------------------------------
  18. IMPLEMENT_ELEMENT_FACTORY( DmeSource, CDmeSource );
  19. //-----------------------------------------------------------------------------
  20. // Construction/destruction
  21. //-----------------------------------------------------------------------------
  22. void CDmeSource::OnConstruction()
  23. {
  24. m_DependentMakefile = NULL;
  25. }
  26. void CDmeSource::OnDestruction()
  27. {
  28. }
  29. //-----------------------------------------------------------------------------
  30. // Sets/gets the makefile that was used to build this source
  31. //-----------------------------------------------------------------------------
  32. void CDmeSource::SetDependentMakefile( CDmeMakefile *pMakeFile )
  33. {
  34. m_DependentMakefile = pMakeFile;
  35. }
  36. CDmeMakefile *CDmeSource::GetDependentMakefile()
  37. {
  38. return m_DependentMakefile.Get();
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Call this to open the source file in an editor
  42. //-----------------------------------------------------------------------------
  43. void CDmeSource::OpenEditor()
  44. {
  45. if ( g_pDmeMakefileUtils )
  46. {
  47. g_pDmeMakefileUtils->PerformOpenEditor( this );
  48. }
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Hook into element factories
  52. //-----------------------------------------------------------------------------
  53. IMPLEMENT_ELEMENT_FACTORY( DmeMakefile, CDmeMakefile );
  54. //-----------------------------------------------------------------------------
  55. // Construction/destruction
  56. //-----------------------------------------------------------------------------
  57. void CDmeMakefile::OnConstruction()
  58. {
  59. m_Sources.Init( this, "sources" );
  60. m_hOutput = NULL;
  61. m_hCompileProcess = PROCESS_HANDLE_INVALID;
  62. m_bIsDirty = false;
  63. }
  64. void CDmeMakefile::OnDestruction()
  65. {
  66. DestroyOutputElement( m_hOutput.Get() );
  67. m_hOutput = NULL;
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Performs pre-compilation step
  71. //-----------------------------------------------------------------------------
  72. void CDmeMakefile::PreCompile( )
  73. {
  74. // Make all outputs writeable
  75. MakeOutputsWriteable();
  76. // Destroy the current output object; we'll need to reload it
  77. // NOTE: Don't check for m_hOutput == 0; we always need to call DestroyOutputElement
  78. // Sometimes makefiles have to do stuff even if m_hOutput == NULL
  79. DestroyOutputElement( m_hOutput );
  80. m_hOutput = NULL;
  81. }
  82. void CDmeMakefile::PostCompile( )
  83. {
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Gets the output element created by compilation of this makefile
  87. //-----------------------------------------------------------------------------
  88. CDmElement *CDmeMakefile::GetOutputElement( bool bCreateIfNecessary )
  89. {
  90. if ( m_hOutput.Get() )
  91. return m_hOutput.Get();
  92. if ( !bCreateIfNecessary )
  93. return NULL;
  94. if ( !g_pDmeMakefileUtils || !g_pDmeMakefileUtils->IsCurrentlyCompiling() )
  95. {
  96. m_hOutput = CreateOutputElement();
  97. }
  98. return m_hOutput.Get();
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Gets the path of the makefile
  102. //-----------------------------------------------------------------------------
  103. void CDmeMakefile::GetMakefilePath( char *pFullPath, int nBufLen )
  104. {
  105. DmFileId_t fileId = GetFileId();
  106. const char *pFileName = ( fileId != DMFILEID_INVALID ) ? g_pDataModel->GetFileName( fileId ) : "";
  107. Assert( !pFileName[0] || Q_IsAbsolutePath( pFileName ) );
  108. Q_ExtractFilePath( pFileName, pFullPath, nBufLen );
  109. }
  110. //-----------------------------------------------------------------------------
  111. // Returns the output directory we expect to compile files into
  112. //-----------------------------------------------------------------------------
  113. bool CDmeMakefile::GetOutputDirectory( char *pFullPath, int nBufLen )
  114. {
  115. return GetDefaultDirectory( GetOutputDirectoryID(), pFullPath, nBufLen );
  116. }
  117. //-----------------------------------------------------------------------------
  118. // Returns the output name (output directory + filename, no extension)
  119. //-----------------------------------------------------------------------------
  120. bool CDmeMakefile::GetOutputName( char *pFullPath, int nBufLen )
  121. {
  122. pFullPath[0] = 0;
  123. char pOutputPath[MAX_PATH];
  124. if ( !GetDefaultDirectory( GetOutputDirectoryID(), pOutputPath, sizeof(pOutputPath) ) )
  125. return false;
  126. DmFileId_t fileId = GetFileId();
  127. const char *pFileName = ( fileId != DMFILEID_INVALID ) ? g_pDataModel->GetFileName( fileId ) : "";
  128. if ( !pFileName || !pFileName[0] )
  129. return false;
  130. Q_ComposeFileName( pOutputPath, Q_UnqualifiedFileName(pFileName), pFullPath, nBufLen );
  131. Q_RemoveDotSlashes( pFullPath );
  132. return true;
  133. }
  134. //-----------------------------------------------------------------------------
  135. // Converts the m_pDefaultDirectoryID field of the DmeMakefileType_t to a full path
  136. //-----------------------------------------------------------------------------
  137. bool CDmeMakefile::GetDefaultDirectory( const char *pDefaultDirectoryID, char *pFullPath, int nBufLen )
  138. {
  139. if ( StringHasPrefix( pDefaultDirectoryID, "contentdir:" ) )
  140. {
  141. pDefaultDirectoryID += 11;
  142. GetModContentSubdirectory( pDefaultDirectoryID, pFullPath, nBufLen );
  143. Q_RemoveDotSlashes( pFullPath );
  144. return true;
  145. }
  146. if ( StringHasPrefix( pDefaultDirectoryID, "gamedir:" ) )
  147. {
  148. pDefaultDirectoryID += 8;
  149. GetModSubdirectory( pDefaultDirectoryID, pFullPath, nBufLen );
  150. Q_RemoveDotSlashes( pFullPath );
  151. return true;
  152. }
  153. if ( StringHasPrefix( pDefaultDirectoryID, "makefiledir:" ) )
  154. {
  155. char pMakefilePath[MAX_PATH];
  156. GetMakefilePath( pMakefilePath, sizeof(pMakefilePath) );
  157. pDefaultDirectoryID += 12;
  158. Q_ComposeFileName( pMakefilePath, pDefaultDirectoryID, pFullPath, nBufLen );
  159. Q_RemoveDotSlashes( pFullPath );
  160. return true;
  161. }
  162. if ( StringHasPrefix( pDefaultDirectoryID, "makefilegamedir:" ) )
  163. {
  164. char pMakefilePath[MAX_PATH];
  165. GetMakefilePath( pMakefilePath, sizeof(pMakefilePath) );
  166. char pModContentDirectory[MAX_PATH];
  167. GetModContentSubdirectory( NULL, pModContentDirectory, sizeof(pModContentDirectory) );
  168. char pRelativePath[MAX_PATH];
  169. if ( !Q_MakeRelativePath( pMakefilePath, pModContentDirectory, pRelativePath, sizeof(pRelativePath) ) )
  170. {
  171. pFullPath[0] = 0;
  172. return false;
  173. }
  174. char pModDirectory[MAX_PATH];
  175. GetModSubdirectory( NULL, pModDirectory, sizeof(pModDirectory) );
  176. char pMakefileGamePath[MAX_PATH];
  177. Q_ComposeFileName( pModDirectory, pRelativePath, pMakefileGamePath, sizeof(pMakefileGamePath) );
  178. pDefaultDirectoryID += 16;
  179. Q_ComposeFileName( pMakefileGamePath, pDefaultDirectoryID, pFullPath, nBufLen );
  180. Q_RemoveDotSlashes( pFullPath );
  181. return true;
  182. }
  183. // Assume it's a content subdir
  184. GetModContentSubdirectory( pDefaultDirectoryID, pFullPath, nBufLen );
  185. Q_RemoveDotSlashes( pFullPath );
  186. return true;
  187. }
  188. //-----------------------------------------------------------------------------
  189. // Relative path to full path
  190. //-----------------------------------------------------------------------------
  191. void CDmeMakefile::RelativePathToFullPath( const char *pRelativePath, char *pFullPath, int nBufLen )
  192. {
  193. if ( !pRelativePath[0] )
  194. {
  195. pFullPath[0] = 0;
  196. return;
  197. }
  198. char pRootDir[ MAX_PATH ];
  199. GetMakefilePath( pRootDir, sizeof(pRootDir) );
  200. Q_ComposeFileName( pRootDir, pRelativePath, pFullPath, nBufLen );
  201. Q_RemoveDotSlashes( pFullPath );
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Fullpath to relative path
  205. //-----------------------------------------------------------------------------
  206. void CDmeMakefile::FullPathToRelativePath( const char *pFullPath, char *pRelativePath, int nBufLen )
  207. {
  208. if ( !pFullPath[0] )
  209. {
  210. pRelativePath[0] = 0;
  211. return;
  212. }
  213. char pRootDir[ MAX_PATH ];
  214. GetMakefilePath( pRootDir, sizeof(pRootDir) );
  215. if ( pRootDir[0] )
  216. {
  217. Q_MakeRelativePath( pFullPath, pRootDir, pRelativePath, nBufLen );
  218. }
  219. else
  220. {
  221. Q_strncpy( pRelativePath, pFullPath, nBufLen );
  222. Q_FixSlashes( pRelativePath );
  223. }
  224. }
  225. //-----------------------------------------------------------------------------
  226. // Adds a single source
  227. //-----------------------------------------------------------------------------
  228. CDmeSource *CDmeMakefile::AddSource( const char *pSourceType, const char *pFullPath )
  229. {
  230. if ( pFullPath[0] && FindSource( pSourceType, pFullPath ) )
  231. {
  232. Warning( "Attempted to add the same source twice %s!\n", pFullPath );
  233. return NULL;
  234. }
  235. CDmElement *pElement = GetElement< CDmElement >( g_pDataModel->CreateElement( pSourceType, "", GetFileId() ) );
  236. CDmeSource *pSource = CastElement< CDmeSource >( pElement );
  237. Assert( pSource );
  238. if ( !pSource )
  239. {
  240. Warning( "Invalid source type name %s!\n", pSourceType );
  241. if ( pElement )
  242. {
  243. DestroyElement( pElement );
  244. }
  245. return NULL;
  246. }
  247. char pRelativePath[MAX_PATH];
  248. FullPathToRelativePath( pFullPath, pRelativePath, sizeof( pRelativePath ) );
  249. pSource->SetRelativeFileName( pRelativePath );
  250. m_Sources.AddToTail( pSource );
  251. return pSource;
  252. }
  253. //-----------------------------------------------------------------------------
  254. // Removes a single source
  255. //-----------------------------------------------------------------------------
  256. CDmeSource *CDmeMakefile::FindSource( const char *pSourceType, const char *pFullPath )
  257. {
  258. char pRelativePath[MAX_PATH];
  259. FullPathToRelativePath( pFullPath, pRelativePath, sizeof( pRelativePath ) );
  260. int nCount = m_Sources.Count();
  261. for ( int i = 0; i < nCount; ++i )
  262. {
  263. if ( Q_stricmp( pSourceType, m_Sources[i]->GetTypeString() ) )
  264. continue;
  265. if ( !Q_stricmp( pRelativePath, m_Sources[i]->GetRelativeFileName() ) )
  266. return m_Sources[i];
  267. }
  268. return NULL;
  269. }
  270. //-----------------------------------------------------------------------------
  271. // Sets a source to be a single source
  272. //-----------------------------------------------------------------------------
  273. CDmeSource *CDmeMakefile::SetSingleSource( const char *pSourceType, const char *pFullPath )
  274. {
  275. // FIXME: we maybe shouldn't remove everything if the source can't be created for some reason?
  276. RemoveAllSources( pSourceType );
  277. return AddSource( pSourceType, pFullPath );
  278. }
  279. //-----------------------------------------------------------------------------
  280. // Changes a source
  281. //-----------------------------------------------------------------------------
  282. void CDmeMakefile::SetSourceFullPath( CDmeSource *pSource, const char *pFullPath )
  283. {
  284. char pRelativePath[MAX_PATH];
  285. FullPathToRelativePath( pFullPath, pRelativePath, sizeof( pRelativePath ) );
  286. if ( Q_stricmp( pRelativePath, pSource->GetRelativeFileName() ) )
  287. {
  288. pSource->SetRelativeFileName( pRelativePath );
  289. // FIXME: Should we delete the dependent makefile?
  290. pSource->SetDependentMakefile( NULL );
  291. }
  292. }
  293. //-----------------------------------------------------------------------------
  294. // Returns the full path of a source
  295. //-----------------------------------------------------------------------------
  296. void CDmeMakefile::GetSourceFullPath( CDmeSource *pSource, char *pFullPath, int nBufLen )
  297. {
  298. const char *pRelativePath = pSource->GetRelativeFileName( );
  299. RelativePathToFullPath( pRelativePath, pFullPath, nBufLen );
  300. }
  301. //-----------------------------------------------------------------------------
  302. // Returns a list of sources
  303. //-----------------------------------------------------------------------------
  304. void CDmeMakefile::GetSources( const char *pSourceType, CUtlVector< CDmeHandle< CDmeSource > > &sources )
  305. {
  306. int nCount = m_Sources.Count();
  307. sources.EnsureCapacity( nCount );
  308. for ( int i = 0; i < nCount; ++i )
  309. {
  310. if ( m_Sources[i]->IsA( pSourceType ) )
  311. {
  312. int j = sources.AddToTail();
  313. sources[j] = m_Sources[i];
  314. }
  315. }
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Gets a list of all sources, regardless of type
  319. //-----------------------------------------------------------------------------
  320. int CDmeMakefile::GetSourceCount()
  321. {
  322. return m_Sources.Count();
  323. }
  324. CDmeSource *CDmeMakefile::GetSource( int nIndex )
  325. {
  326. return m_Sources[nIndex];
  327. }
  328. //-----------------------------------------------------------------------------
  329. // Removes a single source
  330. //-----------------------------------------------------------------------------
  331. void CDmeMakefile::RemoveSource( CDmeSource *pSource )
  332. {
  333. int nCount = m_Sources.Count();
  334. for ( int i = 0; i < nCount; ++i )
  335. {
  336. if ( m_Sources[i] == pSource )
  337. {
  338. m_Sources.Remove( i );
  339. break;
  340. }
  341. }
  342. }
  343. void CDmeMakefile::RemoveSource( const char *pSourceType, const char *pFullPath )
  344. {
  345. char pRelativePath[MAX_PATH];
  346. FullPathToRelativePath( pFullPath, pRelativePath, sizeof( pRelativePath ) );
  347. int nCount = m_Sources.Count();
  348. for ( int i = 0; i < nCount; ++i )
  349. {
  350. if ( Q_stricmp( pSourceType, m_Sources[i]->GetTypeString() ) )
  351. continue;
  352. if ( !Q_stricmp( pRelativePath, m_Sources[i]->GetRelativeFileName() ) )
  353. {
  354. m_Sources.Remove( i );
  355. break;
  356. }
  357. }
  358. }
  359. //-----------------------------------------------------------------------------
  360. // Removes all sources of a particular type
  361. //-----------------------------------------------------------------------------
  362. void CDmeMakefile::RemoveAllSources( const char *pSourceType )
  363. {
  364. int nCount = m_Sources.Count();
  365. for ( int i = nCount; --i >= 0; )
  366. {
  367. if ( !Q_stricmp( pSourceType, m_Sources[i]->GetTypeString() ) )
  368. {
  369. // NOTE: This works because we're iterating backward
  370. m_Sources.Remove( i );
  371. }
  372. }
  373. }
  374. //-----------------------------------------------------------------------------
  375. // Source iteration
  376. //-----------------------------------------------------------------------------
  377. bool CDmeMakefile::HasSourceOfType( const char *pSourceType )
  378. {
  379. int nCount = m_Sources.Count();
  380. for ( int i = nCount; --i >= 0; )
  381. {
  382. if ( !Q_stricmp( pSourceType, m_Sources[i]->GetTypeString() ) )
  383. return true;
  384. }
  385. return false;
  386. }
  387. //-----------------------------------------------------------------------------
  388. // Updates the source names to be relative to a particular path
  389. //-----------------------------------------------------------------------------
  390. bool CDmeMakefile::UpdateSourceNames( const char *pOldRootDir, const char *pNewRootDir, bool bApplyChanges )
  391. {
  392. char pOldSourcePath[ MAX_PATH ];
  393. char pNewSourcePath[ MAX_PATH ];
  394. int nCount = m_Sources.Count();
  395. for ( int i = 0; i < nCount; ++i )
  396. {
  397. const char *pOldRelativePath = m_Sources[i]->GetRelativeFileName();
  398. if ( pOldRelativePath[0] )
  399. {
  400. Q_ComposeFileName( pOldRootDir, pOldRelativePath, pOldSourcePath, sizeof(pOldSourcePath) );
  401. Q_RemoveDotSlashes( pOldSourcePath );
  402. if ( !Q_MakeRelativePath( pOldSourcePath, pNewRootDir, pNewSourcePath, sizeof(pNewSourcePath) ) )
  403. {
  404. Assert( !bApplyChanges );
  405. return false;
  406. }
  407. }
  408. else
  409. {
  410. pNewSourcePath[0] = 0;
  411. }
  412. if ( !bApplyChanges )
  413. continue;
  414. m_Sources[i]->SetRelativeFileName( pNewSourcePath );
  415. }
  416. return true;
  417. }
  418. //-----------------------------------------------------------------------------
  419. // Returns the filename
  420. //-----------------------------------------------------------------------------
  421. const char *CDmeMakefile::GetFileName() const
  422. {
  423. DmFileId_t fileId = GetFileId();
  424. return g_pDataModel->GetFileName( fileId );
  425. }
  426. //-----------------------------------------------------------------------------
  427. // Call this to change the file the makefile is stored in
  428. // Will make all sources be relative to this path
  429. //-----------------------------------------------------------------------------
  430. bool CDmeMakefile::SetFileName( const char *pFileName )
  431. {
  432. if ( !Q_IsAbsolutePath( pFileName ) )
  433. return false;
  434. char pOldRootDir[ MAX_PATH ];
  435. char pNewRootDir[ MAX_PATH ];
  436. GetMakefilePath( pOldRootDir, sizeof(pOldRootDir) );
  437. Q_ExtractFilePath( pFileName, pNewRootDir, sizeof(pNewRootDir) );
  438. // Gotta do this twice; once to check for validity, once to actually do it
  439. if ( !UpdateSourceNames( pOldRootDir, pNewRootDir, false ) )
  440. return false;
  441. UpdateSourceNames( pOldRootDir, pNewRootDir, true );
  442. DmFileId_t fileId = GetFileId();
  443. if ( fileId == DMFILEID_INVALID )
  444. {
  445. fileId = g_pDataModel->FindOrCreateFileId( pFileName );
  446. SetFileId( fileId, TD_DEEP );
  447. }
  448. else
  449. {
  450. g_pDataModel->SetFileName( fileId, pFileName );
  451. }
  452. return true;
  453. }
  454. //-----------------------------------------------------------------------------
  455. // Make all outputs writeable
  456. //-----------------------------------------------------------------------------
  457. void CDmeMakefile::MakeOutputsWriteable( )
  458. {
  459. // When we publish, we'll check them out.
  460. CUtlVector<CUtlString> outputs;
  461. GetOutputs( outputs );
  462. int nCount = outputs.Count();
  463. for ( int i = 0; i < nCount; ++i )
  464. {
  465. g_pFullFileSystem->SetFileWritable( outputs[i], true );
  466. }
  467. }
  468. //-----------------------------------------------------------------------------
  469. // Sets a makefile/source association
  470. //-----------------------------------------------------------------------------
  471. void CDmeMakefile::SetAssociation( CDmeSource *pSource, CDmeMakefile *pSourceMakefile )
  472. {
  473. if ( !pSource )
  474. return;
  475. int nCount = m_Sources.Count();
  476. for ( int i = 0; i < nCount; ++i )
  477. {
  478. if ( m_Sources[i] != pSource )
  479. continue;
  480. CDmeMakefile *pDependentMakeFile = m_Sources[i]->GetDependentMakefile();
  481. if ( pSourceMakefile != pDependentMakeFile )
  482. {
  483. // FIXME: Should I recursively delete pDependentMakeFile ?
  484. m_Sources[i]->SetDependentMakefile( pSourceMakefile );
  485. }
  486. return;
  487. }
  488. }
  489. //-----------------------------------------------------------------------------
  490. // Finds a dependent makefile
  491. //-----------------------------------------------------------------------------
  492. CDmeMakefile *CDmeMakefile::FindDependentMakefile( CDmeSource *pSource )
  493. {
  494. if ( !pSource )
  495. return NULL;
  496. int nCount = m_Sources.Count();
  497. for ( int i = 0; i < nCount; ++i )
  498. {
  499. if ( m_Sources[i] == pSource )
  500. return m_Sources[i]->GetDependentMakefile();
  501. }
  502. return NULL;
  503. }
  504. //-----------------------------------------------------------------------------
  505. // Finds the associated source
  506. //-----------------------------------------------------------------------------
  507. CDmeSource *CDmeMakefile::FindAssociatedSource( CDmeMakefile *pChildMakefile )
  508. {
  509. if ( !pChildMakefile )
  510. return NULL;
  511. int nCount = m_Sources.Count();
  512. for ( int i = 0; i < nCount; ++i )
  513. {
  514. if ( m_Sources[i]->GetDependentMakefile() == pChildMakefile )
  515. return m_Sources[i];
  516. }
  517. return NULL;
  518. }