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
628 lines
19 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Describes an asset: something that is compiled from sources, |
|
// in potentially multiple steps, to a compiled resource |
|
// |
|
//============================================================================= |
|
|
|
|
|
#include "movieobjects/dmemdlmakefile.h" |
|
#include "movieobjects/idmemakefileutils.h" |
|
#include "datamodel/dmelementfactoryhelper.h" |
|
#include "tier2/fileutils.h" |
|
#include "tier3/tier3.h" |
|
#include "filesystem.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Hook into element factories |
|
//----------------------------------------------------------------------------- |
|
IMPLEMENT_ELEMENT_FACTORY( DmeSource, CDmeSource ); |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Construction/destruction |
|
//----------------------------------------------------------------------------- |
|
void CDmeSource::OnConstruction() |
|
{ |
|
m_DependentMakefile = NULL; |
|
} |
|
|
|
void CDmeSource::OnDestruction() |
|
{ |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Sets/gets the makefile that was used to build this source |
|
//----------------------------------------------------------------------------- |
|
void CDmeSource::SetDependentMakefile( CDmeMakefile *pMakeFile ) |
|
{ |
|
m_DependentMakefile = pMakeFile; |
|
} |
|
|
|
CDmeMakefile *CDmeSource::GetDependentMakefile() |
|
{ |
|
return m_DependentMakefile.Get(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Call this to open the source file in an editor |
|
//----------------------------------------------------------------------------- |
|
void CDmeSource::OpenEditor() |
|
{ |
|
if ( g_pDmeMakefileUtils ) |
|
{ |
|
g_pDmeMakefileUtils->PerformOpenEditor( this ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Hook into element factories |
|
//----------------------------------------------------------------------------- |
|
IMPLEMENT_ELEMENT_FACTORY( DmeMakefile, CDmeMakefile ); |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Construction/destruction |
|
//----------------------------------------------------------------------------- |
|
void CDmeMakefile::OnConstruction() |
|
{ |
|
m_Sources.Init( this, "sources" ); |
|
m_hOutput = NULL; |
|
m_hCompileProcess = PROCESS_HANDLE_INVALID; |
|
m_bIsDirty = false; |
|
} |
|
|
|
void CDmeMakefile::OnDestruction() |
|
{ |
|
DestroyOutputElement( m_hOutput.Get() ); |
|
m_hOutput = NULL; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Performs pre-compilation step |
|
//----------------------------------------------------------------------------- |
|
void CDmeMakefile::PreCompile( ) |
|
{ |
|
// Make all outputs writeable |
|
MakeOutputsWriteable(); |
|
|
|
// Destroy the current output object; we'll need to reload it |
|
// NOTE: Don't check for m_hOutput == 0; we always need to call DestroyOutputElement |
|
// Sometimes makefiles have to do stuff even if m_hOutput == NULL |
|
DestroyOutputElement( m_hOutput ); |
|
m_hOutput = NULL; |
|
} |
|
|
|
void CDmeMakefile::PostCompile( ) |
|
{ |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Gets the output element created by compilation of this makefile |
|
//----------------------------------------------------------------------------- |
|
CDmElement *CDmeMakefile::GetOutputElement( bool bCreateIfNecessary ) |
|
{ |
|
if ( m_hOutput.Get() ) |
|
return m_hOutput.Get(); |
|
|
|
if ( !bCreateIfNecessary ) |
|
return NULL; |
|
|
|
if ( !g_pDmeMakefileUtils || !g_pDmeMakefileUtils->IsCurrentlyCompiling() ) |
|
{ |
|
m_hOutput = CreateOutputElement(); |
|
} |
|
|
|
return m_hOutput.Get(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Gets the path of the makefile |
|
//----------------------------------------------------------------------------- |
|
void CDmeMakefile::GetMakefilePath( char *pFullPath, int nBufLen ) |
|
{ |
|
DmFileId_t fileId = GetFileId(); |
|
const char *pFileName = ( fileId != DMFILEID_INVALID ) ? g_pDataModel->GetFileName( fileId ) : ""; |
|
Assert( !pFileName[0] || Q_IsAbsolutePath( pFileName ) ); |
|
|
|
Q_ExtractFilePath( pFileName, pFullPath, nBufLen ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns the output directory we expect to compile files into |
|
//----------------------------------------------------------------------------- |
|
bool CDmeMakefile::GetOutputDirectory( char *pFullPath, int nBufLen ) |
|
{ |
|
return GetDefaultDirectory( GetOutputDirectoryID(), pFullPath, nBufLen ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns the output name (output directory + filename, no extension) |
|
//----------------------------------------------------------------------------- |
|
bool CDmeMakefile::GetOutputName( char *pFullPath, int nBufLen ) |
|
{ |
|
pFullPath[0] = 0; |
|
|
|
char pOutputPath[MAX_PATH]; |
|
if ( !GetDefaultDirectory( GetOutputDirectoryID(), pOutputPath, sizeof(pOutputPath) ) ) |
|
return false; |
|
|
|
DmFileId_t fileId = GetFileId(); |
|
const char *pFileName = ( fileId != DMFILEID_INVALID ) ? g_pDataModel->GetFileName( fileId ) : ""; |
|
if ( !pFileName || !pFileName[0] ) |
|
return false; |
|
|
|
Q_ComposeFileName( pOutputPath, Q_UnqualifiedFileName(pFileName), pFullPath, nBufLen ); |
|
Q_RemoveDotSlashes( pFullPath ); |
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Converts the m_pDefaultDirectoryID field of the DmeMakefileType_t to a full path |
|
//----------------------------------------------------------------------------- |
|
bool CDmeMakefile::GetDefaultDirectory( const char *pDefaultDirectoryID, char *pFullPath, int nBufLen ) |
|
{ |
|
if ( StringHasPrefix( pDefaultDirectoryID, "contentdir:" ) ) |
|
{ |
|
pDefaultDirectoryID += 11; |
|
GetModContentSubdirectory( pDefaultDirectoryID, pFullPath, nBufLen ); |
|
Q_RemoveDotSlashes( pFullPath ); |
|
return true; |
|
} |
|
|
|
if ( StringHasPrefix( pDefaultDirectoryID, "gamedir:" ) ) |
|
{ |
|
pDefaultDirectoryID += 8; |
|
GetModSubdirectory( pDefaultDirectoryID, pFullPath, nBufLen ); |
|
Q_RemoveDotSlashes( pFullPath ); |
|
return true; |
|
} |
|
|
|
if ( StringHasPrefix( pDefaultDirectoryID, "makefiledir:" ) ) |
|
{ |
|
char pMakefilePath[MAX_PATH]; |
|
GetMakefilePath( pMakefilePath, sizeof(pMakefilePath) ); |
|
pDefaultDirectoryID += 12; |
|
Q_ComposeFileName( pMakefilePath, pDefaultDirectoryID, pFullPath, nBufLen ); |
|
Q_RemoveDotSlashes( pFullPath ); |
|
return true; |
|
} |
|
|
|
if ( StringHasPrefix( pDefaultDirectoryID, "makefilegamedir:" ) ) |
|
{ |
|
char pMakefilePath[MAX_PATH]; |
|
GetMakefilePath( pMakefilePath, sizeof(pMakefilePath) ); |
|
|
|
char pModContentDirectory[MAX_PATH]; |
|
GetModContentSubdirectory( NULL, pModContentDirectory, sizeof(pModContentDirectory) ); |
|
|
|
char pRelativePath[MAX_PATH]; |
|
if ( !Q_MakeRelativePath( pMakefilePath, pModContentDirectory, pRelativePath, sizeof(pRelativePath) ) ) |
|
{ |
|
pFullPath[0] = 0; |
|
return false; |
|
} |
|
|
|
char pModDirectory[MAX_PATH]; |
|
GetModSubdirectory( NULL, pModDirectory, sizeof(pModDirectory) ); |
|
|
|
char pMakefileGamePath[MAX_PATH]; |
|
Q_ComposeFileName( pModDirectory, pRelativePath, pMakefileGamePath, sizeof(pMakefileGamePath) ); |
|
|
|
pDefaultDirectoryID += 16; |
|
Q_ComposeFileName( pMakefileGamePath, pDefaultDirectoryID, pFullPath, nBufLen ); |
|
Q_RemoveDotSlashes( pFullPath ); |
|
return true; |
|
} |
|
|
|
// Assume it's a content subdir |
|
GetModContentSubdirectory( pDefaultDirectoryID, pFullPath, nBufLen ); |
|
Q_RemoveDotSlashes( pFullPath ); |
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Relative path to full path |
|
//----------------------------------------------------------------------------- |
|
void CDmeMakefile::RelativePathToFullPath( const char *pRelativePath, char *pFullPath, int nBufLen ) |
|
{ |
|
if ( !pRelativePath[0] ) |
|
{ |
|
pFullPath[0] = 0; |
|
return; |
|
} |
|
char pRootDir[ MAX_PATH ]; |
|
GetMakefilePath( pRootDir, sizeof(pRootDir) ); |
|
Q_ComposeFileName( pRootDir, pRelativePath, pFullPath, nBufLen ); |
|
Q_RemoveDotSlashes( pFullPath ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Fullpath to relative path |
|
//----------------------------------------------------------------------------- |
|
void CDmeMakefile::FullPathToRelativePath( const char *pFullPath, char *pRelativePath, int nBufLen ) |
|
{ |
|
if ( !pFullPath[0] ) |
|
{ |
|
pRelativePath[0] = 0; |
|
return; |
|
} |
|
char pRootDir[ MAX_PATH ]; |
|
GetMakefilePath( pRootDir, sizeof(pRootDir) ); |
|
if ( pRootDir[0] ) |
|
{ |
|
Q_MakeRelativePath( pFullPath, pRootDir, pRelativePath, nBufLen ); |
|
} |
|
else |
|
{ |
|
Q_strncpy( pRelativePath, pFullPath, nBufLen ); |
|
Q_FixSlashes( pRelativePath ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Adds a single source |
|
//----------------------------------------------------------------------------- |
|
CDmeSource *CDmeMakefile::AddSource( const char *pSourceType, const char *pFullPath ) |
|
{ |
|
if ( pFullPath[0] && FindSource( pSourceType, pFullPath ) ) |
|
{ |
|
Warning( "Attempted to add the same source twice %s!\n", pFullPath ); |
|
return NULL; |
|
} |
|
|
|
CDmElement *pElement = GetElement< CDmElement >( g_pDataModel->CreateElement( pSourceType, "", GetFileId() ) ); |
|
CDmeSource *pSource = CastElement< CDmeSource >( pElement ); |
|
Assert( pSource ); |
|
if ( !pSource ) |
|
{ |
|
Warning( "Invalid source type name %s!\n", pSourceType ); |
|
if ( pElement ) |
|
{ |
|
DestroyElement( pElement ); |
|
} |
|
return NULL; |
|
} |
|
|
|
char pRelativePath[MAX_PATH]; |
|
FullPathToRelativePath( pFullPath, pRelativePath, sizeof( pRelativePath ) ); |
|
pSource->SetRelativeFileName( pRelativePath ); |
|
m_Sources.AddToTail( pSource ); |
|
return pSource; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Removes a single source |
|
//----------------------------------------------------------------------------- |
|
CDmeSource *CDmeMakefile::FindSource( const char *pSourceType, const char *pFullPath ) |
|
{ |
|
char pRelativePath[MAX_PATH]; |
|
FullPathToRelativePath( pFullPath, pRelativePath, sizeof( pRelativePath ) ); |
|
int nCount = m_Sources.Count(); |
|
for ( int i = 0; i < nCount; ++i ) |
|
{ |
|
if ( Q_stricmp( pSourceType, m_Sources[i]->GetTypeString() ) ) |
|
continue; |
|
|
|
if ( !Q_stricmp( pRelativePath, m_Sources[i]->GetRelativeFileName() ) ) |
|
return m_Sources[i]; |
|
} |
|
return NULL; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Sets a source to be a single source |
|
//----------------------------------------------------------------------------- |
|
CDmeSource *CDmeMakefile::SetSingleSource( const char *pSourceType, const char *pFullPath ) |
|
{ |
|
// FIXME: we maybe shouldn't remove everything if the source can't be created for some reason? |
|
RemoveAllSources( pSourceType ); |
|
return AddSource( pSourceType, pFullPath ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Changes a source |
|
//----------------------------------------------------------------------------- |
|
void CDmeMakefile::SetSourceFullPath( CDmeSource *pSource, const char *pFullPath ) |
|
{ |
|
char pRelativePath[MAX_PATH]; |
|
FullPathToRelativePath( pFullPath, pRelativePath, sizeof( pRelativePath ) ); |
|
|
|
if ( Q_stricmp( pRelativePath, pSource->GetRelativeFileName() ) ) |
|
{ |
|
pSource->SetRelativeFileName( pRelativePath ); |
|
|
|
// FIXME: Should we delete the dependent makefile? |
|
pSource->SetDependentMakefile( NULL ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns the full path of a source |
|
//----------------------------------------------------------------------------- |
|
void CDmeMakefile::GetSourceFullPath( CDmeSource *pSource, char *pFullPath, int nBufLen ) |
|
{ |
|
const char *pRelativePath = pSource->GetRelativeFileName( ); |
|
RelativePathToFullPath( pRelativePath, pFullPath, nBufLen ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns a list of sources |
|
//----------------------------------------------------------------------------- |
|
void CDmeMakefile::GetSources( const char *pSourceType, CUtlVector< CDmeHandle< CDmeSource > > &sources ) |
|
{ |
|
int nCount = m_Sources.Count(); |
|
sources.EnsureCapacity( nCount ); |
|
for ( int i = 0; i < nCount; ++i ) |
|
{ |
|
if ( m_Sources[i]->IsA( pSourceType ) ) |
|
{ |
|
int j = sources.AddToTail(); |
|
sources[j] = m_Sources[i]; |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Gets a list of all sources, regardless of type |
|
//----------------------------------------------------------------------------- |
|
int CDmeMakefile::GetSourceCount() |
|
{ |
|
return m_Sources.Count(); |
|
} |
|
|
|
CDmeSource *CDmeMakefile::GetSource( int nIndex ) |
|
{ |
|
return m_Sources[nIndex]; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Removes a single source |
|
//----------------------------------------------------------------------------- |
|
void CDmeMakefile::RemoveSource( CDmeSource *pSource ) |
|
{ |
|
int nCount = m_Sources.Count(); |
|
for ( int i = 0; i < nCount; ++i ) |
|
{ |
|
if ( m_Sources[i] == pSource ) |
|
{ |
|
m_Sources.Remove( i ); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
void CDmeMakefile::RemoveSource( const char *pSourceType, const char *pFullPath ) |
|
{ |
|
char pRelativePath[MAX_PATH]; |
|
FullPathToRelativePath( pFullPath, pRelativePath, sizeof( pRelativePath ) ); |
|
int nCount = m_Sources.Count(); |
|
for ( int i = 0; i < nCount; ++i ) |
|
{ |
|
if ( Q_stricmp( pSourceType, m_Sources[i]->GetTypeString() ) ) |
|
continue; |
|
|
|
if ( !Q_stricmp( pRelativePath, m_Sources[i]->GetRelativeFileName() ) ) |
|
{ |
|
m_Sources.Remove( i ); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Removes all sources of a particular type |
|
//----------------------------------------------------------------------------- |
|
void CDmeMakefile::RemoveAllSources( const char *pSourceType ) |
|
{ |
|
int nCount = m_Sources.Count(); |
|
for ( int i = nCount; --i >= 0; ) |
|
{ |
|
if ( !Q_stricmp( pSourceType, m_Sources[i]->GetTypeString() ) ) |
|
{ |
|
// NOTE: This works because we're iterating backward |
|
m_Sources.Remove( i ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Source iteration |
|
//----------------------------------------------------------------------------- |
|
bool CDmeMakefile::HasSourceOfType( const char *pSourceType ) |
|
{ |
|
int nCount = m_Sources.Count(); |
|
for ( int i = nCount; --i >= 0; ) |
|
{ |
|
if ( !Q_stricmp( pSourceType, m_Sources[i]->GetTypeString() ) ) |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Updates the source names to be relative to a particular path |
|
//----------------------------------------------------------------------------- |
|
bool CDmeMakefile::UpdateSourceNames( const char *pOldRootDir, const char *pNewRootDir, bool bApplyChanges ) |
|
{ |
|
char pOldSourcePath[ MAX_PATH ]; |
|
char pNewSourcePath[ MAX_PATH ]; |
|
|
|
int nCount = m_Sources.Count(); |
|
for ( int i = 0; i < nCount; ++i ) |
|
{ |
|
const char *pOldRelativePath = m_Sources[i]->GetRelativeFileName(); |
|
if ( pOldRelativePath[0] ) |
|
{ |
|
Q_ComposeFileName( pOldRootDir, pOldRelativePath, pOldSourcePath, sizeof(pOldSourcePath) ); |
|
Q_RemoveDotSlashes( pOldSourcePath ); |
|
if ( !Q_MakeRelativePath( pOldSourcePath, pNewRootDir, pNewSourcePath, sizeof(pNewSourcePath) ) ) |
|
{ |
|
Assert( !bApplyChanges ); |
|
return false; |
|
} |
|
} |
|
else |
|
{ |
|
pNewSourcePath[0] = 0; |
|
} |
|
|
|
if ( !bApplyChanges ) |
|
continue; |
|
|
|
m_Sources[i]->SetRelativeFileName( pNewSourcePath ); |
|
} |
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns the filename |
|
//----------------------------------------------------------------------------- |
|
const char *CDmeMakefile::GetFileName() const |
|
{ |
|
DmFileId_t fileId = GetFileId(); |
|
return g_pDataModel->GetFileName( fileId ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Call this to change the file the makefile is stored in |
|
// Will make all sources be relative to this path |
|
//----------------------------------------------------------------------------- |
|
bool CDmeMakefile::SetFileName( const char *pFileName ) |
|
{ |
|
if ( !Q_IsAbsolutePath( pFileName ) ) |
|
return false; |
|
|
|
char pOldRootDir[ MAX_PATH ]; |
|
char pNewRootDir[ MAX_PATH ]; |
|
GetMakefilePath( pOldRootDir, sizeof(pOldRootDir) ); |
|
Q_ExtractFilePath( pFileName, pNewRootDir, sizeof(pNewRootDir) ); |
|
|
|
// Gotta do this twice; once to check for validity, once to actually do it |
|
if ( !UpdateSourceNames( pOldRootDir, pNewRootDir, false ) ) |
|
return false; |
|
|
|
UpdateSourceNames( pOldRootDir, pNewRootDir, true ); |
|
|
|
DmFileId_t fileId = GetFileId(); |
|
if ( fileId == DMFILEID_INVALID ) |
|
{ |
|
fileId = g_pDataModel->FindOrCreateFileId( pFileName ); |
|
SetFileId( fileId, TD_DEEP ); |
|
} |
|
else |
|
{ |
|
g_pDataModel->SetFileName( fileId, pFileName ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Make all outputs writeable |
|
//----------------------------------------------------------------------------- |
|
void CDmeMakefile::MakeOutputsWriteable( ) |
|
{ |
|
// When we publish, we'll check them out. |
|
CUtlVector<CUtlString> outputs; |
|
GetOutputs( outputs ); |
|
int nCount = outputs.Count(); |
|
for ( int i = 0; i < nCount; ++i ) |
|
{ |
|
g_pFullFileSystem->SetFileWritable( outputs[i], true ); |
|
} |
|
} |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Sets a makefile/source association |
|
//----------------------------------------------------------------------------- |
|
void CDmeMakefile::SetAssociation( CDmeSource *pSource, CDmeMakefile *pSourceMakefile ) |
|
{ |
|
if ( !pSource ) |
|
return; |
|
|
|
int nCount = m_Sources.Count(); |
|
for ( int i = 0; i < nCount; ++i ) |
|
{ |
|
if ( m_Sources[i] != pSource ) |
|
continue; |
|
|
|
CDmeMakefile *pDependentMakeFile = m_Sources[i]->GetDependentMakefile(); |
|
if ( pSourceMakefile != pDependentMakeFile ) |
|
{ |
|
// FIXME: Should I recursively delete pDependentMakeFile ? |
|
m_Sources[i]->SetDependentMakefile( pSourceMakefile ); |
|
} |
|
return; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Finds a dependent makefile |
|
//----------------------------------------------------------------------------- |
|
CDmeMakefile *CDmeMakefile::FindDependentMakefile( CDmeSource *pSource ) |
|
{ |
|
if ( !pSource ) |
|
return NULL; |
|
|
|
int nCount = m_Sources.Count(); |
|
for ( int i = 0; i < nCount; ++i ) |
|
{ |
|
if ( m_Sources[i] == pSource ) |
|
return m_Sources[i]->GetDependentMakefile(); |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Finds the associated source |
|
//----------------------------------------------------------------------------- |
|
CDmeSource *CDmeMakefile::FindAssociatedSource( CDmeMakefile *pChildMakefile ) |
|
{ |
|
if ( !pChildMakefile ) |
|
return NULL; |
|
|
|
int nCount = m_Sources.Count(); |
|
for ( int i = 0; i < nCount; ++i ) |
|
{ |
|
if ( m_Sources[i]->GetDependentMakefile() == pChildMakefile ) |
|
return m_Sources[i]; |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
|