diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /external/vpc/utils | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'external/vpc/utils')
56 files changed, 25961 insertions, 0 deletions
diff --git a/external/vpc/utils/vpc/Makefile b/external/vpc/utils/vpc/Makefile new file mode 100644 index 0000000..1bf7b05 --- /dev/null +++ b/external/vpc/utils/vpc/Makefile @@ -0,0 +1,298 @@ +# Make command to use for dependencies +SHELL=/bin/sh +RM:=rm +MKDIR:=mkdir +OS:=$(shell uname) +EXE_POSTFIX:="" + + +# ---------------------------------------------------------------- # +# Figure out if we're building in the Steam tree or not. +# ---------------------------------------------------------------- # + +SRCROOT:=../.. +-include $(SRCROOT)/devtools/steam_def.mak + + +# ---------------------------------------------------------------- # +# Set paths to gcc. +# ---------------------------------------------------------------- # + +CC:=gcc +CXX:=g++ + +ifeq ($(OS),Darwin) +SDKROOT:=$(shell xcodebuild -sdk macosx -version Path) +CC:=clang -m32 +CXX:=clang++ -m32 +EXE_POSTFIX:=_osx +endif + +ifeq ($(OS),Linux) +ifeq ($(wildcard /valve/bin/gcc),) +CC:=gcc +CXX:=g++ +else +CC:=/valve/bin/gcc-4.7 +CXX:=/valve/bin/g++-4.7 +endif +EXE_POSTFIX:=_linux +endif + +ifneq ($(CC_OVERRIDE),) + CC:=$(CC_OVERRIDE) + CXX:=$(CPP_OVERRIDE) +endif + + +# ---------------------------------------------------------------- # +# Lists of files. +# ---------------------------------------------------------------- # + +VPC_SRC:= \ + exprsimplifier.cpp \ + groupscript.cpp \ + conditionals.cpp \ + macros.cpp \ + projectscript.cpp \ + scriptsource.cpp \ + baseprojectdatacollector.cpp \ + configuration.cpp \ + dependencies.cpp \ + main.cpp \ + projectgenerator_makefile.cpp \ + solutiongenerator_makefile.cpp \ + solutiongenerator_xcode.cpp \ + sys_utils.cpp \ + ../vpccrccheck/crccheck_shared.cpp \ + projectgenerator_codelite.cpp \ + solutiongenerator_codelite.cpp \ + +TIER0_SRC:= \ + ../../tier0/assert_dialog.cpp \ + ../../tier0/cpu_posix.cpp \ + ../../tier0/cpu.cpp \ + ../../tier0/dbg.cpp \ + ../../tier0/fasttimer.cpp \ + ../../tier0/mem.cpp \ + ../../tier0/mem_helpers.cpp \ + ../../tier0/memdbg.cpp \ + ../../tier0/memstd.cpp \ + ../../tier0/memvalidate.cpp \ + ../../tier0/minidump.cpp \ + ../../tier0/pch_tier0.cpp \ + ../../tier0/threadtools.cpp \ + ../../tier0/valobject.cpp \ + ../../tier0/vprof.cpp + + +TIER1_SRC:= \ + ../../tier1/keyvalues.cpp \ + ../../tier1/checksum_crc.cpp \ + ../../tier1/checksum_md5.cpp \ + ../../tier1/convar.cpp \ + ../../tier1/generichash.cpp \ + ../../tier1/interface.cpp \ + ../../tier1/mempool.cpp \ + ../../tier1/memstack.cpp \ + ../../tier1/stringpool.cpp \ + ../../tier1/utlbuffer.cpp \ + ../../tier1/utlsymbol.cpp + +VSTDLIB_SRC:= \ + ../../vstdlib/cvar.cpp \ + ../../vstdlib/vstrtools.cpp \ + ../../vstdlib/random.cpp + + +ifeq "$(STEAM_BRANCH)" "1" + TIER0_SRC+= \ + ../../tier0/tier0.cpp \ + ../../tier0/platform_posix.cpp \ + ../../tier0/validator.cpp \ + ../../tier0/thread.cpp \ + ../../tier0/pmelib.cpp \ + ../../tier0/pme_posix.cpp \ + ../../tier0/testthread.cpp \ + ../../tier0/cpu_posix.cpp \ + ../../tier0/memblockhdr.cpp + + VSTDLIB_SRC+= \ + ../../vstdlib/keyvaluessystem.cpp \ + ../../vstdlib/qsort_s.cpp \ + ../../vstdlib/strtools.cpp \ + ../../vstdlib/stringnormalize.cpp \ + ../../vstdlib/splitstring.cpp \ + ../../vstdlib/commandline.cpp + + INTERFACES_SRC= + + BINLAUNCH_SRC = + +else + + TIER0_SRC+= \ + ../../tier0/platform_posix.cpp \ + ../../tier0/pme_posix.cpp \ + ../../tier0/commandline.cpp \ + ../../tier0/win32consoleio.cpp \ + ../../tier0/logging.cpp \ + ../../tier0/tier0_strtools.cpp + + TIER1_SRC+= \ + ../../tier1/utlstring.cpp \ + ../../tier1/tier1.cpp \ + ../../tier1/characterset.cpp \ + ../../tier1/splitstring.cpp \ + ../../tier1/strtools.cpp \ + ../../tier1/exprevaluator.cpp \ + + VSTDLIB_SRC+= \ + ../../vstdlib/keyvaluessystem.cpp + + INTERFACES_SRC= \ + ../../interfaces/interfaces.cpp + + BINLAUNCH_SRC = \ + +endif + + +SRC:=$(VPC_SRC) $(TIER0_SRC) $(TIER1_SRC) $(VSTDLIB_SRC) $(INTERFACES_SRC) $(BINLAUNCH_SRC) + + +# -----Begin user-editable area----- + +# -----End user-editable area----- + +# If no configuration is specified, "Debug" will be used +ifndef "CFG" +CFG:=Release +endif + + +# +# Configuration: Debug +# +ifeq "$(CFG)" "Debug" + +OUTDIR:=obj/$(OS)/debug +CONFIG_DEPENDENT_FLAGS:=-O0 -g3 -ggdb + +else + +OUTDIR:=obj/$(OS)/release +CONFIG_DEPENDENT_FLAGS:=-O3 -g1 -ggdb + +endif + +OBJS:=$(addprefix $(OUTDIR)/, $(subst ../../, ,$(SRC:.cpp=.o))) + + +OUTFILE:=$(OUTDIR)/vpc +CFG_INC:=-I../../public -I../../common -I../../public/tier0 \ + -I../../public/tier1 -I../../public/tier2 -I../../public/vstdlib + + +CFLAGS=-D_POSIX -DPOSIX -DGNUC -DNDEBUG $(CONFIG_DEPENDENT_FLAGS) -msse -mmmx -pipe -w -fpermissive -fPIC $(CFG_INC) +ifeq "$(STEAM_BRANCH)" "1" +CFLAGS+= -DSTEAM +endif + + +ifeq "$(OS)" "Darwin" +CFLAGS+=-I$(SDKROOT)/usr/include/malloc +CFLAGS+= -DOSX -D_OSX +CFLAGS+= -arch i386 -fasm-blocks +endif + +ifeq "$(OS)" "Linux" +CFLAGS+= -DPLATFORM_LINUX -D_LINUX -DLINUX +endif + +ifeq ($(CYGWIN),1) +CFLAGS+=-D_CYGWIN -DCYGWIN -D_CYGWIN_WINDOWS_TARGET +endif + +CFLAGS+= -DCOMPILER_GCC + +# the sed magic here adds the dependency file to the list of things that depend on the computed dependency +# set, so if any of them change, the dependencies are re-made +MAKEDEPEND=$(CXX) -M -MT $@ -MM $(CFLAGS) $< | sed -e 's@^\(.*\)\.o:@\1.d \1.o:@' > $(@:.o=.d) +COMPILE=$(CXX) -c $(CFLAGS) -o $@ $< +LINK=$(CXX) $(CONFIG_DEPENDENT_FLAGS) -o "$(OUTFILE)" $(OBJS) -ldl -lpthread + +ifeq "$(OS)" "Darwin" +LINK+=-liconv -framework Foundation +endif + +ifeq "$(OS)" "Darwin" +LINK+= -arch i386 +endif + + +# Build rules +all: $(OUTFILE) ../../../../devtools/bin/vpc$(EXE_POSTFIX) + +../../../../devtools/bin/vpc$(EXE_POSTFIX) : $(OUTFILE) + cp "$(OUTFILE)" ../../../../devtools/bin/vpc$(EXE_POSTFIX) + +$(OUTFILE): Makefile $(OBJS) + $(LINK) + + +# Rebuild this project +rebuild: cleanall all + +# Clean this project +clean: + $(RM) -f $(OUTFILE) + $(RM) -f $(OBJS) + $(RM) -f $(OBJS:.o=.d) + $(RM) -f ../../../../devtools/bin/vpc$(EXE_POSTFIX) + +# Clean this project and all dependencies +cleanall: clean + +# magic rules - tread with caution +-include $(OBJS:.o=.d) + +# Pattern rules +$(OUTDIR)/%.o : %.cpp + -$(MKDIR) -p $(@D) + @$(MAKEDEPEND); + $(COMPILE) + +$(OUTDIR)/tier0/%.o : ../../tier0/%.cpp + -$(MKDIR) -p $(@D) + @$(MAKEDEPEND); + $(COMPILE) + +$(OUTDIR)/tier1/%.o : ../../tier1/%.cpp + -$(MKDIR) -p $(@D) + @$(MAKEDEPEND); + $(COMPILE) + +$(OUTDIR)/vstdlib/%.o : ../../vstdlib/%.cpp + -$(MKDIR) -p $(@D) + @$(MAKEDEPEND); + $(COMPILE) + +$(OUTDIR)/interfaces/%.o : ../../interfaces/%.cpp + if [ ! -d $(@D) ]; then $(MKDIR) $(@D); fi + @$(MAKEDEPEND); + $(COMPILE) + +$(OUTDIR)/utils/binlaunch/%.o : ../binlaunch/%.cpp + if [ ! -d $(@D) ]; then $(MKDIR) $(@D); fi + @$(MAKEDEPEND); + $(COMPILE) + + +# the tags file) seems like more work than it's worth. feel free to fix that up +# if it bugs you. +TAGS: + @find . -name '*.cpp' -print0 | xargs -0 etags --declarations --ignore-indentation + @find . -name '*.h' -print0 | xargs -0 etags --language=c++ --declarations --ignore-indentation --append + @find . -name '*.c' -print0 | xargs -0 etags --declarations --ignore-indentation --append + diff --git a/external/vpc/utils/vpc/baseprojectdatacollector.cpp b/external/vpc/utils/vpc/baseprojectdatacollector.cpp new file mode 100644 index 0000000..c6dcc35 --- /dev/null +++ b/external/vpc/utils/vpc/baseprojectdatacollector.cpp @@ -0,0 +1,381 @@ +//====== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#include "vpc.h" +#include "baseprojectdatacollector.h" +#include "tier1/utlstack.h" +#include "p4lib/ip4.h" + +static const char * const s_rgsAmbiguousPropertyNames[] = +{ + "$CommandLine", +}; + +// ------------------------------------------------------------------------------------------------ // +// CSpecificConfig implementation. +// ------------------------------------------------------------------------------------------------ // + +CSpecificConfig::CSpecificConfig( CSpecificConfig *pParentConfig ) + : m_pParentConfig( pParentConfig ) +{ + m_pKV = new KeyValues( "" ); + m_bFileExcluded = false; + m_bIsSchema = false; + m_bIsDynamic = false; +} + +CSpecificConfig::~CSpecificConfig() +{ + m_pKV->deleteThis(); +} + +const char* CSpecificConfig::GetConfigName() +{ + return m_pKV->GetName(); +} + +const char* CSpecificConfig::GetOption( const char *pOptionName ) +{ + const char *pRet = m_pKV->GetString( pOptionName, NULL ); + if ( pRet ) + return pRet; + + if ( m_pParentConfig ) + return m_pParentConfig->m_pKV->GetString( pOptionName, NULL ); + + return NULL; +} + + +// ------------------------------------------------------------------------------------------------ // +// CFileConfig implementation. +// ------------------------------------------------------------------------------------------------ // + +CFileConfig::~CFileConfig() +{ + Term(); +} + +void CFileConfig::Term() +{ + m_Configurations.PurgeAndDeleteElements(); +} + +const char* CFileConfig::GetName() +{ + return m_Filename.String(); +} + +CSpecificConfig* CFileConfig::GetConfig( const char *pConfigName ) +{ + int i = m_Configurations.Find( pConfigName ); + if ( i == m_Configurations.InvalidIndex() ) + return NULL; + else + return m_Configurations[i]; +} + +CSpecificConfig* CFileConfig::GetOrCreateConfig( const char *pConfigName, CSpecificConfig *pParentConfig ) +{ + int i = m_Configurations.Find( pConfigName ); + if ( i == m_Configurations.InvalidIndex() ) + { + CSpecificConfig *pConfig = new CSpecificConfig( pParentConfig ); + i = m_Configurations.Insert( pConfigName, pConfig ); + } + + return m_Configurations[i]; +} + +bool CFileConfig::IsExcludedFrom( const char *pConfigName ) +{ + CSpecificConfig *pSpecificConfig = GetConfig( pConfigName ); + if ( pSpecificConfig ) + return pSpecificConfig->m_bFileExcluded; + else + return false; +} + +bool CFileConfig::IsDynamicFile( const char *pConfigName ) +{ + CSpecificConfig *pSpecificConfig = GetConfig( pConfigName ); + if ( pSpecificConfig ) + return pSpecificConfig->m_bIsDynamic; + else + return false; +} + + +// ------------------------------------------------------------------------------------------------ // +// CBaseProjectDataCollector implementation. +// ------------------------------------------------------------------------------------------------ // + +CBaseProjectDataCollector::CBaseProjectDataCollector( CRelevantPropertyNames *pNames ) : m_Files( k_eDictCompareTypeFilenames ) +{ + m_RelevantPropertyNames.m_nNames = 0; + m_RelevantPropertyNames.m_pNames = NULL; + + if ( pNames ) + { + m_RelevantPropertyNames = *pNames; + } +} + +CBaseProjectDataCollector::~CBaseProjectDataCollector() +{ + Term(); +} + +void CBaseProjectDataCollector::StartProject() +{ + for (int i = 0; i < m_RelevantPropertyNames.m_nNames; i++) + { + for (int j = 0; j < V_ARRAYSIZE(s_rgsAmbiguousPropertyNames); j++ ) + { + if ( V_stricmp( m_RelevantPropertyNames.m_pNames[i], s_rgsAmbiguousPropertyNames[j] ) == 0 ) + g_pVPC->VPCWarning( "Property name %s may occur in multiple contexts and should be fully qualified", m_RelevantPropertyNames.m_pNames[i] ); + } + } + m_ProjectName = "UNNAMED"; + m_CurFileConfig.Push( &m_BaseConfigData ); + m_CurSpecificConfig.Push( NULL ); +} + +void CBaseProjectDataCollector::EndProject() +{ +} + +void CBaseProjectDataCollector::Term() +{ + m_BaseConfigData.Term(); + m_Files.PurgeAndDeleteElements(); + m_CurFileConfig.Purge(); + m_CurSpecificConfig.Purge(); +} + +CUtlString CBaseProjectDataCollector::GetProjectName() +{ + return m_ProjectName; +} + +void CBaseProjectDataCollector::SetProjectName( const char *pProjectName ) +{ + char tmpBuf[MAX_PATH]; + V_strncpy( tmpBuf, pProjectName, sizeof( tmpBuf ) ); + V_strlower( tmpBuf ); + m_ProjectName = tmpBuf; +} + +// Get a list of all configurations. +void CBaseProjectDataCollector::GetAllConfigurationNames( CUtlVector< CUtlString > &configurationNames ) +{ + configurationNames.Purge(); + for ( int i=m_BaseConfigData.m_Configurations.First(); i != m_BaseConfigData.m_Configurations.InvalidIndex(); i=m_BaseConfigData.m_Configurations.Next(i) ) + { + configurationNames.AddToTail( m_BaseConfigData.m_Configurations.GetElementName(i) ); + } +} + +void CBaseProjectDataCollector::StartConfigurationBlock( const char *pConfigName, bool bFileSpecific ) +{ + CFileConfig *pFileConfig = m_CurFileConfig.Top(); + + // Find or add a new config block. + char sLowerCaseConfigName[MAX_PATH]; + V_strncpy( sLowerCaseConfigName, pConfigName, sizeof( sLowerCaseConfigName ) ); + V_strlower( sLowerCaseConfigName ); + + int index = pFileConfig->m_Configurations.Find( sLowerCaseConfigName ); + if ( index == -1 ) + { + CSpecificConfig *pParent = ( pFileConfig==&m_BaseConfigData ? NULL : m_BaseConfigData.GetOrCreateConfig( sLowerCaseConfigName, NULL ) ); + + CSpecificConfig *pConfig = new CSpecificConfig( pParent ); + pConfig->m_bFileExcluded = false; + pConfig->m_pKV->SetName( sLowerCaseConfigName ); + index = pFileConfig->m_Configurations.Insert( sLowerCaseConfigName, pConfig ); + } + + // Remember what the current config is. + m_CurSpecificConfig.Push( pFileConfig->m_Configurations[index] ); +} + +void CBaseProjectDataCollector::EndConfigurationBlock() +{ + m_CurSpecificConfig.Pop(); +} + +bool CBaseProjectDataCollector::StartPropertySection( configKeyword_e keyword, bool *pbShouldSkip ) +{ + m_CurPropertySection.Push( keyword ); + return true; +} + +void CBaseProjectDataCollector::HandleProperty( const char *pProperty, const char *pCustomScriptData ) +{ + CFmtStr sQualifiedProperty( "%s%s%s", m_CurPropertySection.Count() ? g_pVPC->KeywordToName( m_CurPropertySection.Top() ) : "", + m_CurPropertySection.Count() ? "/" : "", + pProperty ); + bool bSetQualifiedProperty = false; + int i; + for ( i=0; i < m_RelevantPropertyNames.m_nNames; i++ ) + { + if ( V_stricmp( m_RelevantPropertyNames.m_pNames[i], pProperty ) == 0 ) + break; + if ( V_stricmp( m_RelevantPropertyNames.m_pNames[i], sQualifiedProperty.Access() ) == 0 ) + { + bSetQualifiedProperty = true; + break; + } + } + if ( i == m_RelevantPropertyNames.m_nNames ) + { + // not found + return; + } + + if ( pCustomScriptData ) + { + g_pVPC->GetScript().PushScript( "HandleProperty( custom script data )", pCustomScriptData ); + } + + const char *pNextToken = g_pVPC->GetScript().PeekNextToken( false ); + if ( pNextToken && pNextToken[0] != 0 ) + { + // Pass in the previous value so the $base substitution works. + CSpecificConfig *pConfig = m_CurSpecificConfig.Top(); + const char *pBaseString = pConfig->m_pKV->GetString( bSetQualifiedProperty ? sQualifiedProperty.Access() : pProperty ); + char buff[MAX_SYSTOKENCHARS]; + if ( g_pVPC->GetScript().ParsePropertyValue( pBaseString, buff, sizeof( buff ) ) ) + { + pConfig->m_pKV->SetString( bSetQualifiedProperty ? sQualifiedProperty.Access() : pProperty, buff ); + } + } + + if ( pCustomScriptData ) + { + // Restore prior script state + g_pVPC->GetScript().PopScript(); + } +} + +void CBaseProjectDataCollector::EndPropertySection( configKeyword_e keyword ) +{ + configKeyword_e kw; + m_CurPropertySection.Pop( kw ); + Assert( kw == keyword ); +} + +void CBaseProjectDataCollector::StartFolder( const char *pFolderName ) +{ +} +void CBaseProjectDataCollector::EndFolder() +{ +} + +bool CBaseProjectDataCollector::StartFile( const char *pFilename, bool bWarnIfAlreadyExists ) +{ + CFileConfig *pFileConfig = new CFileConfig; + pFileConfig->m_Filename = pFilename; + pFileConfig->m_nInsertOrder = m_Files.Count(); + m_Files.Insert( pFilename, pFileConfig ); + + m_CurFileConfig.Push( pFileConfig ); + m_CurSpecificConfig.Push( NULL ); + + char szFullPath[MAX_PATH]; + + V_GetCurrentDirectory( szFullPath, sizeof( szFullPath ) ); + V_AppendSlash( szFullPath, sizeof( szFullPath ) ); + V_strncat( szFullPath, pFilename, sizeof( szFullPath ) ); + V_RemoveDotSlashes( szFullPath ); + +#if 0 + // Add file to Perforce if it isn't there already + if ( Sys_Exists( szFullPath ) ) + { + if ( m_bP4AutoAdd && p4 && !p4->IsFileInPerforce( szFullPath ) ) + { + p4->OpenFileForAdd( szFullPath ); + VPCStatus( "%s automatically opened for add in default changelist.", szFullPath ); + + } + } + else + { + // g_pVPC->Warning( "%s not found on disk at location specified in project script.", szFullPath ); + } +#endif + + return true; +} + +void CBaseProjectDataCollector::EndFile() +{ + m_CurFileConfig.Pop(); + m_CurSpecificConfig.Pop(); +} + +// This is actually just per-file configuration data. +void CBaseProjectDataCollector::FileExcludedFromBuild( bool bExcluded ) +{ + CSpecificConfig *pConfig = m_CurSpecificConfig.Top(); + pConfig->m_bFileExcluded = bExcluded; +} + +void CBaseProjectDataCollector::FileIsSchema( bool bIsSchema ) +{ + CSpecificConfig *pConfig = m_CurSpecificConfig.Top(); + pConfig->m_bIsSchema = bIsSchema; +} + +void CBaseProjectDataCollector::FileIsDynamic( bool bIsDynamic ) +{ + CSpecificConfig *pConfig = m_CurSpecificConfig.Top(); + pConfig->m_bIsDynamic = bIsDynamic; +} + + +bool CBaseProjectDataCollector::RemoveFile( const char *pFilename ) +{ + bool bRet = false; + int i = m_Files.Find( pFilename ); + if ( i != m_Files.InvalidIndex() ) + { + delete m_Files[i]; + m_Files.RemoveAt( i ); + bRet = true; + } + return bRet; +} + +void CBaseProjectDataCollector::DoStandardVisualStudioReplacements( const char *pStartString, const char *pFullInputFilename, char *pOut, int outLen ) +{ + // Decompose the input filename. + char sInputDir[MAX_PATH], sFileBase[MAX_PATH]; + if ( !V_ExtractFilePath( pFullInputFilename, sInputDir, sizeof( sInputDir ) ) ) + V_strcpy( sInputDir, "." ); + + V_FileBase( pFullInputFilename, sFileBase, sizeof( sFileBase ) ); + + // Handle $(InputPath), $(InputDir), $(InputName) + char *strings[2] = + { + (char*)stackalloc( outLen ), + (char*)stackalloc( outLen ) + }; + + V_StrSubst( pStartString, "$(InputPath)", pFullInputFilename, strings[0], outLen ); + V_StrSubst( strings[0], "$(InputDir)", sInputDir, strings[1], outLen ); + V_StrSubst( strings[1], "$(InputName)", sFileBase, strings[0], outLen ); + V_StrSubst( strings[0], "$(IntDir)", "$(OBJ_DIR)", strings[1], outLen ); + V_StrSubst( strings[1], "$(InputFileName)", pFullInputFilename + V_strlen(sInputDir), strings[0], outLen ); + V_StrSubst( strings[0], "$(ConfigurationName)", "${CONFIGURATION}", strings[1], outLen ); + V_StrSubst( strings[1], "$(Configuration)", "${CONFIGURATION}", strings[0], outLen ); + + V_strncpy( pOut, strings[0], outLen ); + V_FixSlashes( pOut, '/' ); +} diff --git a/external/vpc/utils/vpc/baseprojectdatacollector.h b/external/vpc/utils/vpc/baseprojectdatacollector.h new file mode 100644 index 0000000..543e732 --- /dev/null +++ b/external/vpc/utils/vpc/baseprojectdatacollector.h @@ -0,0 +1,130 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======= +// +// +//============================================================================= + +#ifndef BASEPROJECTDATACOLLECTOR_H +#define BASEPROJECTDATACOLLECTOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/keyvalues.h" +#include "tier1/utlstack.h" + +class CSpecificConfig +{ +public: + CSpecificConfig( CSpecificConfig *pParentConfig ); + ~CSpecificConfig(); + + const char *GetConfigName(); + const char *GetOption( const char *pOptionName ); + +public: + CSpecificConfig *m_pParentConfig; + KeyValues *m_pKV; + bool m_bFileExcluded; // Is the file that holds this config excluded from the build? + bool m_bIsSchema; // Is this a schema file? + bool m_bIsDynamic; // Is this a schema file? +}; + +class CFileConfig +{ +public: + ~CFileConfig(); + + void Term(); + const char *GetName(); + CSpecificConfig *GetConfig( const char *pConfigName ); + CSpecificConfig *GetOrCreateConfig( const char *pConfigName, CSpecificConfig *pParentConfig ); + bool IsExcludedFrom( const char *pConfigName ); + bool IsDynamicFile( const char *pConfigName ); + +public: + CUtlDict< CSpecificConfig*, int > m_Configurations; + CUtlString m_Filename; // "" if this is the config data for the whole project. + int m_nInsertOrder; +}; + +// This just holds the list of property names that we're supposed to scan for. +class CRelevantPropertyNames +{ +public: + const char **m_pNames; + int m_nNames; +}; + +// +// This class is shared by the makefile and SlickEdit project file generator. +// It just collects interesting file properties into KeyValues and then the project file generator +// is responsible for using that data to write out a project file. +// +class CBaseProjectDataCollector : public IBaseProjectGenerator +{ +// IBaseProjectGenerator implementation. +public: + + CBaseProjectDataCollector( CRelevantPropertyNames *pNames ); + ~CBaseProjectDataCollector(); + + // Called before doing anything in a project (in g_pVPC->GetOutputFilename()). + virtual void StartProject(); + virtual void EndProject(); + + // Access the project name. + virtual CUtlString GetProjectName(); + virtual void SetProjectName( const char *pProjectName ); + + // Get a list of all configurations. + virtual void GetAllConfigurationNames( CUtlVector< CUtlString > &configurationNames ); + + // Configuration data is specified in between these calls and inside BeginPropertySection/EndPropertySection. + // If bFileSpecific is set, then the configuration data only applies to the last file added. + virtual void StartConfigurationBlock( const char *pConfigName, bool bFileSpecific ); + virtual void EndConfigurationBlock(); + + // These functions are called when it enters a section like $Compiler, $Linker, etc. + // In between the BeginPropertySection/EndPropertySection, it'll call HandleProperty for any properties inside that section. + // + // If you pass pCustomScriptData to HandleProperty, it won't touch the global parsing state - + // it'll parse the platform filters and property value from pCustomScriptData instead. + virtual bool StartPropertySection( configKeyword_e keyword, bool *pbShouldSkip = NULL ); + virtual void HandleProperty( const char *pProperty, const char *pCustomScriptData = NULL ); + virtual void EndPropertySection( configKeyword_e keyword ); + + // Files go in folders. The generator should maintain a stack of folders as they're added. + virtual void StartFolder( const char *pFolderName ); + virtual void EndFolder(); + + // Add files. Any config blocks/properties between StartFile/EndFile apply to this file only. + // It will only ever have one active file. + virtual bool StartFile( const char *pFilename, bool bWarnIfAlreadyExists ); + virtual void EndFile(); + + // This is actually just per-file configuration data. + virtual void FileExcludedFromBuild( bool bExcluded ); + virtual void FileIsSchema( bool bIsSchema ); + virtual void FileIsDynamic( bool bIsDynamic ); + + // Remove the specified file. + virtual bool RemoveFile( const char *pFilename ); // returns ture if a file was removed + +public: + // This is called in EndProject if bAutoCleanupAfterProject is set. + void Term(); + static void DoStandardVisualStudioReplacements( const char *pStartString, const char *pFullInputFilename, char *pOut, int outLen ); + +public: + CUtlString m_ProjectName; + + CUtlDict< CFileConfig *, int > m_Files; + CFileConfig m_BaseConfigData; + + CUtlStack< CFileConfig* > m_CurFileConfig; // Either m_BaseConfigData or one of the files. + CUtlStack< CSpecificConfig* > m_CurSpecificConfig; // Debug, release? + CUtlStack< configKeyword_e > m_CurPropertySection; + CRelevantPropertyNames m_RelevantPropertyNames; +}; + +#endif // BASEPROJECTDATACOLLECTOR_H diff --git a/external/vpc/utils/vpc/conditionals.cpp b/external/vpc/utils/vpc/conditionals.cpp new file mode 100644 index 0000000..f72376b --- /dev/null +++ b/external/vpc/utils/vpc/conditionals.cpp @@ -0,0 +1,244 @@ +//========= Copyright 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: VPC +// +//=====================================================================================// + +#include "vpc.h" + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CVPC::SetupDefaultConditionals() +{ + // + // PLATFORM Conditionals + // + { + FindOrCreateConditional( "WIN32", true, CONDITIONAL_PLATFORM ); + FindOrCreateConditional( "WIN64", true, CONDITIONAL_PLATFORM ); + + // LINUX is the platform but the VPC scripts use $LINUX and $DEDICATED + // (which we automatically create later). + FindOrCreateConditional( "LINUX32", true, CONDITIONAL_PLATFORM ); + FindOrCreateConditional( "LINUX64", true, CONDITIONAL_PLATFORM ); + + FindOrCreateConditional( "OSX32", true, CONDITIONAL_PLATFORM ); + FindOrCreateConditional( "OSX64", true, CONDITIONAL_PLATFORM ); + + FindOrCreateConditional( "X360", true, CONDITIONAL_PLATFORM ); + FindOrCreateConditional( "PS3", true, CONDITIONAL_PLATFORM ); + } + + // + // CUSTOM conditionals + // + { + // setup default custom conditionals + FindOrCreateConditional( "PROFILE", true, CONDITIONAL_CUSTOM ); + FindOrCreateConditional( "RETAIL", true, CONDITIONAL_CUSTOM ); + FindOrCreateConditional( "CALLCAP", true, CONDITIONAL_CUSTOM ); + FindOrCreateConditional( "FASTCAP", true, CONDITIONAL_CUSTOM ); + FindOrCreateConditional( "CERT", true, CONDITIONAL_CUSTOM ); + FindOrCreateConditional( "MEMTEST", true, CONDITIONAL_CUSTOM ); + FindOrCreateConditional( "NOFPO", true, CONDITIONAL_CUSTOM ); + FindOrCreateConditional( "POSIX", true, CONDITIONAL_CUSTOM ); + FindOrCreateConditional( "LV", true, CONDITIONAL_CUSTOM ); + FindOrCreateConditional( "DEMO", true, CONDITIONAL_CUSTOM ); + FindOrCreateConditional( "NO_STEAM", true, CONDITIONAL_CUSTOM ); + FindOrCreateConditional( "DVDEMU", true, CONDITIONAL_CUSTOM ); + FindOrCreateConditional( "QTDEBUG", true, CONDITIONAL_CUSTOM ); + FindOrCreateConditional( "NO_CEG", true, CONDITIONAL_CUSTOM ); + FindOrCreateConditional( "UPLOAD_CEG", true, CONDITIONAL_CUSTOM ); + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +const char *CVPC::GetTargetPlatformName() +{ + for ( int i = 0; i < m_Conditionals.Count(); i++ ) + { + conditional_t *pConditional = &m_Conditionals[i]; + if ( pConditional->type == CONDITIONAL_PLATFORM && pConditional->m_bDefined ) + { + return pConditional->name.String(); + } + } + + // fatal - should have already been default set + Assert( 0 ); + VPCError( "Unspecified platform." ); + + return NULL; +} + +//----------------------------------------------------------------------------- +// Case Insensitive. Returns true if platform conditional has been marked +// as defined. +//----------------------------------------------------------------------------- +bool CVPC::IsPlatformDefined( const char *pName ) +{ + for ( int i=0; i<m_Conditionals.Count(); i++ ) + { + if ( m_Conditionals[i].type == CONDITIONAL_PLATFORM && !V_stricmp( pName, m_Conditionals[i].name.String() ) ) + { + return m_Conditionals[i].m_bDefined; + } + + } + + return false; +} + +//----------------------------------------------------------------------------- +// Case Insensitive +//----------------------------------------------------------------------------- +conditional_t *CVPC::FindOrCreateConditional( const char *pName, bool bCreate, conditionalType_e type ) +{ + for (int i=0; i<m_Conditionals.Count(); i++) + { + if ( !V_stricmp( pName, m_Conditionals[i].name.String() ) ) + { + // found + return &m_Conditionals[i]; + } + } + + if ( !bCreate ) + { + return NULL; + } + + int index = m_Conditionals.AddToTail(); + + char tempName[256]; + V_strncpy( tempName, pName, sizeof( tempName ) ); + + // primary internal use as lower case, but spewed to user as upper for style consistency + m_Conditionals[index].name = V_strlower( tempName ); + m_Conditionals[index].upperCaseName = V_strupr( tempName ); + m_Conditionals[index].type = type; + + return &m_Conditionals[index]; +} + +void CVPC::SetConditional( const char *pString, bool bSet ) +{ + VPCStatus( false, "Set Conditional: $%s = %s", pString, ( bSet ? "1" : "0" ) ); + + conditional_t *pConditional = FindOrCreateConditional( pString, true, CONDITIONAL_CUSTOM ); + if ( !pConditional ) + { + VPCError( "Failed to find or create $%s conditional", pString ); + } + + pConditional->m_bDefined = bSet; +} + +//----------------------------------------------------------------------------- +// Returns true if string has a conditional of the specified type +//----------------------------------------------------------------------------- +bool CVPC::ConditionHasDefinedType( const char* pCondition, conditionalType_e type ) +{ + char symbol[MAX_SYSTOKENCHARS]; + + for ( int i=0; i<m_Conditionals.Count(); i++ ) + { + if ( m_Conditionals[i].type != type ) + continue; + + sprintf( symbol, "$%s", m_Conditionals[i].name.String() ); + if ( V_stristr( pCondition, symbol ) ) + { + // a define of expected type occurs in the conditional expression + return true; + } + } + + return false; +} + +//----------------------------------------------------------------------------- +// Callback for expression evaluator. +//----------------------------------------------------------------------------- +bool CVPC::ResolveConditionalSymbol( const char *pSymbol ) +{ + int offset = 0; + + if ( !V_stricmp( pSymbol, "$0" ) || !V_stricmp( pSymbol, "0" ) ) + { + return false; + } + else if ( !V_stricmp( pSymbol, "$1" ) || !V_stricmp( pSymbol, "1" ) ) + { + return true; + } + + if ( pSymbol[0] == '$' ) + { + offset = 1; + } + + conditional_t *pConditional = FindOrCreateConditional( (char*)pSymbol+offset, false, CONDITIONAL_NULL ); + if ( pConditional ) + { + // game conditionals only resolve true when they are 'defined' and 'active' + // only one game conditional is expected to be active at a time + if ( pConditional->type == CONDITIONAL_GAME ) + { + if ( !pConditional->m_bDefined ) + { + return false; + } + + return pConditional->m_bGameConditionActive; + } + + // all other type of conditions are gated by their 'defined' state + return pConditional->m_bDefined; + } + + // unknown conditional, defaults to false + return false; +} + +//----------------------------------------------------------------------------- +// Callback for expression evaluator. +//----------------------------------------------------------------------------- +static bool ResolveSymbol( const char *pSymbol ) +{ + return g_pVPC->ResolveConditionalSymbol( pSymbol ); +} + +//----------------------------------------------------------------------------- +// Callback for expression evaluator. +//----------------------------------------------------------------------------- +static void SymbolSyntaxError( const char *pReason ) +{ + // invoke internal syntax error hndling which spews script stack as well + g_pVPC->VPCSyntaxError( pReason ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CVPC::EvaluateConditionalExpression( const char *pExpression ) +{ + char conditionalBuffer[MAX_SYSTOKENCHARS]; + ResolveMacrosInConditional( pExpression, conditionalBuffer, sizeof( conditionalBuffer ) ); + + if ( !conditionalBuffer[0] ) + { + // empty string, same as not having a conditional + return true; + } + + bool bResult = false; + CExpressionEvaluator ExpressionHandler; + bool bValid = ExpressionHandler.Evaluate( bResult, conditionalBuffer, ::ResolveSymbol, ::SymbolSyntaxError ); + if ( !bValid ) + { + g_pVPC->VPCSyntaxError( "VPC Conditional Evaluation Error" ); + } + + return bResult; +} diff --git a/external/vpc/utils/vpc/config_general.cpp b/external/vpc/utils/vpc/config_general.cpp new file mode 100644 index 0000000..90fdaa7 --- /dev/null +++ b/external/vpc/utils/vpc/config_general.cpp @@ -0,0 +1,180 @@ +//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: VPC +// +//=====================================================================================// + +#include "vpc.h" + +bool VPC_Config_General_AdditionalOutputFiles( const char *pPropertyName ) +{ + // Ignore this. We only care about it when looking at dependencies, + // and baseprojectdatacollector will get it in that case. + char buff[MAX_SYSTOKENCHARS]; + ParsePropertyValue( &g_pScriptData, g_pScriptLine, NULL, buff, sizeof( buff ) ); + return true; +} + +bool VPC_Config_General_OutputDirectory( const char *pPropertyName ) +{ + SET_STRING_PROPERTY( pPropertyName, g_spConfig, get_OutputDirectory, put_OutputDirectory ); +} + +bool VPC_Config_General_IntermediateDirectory( const char *pPropertyName ) +{ + SET_STRING_PROPERTY( pPropertyName, g_spConfig, get_IntermediateDirectory, put_IntermediateDirectory ); +} + +bool VPC_Config_General_ExtensionsToDeleteOnClean( const char *pPropertyName ) +{ + SET_STRING_PROPERTY( pPropertyName, g_spConfig, get_DeleteExtensionsOnClean, put_DeleteExtensionsOnClean ); +} + +bool VPC_Config_General_BuildLogFile( const char *pPropertyName ) +{ + SET_STRING_PROPERTY( pPropertyName, g_spConfig, get_BuildLogFile, put_BuildLogFile ); +} + +bool VPC_Config_General_InheritedProjectPropertySheets( const char *pPropertyName ) +{ + SET_STRING_PROPERTY( pPropertyName, g_spConfig, get_InheritedPropertySheets, put_InheritedPropertySheets ); +} + +bool VPC_Config_General_ConfigurationType( const char *pPropertyName ) +{ + char buff[MAX_SYSTOKENCHARS]; + + if ( !ParsePropertyValue( &g_pScriptData, g_pScriptLine, NULL, buff, sizeof( buff ) ) ) + return true; + + ConfigurationTypes option = typeUnknown; + if ( !V_stricmp( buff, "Utility" ) ) + option = typeUnknown; + else if ( !V_stricmp( buff, "Application (.exe)" ) || !V_stricmp( buff, "Title (.xex)" ) ) + option = typeApplication; + else if ( !V_stricmp( buff, "Dynamic Library (.dll)" ) || !V_stricmp( buff, "Dynamic Library (.xex)" ) ) + option = typeDynamicLibrary; + else if ( !V_stricmp( buff, "Static Library (.lib)" ) ) + option = typeStaticLibrary; + else + VPC_SyntaxError(); + + SET_LIST_PROPERTY( pPropertyName, g_spConfig, get_ConfigurationType, put_ConfigurationType, ConfigurationTypes, option ); +} + +bool VPC_Config_General_UseOfMFC( const char *pPropertyName ) +{ + char buff[MAX_SYSTOKENCHARS]; + + if ( !ParsePropertyValue( &g_pScriptData, g_pScriptLine, NULL, buff, sizeof( buff ) ) ) + return true; + + useOfMfc option = useMfcStdWin; + if ( !V_stricmp( buff, "Use Standard Windows Libraries" ) ) + option = useMfcStdWin; + else if ( !V_stricmp( buff, "Use MFC in a Static Library" ) ) + option = useMfcStatic; + else if ( !V_stricmp( buff, "Use MFC in a Shared DLL" ) ) + option = useMfcDynamic; + else + VPC_SyntaxError(); + + SET_LIST_PROPERTY( pPropertyName, g_spConfig, get_useOfMfc, put_useOfMfc, useOfMfc, option ); +} + +bool VPC_Config_General_UseOfATL( const char *pPropertyName ) +{ + char buff[MAX_SYSTOKENCHARS]; + + if ( !ParsePropertyValue( &g_pScriptData, g_pScriptLine, NULL, buff, sizeof( buff ) ) ) + return true; + + useOfATL option = useATLNotSet; + if ( !V_stricmp( buff, "Not Using ATL" ) ) + option = useATLNotSet; + else if ( !V_stricmp( buff, "Static Link to ATL" ) ) + option = useATLStatic; + else if ( !V_stricmp( buff, "Dynamic Link to ATL" ) ) + option = useATLDynamic; + else + VPC_SyntaxError(); + + SET_LIST_PROPERTY( pPropertyName, g_spConfig, get_useOfATL, put_useOfATL, useOfATL, option ); +} + +bool VPC_Config_General_MinimizeCRTUseInATL( const char *pPropertyName ) +{ + SET_BOOL_PROPERTY( pPropertyName, g_spConfig, get_ATLMinimizesCRunTimeLibraryUsage, put_ATLMinimizesCRunTimeLibraryUsage ); +} + +bool VPC_Config_General_CharacterSet( const char *pPropertyName ) +{ + char buff[MAX_SYSTOKENCHARS]; + + if ( !ParsePropertyValue( &g_pScriptData, g_pScriptLine, NULL, buff, sizeof( buff ) ) ) + return true; + + charSet option = charSetNotSet; + if ( !V_stricmp( buff, "Not Set" ) ) + option = charSetNotSet; + else if ( !V_stricmp( buff, "Use Unicode Character Set" ) ) + option = charSetUnicode; + else if ( !V_stricmp( buff, "Use Multi-Byte Character Set" ) ) + option = charSetMBCS; + else + VPC_SyntaxError(); + + SET_LIST_PROPERTY( pPropertyName, g_spConfig, get_CharacterSet, put_CharacterSet, charSet, option ); +} + +bool VPC_Config_General_CommonLanguageRuntimeSupport( const char *pPropertyName ) +{ + VPC_Error( "Setting '%s' Not Implemented", pPropertyName ); + return false; +} + +bool VPC_Config_General_WholeProgramOptimization( const char *pPropertyName ) +{ + char buff[MAX_SYSTOKENCHARS]; + + if ( !ParsePropertyValue( &g_pScriptData, g_pScriptLine, NULL, buff, sizeof( buff ) ) ) + return true; + + WholeProgramOptimizationTypes option = WholeProgramOptimizationNone; + if ( !V_stricmp( buff, "No Whole Program Optimization" ) ) + option = WholeProgramOptimizationNone; + else if ( !V_stricmp( buff, "Use Link Time Code Generation" ) ) + option = WholeProgramOptimizationLinkTimeCodeGen; + else if ( !V_stricmp( buff, "Profile Guided Optimization - Instrument" ) ) + option = WholeProgramOptimizationPGOInstrument; + else if ( !V_stricmp( buff, "Profile Guided Optimization - Optimize" ) ) + option = WholeProgramOptimizationPGOOptimize; + else if ( !V_stricmp( buff, "Profile Guided Optimization - Update" ) ) + option = WholeProgramOptimizationPGOUpdate; + else + VPC_SyntaxError(); + + SET_LIST_PROPERTY( pPropertyName, g_spConfig, get_WholeProgramOptimization, put_WholeProgramOptimization, WholeProgramOptimizationTypes, option ); +} + +extern bool VPC_Config_IgnoreOption( const char *pPropertyName ); + +property_t g_generalProperties[] = +{ + {g_pOption_AdditionalProjectDependencies, VPC_Config_IgnoreOption }, + {g_pOption_AdditionalOutputFiles, VPC_Config_IgnoreOption }, + {"$GameOutputFile", VPC_Config_IgnoreOption }, + {"$OutputDirectory", VPC_Config_General_OutputDirectory }, + {"$IntermediateDirectory", VPC_Config_General_IntermediateDirectory}, + {"$ExtensionsToDeleteOnClean", VPC_Config_General_ExtensionsToDeleteOnClean}, + {"$BuildLogFile", VPC_Config_General_BuildLogFile}, + {"$InheritedProjectPropertySheets", VPC_Config_General_InheritedProjectPropertySheets}, + {"$ConfigurationType", VPC_Config_General_ConfigurationType}, + {"$UseOfMFC", VPC_Config_General_UseOfMFC, PLATFORM_WINDOWS}, + {"$UseOfATL", VPC_Config_General_UseOfATL, PLATFORM_WINDOWS}, + {"$MinimizeCRTUseInATL", VPC_Config_General_MinimizeCRTUseInATL, PLATFORM_WINDOWS}, + {"$CharacterSet", VPC_Config_General_CharacterSet}, + {"$CommonLanguageRuntimeSupport", VPC_Config_General_CommonLanguageRuntimeSupport, PLATFORM_WINDOWS}, + {"$WholeProgramOptimization", VPC_Config_General_WholeProgramOptimization}, + {NULL} +}; diff --git a/external/vpc/utils/vpc/configuration.cpp b/external/vpc/utils/vpc/configuration.cpp new file mode 100644 index 0000000..c822f22 --- /dev/null +++ b/external/vpc/utils/vpc/configuration.cpp @@ -0,0 +1,487 @@ +//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: VPC +// +//=====================================================================================// + +#include "vpc.h" + +static KeywordName_t s_KeywordNameTable[] = +{ + {"$General", KEYWORD_GENERAL}, + {"$Debugging", KEYWORD_DEBUGGING}, + {"$Compiler", KEYWORD_COMPILER}, + {"$SNCCompiler", KEYWORD_PS3_SNCCOMPILER}, + {"$GCCCompiler", KEYWORD_PS3_GCCCOMPILER}, + {"$Librarian", KEYWORD_LIBRARIAN}, + {"$Linker", KEYWORD_LINKER}, + {"$SNCLinker", KEYWORD_PS3_SNCLINKER}, + {"$GCCLinker", KEYWORD_PS3_GCCLINKER}, + {"$ManifestTool", KEYWORD_MANIFEST}, + {"$XMLDocumentGenerator", KEYWORD_XMLDOCGEN}, + {"$BrowseInformation", KEYWORD_BROWSEINFO}, + {"$Resources", KEYWORD_RESOURCES}, + {"$PreBuildEvent", KEYWORD_PREBUILDEVENT}, + {"$PreLinkEvent", KEYWORD_PRELINKEVENT}, + {"$PostBuildEvent", KEYWORD_POSTBUILDEVENT}, + {"$CustomBuildStep", KEYWORD_CUSTOMBUILDSTEP}, + {"$Xbox360ImageConversion", KEYWORD_XBOXIMAGE}, + {"$ConsoleDeployment", KEYWORD_XBOXDEPLOYMENT}, +}; + +const char *CVPC::KeywordToName( configKeyword_e keyword ) +{ + COMPILE_TIME_ASSERT( ARRAYSIZE( s_KeywordNameTable ) == KEYWORD_MAX ); + + if ( keyword == KEYWORD_UNKNOWN ) + { + return "???"; + } + + return s_KeywordNameTable[keyword].m_pName; +} + +configKeyword_e CVPC::NameToKeyword( const char *pKeywordName ) +{ + COMPILE_TIME_ASSERT( ARRAYSIZE( s_KeywordNameTable ) == KEYWORD_MAX ); + + for ( int i = 0; i < ARRAYSIZE( s_KeywordNameTable ); i++ ) + { + if ( !V_stricmp( pKeywordName, s_KeywordNameTable[i].m_pName ) ) + { + return s_KeywordNameTable[i].m_Keyword; + } + } + + return KEYWORD_UNKNOWN; +} + +//----------------------------------------------------------------------------- +// VPC_Config_Keyword +// +//----------------------------------------------------------------------------- +void VPC_Config_Keyword( configKeyword_e keyword, const char *pkeywordToken ) +{ + const char *pToken; + + bool bShouldSkip = false; + if ( !g_pVPC->GetProjectGenerator()->StartPropertySection( keyword, &bShouldSkip ) ) + { + g_pVPC->VPCSyntaxError( "Unsupported Keyword: %s for target platform", pkeywordToken ); + } + + if ( bShouldSkip ) + { + pToken = g_pVPC->GetScript().PeekNextToken( true ); + if ( !pToken || !pToken[0] || V_stricmp( pToken, "{" ) ) + g_pVPC->VPCSyntaxError(); + + g_pVPC->GetScript().SkipBracedSection(); + } + else + { + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] || V_stricmp( pToken, "{" ) ) + g_pVPC->VPCSyntaxError(); + + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] ) + break; + + if ( !V_stricmp( pToken, "}" ) ) + { + // end of section + break; + } + + // Copy off the token name so HandleProperty() doesn't have to (or else the parser will overwrite it on the next token). + char tempTokenName[MAX_PATH]; + V_strncpy( tempTokenName, pToken, sizeof( tempTokenName ) ); + + g_pVPC->GetProjectGenerator()->HandleProperty( tempTokenName ); + } + } + + g_pVPC->GetProjectGenerator()->EndPropertySection( keyword ); +} + +//----------------------------------------------------------------------------- +// VPC_Keyword_Configuration +// +//----------------------------------------------------------------------------- +void VPC_Keyword_Configuration() +{ + const char *pToken; + char szConfigName[MAX_PATH]; + bool bAllowNextLine = false; + int i; + CUtlVector<CUtlString> configs; + char buff[MAX_SYSTOKENCHARS]; + + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( bAllowNextLine ); + if ( !pToken || !pToken[0] ) + break; + + if ( !V_stricmp( pToken, "\\" ) ) + { + bAllowNextLine = true; + continue; + } + else + { + bAllowNextLine = false; + } + + int index = configs.AddToTail(); + configs[index] = pToken; + + // check for another optional config + pToken = g_pVPC->GetScript().PeekNextToken( bAllowNextLine ); + if ( !pToken || !pToken[0] || !V_stricmp( pToken, "{" ) || !V_stricmp( pToken, "}" ) || (pToken[0] == '$') ) + break; + } + + // no configuration specified, use all known + if ( !configs.Count() ) + { + g_pVPC->GetProjectGenerator()->GetAllConfigurationNames( configs ); + if ( !configs.Count() ) + { + g_pVPC->VPCError( "Trying to parse a configuration block and no configs have been defined yet.\n[%s line:%d]", g_pVPC->GetScript().GetName(), g_pVPC->GetScript().GetLine() ); + } + } + + // save parser state + CScriptSource scriptSource = g_pVPC->GetScript().GetCurrentScript(); + + for ( i=0; i<configs.Count(); i++ ) + { + // restore parser state + g_pVPC->GetScript().RestoreScript( scriptSource ); + + V_strncpy( szConfigName, configs[i].String(), sizeof( szConfigName ) ); + + // get access objects + g_pVPC->GetProjectGenerator()->StartConfigurationBlock( szConfigName, false ); + + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] || V_stricmp( pToken, "{" ) ) + { + g_pVPC->VPCSyntaxError(); + } + + while ( 1 ) + { + g_pVPC->GetScript().SkipToValidToken(); + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, buff, sizeof( buff ) ) ) + { + g_pVPC->GetScript().SkipBracedSection(); + continue; + } + + if ( !V_stricmp( buff, "}" ) ) + { + // end of section + break; + } + + configKeyword_e keyword = g_pVPC->NameToKeyword( buff ); + if ( keyword == KEYWORD_UNKNOWN ) + { + g_pVPC->VPCSyntaxError(); + } + else + { + VPC_Config_Keyword( keyword, buff ); + } + } + + g_pVPC->GetProjectGenerator()->EndConfigurationBlock(); + } +} + +//----------------------------------------------------------------------------- +// VPC_Keyword_FileConfiguration +// +//----------------------------------------------------------------------------- +void VPC_Keyword_FileConfiguration() +{ + const char *pToken; + char szConfigName[MAX_PATH]; + bool bAllowNextLine = false; + char buff[MAX_SYSTOKENCHARS]; + CUtlVector< CUtlString > configurationNames; + + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( bAllowNextLine ); + if ( !pToken || !pToken[0] ) + break; + + if ( !V_stricmp( pToken, "\\" ) ) + { + bAllowNextLine = true; + continue; + } + else + { + bAllowNextLine = false; + } + + strcpy( szConfigName, pToken ); + configurationNames.AddToTail( pToken ); + + // check for another optional config + pToken = g_pVPC->GetScript().PeekNextToken( bAllowNextLine ); + if ( !pToken || !pToken[0] || !V_stricmp( pToken, "{" ) || !V_stricmp( pToken, "}" ) || (pToken[0] == '$') ) + break; + } + + // no configuration specified, use all known + if ( configurationNames.Count() == 0 ) + { + g_pVPC->GetProjectGenerator()->GetAllConfigurationNames( configurationNames ); + } + + // save parser state + CScriptSource scriptSource = g_pVPC->GetScript().GetCurrentScript(); + + for ( int i=0; i < configurationNames.Count(); i++ ) + { + // restore parser state + g_pVPC->GetScript().RestoreScript( scriptSource ); + + // Tell the generator we're about to feed it configuration data for this file. + g_pVPC->GetProjectGenerator()->StartConfigurationBlock( configurationNames[i].String(), true ); + + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] || V_stricmp( pToken, "{" ) ) + { + g_pVPC->VPCSyntaxError(); + } + + while ( 1 ) + { + g_pVPC->GetScript().SkipToValidToken(); + + pToken = g_pVPC->GetScript().PeekNextToken( true ); + if ( pToken && pToken[0] && !V_stricmp( pToken, "$ExcludedFromBuild" ) ) + { + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] ) + g_pVPC->VPCSyntaxError(); + + char buff[MAX_SYSTOKENCHARS]; + if ( g_pVPC->GetScript().ParsePropertyValue( NULL, buff, sizeof( buff ) ) ) + { + g_pVPC->GetProjectGenerator()->FileExcludedFromBuild( Sys_StringToBool( buff ) ); + } + + continue; + } + + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, buff, sizeof( buff ) ) ) + { + g_pVPC->GetScript().SkipBracedSection(); + continue; + } + + if ( !V_stricmp( buff, "}" ) ) + { + // end of section + break; + } + + configKeyword_e keyword = g_pVPC->NameToKeyword( buff ); + switch ( keyword ) + { + case KEYWORD_COMPILER: + case KEYWORD_PS3_SNCCOMPILER: + case KEYWORD_PS3_GCCCOMPILER: + case KEYWORD_RESOURCES: + case KEYWORD_CUSTOMBUILDSTEP: + VPC_Config_Keyword( keyword, buff ); + break; + default: + g_pVPC->VPCSyntaxError(); + } + } + + g_pVPC->GetProjectGenerator()->EndConfigurationBlock(); + } +} + + +//----------------------------------------------------------------------------- +// Just advances past config keywords without acting on them +// +//----------------------------------------------------------------------------- +void VPC_Read_Config_Keywords( const char *pkeywordToken ) +{ + const char *pToken; + + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] || V_stricmp( pToken, "{" ) ) + g_pVPC->VPCSyntaxError(); + + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] ) + break; + + if ( !V_stricmp( pToken, "}" ) ) + { + // end of section + break; + } + } +} + + +//----------------------------------------------------------------------------- +// Read a configuration block that applies to an entire folder +// +//----------------------------------------------------------------------------- +void VPC_Keyword_FolderConfiguration( folderConfig_t *pFolderConfig ) +{ + pFolderConfig->Clear(); + + const char *pToken; + char szConfigName[MAX_PATH]; + bool bAllowNextLine = false; + char buff[MAX_SYSTOKENCHARS]; + + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( bAllowNextLine ); + if ( !pToken || !pToken[0] ) + break; + + if ( !V_stricmp( pToken, "\\" ) ) + { + bAllowNextLine = true; + continue; + } + else + { + bAllowNextLine = false; + } + + strcpy( szConfigName, pToken ); + pFolderConfig->vecConfigurationNames.AddToTail( pToken ); + + // check for another optional config + pToken = g_pVPC->GetScript().PeekNextToken( bAllowNextLine ); + if ( !pToken || !pToken[0] || !V_stricmp( pToken, "{" ) || !V_stricmp( pToken, "}" ) || ( pToken[0] == '$' ) ) + break; + } + + // no configuration specified, use all known + if ( pFolderConfig->vecConfigurationNames.Count() == 0 ) + { + g_pVPC->GetProjectGenerator()->GetAllConfigurationNames( pFolderConfig->vecConfigurationNames ); + } + + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] || V_stricmp( pToken, "{" ) ) + { + g_pVPC->VPCSyntaxError(); + } + + // save parser state so we remember where the block is. We'll refer back to it when handlign individual files. + pFolderConfig->scriptSource = g_pVPC->GetScript().GetCurrentScript(); + + // just read past all the tokens. We'll reparse this later, per file. + // it would be cool to parse just once, but leaf code in the project generator expects the parser to be in the right position and parses directly. + while ( 1 ) + { + g_pVPC->GetScript().SkipToValidToken(); + + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, buff, sizeof( buff ) ) ) + { + g_pVPC->GetScript().SkipBracedSection(); + continue; + } + + if ( !V_stricmp( buff, "}" ) ) + { + // end of section + break; + } + + configKeyword_e keyword = g_pVPC->NameToKeyword( buff ); + switch ( keyword ) + { + case KEYWORD_COMPILER: + case KEYWORD_PS3_SNCCOMPILER: + case KEYWORD_PS3_GCCCOMPILER: + case KEYWORD_RESOURCES: + case KEYWORD_CUSTOMBUILDSTEP: + { + VPC_Read_Config_Keywords( buff ); + } + break; + default: + g_pVPC->VPCSyntaxError(); + } + } +} + + +//----------------------------------------------------------------------------- +// Apply a folder-wide configuration to an individual file +// +//----------------------------------------------------------------------------- +void VPC_ApplyFolderConfigurationToFile( const folderConfig_t &folderConfig ) +{ + char buff[MAX_SYSTOKENCHARS]; + g_pVPC->GetScript().PushCurrentScript(); + + for ( int i = 0; i < folderConfig.vecConfigurationNames.Count(); i++ ) + { + g_pVPC->GetScript().RestoreScript( folderConfig.scriptSource ); + + // Tell the generator we're about to feed it configuration data for this file. + g_pVPC->GetProjectGenerator()->StartConfigurationBlock( folderConfig.vecConfigurationNames[i].String(), true ); + + while ( 1 ) + { + g_pVPC->GetScript().SkipToValidToken(); + + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, buff, sizeof( buff ) ) ) + { + g_pVPC->GetScript().SkipBracedSection(); + continue; + } + + if ( !V_stricmp( buff, "}" ) ) + { + // end of section + break; + } + + configKeyword_e keyword = g_pVPC->NameToKeyword( buff ); + switch ( keyword ) + { + case KEYWORD_COMPILER: + case KEYWORD_PS3_SNCCOMPILER: + case KEYWORD_PS3_GCCCOMPILER: + case KEYWORD_RESOURCES: + case KEYWORD_CUSTOMBUILDSTEP: + VPC_Config_Keyword( keyword, buff ); + break; + default: + g_pVPC->VPCSyntaxError(); + } + } + + g_pVPC->GetProjectGenerator()->EndConfigurationBlock(); + } + + g_pVPC->GetScript().PopScript(); +}
\ No newline at end of file diff --git a/external/vpc/utils/vpc/dependencies.cpp b/external/vpc/utils/vpc/dependencies.cpp new file mode 100644 index 0000000..b198741 --- /dev/null +++ b/external/vpc/utils/vpc/dependencies.cpp @@ -0,0 +1,1133 @@ +//====== Copyright 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#include "vpc.h" +#include "dependencies.h" +#include "baseprojectdatacollector.h" +#include "tier0/fasttimer.h" + + +#define VPC_CRC_CACHE_VERSION 3 + +extern char *g_IncludeSeparators[2]; + +static const char *g_pDependencyRelevantProperties[] = +{ + g_pOption_AdditionalProjectDependencies, + g_pOption_AdditionalOutputFiles, + g_pOption_AdditionalIncludeDirectories, + g_pOption_GameOutputFile, + g_pOption_ImportLibrary, + g_pOption_OutputFile, +}; + +static CRelevantPropertyNames g_DependencyRelevantPropertyNames = +{ + g_pDependencyRelevantProperties, + V_ARRAYSIZE( g_pDependencyRelevantProperties ) +}; + + +bool IsSharedLibraryFile( const char *pFilename ) +{ + const char *pExt = V_GetFileExtension( pFilename ); + if ( pExt && ( V_stricmp( pExt, "so" ) == 0 || V_stricmp( pExt, "dylib" ) == 0 || V_stricmp( pExt, "dll" ) == 0 ) ) + { + return true; + } + else + { + return false; + } +} + +bool IsLibraryFile( const char *pFilename ) +{ + const char *pExt = V_GetFileExtension( pFilename ); + if ( IsSharedLibraryFile( pFilename ) || ( pExt && ( V_stricmp( pExt, "lib" ) == 0 || V_stricmp( pExt, "a" ) == 0 ) ) ) + { + return true; + } + else + { + return false; + } +} + +static inline bool IsSourceFile( const char *pFilename ) +{ + const char *pExt = V_GetFileExtension( pFilename ); + + if ( pExt && ( IsCFileExtension( pExt ) || IsHFileExtension( pExt ) || + !V_stricmp( pExt, "rc" ) || !V_stricmp( pExt, "inc" ) ) ) + { + return true; + } + else + { + return false; + } +} + + + +// ------------------------------------------------------------------------------------------------------- // +// CDependency functions. +// ------------------------------------------------------------------------------------------------------- // + +CDependency::CDependency( CProjectDependencyGraph *pDependencyGraph ) : + m_pDependencyGraph( pDependencyGraph ) +{ + m_iDependencyMark = m_pDependencyGraph->m_iDependencyMark - 1; + m_bCheckedIncludes = false; + m_nCacheModificationTime = m_nCacheFileSize = 0; +} + +CDependency::~CDependency() +{ +} + +const char* CDependency::GetName() const +{ + return m_Filename.String(); +} + +bool CDependency::CompareAbsoluteFilename( const char *pAbsPath ) const +{ + return ( V_stricmp( m_Filename.String(), pAbsPath ) == 0 ); +} + +bool CDependency::DependsOn( CDependency *pTest, int flags ) +{ + m_pDependencyGraph->ClearAllDependencyMarks(); + CUtlVector<CUtlBuffer> callTreeOutputStack; + if ( FindDependency_Internal( callTreeOutputStack, pTest, flags, 1 ) ) + { + if ( g_pVPC->IsShowDependencies() ) + { + printf( "-------------------------------------------------------------------------------\n" ); + printf( "%s\n", GetName() ); + int i; + for( i = callTreeOutputStack.Count() - 1; i >= 0; i-- ) + { + printf( ( const char * )callTreeOutputStack[i].Base() ); + } + printf( "-------------------------------------------------------------------------------\n" ); + } + return true; + } + else + { + return false; + } +} + +bool CDependency::FindDependency_Internal( CUtlVector<CUtlBuffer> &callTreeOutputStack, CDependency *pTest, int flags, int depth ) +{ + if ( pTest == this ) + return true; + + // Don't revisit us. + if ( HasBeenMarked() ) + return false; + + Mark(); + + // Don't recurse further? + if ( depth > 1 && !(flags & k_EDependsOnFlagRecurse) ) + return false; + + // Don't go into the children of libs if they don't want. + if ( !(flags & k_EDependsOnFlagTraversePastLibs) && m_Type == k_eDependencyType_Library ) + return false; + + // Go through everything I depend on. If any of those things + for ( int iDepList=0; iDepList < 2; iDepList++ ) + { + if ( iDepList == 1 && !(flags & k_EDependsOnFlagCheckAdditionalDependencies) ) + continue; + + CUtlVector<CDependency*> &depList = (iDepList == 0 ? m_Dependencies : m_AdditionalDependencies); + + for ( int i=0; i < depList.Count(); i++ ) + { + CDependency *pChild = depList[i]; + if ( pChild->FindDependency_Internal( callTreeOutputStack, pTest, flags, depth+1 ) ) + { + if ( g_pVPC->IsShowDependencies() ) + { + char buf[2048]; + V_strncpy( buf, "depends on ", sizeof( buf ) ); + V_strcat( buf, pChild->GetName(), sizeof( buf ) ); + V_strcat( buf, "\n", sizeof( buf ) ); + int n = callTreeOutputStack.AddToTail(); + CUtlBuffer &b = callTreeOutputStack[n]; + b.EnsureCapacity( V_strlen( buf ) + 2 ); + b.PutString( buf ); + b.PutChar( 0 ); + } + return true; + } + } + } + + return false; +} + +void CDependency::Mark() +{ + m_iDependencyMark = m_pDependencyGraph->m_iDependencyMark; +} + +bool CDependency::HasBeenMarked() +{ + return m_iDependencyMark == m_pDependencyGraph->m_iDependencyMark; +} + + +CDependency_Project::CDependency_Project( CProjectDependencyGraph *pDependencyGraph ) + : CDependency( pDependencyGraph ) +{ + m_iProjectIndex = -1; +} + + +void CDependency_Project::StoreProjectParameters( const char *szScriptName ) +{ + m_StoredOutputFilename = g_pVPC->GetOutputFilename(); + V_GetCurrentDirectory( m_szStoredCurrentDirectory, sizeof( m_szStoredCurrentDirectory ) ); + V_strncpy( m_szStoredScriptName, szScriptName, sizeof( m_szStoredScriptName ) ); + m_StoredConditionalsActive.SetSize( g_pVPC->m_Conditionals.Count() ); + + for ( int iConditional=0; iConditional < g_pVPC->m_Conditionals.Count(); iConditional++ ) + { + m_StoredConditionalsActive[iConditional] = g_pVPC->m_Conditionals[iConditional].m_bGameConditionActive; + } +} + + +void CDependency_Project::ExportProjectParameters() +{ + g_pVPC->SetOutputFilename( m_StoredOutputFilename.Get() ); + V_SetCurrentDirectory( m_szStoredCurrentDirectory ); + + if ( m_StoredConditionalsActive.Count() > g_pVPC->m_Conditionals.Count() ) + { + g_pVPC->VPCError( "ExportProjectParameters( %s ) - too many defines stored.", m_szStoredScriptName ); + } + + for ( int iConditional=0; iConditional < g_pVPC->m_Conditionals.Count(); iConditional++ ) + { + g_pVPC->m_Conditionals[iConditional].m_bGameConditionActive = m_StoredConditionalsActive[iConditional]; + } +} + +int CDependency_Project::FindByProjectName( CUtlVector<CDependency_Project*> &projects, const char *pTestName ) +{ + for ( int i=0; i < projects.Count(); i++ ) + { + CDependency_Project *pProject = projects[i]; + + if ( V_stricmp( pProject->m_ProjectName.String(), pTestName ) == 0 ) + return i; + } + + return -1; +} + + +// This is responsible for scanning a project file and pulling out: +// - a list of libraries it uses +// - the $AdditionalIncludeDirectories paths +// - a list of source files it uses +// - the name of the file it generates +class CSingleProjectScanner : public CBaseProjectDataCollector +{ +public: + typedef CBaseProjectDataCollector BaseClass; + + CSingleProjectScanner() : CBaseProjectDataCollector( &g_DependencyRelevantPropertyNames ) + { + m_bInLinker = false; + } + + virtual void EndProject() + { + } + + void ScanProjectFile( CProjectDependencyGraph *pGraph, const char *szScriptName, CDependency_Project *pProject ) + { + // Someday we'll pass this interface down into VPC_ParseProjectScript instead of using the global. + IBaseProjectGenerator *pOldGenerator = g_pVPC->GetProjectGenerator(); + g_pVPC->SetProjectGenerator( this ); + + // This has VPC parse the script and CBaseProjectDataCollector collects all the data into lists of the + // stuff we care about like source files and include paths. + m_ScriptName = szScriptName; + g_pVPC->ParseProjectScript( szScriptName, 0, true, false ); + + int iConfig = m_BaseConfigData.m_Configurations.First(); + if ( iConfig != m_BaseConfigData.m_Configurations.InvalidIndex() ) + { + CSpecificConfig *pConfig = m_BaseConfigData.m_Configurations[iConfig]; + + SetupIncludeDirectories( pConfig, szScriptName ); + SetupFilesList( pGraph, pProject ); + SetupImportLibrary( pGraph, pConfig, szScriptName ); + SetupAdditionalProjectDependencies( pProject, pConfig ); + SetupAdditionalOutputFiles( pProject, pConfig ); + + } + + g_pVPC->SetProjectGenerator( pOldGenerator ); + Term(); + } + + void SetupFilesList( CProjectDependencyGraph *pGraph, CDependency_Project *pProject ) + { + for ( int i=m_Files.First(); i != m_Files.InvalidIndex(); i=m_Files.Next( i ) ) + { + CFileConfig *pFile = m_Files[i]; + + // If this file is excluded from all configs, then exclude it. + if ( pFile->m_Configurations.Count() > 0 ) + { + int nExcluded = 0; + for ( int iSpecific=pFile->m_Configurations.First(); iSpecific != pFile->m_Configurations.InvalidIndex(); iSpecific=pFile->m_Configurations.Next( iSpecific ) ) + { + CSpecificConfig *pTest = pFile->m_Configurations[iSpecific]; + if ( pTest->m_bFileExcluded && !pTest->m_bIsSchema ) + ++nExcluded; + } + if ( nExcluded == (int)m_BaseConfigData.m_Configurations.Count() ) + continue; + } + + + // Make this an absolute path. + const char *pFilename = pFile->GetName(); + char sAbsolutePath[MAX_PATH]; + V_MakeAbsolutePath( sAbsolutePath, sizeof( sAbsolutePath ), pFilename ); + + // Don't bother with source files if we're not building the full dependency set. + if ( !pGraph->m_bFullDependencySet ) + if ( IsSourceFile( sAbsolutePath ) ) + continue; + + // For source files, don't bother with files that don't exist. If we do create entries + // for files that don't exist, then they'll have a "cache file size" + if ( !Sys_Exists( sAbsolutePath ) && IsSourceFile( sAbsolutePath ) ) + continue; + + // Add an entry for this file. + CDependency *pDep = pGraph->FindOrCreateDependency( sAbsolutePath ); + pProject->m_Dependencies.AddToTail( pDep ); + + // Add includes. + if ( pDep->m_Type == k_eDependencyType_SourceFile ) + AddIncludesForFile( pGraph, pDep ); + } + } + + void AddIncludesForFile( CProjectDependencyGraph *pGraph, CDependency *pFile ) + { + // Have we already parsed this file for its includes? + if ( pFile->m_bCheckedIncludes ) + return; + + pFile->m_bCheckedIncludes = true; + + // Setup all the include paths we want to search. + CUtlVector<CUtlString> includeDirs; + char szDir[MAX_PATH]; + if ( !V_ExtractFilePath( pFile->GetName(), szDir, sizeof( szDir ) ) ) + g_pVPC->VPCError( "AddIncludesForFile: V_ExtractFilePath( %s ) failed.", pFile->GetName() ); + + includeDirs.AddToTail( szDir ); + includeDirs.AddMultipleToTail( m_IncludeDirectories.Count(), m_IncludeDirectories.Base() ); + + // Get all the #include directives. + CUtlVector<CUtlString> includes; + GetIncludeFiles( pFile->GetName(), includes ); + ++pGraph->m_nFilesParsedForIncludes; + + // Now see which of them we can open. + for ( int iIncludeFile=0; iIncludeFile < includes.Count(); iIncludeFile++ ) + { + for ( int iIncludeDir=0; iIncludeDir < includeDirs.Count(); iIncludeDir++ ) + { + char szFullName[MAX_PATH]; + V_ComposeFileName( includeDirs[iIncludeDir].String(), includes[iIncludeFile].String(), szFullName, sizeof( szFullName ) ); + + CDependency *pIncludeFile = pGraph->FindDependency( szFullName ); + if ( !pIncludeFile ) + { + if ( !Sys_Exists( szFullName ) ) + continue; + + // Find or add the dependency. + pIncludeFile = pGraph->FindOrCreateDependency( szFullName ); + } + pFile->m_Dependencies.AddToTail( pIncludeFile ); + + // Recurse. + AddIncludesForFile( pGraph, pIncludeFile ); + } + } + } + + bool SeekToIncludeStart( const char* &pSearchPos ) + { + while ( 1 ) + { + ++pSearchPos; + if ( *pSearchPos == 0 || *pSearchPos == '\r' || *pSearchPos == '\n' ) + return false; + + if ( *pSearchPos == '\"' || *pSearchPos == '<' ) + { + ++pSearchPos; + return true; + } + } + } + + bool SeekToIncludeEnd( const char* &pSearchPos ) + { + while ( 1 ) + { + ++pSearchPos; + if ( *pSearchPos == 0 || *pSearchPos == '\r' || *pSearchPos == '\n' ) + return false; + + if ( *pSearchPos == '\"' || *pSearchPos == '>' ) + return true; + } + } + + void GetIncludeFiles( const char *pFilename, CUtlVector<CUtlString> &includes ) + { + char *pFileData; + int ret = Sys_LoadFile( pFilename, (void**)&pFileData, false ); + if ( ret == -1 ) + { + if ( g_pVPC->IsVerbose() ) + { + g_pVPC->VPCWarning( "GetIncludeFiles( %s ) - can't open file (included by project %s).", pFilename, m_ScriptName.String() ); + } + return; + } + + const char *pSearchPos = pFileData; + while ( 1 ) + { + const char *pLookFor = "#include"; + const char *pIncludeStatement = V_strstr( pSearchPos, pLookFor ); + if ( !pIncludeStatement ) + break; + + pSearchPos = pIncludeStatement + V_strlen( pLookFor ); + + if ( !SeekToIncludeStart( pSearchPos ) ) + continue; + const char *pFilenameStart = pSearchPos; + + if ( !SeekToIncludeEnd( pSearchPos ) ) + continue; + const char *pFilenameEnd = pSearchPos; + + if ( (pFilenameEnd - pFilenameStart) > MAX_PATH-10 ) + g_pVPC->VPCError( "Include statement too long in %s.", pFilename ); + + char szIncludeFilename[MAX_PATH], szFixed[MAX_PATH]; + V_strncpy( szIncludeFilename, pFilenameStart, pFilenameEnd - pFilenameStart + 1 ); + + // Fixup double slashes. + V_StrSubst( szIncludeFilename, "\\\\", "\\", szFixed, sizeof( szFixed ) ); + V_FixSlashes( szFixed ); + + includes.AddToTail( szFixed ); + } + + free( pFileData ); + } + + void SetupIncludeDirectories( CSpecificConfig *pConfig, const char *szScriptName ) + { + if ( m_BaseConfigData.m_Configurations.Count() == 0 ) + g_pVPC->VPCError( "No configurations for %s in project %s.", szScriptName, m_ScriptName.String() ); + + const char *pIncludes = pConfig->m_pKV->GetString( g_pOption_AdditionalIncludeDirectories, "" ); + CSplitString relativeIncludeDirs( pIncludes, (const char**)g_IncludeSeparators, V_ARRAYSIZE( g_IncludeSeparators ) ); + + for ( int i=0; i < relativeIncludeDirs.Count(); i++ ) + { + char sAbsolute[MAX_PATH]; + V_MakeAbsolutePath( sAbsolute, sizeof( sAbsolute ), relativeIncludeDirs[i] ); + m_IncludeDirectories.AddToTail( sAbsolute ); + } + } + + void SetupImportLibrary( CProjectDependencyGraph *pGraph, CSpecificConfig *pConfig, const char *szScriptName ) + { + m_ImportLibrary = pConfig->m_pKV->GetString( g_pOption_ImportLibrary, NULL ); + // XXX(JohnS): For projects that define a separate "GameOutputFile" step, that is the final product. This was + // kind of hackily added originally -- the $OutputFile directive was relative to the base directory, + // but some generators (XCode) put all their outputs into a object directory, then use + // $GameOutputFile to *actually* output. + m_LinkerOutputFile = pConfig->m_pKV->GetString( g_pOption_GameOutputFile, NULL ); + if ( !m_LinkerOutputFile.Length() ) + { + m_LinkerOutputFile = pConfig->m_pKV->GetString( g_pOption_OutputFile, NULL ); + } + } + + void SetupAdditionalProjectDependencies( CDependency_Project *pProject, CSpecificConfig *pConfig ) + { + const char *pVal = pConfig->m_pKV->GetString( g_pOption_AdditionalProjectDependencies ); + if ( pVal ) + { + pProject->m_AdditionalProjectDependencies.Purge(); + + CSplitString outStrings ( pVal, ";" ); + for ( int i=0; i < outStrings.Count(); i++ ) + { + char szProjectName[MAX_PATH]; + sprintf( szProjectName, "%s", outStrings[i] ); + + if ( g_pVPC->IsDecorateProject() ) + { + g_pVPC->DecorateProjectName( szProjectName ); + } + pProject->m_AdditionalProjectDependencies.AddToTail( szProjectName ); + } + } + } + + void SetupAdditionalOutputFiles( CDependency_Project *pProject, CSpecificConfig *pConfig ) + { + const char *pVal = pConfig->m_pKV->GetString( g_pOption_AdditionalOutputFiles ); + if ( pVal ) + { + pProject->m_AdditionalOutputFiles.Purge(); + + CSplitString outStrings( pVal, ";" ); + for ( int i=0; i < outStrings.Count(); i++ ) + { + pProject->m_AdditionalOutputFiles.AddToTail( outStrings[i] ); + } + } + } + + virtual const char* GetProjectFileExtension() + { + return "UNUSED"; + } + +protected: + + virtual bool StartPropertySection( configKeyword_e keyword, bool *pbShouldSkip ) + { + m_bInLinker = ( keyword == KEYWORD_LINKER || keyword == KEYWORD_LIBRARIAN ); + return true; + } + + virtual void HandleProperty( const char *pProperty, const char *pCustomScriptData ) + { + // We don't want the $OutputFile property from the $BrowseInformation section. + if ( V_stricmp( pProperty, g_pOption_OutputFile ) == 0 && !m_bInLinker ) + return; + + BaseClass::HandleProperty( pProperty, pCustomScriptData ); + } + + virtual void EndPropertySection( configKeyword_e keyword ) + { + m_bInLinker = false; + } + +public: + // Project include directories. These strings are deleted when the object goes away. + CUtlVector<CUtlString> m_IncludeDirectories; + CUtlString m_ImportLibrary; + CUtlString m_LinkerOutputFile; + CUtlString m_ScriptName; + bool m_bInLinker; +}; + + +CProjectDependencyGraph::CProjectDependencyGraph() +{ + m_iDependencyMark = 0; + m_bFullDependencySet = false; + m_bHasGeneratedDependencies = false; +} + + +void CProjectDependencyGraph::BuildProjectDependencies( int nBuildProjectDepsFlags, CUtlVector< CDependency_Project *> *pPhase1Projects ) +{ + m_bFullDependencySet = ( ( nBuildProjectDepsFlags & BUILDPROJDEPS_FULL_DEPENDENCY_SET ) != 0 ); + m_nFilesParsedForIncludes = 0; + + if ( m_bFullDependencySet ) + { + Log_Msg( LOG_VPC, "\nBuilding full dependency set (all sources and headers)..." ); + } + else + { + Log_Msg( LOG_VPC, "\nBuilding partial dependency set (libs only)..." ); + } + + // Have it iterate ALL projects in the list, with whatever platform conditionals are around. + // When it visits a + CUtlVector<projectIndex_t> projectList; + CUtlVector<int> oldState; + + if ( nBuildProjectDepsFlags & BUILDPROJDEPS_CHECK_ALL_PROJECTS ) + { + // So iterate all projects. + projectList.SetSize( g_pVPC->m_Projects.Count() ); + for ( int i=0; i < g_pVPC->m_Projects.Count(); i++ ) + projectList[i] = i; + + // Simulate /allgames but remember the old state too. + for ( int j=0; j<g_pVPC->m_Conditionals.Count(); j++ ) + { + if ( g_pVPC->m_Conditionals[j].type == CONDITIONAL_GAME ) + { + oldState.AddToTail( (j << 16) + (int)g_pVPC->m_Conditionals[j].m_bDefined ); + g_pVPC->m_Conditionals[j].m_bDefined = true; + } + } + } + else + { + projectList.AddMultipleToTail( g_pVPC->m_TargetProjects.Count(), g_pVPC->m_TargetProjects.Base() ); + } + + // Load any prior results so we don't have to regenerate the whole cache (which can take a couple minutes). + char sCacheFile[MAX_PATH] = {0}; + V_ComposeFileName( g_pVPC->GetSourcePath(), "vpc.cache", sCacheFile, sizeof( sCacheFile ) ); + if ( m_bFullDependencySet ) + { + if ( !LoadCache( sCacheFile ) ) + { + Log_Msg( LOG_VPC, "\n\nNo vpc.cache file found.\nThis will take a minute to generate dependency info from all the sources.\nPut the kleenex down.\nNext time it will have a cache file and be fast.\n\n" ); + } + } + + CFastTimer timer; + timer.Start(); + g_pVPC->IterateTargetProjects( projectList, this ); + timer.End(); + + ResolveAdditionalProjectDependencies( pPhase1Projects ); + + // Restore the old game defines state? + if ( nBuildProjectDepsFlags & BUILDPROJDEPS_CHECK_ALL_PROJECTS ) + { + for ( int i=0; i < oldState.Count(); i++ ) + { + int iDefine = oldState[i] >> 16; + g_pVPC->m_Conditionals[iDefine].m_bDefined = ( (oldState[i] & 1) != 0 ); + } + } + + // Save the expensive work we did into a cache file so it can be used next time. + if ( m_bFullDependencySet ) + { + SaveCache( sCacheFile ); + } + + Log_Msg( LOG_VPC, "\n\n" ); + if ( m_nFilesParsedForIncludes > 0 ) + { + Log_Msg( LOG_VPC, "%d files parsed in %.2f seconds for #includes.\n", m_nFilesParsedForIncludes, timer.GetDuration().GetSeconds() ); + } + + m_bHasGeneratedDependencies = true; +} + +void CProjectDependencyGraph::ResolveAdditionalProjectDependencies( CUtlVector< CDependency_Project *> *pPhase1Projects ) +{ + for ( int iMainProject=0; iMainProject < m_Projects.Count(); iMainProject++ ) + { + CDependency_Project *pMainProject = m_Projects[iMainProject]; + + for ( int i=0; i < pMainProject->m_AdditionalProjectDependencies.Count(); i++ ) + { + const char *pLookingFor = pMainProject->m_AdditionalProjectDependencies[i].String(); + + // Look for this project name among all the projects. + int j; + for ( j=0; j < m_Projects.Count(); j++ ) + { + if ( V_stricmp( m_Projects[j]->m_ProjectName.String(), pLookingFor ) == 0 ) + break; + } + + if ( j == m_Projects.Count() ) + { + //VPCError( "Project %s lists '%s' in its $AdditionalProjectDependencies, but there is no project by that name.", pMainProject->GetName(), pLookingFor ); + continue; + } + + if ( pMainProject->m_AdditionalDependencies.Find( m_Projects[j] ) == pMainProject->m_AdditionalDependencies.InvalidIndex() ) + pMainProject->m_AdditionalDependencies.AddToTail( m_Projects[j] ); + } + + + if ( pPhase1Projects != NULL ) + { + // + // See if there's a project in phase 1 built from the same VPC, and, if so, add it as a dependency. + // This prevents a bunch of race conditions when projects are built in a distributed fashion + // (ala Incredibuild) and the projects step on each other. + // + const char *pFileName = pMainProject->m_Filename.String(); + + int j; + for ( j = 0; j < pPhase1Projects->Count(); j++ ) + { + if ( V_stricmp( (*pPhase1Projects)[j]->m_Filename.String(), pFileName ) == 0) + { + break; + } + } + if ( j == pPhase1Projects->Count() ) + { + continue; + } + + if ( pMainProject->m_AdditionalDependencies.Find( (*pPhase1Projects)[j] ) == pMainProject->m_AdditionalDependencies.InvalidIndex() ) + { + pMainProject->m_AdditionalDependencies.AddToTail( (*pPhase1Projects)[j] ); + } + } + } +} + +bool CProjectDependencyGraph::HasGeneratedDependencies() const +{ + return m_bHasGeneratedDependencies; +} + +bool CProjectDependencyGraph::VisitProject( projectIndex_t iProject, const char *szProjectName ) +{ + // Read in the project. + if ( !Sys_Exists( szProjectName ) ) + { + return false; + } + + // Add another dot for the pacifier. + Log_Msg( LOG_VPC, "." ); + + // Add this project. + CDependency_Project *pProject = new CDependency_Project( this ); + + char szAbsolute[MAX_PATH]; + V_MakeAbsolutePath( szAbsolute, sizeof( szAbsolute ), szProjectName ); + pProject->m_Filename = szAbsolute; + + pProject->m_Type = k_eDependencyType_Project; + pProject->m_iProjectIndex = iProject; + m_Projects.AddToTail( pProject ); + m_AllFiles.Insert( szAbsolute, pProject ); + + // Remember various parameters passed to us so we can regenerate this project without having + // to call VPC_IterateTargetProjects. + pProject->StoreProjectParameters( szProjectName ); + + char sAbsProjectFilename[MAX_PATH]; + V_MakeAbsolutePath( sAbsProjectFilename, sizeof( sAbsProjectFilename ), g_pVPC->GetOutputFilename() ); + pProject->m_ProjectFilename = sAbsProjectFilename; + + // Scan the project file and get all its libs, cpp, and h files. + CSingleProjectScanner scanner; + scanner.ScanProjectFile( this, szAbsolute, pProject ); + pProject->m_IncludeDirectories = scanner.m_IncludeDirectories; + pProject->m_ProjectName = scanner.m_ProjectName; + + // Get a list of all files that depend on this project, starting with the .lib if it generates one. + CUtlVector<CUtlString> outputFiles; + outputFiles = pProject->m_AdditionalOutputFiles; + + // Now note that the import library depends on this project. + // $(ImportLibrary) will be a lib in the case of DLLs that create libs (like tier0). + // $(OutputFile) will be a lib in the case of static libs (like tier1). + const char *pLinkerOutputFile = scanner.m_LinkerOutputFile.String(); + const char *pImportLibrary = scanner.m_ImportLibrary.String(); + if ( !IsLibraryFile( pImportLibrary ) ) + { + pImportLibrary = pLinkerOutputFile; + } + + if ( IsLibraryFile( pImportLibrary ) ) + { + outputFiles.AddToTail( pImportLibrary ); + } + + // The string that we replace $(TargetName) with is the output project filename without the path or extension. + // That'll be something like "tier0_360". + char sTargetNameReplacement[MAX_PATH]; + V_FileBase( pLinkerOutputFile, sTargetNameReplacement, sizeof( sTargetNameReplacement ) ); + + // Now add a CDependency for each file. + for ( int i=0; i < outputFiles.Count(); i++ ) + { + const char *pFilename = outputFiles[i].String(); + + // Replace $(TargetName) and fixup the path. + char sReplaced[MAX_PATH], sAbsImportLibrary[MAX_PATH]; + V_StrSubst( pFilename, "$(TargetName)", sTargetNameReplacement, sReplaced, sizeof( sReplaced ) ); + V_MakeAbsolutePath( sAbsImportLibrary, sizeof( sAbsImportLibrary ), sReplaced ); + + CDependency *pImportLibrary = FindOrCreateDependency( sAbsImportLibrary ); + pImportLibrary->m_Dependencies.AddToTail( pProject ); + } + + return true; +} + + +void CProjectDependencyGraph::GetProjectDependencyTree( projectIndex_t iProject, CUtlVector<projectIndex_t> &dependentProjects, bool bDownwards ) +{ + // First add the project itself. + if ( dependentProjects.Find( iProject ) == dependentProjects.InvalidIndex() ) + dependentProjects.AddToTail( iProject ); + + // Now add anything that depends on it. + for ( int i=0; i < m_Projects.Count(); i++) + { + CDependency_Project *pProject = m_Projects[i]; + + if ( pProject->m_iProjectIndex != iProject ) + continue; + + // Ok, this project/game/platform combo comes from iProject. Now find anything that depends on it. + for ( int iOther=0; iOther < m_Projects.Count(); iOther++ ) + { + CDependency_Project *pOther = m_Projects[iOther]; + + if ( pOther->m_iProjectIndex == iProject ) + continue; + + bool bThereIsADependency; + if ( bDownwards ) + bThereIsADependency = pProject->DependsOn( pOther, k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagCheckAdditionalDependencies | k_EDependsOnFlagRecurse | k_EDependsOnFlagTraversePastLibs ); + else + bThereIsADependency = pOther->DependsOn( pProject, k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagCheckAdditionalDependencies | k_EDependsOnFlagRecurse | k_EDependsOnFlagTraversePastLibs ); + + if ( bThereIsADependency ) + { + if ( dependentProjects.Find( pOther->m_iProjectIndex ) == dependentProjects.InvalidIndex() ) + dependentProjects.AddToTail( pOther->m_iProjectIndex ); + } + } + } +} + + +CDependency* CProjectDependencyGraph::FindDependency( const char *pFilename ) +{ + int i = m_AllFiles.Find( pFilename ); + if ( i == m_AllFiles.InvalidIndex() ) + return NULL; + else + return m_AllFiles[i]; +} + + +CDependency* CProjectDependencyGraph::FindOrCreateDependency( const char *pFilename ) +{ + // Fix up stuff like blah/../blah + char sFixed[MAX_PATH]; + + V_FixupPathName( sFixed, sizeof( sFixed ), pFilename ); + pFilename = sFixed; + + CDependency *pDependency = FindDependency( pFilename ); + if ( pDependency ) + return pDependency; + + // Couldn't find it. Create one. + pDependency = new CDependency( this ); + pDependency->m_Filename = pFilename; + m_AllFiles.Insert( pFilename, pDependency ); + + Sys_FileInfo( pFilename, pDependency->m_nCacheFileSize, pDependency->m_nCacheModificationTime ); + + if ( IsSourceFile( pFilename ) ) + pDependency->m_Type = k_eDependencyType_SourceFile; + else if ( IsLibraryFile( pFilename ) ) + pDependency->m_Type = k_eDependencyType_Library; + else + pDependency->m_Type = k_eDependencyType_Unknown; + + return pDependency; +} + + +void CProjectDependencyGraph::ClearAllDependencyMarks() +{ + if ( m_iDependencyMark == 0xFFFFFFFF ) + { + m_iDependencyMark = 1; + for ( int i=m_AllFiles.First(); i != m_AllFiles.InvalidIndex(); i=m_AllFiles.Next(i) ) + { + m_AllFiles[i]->m_iDependencyMark = 0; + } + } + else + { + // The 99.9999999% chance case. + ++m_iDependencyMark; + } +} + +bool CProjectDependencyGraph::LoadCache( const char *pFilename ) +{ + FILE *fp = fopen( pFilename, "rb" ); + if ( !fp ) + return false; + + int version; + fread( &version, sizeof( version ), 1, fp ); + if ( version != VPC_CRC_CACHE_VERSION ) + { + g_pVPC->VPCWarning( "Invalid dependency cache file version in %s.", pFilename ); + return false; + } + + while ( 1 ) + { + byte bMore; + if ( fread( &bMore, 1, 1, fp ) != 1 || bMore == 0 ) + break; + + CUtlString filename = ReadString( fp ); + CDependency *pDep = FindOrCreateDependency( filename.String() ); + if ( pDep->m_Dependencies.Count() != 0 ) + g_pVPC->VPCError( "Cache loading dependency %s but it already exists!", filename.String() ); + + fread( &pDep->m_nCacheFileSize, sizeof( pDep->m_nCacheFileSize ), 1, fp ); + fread( &pDep->m_nCacheModificationTime, sizeof( pDep->m_nCacheModificationTime ), 1, fp ); + + int nDependencies; + fread( &nDependencies, sizeof( nDependencies ), 1, fp ); + pDep->m_Dependencies.SetSize( nDependencies ); + + for ( int iDependency=0; iDependency < nDependencies; iDependency++ ) + { + CUtlString childDepName = ReadString( fp ); + CDependency *pChildDep = FindOrCreateDependency( childDepName.String() ); + pDep->m_Dependencies[iDependency] = pChildDep; + } + } + + fclose( fp ); + + int nOriginalEntries = m_AllFiles.Count(); + + CheckCacheEntries(); + RemoveDirtyCacheEntries(); + MarkAllCacheEntriesValid(); + + Log_Msg( LOG_VPC, "\n\nLoaded %d valid dependency cache entries (%d were out of date).\n\n", m_AllFiles.Count(), nOriginalEntries-m_AllFiles.Count() ); + return true; +} + +bool CProjectDependencyGraph::SaveCache( const char *pFilename ) +{ + FILE *fp = fopen( pFilename, "wb" ); + if ( !fp ) + return false; + + // Write the version. + int version = VPC_CRC_CACHE_VERSION; + fwrite( &version, sizeof( version ), 1, fp ); + + // Write each file. + for ( int i=m_AllFiles.First(); i != m_AllFiles.InvalidIndex(); i=m_AllFiles.Next( i ) ) + { + CDependency *pDep = m_AllFiles[i]; + + // We only care about source files. + if ( pDep->m_Type != k_eDependencyType_SourceFile ) + continue; + + // Write that there's a file here. + byte bYesThereIsAFileHere = 1; + fwrite( &bYesThereIsAFileHere, 1, 1, fp ); + + WriteString( fp, pDep->m_Filename ); + fwrite( &pDep->m_nCacheFileSize, sizeof( pDep->m_nCacheFileSize ), 1, fp ); + fwrite( &pDep->m_nCacheModificationTime, sizeof( pDep->m_nCacheModificationTime ), 1, fp ); + + int nDependencies = pDep->m_Dependencies.Count(); + fwrite( &nDependencies, sizeof( nDependencies ), 1, fp ); + + for ( int iDependency=0; iDependency < pDep->m_Dependencies.Count(); iDependency++ ) + { + WriteString( fp, pDep->m_Dependencies[iDependency]->m_Filename ); + } + } + + // Write a terminator. + byte bNoMore = 0; + fwrite( &bNoMore, 1, 1, fp ); + + fclose( fp ); + + Sys_CopyToMirror( pFilename ); + + return true; +} + +void CProjectDependencyGraph::WriteString( FILE *fp, CUtlString &utlString ) +{ + const char *pStr = utlString.String(); + int len = V_strlen( pStr ); + fwrite( &len, sizeof( len ), 1, fp ); + fwrite( pStr, len, 1, fp ); +} + +CUtlString CProjectDependencyGraph::ReadString( FILE *fp ) +{ + int len; + fread( &len, sizeof( len ), 1, fp ); + + char *pTemp = new char[len+1]; + fread( pTemp, len, 1, fp ); + pTemp[len] = 0; + + CUtlString ret = pTemp; + delete [] pTemp; + + return ret; +} + + +void CProjectDependencyGraph::CheckCacheEntries() +{ + for ( int i=m_AllFiles.First(); i != m_AllFiles.InvalidIndex(); i=m_AllFiles.Next( i ) ) + { + CDependency *pDep = m_AllFiles[i]; + pDep->m_bCacheDirty = false; + + if ( pDep->m_Type != k_eDependencyType_SourceFile ) + continue; + + int64 fileSize, modTime; + if ( !Sys_FileInfo( pDep->m_Filename.String(), fileSize, modTime ) || + pDep->m_nCacheFileSize != fileSize || + pDep->m_nCacheModificationTime != modTime ) + { + pDep->m_bCacheDirty = true; + } + } +} + +void CProjectDependencyGraph::RemoveDirtyCacheEntries() +{ + // NOTE: This could be waaaay more efficient by pointing files at their parents and removing all the way + // up the chain rather than iterating over and over but this keeps the data structures simple. + bool bAnyDirty = true; + while ( bAnyDirty ) + { + bAnyDirty = false; + + for ( int i=m_AllFiles.First(); i != m_AllFiles.InvalidIndex(); i=m_AllFiles.Next( i ) ) + { + CDependency *pDep = m_AllFiles[i]; + if ( pDep->m_bCacheDirty ) + continue; + + // If any of its children are dirty, then mark this guy as dirty and make sure to remove the child. + for ( int iChild=0; iChild < pDep->m_Dependencies.Count(); iChild++ ) + { + CDependency *pChild = pDep->m_Dependencies[iChild]; + if ( pChild->m_bCacheDirty ) + { + pDep->m_bCacheDirty = true; + bAnyDirty = true; + } + } + } + } + + // Now that any dirty children have flagged their parents as dirty, we can remove them. + int iNext; + for ( int i=m_AllFiles.First(); i != m_AllFiles.InvalidIndex(); i=iNext ) + { + iNext = m_AllFiles.Next( i ); + + if ( m_AllFiles[i]->m_bCacheDirty ) + { + delete m_AllFiles[ i ]; + m_AllFiles.RemoveAt( i ); + } + } +} + + +void CProjectDependencyGraph::MarkAllCacheEntriesValid() +{ + for ( int i=m_AllFiles.First(); i != m_AllFiles.InvalidIndex(); i=m_AllFiles.Next( i ) ) + { + CDependency *pDep = m_AllFiles[i]; + pDep->m_bCheckedIncludes = true; + } +} + + + +// This is called by VPC_IterateTargetProjects and all it does is look forf a +class CGameFilterProjectIterator : public IProjectIterator +{ +public: + virtual bool VisitProject( projectIndex_t iProject, const char *szProjectName ) + { + char szAbsolute[MAX_PATH]; + V_MakeAbsolutePath( szAbsolute, sizeof( szAbsolute ), szProjectName ); + + // Ok, we've got an (absolute) project filename. Search all the projects for one with that name. + bool bAdded = false; + for ( int i=0; i < m_pAllProjectsList->Count(); i++ ) + { + CDependency_Project *pProject = m_pAllProjectsList->Element( i ); + + if ( pProject->CompareAbsoluteFilename( szAbsolute ) ) + { + m_pOutProjectsList->AddToTail( pProject ); + bAdded = true; + break; + } + } + + if ( !bAdded ) + { + g_pVPC->VPCError( "CGameFilterProjectIterator::VisitProject( %s ) - no project found by that name.", szProjectName ); + return false; + } + + return true; + } + +public: + const CUtlVector<CDependency_Project*> *m_pAllProjectsList; + CUtlVector<CDependency_Project*> *m_pOutProjectsList; +}; + +void CProjectDependencyGraph::TranslateProjectIndicesToDependencyProjects( CUtlVector<projectIndex_t> &projectList, CUtlVector<CDependency_Project*> &out ) +{ + CGameFilterProjectIterator iterator; + iterator.m_pAllProjectsList = &m_Projects; + iterator.m_pOutProjectsList = &out; + + g_pVPC->IterateTargetProjects( projectList, &iterator ); +} diff --git a/external/vpc/utils/vpc/dependencies.h b/external/vpc/utils/vpc/dependencies.h new file mode 100644 index 0000000..87ff41d --- /dev/null +++ b/external/vpc/utils/vpc/dependencies.h @@ -0,0 +1,197 @@ +//====== Copyright 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef DEPENDENCIES_H +#define DEPENDENCIES_H +#ifdef _WIN32 +#pragma once +#endif + +enum EDependencyType +{ + k_eDependencyType_SourceFile, // .cpp, .cxx, .h, .hxx + k_eDependencyType_Project, // this is a project file WITHOUT the target-specific extension (.mak, .vpj, .vcproj). + k_eDependencyType_Library, // this is a library file + k_eDependencyType_Unknown // Unrecognized file extension (probably .ico or .rc2 or somesuch). +}; + +class CProjectDependencyGraph; +enum k_EDependsOnFlags +{ + k_EDependsOnFlagCheckNormalDependencies = 0x01, + k_EDependsOnFlagCheckAdditionalDependencies = 0x02, + k_EDependsOnFlagRecurse = 0x04, + k_EDependsOnFlagTraversePastLibs = 0x08 +}; + +// Flags to CProjectDependencyGraph::BuildProjectDependencies. +#define BUILDPROJDEPS_FULL_DEPENDENCY_SET 0x01 // This tells it to build a graph of all projects in the source tree _including_ all games. +#define BUILDPROJDEPS_CHECK_ALL_PROJECTS 0x02 // If this is set, then it reads all .vpc files. + // If this is not set, then it only includes the files from the command line with the "vpc +tier0 *bitmap +client /tf" syntax + +class CDependency +{ +friend class CProjectDependencyGraph; +friend class CSingleProjectScanner; + +public: + CDependency( CProjectDependencyGraph *pDependencyGraph ); + virtual ~CDependency(); + + // Flags are a combination of k_EDependsOnFlags. + bool DependsOn( CDependency *pTest, int flags=k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse ); + const char* GetName() const; + + // Returns true if the absolute filename of this thing (CDependency::m_Filename) matches the absolute path specified. + bool CompareAbsoluteFilename( const char *pAbsPath ) const; + + +private: + bool FindDependency_Internal( CUtlVector<CUtlBuffer> &callTreeOutputStack, CDependency *pTest, int flags, int depth ); + void Mark(); + bool HasBeenMarked(); + +public: + CUtlString m_Filename; // Full paths (slashes are platform dependent). + // This is the VPC filename for a project (use CDependency_Project::m_ProjectFilename for the VCPROJ/VPJ filename). + EDependencyType m_Type; + + // Files that this guy depends on. + CUtlVector<CDependency*> m_Dependencies; + + // Files added by $AdditionalProjectDependencies. This is in a separate list because we don't + // always want DependsOn() to check this. + CUtlVector<CDependency*> m_AdditionalDependencies; + +private: + CProjectDependencyGraph *m_pDependencyGraph; + unsigned int m_iDependencyMark; + bool m_bCheckedIncludes; // Set to true when we have checked all the includes for this. + + // Cache info. + int64 m_nCacheFileSize; + int64 m_nCacheModificationTime; + + // Used by the cache. + bool m_bCacheDirty; // File size or modification time don't match. +}; + + +// This represents a project (.vcproj) file, NOT a project like a projectIndex_t. +// There can be separate .vcproj files (and thus separate CDependency_Project) for each game and platform of a projectIndex_t. +// If m_Type == k_eDependencyType_Project, then you can cast to this. +class CDependency_Project : public CDependency +{ +public: + typedef CDependency BaseClass; + + CDependency_Project( CProjectDependencyGraph *pDependencyGraph ); + + // These functions read/write g_pVPC->GetOutputFilename() and such (all the m_xxStoredXXXX vars below). + void StoreProjectParameters( const char *szScriptName ); + void ExportProjectParameters(); + + // Does a case-insensitive string compare against m_ProjectName. + // Returns -1 if not found or the index into projects. + static int FindByProjectName( CUtlVector<CDependency_Project*> &projects, const char *pTestName ); + + +public: + // Include directories for the project. + CUtlVector<CUtlString> m_IncludeDirectories; + + // Straight out of the $AdditionalProjectDependencies key (split on semicolons). + CUtlVector<CUtlString> m_AdditionalProjectDependencies; + + // Straight out of the $AdditionalOutputFiles key (split on semicolons). + CUtlVector<CUtlString> m_AdditionalOutputFiles; + + CUtlString m_ProjectName; // This comes from the $Project key in the .vpc file. + CUtlString m_ProjectFilename; // Absolute path to the VCPROJ file (g_pVPC->GetOutputFilename() - see CDependency::m_Filename for the VPC filename). + CUtlString m_ImportLibrary; + + // Note that there can be multiple CDependency_Projects with the same m_iProjectIndex. + projectIndex_t m_iProjectIndex; + + // This is used by /p4sln. It uses this to call into VPC_ParseProjectScript. These are the values of g_pVPC->GetOutputFilename(), szScriptName, + // and the defines at the time of building this project. + CUtlString m_StoredOutputFilename; + char m_szStoredScriptName[MAX_PATH]; + char m_szStoredCurrentDirectory[MAX_PATH]; + CUtlVector<bool> m_StoredConditionalsActive; +}; + + +// This class builds a graph of all dependencies, starting at the projects. +class CProjectDependencyGraph : public IProjectIterator +{ +friend class CDependency; + +public: + CProjectDependencyGraph(); + + // This is the main function to generate dependencies. + // nBuildProjectDepsFlags is a combination of BUILDPROJDEPS_ flags. + void BuildProjectDependencies( int nBuildProjectDepsFlags, CUtlVector< CDependency_Project *> *pPhase1Projects = NULL ); + + bool HasGeneratedDependencies() const; + + CDependency* FindDependency( const char *pFilename ); + CDependency* FindOrCreateDependency( const char *pFilename ); + + // Look for all projects (that we've scanned during BuildProjectDependencies) that depend on the specified project. + // If bDownwards is true, then it adds iProject and all projects that _it depends on_. + // If bDownwards is false, then it adds iProject and all projects that _depend on it_. + void GetProjectDependencyTree( projectIndex_t iProject, CUtlVector<projectIndex_t> &dependentProjects, bool bDownwards ); + + // This solves the central mismatch between the way VPC references projects and the way the CDependency stuff does. + // + // - VPC uses projectIndex_t, but a single projectIndex_t can turn into multiple games (server_tf, server_episodic, etc) in VPC_IterateTargetProjects. + // - The dependency code has a separate CDependency_Project for each game. + // + // This takes a bunch of project indices (usually m_targetProjects, which comes from the command line's "+this -that *theother" syntax), + // which are game-agnostic, and based on what games were specified on the command line, it builds the list of CDependency_Project*s. + void TranslateProjectIndicesToDependencyProjects( CUtlVector<projectIndex_t> &projectList, CUtlVector<CDependency_Project*> &out ); + +// IProjectIterator overrides. +protected: + virtual bool VisitProject( projectIndex_t iProject, const char *szProjectName ); + + +private: + void ClearAllDependencyMarks(); + + // Functions for the vpc.cache file management. + bool LoadCache( const char *pFilename ); + bool SaveCache( const char *pFilename ); + void WriteString( FILE *fp, CUtlString &utlString ); + CUtlString ReadString( FILE *fp ); + + void CheckCacheEntries(); + void RemoveDirtyCacheEntries(); + void MarkAllCacheEntriesValid(); + + void ResolveAdditionalProjectDependencies( CUtlVector< CDependency_Project *> *pPhase1Projects = NULL ); + +public: + // Projects and everything they depend on. + CUtlVector<CDependency_Project*> m_Projects; + CUtlDict<CDependency*,int> m_AllFiles; // All files go in here. They should never be duplicated. These are indexed by the full filename (except .lib files, which have that stripped off). + bool m_bFullDependencySet; // See bFullDepedencySet passed into BuildProjectDependencies. + int m_nFilesParsedForIncludes; + +private: + // Used when sweeping the dependency graph to prevent looping around forever. + unsigned int m_iDependencyMark; + bool m_bHasGeneratedDependencies; // Set to true after finishing BuildProjectDependencies. +}; + + +bool IsLibraryFile( const char *pFilename ); +bool IsSharedLibraryFile( const char *pFilename ); + + +#endif // DEPENDENCIES_H diff --git a/external/vpc/utils/vpc/exprsimplifier.cpp b/external/vpc/utils/vpc/exprsimplifier.cpp new file mode 100644 index 0000000..d7cce05 --- /dev/null +++ b/external/vpc/utils/vpc/exprsimplifier.cpp @@ -0,0 +1,324 @@ +//===== Copyright (c) 1996-2006, Valve Corporation, All rights reserved. ======// +// +// Purpose: ExprSimplifier builds a binary tree from an infix expression (in the +// form of a character array). +// +//===========================================================================// +#include "vpc.h" + +static ExprTree mExprTree; // Tree representation of the expression +static char mCurToken; // Current token read from the input expression +static const char *mExpression; // Array of the expression characters +static int mCurPosition; // Current position in the input expression +static char mIdentifier[MAX_IDENTIFIER_LEN]; // Stores the identifier string +static GetSymbolProc_t g_pGetSymbolProc; + +//----------------------------------------------------------------------------- +// Sets mCurToken to the next token in the input string. Skips all whitespace. +//----------------------------------------------------------------------------- +static char GetNextToken( void ) +{ + // while whitespace, Increment CurrentPosition + while( mExpression[mCurPosition] == ' ' ) + ++mCurPosition; + + // CurrentToken = Expression[CurrentPosition] + mCurToken = mExpression[mCurPosition++]; + + return mCurToken; +} + + +//----------------------------------------------------------------------------- +// Utility funcs +//----------------------------------------------------------------------------- +static void FreeNode( ExprNode *node ) +{ + delete node; +} + +static ExprNode *AllocateNode( void ) +{ + return new ExprNode; +} + +static void FreeTree( ExprTree& node ) +{ + if(!node) + return; + + FreeTree(node->left); + FreeTree(node->right); + FreeNode(node); + node = 0; +} + +static bool IsConditional( const char token ) +{ + char nextchar = ' '; + if ( token == OR_OP || token == AND_OP ) + { + nextchar = mExpression[mCurPosition++]; + if ( (token & nextchar) == token ) + { + return true; + } + else + g_pVPC->VPCSyntaxError( "Bad expression token: %c %c", token, nextchar ); + } + + return false; +} + +static bool IsNotOp( const char token ) +{ + if ( token == NOT_OP ) + return true; + else + return false; +} + +static bool IsIdentifierOrConstant( const char token ) +{ + bool success = false; + if ( token == '$' ) + { + // store the entire identifier + int i = 0; + mIdentifier[i++] = token; + while( (isalnum( mExpression[mCurPosition] ) || mExpression[mCurPosition] == '_') && i < MAX_IDENTIFIER_LEN ) + { + mIdentifier[i] = mExpression[mCurPosition]; + ++mCurPosition; + ++i; + } + + if ( i < MAX_IDENTIFIER_LEN - 1 ) + { + mIdentifier[i] = '\0'; + success = true; + } + } + else + { + if ( isdigit( token ) ) + { + int i = 0; + mIdentifier[i++] = token; + while( isdigit( mExpression[mCurPosition] ) && ( i < MAX_IDENTIFIER_LEN ) ) + { + mIdentifier[i] = mExpression[mCurPosition]; + ++mCurPosition; + ++i; + } + if ( i < MAX_IDENTIFIER_LEN - 1 ) + { + mIdentifier[i] = '\0'; + success = true; + } + } + } + + return success; +} + +static void MakeExprNode( ExprTree &tree, char token, Kind kind, ExprTree left, ExprTree right ) +{ + tree = AllocateNode(); + tree->left = left; + tree->right = right; + tree->kind = kind; + + switch ( kind ) + { + case CONDITIONAL: + tree->data.cond = token; + break; + case LITERAL: + if ( isdigit( mIdentifier[0] ) ) + { + tree->data.value = atoi( mIdentifier ) != 0; + } + else + { + tree->data.value = g_pGetSymbolProc( mIdentifier ); + } + break; + case NOT: + break; + default: + g_pVPC->VPCError( "Error in ExpTree" ); + } +} + +static void MakeExpression( ExprTree& tree ); +//----------------------------------------------------------------------------- +// Makes a factor :: { <expression> } | <identifier>. +//----------------------------------------------------------------------------- +static void MakeFactor( ExprTree& tree ) +{ + if ( mCurToken == '(' ) + { + // Get the next token + GetNextToken(); + + // Make an expression, setting Tree to point to it + MakeExpression( tree ); + } + else if ( IsIdentifierOrConstant( mCurToken ) ) + { + // Make a literal node, set Tree to point to it, set left/right children to NULL. + MakeExprNode( tree, mCurToken, LITERAL, NULL, NULL ); + } + else if ( IsNotOp( mCurToken ) ) + { + // do nothing + return; + } + else + { + // This must be a bad token + g_pVPC->VPCSyntaxError( "Bad expression token: %c", mCurToken ); + } + + // Get the next token + GetNextToken(); +} + + +//----------------------------------------------------------------------------- +// Makes a term :: <factor> { <not> }. +//----------------------------------------------------------------------------- +static void MakeTerm( ExprTree& tree ) +{ + // Make a factor, setting Tree to point to it + MakeFactor( tree ); + + // while the next token is ! + while( IsNotOp( mCurToken ) ) + { + // Make an operator node, setting left child to Tree and right to NULL. (Tree points to new node) + MakeExprNode( tree, mCurToken, NOT, tree, NULL ); + + // Get the next token. + GetNextToken(); + + // Make a factor, setting the right child of Tree to point to it. + MakeFactor(tree->right); + } +} + + +//----------------------------------------------------------------------------- +// Makes a complete expression :: <term> { <cond> <term> }. +//----------------------------------------------------------------------------- +static void MakeExpression( ExprTree& tree ) +{ + // Make a term, setting Tree to point to it + MakeTerm( tree ); + + // while the next token is a conditional + while ( IsConditional( mCurToken ) ) + { + // Make a conditional node, setting left child to Tree and right to NULL. (Tree points to new node) + MakeExprNode( tree, mCurToken, CONDITIONAL, tree, NULL ); + + // Get the next token. + GetNextToken(); + + // Make a term, setting the right child of Tree to point to it. + MakeTerm( tree->right ); + } +} + + +//----------------------------------------------------------------------------- +// returns true for success, false for failure +//----------------------------------------------------------------------------- +static bool BuildExpression( void ) +{ + // Get the first token, and build the tree. + GetNextToken(); + + MakeExpression( mExprTree ); + return true; +} + +//----------------------------------------------------------------------------- +// returns the value of the node after resolving all children +//----------------------------------------------------------------------------- +static bool SimplifyNode( ExprTree& node ) +{ + if( !node ) + return false; + + // Simplify the left and right children of this node + bool leftVal = SimplifyNode(node->left); + bool rightVal = SimplifyNode(node->right); + + // Simplify this node + switch( node->kind ) + { + case NOT: + // the child of '!' is always to the right + node->data.value = !rightVal; + break; + + case CONDITIONAL: + if ( node->data.cond == AND_OP ) + { + node->data.value = leftVal && rightVal; + } + else // OR_OP + { + node->data.value = leftVal || rightVal; + } + break; + + default: // LITERAL + break; + } + + // This node has beed resolved + node->kind = LITERAL; + return node->data.value; +} + + +//----------------------------------------------------------------------------- +// Interface to solve a conditional expression. Returns false on failure. +//----------------------------------------------------------------------------- +bool EvaluateExpression( bool &result, const char *InfixExpression, GetSymbolProc_t pGetSymbolProc ) +{ + if ( !InfixExpression ) + return false; + + g_pGetSymbolProc = pGetSymbolProc; + + bool success = false; + mExpression = InfixExpression; + mExprTree = 0; + mCurPosition = 0; + + // Building the expression tree will fail on bad syntax + if ( BuildExpression() ) + { + success = true; + result = SimplifyNode( mExprTree ); + } + + FreeTree( mExprTree ); + return success; +} + + + + + + + + + + + + diff --git a/external/vpc/utils/vpc/generatordefinition.cpp b/external/vpc/utils/vpc/generatordefinition.cpp new file mode 100644 index 0000000..474cf3c --- /dev/null +++ b/external/vpc/utils/vpc/generatordefinition.cpp @@ -0,0 +1,353 @@ +//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============// +// +// +//=====================================================================================// + +#include "vpc.h" + +CGeneratorDefinition::CGeneratorDefinition() +{ + Clear(); +} + +void CGeneratorDefinition::Clear() +{ + m_pPropertyNames = NULL; + m_ScriptName.Clear(); + m_NameString.Clear(); + m_VersionString.Clear(); + m_Tools.Purge(); + m_ScriptCRC = 0; +} + +void CGeneratorDefinition::IterateAttributesKey( ToolProperty_t *pProperty, KeyValues *pAttributesKV ) +{ + const char *pAttributeName = pAttributesKV->GetName(); + const char *pValue = pAttributesKV->GetString( "" ); + + //Msg( "Attribute name: %s\n", pAttributeName ); + + if ( !V_stricmp( pAttributeName, "type" ) ) + { + if ( !V_stricmp( pValue, "bool" ) || !V_stricmp( pValue, "boolean" ) ) + { + pProperty->m_nType = PT_BOOLEAN; + } + else if ( !V_stricmp( pValue, "string" ) ) + { + pProperty->m_nType = PT_STRING; + } + else if ( !V_stricmp( pValue, "list" ) ) + { + pProperty->m_nType = PT_LIST; + } + else if ( !V_stricmp( pValue, "int" ) || !V_stricmp( pValue, "integer" ) ) + { + pProperty->m_nType = PT_INTEGER; + } + else if ( !V_stricmp( pValue, "ignore" ) || !V_stricmp( pValue, "none" ) ) + { + pProperty->m_nType = PT_IGNORE; + } + else if ( !V_stricmp( pValue, "deprecated" ) || !V_stricmp( pValue, "donotuse" ) ) + { + pProperty->m_nType = PT_DEPRECATED; + } + else + { + // unknown + g_pVPC->VPCError( "Unknown type '%s' in '%s'", pValue, pProperty->m_ParseString.Get() ); + } + } + else if ( !V_stricmp( pAttributeName, "alias" ) ) + { + pProperty->m_AliasString = pValue; + } + else if ( !V_stricmp( pAttributeName, "legacy" ) ) + { + pProperty->m_LegacyString = pValue; + } + else if ( !V_stricmp( pAttributeName, "InvertOutput" ) ) + { + pProperty->m_bInvertOutput = pAttributesKV->GetBool(); + } + else if ( !V_stricmp( pAttributeName, "output" ) ) + { + pProperty->m_OutputString = pValue; + } + else if ( !V_stricmp( pAttributeName, "fixslashes" ) ) + { + pProperty->m_bFixSlashes = pAttributesKV->GetBool(); + } + else if ( !V_stricmp( pAttributeName, "PreferSemicolonNoComma" ) ) + { + pProperty->m_bPreferSemicolonNoComma = pAttributesKV->GetBool(); + } + else if ( !V_stricmp( pAttributeName, "PreferSemicolonNoSpace" ) ) + { + pProperty->m_bPreferSemicolonNoSpace = pAttributesKV->GetBool(); + } + else if ( !V_stricmp( pAttributeName, "AppendSlash" ) ) + { + pProperty->m_bAppendSlash = pAttributesKV->GetBool(); + } + else if ( !V_stricmp( pAttributeName, "GlobalProperty" ) ) + { + pProperty->m_bEmitAsGlobalProperty = pAttributesKV->GetBool(); + } + else if ( !V_stricmp( pAttributeName, "ordinals" ) ) + { + if ( pProperty->m_nType == PT_UNKNOWN ) + { + pProperty->m_nType = PT_LIST; + } + + for ( KeyValues *pKV = pAttributesKV->GetFirstSubKey(); pKV; pKV = pKV->GetNextKey() ) + { + const char *pOrdinalName = pKV->GetName(); + const char *pOrdinalValue = pKV->GetString(); + if ( !pOrdinalValue[0] ) + { + g_pVPC->VPCError( "Unknown ordinal value for name '%s' in '%s'", pOrdinalName, pProperty->m_ParseString.Get() ); + } + + int iIndex = pProperty->m_Ordinals.AddToTail(); + pProperty->m_Ordinals[iIndex].m_ParseString = pOrdinalName; + pProperty->m_Ordinals[iIndex].m_ValueString = pOrdinalValue; + } + } + else + { + g_pVPC->VPCError( "Unknown attribute '%s' in '%s'", pAttributeName, pProperty->m_ParseString.Get() ); + } +} + +void CGeneratorDefinition::IteratePropertyKey( GeneratorTool_t *pTool, KeyValues *pPropertyKV ) +{ + //Msg( "Property Key name: %s\n", pPropertyKV->GetName() ); + + int iIndex = pTool->m_Properties.AddToTail(); + ToolProperty_t *pProperty = &pTool->m_Properties[iIndex]; + + pProperty->m_ParseString = pPropertyKV->GetName(); + + KeyValues *pKV = pPropertyKV->GetFirstSubKey(); + if ( !pKV ) + return; + + for ( ;pKV; pKV = pKV->GetNextKey() ) + { + IterateAttributesKey( pProperty, pKV ); + } +} + +void CGeneratorDefinition::IterateToolKey( KeyValues *pToolKV ) +{ + //Msg( "Tool Key name: %s\n", pToolKV->GetName() ); + + // find or create + GeneratorTool_t *pTool = NULL; + for ( int i = 0; i < m_Tools.Count(); i++ ) + { + if ( !V_stricmp( pToolKV->GetName(), m_Tools[i].m_ParseString ) ) + { + pTool = &m_Tools[i]; + break; + } + } + if ( !pTool ) + { + int iIndex = m_Tools.AddToTail(); + pTool = &m_Tools[iIndex]; + } + + pTool->m_ParseString = pToolKV->GetName(); + + KeyValues *pKV = pToolKV->GetFirstSubKey(); + if ( !pKV ) + return; + + for ( ;pKV; pKV = pKV->GetNextKey() ) + { + IteratePropertyKey( pTool, pKV ); + } +} + +void CGeneratorDefinition::AssignIdentifiers() +{ + CUtlVector< bool > usedPropertyNames; + int nTotalPropertyNames = 0; + while ( m_pPropertyNames[nTotalPropertyNames].m_nPropertyId >= 0 ) + { + nTotalPropertyNames++; + } + usedPropertyNames.SetCount( nTotalPropertyNames ); + + // assign property identifiers + for ( int i = 0; i < m_Tools.Count(); i++ ) + { + GeneratorTool_t *pTool = &m_Tools[i]; + + // assign the tool keyword + configKeyword_e keyword = g_pVPC->NameToKeyword( pTool->m_ParseString.Get() ); + if ( keyword == KEYWORD_UNKNOWN ) + { + g_pVPC->VPCError( "Unknown Tool Keyword '%s' in '%s'", pTool->m_ParseString.Get(), m_ScriptName.Get() ); + } + pTool->m_nKeyword = keyword; + + const char *pPrefix = m_NameString.Get(); + const char *pToolName = pTool->m_ParseString.Get(); + if ( pToolName[0] == '$' ) + { + pToolName++; + } + + for ( int j = 0; j < pTool->m_Properties.Count(); j++ ) + { + ToolProperty_t *pProperty = &pTool->m_Properties[j]; + + if ( pProperty->m_nType == PT_IGNORE || pProperty->m_nType == PT_DEPRECATED ) + { + continue; + } + + const char *pPropertyName = pProperty->m_AliasString.Get(); + if ( !pPropertyName[0] ) + { + pPropertyName = pProperty->m_ParseString.Get(); + } + if ( pPropertyName[0] == '$' ) + { + pPropertyName++; + } + + CUtlString prefixString = CFmtStr( "%s_%s", pPrefix, pToolName ); + + bool bFound = false; + for ( int k = 0; k < nTotalPropertyNames && !bFound; k++ ) + { + if ( !V_stricmp( prefixString.Get(), m_pPropertyNames[k].m_pPrefixName ) ) + { + if ( !V_stricmp( pPropertyName, m_pPropertyNames[k].m_pPropertyName ) ) + { + pProperty->m_nPropertyId = m_pPropertyNames[k].m_nPropertyId; + bFound = true; + usedPropertyNames[k] = true; + } + } + } + if ( !bFound ) + { + g_pVPC->VPCError( "Could not find PROPERTYNAME( %s, %s ) for %s", prefixString.Get(), pPropertyName, m_ScriptName.Get() ); + } + } + } + + if ( g_pVPC->IsVerbose() ) + { + for ( int i = 0; i < usedPropertyNames.Count(); i++ ) + { + if ( !usedPropertyNames[i] ) + { + g_pVPC->VPCWarning( "Unused PROPERTYNAME( %s, %s ) in %s", m_pPropertyNames[i].m_pPrefixName, m_pPropertyNames[i].m_pPropertyName, m_ScriptName.Get() ); + } + } + } +} + +void CGeneratorDefinition::LoadDefinition( const char *pDefnitionName, PropertyName_t *pPropertyNames ) +{ + Clear(); + + m_pPropertyNames = pPropertyNames; + g_pVPC->GetScript().PushScript( CFmtStr( "vpc_scripts\\definitions\\%s", pDefnitionName ) ); + + // project definitions are KV format + KeyValues *pScriptKV = new KeyValues( g_pVPC->GetScript().GetName() ); + + pScriptKV->LoadFromBuffer( g_pVPC->GetScript().GetName(), g_pVPC->GetScript().GetData() ); + + m_ScriptName = g_pVPC->GetScript().GetName(); + m_ScriptCRC = CRC32_ProcessSingleBuffer( g_pVPC->GetScript().GetData(), strlen( g_pVPC->GetScript().GetData() ) ); + + m_NameString = pScriptKV->GetName(); + + KeyValues *pKV = pScriptKV->GetFirstSubKey(); + for ( ;pKV; pKV = pKV->GetNextKey() ) + { + const char *pKeyName = pKV->GetName(); + if ( !V_stricmp( pKeyName, "version" ) ) + { + m_VersionString = pKV->GetString(); + } + else + { + IterateToolKey( pKV ); + } + } + + g_pVPC->GetScript().PopScript(); + pScriptKV->deleteThis(); + + g_pVPC->VPCStatus( false, "Definition: '%s' Version: %s", m_NameString.Get(), m_VersionString.Get() ); + + AssignIdentifiers(); +} + +const char *CGeneratorDefinition::GetScriptName( CRC32_t *pCRC ) +{ + if ( pCRC ) + { + *pCRC = m_ScriptCRC; + } + + return m_ScriptName.Get(); +} + +ToolProperty_t *CGeneratorDefinition::GetProperty( configKeyword_e keyword, const char *pPropertyName ) +{ + for ( int i = 0; i < m_Tools.Count(); i++ ) + { + GeneratorTool_t *pTool = &m_Tools[i]; + if ( pTool->m_nKeyword != keyword ) + continue; + + for ( int j = 0; j < pTool->m_Properties.Count(); j++ ) + { + ToolProperty_t *pToolProperty = &pTool->m_Properties[j]; + if ( !V_stricmp( pToolProperty->m_ParseString.Get(), pPropertyName ) ) + { + // found + return pToolProperty; + } + if ( !pToolProperty->m_LegacyString.IsEmpty() && !V_stricmp( pToolProperty->m_LegacyString.Get(), pPropertyName ) ) + { + // found + return pToolProperty; + } + } + } + + // not found + return NULL; +} + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/external/vpc/utils/vpc/generatordefinition.h b/external/vpc/utils/vpc/generatordefinition.h new file mode 100644 index 0000000..839b8ec --- /dev/null +++ b/external/vpc/utils/vpc/generatordefinition.h @@ -0,0 +1,130 @@ +//===================== Copyright (c) Valve Corporation. All Rights Reserved. ====================== +// +// +//================================================================================================== + +#ifndef GENERATORDEFINITION_H +#define GENERATORDEFINITION_H +#ifdef _WIN32 +#pragma once +#endif + +struct PropertyName_t +{ + int m_nPropertyId; + const char *m_pPrefixName; + const char *m_pPropertyName; +}; + +enum configKeyword_e +{ + KEYWORD_UNKNOWN = -1, + KEYWORD_GENERAL, + KEYWORD_DEBUGGING, + KEYWORD_COMPILER, + KEYWORD_PS3_SNCCOMPILER, + KEYWORD_PS3_GCCCOMPILER, + KEYWORD_LIBRARIAN, + KEYWORD_LINKER, + KEYWORD_PS3_SNCLINKER, + KEYWORD_PS3_GCCLINKER, + KEYWORD_MANIFEST, + KEYWORD_XMLDOCGEN, + KEYWORD_BROWSEINFO, + KEYWORD_RESOURCES, + KEYWORD_PREBUILDEVENT, + KEYWORD_PRELINKEVENT, + KEYWORD_POSTBUILDEVENT, + KEYWORD_CUSTOMBUILDSTEP, + KEYWORD_XBOXIMAGE, + KEYWORD_XBOXDEPLOYMENT, + KEYWORD_MAX, +}; + +enum PropertyType_e +{ + PT_UNKNOWN = 0, + PT_BOOLEAN, + PT_STRING, + PT_INTEGER, + PT_LIST, + PT_IGNORE, + PT_DEPRECATED, +}; + +struct PropertyOrdinal_t +{ + CUtlString m_ParseString; + CUtlString m_ValueString; +}; + +struct ToolProperty_t +{ + ToolProperty_t() + { + m_nPropertyId = -1; + m_nType = PT_UNKNOWN; + m_bFixSlashes = false; + m_bEmitAsGlobalProperty = false; + m_bInvertOutput = false; + m_bAppendSlash = false; + m_bPreferSemicolonNoComma = false; + m_bPreferSemicolonNoSpace = false; + } + + CUtlString m_ParseString; + CUtlString m_AliasString; + CUtlString m_LegacyString; + CUtlString m_OutputString; + CUtlVector< PropertyOrdinal_t > m_Ordinals; + + int m_nPropertyId; + PropertyType_e m_nType; + bool m_bFixSlashes; + bool m_bEmitAsGlobalProperty; + bool m_bInvertOutput; + bool m_bAppendSlash; + bool m_bPreferSemicolonNoComma; + bool m_bPreferSemicolonNoSpace; +}; + +struct GeneratorTool_t +{ + GeneratorTool_t() + { + m_nKeyword = KEYWORD_UNKNOWN; + } + + CUtlString m_ParseString; + CUtlVector< ToolProperty_t > m_Properties; + configKeyword_e m_nKeyword; +}; + +class CGeneratorDefinition +{ +public: + CGeneratorDefinition(); + + void LoadDefinition( const char *pDefinitionName, PropertyName_t *pPropertyNames ); + ToolProperty_t *GetProperty( configKeyword_e keyword, const char *pPropertyName ); + + const char *GetScriptName( CRC32_t *pCRC ); + +private: + void AssignIdentifiers(); + void IterateToolKey( KeyValues *pToolKV ); + void IteratePropertyKey( GeneratorTool_t *pTool, KeyValues *pPropertyKV ); + void IterateAttributesKey( ToolProperty_t *pProperty, KeyValues *pAttributesKV ); + void Clear(); + + PropertyName_t *m_pPropertyNames; + CUtlString m_ScriptName; + CUtlString m_NameString; + CUtlString m_VersionString; + CUtlVector< GeneratorTool_t > m_Tools; + CRC32_t m_ScriptCRC; +}; + + + +#endif // GENERATORDEFINITION_H diff --git a/external/vpc/utils/vpc/groupscript.cpp b/external/vpc/utils/vpc/groupscript.cpp new file mode 100644 index 0000000..2593352 --- /dev/null +++ b/external/vpc/utils/vpc/groupscript.cpp @@ -0,0 +1,369 @@ +//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: VPC +// +//=====================================================================================// + +#include "vpc.h" + +// This keyword works in both group and project scripts +extern void VPC_SharedKeyword_Conditional(); + + +//----------------------------------------------------------------------------- +// VPC_Group_FindOrCreateProject +// +//----------------------------------------------------------------------------- +projectIndex_t VPC_Group_FindOrCreateProject( const char *pName, bool bCreate ) +{ + for ( int i = 0; i < g_pVPC->m_Projects.Count(); i++ ) + { + if ( !V_stricmp( pName, g_pVPC->m_Projects[i].name.String() ) ) + { + return i; + } + } + + if ( !bCreate ) + return INVALID_INDEX; + + int index = g_pVPC->m_Projects.AddToTail(); + g_pVPC->m_Projects[index].name = pName; + + return index; +} + +//----------------------------------------------------------------------------- +// VPC_Group_CreateGroup +// +//----------------------------------------------------------------------------- +groupIndex_t VPC_Group_CreateGroup() +{ + groupIndex_t index = g_pVPC->m_Groups.AddToTail(); + return index; +} + +//----------------------------------------------------------------------------- +// VPC_Group_FindOrCreateGroupTag +// +//----------------------------------------------------------------------------- +groupTagIndex_t VPC_Group_FindOrCreateGroupTag( const char *pName, bool bCreate ) +{ + for (int i=0; i<g_pVPC->m_GroupTags.Count(); i++) + { + if ( !V_stricmp( pName, g_pVPC->m_GroupTags[i].name.String() ) ) + return i; + } + + if ( !bCreate ) + return INVALID_INDEX; + + groupTagIndex_t index = g_pVPC->m_GroupTags.AddToTail(); + g_pVPC->m_GroupTags[index].name = pName; + + return index; +} + +//----------------------------------------------------------------------------- +// VPC_GroupKeyword_Games +// +//----------------------------------------------------------------------------- +void VPC_GroupKeyword_Games() +{ + const char *pToken; + + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] || V_stricmp( pToken, "{" ) ) + g_pVPC->VPCSyntaxError(); + + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] ) + g_pVPC->VPCSyntaxError(); + + if ( !V_stricmp( pToken, "}" ) ) + { + // end of section + break; + } + else + { + g_pVPC->FindOrCreateConditional( pToken, true, CONDITIONAL_GAME ); + } + } +} + +//----------------------------------------------------------------------------- +// VPC_GroupKeyword_Group +// +//----------------------------------------------------------------------------- +void VPC_GroupKeyword_Group() +{ + const char *pToken; + bool bFirstToken = true; + groupIndex_t groupIndex; + projectIndex_t projectIndex; + + groupIndex = VPC_Group_CreateGroup(); + + while ( 1 ) + { + if ( !bFirstToken ) + { + pToken = g_pVPC->GetScript().PeekNextToken( false ); + if ( !pToken || !pToken[0] ) + break; + } + else + { + bFirstToken = false; + } + + pToken = g_pVPC->GetScript().GetToken( false ); + if ( !pToken || !pToken[0] ) + g_pVPC->VPCSyntaxError(); + + // specified tag now builds this group + groupTagIndex_t groupTagIndex = VPC_Group_FindOrCreateGroupTag( pToken, true ); + g_pVPC->m_GroupTags[groupTagIndex].groups.AddToTail( groupIndex ); + } + + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] || V_stricmp( pToken, "{" ) ) + g_pVPC->VPCSyntaxError(); + + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] ) + g_pVPC->VPCSyntaxError(); + + if ( !V_stricmp( pToken, "}" ) ) + { + // end of section + break; + } + else + { + projectIndex = VPC_Group_FindOrCreateProject( pToken, false ); + if ( projectIndex != INVALID_INDEX ) + { + int index = g_pVPC->m_Groups[groupIndex].projects.AddToTail(); + g_pVPC->m_Groups[groupIndex].projects[index] = projectIndex; + } + else + { + g_pVPC->VPCWarning( "No Project %s defined, ignoring.", pToken ); + continue; + } + } + } +} + +//----------------------------------------------------------------------------- +// VPC_GroupKeyword_Project +// +//----------------------------------------------------------------------------- +void VPC_GroupKeyword_Project() +{ + const char *pToken; + + pToken = g_pVPC->GetScript().GetToken( false ); + if ( !pToken || !pToken[0] ) + g_pVPC->VPCSyntaxError(); + + if ( VPC_Group_FindOrCreateProject( pToken, false ) != INVALID_INDEX ) + { + // already defined + g_pVPC->VPCWarning( "project %s already defined", pToken ); + g_pVPC->VPCSyntaxError(); + } + + projectIndex_t projectIndex = VPC_Group_FindOrCreateProject( pToken, true ); + + // create a default group that contains just this project + groupIndex_t groupIndex = VPC_Group_CreateGroup(); + g_pVPC->m_Groups[groupIndex].projects.AddToTail( projectIndex ); + + // create a default tag that matches the project name + groupTagIndex_t groupTagIndex = VPC_Group_FindOrCreateGroupTag( pToken, true ); + g_pVPC->m_GroupTags[groupTagIndex].groups.AddToTail( groupIndex ); + g_pVPC->m_GroupTags[groupTagIndex].bSameAsProject = true; + + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] || V_stricmp( pToken, "{" ) ) + g_pVPC->VPCSyntaxError(); + + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] ) + g_pVPC->VPCSyntaxError(); + + if ( !V_stricmp( pToken, "}" ) ) + { + // end of section + break; + } + else + { + scriptIndex_t scriptIndex = g_pVPC->m_Projects[projectIndex].scripts.AddToTail(); + g_pVPC->m_Projects[projectIndex].scripts[scriptIndex].name = pToken; + + pToken = g_pVPC->GetScript().PeekNextToken( false ); + if ( pToken && pToken[0] ) + { + pToken = g_pVPC->GetScript().GetToken( false ); + g_pVPC->m_Projects[projectIndex].scripts[scriptIndex].m_condition = pToken; + } + } + } +} + + +//----------------------------------------------------------------------------- +// VPC_ParseGroupScript +// +//----------------------------------------------------------------------------- +void VPC_ParseGroupScript( const char *pScriptName ) +{ + char szScriptName[MAX_PATH]; + const char *pToken; + + // caller's pointer is aliased + strcpy( szScriptName, pScriptName ); + V_FixSlashes( szScriptName ); + + g_pVPC->VPCStatus( false, "Parsing: %s", szScriptName ); + g_pVPC->GetScript().PushScript( szScriptName ); + + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] ) + { + // end of file + break; + } + + if ( !V_stricmp( pToken, "$include" ) ) + { + pToken = g_pVPC->GetScript().GetToken( false ); + if ( !pToken || !pToken[0] ) + { + // end of file + g_pVPC->VPCSyntaxError(); + } + + // recurse into and run + VPC_ParseGroupScript( pToken ); + } + else if ( !V_stricmp( pToken, "$games" ) ) + { + VPC_GroupKeyword_Games(); + } + else if ( !V_stricmp( pToken, "$group" ) ) + { + VPC_GroupKeyword_Group(); + } + else if ( !V_stricmp( pToken, "$project" ) ) + { + VPC_GroupKeyword_Project(); + } + else if ( !V_stricmp( pToken, "$Conditional" ) ) + { + VPC_SharedKeyword_Conditional(); + } + else + { + g_pVPC->VPCSyntaxError(); + } + } + + g_pVPC->GetScript().PopScript(); +} + +//----------------------------------------------------------------------------- +// Collect all the +XXX, remove all the -XXX +// This allows removal to be the expected trumping operation. +//----------------------------------------------------------------------------- +void CVPC::GenerateBuildSet( CProjectDependencyGraph &dependencyGraph ) +{ + // process +XXX commands + for ( int i = 0; i < m_BuildCommands.Count(); i++ ) + { + const char *pCommand = m_BuildCommands[i].Get(); + if ( pCommand[0] == '-' ) + continue; + + groupTagIndex_t groupTagIndex = VPC_Group_FindOrCreateGroupTag( pCommand+1, false ); + if ( groupTagIndex == INVALID_INDEX ) + continue; + groupTag_t *pGroupTag = &g_pVPC->m_GroupTags[groupTagIndex]; + + CUtlVector<projectIndex_t> projectsToAdd; + + for ( int j=0; j<pGroupTag->groups.Count(); j++ ) + { + group_t *pGroup = &g_pVPC->m_Groups[pGroupTag->groups[j]]; + for ( int k=0; k<pGroup->projects.Count(); k++ ) + { + projectIndex_t targetProject = pGroup->projects[k]; + if ( pCommand[0] == '*' ) + { + // Add this project and any projects that depend on it. + if ( !dependencyGraph.HasGeneratedDependencies() ) + dependencyGraph.BuildProjectDependencies( BUILDPROJDEPS_CHECK_ALL_PROJECTS, m_pPhase1Projects ); + + dependencyGraph.GetProjectDependencyTree( targetProject, projectsToAdd, false ); + } + else if ( pCommand[0] == '@' ) + { + // Add this project and any projects that it depends on. + if ( !dependencyGraph.HasGeneratedDependencies() ) + dependencyGraph.BuildProjectDependencies( BUILDPROJDEPS_CHECK_ALL_PROJECTS, m_pPhase1Projects ); + + dependencyGraph.GetProjectDependencyTree( targetProject, projectsToAdd, true ); + } + else + { + projectsToAdd.AddToTail( targetProject ); + } + } + } + + // Add all the projects in the list. + for ( int j=0; j < projectsToAdd.Count(); j++ ) + { + projectIndex_t targetProject = projectsToAdd[j]; + + if ( g_pVPC->m_TargetProjects.Find( targetProject ) == -1 ) + { + g_pVPC->m_TargetProjects.AddToTail( targetProject ); + } + } + } + + // process -XXX commands, explicitly remove tagge projects + for ( int i=0; i<m_BuildCommands.Count(); i++ ) + { + const char *pCommand = m_BuildCommands[i].Get(); + if ( pCommand[0] == '+' || pCommand[0] == '*' || pCommand[0] == '@' ) + continue; + + groupTagIndex_t groupTagIndex = VPC_Group_FindOrCreateGroupTag( pCommand+1, false ); + if ( groupTagIndex == INVALID_INDEX ) + continue; + groupTag_t *pGroupTag = &g_pVPC->m_GroupTags[groupTagIndex]; + + for ( int j=0; j<pGroupTag->groups.Count(); j++ ) + { + group_t *pGroup = &g_pVPC->m_Groups[pGroupTag->groups[j]]; + for ( int k=0; k<pGroup->projects.Count(); k++ ) + { + g_pVPC->m_TargetProjects.FindAndRemove( pGroup->projects[k] ); + } + } + } +} diff --git a/external/vpc/utils/vpc/ibaseprojectgenerator.h b/external/vpc/utils/vpc/ibaseprojectgenerator.h new file mode 100644 index 0000000..f267d7a --- /dev/null +++ b/external/vpc/utils/vpc/ibaseprojectgenerator.h @@ -0,0 +1,75 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef IBASEPROJECTGENERATOR_H +#define IBASEPROJECTGENERATOR_H +#ifdef _WIN32 +#pragma once +#endif + + +// +// Usage: +// +// StartProject +// StartConfigurationBlock +// StartPropertySection +// HandleProperty... +// EndPropertySection +// EndConfigurationBlock +// +// AddFile... +// [inside each file it can do another configuration block as above] +// [also, files can be put in folders with StartFolder/AddFolder] +// EndProject +// +class IBaseProjectGenerator +{ +public: + // What file extension does this use? (vcproj, mak, vpj). + virtual const char* GetProjectFileExtension() = 0; + + // Called before doing anything in a project (in g_pVPC->GetOutputFilename()). + virtual void StartProject() = 0; + virtual void EndProject() = 0; + + // Access the project name. + virtual CUtlString GetProjectName() = 0; + virtual void SetProjectName( const char *pProjectName ) = 0; + + // Get a list of all configurations. + virtual void GetAllConfigurationNames( CUtlVector< CUtlString > &configurationNames ) = 0; + + // Configuration data is specified in between these calls and inside BeginPropertySection/EndPropertySection. + // If bFileSpecific is set, then the configuration data only applies to the last file added. + virtual void StartConfigurationBlock( const char *pConfigName, bool bFileSpecific ) = 0; + virtual void EndConfigurationBlock() = 0; + + // These functions are called when it enters a section like $Compiler, $Linker, etc. + // In between the BeginPropertySection/EndPropertySection, it'll call HandleProperty for any properties inside that section. + virtual bool StartPropertySection( configKeyword_e keyword, bool *pbShouldSkip = NULL ) = 0; + virtual void HandleProperty( const char *pProperty, const char *pCustomScriptData=NULL ) = 0; + virtual void EndPropertySection( configKeyword_e keyword ) = 0; + + // Files go in folders. The generator should maintain a stack of folders as they're added. + virtual void StartFolder( const char *pFolderName ) = 0; + virtual void EndFolder() = 0; + + // Add files. Any config blocks/properties between StartFile/EndFile apply to this file only. + // It will only ever have one active file. + virtual bool StartFile( const char *pFilename, bool bWarnIfAlreadyExists ) = 0; + virtual void EndFile() = 0; + + // This is actually just per-file configuration data. + virtual void FileExcludedFromBuild( bool bExcluded ) = 0; + virtual void FileIsSchema( bool bIsSchema ) = 0; // Mark the current file as schema. + virtual void FileIsDynamic( bool bIsDynamic ) = 0; // Mark the current file as dynamic. + + // Remove the specified file. return true if success + virtual bool RemoveFile( const char *pFilename ) = 0; +}; + +#endif // IBASEPROJECTGENERATOR_H diff --git a/external/vpc/utils/vpc/ibasesolutiongenerator.h b/external/vpc/utils/vpc/ibasesolutiongenerator.h new file mode 100644 index 0000000..cb566cf --- /dev/null +++ b/external/vpc/utils/vpc/ibasesolutiongenerator.h @@ -0,0 +1,24 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef IBASESOLUTIONGENERATOR_H +#define IBASESOLUTIONGENERATOR_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "dependencies.h" + + +class IBaseSolutionGenerator +{ +public: + virtual void GenerateSolutionFile( const char *pSolutionFilename, CUtlVector<CDependency_Project*> &projects ) = 0; +}; + + +#endif // IBASESOLUTIONGENERATOR_H diff --git a/external/vpc/utils/vpc/macros.cpp b/external/vpc/utils/vpc/macros.cpp new file mode 100644 index 0000000..feb518d --- /dev/null +++ b/external/vpc/utils/vpc/macros.cpp @@ -0,0 +1,167 @@ +//========= Copyright 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: VPC +// +//=====================================================================================// + +#include "vpc.h" + +void CVPC::SetMacro( const char *pName, const char *pValue, bool bSetupDefineInProjectFile ) +{ + // Setup the macro. + VPCStatus( false, "Set Macro: $%s = %s", pName, pValue ); + + macro_t *pMacro = FindOrCreateMacro( pName, true, pValue ); + pMacro->m_bSetupDefineInProjectFile = bSetupDefineInProjectFile; + pMacro->m_bInternalCreatedMacro = true; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +macro_t *CVPC::FindOrCreateMacro( const char *pName, bool bCreate, const char *pValue ) +{ + for ( int i = 0; i < m_Macros.Count(); i++ ) + { + if ( !V_stricmp( pName, m_Macros[i].name.String() ) ) + { + if ( pValue && V_stricmp( pValue, m_Macros[i].value.String() ) ) + { + // update + m_Macros[i].value = pValue; + } + + return &m_Macros[i]; + } + } + + if ( !bCreate ) + { + return NULL; + } + + int index = m_Macros.AddToTail(); + m_Macros[index].name = pName; + m_Macros[index].value = pValue; + + return &m_Macros[index]; +} + +int CVPC::GetMacrosMarkedForCompilerDefines( CUtlVector< macro_t* > ¯oDefines ) +{ + macroDefines.Purge(); + + for ( int i = 0; i < m_Macros.Count(); i++ ) + { + if ( m_Macros[i].m_bSetupDefineInProjectFile ) + { + macroDefines.AddToTail( &m_Macros[i] ); + } + } + + return macroDefines.Count(); +} + +static int __cdecl SortMacrosByNameLength( const macro_t *lhs, const macro_t *rhs ) +{ + if ( lhs->name.Length() < rhs->name.Length() ) + return 1; + if ( lhs->name.Length() > rhs->name.Length() ) + return -1; + return 0; +} + +void CVPC::ResolveMacrosInStringInternal( char const *pString, char *pOutBuff, int outBuffSize, bool bStringIsConditional ) +{ + char macroName[MAX_SYSTOKENCHARS]; + char buffer1[MAX_SYSTOKENCHARS]; + char buffer2[MAX_SYSTOKENCHARS]; + int i; + + // ensure a "greedy" match by sorting longest to shortest + m_Macros.Sort( SortMacrosByNameLength ); + + // iterate and resolve user macros until all macros resolved + strcpy( buffer1, pString ); + bool bDone; + do + { + bDone = true; + bool bDoReplace = true; + for ( i=0; i<m_Macros.Count(); i++ ) + { + sprintf( macroName, "$%s", m_Macros[i].name.String() ); + const char *pFound = V_stristr( buffer1, macroName ); + if ( pFound && bStringIsConditional ) + { + // if expanding a conditional, give conditionals priority over macros + // i.e. if the string we've found begins both a macro and conditional, + // don't expand the macro + for ( int j = 0; j < m_Conditionals.Count(); j++ ) + { + if ( V_stristr( pFound+1, m_Conditionals[j].name.String() ) == pFound+1 ) + { + bDoReplace = false; + // the warning is super chatty about $LINUX and $POSIX + if ( V_stricmp( macroName, "$LINUX" ) && V_stricmp( macroName, "$POSIX" ) ) + g_pVPC->VPCWarning( "Not replacing macro %s with its value (%s) in conditional %s\n", macroName, m_Macros[i].value.Length() ? m_Macros[i].value.String() : "null" , pFound ); + break; + } + } + } + + // can't use ispunct as '|' and '&' are punctuation, but we dont want to warn on them + if ( pFound && bStringIsConditional && bDoReplace && + ( isalnum( pFound[strlen(macroName)] ) || pFound[strlen(macroName)] == '_' ) ) + g_pVPC->VPCWarning( "Replacing macro %s with its value (%s) in conditional %s\n", macroName, m_Macros[i].value.Length() ? m_Macros[i].value.String() : "null" , pFound ); + + if ( bDoReplace && Sys_ReplaceString( buffer1, macroName, m_Macros[i].value.String(), buffer2, sizeof( buffer2 ) ) ) + { + bDone = false; + } + strcpy( buffer1, buffer2 ); + } + } + while ( !bDone ); + + int len = strlen( buffer1 ); + if ( outBuffSize < len ) + len = outBuffSize; + memcpy( pOutBuff, buffer1, len ); + pOutBuff[len] = '\0'; +} + +void CVPC::ResolveMacrosInString( char const *pString, char *pOutBuff, int outBuffSize ) +{ + ResolveMacrosInStringInternal( pString, pOutBuff, outBuffSize, false ); +} + +void CVPC::ResolveMacrosInConditional( char const *pString, char *pOutBuff, int outBuffSize ) +{ + ResolveMacrosInStringInternal( pString, pOutBuff, outBuffSize, true ); +} + +void CVPC::RemoveScriptCreatedMacros() +{ + for ( int i=0; i < m_Macros.Count(); i++ ) + { + if ( !m_Macros[i].m_bInternalCreatedMacro ) + { + m_Macros.Remove( i ); + --i; + } + } +} + +const char *CVPC::GetMacroValue( const char *pName ) +{ + for ( int i = 0; i < m_Macros.Count(); i++ ) + { + if ( !V_stricmp( pName, m_Macros[i].name.String() ) ) + { + return m_Macros[i].value.String(); + } + } + + // not found + return ""; +} diff --git a/external/vpc/utils/vpc/main.cpp b/external/vpc/utils/vpc/main.cpp new file mode 100644 index 0000000..0caa9c9 --- /dev/null +++ b/external/vpc/utils/vpc/main.cpp @@ -0,0 +1,2810 @@ +//========= Copyright 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: VPC +// +//=====================================================================================// + +#include "vpc.h" +#include "dependencies.h" +#include "p4sln.h" +#include "ilaunchabledll.h" +#include <time.h> + +DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_VPC, "VPC" ); + +CVPC *g_pVPC; + +class CBaseProjectDataCollector; +CUtlVector<CBaseProjectDataCollector*> g_vecPGenerators; + +// Stuff that we might encounter in a vpc file that parts of vpc care about +const char *g_pOption_ImportLibrary = "$ImportLibrary"; +const char *g_pOption_OutputFile = "$OutputFile"; +const char *g_pOption_GameOutputFile = "$GameOutputFile"; +const char *g_pOption_AdditionalIncludeDirectories = "$AdditionalIncludeDirectories"; +const char *g_pOption_AdditionalProjectDependencies = "$AdditionalProjectDependencies"; +const char *g_pOption_AdditionalOutputFiles = "$AdditionalOutputFiles"; +const char *g_pOption_PreprocessorDefinitions = "$PreprocessorDefinitions"; +char *g_IncludeSeparators[2] = {";",","}; + +#ifdef POSIX +#define _unlink unlink +#define _stat stat +#endif + +CVPC::CVPC() +{ + m_pP4Module = NULL; + m_pFilesystemModule = NULL; + + m_nArgc = 0; + m_ppArgv = NULL; + + m_bVerbose = false; + m_bQuiet = false; + m_bUsageOnly = false; + m_bHelp = false; + m_bSpewPlatforms = false; + m_bSpewGames = false; + m_bSpewGroups = false; + m_bSpewProjects = false; + m_bIgnoreRedundancyWarning = false; + m_bSpewProperties = false; + m_bTestMode = false; + m_bGeneratedProject = false; + m_bAnyProjectQualified = false; + m_bForceGenerate = false; + m_bNoPosixPCH = false; + m_bEnableVpcGameMacro = true; + m_bDecorateProject = false; + m_bShowDeps = false; + m_bP4AutoAdd = false; + m_bP4SlnCheckEverything = false; + m_bInMkSlnPass = false; + m_bShowCaseIssues = false; + m_bVerboseMakefile = false; + m_bP4SCC = false; + m_b32BitTools = false; + +#ifdef VPC_SCC_INTEGRATION + m_bP4SCC = true; +#endif + if ( getenv( "VPC_SRCCTL" ) != NULL ) + { + m_bP4SCC = V_atoi( getenv( "VPC_SRCCTL" ) ) != 0; + } + +#ifdef WIN32 + m_eVSVersion = k_EVSVersion_2015; + m_bUseVS2010FileFormat = true; + m_bUseUnity = false; +#else + m_eVSVersion = k_EVSVersion_Invalid; + m_bUseVS2010FileFormat = false; + m_bUseUnity = false; +#endif + + m_FilesMissing = 0; + + // need to check files by default, otherwise dependency failure (due to missing file) cause needles rebuilds + m_bCheckFiles = true; + + m_pProjectGenerator = NULL; + m_pSolutionGenerator = NULL; + +#ifdef OSX + m_bForceIterate = true; +#else + m_bForceIterate = false; +#endif + + m_pPhase1Projects = NULL; +} + +CVPC::~CVPC() +{ + // BUGBUG: There is probably some actual cleanup to be done here. +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CVPC::Init( int argc, char **argv ) +{ + m_nArgc = argc; + m_ppArgv = argv; + + // vpc operates tersely by preferred company opinion + // verbosity necessary for debugging + m_bVerbose = ( HasCommandLineParameter( "/v" ) || HasCommandLineParameter( "/verbose" ) ); + m_bQuiet = ( HasCommandLineParameter( "/q" ) || + HasCommandLineParameter( "/quiet" ) || + ( getenv( "VPC_QUIET" ) && V_stricmp( getenv( "VPC_QUIET" ), "0" ) ) ); + +#ifndef STEAM + // We don't really need to pop the logging state since the process will terminate when we're done. + LoggingSystem_PushLoggingState(); + + m_LoggingListener.m_bQuietPrintf = m_bQuiet; + LoggingSystem_RegisterLoggingListener( &m_LoggingListener ); +#endif + + // needs to occur early and before any other expensive setup, a crc check just exits with an error code used by caller + InProcessCRCCheck(); + + LoadPerforceInterface(); + + // vpc may have been run from wrong location, restart self + bool bIsRestart = false; + if ( RestartFromCorrectLocation( &bIsRestart ) ) + { + // successfully ran under restart condition, all done + return false; + } + if ( bIsRestart ) + { + // this process is the restart child, cull the internal private restart guard option + // otherwise it gets confused as a build option + m_nArgc--; + } + + Log_Msg( LOG_VPC, "VPC - Valve Project Creator For " ); + Log_Msg( LOG_VPC, "Visual Studio, Xbox 360, PlayStation 3, " ); + Log_Msg( LOG_VPC, "Xcode and Make (Build: %s %s)\n", __DATE__, __TIME__ ); + Log_Msg( LOG_VPC, "(C) Copyright 1996-2015, Valve Corporation, All rights reserved.\n" ); + Log_Msg( LOG_VPC, "\n" ); + + return true; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CVPC::Shutdown( bool bHasError ) +{ + if ( !bHasError ) + { + GetScript().EnsureScriptStackEmpty(); + } + + if ( !m_TempGroupScriptFilename.IsEmpty() ) + { + // delete temp work file + _unlink( m_TempGroupScriptFilename.Get() ); + m_TempGroupScriptFilename.Clear(); + } + + UnloadPerforceInterface(); +} + +#if defined( STANDALONE_VPC ) +class CP4; +extern CP4 s_p4; +#endif + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CVPC::LoadPerforceInterface() +{ + if ( p4 ) + { + // already loaded + return true; + } + +#if defined( STANDALONE_VPC ) + p4 = (IP4*)&s_p4; + return (p4 != NULL); +#else + + // + // Try to load p4lib.dll and the filesystem since the p4lib relies on it + // + char p4libdll[MAX_PATH]; + char filesystemdll[MAX_PATH]; + +#ifdef _WIN32 + // Don't require them to have game\bin in their path. Since we know where vpc.exe is, + // point directly to p4lib.dll in its rightful place. + char szModuleBinPath[MAX_PATH]; + GetModuleFileName( NULL, szModuleBinPath, sizeof( szModuleBinPath ) ); + V_ExtractFilePath( szModuleBinPath, p4libdll, sizeof( p4libdll ) ); + V_AppendSlash( p4libdll, sizeof( p4libdll ) ); + V_strncpy( filesystemdll, p4libdll, sizeof( filesystemdll ) ); + V_strncat( p4libdll, "..\\..\\..\\game\\bin\\p4lib.dll", sizeof( p4libdll ) ); + V_strncat( filesystemdll, "..\\..\\..\\game\\bin\\filesystem_stdio.dll", sizeof( filesystemdll ) ); +#else + V_strncpy( p4libdll, "p4lib", sizeof( p4libdll ) ); + V_strncpy( filesystemdll, "filesystem_stdio", sizeof( filesystemdll ) ); +#endif + + if ( !Sys_LoadInterface( p4libdll, P4_INTERFACE_VERSION, &m_pP4Module, (void**)&p4 ) ) + { +#ifdef _WIN32 + // This always fails on non-Windows build machines -- the warning is + // annoying and not helpful. + VPCWarning( "Unable to get Perforce interface from p4lib.dll." ); +#endif + return false; + } + + // Let the P4 module get its interface to the filesystem - hate this + + // This method is not available in portal2, but is in source2. + // p4->SetVerbose( false ); + m_pFilesystemModule = Sys_LoadModule( filesystemdll ); + p4->Connect( Sys_GetFactory( m_pFilesystemModule ) ); + + return true; +#endif +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CVPC::UnloadPerforceInterface() +{ + // Unload P4 if it was loaded + if ( m_pP4Module ) + { + Sys_UnloadModule( m_pP4Module ); + m_pP4Module = NULL; + } + + if ( m_pFilesystemModule ) + { + Sys_UnloadModule( m_pFilesystemModule ); + m_pFilesystemModule = NULL; + } +} + + +bool VPC_Config_IgnoreOption( const char *pPropertyName ) +{ + char buff[MAX_SYSTOKENCHARS]; + g_pVPC->GetScript().ParsePropertyValue( NULL, buff, sizeof( buff ) ); + return true; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CVPC::VPCError( const char* format, ... ) +{ + va_list argptr; + char msg[MAX_SYSPRINTMSG]; + + va_start( argptr,format ); + vsprintf( msg,format,argptr ); + va_end( argptr ); + + // spew in red + Log_Warning( LOG_VPC, Color( 255, 0, 0, 255 ), "ERROR: %s\n", msg ); + + // dump the script stack to assist in user understading of the include chain + GetScript().SpewScriptStack(); + + // do proper shutdown in an error context + Shutdown( true ); + + // errors are expected to be fatal by all calling code + // otherwise it would have been a warning + exit( 1 ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CVPC::VPCSyntaxError( const char* format, ... ) +{ + va_list argptr; + char msg[MAX_SYSPRINTMSG]; + + va_start( argptr, format ); + if ( format ) + { + vsprintf( msg, format, argptr ); + } + va_end( argptr ); + + if ( format ) + { + Log_Warning( LOG_VPC, Color( 255, 0, 0, 255 ), "Bad Syntax: %s\n", msg ); + } + + // syntax errors are fatal + VPCError( "Bad Syntax in '%s' line:%d\n", GetScript().GetName(), GetScript().GetLine() ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CVPC::VPCWarning( const char* format, ... ) +{ + va_list argptr; + char msg[MAX_SYSPRINTMSG]; + + va_start( argptr,format ); + vsprintf( msg,format,argptr ); + va_end( argptr ); + + if ( m_bIgnoreRedundancyWarning ) + { + if ( V_stristr( msg, "matches default setting" ) ) + return; + if ( V_stristr( msg, "already exists in project" ) ) + return; + } + + Log_Warning( LOG_VPC, Color( 255, 255, 0, 255 ), "WARNING: %s\n", msg ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CVPC::VPCStatus( bool bAlwaysSpew, const char* format, ... ) +{ + if ( m_bQuiet ) + return; + + va_list argptr; + char msg[MAX_SYSPRINTMSG]; + + va_start( argptr,format ); + vsprintf( msg,format,argptr ); + va_end( argptr ); + + if ( bAlwaysSpew || m_bVerbose ) + { + Log_Msg( LOG_VPC, "%s\n", msg ); + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int CVPC::GetProjectsInGroup( CUtlVector< projectIndex_t > &projectList, const char *pGroupName ) +{ + projectList.RemoveAll(); + + // Find the specified group + groupTagIndex_t groupTagIndex = VPC_Group_FindOrCreateGroupTag( pGroupName, false ); + + if ( groupTagIndex != INVALID_INDEX ) + { + FOR_EACH_VEC( m_GroupTags[groupTagIndex].groups, m ) + { + FOR_EACH_VEC( m_Groups[m_GroupTags[groupTagIndex].groups[m]].projects, n ) + { + projectList.AddToTail( m_Groups[m_GroupTags[groupTagIndex].groups[m]].projects[n] ); + } + } + } + + return projectList.Count(); +} + +//----------------------------------------------------------------------------- +// Checks to ensure the bin path is in the same tree as the vpc_scripts +// Returns true if bin path valid +//----------------------------------------------------------------------------- +#if !defined( POSIX ) +bool CVPC::CheckBinPath( char *pOutBinPath, int outBinPathSize ) +{ + char szScriptPath[MAX_PATH]; + char szDirectory[MAX_PATH]; + char szLastDirectory[MAX_PATH]; + + // non destructively determine the vpc_scripts directory + bool bFound = false; + szLastDirectory[0] = '\0'; + szScriptPath[0] = '\0'; + V_GetCurrentDirectory( szDirectory, sizeof( szDirectory ) ); + while ( 1 ) + { + V_ComposeFileName( szDirectory, "vpc_scripts", szScriptPath, sizeof( szScriptPath ) ); + struct _stat statBuf; + if ( _stat( szScriptPath, &statBuf ) != -1 ) + { + bFound = true; + break; + } + + // previous dir + V_ComposeFileName( szDirectory, "..", szScriptPath, sizeof( szScriptPath ) ); + + char fullPath[MAX_PATH]; + if ( _fullpath( fullPath, szScriptPath, sizeof( fullPath ) ) ) + { + V_strncpy( szDirectory, fullPath, sizeof( szDirectory ) ); + } + + if ( !V_stricmp( szDirectory, szLastDirectory ) ) + { + // can back up no further + break; + } + strcpy( szLastDirectory, szDirectory ); + } + + if ( !bFound ) + { + VPCError( "Failed to determine source directory from current path. Expecting 'vpc_scripts' in source path." ); + } + + char szSourcePath[MAX_PATH]; + strcpy( szSourcePath, szDirectory ); + + // check to ensure that executeable and src directory are in the same tree + // executeable needs to be tightly bound to its vpc_scripts + char szModuleBinPath[MAX_PATH]; + GetModuleFileName( NULL, szModuleBinPath, sizeof( szModuleBinPath ) ); + + // cannot trust output from GetModuleFileName(), occasionally has ./ or ../ screwing up comparisons + V_RemoveDotSlashes( szModuleBinPath, '\\' ); + V_strlower( szModuleBinPath ); + V_strncpy( pOutBinPath, szModuleBinPath, outBinPathSize ); + + // allowed to run from a root "devbin", for use with junctions + if ( Sys_StringPatternMatch( "?:\\devbin\\vpc.exe", szModuleBinPath ) ) + return true; + + char *pString = V_stristr( szModuleBinPath, "\\devtools\\bin\\" ); + if ( pString ) + { + // source dirs should match + char chSave = *pString; + *pString = '\0'; + bool bSame = V_stricmp( szSourcePath, szModuleBinPath ) == 0; + *pString = chSave; + + if ( bSame ) + { + return true; + } + } + else + { + VPCError( "Executable not running from 'devtools/bin' but from unexpected directory '%s'", szModuleBinPath ); + } + + // mismatched, wierd bin patch could have been a result of user's environment path + // use expected source path which is based on user's cwd to get the real bin path + V_strncpy( pOutBinPath, szSourcePath, outBinPathSize ); + V_strncat( pOutBinPath, "\\devtools\\bin\\vpc.exe", outBinPathSize ); + struct _stat statBuf; + if ( _stat( pOutBinPath, &statBuf ) == -1 ) + { + VPCError( "Correct executeable missing, should be at '%s'", pOutBinPath ); + } + + // yikes, wrong executeable was started, agreed behavior was to restart based on user's cwd + // REALLY want users to see this, it indicates a possible hazard of using the wrong vpc + Log_Warning( LOG_VPC, Color( 255, 255, 0, 255 ), "********************************************************************************\n" ); + Log_Warning( LOG_VPC, Color( 255, 255, 0, 255 ), "Wrong Executable '%s' Running!\nRestarting at '%s'\n", szModuleBinPath, pOutBinPath ); + Log_Warning( LOG_VPC, Color( 255, 255, 0, 255 ), "********************************************************************************\n" ); + + return false; +} +#endif + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CVPC::DetermineSourcePath() +{ + char szSourcePath[MAX_PATH]; + char szLastDirectory[MAX_PATH]; + + char szOldPath[MAX_PATH]; + V_GetCurrentDirectory( szOldPath, sizeof( szOldPath ) ); + + // find vpc_scripts from cwd + szLastDirectory[0] = '\0'; + bool bFound = false; + while ( 1 ) + { + V_GetCurrentDirectory( szSourcePath, sizeof( szSourcePath ) ); + if ( !V_stricmp( szSourcePath, szLastDirectory ) ) + { + // can back up no further + break; + } + V_strncpy( szLastDirectory, szSourcePath, sizeof( szLastDirectory ) ); + + char szTestDir[MAX_PATH]; + V_ComposeFileName( szSourcePath, "vpc_scripts", szTestDir, sizeof( szTestDir ) ); + struct _stat statBuf; + if ( _stat( szTestDir, &statBuf ) != -1 ) + { + bFound = true; + break; + } + + // previous dir + char szPrevDir[MAX_PATH]; + V_ComposeFileName( szSourcePath, "..", szPrevDir, sizeof( szPrevDir ) ); + V_SetCurrentDirectory( szPrevDir ); + } + + if ( !bFound ) + { + VPCError( "Failed to determine source directory from current path. Expecting 'vpc_scripts' in source path." ); + } + + // Remember the source path and restore the path to where it was. + m_SourcePath = szSourcePath; + V_SetCurrentDirectory( szOldPath ); + + // always emit source path, identifies MANY redundant user problems + // users can easily run from an unintended place due to botched path, mangled directories, etc + Log_Msg( LOG_VPC, "Source Path: %s\n", m_SourcePath.Get() ); +} + +//----------------------------------------------------------------------------- +// Sets the working directory to .../vpc_scripts as all scripts are +// guaranteed relative to the vpc script directory. +//----------------------------------------------------------------------------- +void CVPC::SetDefaultSourcePath() +{ + V_SetCurrentDirectory( m_SourcePath.Get() ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CVPC::IsProjectCurrent( const char *pOutputFilename, bool bSpewStatus ) +{ + // default is project is stale + if ( !Sys_Exists( pOutputFilename ) ) + { + return false; + } + + if ( Is2010() && !Sys_Exists( CFmtStr( "%s.filters", pOutputFilename ) ) ) + { + return false; + } + + char errorString[1024]; + bool bCRCValid = VPC_CheckProjectDependencyCRCs( pOutputFilename, m_SupplementalCRCString.Get(), errorString, sizeof( errorString ) ); + + if ( bSpewStatus ) + { + if ( bCRCValid ) + { + VPCStatus( true, "Valid: '%s' Passes CRC Checks.", pOutputFilename ); + } + else + { + VPCStatus( true, "Stale: '%s' Requires Rebuild. [%s]", pOutputFilename, errorString ); + } + } + + return bCRCValid; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CVPC::SpewUsage( void ) +{ + // skip header if user requested specific detail + bool bNoHeader = + m_bSpewPlatforms || + m_bSpewGames || + m_bSpewProjects || + m_bSpewGroups || + m_bSpewProperties || + m_BuildCommands.Count(); + + if ( !bNoHeader ) + { + Log_Msg( LOG_VPC, "\n" ); + + if ( !m_bHelp ) + { + // terse + Log_Msg( LOG_VPC, "Type vpc /h for help...\n" ); + } + else + { + // verbose + Log_Msg( LOG_VPC, "usage: vpc [options] <+/-/*project or group>\n"); + + Log_Msg( LOG_VPC, "\n" ); + Log_Msg( LOG_VPC, "Examples:\n" ); + + Log_Msg( LOG_VPC, "\n" ); + Log_Msg( LOG_VPC, " Single .vcproj generation:\n" ); + Log_Msg( LOG_VPC, " vpc +client /hl2 <-- Creates a Win32 .vcproj for the HL2 client.\n" ); + Log_Msg( LOG_VPC, " vpc +shaderapi /x360 <-- Creates a Xbox360 .vcproj for the shaderapi.\n" ); + + Log_Msg( LOG_VPC, "\n" ); + Log_Msg( LOG_VPC, " Multiple .vcproj generation - Multiple Projects for Games and Platforms:\n" ); + Log_Msg( LOG_VPC, " vpc +client /hl2 /tf <-- Creates ALL the Win32 .vcprojs for the HL2 and TF client.\n" ); + Log_Msg( LOG_VPC, " vpc +gamedlls /allgames <-- Creates ALL the Win32 .vcprojs for client and server for all GAMES.\n" ); + Log_Msg( LOG_VPC, " vpc +tools -tier0 /win32 /x360 <-- Creates ALL the Win32 and Xbox360 .vcprojs for the tool projects but not the tier0 project.\n" ); + + Log_Msg( LOG_VPC, "\n" ); + Log_Msg( LOG_VPC, " Use +/- to add or remove projects or groups.\n"); + Log_Msg( LOG_VPC, " Use * to add a project and all projects that depend on it.\n"); + Log_Msg( LOG_VPC, " Use @ to add a project and all projects that it depends on.\n"); + Log_Msg( LOG_VPC, " Use /h spew final target build set only (no .vcproj created).\n"); + Log_Msg( LOG_VPC, "\n" ); + Log_Msg( LOG_VPC, " Further details can be found on Valve Internal Wiki on VPC.\n" ); + + Log_Msg( LOG_VPC, "\n--- OPTIONS ---\n" ); + Log_Msg( LOG_VPC, "[/q]: Quiet mode (quiet mode is automatically on if the VPC_QUIET environment variable is set)\n" ); + Log_Msg( LOG_VPC, "[/v]: Verbose\n" ); + Log_Msg( LOG_VPC, "[/f]: Force generate .vcproj, otherwise use crc checks\n" ); + Log_Msg( LOG_VPC, "[/dp]: Decorate project names with platform\n" ); + Log_Msg( LOG_VPC, "[/testmode]: Override output .vcproj file to be named 'test.vcproj'\n" ); +#ifdef VPC_SCC_INTEGRATION + Log_Msg( LOG_VPC, "[/nosrcctl]: Disable P4SCC source control integration - can also set environment variable VPC_SRCCTL to 0\n" ); +#else + Log_Msg( LOG_VPC, "[/srcctl]: Enable P4SCC source control integration - can also set environment variable VPC_SRCCTL to 1\n" ); +#endif + Log_Msg( LOG_VPC, "[/mirror]: <path> - Mirror output files to specified path. Used for A:B testing.\n" ); + Log_Msg( LOG_VPC, "[/2015]: Generate projects and solutions for Visual Studio 2015 [default]\n" ); + Log_Msg( LOG_VPC, "[/2013]: Generate projects and solutions for Visual Studio 2013\n" ); + Log_Msg( LOG_VPC, "[/2012]: Generate projects and solutions for Visual Studio 2012\n" ); + Log_Msg( LOG_VPC, "[/2010]: Generate projects and solutions for Visual Studio 2010\n" ); + Log_Msg( LOG_VPC, "[/2005]: Generate projects and solutions for Visual Studio 2005\n" ); + Log_Msg( LOG_VPC, "[/2008]: Generate projects and solutions for Visual Studio 2008\n" ); + Log_Msg( LOG_VPC, "[/windows]: Generate projects for both Win32 and Win64\n" ); + Log_Msg( LOG_VPC, "[/unity]: Enable unity file generation\n" ); + Log_Msg( LOG_VPC, "[/32bittools]: Specify 32-bit toolchain in VC++ even when compiling 64 bit target\n" ); + + Log_Msg( LOG_VPC, "\n--- Help ---\n" ); + Log_Msg( LOG_VPC, "[/h]: Help\n" ); + Log_Msg( LOG_VPC, "[/?]: Help\n" ); + Log_Msg( LOG_VPC, "[/platforms]: Spew Platforms\n" ); + Log_Msg( LOG_VPC, "[/games]: Spew Games\n" ); + Log_Msg( LOG_VPC, "[/projects]: Spew Projects\n" ); + Log_Msg( LOG_VPC, "[/groups]: Spew Groups\n" ); + Log_Msg( LOG_VPC, "[/properties]: Spew VS2005 Properties\n" ); + + Log_Msg( LOG_VPC, "\n--- Conditionals ---\n" ); + Log_Msg( LOG_VPC, "[/profile]: Set Reserved $PROFILE=1\n" ); + Log_Msg( LOG_VPC, "[/retail]: Set Reserved $RETAIL=1\n" ); + Log_Msg( LOG_VPC, "[/callcap]: Set Reserved $CALLCAP=1\n" ); + Log_Msg( LOG_VPC, "[/fastcap]: Set Reserved $FASTCAP=1\n" ); + Log_Msg( LOG_VPC, "[/memtest]: Set Reserved $MEMTEST=1\n" ); + Log_Msg( LOG_VPC, "[/nofpo]: Set Reserved $NOFPO=1\n" ); + Log_Msg( LOG_VPC, "[/lv]: Set Reserved $LV=1\n" ); + Log_Msg( LOG_VPC, "[/demo]: Set Reserved $DEMO=1\n" ); + Log_Msg( LOG_VPC, "[/no_steam]: Set Reserved $NO_STEAM=1\n" ); + Log_Msg( LOG_VPC, "[/qtdebug]: Set Reserved $QTDEBUG=1\n" ); + Log_Msg( LOG_VPC, "[/no_ceg]: Set Reserved $NO_CEG=1\n" ); + Log_Msg( LOG_VPC, "[/upload_ceg]: Set Reserved $UPLOAD_CEG=1\n" ); + + Log_Msg( LOG_VPC, "\n--- Other ---\n" ); + Log_Msg( LOG_VPC, "[/mksln]: <.sln filename> - make a solution file\n" ); + Log_Msg( LOG_VPC, "[/p4sln]: <.sln filename> <changelists...> - make a solution file based on\n" ); + Log_Msg( LOG_VPC, " the changelist. Changelists can be specific numbers, 0 or \"default\"\n" ); + Log_Msg( LOG_VPC, " for the default changelist, or \"all\" for all active changelists.\n" ); + Log_Msg( LOG_VPC, "[/nop4add]: Don't automatically add project files to Perforce\n" ); + Log_Msg( LOG_VPC, "[/slnitems]: <filename> - adds all files listed in <filename> to generated\n" ); + Log_Msg( LOG_VPC, " solutions\n" ); + Log_Msg( LOG_VPC, "[/showdeps]: Show an example dependency chain for each project that depends\n" ); + Log_Msg( LOG_VPC, " on your p4 change list(s). Use with /p4sln.\n" ); + Log_Msg( LOG_VPC, "[/checkfiles]: Check for the existence of files in $file commands. For debugging vpc files.\n" ); + Log_Msg( LOG_VPC, " Only works if the currrent directory is the project directory.\n" ); +// Log_Msg( LOG_VPC, "[/novpcgame]: Disable reserved vpc macro $VPCGAME and $VPCGAMECAPS.\n" ); +// Log_Msg( LOG_VPC, " By default if a single game is specified on command line, then that specified\n" ); +// Log_Msg( LOG_VPC, " game name will be used as a value for $VPCGAME and $VPCGAMECAPS macros.\n" ); + Log_Msg( LOG_VPC, "[/define:xxx]: Enable a custom conditional $XXX to use for quick testing in VPC files.\n" ); + } + } + + if ( m_Conditionals.Count() && m_bSpewPlatforms ) + { + bool bFirstDefine = false; + for ( int i = 0; i < m_Conditionals.Count(); i++ ) + { + if ( m_Conditionals[i].type != CONDITIONAL_PLATFORM ) + continue; + if ( !bFirstDefine ) + { + Log_Msg( LOG_VPC, "\n--- PLATFORMS ---\n" ); + bFirstDefine = true; + } + Log_Msg( LOG_VPC, "%s%s\n", m_Conditionals[i].upperCaseName.String(), m_Conditionals[i].m_bDefined ? " = 1" : "" ); + } + } + + if ( m_Conditionals.Count() && m_bSpewGames ) + { + bool bFirstGame = false; + for ( int i = 0; i < m_Conditionals.Count(); i++ ) + { + if ( m_Conditionals[i].type != CONDITIONAL_GAME ) + continue; + if ( !bFirstGame ) + { + Log_Msg( LOG_VPC, "\n--- GAMES ---\n" ); + bFirstGame = true; + } + Log_Msg( LOG_VPC, "%s%s\n", m_Conditionals[i].upperCaseName.String(), m_Conditionals[i].m_bDefined ? " = 1" : "" ); + } + } + + if ( m_Projects.Count() && m_bSpewProjects ) + { + // spew all sorted projects + Log_Msg( LOG_VPC, "\n--- PROJECTS ---\n" ); + CUtlRBTree< const char * > sorted( 0, 0, CaselessStringLessThan ); + for ( int i = 0; i < m_Projects.Count(); i++ ) + { + sorted.Insert( m_Projects[i].name.String() ); + } + for ( int i = sorted.FirstInorder(); i != sorted.InvalidIndex(); i = sorted.NextInorder( i ) ) + { + Log_Msg( LOG_VPC, "[+/-] %s\n", sorted[i] ); + } + } + + if ( g_pVPC->m_GroupTags.Count() && m_bSpewGroups ) + { + // spew all sorted groups + Log_Msg( LOG_VPC, "\n--- GROUPS ---\n" ); + CUtlRBTree< const char * > sorted( 0, 0, CaselessStringLessThan ); + for ( int i = 0; i < g_pVPC->m_GroupTags.Count(); i++ ) + { + if ( !g_pVPC->m_GroupTags[i].bSameAsProject ) + { + sorted.Insert( g_pVPC->m_GroupTags[i].name.String() ); + } + } + for ( int i = sorted.FirstInorder(); i != sorted.InvalidIndex(); i = sorted.NextInorder( i ) ) + { + Log_Msg( LOG_VPC, "[+/-] %s\n", sorted[i] ); + } + } + +#if 0 +#if defined( _WIN32 ) + if ( m_bSpewProperties ) + { + for ( int i = 0; i < KEYWORD_MAX; i++ ) + { + VPC_Config_SpewProperties( (configKeyword_e)i ); + } + } +#endif +#endif + + if ( m_BuildCommands.Count() ) + { + // spew details about each command + Log_Msg( LOG_VPC, "\nUser Build Commands:\n" ); + Log_Msg( LOG_VPC, "--------------------\n" ); + for ( int i = 0; i < m_BuildCommands.Count(); i++ ) + { + Log_Msg( LOG_VPC, "%s\n", m_BuildCommands[i].String() ); + groupTagIndex_t groupTagIndex = VPC_Group_FindOrCreateGroupTag( m_BuildCommands[i].Get()+1, false ); + if ( groupTagIndex == INVALID_INDEX ) + { + Log_Msg( LOG_VPC, " ??? (Unknown Group)\n" ); + } + else + { + groupTag_t *pGroupTag = &g_pVPC->m_GroupTags[groupTagIndex]; + for (int j=0; j<pGroupTag->groups.Count(); j++ ) + { + group_t *pGroup = &m_Groups[pGroupTag->groups[j]]; + for ( int k=0; k<pGroup->projects.Count(); k++ ) + { + Log_Msg( LOG_VPC, " %s\n", m_Projects[pGroup->projects[k]].name.String() ); + } + } + } + } + + Log_Msg( LOG_VPC, "\nTarget Projects:\n" ); + Log_Msg( LOG_VPC, "----------------\n" ); + if ( m_TargetProjects.Count() ) + { + for ( int i=0; i<m_TargetProjects.Count(); i++ ) + { + Log_Msg( LOG_VPC, "%s\n", m_Projects[m_TargetProjects[i]].name.String() ); + } + } + else + { + Log_Msg( LOG_VPC, "Empty Set (no output)\n" ); + } + + Log_Msg( LOG_VPC, "\nTarget Games:\n" ); + Log_Msg( LOG_VPC, "-------------\n" ); + bool bHasDefine = false; + for ( int i=0; i<m_Conditionals.Count(); i++ ) + { + if ( m_Conditionals[i].type != CONDITIONAL_GAME ) + continue; + if ( m_Conditionals[i].m_bDefined ) + { + Log_Msg( LOG_VPC, "$%s = 1\n", m_Conditionals[i].upperCaseName.String() ); + bHasDefine = true; + } + } + if ( !bHasDefine ) + { + Log_Msg( LOG_VPC, "No Game Set!\n" ); + } + + Log_Msg( LOG_VPC, "\nTarget Platforms:\n" ); + Log_Msg( LOG_VPC, "-----------------\n" ); + bHasDefine = false; + for ( int i=0; i<m_Conditionals.Count(); i++ ) + { + if ( m_Conditionals[i].type != CONDITIONAL_PLATFORM ) + continue; + if ( m_Conditionals[i].m_bDefined ) + { + Log_Msg( LOG_VPC, "$%s = 1\n", m_Conditionals[i].upperCaseName.String() ); + bHasDefine = true; + } + } + if ( !bHasDefine ) + { + Log_Msg( LOG_VPC, "No Platform Set!\n" ); + } + + Log_Msg( LOG_VPC, "\nCustom Conditionals:\n" ); + Log_Msg( LOG_VPC, "---------------------\n" ); + bHasDefine = false; + for ( int i=0; i<m_Conditionals.Count(); i++ ) + { + if ( m_Conditionals[i].type != CONDITIONAL_CUSTOM ) + continue; + if ( m_Conditionals[i].m_bDefined ) + { + Log_Msg( LOG_VPC, "$%s = 1\n", m_Conditionals[i].upperCaseName.String() ); + bHasDefine = true; + } + } + if ( !bHasDefine ) + { + Log_Msg( LOG_VPC, "No Custom Defines Set!\n" ); + } + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CVPC::HandleSingleCommandLineArg( const char *pArg ) +{ + if ( ( pArg[0] == '-' ) || ( pArg[0] == '/' ) ) + { + // skip past arg prefix + const char *pArgName = pArg+1; + + // check options + if ( !V_stricmp( pArgName, "h" ) || !V_stricmp( pArgName, "?" ) || !V_stricmp( pArgName, "help" ) ) + { + m_bHelp = true; + m_bUsageOnly = true; + } + else if ( !V_stricmp( pArgName, "v" ) || !V_stricmp( pArgName, "verbose" ) ) + { + m_bVerbose = true; + } + else if ( !V_stricmp( pArgName, "testmode" ) || !V_stricmp( pArgName, "test" ) ) + { + m_bTestMode = true; + } + else if ( !V_stricmp( pArgName, "f" ) || !V_stricmp( pArgName, "force" ) ) + { + m_bForceGenerate = true; + } + else if ( !V_stricmp( pArgName, "no_posix_pch" ) ) + { + // Not implemented for win32 generators since those just pass through raw options :-/ + m_bNoPosixPCH = true; + // Ensure this changes CRC. Ideally it would only change if anything ended up using the PCH conditional + m_ExtraOptionsCRCString += pArgName; + } + else if ( !V_stricmp( pArgName, "novpcgame" ) ) + { + m_bEnableVpcGameMacro = false; + } + else if ( !V_stricmp( pArgName, "checkfiles" ) ) + { + m_bCheckFiles = true; + } + else if ( !V_stricmp( pArgName, "nocheckfiles" ) ) + { + m_bCheckFiles = false; + } + else if ( !V_stricmp( pArgName, "showcaseissues" ) || !V_stricmp( pArgName, "showcase" ) ) + { + m_bShowCaseIssues = true; + } + else if ( !V_stricmp( pArgName, "dp" ) ) + { + m_bDecorateProject = true; + } + else if ( char const *szActualDecorateName = StringAfterPrefix( pArgName, "decorate:" ) ) + { + m_bDecorateProject = true; + m_strDecorate = szActualDecorateName; + } + else if ( !V_stricmp( pArgName, "dedicated" ) ) + { + m_bDedicatedBuild = true; + m_bAppendSrvToDedicated = true; + m_bUseValveBinDir = true; + } + else if ( !V_stricmp( pArgName, "use_valve_bin" ) ) + { + m_bUseValveBinDir = true; + } + else if ( !V_stricmp( pArgName, "platforms" ) || !V_stricmp( pArgName, "plats" ) ) + { + m_bSpewPlatforms = true; + m_bUsageOnly = true; + } + else if ( !V_stricmp( pArgName, "games" ) ) + { + m_bSpewGames = true; + m_bUsageOnly = true; + } + else if ( !V_stricmp( pArgName, "projects" ) ) + { + m_bSpewProjects = true; + m_bUsageOnly = true; + } + else if ( !V_stricmp( pArgName, "groups" ) ) + { + m_bSpewGroups = true; + m_bUsageOnly = true; + } + else if ( !V_stricmp( pArgName, "properties" ) ) + { + m_bSpewProperties = true; + m_bUsageOnly = true; + } + else if ( !V_stricmp( pArgName, "allgames" ) ) + { + // shortcut for all games defined + for ( int j=0; j<m_Conditionals.Count(); j++ ) + { + if ( m_Conditionals[j].type == CONDITIONAL_GAME ) + { + m_Conditionals[j].m_bDefined = true; + } + } + } + else if ( !V_stricmp( pArgName, "showdeps" ) ) + { + m_bShowDeps = true; + } + else if ( !V_stricmp( pArgName, "nop4add" ) ) + { + m_bP4AutoAdd = false; + } + else if ( !V_stricmp( pArgName, "2005" ) ) + { + m_eVSVersion = k_EVSVersion_2005; + m_ExtraOptionsCRCString += pArgName; + } + else if ( !V_stricmp( pArgName, "2008" ) ) + { + m_eVSVersion = k_EVSVersion_2008; + m_ExtraOptionsCRCString += pArgName; + } + else if ( !V_stricmp( pArgName, "2010" ) ) + { + m_eVSVersion = k_EVSVersion_2010; + m_ExtraOptionsCRCString += pArgName; + } + else if ( !V_stricmp( pArgName, "2012" ) ) + { + m_eVSVersion = k_EVSVersion_2012; + m_ExtraOptionsCRCString += pArgName; + } + else if ( !V_stricmp( pArgName, "2013" ) ) + { + m_eVSVersion = k_EVSVersion_2013; + m_ExtraOptionsCRCString += pArgName; + } + else if ( !V_stricmp( pArgName, "2015" ) ) + { + m_eVSVersion = k_EVSVersion_2015; + m_ExtraOptionsCRCString += pArgName; + } + else if ( !V_stricmp( pArgName, "nounity" ) ) + { + m_bUseUnity = false; + m_ExtraOptionsCRCString += pArgName; + } + else if ( !V_stricmp( pArgName, "unity" ) ) + { + m_bUseUnity = true; + m_ExtraOptionsCRCString += pArgName; + } + else if ( !V_stricmp( pArgName, "verbosemakefile" ) ) + { + m_bVerboseMakefile = true; + } + else if ( char const *szActualDefineName = StringAfterPrefix( pArgName, "define:" ) ) + { + // allow setting custom defines straight from command line + conditional_t *pConditional = FindOrCreateConditional( szActualDefineName, true, CONDITIONAL_CUSTOM ); + if ( pConditional ) + { + pConditional->m_bDefined = true; + + m_ExtraOptionsCRCString += "/define:"; // force this into additional CRC string + m_ExtraOptionsCRCString += pConditional->name.Get(); // force this into additional CRC string + } + } + else if ( !V_stricmp( pArgName, "32bittools" ) ) + { + m_b32BitTools = true; // use 32-bit toolchain even when building 64-bit targets + m_ExtraOptionsCRCString += pArgName; // Make sure these options affect the CRC. + } + else if ( !V_stricmp( pArgName, "nosrcctl" ) ) + { + m_bP4SCC = false; + m_ExtraOptionsCRCString += pArgName; // Make sure these options affect the CRC. + } + else if ( !V_stricmp( pArgName, "srcctl" ) ) + { + m_bP4SCC = true; + m_ExtraOptionsCRCString += pArgName; // Make sure these options affect the CRC. + } + else + { + // not a recognized option, try conditionals + // find in list of conditionals + conditional_t *pConditional = FindOrCreateConditional( pArgName, false, CONDITIONAL_NULL ); + if ( !pConditional ) + { + // not a recognized conditional, add to build commands + int index = m_BuildCommands.AddToTail(); + m_BuildCommands[index] = pArg; + } + else + { + // found conditional, mark as defined + pConditional->m_bDefined = true; + } + } + } + else if ( pArg[0] == '+' || pArg[0] == '*' || pArg[0] == '@' ) + { + // add to build commands + int index = m_BuildCommands.AddToTail(); + m_BuildCommands[index] = pArg; + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CVPC::ParseBuildOptions( int argc, char *argv[] ) +{ + m_bDedicatedBuild = false; + m_bAppendSrvToDedicated = false; + m_bUseValveBinDir = false; + + // parse options + // prefer +??? or -??? prefix syntax for groups and /??? for options because less confusing for new vpc users + // for ease we will support -??? prefix syntax for matched options as well + for ( int i = 1; i < argc; i++ ) + { + const char *pArg = argv[i]; + + if ( !V_stricmp( pArg, "/mksln" ) ) + { + if ( !m_P4SolutionFilename.IsEmpty() ) + { + VPCError( "Can't use /mksln with /p4sln." ); + } + + if ( (i+1) >= argc ) + { + VPCError( "/mksln requires a filename after it." ); + } + + // If the next parameter is a standard + or - or / or * parameter, then we take that to be the name of the solution file. + // So vpc /mksln +engine would generate engine.sln. + if ( argv[i+1][0] == '+' || argv[i+1][0] == '-' || argv[i+1][0] == '/' || argv[i+1][0] == '*' || argv[i+1][0] == '@' ) + { + m_MKSolutionFilename = &argv[i+1][1]; + } + else + { + m_MKSolutionFilename = argv[i+1]; + ++i; + } + } + else if ( !V_stricmp( pArg, "/p4sln" ) ) + { + if ( !m_MKSolutionFilename.IsEmpty() ) + { + VPCError( "Can't use /mksln with /p4sln." ); + } + + // Get the solution filename. + ++i; + if ( i >= argc || argv[i][0] == '+' || argv[i][0] == '-' || argv[i][0] == '/' || argv[i][0] == '*' || argv[i][0] == '@' ) + { + VPCError( "%s <solution filename> <changelist number> [ [restrict_to_group] ].", pArg ); + } + + m_P4SolutionFilename = argv[i]; + + // Get the changelist number. + while ( 1 ) + { + ++i; + + // No more args? + if ( i >= argc ) + break; + + // Special syntax for including all changelists. + if ( V_stricmp( argv[i], "all" ) == 0 ) + { + m_iP4Changelists.AddToTail( -1 ); + continue; + } + + // Special syntax for including default changelists. + if ( V_stricmp( argv[i], "default" ) == 0 ) + { + m_iP4Changelists.AddToTail( 0 ); + continue; + } + + // This arg isn't a changelist number? + if ( argv[i][0] < '0' || argv[i][0] > '9' ) + { + --i; + break; + } + + // Add the changelist number. + m_iP4Changelists.AddToTail( atoi( argv[i] ) ); + } + + // Make sure at least one changelist number was specified. + if ( m_iP4Changelists.Count() == 0 ) + { + VPCError( "%s <solution filename> <changelist number> [additional changelist numbers] [ [restrict_to_group] ].", pArg ); + } + + // Get the group restriction. + while ( 1 ) + { + ++i; + + // No more args? + if ( i >= argc ) + break; + + if ( argv[i][0] != '[' || argv[i][V_strlen( argv[i] ) - 1] != ']' ) + { + // This arg isn't a group name + --i; + break; + } + + // strip the braces + CUtlString groupName = argv[i]; + int nLastChar = groupName.Length() - 1; + groupName = groupName.Slice( 1, nLastChar ); + + // Add the restricted group name + m_P4GroupRestrictions.AddToTail( groupName ); + } + } + else if ( !V_stricmp( pArg, "/slnitems" ) ) + { + // Get the solution items filename + ++i; + if ( i >= argc || argv[i][0] == '+' || argv[i][0] == '-' || argv[i][0] == '/' || argv[i][0] == '*' || argv[i][0] == '@' ) + { + VPCError( "/slnitems <solution items filename>." ); + } + + m_SolutionItemsFilename = argv[i]; + } + else if ( !V_stricmp( pArg, "/mirror" ) ) + { + // force an output mirror, used for A:B comparison runs + ++i; + if ( i >= argc || argv[i][0] == '+' || argv[i][0] == '-' || argv[i][0] == '/' || argv[i][0] == '*' || argv[i][0] == '@' ) + { + VPCError( "/mirror <absolute path>." ); + } + + m_OutputMirrorString = argv[i]; + if ( !m_OutputMirrorString.IsEmpty() && !V_IsAbsolutePath( m_OutputMirrorString.Get() ) ) + { + VPCError( "/mirror <path> requires an absolute path specification." ); + } + } + else + { + HandleSingleCommandLineArg( pArg ); + } + } + + // If they did /p4sln but didn't specify any build commands, then have it check everything. + if ( m_iP4Changelists.Count() > 0 && m_BuildCommands.Count() == 0 ) + { + m_bP4SlnCheckEverything = true; + } + + CheckForInstalledXDK(); +} + +//----------------------------------------------------------------------------- +// Generate a string supplemental to CRC data, derived from command-line options, +// so varying certain command-line options can cause .VCPROJ rebuilds. +//----------------------------------------------------------------------------- +void CVPC::GenerateOptionsCRCString() +{ + m_SupplementalCRCString = "_"; + + conditional_t *pConditional = FindOrCreateConditional( "PROFILE", false, CONDITIONAL_NULL ); + if ( pConditional && pConditional->m_bDefined ) + { + m_SupplementalCRCString += "Pr"; + } + + pConditional = FindOrCreateConditional( "RETAIL", false, CONDITIONAL_NULL ); + if ( pConditional && pConditional->m_bDefined ) + { + m_SupplementalCRCString += "Rt"; + } + + pConditional = FindOrCreateConditional( "CALLCAP", false, CONDITIONAL_NULL ); + if ( pConditional && pConditional->m_bDefined ) + { + m_SupplementalCRCString += "Cc"; + } + + pConditional = FindOrCreateConditional( "FASTCAP", false, CONDITIONAL_NULL ); + if ( pConditional && pConditional->m_bDefined ) + { + m_SupplementalCRCString += "Fc"; + } + + pConditional = FindOrCreateConditional( "MEMTEST", false, CONDITIONAL_NULL ); + if ( pConditional && pConditional->m_bDefined ) + { + m_SupplementalCRCString += "Mt"; + } + + pConditional = FindOrCreateConditional( "NOFPO", false, CONDITIONAL_NULL ); + if ( pConditional && pConditional->m_bDefined ) + { + m_SupplementalCRCString += "Nf"; + } + + pConditional = FindOrCreateConditional( "LV", false, CONDITIONAL_NULL ); + if ( pConditional && pConditional->m_bDefined ) + { + m_SupplementalCRCString += "Lv"; + } + + pConditional = FindOrCreateConditional( "DEMO", false, CONDITIONAL_NULL ); + if ( pConditional && pConditional->m_bDefined ) + { + m_SupplementalCRCString += "Dm"; + } + + pConditional = FindOrCreateConditional( "NO_STEAM", false, CONDITIONAL_NULL ); + if ( pConditional && pConditional->m_bDefined ) + { + m_SupplementalCRCString += "Ns"; + } + + pConditional = FindOrCreateConditional( "QTDEBUG", false, CONDITIONAL_NULL ); + if ( pConditional && pConditional->m_bDefined ) + { + m_SupplementalCRCString += "Qt"; + } + + pConditional = FindOrCreateConditional( "NO_CEG", false, CONDITIONAL_NULL ); + + // + // !!NEVER INTEGRATE THIS CHANGE TO REL BRANCHES!! + // !!THIS TURNS OF CEG FOR NON-REL BRANCHES!! + // -Jeep & AaronN + // + //if ( pConditional && pConditional->m_bDefined ) + if ( pConditional ) + { + pConditional->m_bDefined = true; + m_SupplementalCRCString += "Nc"; + } + + pConditional = FindOrCreateConditional( "UPLOAD_CEG", false, CONDITIONAL_NULL ); + if ( pConditional && pConditional->m_bDefined ) + { + m_SupplementalCRCString += "Uc"; + } + + if ( !m_ExtraOptionsCRCString.IsEmpty() ) + { + m_SupplementalCRCString += CFmtStr( "_%s_", m_ExtraOptionsCRCString.Get() ); + } +} + +//----------------------------------------------------------------------------- +// Restart self from correct location and re-run. Returns FALSE if not applicable, +// otherwise TRUE if restart occurred. +//----------------------------------------------------------------------------- +bool CVPC::RestartFromCorrectLocation( bool *pIsChild ) +{ +#if defined( POSIX ) + return false; +#else + // recursive restart guard + // restart is a hidden internal param, always the last argument + // presence identifies spawned process + bool bIsRestart = false; + if ( !V_stricmp( m_ppArgv[m_nArgc-1], "/restart" ) ) + { + bIsRestart = true; + } + *pIsChild = bIsRestart; + + char szBinPath[MAX_PATH]; + if ( !CheckBinPath( szBinPath, sizeof( szBinPath ) ) ) + { + if ( bIsRestart ) + { + VPCError( "Cyclical Restart: Tell A Programmer!, Aborting." ); + } + + // replicate arguments, add -restart as a recursion guard for the new process + char *newArgs[128]; + if ( m_nArgc >= V_ARRAYSIZE( newArgs ) - 2 ) + { + VPCError( "Excessive Arguments: Tell A Programmer!, Aborting." ); + } + int i; + for ( i = 0; i < m_nArgc; i++ ) + { + newArgs[i] = m_ppArgv[i]; + } + newArgs[i++] = "/restart"; + newArgs[i++] = NULL; + + // restart using synchronous semantic, async semantic causes wierd hang + int status = _spawnv( _P_WAIT, szBinPath, newArgs ); + if ( !status ) + { + // called process exited normally + return true; + } + else if ( status > 0 ) + { + // called process exited with error, pass it along + exit( status ); + } + + // called process could not be started + VPCError( "Restart of '%s' failed\n", szBinPath ); + } + + // process is running from correct location + return false; +#endif +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CVPC::CheckForInstalledXDK() +{ +#ifndef POSIX + if ( !IsPlatformDefined( "X360" ) ) + { + // caller not doing any 360 work, so ignore + return; + } + + // quick and dirty early check for 360 XDK ability + // can only detect simplistic condition, VPC can't validate a perfect XDK/MSDEV installation + bool bHasXDK = false; + const char *pXDK = getenv( "XEDK" ); + if ( pXDK && pXDK[0] ) + { + // look for expected compiler + char fullPath[MAX_PATH]; + V_strncpy( fullPath, pXDK, sizeof( fullPath ) ); + V_AppendSlash( fullPath, sizeof( fullPath ) ); + V_strncat( fullPath, "bin\\win32\\cl.exe", sizeof( fullPath ) ); + int fileSize = Sys_FileLength( fullPath, false ); + if ( fileSize > 0 ) + { + bHasXDK = true; + } + } + if ( !bHasXDK ) + { + VPCError( "Cannot Build For Xbox 360, XDK is missing or damaged. Remove /x360 from command line." ); + } +#endif +} + +void CVPC::CreateOutputFilename( project_t *pProject, const char *pchPlatform, const char *pchPhase, const char *pGameName, const char *pchExtension ) +{ + const char *pProjectFileNamePrefix = m_bTestMode ? "test" : pProject->name.String(); + + m_OutputFilename = pProjectFileNamePrefix; + + if ( pchPlatform && pchPlatform[0] ) + { + // non-pc platforms get decorated + m_OutputFilename += "_"; + m_OutputFilename += pchPlatform; + } + + if( m_bAppendSrvToDedicated ) + { + // Add _srv to the temp lib path. Ie: tier0/obj_tier0_linux32_srv + m_OutputFilename += "_srv"; + } + + if ( pchPhase && pchPhase[0] ) + { + m_OutputFilename += "_"; + m_OutputFilename += pchPhase; + } + + if ( pGameName && pGameName[0] ) + { + // game projects get decorated + m_OutputFilename += "_"; + m_OutputFilename += pGameName; + } + + if ( m_bDecorateProject ) + { + char rgchDecorate[256] = ""; + DecorateProjectName( rgchDecorate ); + m_OutputFilename += rgchDecorate; + } + + if ( pchExtension && pchExtension[0] ) + { + m_OutputFilename += "."; + m_OutputFilename += pchExtension; + } +} + +bool CVPC::BuildTargetProject( IProjectIterator *pIterator, projectIndex_t projectIndex, script_t *pProjectScript, const char *pGameName ) +{ + // evaluate the project's script conditional which determines game/platform + if ( !EvaluateConditionalExpression( pProjectScript->m_condition.String() ) ) + { + // conditionals prevent this project from consideration + return false; + } + + // set once anything is expected to output + m_bAnyProjectQualified = true; + + if ( !m_Projects.IsValidIndex( projectIndex ) ) + { + // unexpected bad project index + Assert( 0 ); + return false; + } + project_t *pProject = &m_Projects[projectIndex]; + + // track the internal project name, unaffected by user name mangling + m_ProjectName = pProject->name.String(); + m_LoadAddressName = pProject->name.String(); + + // win32 projects are the most prevalent, so by popular demand they have no decoration + // all other platforms use their platform name as a suffix + const char *pPlatformName = NULL; + if ( !IsPlatformDefined( "win32" ) ) + { + pPlatformName = GetTargetPlatformName(); + } + + // + // If we're doing multiple build phases, decorate the project + // names to indicate which phase they build in, and always include + // the platform. + // + const char *pPhaseName = NULL; + if ( FindOrCreateConditional( "phase2", false, CONDITIONAL_CUSTOM ) ) + { + pPlatformName = GetTargetPlatformName(); + pPhaseName = "phase2"; + } + else if ( FindOrCreateConditional( "phase1", false, CONDITIONAL_CUSTOM ) ) + { + pPlatformName = GetTargetPlatformName(); + pPhaseName = "phase1"; + } + + // create a decorated project filename based on project/game/platform/etc + CreateOutputFilename( + pProject, + pPlatformName, + pPhaseName, + pGameName, + g_pVPC->GetProjectGenerator()->GetProjectFileExtension() ); + + // each vpc script is written with paths relative to their base + // force each script needs to start relative to their script location + // this allows vpc to be invoked anywhere, but the groups resolve their projects correctly + char szScriptPath[MAX_PATH]; + V_ComposeFileName( g_pVPC->GetStartDirectory(), pProjectScript->name.String(), szScriptPath, sizeof( szScriptPath ) ); + V_StripFilename( szScriptPath ); + m_ProjectPath = szScriptPath; + V_SetCurrentDirectory( szScriptPath ); + + // build it + char szScriptName[MAX_PATH]; + Sys_StripPath( pProjectScript->name.String(), szScriptName ); + return pIterator->VisitProject( projectIndex, szScriptName ); +} + +//----------------------------------------------------------------------------- +// Iterate and build each of the projects. Game projects can themselves be +// auto-iterated to apply each of their mod variant. +//----------------------------------------------------------------------------- +void CVPC::IterateTargetProjects( CUtlVector<projectIndex_t> &projectList, IProjectIterator *pIterator ) +{ + m_bGeneratedProject = false; + m_bAnyProjectQualified = false; + + if ( !projectList.Count() ) + { + // nothing to do + return; + } + + for ( int nProject = 0; nProject < projectList.Count(); nProject++ ) + { + project_t *pProject = &m_Projects[projectList[nProject]]; + + // each project can have 1 or more scripts that are predicated by game/platform conditionals (i.e. client or server) + for ( int nScript = 0; nScript < pProject->scripts.Count(); nScript++ ) + { + script_t *pProjectScript = &pProject->scripts[nScript]; + + // occurrence of game condition(s) dictates iteration behavior + // client/server would have multiple game conditions + bool bHasGameCondition = g_pVPC->ConditionHasDefinedType( pProjectScript->m_condition.String(), CONDITIONAL_GAME ); + + if ( !bHasGameCondition ) + { + // no game condition + BuildTargetProject( pIterator, projectList[nProject], pProjectScript, NULL ); + } + else + { + // auto iterate through all defined game conditionals, setting each in turn + // this provides for building say client for all mod(s) that it can support + for ( int nTargetGame = 0; nTargetGame < m_Conditionals.Count(); nTargetGame++ ) + { + if ( m_Conditionals[nTargetGame].type != CONDITIONAL_GAME || !m_Conditionals[nTargetGame].m_bDefined ) + { + // the game conditions must be defined to be considered + // i.e. the user has specified to build /hl2 /tf2, but not /portal + continue; + } + + // only one game condition is active during project generation + for ( int k = 0; k < m_Conditionals.Count(); k++ ) + { + // unmark all game conditionals + if ( m_Conditionals[k].type == CONDITIONAL_GAME ) + { + m_Conditionals[k].m_bGameConditionActive = false; + } + } + m_Conditionals[nTargetGame].m_bGameConditionActive = true; + + BuildTargetProject( pIterator, projectList[nProject], pProjectScript, m_Conditionals[nTargetGame].name.String() ); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Build all the projects in m_targetProjects. +//----------------------------------------------------------------------------- +bool CVPC::BuildTargetProjects() +{ + class CDefaultProjectIterator : public IProjectIterator + { + public: + virtual bool VisitProject( projectIndex_t iProject, const char *pScriptPath ) + { + Log_Msg( LOG_VPC, "\n" ); + + // check project's crc signature + if ( !g_pVPC->IsForceGenerate() && g_pVPC->IsProjectCurrent( g_pVPC->GetOutputFilename(), true ) && !g_pVPC->IsForceIterate() ) + { + // valid, does not need to build + return false; + } + + return g_pVPC->ParseProjectScript( pScriptPath, 0, false, true ); + } + }; + + if ( !m_TargetProjects.Count() ) + { + VPCError( "No recognized project(s) to build. Use /h or /projects or /groups to spew more info." ); + } + + /* At this point we might've built the project dependency graph, which increments the missing file count + * if *any* project in your VPC directory has a missing file, so we reset it here to get the accurate count. + */ + ResetMissingFilesCount(); + + CDefaultProjectIterator iterator; + IterateTargetProjects( m_TargetProjects, &iterator ); + + if ( GetMissingFilesCount() > 0 ) + { + VPCError( "%d files missing. VPC failed.\n", GetMissingFilesCount() ); + } + + // Catch user attention to notify lack of any expected output + // Novice users would not be aware of expected conditionals + if ( !m_bGeneratedProject && !m_bAnyProjectQualified ) + { + Log_Warning( LOG_VPC, Color( 255, 255, 0, 255 ), "\n" ); + Log_Warning( LOG_VPC, Color( 255, 255, 0, 255 ), "----------------------------\n" ); + Log_Warning( LOG_VPC, Color( 255, 255, 0, 255 ), "!!! No Project Generated !!!\n" ); + Log_Warning( LOG_VPC, Color( 255, 255, 0, 255 ), "----------------------------\n" ); + Log_Warning( LOG_VPC, Color( 255, 255, 0, 255 ), "\n" ); + Log_Warning( LOG_VPC, Color( 255, 255, 0, 255 ), "Possibly missing game, platform, or other conditional expected by script.\n" ); + Log_Warning( LOG_VPC, Color( 255, 255, 0, 255 ), "Use /h verify desired target build set.\n" ); + + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Find the project that corresponds to the specified vcproj and setup +// to build that project. +//----------------------------------------------------------------------------- +void CVPC::FindProjectFromVCPROJ( const char *pScriptNameVCProj ) +{ + // caller is specifying the output vcproj, i.e. via tool shortcut from within MSDEV to re-gen + // use the vpc standardized output vcproj name to determine re-gen parameters + // mod and platform will be seperated by '_' after the project name + // resolve to correct project, best will be longest match, due to project names like foo_? and foo_bar_? + char szProject[MAX_PATH]; + unsigned int bestLen = 0; + for ( int i = 0; i < m_Projects.Count(); i++ ) + { + if ( V_stristr( pScriptNameVCProj, m_Projects[i].name.String() ) ) + { + if ( bestLen < strlen( m_Projects[i].name.String() ) ) + { + bestLen = strlen( m_Projects[i].name.String() ); + strcpy( szProject, m_Projects[i].name.String() ); + } + } + } + if ( bestLen == 0 ) + { + VPCError( "Could not resolve '%s' to any known projects", pScriptNameVCProj ); + } + + // skip past known project + char szBuffer[MAX_PATH]; + V_StripExtension( pScriptNameVCProj + strlen( szProject ), szBuffer, sizeof( szBuffer ) ); + + // each token is seperated by '_' + int numTokens = 0; + char *pToken = szBuffer; + char *pStart = pToken; + char szTokens[2][MAX_PATH]; + while ( numTokens < 2 ) + { + if ( pStart[0] == '_' ) + { + pStart++; + pToken = strchr( pStart, '_' ); + if ( !pToken ) + { + strcpy( szTokens[numTokens++], pStart ); + break; + } + else + { + strncpy( szTokens[numTokens], pStart, pToken-pStart ); + szTokens[numTokens][pToken-pStart] = '\0'; + numTokens++; + pStart = pToken; + } + } + else + { + break; + } + } + + // re-build a commandline + int localArgc = 0; + char *localArgv[16]; + char argBuffers[16][MAX_PATH]; + for ( int i=0; i<V_ARRAYSIZE( localArgv ); i++ ) + { + localArgv[i] = argBuffers[i]; + } + strcpy( localArgv[localArgc++], "vpc.exe" ); + sprintf( localArgv[localArgc++], "+%s", szProject ); + for ( int i=0; i<numTokens; i++ ) + { + sprintf( localArgv[localArgc++], "/%s", szTokens[i] ); + } + + ParseBuildOptions( localArgc, localArgv ); +} + +//----------------------------------------------------------------------------- +// This sets up various defines that are funneled into the .vpc script and the #defines in the engine. +// +// VPC makes a distinction between defines and macros (defines are just binary on/off things that are used like this: +// $File "blah.cpp" [$somedefine] +// +// macros are used for substitutions like this: +// $File "blah.$SOMEMACRO" +//----------------------------------------------------------------------------- +void CVPC::SetMacrosAndConditionals() +{ + // Find the target platform. + conditional_t *pPlatformConditional = NULL; + for ( int i = 0; i < m_Conditionals.Count(); i++ ) + { + if ( m_Conditionals[i].type == CONDITIONAL_PLATFORM && m_Conditionals[i].m_bDefined ) + { + pPlatformConditional = &m_Conditionals[i]; + break; + } + } + + // Only one platform is allowed to be defined. + for ( int i = 0; i < m_Conditionals.Count(); i++ ) + { + if ( &m_Conditionals[i] != pPlatformConditional && m_Conditionals[i].type == CONDITIONAL_PLATFORM && m_Conditionals[i].m_bDefined ) + { + // no no no, the user is not allowed to build multiple platforms simultaneously + // this prior feature really confused/crapped up the code, so absolutely not supporting that + VPCWarning( "Detected multiple target platforms...Disabling '%s'", m_Conditionals[i].name.String() ); + m_Conditionals[i].m_bDefined = false; + } + } + + if ( !pPlatformConditional ) + { + // no user specified platform defined, defaults to primary vpc.exe built platform +#if defined( WIN32 ) + pPlatformConditional = FindOrCreateConditional( "WIN32", false, CONDITIONAL_PLATFORM ); +#elif defined( OSX ) + pPlatformConditional = FindOrCreateConditional( "OSX32", false, CONDITIONAL_PLATFORM ); +#elif defined( LINUX ) + pPlatformConditional = FindOrCreateConditional( "LINUX32", false, CONDITIONAL_PLATFORM ); +#elif defined( CYGWIN ) + pPlatformConditional = FindOrCreateConditional( "CYGWIN", false, CONDITIONAL_PLATFORM ); +#else +#error "Unsupported platform." +#endif + pPlatformConditional->m_bDefined = true; + } + + // Cache the platform name so that we can use it without dereferencing pPlatformConditional + CUtlString cVPCPlatform = pPlatformConditional->name; + // pPlatformConditional is a pointer into a container and it may be + // invalidated by future changes. NULLing the pointer is the only sure + // way to prevent programmers from using the invalid pointer. + pPlatformConditional = NULL; + VPCStatus( true, "Target Platform: %s", cVPCPlatform.String() ); + + // src_main doesn't want this #define because it conflicts with Python's SDK. + // It really should be called something else that won't conflict with the rest of the world. + bool bIncludePlatformDefineInProjects = false; +#ifdef STEAM + bIncludePlatformDefineInProjects = true; +#endif + + SetMacro( "PLATFORM", cVPCPlatform.String(), bIncludePlatformDefineInProjects ); + + // DO NOT INTEGRATE OR TAKE THIS - THIS IS TEMP PORTING GLUE. + // This define will not exist in the Source2 branch. + SetMacro( "SOURCE1", "1", true ); + + // create reserved $QUOTE - used for embedding quotes, or use msdev's " + SetMacro( "QUOTE", "\"", false ); + + if ( !V_stricmp( cVPCPlatform.String(), "WIN32" ) || !V_stricmp( cVPCPlatform.String(), "WIN64" ) || !V_stricmp( cVPCPlatform.String(), "X360" ) ) + { + // VS2010 is strictly win32/xbox360 + switch ( m_eVSVersion ) + { + case k_EVSVersion_2015: + m_ExtraOptionsCRCString += "VS2015"; + SetConditional( "VS2015", true ); + + // temporarily allow VS2013 conditionals also as there are many. Will fix. + SetConditional( "VS2013", true ); + + m_bUseVS2010FileFormat = true; + break; + + case k_EVSVersion_2013: + m_ExtraOptionsCRCString += "VS2013"; + SetConditional( "VS2013", true ); + m_bUseVS2010FileFormat = true; + break; + + case k_EVSVersion_2012: + m_ExtraOptionsCRCString += "VS2012"; + SetConditional( "VS2012", true ); + m_bUseVS2010FileFormat = true; + break; + + case k_EVSVersion_2010: + m_ExtraOptionsCRCString += "VS2010"; + SetConditional( "VS2010", true ); + m_bUseVS2010FileFormat = true; + break; + + case k_EVSVersion_2008: + m_ExtraOptionsCRCString += "VS2008"; + SetConditional( "VS2005", true ); // use 2005 defines + m_bUseVS2010FileFormat = false; + break; + + default: + m_ExtraOptionsCRCString += "VS2005"; + SetConditional( "VS2005", true ); + m_bUseVS2010FileFormat = false; + break; + } + } + + // create and define various other platform related helper conditionals andmacros + if ( V_stricmp( cVPCPlatform.String(), "WIN32" ) == 0 || V_stricmp( cVPCPlatform.String(), "WIN64" ) == 0 ) + { + if ( V_stricmp( cVPCPlatform.String(), "WIN32" ) == 0 ) + { + SetMacro( "PLATSUBDIR", "\\win32", false ); + } + else + { + SetMacro( "PLATSUBDIR", "\\win64", false ); + } + SetConditional( "WINDOWS" ); + + SetMacro( "_DLL_EXT", ".dll", true ); + SetMacro( "_IMPLIB_EXT", ".lib", false ); + + SetMacro( "_IMPLIB_PREFIX", "", false ); + SetMacro( "_IMPLIB_DLL_PREFIX", "", false ); + + SetMacro( "_STATICLIB_PREFIX", "", false ); + SetMacro( "_STATICLIB_EXT", ".lib", false ); + + SetMacro( "_EXE_EXT", ".exe", false ); + + SetMacro( "_EXTERNAL_DLL_EXT", ".dll", true ); + SetMacro( "_EXTERNAL_IMPLIB_EXT", ".lib", false ); + SetMacro( "_EXTERNAL_STATICLIB_EXT", ".lib", false ); + + } + else if ( V_stricmp( cVPCPlatform.String(), "X360" ) == 0 ) + { + SetMacro( "PLATSUBDIR", "\\x360", false ); + + SetMacro( "_DLL_EXT", "_360.dll", true ); + SetMacro( "_IMPLIB_EXT", "_360.lib", false ); + + SetMacro( "_IMPLIB_PREFIX", "", false ); + + SetMacro( "_IMPLIB_DLL_PREFIX", "", false ); + + SetMacro( "_STATICLIB_PREFIX", "", false ); + SetMacro( "_STATICLIB_EXT", "_360.lib", false ); + + SetMacro( "_EXE_EXT", ".exe", false ); + } + else if ( V_stricmp( cVPCPlatform.String(), "PS3" ) == 0 ) + { + SetMacro( "PLATSUBDIR", "\\ps3", false ); + + SetMacro( "_DLL_EXT", "_ps3.sprx", true ); + SetMacro( "_IMPLIB_EXT", "_ps3.lib", false ); + + SetMacro( "_IMPLIB_PREFIX", "", false ); + SetMacro( "_IMPLIB_DLL_PREFIX", "", false ); + + SetMacro( "_STATICLIB_PREFIX", "", false ); + SetMacro( "_STATICLIB_EXT", "_ps3.lib", false ); + + SetMacro( "_EXE_EXT", ".self", false ); + } + else if ( V_stricmp( cVPCPlatform.String(), "LINUX32" ) == 0 || V_stricmp( cVPCPlatform.String(), "LINUX64" ) == 0 ) + { + bool IsLinux32 = ( V_stricmp( cVPCPlatform.String(), "LINUX32" ) == 0 ); + + SetMacro( "PLATSUBDIR", IsLinux32 ? "\\linux32" : "\\linux64", false ); + + SetConditional( "LINUXALL" ); + if ( m_bDedicatedBuild ) + { + SetConditional( "DEDICATED" ); + } + SetConditional( "POSIX" ); + + SetMacro( "LINUX", "1", true ); + SetMacro( "_LINUX", "1", true ); + SetMacro( "POSIX", "1", true ); + SetMacro( "_POSIX", "1", true ); + + const char *str3264 = IsLinux32 ? "" : "64"; + const char *strSrv = m_bAppendSrvToDedicated ? "_srv" : ""; + CFmtStrN<128> strDso( "%s%s.so", strSrv, str3264 ); + CFmtStrN<128> strLib( "%s%s.a", strSrv, str3264 ); + + SetMacro( "_DLL_EXT", strDso.Access(), true ); + SetMacro( "_IMPLIB_EXT", strDso.Access(), false ); + SetMacro( "_STATICLIB_EXT", strLib.Access(), false ); + + // Extensions for external dependencies like libsteam_api.so (not libsteam_api_ds.so). + // VPC_Keyword_Folder in projectscript.cpp will check for ImpLibExternal or LibExternal and + // use these prefixes instead of _ds.so if they exist. + SetMacro( "_EXTERNAL_DLL_EXT", ".so", true ); + SetMacro( "_EXTERNAL_IMPLIB_EXT", ".so", false ); + SetMacro( "_EXTERNAL_STATICLIB_EXT", ".a", false ); + + //SetMacro( "_STATICLIB_PREFIX", "lib", false ); + SetMacro( "_STATICLIB_PREFIX", "", false ); + + SetMacro( "_IMPLIB_PREFIX", "lib", false ); + SetMacro( "_IMPLIB_DLL_PREFIX", "lib", false ); + SetMacro( "_EXE_EXT", "", false ); + SetMacro( "_SYM_EXT", ".dbg", false ); + + SetConditional( "GL" ); + } + else if ( V_stricmp( cVPCPlatform.String(), "OSX32" ) == 0 || V_stricmp( cVPCPlatform.String(), "OSX64" ) == 0 ) + { + if ( V_stricmp( cVPCPlatform.String(), "OSX32" ) == 0 ) + { + SetMacro( "PLATSUBDIR", "\\osx32", false ); + } + else + { + SetMacro( "PLATSUBDIR", "\\osx64", false ); + } + + SetConditional( "OSXALL" ); + if ( m_bDedicatedBuild ) + { + SetConditional( "DEDICATED" ); + } + SetConditional( "POSIX" ); + SetMacro( "_POSIX", "1", true ); + + SetMacro( "_DLL_EXT", ".dylib", true ); + SetMacro( "_IMPLIB_EXT", ".dylib", false ); + + SetMacro( "_IMPLIB_PREFIX", "lib", false ); + SetMacro( "_IMPLIB_DLL_PREFIX", "lib", false ); + + //SetMacro( "_STATICLIB_PREFIX", "lib", false ); + SetMacro( "_STATICLIB_PREFIX", "", false ); + SetMacro( "_STATICLIB_EXT", ".a", false ); + + SetMacro( "_EXE_EXT", "", false ); + SetMacro( "_SYM_EXT", ".dSYM", false ); + + SetMacro( "_EXTERNAL_DLL_EXT", ".dylib", true ); + SetMacro( "_EXTERNAL_IMPLIB_EXT", ".dylib", false ); + SetMacro( "_EXTERNAL_STATICLIB_EXT", ".a", false ); + + // Mac defaults to GL on + SetConditional( "GL" ); + } + else if ( V_stricmp( cVPCPlatform.String(), "IOS" ) == 0 ) + { + SetConditional( "OSXALL" ); + if ( m_bDedicatedBuild ) + { + SetConditional( "DEDICATED" ); + } + SetConditional( "POSIX" ); + SetMacro( "_POSIX", "1", true ); + + SetConditional( "IOS" ); + SetMacro( "_IOS", "1", true ); + SetMacro( "IOS", "1", true ); + + SetMacro( "_DLL_EXT", "_ios.dylib", true ); + SetMacro( "_IMPLIB_EXT", "_ios.dylib", false ); + + SetMacro( "_IMPLIB_PREFIX", "lib", false ); + SetMacro( "_IMPLIB_DLL_PREFIX", "lib", false ); + + //SetMacro( "_STATICLIB_PREFIX", "lib", false ); + SetMacro( "_STATICLIB_PREFIX", "", false ); + SetMacro( "_STATICLIB_EXT", "_ios.a", false ); + + SetMacro( "_EXE_EXT", "", false ); + + SetMacro( "_EXTERNAL_DLL_EXT", "_ios.dylib", true ); + SetMacro( "_EXTERNAL_IMPLIB_EXT", "_ios.dylib", false ); + SetMacro( "_EXTERNAL_STATICLIB_EXT", "_ios.a", false ); + } + else if ( V_stricmp( cVPCPlatform.String(), "ANDROID" ) == 0 ) + { + SetConditional( "LINUXALL" ); + if ( m_bDedicatedBuild ) + { + SetConditional( "DEDICATED" ); + } + SetConditional( "POSIX" ); + SetConditional( "ANDROID" ); + + SetMacro( "LINUX", "1", true ); + SetMacro( "_LINUX", "1", true ); + SetMacro( "POSIX", "1", true ); + SetMacro( "_POSIX", "1", true ); + SetMacro( "ANDROID", "1", true ); + SetMacro( "_ANDROID", "1", true ); + + SetMacro( "_DLL_EXT", "_an.so", true ); + SetMacro( "_IMPLIB_EXT", "_an.so", false ); + + SetMacro( "_IMPLIB_PREFIX", "lib", false ); + SetMacro( "_IMPLIB_DLL_PREFIX", "lib", false ); + + SetMacro( "_STATICLIB_PREFIX", "lib", false ); + SetMacro( "_STATICLIB_EXT", "_an.a", false ); + + SetMacro( "_EXE_EXT", "", false ); + + SetMacro( "_EXTERNAL_DLL_EXT", "_an.so", true ); + SetMacro( "_EXTERNAL_IMPLIB_EXT", "_an.so", false ); + SetMacro( "_EXTERNAL_STATICLIB_EXT", "_an.a", false ); + + // and is a cross-compiled target + SetConditional( "CROSS_COMPILED" ); + SetMacro( "CROSS_COMPILED", "1", true ); + SetMacro( "_CROSS_COMPILED", "1", true ); + + SetConditional( "GL" ); + } + else if ( V_stricmp( cVPCPlatform.String(), "CYGWIN" ) == 0 ) + { + SetMacro( "PLATSUBDIR", "\\cygwin", false ); + + SetConditional( "CYGWIN" ); + SetConditional( "CYGWIN_WINDOWS_TARGET" ); + SetConditional( "DEDICATED" ); + SetConditional( "POSIX" ); + + SetMacro( "CYGWIN", "1", true ); + SetMacro( "_CYGWIN", "1", true ); + SetMacro( "CYGWIN_WINDOWS_TARGET", "1", true ); + SetMacro( "_CYGWIN_WINDOWS_TARGET", "1", true ); + SetMacro( "POSIX", "1", true ); + SetMacro( "_POSIX", "1", true ); + + SetMacro( "_DLL_EXT", ".dll", true ); + SetMacro( "_IMPLIB_EXT", ".dll.a", false ); + + SetMacro( "_IMPLIB_DLL_PREFIX", "", false ); + SetMacro( "_IMPLIB_PREFIX", "lib", false ); + + //SetMacro( "_STATICLIB_PREFIX", "lib", false ); + SetMacro( "_STATICLIB_PREFIX", "", false ); + SetMacro( "_STATICLIB_EXT", ".a", false ); + + SetMacro( "_EXE_EXT", ".exe", false ); + } + + // DO NOT INTEGRATE OR TAKE THIS - THIS IS TEMP PORTING GLUE. + { + // CERT has been decided to be a platform permutation of RETAIL. + // The DOTA S1 scripts are not in a clean enough condition to place this logic there. + // The S2 scripts have it there along with similar common concepts. + conditional_t *pRetailConditional = FindOrCreateConditional( "RETAIL", false, CONDITIONAL_CUSTOM ); + if ( pRetailConditional && pRetailConditional->m_bDefined && ( !V_stricmp( cVPCPlatform.String(), "X360" ) || !V_stricmp( cVPCPlatform.String(), "PS3" ) ) ) + { + // CERT is a restricted console RETAIL concept, with publisher dictated rules, there is no CERT process for non-console platforms. + SetConditional( "CERT" ); + } + } + + + // Set VPCGAME macro based on target game + if ( m_bEnableVpcGameMacro ) + { + int nGameDefineIndex = -1; + for ( int iOtherGameDefine = 0; iOtherGameDefine < m_Conditionals.Count(); ++ iOtherGameDefine ) + { + if ( m_Conditionals[iOtherGameDefine].type == CONDITIONAL_GAME && + m_Conditionals[iOtherGameDefine].m_bDefined ) + { + if ( nGameDefineIndex == -1 ) + { + nGameDefineIndex = iOtherGameDefine; + } + else + { + // uh-oh, multiple games defined for target build + // can't set VPCGAME accurately + nGameDefineIndex = -2; + } + } + } + + SetMacro( "VPCGAME", ( nGameDefineIndex >= 0 ) ? m_Conditionals[nGameDefineIndex].name.Get() : "valve", true ); + SetMacro( "VPCGAMECAPS", ( nGameDefineIndex >= 0 ) ? m_Conditionals[nGameDefineIndex].upperCaseName.Get() : "VALVE", true ); + + // force this into additional CRC string + m_ExtraOptionsCRCString += CFmtStr( "/vpcgame:%s", GetMacroValue( "VPCGAME" ) ); + } +} + + +//----------------------------------------------------------------------------- +// Decorate project name +//----------------------------------------------------------------------------- +void CVPC::DecorateProjectName( char *pchProjectName ) +{ + macro_t *pMacro = g_pVPC->FindOrCreateMacro( "PLATFORM", false, NULL ); + if ( pMacro ) + { + char szPlatform[MAX_PATH]; + sprintf( szPlatform, " (%s)", pMacro->value.String() ); + strcat( pchProjectName, szPlatform ); + } + + const char *pchDecorate = g_pVPC->GetDecorateString(); + if ( pchDecorate && V_strlen( pchDecorate ) > 0 ) + { + strcat( pchProjectName, pchDecorate ); + } +} + + +//----------------------------------------------------------------------------- +// Checks for command line /params ( +/- used for projects, so ICommandLine() not suitable) +//----------------------------------------------------------------------------- +bool CVPC::HasCommandLineParameter( const char *pParamName ) +{ + for ( int i=1; i < m_nArgc; i++ ) + { + if ( V_stricmp( m_ppArgv[i], pParamName ) == 0 ) + return true; + } + return false; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CVPC::HasP4SLNCommand() +{ + return HasCommandLineParameter( "/p4sln" ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CVPC::HandleP4SLN( IBaseSolutionGenerator *pSolutionGenerator ) +{ +#ifdef WIN32 + // If they want to generate a solution based on a Perforce changelist, adjust m_targetProjects and set it up like /mksln had been passed in. + if ( m_iP4Changelists.Count() == 0 ) + return false; + + if ( !pSolutionGenerator ) + { + VPCError( "No solution generator exists for this platform." ); + } + + // Figure out where to put the solution file. + char szFullSolutionPath[MAX_PATH]; + if ( V_IsAbsolutePath( m_P4SolutionFilename.Get() ) ) + { + V_strncpy( szFullSolutionPath, m_P4SolutionFilename.Get(), sizeof( szFullSolutionPath ) ); + } + else + { + V_ComposeFileName( g_pVPC->GetStartDirectory(), m_P4SolutionFilename.Get(), szFullSolutionPath, sizeof( szFullSolutionPath ) ); + } + + CProjectDependencyGraph dependencyGraph; + GenerateSolutionForPerforceChangelist( dependencyGraph, m_iP4Changelists, pSolutionGenerator, szFullSolutionPath ); + return true; +#else + return false; +#endif +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CVPC::GetProjectDependencies( CUtlVector<CDependency_Project *> &referencedProjects ) +{ + bool bInSlnPass = m_bInMkSlnPass; + + m_bInMkSlnPass = true; + + // Find out what depends on what. + if ( !m_dependencyGraph.HasGeneratedDependencies() ) + { + m_dependencyGraph.BuildProjectDependencies( 0, m_pPhase1Projects ); + } + + // GenerateBuildSet basically generates what we want, except it uses projectIndex_t's, meaning that + // we don't know what subset of games we should use until we've called VPC_IterateTargetProjects. + m_dependencyGraph.TranslateProjectIndicesToDependencyProjects( m_TargetProjects, referencedProjects ); + + m_bInMkSlnPass = bInSlnPass; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CVPC::HandleMKSLN( IBaseSolutionGenerator *pSolutionGenerator ) +{ + if ( m_MKSolutionFilename.IsEmpty() ) + { + return; + } + + m_bInMkSlnPass = true; + + if ( !pSolutionGenerator ) + { + VPCError( "No solution generator exists for this platform." ); + } + + // Find out what depends on what. + if ( !m_dependencyGraph.HasGeneratedDependencies() ) + { + m_dependencyGraph.BuildProjectDependencies( 0 ); + } + + // GenerateBuildSet basically generates what we want, except it uses projectIndex_t's, meaning that + // we don't know what subset of games we should use until we've called VPC_IterateTargetProjects. + CUtlVector<CDependency_Project*> referencedProjects; + m_dependencyGraph.TranslateProjectIndicesToDependencyProjects( m_TargetProjects, referencedProjects ); + + // Generate a solution file. + char szFullSolutionPath[MAX_PATH]; + if ( V_IsAbsolutePath( m_MKSolutionFilename.Get() ) ) + { + V_strncpy( szFullSolutionPath, m_MKSolutionFilename.Get(), sizeof( szFullSolutionPath ) ); + } + else + { + V_ComposeFileName( g_pVPC->GetStartDirectory(), m_MKSolutionFilename.Get(), szFullSolutionPath, sizeof( szFullSolutionPath ) ); + } + + if ( m_pPhase1Projects != NULL ) + { + referencedProjects.AddVectorToTail( *m_pPhase1Projects ); + } + + pSolutionGenerator->GenerateSolutionFile( szFullSolutionPath, referencedProjects ); + + m_bInMkSlnPass = false; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CVPC::SetupGenerators() +{ + extern IBaseSolutionGenerator *GetSolutionGenerator_Win32(); + extern IBaseProjectGenerator *GetWin32ProjectGenerator(); + extern IBaseProjectGenerator *GetWin32ProjectGenerator_2010(); + extern IBaseProjectGenerator *GetPS3ProjectGenerator(); + extern IBaseProjectGenerator *GetXbox360ProjectGenerator(); + extern IBaseProjectGenerator *GetXbox360ProjectGenerator_2010(); + extern IBaseProjectGenerator *GetMakefileProjectGenerator(); + extern IBaseSolutionGenerator *GetMakefileSolutionGenerator(); + extern IBaseProjectGenerator *GetXcodeProjectGenerator(); + extern IBaseSolutionGenerator *GetXcodeSolutionGenerator(); + + bool bIsLinux = IsPlatformDefined( "LINUX32" ) || IsPlatformDefined( "LINUX64" ); + bool bIsOSX = IsPlatformDefined( "OSX32" ) || IsPlatformDefined( "OSX64" ); + +#if defined( WIN32 ) + // Under Windows we have the ability to generate makefiles so if they specified a linux config, + // or if they're building the (non-SRCDS) dedicated server, then use the makefile generator + conditional_t *pConditional = FindOrCreateConditional( "DEDICATED", false, CONDITIONAL_CUSTOM ); + + bool bUseMakefile = bIsLinux || ( pConditional && pConditional->m_bDefined ); + bool bUseXcode = bIsOSX; + + if ( bUseMakefile ) + { + Log_Msg( LOG_VPC, "\n** Detected Linux platform. Using Makefile generator.\n" ); + } + + if ( bUseMakefile ) + { + m_pProjectGenerator = GetMakefileProjectGenerator(); + m_pSolutionGenerator = GetMakefileSolutionGenerator(); + } + else if ( bUseXcode ) + { + m_pProjectGenerator = GetXcodeProjectGenerator(); + m_pSolutionGenerator = GetXcodeSolutionGenerator(); + m_bForceIterate = true; + } + else + { + if ( IsPlatformDefined( "PS3" ) ) + { + m_pProjectGenerator = GetPS3ProjectGenerator(); + m_pSolutionGenerator = GetSolutionGenerator_Win32(); + } + else if ( IsPlatformDefined( "X360" ) ) + { + if ( m_bUseVS2010FileFormat ) + { + Log_Msg( LOG_VPC, Color( 0, 255, 255, 255 ), "Generating for Visual Studio 2010.\n" ); + m_pProjectGenerator = GetXbox360ProjectGenerator_2010(); + } + else + { + m_pProjectGenerator = GetXbox360ProjectGenerator(); + } + m_pSolutionGenerator = GetSolutionGenerator_Win32(); + } + else + { + // spew what we are generating + const char *pchLogLine = "Generating for Visual Studio 2005.\n"; + if ( m_eVSVersion == k_EVSVersion_2015 ) + pchLogLine = "Generating for Visual Studio 2015.\n"; + else if ( m_eVSVersion == k_EVSVersion_2013 ) + pchLogLine = "Generating for Visual Studio 2013.\n"; + else if ( m_eVSVersion == k_EVSVersion_2012 ) + pchLogLine = "Generating for Visual Studio 2012.\n"; + else if ( m_eVSVersion == k_EVSVersion_2010 ) + pchLogLine = "Generating for Visual Studio 2010.\n"; + + Log_Msg( LOG_VPC, Color( 0, 255, 255, 255 ), pchLogLine ); + + // pick a project generator + if ( m_bUseVS2010FileFormat ) + m_pProjectGenerator = GetWin32ProjectGenerator_2010(); + else + m_pProjectGenerator = GetWin32ProjectGenerator(); + + m_pSolutionGenerator = GetSolutionGenerator_Win32(); + } + } +#else + if ( bIsLinux ) + { + // Linux always uses the makefile project generator. + m_pProjectGenerator = GetMakefileProjectGenerator(); + m_pSolutionGenerator = GetMakefileSolutionGenerator(); + } + if ( bIsOSX ) + { + m_pProjectGenerator = GetXcodeProjectGenerator(); + m_pSolutionGenerator = GetXcodeSolutionGenerator(); + } +#endif +} + + +//----------------------------------------------------------------------------- +// Since Steam's VPC builds tier0 and vstdlib directly in, Steam uses vpc.exe as the CRC checker. +// Source uses vpccrccheck.exe to do this. +//----------------------------------------------------------------------------- +void CVPC::InProcessCRCCheck() +{ + for ( int i = 1; i<m_nArgc; i++ ) + { + if ( !V_stricmp( m_ppArgv[i], "-crc" ) || !V_stricmp( m_ppArgv[i], "-crc2" ) ) + { + // caller wants the crc check only + int ret = VPC_CommandLineCRCChecks( m_nArgc, m_ppArgv ); + exit( ret ); + } + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +const char *CVPC::BuildTempGroupScript( const char *pVPCScriptName ) +{ + char projectName[MAX_PATH]; + V_StripExtension( pVPCScriptName, projectName, sizeof( projectName ) ); + + char szCurrentDirectory[MAX_PATH]; + V_GetCurrentDirectory( szCurrentDirectory, sizeof( szCurrentDirectory ) ); + + // caller is specifying an explicit VPC, i.e. not a project from the default group + // create a temporary group file that mimics a VGC, that points to the current dir's VPC + + // Generate a really crappy temp filename + uint32 tmpHash = rand(); + for ( const char *c = pVPCScriptName ; *c ; ++c ) + tmpHash = tmpHash * 257 + *c; + uint32 tmpTime = time( NULL ); + + char tempGroupScriptFilename[MAX_PATH]; + V_ComposeFileName( szCurrentDirectory, CFmtStr( "%08x%08xvgc.tmp", tmpHash, tmpTime ), tempGroupScriptFilename, sizeof( tempGroupScriptFilename ) ); + m_TempGroupScriptFilename = tempGroupScriptFilename; + + // build the temp group script + FILE *fp = fopen( m_TempGroupScriptFilename.Get(), "w+t" ); + if ( !fp ) + { + VPCError( "Could not open temp file '%s'. Tell a Programmer.\n", m_TempGroupScriptFilename.Get() ); + } + + char vpcScriptFilename[MAX_PATH]; + V_ComposeFileName( szCurrentDirectory, pVPCScriptName, vpcScriptFilename, sizeof( vpcScriptFilename ) ); + + // the actual vpc must be relative to the source path + const char *pVPCFilename = StringAfterPrefix( vpcScriptFilename, m_SourcePath.Get() ); + if ( !pVPCFilename ) + { + VPCError( "Script %s is not in source path %s\n", vpcScriptFilename, m_SourcePath.Get() ); + } + + if ( pVPCFilename[0] == '\\' ) + { + pVPCFilename++; + } + + fprintf( fp, "$Project \"%s\"\n", projectName ); + fprintf( fp, "{\n" ); + fprintf( fp, "\"%s\"\n", pVPCFilename ); + fprintf( fp, "}\n" ); + fclose( fp ); + + // fake a build command + char buildCommand[MAX_PATH]; + V_snprintf( buildCommand, sizeof( buildCommand ), "+%s", projectName ); + int index = m_BuildCommands.AddToTail(); + m_BuildCommands[index] = buildCommand; + + return m_TempGroupScriptFilename.Get(); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int CVPC::ProcessCommandLine() +{ + SetupDefaultConditionals(); + + DetermineSourcePath(); + + // possible extensions determine operation mode beyond expected normal user case + bool bScriptIsVGC = false; + bool bScriptIsVPC = false; + bool bScriptIsVCProj = false; + bool bHasBuildCommand = false; + const char *pScriptName = NULL; + const char *pScriptNameVCProj = NULL; + + for ( int i = 1; i < m_nArgc; i++ ) + { + const char *pArg = m_ppArgv[i]; + if ( V_stristr( pArg, ".vgc" ) ) + { + // caller explicitly providing group + pScriptName = pArg; + bScriptIsVGC = true; + bHasBuildCommand = true; + break; + } + else if ( V_stristr( pArg, ".vpc" ) ) + { + // caller is using a local vpc, i.e. one that is not hooked into the groups + pScriptName = pArg; + bScriptIsVPC = true; + bHasBuildCommand = true; + break; + } + else + { + if ( V_stristr( pArg, ".vcproj" ) || V_stristr( pArg, ".vcxproj" ) ) + { + // caller wants to re-gen the vcproj, this is commonly used by MSDEV to re-gen + pScriptNameVCProj = pArg; + bScriptIsVCProj = true; + bHasBuildCommand = true; + break; + } + } + } + + for ( int i = 1; i < m_nArgc; i++ ) + { + if ( m_ppArgv[i][0] == '-' || m_ppArgv[i][0] == '+' || m_ppArgv[i][0] == '*' || m_ppArgv[i][0] == '@' ) + { + bHasBuildCommand = true; + break; + } + } + + if ( bScriptIsVPC ) + { + pScriptName = BuildTempGroupScript( pScriptName ); + bScriptIsVPC = false; + bScriptIsVGC = true; + } + + if ( !bScriptIsVGC ) + { + // no script, use default group + pScriptName = "vpc_scripts\\default.vgc"; + bScriptIsVGC = true; + } + + // set the current directory, it is to be expected src, i.e. .\vpc_scripts\.. + SetDefaultSourcePath(); + + char szCurrentDirectory[MAX_PATH]; + V_GetCurrentDirectory( szCurrentDirectory, sizeof( szCurrentDirectory ) ); + m_StartDirectory = szCurrentDirectory; + + // parse and build tables from group script that options will reference + if ( bScriptIsVGC ) + { + VPC_ParseGroupScript( pScriptName ); + } + + if ( bScriptIsVCProj ) + { + // this is commonly used as an extern tool in MSDEV to re-vpc in place + // caller is msdev providing the vcproj name, solve to determine which project and generate + FindProjectFromVCPROJ( pScriptNameVCProj ); + } + else + { + ParseBuildOptions( m_nArgc, m_ppArgv ); + } + + // set macros and conditionals derived from command-line options + SetMacrosAndConditionals(); + + // generate a CRC string derived from command-line options + GenerateOptionsCRCString(); + + SetupGenerators(); + + // filter user's build commands + // generate list of build targets + CProjectDependencyGraph dependencyGraph; + GenerateBuildSet( dependencyGraph ); + + if ( !bHasBuildCommand && !HasP4SLNCommand() ) + { + // spew usage + m_bUsageOnly = true; + } + + if ( m_bUsageOnly ) + { + // spew only + SpewUsage(); + return 0; + } + +#ifdef WIN32 + if ( HandleP4SLN( m_pSolutionGenerator ) ) + { + return 0; + } +#endif + + // iterate and build target projects + if ( !BuildTargetProjects() ) + { + // build failure + return 0; + } + + // now that we have valid project files, can generate solution + HandleMKSLN( m_pSolutionGenerator ); + + return 0; +} + +//----------------------------------------------------------------------------- +// main +// +//----------------------------------------------------------------------------- + +// VPC is a DLL in Source. +#if defined(STANDALONE_VPC) || defined(OSX) || defined(LINUX) +int main( int argc, char **argv ) +#else +int vpcmain( int argc, char **argv ) +#endif +{ + bool bWindowsTwoPhase = false; + + for ( int i = 0; i < argc; i++ ) + { + if ( V_stricmp( "/windows", argv[i] ) == 0 ) + { + bWindowsTwoPhase = true; + break; + } + } + + int nRetVal; + g_pVPC = new CVPC(); + + if ( bWindowsTwoPhase ) + { + // + // We're going to do some grotesque hackery by manipulating + // the command line arguments. + // + // First we're going to generate a VPC object to generate all the + // 32-bit .vcxproj files but not write a solution file. Then + // we'll run it for the 64-bit .vcxproj files, then write a solution + // file containing both (if a solution file was requested). + // + // To accomplish this, subtract the /windows parameter (and /MKSLN if present), run, extract + // the list of generated project files, add a /WIN64 (and put /MKSLN back if necessary) + // and pass in the generated project file list. + // + bool bBuildSolution = false; + char szSolutionFile[_MAX_PATH]; + nRetVal = -1; + + char *newargs[128] = { NULL }; + int cParms = 0; + + // + // Do the 32-bit VPC, capturing the list of project files produced. + // + Assert( argc <= V_ARRAYSIZE( newargs ) ); + for ( int i = 0; i < argc; i++ ) + { + char *pszArg = argv[i]; + + if ( !V_stricmp( pszArg, "/windows" ) || !V_stricmp( pszArg, "/dp" ) ) + { + // Skip + } + else if ( !V_stricmp( pszArg, "/mksln" ) && ( i + 1 < argc ) ) + { + // If the next parameter is a standard + or - or / or * parameter, then we take that to be the name of the solution file. + // So vpc /mksln +engine would generate engine.sln. + if ( argv[i+1][0] == '+' || argv[i+1][0] == '-' || argv[i+1][0] == '/' || argv[i+1][0] == '*' || argv[i+1][0] == '@' ) + { + V_strncpy( szSolutionFile, &argv[i + 1][1], sizeof(szSolutionFile) ); + } + else + { + V_strncpy( szSolutionFile, argv[i + 1], sizeof(szSolutionFile) ); + i++; + } + bBuildSolution = true; + + } + else + { + newargs[ cParms++ ] = pszArg; + } + } + + // + // Add a /dp parameter to decorate the 32-bit project names with (win32). This + // makes it easier to differentiate between projects in the solution explorer. + // + newargs[ cParms++ ] = "/dp"; + + // + // Add a define for PHASE1 for any VPC files that need to be aware of that sort + // of thing. + // + newargs[ cParms++ ] = "/define:PHASE1"; + + if ( !g_pVPC->Init( cParms, newargs ) ) + { + return 0; + } + + nRetVal = g_pVPC->ProcessCommandLine(); + + if ( nRetVal != 0 ) + { + return nRetVal; + } + + // + // Grab a list of all the project files that got generated by this pass, + // we will stuff these into the solution file later. If we aren't + // building a solution, then don't bother. + // + CUtlVector<CDependency_Project*> referencedProjects; + if ( bBuildSolution ) + { + g_pVPC->GetProjectDependencies( referencedProjects ); + } + + // + // Now reconstruct the command line with the 64-bit flag and the solution file added + // back in. + // + // Decrement cParms to eat the /dp and /define we added before. + // + cParms--; + cParms--; + newargs[ cParms++ ] = "/win64"; + + // + // Add a define for PHASE2 for any VPC files that need to be aware of that sort + // of thing. Example: Projects that generate headers-only and are not bitness + // specific. + // + newargs[ cParms++ ] = "/define:PHASE2"; + + if ( bBuildSolution ) + { + newargs[ cParms++ ] = "/mksln"; + newargs[ cParms++ ] = szSolutionFile; + } + + g_pVPC->Shutdown(); + delete g_pVPC; + g_pVPC = new CVPC(); + + if ( !g_pVPC->Init( cParms, newargs ) ) + { + return 0; + } + + if ( bBuildSolution ) + { + g_pVPC->SetPhase1Projects( &referencedProjects ); + } + + nRetVal = g_pVPC->ProcessCommandLine(); + } + else + { + if ( !g_pVPC->Init( argc, argv ) ) + { + return 0; + } + + nRetVal = g_pVPC->ProcessCommandLine(); + } + + g_pVPC->Shutdown(); + + return nRetVal; +} + +// VPC is a DLL in Source. +#if !(defined(STANDALONE_VPC) || defined(OSX) || defined(LINUX)) +#include "ilaunchabledll.h" + +// VPC is launched by vpc.exe, which is a copy of binlaunch.exe. +// All binlaunch does is setup the path to game\bin and load an ILaunchableDLL +// interface out of a DLL with the same name as the exe. +class CVPCLaunchableDLL : public ILaunchableDLL +{ +public: + // All vpc.exe does is load the vpc DLL and run this. + virtual int main( int argc, char **argv ) + { + return vpcmain( argc, argv ); + } +}; + +EXPOSE_SINGLE_INTERFACE( CVPCLaunchableDLL, ILaunchableDLL, LAUNCHABLE_DLL_INTERFACE_VERSION ); +#endif + + diff --git a/external/vpc/utils/vpc/p4sln.cpp b/external/vpc/utils/vpc/p4sln.cpp new file mode 100644 index 0000000..6b23a21 --- /dev/null +++ b/external/vpc/utils/vpc/p4sln.cpp @@ -0,0 +1,273 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#include "vpc.h" +#include "p4lib/ip4.h" + +// fix filenames that have double backslashes at the start +// (Perforce will return this if the root of a clientspec is e.g. "D:\") +static const char* FixPerforceFilename( const char *filename ) +{ + if ( filename && V_strlen( filename ) > 2 && !V_strnicmp( filename + 1, ":\\\\", 3 ) ) + { + // strip out the first backslash + static char newFilename[MAX_PATH]; + V_snprintf( newFilename, sizeof(newFilename), "%c:%s", + filename[0], + &filename[3] + ); + + return newFilename; + } + return filename; +} + +static void GetChangelistFilenames( CUtlVector<int> &changelists, CUtlVector<CUtlString> &changelistFilenames ) +{ + // P4 interface didn't initalize in main - abort + if ( !p4 ) + { + g_pVPC->VPCWarning( "P4SLN: Perforce interface not available. Unable to generate solution from the given Perforce changelist." ); + return; + } + + CUtlVector<P4File_t> fileList; + int changeListIndex = 0; + if ( changelists.Count() ) + { + changeListIndex = changelists[0]; + } + if ( changeListIndex == -1 ) + { + p4->GetOpenedFileList( fileList, false ); + } + else if ( changeListIndex == 0 ) + { + p4->GetOpenedFileList( fileList, true ); + } + else + { + CUtlVector<P4File_t> partialFileList; + + FOR_EACH_VEC( changelists, i ) + { + p4->GetFileListInChangelist( changelists[i], partialFileList ); + + FOR_EACH_VEC( partialFileList, j ) + { + fileList.AddToTail( partialFileList[j] ); + } + } + } + + // If -1 is in the changelist index, then include all. + bool bIncludeAllChangelists = ( changelists.Find( -1 ) != changelists.InvalidIndex() ); + + for ( int i=0; i < fileList.Count(); i++ ) + { + if ( bIncludeAllChangelists || changelists.Find( fileList[i].m_iChangelist ) != changelists.InvalidIndex() ) + { + const char *pFilename = p4->String( fileList[i].m_sLocalFile ); + + const char *pNewFilename = FixPerforceFilename( pFilename ); + + changelistFilenames.AddToTail( pNewFilename ); + } + } +} + +static void AddAdditionalDependencies( CUtlVector<CDependency_Project*> &projects, CUtlVector<CDependency_Project*> &allProjects ) +{ + for ( int nProject=0; nProject < projects.Count(); nProject++ ) + { + CDependency_Project *pCurProject = projects[nProject]; + + // Look at all the $AdditionalProjectDependencies projects for this one. + for ( int nDependency=0; nDependency < pCurProject->m_AdditionalProjectDependencies.Count(); nDependency++ ) + { + const char *pLookingFor = pCurProject->m_AdditionalProjectDependencies[nDependency].String(); + + // Search for a match in allProjects. + int nFound = CDependency_Project::FindByProjectName( allProjects, pLookingFor ); + if ( nFound == -1 ) + { + g_pVPC->VPCError( "P4SLN: Project %s lists '%s' in its $AdditionalProjectDependencies, but there is no project by that name.", pCurProject->GetName(), pLookingFor ); + } + else + { + // Got a match. + CDependency_Project *pFound = allProjects[nFound]; + int nTest = projects.Find( pFound ); + if ( nTest == projects.InvalidIndex() ) + { + projects.AddToTail( pFound ); + } + } + } + } +} + +static void GetProjectsDependingOnFiles( CProjectDependencyGraph &dependencyGraph, CUtlVector<CUtlString> &filenames, CUtlVector<CDependency_Project*> &projects ) +{ + // Now figure out the projects that depend on each of these files. + for ( int iFile=0; iFile < filenames.Count(); iFile++ ) + { + CDependency *pFile = dependencyGraph.FindDependency( filenames[iFile].String() ); + if ( !pFile ) + { + char szRelative[MAX_PATH]; + if ( !V_MakeRelativePath( filenames[iFile].String(), g_pVPC->GetSourcePath(), szRelative, sizeof( szRelative ) ) ) + { + V_strncpy( szRelative, filenames[iFile].String(), sizeof( szRelative ) ); + } + + // This probably means their build commands on the command line didn't include + // any projects that included this file. + g_pVPC->VPCWarning( "%s is not found in the projects searched.", szRelative ); + continue; + } + + // Now see which projects depend on this file. + for ( int iProject=0; iProject < dependencyGraph.m_Projects.Count(); iProject++ ) + { + CDependency_Project *pProject = dependencyGraph.m_Projects[iProject]; + + if ( pProject->DependsOn( pFile, k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse | k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckAdditionalDependencies ) ) + { + if ( projects.Find( pProject ) == -1 ) + projects.AddToTail( pProject ); + } + } + } + + // generate the group restrictions + // the user can explicitly provide a set of groups to narrow the wide dependency target + CUtlVector< CUtlString > groupRestrictions; + groupRestrictions = g_pVPC->m_P4GroupRestrictions; + if ( !groupRestrictions.Count() ) + { + // the default restriction is to the "everything" group + groupRestrictions.AddToTail( "everything" ); + } + + CUtlVector< projectIndex_t > allowedProjectIndices; + if ( groupRestrictions.Count() ) + { + // get all of the allowed projects by iterating the restrict-to-groups + for ( int i = 0; i < groupRestrictions.Count(); i++ ) + { + CUtlVector< projectIndex_t > projectIndices; + if ( !g_pVPC->GetProjectsInGroup( projectIndices, groupRestrictions[i].Get() ) ) + { + g_pVPC->VPCError( "No projects found in group '%s'.", groupRestrictions[i].Get() ); + } + + // aggregate into wider list + for ( int j = 0; j < projectIndices.Count(); j++ ) + { + allowedProjectIndices.AddToTail( projectIndices[j] ); + } + } + } + + // Make sure that each of the dependent projects are members of the restricted groups, otherwise prevent their inclusion. + CUtlVector< int > doomedProjectIndices; + if ( allowedProjectIndices.Count() ) + { + for ( int j = 0; j < projects.Count(); j++ ) + { + // find the target project in the allowed set + if ( allowedProjectIndices.Find( projects[j]->m_iProjectIndex ) == allowedProjectIndices.InvalidIndex() ) + { + // the target project is not in the allowed set + // add in descending order so indices can be properly removed below from largest index to smallest + doomedProjectIndices.AddToHead( j ); + } + } + + // Remove the projects that are not part of the restrict-to-groups + // Indexes were added in descending order, so removal is actually from the end, truncating the set + for ( int j = 0; j < doomedProjectIndices.Count(); j++ ) + { + projects.Remove( doomedProjectIndices[j] ); + } + } +} + + +static void UpdateProjects( CUtlVector<CDependency_Project*> &projects ) +{ + for ( int iProject=0; iProject < projects.Count(); iProject++ ) + { + Log_Msg( LOG_VPC, "\n" ); + + CDependency_Project *pDependency = projects[iProject]; + pDependency->ExportProjectParameters(); + + if ( g_pVPC->IsForceGenerate() || !g_pVPC->IsProjectCurrent( g_pVPC->GetOutputFilename(), true ) ) + { + project_t *pProject = &g_pVPC->m_Projects[ pDependency->m_iProjectIndex ]; + g_pVPC->SetProjectName( pProject->name.String() ); + g_pVPC->SetLoadAddressName( pProject->name.String() ); + + g_pVPC->ParseProjectScript( pDependency->m_szStoredScriptName, 0, false, true ); + } + } +} + +class CStringCaseLess +{ +public: + bool Less( const char *lhs, const char *rhs, void *pCtx ) + { + return ( V_stricmp( lhs, rhs ) < 0 ? true : false ); + } +}; + +void GenerateSolutionForPerforceChangelist( CProjectDependencyGraph &dependencyGraph, CUtlVector<int> &changelists, IBaseSolutionGenerator *pGenerator, const char *pSolutionFilename ) +{ + // We want to check against ALL projects in projects.vgc. + int nDepFlags = BUILDPROJDEPS_FULL_DEPENDENCY_SET | BUILDPROJDEPS_CHECK_ALL_PROJECTS; + dependencyGraph.BuildProjectDependencies( nDepFlags ); + + // Get the list of files from Perforce. + CUtlVector<CUtlString> filenames; + GetChangelistFilenames( changelists, filenames ); + + // Get the list of projects that depend on these files. + CUtlVector<CDependency_Project*> projects; + GetProjectsDependingOnFiles( dependencyGraph, filenames, projects ); + + // Add g_targetProjects, which will include any other projects that they added on the command line with +tier0 *engine syntax. + CUtlVector<CDependency_Project*> commandLineProjects; + dependencyGraph.TranslateProjectIndicesToDependencyProjects( g_pVPC->m_TargetProjects, commandLineProjects ); + for ( int i=0; i < commandLineProjects.Count(); i++ ) + { + if ( projects.Find( commandLineProjects[i] ) == projects.InvalidIndex() ) + projects.AddToTail( commandLineProjects[i] ); + } + + // Make sure the latest .vcproj files are generated. + UpdateProjects( projects ); + + // List the projects. + CUtlSortVector< CUtlString, CStringCaseLess > sortedProjectNames; + for ( int i=0; i < projects.Count(); i++ ) + { + sortedProjectNames.InsertNoSort( projects[i]->GetName() ); + } + sortedProjectNames.RedoSort(); + + Msg( "Dependent projects: \n\n" ); + for ( int i=0; i < sortedProjectNames.Count(); i++ ) + { + Msg( "%s\n", sortedProjectNames[i].Get() ); + } + + // Write the solution file. + pGenerator->GenerateSolutionFile( pSolutionFilename, projects ); +} + diff --git a/external/vpc/utils/vpc/p4sln.h b/external/vpc/utils/vpc/p4sln.h new file mode 100644 index 0000000..70cea10 --- /dev/null +++ b/external/vpc/utils/vpc/p4sln.h @@ -0,0 +1,17 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef P4SLN_H +#define P4SLN_H +#ifdef _WIN32 +#pragma once +#endif + + +void GenerateSolutionForPerforceChangelist( CProjectDependencyGraph &dependencyGraph, CUtlVector<int> &changelists, IBaseSolutionGenerator *pGenerator, const char *pSolutionFilename ); + + +#endif // P4SLN_H diff --git a/external/vpc/utils/vpc/projectgenerator_codelite.cpp b/external/vpc/utils/vpc/projectgenerator_codelite.cpp new file mode 100644 index 0000000..aae6660 --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_codelite.cpp @@ -0,0 +1,156 @@ +//====== Copyright 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#include "vpc.h" +#include "projectgenerator_codelite.h" + +#ifdef WIN32 +#include <direct.h> +#define mkdir(dir, mode) _mkdir(dir) +#define getcwd _getcwd +#endif + +static const char *k_pchSource = "Source Files"; +static const char *k_pchHeaders = "Header Files"; +static const char *k_pchResources = "Resources"; +static const char *k_pchVPCFiles = "VPC Files"; + +void CProjectGenerator_CodeLite::GenerateCodeLiteProject( CBaseProjectDataCollector *pCollector, const char *pOutFilename, const char *pMakefileFilename ) +{ + char szProjectFile[MAX_PATH]; + sprintf( szProjectFile, "%s.project", pOutFilename ); + + g_pVPC->VPCStatus( true, "Saving CodeLite project for: '%s' File: '%s'", pCollector->GetProjectName().String(), szProjectFile ); + + m_fp = fopen( szProjectFile, "wt" ); + + m_nIndent = 0; + m_pCollector = pCollector; + m_pMakefileFilename = pMakefileFilename; + + Write( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" ); + Write( "<CodeLite_Project Name=\"%s\" InternalType=\"\">\n", pCollector->GetProjectName().String() ); + { + ++m_nIndent; + Write( "<Description/>\n" ); + Write( "<Dependencies/>\n" ); + Write( "<Settings Type=\"Dynamic Library\">\n" ); + { + ++m_nIndent; + Write( "<GlobalSettings>\n" ); + ++m_nIndent; + Write( "<Compiler Options=\"\" C_Options=\"\">\n" ); + ++m_nIndent; + Write( "<IncludePath Value=\"\"/>\n" ); + --m_nIndent; + Write( "</Compiler>\n" ); + Write( "<Linker Options=\"\">\n" ); + ++m_nIndent; + Write( "<LibraryPath Value=\"\"/>\n" ); + --m_nIndent; + Write( "</Linker>\n" ); + Write( "<ResourceCompiler Options=\"\"/>\n" ); + --m_nIndent; + Write( "</GlobalSettings>\n" ); + Write( "<Configuration Name=\"Debug\" CompilerType=\"gnu g++\" DebuggerType=\"GNU gdb debugger\" Type=\"Dynamic Library\" BuildCmpWithGlobalSettings=\"append\" BuildLnkWithGlobalSettings=\"append\" BuildResWithGlobalSettings=\"append\">\n" ); + { + ++m_nIndent; + Write( "<CustomBuild Enabled=\"yes\">\n" ); + { + ++m_nIndent; + Write( "<RebuildCommand>make CFG=debug -f %s clean all</RebuildCommand>\n", pMakefileFilename ); + Write( "<CleanCommand>make CFG=debug -f %s clean</CleanCommand>\n", pMakefileFilename ); + Write( "<BuildCommand>make CFG=debug -f %s -j `getconf _NPROCESSORS_ONLN`</BuildCommand>\n", pMakefileFilename ); + Write( "<WorkingDirectory>$(ProjectPath)</WorkingDirectory>\n" ); + --m_nIndent; + } + Write( "</CustomBuild>\n" ); + --m_nIndent; + } + Write( "</Configuration>\n" ); + + Write( "<Configuration Name=\"Release\" CompilerType=\"gnu g++\" DebuggerType=\"GNU gdb debugger\" Type=\"Dynamic Library\" BuildCmpWithGlobalSettings=\"append\" BuildLnkWithGlobalSettings=\"append\" BuildResWithGlobalSettings=\"append\">\n" ); + { + ++m_nIndent; + Write( "<CustomBuild Enabled=\"yes\">\n" ); + { + ++m_nIndent; + Write( "<RebuildCommand>make -f %s clean all</RebuildCommand>\n", pMakefileFilename ); + Write( "<CleanCommand>make -f %s clean</CleanCommand>\n", pMakefileFilename ); + Write( "<BuildCommand>make -f %s -j `getconf _NPROCESSORS_ONLN`</BuildCommand>\n", pMakefileFilename ); + Write( "<WorkingDirectory>$(ProjectPath)</WorkingDirectory>\n" ); + --m_nIndent; + } + Write( "</CustomBuild>\n" ); + --m_nIndent; + } + Write( "</Configuration>\n" ); + --m_nIndent; + } + Write( "</Settings>\n" ); + + { + ++m_nIndent; + WriteFilesFolder( k_pchSource, "*.c;*.C;*.cc;*.cpp;*.cp;*.cxx;*.c++;*.prg;*.pas;*.dpr;*.asm;*.s;*.bas;*.java;*.cs;*.sc;*.e;*.cob;*.html;*.rc;*.tcl;*.py;*.pl;*.m;*.mm" ); + WriteFilesFolder( k_pchHeaders, "*.h;*.H;*.hh;*.hpp;*.hxx;*.inc;*.sh;*.cpy;*.if" ); + WriteFilesFolder( k_pchResources, "*.plist;*.strings;*.xib" ); + WriteFilesFolder( k_pchVPCFiles, "*.vpc" ); + --m_nIndent; + } + --m_nIndent; + } + Write( "</CodeLite_Project>\n" ); + fclose( m_fp ); +} + +void CProjectGenerator_CodeLite::WriteFilesFolder( const char *pFolderName, const char *pExtensions ) { + CUtlVector<char*> extensions; + V_SplitString( pExtensions, ";", extensions ); + + Write( "<VirtualDirectory Name=\"%s\">\n", pFolderName ); + { + ++m_nIndent; + for ( int i=m_pCollector->m_Files.First(); i != m_pCollector->m_Files.InvalidIndex(); i=m_pCollector->m_Files.Next( i ) ) { + const char *pFilename = m_pCollector->m_Files[i]->GetName(); + + // Make sure this file's extension is one of the extensions they're asking for. + bool bValidExt = false; + const char *pFileExtension = V_GetFileExtension( pFilename ); + if ( pFileExtension ) { + for ( int iExt=0; iExt < extensions.Count(); iExt++ ) { + const char *pTestExt = extensions[iExt]; + + if ( pTestExt[0] == '*' && pTestExt[1] == '.' && V_stricmp( pTestExt+2, pFileExtension ) == 0 ) { + bValidExt = true; + break; + } + } + } + + if ( bValidExt ) { + char sFixedSlashes[MAX_PATH]; + V_strncpy( sFixedSlashes, pFilename, sizeof( sFixedSlashes ) ); + Write( "<File Name=\"%s\"/>\n", sFixedSlashes ); + } + } + --m_nIndent; + } + Write( "</VirtualDirectory>\n"); +} + +void CProjectGenerator_CodeLite::Write( const char *pMsg, ... ) { + char sOut[8192]; + + va_list marker; + va_start( marker, pMsg ); + V_vsnprintf( sOut, sizeof( sOut ), pMsg, marker ); + va_end( marker ); + + for ( int i=0; i < m_nIndent; i++ ) + fprintf( m_fp, " " ); + + fprintf( m_fp, "%s", sOut ); +} diff --git a/external/vpc/utils/vpc/projectgenerator_codelite.h b/external/vpc/utils/vpc/projectgenerator_codelite.h new file mode 100644 index 0000000..6f81e56 --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_codelite.h @@ -0,0 +1,51 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef PROJECTGENERATOR_CODELITE_H +#define PROJECTGENERATOR_CODELITE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "baseprojectdatacollector.h" + +class CProjectGenerator_CodeLite +{ +public: + + void GenerateCodeLiteProject( CBaseProjectDataCollector *pCollector, const char *pOutFilename, const char *pMakefileFilename ); + +private: + + void Write( const char *pMsg, ... ); + void WriteHeader(); + void WriteFileReferences(); + void WriteProject( const char *pchMakefileName ); + void WriteBuildFiles(); + void WriteBuildConfigurations(); + void WriteLegacyTargets( const char *pchMakefileName ); + void WriteTrailer(); + void WriteConfig( CSpecificConfig *pConfig ); + void WriteTarget_Build( CSpecificConfig *pConfig ); + void WriteTarget_Compile( CSpecificConfig *pConfig ); + void WriteTarget_Rebuild( CSpecificConfig *pConfig ); + void WriteTarget_Link( CSpecificConfig *pConfig ); + void WriteTarget_Debug( CSpecificConfig *pConfig ); + void WriteIncludes( CSpecificConfig *pConfig ); + void WriteFilesFolder( const char *pFolderName, const char *pExtensions ); + void WriteFiles(); + +private: + CBaseProjectDataCollector *m_pCollector; + FILE *m_fp; + const char *m_pMakefileFilename; + int m_nIndent; +}; + + + +#endif // PROJECTGENERATOR_CODELITE_H diff --git a/external/vpc/utils/vpc/projectgenerator_makefile.cpp b/external/vpc/utils/vpc/projectgenerator_makefile.cpp new file mode 100644 index 0000000..07f995b --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_makefile.cpp @@ -0,0 +1,1127 @@ +//====== Copyright 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#include "vpc.h" +#include "baseprojectdatacollector.h" +#include "tier1/utlstack.h" +#include "projectgenerator_codelite.h" + +static const char *k_pszBase_Makefile = "$(SRCROOT)/devtools/makefile_base_posix.mak"; + +static const char *g_pOption_BufferSecurityCheck = "$BufferSecurityCheck"; +static const char *g_pOption_CustomBuildStepCommandLine = "$CustomBuildStep/$CommandLine"; +static const char *g_pOption_PostBuildEventCommandLine = "$PostBuildEvent/$CommandLine"; +static const char *g_pOption_CompileAs = "$CompileAs"; +static const char *g_pOption_ConfigurationType = "$ConfigurationType"; +static const char *g_pOption_Description = "$Description"; +static const char *g_pOption_EntryPoint = "$EntryPoint"; +static const char *g_pOption_ExtraCompilerFlags = "$GCC_ExtraCompilerFlags"; +static const char *g_pOption_ExtraLinkerFlags = "$GCC_ExtraLinkerFlags"; +static const char *g_pOption_CustomVersionScript = "$GCC_CustomVersionScript"; +static const char *g_pOption_ForceInclude = "$ForceIncludes"; +static const char *g_pOption_IgnoreAllDefaultLibraries = "$IgnoreAllDefaultLibraries"; +static const char *g_pOption_LocalFrameworks = "$LocalFrameworks"; +static const char *g_pOption_LowerCaseFileNames = "$LowerCaseFileNames"; +static const char *g_pOption_OptimizerLevel = "$OptimizerLevel"; +static const char *g_pOption_AdditionalDependencies = "$AdditionalDependencies"; +static const char *g_pOption_Outputs = "$Outputs"; +static const char *g_pOption_PrecompiledHeader = "$Create/UsePrecompiledHeader"; +static const char *g_pOption_PrecompiledHeaderFile = "$PrecompiledHeaderFile"; +static const char *g_pOption_SymbolVisibility = "$SymbolVisibility"; +static const char *g_pOption_SystemFrameworks = "$SystemFrameworks"; +static const char *g_pOption_SystemLibraries = "$SystemLibraries"; +static const char *g_pOption_UsePCHThroughFile = "$Create/UsePCHThroughFile"; +static const char *g_pOption_TargetCopies = "$TargetCopies"; +static const char *g_pOption_TreatWarningsAsErrors = "$TreatWarningsAsErrors"; + +// These are the only properties we care about for makefiles. +static const char *g_pRelevantProperties[] = +{ + g_pOption_AdditionalIncludeDirectories, + g_pOption_CompileAs, + g_pOption_OptimizerLevel, + g_pOption_OutputFile, + g_pOption_GameOutputFile, + g_pOption_SymbolVisibility, + g_pOption_PreprocessorDefinitions, + g_pOption_ConfigurationType, + g_pOption_ImportLibrary, + g_pOption_PrecompiledHeader, + g_pOption_UsePCHThroughFile, + g_pOption_PrecompiledHeaderFile, + g_pOption_CustomBuildStepCommandLine, + g_pOption_PostBuildEventCommandLine, + g_pOption_AdditionalDependencies, + g_pOption_Outputs, + g_pOption_Description, + g_pOption_SystemLibraries, + g_pOption_SystemFrameworks, + g_pOption_LocalFrameworks, + g_pOption_ExtraCompilerFlags, + g_pOption_ExtraLinkerFlags, + g_pOption_CustomVersionScript, + g_pOption_EntryPoint, + g_pOption_IgnoreAllDefaultLibraries, + g_pOption_BufferSecurityCheck, + g_pOption_ForceInclude, + g_pOption_TargetCopies, + g_pOption_TreatWarningsAsErrors, + g_pOption_LowerCaseFileNames, +}; + + +static CRelevantPropertyNames g_RelevantPropertyNames = +{ + g_pRelevantProperties, + V_ARRAYSIZE( g_pRelevantProperties ) +}; + +void MakeFriendlyProjectName( char *pchProject ); + +void V_MakeAbsoluteCygwinPath( char *pOut, int outLen, const char *pRelativePath ) +{ + // While generating makefiles under Win32, we must translate drive letters like c:\ + // to Cygwin-style paths like /cygdrive/c/ +#ifdef _WIN32 + char tmp[MAX_PATH]; + V_MakeAbsolutePath( tmp, sizeof( tmp ), pRelativePath ); + V_FixSlashes( tmp, '/' ); + + if ( tmp[0] != 0 && tmp[1] == ':' && tmp[2] == '/' ) + { + // Ok, this is an absolute path + V_snprintf( pOut, outLen, "/cygdrive/%c/", tmp[0] ); + V_strncat( pOut, &tmp[3], outLen ); + } + else +#endif // _WIN32 + { + V_MakeAbsolutePath( pOut, outLen, pRelativePath ); + V_RemoveDotSlashes( pOut ); + } +} + +// caller is responsible for free'ing (or leaking) the allocated buffer +static const char* UsePOSIXSlashes( const char *pStr ) +{ + int len = V_strlen( pStr ) + 2; + char *str = (char*)malloc(len*sizeof(char)); + V_strncpy( str, pStr, len ); + for ( int i = 0; i < len; i++ ) + { + if ( str[i] == '\\' ) + { + // allow escaping of bash special characters + if ( i+1 < len && ( str[i+1] != '"' && str[i+1] != '$' && + str[i+1] != '\'' && str[i+1] != '\\' ) ) + str[i] = '/'; + } + if ( str[i] == '\0' ) + break; + } + return str; +} + + +// pExt should be the bare extension without the . in front. i.e. "h", "cpp", "lib". +static inline bool CheckExtension( const char *pFilename, const char *pExt ) +{ + Assert( pExt[0] != '.' ); + + int nFilenameLen = V_strlen( pFilename ); + int nExtensionLen = V_strlen( pExt ); + + return (nFilenameLen > nExtensionLen && pFilename[nFilenameLen-nExtensionLen-1] == '.' && V_stricmp( &pFilename[nFilenameLen-nExtensionLen], pExt ) == 0 ); +} + + +static bool CheckExtensions( const char *pFilename, const char **ppExtensions ) +{ + for ( int i=0; ppExtensions[i] != NULL; i++ ) + { + if ( CheckExtension( pFilename, ppExtensions[i] ) ) + return true; + } + return false; +} + + +static void GetObjFilenameForFile( const char *pConfigName, const char *pFilename, char *pOut, int maxLen ) +{ + char sBaseFilename[MAX_PATH]; + V_FileBase( pFilename, sBaseFilename, sizeof( sBaseFilename ) ); + //V_strlower( sBaseFilename ); + + // We had .cxx files -> .oxx, but this macro: + // GENDEP_CXXFLAGS = -MD -MP -MF $(@:.o=.P) + // was turning into -MF blah.oxx, which led to blah.oxx containing the file dependencies. + // This obviously failed to link. Quick fix is to just have .cxx -> .o like everything else. + //$ const char *pObjExtension = (CheckExtension( pFilename, "cxx" ) ? "oxx" : "o"); + const char *pObjExtension = "o"; + + V_snprintf( pOut, maxLen, "$(OBJ_DIR)/%s.%s", sBaseFilename, pObjExtension ); +} + + +// This class drastically accelerates looking up which file creates which precompiled header. +class CPrecompiledHeaderAccel +{ +public: + void Setup( CUtlDict<CFileConfig*,int> &files, CFileConfig *pBaseConfig ) + { + for ( int i=files.First(); i != files.InvalidIndex(); i=files.Next( i ) ) + { + CFileConfig *pFile = files[i]; + + for ( int iSpecific=pFile->m_Configurations.First(); iSpecific != pFile->m_Configurations.InvalidIndex(); iSpecific=pFile->m_Configurations.Next( iSpecific ) ) + { + CSpecificConfig *pSpecific = pFile->m_Configurations[iSpecific]; + if ( pSpecific->m_bFileExcluded ) + continue; + + // Does this file create a precompiled header? + const char *pPrecompiledHeaderOption = pSpecific->GetOption( g_pOption_PrecompiledHeader ); + if ( pPrecompiledHeaderOption && V_stristr( pPrecompiledHeaderOption, "Create" ) ) + { + // Ok, which header do we scan through? + const char *pUsePCHThroughFile = pSpecific->GetOption( g_pOption_UsePCHThroughFile ); + if ( !pUsePCHThroughFile ) + { + g_pVPC->VPCError( "File %s creates a precompiled header in config %s but no UsePCHThroughFile option specified.", pFile->m_Filename.String(), pSpecific->GetConfigName() ); + } + + char sLookup[1024]; + V_snprintf( sLookup, sizeof( sLookup ), "%s__%s", pSpecific->GetConfigName(), pUsePCHThroughFile ); + + if ( m_Lookup.Find( sLookup ) != m_Lookup.InvalidIndex() ) + { + g_pVPC->VPCError( "File %s has UsePCHThroughFile of %s but another file already does.", pFile->m_Filename.String(), pUsePCHThroughFile ); + } + + m_Lookup.Insert( sLookup, pFile ); + } + } + } + } + + CFileConfig* FindFileThatCreatesPrecompiledHeader( const char *pConfigName, const char *pUsePCHThroughFile ) + { + char sLookup[1024]; + V_snprintf( sLookup, sizeof( sLookup ), "%s__%s", pConfigName, pUsePCHThroughFile ); + + int i = m_Lookup.Find( sLookup ); + if ( i == m_Lookup.InvalidIndex() ) + return NULL; + else + return m_Lookup[i]; + } + +private: + // This indexes whatever file creates a certain precompiled header for a certain config. + // These are indexed as <config name>_<pchthroughfile>. + // So an entry might look like release_cbase.h + CUtlDict<CFileConfig*,int> m_Lookup; +}; + + + +class CProjectGenerator_Makefile : public CBaseProjectDataCollector +{ +public: + + typedef CBaseProjectDataCollector BaseClass; + + CProjectGenerator_Makefile() : BaseClass( &g_RelevantPropertyNames ) + { + } + + virtual void Setup() + { + } + + virtual const char* GetProjectFileExtension() + { + return "mak"; + } + + virtual void EndProject() + { + const char *pMakefileFilename = g_pVPC->GetOutputFilename(); + + CUtlString strProjectName = GetProjectName(); + bool bProjectIsCurrent = g_pVPC->IsProjectCurrent( pMakefileFilename, false ); + if ( g_pVPC->IsForceGenerate() || !bProjectIsCurrent ) + { + g_pVPC->VPCStatus( true, "Saving makefile project for: '%s' File: '%s'", strProjectName.String(), g_pVPC->GetOutputFilename() ); + WriteMakefile( pMakefileFilename ); + } + + const char *pTargetPlatformName = g_pVPC->GetTargetPlatformName(); + if ( !pTargetPlatformName ) + g_pVPC->VPCError( "GetTargetPlatformName failed." ); + + if ( !V_stricmp( pTargetPlatformName, "LINUX32" ) || !V_stricmp( pTargetPlatformName, "LINUX64" ) ) + { + if ( g_pVPC->IsForceGenerate() || !bProjectIsCurrent ) + { + // Write a CodeLite project as well. + char sFilename[MAX_PATH]; + V_StripExtension( g_pVPC->GetOutputFilename(), sFilename, sizeof( sFilename ) ); + CProjectGenerator_CodeLite codeLiteGenerator; + codeLiteGenerator.GenerateCodeLiteProject( this, sFilename, pMakefileFilename ); + } + Term(); + } + else + { + Term(); + } + } + + void WriteSourceFilesList( FILE *fp, const char *pListName, const char **pExtensions, const char *pConfigName ) + { + fprintf( fp, "%s= \\\n", pListName ); + for ( int i=m_Files.First(); i != m_Files.InvalidIndex(); i=m_Files.Next(i) ) + { + CFileConfig *pFileConfig = m_Files[i]; + if ( pFileConfig->IsExcludedFrom( pConfigName ) ) + continue; + + const char *pFilename = m_Files[i]->m_Filename.String(); + if ( CheckExtensions( pFilename, pExtensions ) ) + { + if ( m_bForceLowerCaseFileName ) + fprintf( fp, " %s \\\n", UsePOSIXSlashes( V_strlower((char *)pFilename) ) ); + else + fprintf( fp, " %s \\\n", UsePOSIXSlashes( pFilename ) ); + } + } + fprintf( fp, "\n\n" ); + } + + void WriteNonConfigSpecificStuff( FILE *fp ) + { + fprintf( fp, "ifneq \"$(LINUX_TOOLS_PATH)\" \"\"\n" ); + fprintf( fp, "TOOL_PATH = $(LINUX_TOOLS_PATH)/\n" ); + fprintf( fp, "endif\n\n" ); + + // NAME + char szName[256]; + V_strncpy( szName, m_ProjectName.String(), sizeof(szName) ); + MakeFriendlyProjectName( szName ); + fprintf( fp, "NAME=%s\n", szName ); + + // SRCDIR + char sSrcRootRelative[MAX_PATH]; + g_pVPC->ResolveMacrosInString( "$SRCDIR", sSrcRootRelative, sizeof( sSrcRootRelative ) ); + + fprintf( fp, "SRCROOT=%s\n", UsePOSIXSlashes( sSrcRootRelative ) ); + + // TargetPlatformName + const char *pTargetPlatformName; + // forestw: if PLATFORM macro exists we should use its value, this accommodates overrides of PLATFORM in .vpc files + macro_t *pMacro = g_pVPC->FindOrCreateMacro( "PLATFORM", false, NULL ); + if ( pMacro ) + pTargetPlatformName = pMacro->value.String(); + else + pTargetPlatformName = g_pVPC->GetTargetPlatformName(); + if ( !pTargetPlatformName ) + g_pVPC->VPCError( "GetTargetPlatformName failed." ); + fprintf( fp, "TARGET_PLATFORM=%s\n", pTargetPlatformName ); + fprintf( fp, "TARGET_PLATFORM_EXT=%s\n", g_pVPC->IsDedicatedBuild() ? "_srv" : "" ); + fprintf( fp, "USE_VALVE_BINDIR=%s\n", ( g_pVPC->UseValveBinDir() ? "1" : "0" ) ); + + fprintf( fp, "PWD:=$(shell $(TOOL_PATH)pwd)\n" ); + + + // Select debug config if no config is specified. + fprintf( fp, "# If no configuration is specified, \"release\" will be used.\n" ); + fprintf( fp, "ifeq \"$(CFG)\" \"\"\n" ); + fprintf( fp, "\tCFG = release\n" ); + fprintf( fp, "endif\n\n" ); + } + + struct Filename_t + { + char szFilename[MAX_PATH]; + int iBasename; + }; + + class FileSortSortFunc + { + public: + bool Less( const CFileConfig * const & src1, const CFileConfig * const & src2, void *pCtx ) + { + return src1->m_nInsertOrder < src2->m_nInsertOrder; + } + }; + + void WriteVpcMacroDefines( CSpecificConfig *pConfig, FILE *fp ) + { + // Add VPC macros marked to become defines. + CUtlVector< macro_t* > macroDefines; + g_pVPC->GetMacrosMarkedForCompilerDefines( macroDefines ); + for ( int i=0; i < macroDefines.Count(); i++ ) + { + macro_t *pMacro = macroDefines[i]; + fprintf( fp, "-D%s=%s ", pMacro->name.String(), pMacro->value.String() ); + } + } + + void WriteConfigSpecificStuff( CSpecificConfig *pConfig, FILE *fp, CPrecompiledHeaderAccel *pAccel, CSpecificConfig *pConfig1 ) + { + KeyValues *pKV = pConfig->m_pKV; + + // If we've got a pConfig1, then that means pConfig0 == pConfig1, except for $PreprocessorDefinitions. So don't special + // case anything other than that one section. + if( !pConfig1 ) + { + fprintf( fp, "#\n#\n# CFG=%s\n#\n#\n\n", pConfig->GetConfigName() ); + fprintf( fp, "ifeq \"$(CFG)\" \"%s\"\n\n", pConfig->GetConfigName() ); + } + + // GCC_ExtraCompilerFlags + // Hopefully, they don't ever need to use backslashes because we're turning them into forward slashes here. + // If that does become a problem, we can put some token around the pathnames we need to be fixed up and leave the rest alone. + fprintf( fp, "GCC_ExtraCompilerFlags=%s\n", UsePOSIXSlashes( pKV->GetString( g_pOption_ExtraCompilerFlags, "" ) ) ); + + // GCC_ExtraLinkerFlags + fprintf( fp, "GCC_ExtraLinkerFlags=%s\n", pKV->GetString( g_pOption_ExtraLinkerFlags, "" ) ); + + // GCC_CustomVersionScript + fprintf( fp, "GCC_CustomVersionScript=%s\n", pKV->GetString( g_pOption_CustomVersionScript, "" ) ); + + // EntryPoint + fprintf( fp, "EntryPoint=%s\n", pKV->GetString( g_pOption_EntryPoint, "" ) ); + + // IgnoreAllDefaultLibraries + fprintf( fp, "IgnoreAllDefaultLibraries=%s\n", pKV->GetString( g_pOption_IgnoreAllDefaultLibraries, "no" ) ); + + // BufferSecurityCheck + fprintf( fp, "BufferSecurityCheck=%s\n", pKV->GetString( g_pOption_BufferSecurityCheck, "Yes" ) ); + + // SymbolVisibility + fprintf( fp, "SymbolVisibility=%s\n", pKV->GetString( g_pOption_SymbolVisibility, "hidden" ) ); + + // TreatWarningsAsErrors + fprintf( fp, "TreatWarningsAsErrors=%s\n", pKV->GetString( g_pOption_TreatWarningsAsErrors, "false" ) ); + + // OptimizerLevel + fprintf( fp, "OptimizerLevel=%s\n", pKV->GetString( g_pOption_OptimizerLevel, "$(SAFE_OPTFLAGS_GCC_422)" ) ); + + // system libraries + { + fprintf( fp, "SystemLibraries=" ); + { + CSplitString libs( pKV->GetString( g_pOption_SystemLibraries ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < libs.Count(); i++ ) + { + fprintf( fp, "-l%s ", libs[i] ); + } + } + if ( !V_stricmp( g_pVPC->GetTargetPlatformName(), "OSX32" ) || !V_stricmp( g_pVPC->GetTargetPlatformName(), "OSX64" ) ) + { + char rgchFrameworkCompilerFlags[1024]; rgchFrameworkCompilerFlags[0] = '\0'; + CSplitString systemFrameworks( pKV->GetString( g_pOption_SystemFrameworks ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < systemFrameworks.Count(); i++ ) + { + fprintf( fp, "-framework %s ", systemFrameworks[i] ); + } + CSplitString localFrameworks( pKV->GetString( g_pOption_LocalFrameworks ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < localFrameworks.Count(); i++ ) + { + char rgchFrameworkName[MAX_PATH]; + V_StripExtension( V_UnqualifiedFileName( localFrameworks[i] ), rgchFrameworkName, sizeof( rgchFrameworkName ) ); + V_StripFilename( localFrameworks[i] ); + fprintf( fp, "-F%s ", localFrameworks[i] ); + fprintf( fp, "-framework %s ", rgchFrameworkName ); + strcat( rgchFrameworkCompilerFlags, "-F" ); + strcat( rgchFrameworkCompilerFlags, localFrameworks[i] ); + } + fprintf( fp, "\n" ); + if ( rgchFrameworkCompilerFlags[0] ) + // the colon here is important - and should probably get percolated to more places in our generated + // makefiles - it means to perform the assignment once, rather than at evaluation time + fprintf( fp, "GCC_ExtraCompilerFlags:=$(GCC_ExtraCompilerFlags) %s\n", rgchFrameworkCompilerFlags ); + } + else + fprintf( fp, "\n" ); + } + + macro_t *pMacro = g_pVPC->FindOrCreateMacro( "_DLL_EXT", false, NULL ); + if ( pMacro ) + fprintf( fp, "DLL_EXT=%s\n", pMacro->value.String() ); + + pMacro = g_pVPC->FindOrCreateMacro( "_SYM_EXT", false, NULL ); + if ( pMacro ) + fprintf( fp, "SYM_EXT=%s\n", pMacro->value.String() ); + + // ForceIncludes + { + CSplitString outStrings( pKV->GetString( g_pOption_ForceInclude ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + fprintf( fp, "FORCEINCLUDES= " ); + for ( int i=0; i < outStrings.Count(); i++ ) + { + if ( V_strlen( outStrings[i] ) > 2 ) + fprintf( fp, "-include %s ", UsePOSIXSlashes( outStrings[i] ) ); + } + } + fprintf( fp, "\n" ); + + // DEFINES + if( !pConfig1 ) + { + CSplitString outStrings( pKV->GetString( g_pOption_PreprocessorDefinitions ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + fprintf( fp, "DEFINES= " ); + for ( int i=0; i < outStrings.Count(); i++ ) + { + fprintf( fp, "-D%s ", outStrings[i] ); + } + + WriteVpcMacroDefines( pConfig, fp ); + fprintf( fp, "\n" ); + } + else + { + // pConfig0 and pConfig1 are the same other than this section. So write just this one out something like: + // ifeq "$(CFG)" "debug" + // DEFINES += -DDEBUG -D_DEBUG -DPOSIX ... + // else + // DEFINES += -DNDEBUG -DPOSIX ... + // endif + fprintf( fp, "ifeq \"$(CFG)\" \"%s\"\n", pConfig->GetConfigName() ); + + CSplitString outStrings0( pKV->GetString( g_pOption_PreprocessorDefinitions ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + fprintf( fp, "DEFINES += " ); + for ( int i=0; i < outStrings0.Count(); i++ ) + { + fprintf( fp, "-D%s ", outStrings0[i] ); + } + WriteVpcMacroDefines( pConfig, fp ); + + fprintf( fp, "\nelse\n" ); + + CSplitString outStrings1( pConfig1->m_pKV->GetString( g_pOption_PreprocessorDefinitions ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + fprintf( fp, "DEFINES += " ); + for ( int i=0; i < outStrings1.Count(); i++ ) + { + fprintf( fp, "-D%s ", outStrings1[i] ); + } + WriteVpcMacroDefines( pConfig1, fp ); + + fprintf( fp, "\nendif\n" ); + } + + // INCLUDEDIRS + { + CSplitString outStrings( pKV->GetString( g_pOption_AdditionalIncludeDirectories ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + fprintf( fp, "INCLUDEDIRS += " ); + for ( int i=0; i < outStrings.Count(); i++ ) + { + char sDir[MAX_PATH]; + V_strncpy( sDir, outStrings[i], sizeof( sDir ) ); + if ( !V_stricmp( sDir, "$(IntDir)" ) ) + V_strncpy( sDir, "$(OBJ_DIR)", sizeof( sDir ) ); + + V_FixSlashes( sDir, '/' ); + fprintf( fp, "%s ", sDir ); + } + fprintf( fp, "\n" ); + } + // CONFTYPE + if ( V_stristr( pKV->GetString( g_pOption_ConfigurationType ), "dll" ) ) + { + fprintf( fp, "CONFTYPE=dll\n" ); + + // Write ImportLibrary for dll (so) builds. + const char *pRelative = pKV->GetString( g_pOption_ImportLibrary, "" ); + fprintf( fp, "IMPORTLIBRARY=%s\n", UsePOSIXSlashes( pRelative ) ); + } + else if ( V_stristr( pKV->GetString( g_pOption_ConfigurationType ), "lib" ) ) + { + fprintf( fp, "CONFTYPE=lib\n" ); + } + else if ( V_stristr( pKV->GetString( g_pOption_ConfigurationType ), "exe" ) ) + { + fprintf( fp, "CONFTYPE=exe\n" ); + } + else + { + fprintf( fp, "CONFTYPE=***UNKNOWN***\n" ); + } + + // GameOutputFile is where it copies OutputFile to. + fprintf( fp, "GAMEOUTPUTFILE=%s\n", UsePOSIXSlashes( pKV->GetString( g_pOption_GameOutputFile, "" ) ) ); + + // TargetCopies are where OutputFile copies are placed. + fprintf( fp, "TARGETCOPIES=%s\n", UsePOSIXSlashes( pKV->GetString( g_pOption_TargetCopies, "" ) ) ); + + // OutputFile is where it builds to. + char szFixedOutputFile[MAX_PATH]; + V_strncpy( szFixedOutputFile, pKV->GetString( g_pOption_OutputFile ), sizeof( szFixedOutputFile ) ); + V_FixSlashes( szFixedOutputFile, '/' ); + // This file uses a custom build step. + char sFormattedOutputFile[MAX_PATH]; + char szAbsPath[MAX_PATH]; + V_MakeAbsolutePath( szAbsPath, sizeof(szAbsPath), szFixedOutputFile ); + DoStandardVisualStudioReplacements( szFixedOutputFile, szAbsPath, sFormattedOutputFile, sizeof( sFormattedOutputFile ) ); + + fprintf( fp, "OUTPUTFILE=%s\n", sFormattedOutputFile ); + + fprintf( fp, "\n\n" ); + + // post build event + char rgchPostBuildCommand[2048]; rgchPostBuildCommand[0] = '\0'; + if ( pKV->GetString( g_pOption_PostBuildEventCommandLine, NULL ) ) + { + V_strncpy( rgchPostBuildCommand, pKV->GetString( g_pOption_PostBuildEventCommandLine, NULL ), sizeof( rgchPostBuildCommand ) ); + // V_StripPrecedingAndTrailingWhitespace( rgchPostBuildCommand ); + } + if ( V_strlen( rgchPostBuildCommand ) ) + fprintf( fp, "POSTBUILDCOMMAND=%s\n", UsePOSIXSlashes( rgchPostBuildCommand ) ); + else + fprintf( fp, "POSTBUILDCOMMAND=/bin/true\n" ); + + fprintf( fp, "\n\n" ); + + + // Write all the filenames. + const char *sSourceFileExtensions[] = { "cpp", "cxx", "cc", "c", "mm", NULL }; + fprintf( fp, "\n" ); + WriteSourceFilesList( fp, "CPPFILES", (const char**)sSourceFileExtensions, pConfig->GetConfigName() ); + + // LIBFILES + char sImportLibraryFile[MAX_PATH]; + const char *pRelative = pKV->GetString( g_pOption_ImportLibrary, "" ); + V_strncpy( sImportLibraryFile, UsePOSIXSlashes( pRelative ), sizeof( sImportLibraryFile ) ); + V_RemoveDotSlashes( sImportLibraryFile ); + + char sOutputFile[MAX_PATH]; + const char *pOutputFile = pKV->GetString( g_pOption_OutputFile, "" ); + V_strncpy( sOutputFile, UsePOSIXSlashes( pOutputFile ), sizeof( sOutputFile ) ); + V_RemoveDotSlashes( sOutputFile ); + + fprintf( fp, "LIBFILES = \\\n" ); + + // Get original order the link files were specified in the .vpc files. See: + // http://stackoverflow.com/questions/45135/linker-order-gcc + // TL;DR. Gcc does a single pass through the list of libraries to resolve references. + // If library A depends on symbols in library B, library A should appear first so we + // need to restore the original order to allow users to control link order via + // their .vpc files. + CUtlSortVector< CFileConfig *, FileSortSortFunc > OriginalSort; + + for ( int i=m_Files.First(); i != m_Files.InvalidIndex(); i=m_Files.Next(i) ) + { + CFileConfig *pFileConfig = m_Files[i]; + OriginalSort.InsertNoSort( pFileConfig ); + } + OriginalSort.RedoSort(); + + + CUtlVector< Filename_t > ImportLib; + CUtlVector< Filename_t > StaticLib; + + for ( int i=0; i < OriginalSort.Count(); i++ ) + { + CFileConfig *pFileConfig = OriginalSort[i]; + if ( pFileConfig->IsExcludedFrom( pConfig->GetConfigName() ) ) + continue; + + Filename_t Filename; + + Filename.iBasename = 0; + + V_strncpy( Filename.szFilename, UsePOSIXSlashes( pFileConfig->m_Filename.String() ), sizeof( Filename.szFilename ) ); + const char *pFilename = Filename.szFilename; + if ( IsLibraryFile( pFilename ) ) + { + char *pchFileName = (char*)V_strrchr( pFilename, '/' ) + 1; + if (( !sImportLibraryFile[0] || V_stricmp( sImportLibraryFile, pFilename )) && // only link this as a library if it isn't our own output! + ( !sOutputFile[0] || V_stricmp( sOutputFile, pFilename))) + { + char szExt[32]; + V_ExtractFileExtension( pFilename, szExt, sizeof(szExt) ); + if (!( !V_stricmp( g_pVPC->GetTargetPlatformName(), "OSX32" ) || !V_stricmp( g_pVPC->GetTargetPlatformName(), "OSX64" ) ) && + IsLibraryFile( pFilename ) && (pchFileName-1) && pchFileName[0] == 'l' && pchFileName[1] == 'i' && pchFileName[2] == 'b' + && szExt[0] != 'a' ) // its a lib ext but not an archive file, link like a library + { + *(pchFileName-1) = 0; + + // Cygwin import libraries use ".dll.a", so get rid of any file extensions here. + char *pExt; + while ( 1 ) + { + pExt = (char*)V_strrchr( pchFileName, '.' ); + if ( !pExt || V_strrchr( pchFileName, '/' ) > pExt || V_strrchr( pchFileName, '\\' ) > pExt ) + break; + + *pExt = 0; + } + + // +3 to dodge the lib ext + Filename.iBasename = ( pchFileName - pFilename ) + 3; + ImportLib.AddToTail( Filename ); + } + else + { + StaticLib.AddToTail( Filename ); + } + } + } + } + + // Spew static libs out first, then import libraries. Otherwise things like bsppack + // will fail to link because libvstdlib.so came before tier1.a. + for( int i = 0; i < StaticLib.Count(); i++ ) + { + fprintf( fp, " %s \\\n", StaticLib[ i ].szFilename ); + } + for( int i = 0; i < ImportLib.Count(); i++ ) + { + fprintf( fp, " -L%s -l%s \\\n", ImportLib[ i ].szFilename, &ImportLib[ i ].szFilename[ ImportLib[ i ].iBasename ] ); // +3 to dodge the lib ext + } + + fprintf( fp, "\n\n" ); + + fprintf( fp, "LIBFILENAMES = \\\n" ); + for ( int i=m_Files.First(); i != m_Files.InvalidIndex(); i=m_Files.Next(i) ) + { + CFileConfig *pFileConfig = m_Files[i]; + if ( pFileConfig->IsExcludedFrom( pConfig->GetConfigName() ) ) + continue; + + const char *pFilename = pFileConfig->m_Filename.String(); + if ( IsLibraryFile( pFilename ) ) + { + if (( !sImportLibraryFile[0] || V_stricmp( sImportLibraryFile, pFilename ) ) && // only link this as a library if it isn't our own output! + ( !sOutputFile[0] || V_stricmp( sOutputFile, pFilename))) + { + fprintf( fp, " %s \\\n", UsePOSIXSlashes( pFilename ) ); + } + } + } + + fprintf( fp, "\n\n" ); + + + CUtlVector< CUtlString > otherDependencies; + static const char *sDependenciesSeparators[] = { ";", "\r", "\n" }; + + // Scan the list of files for any generated dependencies so we can pull them up front + for ( int i=m_Files.First(); i != m_Files.InvalidIndex(); i=m_Files.Next(i) ) + { + CFileConfig *pFileConfig = m_Files[i]; + CSpecificConfig *pFileSpecificData = pFileConfig->GetOrCreateConfig( pConfig->GetConfigName(), pConfig ); + + if ( pFileConfig->IsExcludedFrom( pConfig->GetConfigName() ) ) + { + continue; + } + + const char *pCustomBuildCommandLine = pFileSpecificData->GetOption( g_pOption_CustomBuildStepCommandLine ); + const char *pOutputFile = pFileSpecificData->GetOption( g_pOption_Outputs ); + if ( pOutputFile && pCustomBuildCommandLine && V_strlen( pCustomBuildCommandLine ) > 0 ) + { + char szTempFilename[MAX_PATH]; + V_strncpy( szTempFilename, UsePOSIXSlashes( pFileConfig->m_Filename.String() ), sizeof( szTempFilename ) ); + const char *pFilename = szTempFilename; + + // This file uses a custom build step. + char sFormattedOutputFile[8192]; + char szAbsPath[MAX_PATH]; + V_MakeAbsolutePath( szAbsPath, sizeof(szAbsPath), pFilename ); + DoStandardVisualStudioReplacements( pOutputFile, szAbsPath, sFormattedOutputFile, sizeof( sFormattedOutputFile ) ); + + CSplitString outFiles( sFormattedOutputFile, sDependenciesSeparators, sizeof( sDependenciesSeparators ) / sizeof( sDependenciesSeparators[ 0 ] ) ); + + for ( int i = 0; i < outFiles.Count(); i ++ ) + { + const char *pchOneFile = outFiles[ i ]; + if ( *pchOneFile == '\0' ) + { + continue; + } + // Remember this as a dependency so the executable will depend on it. + if ( otherDependencies.Find( pchOneFile ) == otherDependencies.InvalidIndex() ) + otherDependencies.AddToTail( pchOneFile ); + } + } + } + + WriteOtherDependencies( fp, otherDependencies ); + fprintf( fp, "\n\n" ); + + // Include the base makefile before the rules to build the .o files. + // Do this after we output otherDependencies definition since $(OTHER_DEPENDENCIES) is a dependency of all: target + const char *sMakeFileDependency = ""; + bool bCondPOSIX = g_pVPC->FindOrCreateConditional( "POSIX", false, CONDITIONAL_NULL ) != NULL; + fprintf( fp, "# Include the base makefile now.\n" ); + if ( bCondPOSIX ) + { + sMakeFileDependency = k_pszBase_Makefile; + fprintf( fp, "include %s\n\n\n", sMakeFileDependency ); + } + + // Now write the rules to build the .o files. + // .o files go in [project dir]/obj/[config]/[base filename] + for ( int i=m_Files.First(); i != m_Files.InvalidIndex(); i=m_Files.Next(i) ) + { + CFileConfig *pFileConfig = m_Files[i]; + CSpecificConfig *pFileSpecificData = pFileConfig->GetOrCreateConfig( pConfig->GetConfigName(), pConfig ); + + if ( pFileConfig->IsExcludedFrom( pConfig->GetConfigName() ) ) + { + continue; + } + + char szTempFilename[MAX_PATH]; + V_strncpy( szTempFilename, UsePOSIXSlashes( pFileConfig->m_Filename.String() ), sizeof( szTempFilename ) ); + const char *pFilename = szTempFilename; + + // Custom build steps?? + const char *pCustomBuildCommandLine = pFileSpecificData->GetOption( g_pOption_CustomBuildStepCommandLine ); + const char *pOutputFile = pFileSpecificData->GetOption( g_pOption_Outputs ); + if ( pOutputFile && pCustomBuildCommandLine && V_strlen( pCustomBuildCommandLine ) > 0 ) + { + // This file uses a custom build step. + char sFormattedOutputFile[8192]; + char sFormattedCommandLine[8192]; + char sFormattedDependencies[8192]; + DoStandardVisualStudioReplacements( pCustomBuildCommandLine, UsePOSIXSlashes( pFilename ), \ + sFormattedCommandLine, sizeof( sFormattedCommandLine ) ); + DoStandardVisualStudioReplacements( pOutputFile, UsePOSIXSlashes( pFilename ), \ + sFormattedOutputFile, sizeof( sFormattedOutputFile ) ); + + + // AdditionalDependencies only applies to custom build steps, not normal compilation steps + const char *pAdditionalDeps = pFileSpecificData->GetOption( g_pOption_AdditionalDependencies ); + if ( pAdditionalDeps ) + DoStandardVisualStudioReplacements( pAdditionalDeps, szAbsPath, sFormattedDependencies, sizeof( sFormattedDependencies ) ); + else + sFormattedDependencies[0] = 0; + + CSplitString additionalDeps( sFormattedDependencies, sDependenciesSeparators, sizeof( sDependenciesSeparators ) / sizeof( sDependenciesSeparators[0] ) ); + FOR_EACH_VEC_BACK( additionalDeps, i ) + { + const char *pchOneFile = additionalDeps[i]; + if ( *pchOneFile == '\0' ) + { + additionalDeps.Remove( i ); + } + } + + CSplitString outFiles( sFormattedOutputFile, sDependenciesSeparators, sizeof( sDependenciesSeparators ) / sizeof( sDependenciesSeparators[ 0 ] ) ); + FOR_EACH_VEC_BACK( outFiles, i ) + { + const char *pchOneFile = outFiles[ i ]; + if ( *pchOneFile == '\0' ) + { + outFiles.Remove( i ); + } + } + + char rgchIntermediateFile[MAX_PATH]; + rgchIntermediateFile[0] = 0; + + // ABSPATH NOTE + // + // Make will not do what we expect with ../../this/dir/foo.cpp, and these are often the result of nested macros + // in VPC files, so ensure we are giving make absolute paths for our targets via $(abspath ...) + + if ( outFiles.Count() == 1 ) + { + // one output file: create a standard rule -- output : input \n \t command + fprintf( fp, "\n$(abspath %s) ", outFiles[0] ); + } + else + { + // multiple output files: DO NOT DO THIS -- output output output : input \n \t command + // as this will cause up to three parallel invocations of command! + // best-practice workaround is to create a temp intermediate file + static int s_uniqueId = 0; + V_snprintf( rgchIntermediateFile, sizeof(rgchIntermediateFile), "$(OBJ_DIR)/_custombuildstep_%d.touchfile", s_uniqueId ); + fprintf( fp, "\n%s ", rgchIntermediateFile ); + ++s_uniqueId; + + V_strcat( sFormattedCommandLine, CFmtStrMax( "\n@touch %s", rgchIntermediateFile ), sizeof(sFormattedCommandLine) ); + } + // Outputs dependent on input file and .mak file + fprintf( fp, ": $(abspath %s) %s", UsePOSIXSlashes( pFilename ), g_pVPC->GetOutputFilename() ); + FOR_EACH_VEC( additionalDeps, i ) + { + fprintf( fp, " %s", additionalDeps[i] ); + } + /// XXX(JohnS): Was this double-added as an accident, or is there some arcane make reason to have it be the + /// first and last dep? + fprintf( fp, " $(abspath %s)\n", UsePOSIXSlashes( pFilename ) ); + const char *pDescription = pFileSpecificData->GetOption( g_pOption_Description ); + DoStandardVisualStudioReplacements( pDescription, UsePOSIXSlashes( pFilename ), \ + sFormattedOutputFile, sizeof( sFormattedOutputFile ) ); + + fprintf( fp, "\t @echo \"%s\";mkdir -p $(OBJ_DIR) 2> /dev/null;\n", sFormattedOutputFile ); + + static const char *sSeparators[] = { "\r", "\n" }; + CSplitString outLines( sFormattedCommandLine, sSeparators, sizeof( sSeparators ) / sizeof( sSeparators[ 0 ] ) ); + for ( int i = 0; i < outLines.Count(); ++i ) + { + const char *pchOneLine = outLines[ i ]; + if ( *pchOneLine == '\0' ) + { + continue; + } + fprintf( fp, "\t %s\n", pchOneLine ); + } + fprintf( fp, "\n" ); + + // for multiple output files, create a dependency between output files and intermediate file + makefile + if ( outFiles.Count() > 1 ) + { + FOR_EACH_VEC( outFiles, i ) + { + // See ABSPATH NOTE above + fprintf( fp, "$(abspath %s) : %s %s\n\t @touch %s\n\n", outFiles[i], rgchIntermediateFile, g_pVPC->GetOutputFilename(), outFiles[i] ); + } + } + } + else if ( CheckExtensions( pFilename, (const char**)sSourceFileExtensions ) ) + { + char sObjFilename[MAX_PATH]; + GetObjFilenameForFile( pConfig->GetConfigName(), pFilename, sObjFilename, sizeof( sObjFilename ) ); + + // Get the base obj filename for the .P file. + char sPFileBase[MAX_PATH]; + V_StripExtension( sObjFilename, sPFileBase, sizeof( sPFileBase ) ); + + fprintf( fp, "\nifneq (clean, $(findstring clean, $(MAKECMDGOALS)))\n" ); + fprintf( fp, "-include %s.P\n", sPFileBase ); + fprintf( fp, "endif\n" ); + + bool bUsedPrecompiledHeader = false; + + // Handle precompiled header options. + const char *pPrecompiledHeaderOption = pFileSpecificData->GetOption( g_pOption_PrecompiledHeader ); + const char *pUsePCHThroughFile = pFileSpecificData->GetOption( g_pOption_UsePCHThroughFile ); + + if ( !g_pVPC->IsPosixPCHDisabled() && pPrecompiledHeaderOption && pUsePCHThroughFile ) + { + char sIncludeFilename[MAX_PATH]; + const char *pHeaderFileName = V_GetFileName( pUsePCHThroughFile ); + V_snprintf( sIncludeFilename, sizeof( sIncludeFilename ), "$(OBJ_DIR)/%s", pHeaderFileName ); + + // Note that we use $(abspath ...) for most things, but the provided PCH file (pUsePCHThroughFile) + // is actually a include filename -- that is, it is meant to be found the same way #include "pch" + // would be. We use make's vpath directive to tell it to resolve this file relative to the + // INCLUDEDIRS list we conveniently have, (starting with PWD to mimic c/c++ include searching), but + // that means we have to be careful to always reference it as a dependency the same way. + // + // However, since we explicitly opt-in to files using said PCH, we can just specifically set the PCH + // as a dependency of every file that has opted-in to use it, so we don't run into issues with + // things like the compiler's -MD dependencies referring to it differently. + if ( V_stristr( pPrecompiledHeaderOption, "Not Using" ) ) + { + // Don't do anything special if this file doesn't want to use a precompiled header. + } + else if ( V_stristr( pPrecompiledHeaderOption, "Create" ) ) + { + // Compile pUsePCHThroughFile and output it to obj/<config>/filename.h.gch + fprintf( fp, "\n%s.gch : %s $(PWD)/%s %s $(OTHER_DEPENDENCIES)\n", + sIncludeFilename, pUsePCHThroughFile, g_pVPC->GetOutputFilename(), sMakeFileDependency ); + fprintf( fp, "\t$(PRE_COMPILE_FILE)\n" ); + fprintf( fp, "\t$(COMPILE_PCH) $(POST_COMPILE_FILE)\n" ); + + // include the .P it spits out, ensuring it is marked as depending on the gch build finishing so + // we don't include a stale one. + fprintf( fp, "\n%s.P : %s.gch\n", sIncludeFilename, sIncludeFilename ); + fprintf( fp, "\nvpath %s . $(INCLUDEDIRS)\n", pUsePCHThroughFile ); + fprintf( fp, "\nifneq (clean, $(findstring clean, $(MAKECMDGOALS)))\n" ); + fprintf( fp, "include %s.P\n", sIncludeFilename ); + fprintf( fp, "endif\n" ); + + // Create obj/<config>/filename.h as well, depending on the GCH so it is re-copied when we + // recompile it. + // + // Because we pass this as -include <foo> to the compiler, this allows conditions where the PCH + // cannot be used to fall back to the compiler simply using the .h, rather than failing + // entirely. + fprintf( fp, "\n%s : %s %s.gch $(PWD)/%s %s\n", + sIncludeFilename, pUsePCHThroughFile, sIncludeFilename, g_pVPC->GetOutputFilename(), sMakeFileDependency ); + fprintf( fp, "\tcp -f $< %s\n", sIncludeFilename ); + } + else if ( V_stristr( pPrecompiledHeaderOption, "Use" ) ) + { + CFileConfig *pCreator = pAccel->FindFileThatCreatesPrecompiledHeader( pConfig->GetConfigName(), pUsePCHThroughFile ); + if ( pCreator && !pCreator->IsExcludedFrom( pConfig->GetConfigName() ) ) + { + const char *pCompileAsOption = pFileSpecificData->GetOption( g_pOption_CompileAs ); + fprintf( fp, "\n%s : TARGET_PCH_FILE = %s\n", sObjFilename, sIncludeFilename ); + fprintf( fp, "%s : $(abspath %s) %s.gch %s $(PWD)/%s %s\n", + sObjFilename, UsePOSIXSlashes( pFilename ), sIncludeFilename, sIncludeFilename, + g_pVPC->GetOutputFilename(), sMakeFileDependency ); + fprintf( fp, "\t$(PRE_COMPILE_FILE)\n" ); + if ( pCompileAsOption && strstr( pCompileAsOption, "(/TC)" ) ) // Compile as C code (/TC) + { + fprintf( fp, "\t$(COMPILE_FILE_WITH_PCH_C) $(POST_COMPILE_FILE)\n" ); + } + else + { + fprintf( fp, "\t$(COMPILE_FILE_WITH_PCH) $(POST_COMPILE_FILE)\n" ); + } + bUsedPrecompiledHeader = true; + } + } + } + + if ( !bUsedPrecompiledHeader ) + { + const char *pCompileAsOption = pFileSpecificData->GetOption( g_pOption_CompileAs ); + fprintf( fp, "\n%s : $(abspath %s) $(PWD)/%s %s $(OTHER_DEPENDENCIES)\n", + sObjFilename, UsePOSIXSlashes( pFilename ), g_pVPC->GetOutputFilename(), sMakeFileDependency ); + fprintf( fp, "\t$(PRE_COMPILE_FILE)\n" ); + if ( pCompileAsOption && strstr( pCompileAsOption, "(/TC)" ) ) // Compile as C code (/TC) + { + fprintf( fp, "\t$(COMPILE_FILE_C) $(POST_COMPILE_FILE)\n" ); + } + else + { + fprintf( fp, "\t$(COMPILE_FILE) $(POST_COMPILE_FILE)\n" ); + } + } + } + } + + if( !pConfig1 ) + { + fprintf( fp, "\n\nendif # (CFG=%s)\n\n", pConfig->GetConfigName() ); + fprintf( fp, "\n\n" ); + } + } + + void WriteOtherDependencies( FILE *fp, CUtlVector< CUtlString > &otherDependencies ) + { + fprintf( fp, "\nOTHER_DEPENDENCIES = \\\n" ); + for ( int i=0; i < otherDependencies.Count(); i++ ) + { + fprintf( fp, "\t$(abspath %s)%s\n", UsePOSIXSlashes( otherDependencies[i].String() ), + (i == otherDependencies.Count()-1) ? "" : " \\" ); + } + fprintf( fp, "\n\n" ); + fprintf( fp, "-include $(OBJ_DIR)/_other_deps.P\n" ); + } + + bool CheckReleaseDebugConfigsAreSame() + { + if ( g_pVPC->IsVerboseMakefile() ) + return false; + + // Go through two configs and check to see that all the strings except the defines are the same. + // If so, we can write the entire makefile and only special case the $PreprocessorDefinitions portion. + // Makes for a much simpler makefile to read and modify when testing various flags, etc. + if( m_BaseConfigData.m_Configurations.Count() == 2 ) + { + CSpecificConfig *pConfig0 = m_BaseConfigData.m_Configurations[0]; + CSpecificConfig *pConfig1 = m_BaseConfigData.m_Configurations[1]; + KeyValues *pKV0 = pConfig0->m_pKV; + KeyValues *pKV1 = pConfig1->m_pKV; + + KeyValues *val0 = pKV0->GetFirstValue(); + KeyValues *val1 = pKV1->GetFirstValue(); + for( ;; ) + { + // If one has run out and the other hasn't, bail. + if( !val0 != !val1 ) + break; + + if( !val0 ) + { + // We've hit the end of both keyvalues, and everything was the same. + Assert( !val1 ); + return true; + } + + // If the datatypes aren't strings or aren't the same, bail. + if( ( val0->GetDataType() != KeyValues::TYPE_STRING ) || ( val0->GetDataType() != val1->GetDataType() ) ) + break; + + // If the keynames differ, bail. + if( V_strcmp( val0->GetName(), val1->GetName() ) ) + break; + + // If this isn't the $PreprocessorDefinitions key, check the values. + if( V_strcmp( val0->GetName(), g_pOption_PreprocessorDefinitions ) ) + { + if( V_strcmp( val0->GetString(), val1->GetString() ) ) + break; + + // look for visual studio macros and assume those evaluate to config specific values + if ( V_strstr( val0->GetString(), "$(" ) ) + break; + } + + // Next. + val0 = val0->GetNextValue(); + val1 = val1->GetNextValue(); + } + } + + return false; + } + + void WriteMakefile( const char *pFilename ) + { + FILE *fp = fopen( pFilename, "wt" ); + + CPrecompiledHeaderAccel accel; + accel.Setup( m_Files, &m_BaseConfigData ); + + m_bForceLowerCaseFileName = false; + + // Write all the non-config-specific stuff. + WriteNonConfigSpecificStuff( fp ); + + bool bReleaseDebugAreSame = CheckReleaseDebugConfigsAreSame(); + if( bReleaseDebugAreSame ) + { + // If the two configs are the same except for $PreprocessorDefinitions, then call + // WriteConfigSpecificStuff() once with both configs. + Assert( m_BaseConfigData.m_Configurations.Count() == 2 ); + CSpecificConfig *pConfig0 = m_BaseConfigData.m_Configurations[0]; + CSpecificConfig *pConfig1 = m_BaseConfigData.m_Configurations[1]; + + // Make sure we always have "release" second (ie, the default case). + if( !V_stricmp( pConfig0->GetConfigName(), "release" ) ) + { + CSpecificConfig *pConfigTemp = pConfig0; + pConfig0 = pConfig1; + pConfig1 = pConfigTemp; + } + + m_bForceLowerCaseFileName = pConfig0->m_pKV->GetBool( g_pOption_LowerCaseFileNames, false ); + WriteConfigSpecificStuff( pConfig0, fp, &accel, pConfig1 ); + } + else + { + // Write each config out. + for ( int i=m_BaseConfigData.m_Configurations.First(); i != m_BaseConfigData.m_Configurations.InvalidIndex(); i=m_BaseConfigData.m_Configurations.Next( i ) ) + { + CSpecificConfig *pConfig = m_BaseConfigData.m_Configurations[i]; + m_bForceLowerCaseFileName = pConfig->m_pKV->GetBool( g_pOption_LowerCaseFileNames, false ); + WriteConfigSpecificStuff( pConfig, fp, &accel, NULL ); + } + } + + fclose( fp ); + Sys_CopyToMirror( pFilename ); + } + + bool m_bForceLowerCaseFileName; +}; + +static CProjectGenerator_Makefile g_ProjectGenerator_Makefile; +IBaseProjectGenerator* GetMakefileProjectGenerator() +{ + return &g_ProjectGenerator_Makefile; +} diff --git a/external/vpc/utils/vpc/projectgenerator_ps3.cpp b/external/vpc/utils/vpc/projectgenerator_ps3.cpp new file mode 100644 index 0000000..c3b4641 --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_ps3.cpp @@ -0,0 +1,1257 @@ +//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: VPC +// +//=====================================================================================// + +#include "vpc.h" + +#undef PROPERTYNAME +#define PROPERTYNAME( X, Y ) { X##_##Y, #X, #Y }, +static PropertyName_t s_PS3PropertyNames[] = +{ + #include "projectgenerator_ps3.inc" + { -1, NULL, NULL } +}; + +IBaseProjectGenerator* GetPS3ProjectGenerator() +{ + static CProjectGenerator_PS3 *s_pProjectGenerator = NULL; + if ( !s_pProjectGenerator ) + { + s_pProjectGenerator = new CProjectGenerator_PS3(); + } + + return s_pProjectGenerator->GetProjectGenerator(); +} + +CProjectGenerator_PS3::CProjectGenerator_PS3() +{ + m_pVCProjGenerator = new CVCProjGenerator(); + m_pVCProjGenerator->SetupGeneratorDefinition( this, "ps3.def", s_PS3PropertyNames ); +} + +bool CProjectGenerator_PS3::WriteFile( CProjectFile *pFile ) +{ + m_XMLWriter.PushNode( "File" ); + m_XMLWriter.Write( CFmtStrMax( "RelativePath=\"%s\"", pFile->m_Name.Get() ) ); + m_XMLWriter.Write( ">" ); + + for ( int i = 0; i < pFile->m_Configs.Count(); i++ ) + { + if ( !WriteConfiguration( pFile->m_Configs[i] ) ) + return false; + } + + m_XMLWriter.PopNode( true ); + + return true; +} + +bool CProjectGenerator_PS3::WriteFolder( CProjectFolder *pFolder ) +{ + m_XMLWriter.PushNode( "Filter" ); + m_XMLWriter.Write( CFmtStrMax( "Name=\"%s\"", m_XMLWriter.FixupXMLString( pFolder->m_Name.Get() ) ) ); + m_XMLWriter.Write( ">" ); + + for ( int iIndex = pFolder->m_Folders.Head(); iIndex != pFolder->m_Folders.InvalidIndex(); iIndex = pFolder->m_Folders.Next( iIndex ) ) + { + if ( !WriteFolder( pFolder->m_Folders[iIndex] ) ) + return false; + } + + for ( int iIndex = pFolder->m_Files.Head(); iIndex != pFolder->m_Files.InvalidIndex(); iIndex = pFolder->m_Files.Next( iIndex ) ) + { + if ( !WriteFile( pFolder->m_Files[iIndex] ) ) + return false; + } + + m_XMLWriter.PopNode( true ); + + return true; +} + +bool CProjectGenerator_PS3::WritePreBuildEventTool( CPreBuildEventTool *pPreBuildEventTool ) +{ + if ( !pPreBuildEventTool ) + { + // not an error, some tools n/a for aconfig + return true; + } + + m_XMLWriter.PushNode( "Tool" ); + + m_XMLWriter.Write( "Name=\"VCPreBuildEventTool\"" ); + + for ( int i = 0; i < pPreBuildEventTool->m_PropertyStates.m_Properties.Count(); i++ ) + { + switch ( pPreBuildEventTool->m_PropertyStates.m_Properties[i].m_pToolProperty->m_nPropertyId ) + { + case PS3_PREBUILDEVENT_CommandLine: + m_XMLWriter.Write( CFmtStrMax( "CommandLine=\"%s\"", m_XMLWriter.FixupXMLString( pPreBuildEventTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ) ); + break; + + case PS3_PREBUILDEVENT_Description: + m_XMLWriter.Write( CFmtStrMax( "Description=\"%s\"", pPreBuildEventTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_PREBUILDEVENT_ExcludedFromBuild: + m_XMLWriter.Write( CFmtStrMax( "ExcludedFromBuild=\"%s\"", BoolStringToTrueFalseString( pPreBuildEventTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ) ); + break; + } + } + + m_XMLWriter.PopNode( false ); + + return true; +} + +bool CProjectGenerator_PS3::WriteCustomBuildTool( CCustomBuildTool *pCustomBuildTool ) +{ + if ( !pCustomBuildTool ) + { + // not an error, some tools n/a for aconfig + return true; + } + + m_XMLWriter.PushNode( "Tool" ); + + m_XMLWriter.Write( "Name=\"VCCustomBuildTool\"" ); + + for ( int i = 0; i < pCustomBuildTool->m_PropertyStates.m_Properties.Count(); i++ ) + { + switch ( pCustomBuildTool->m_PropertyStates.m_Properties[i].m_pToolProperty->m_nPropertyId ) + { + case PS3_CUSTOMBUILDSTEP_CommandLine: + m_XMLWriter.Write( CFmtStrMax( "CommandLine=\"%s\"", m_XMLWriter.FixupXMLString( pCustomBuildTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ) ); + break; + + case PS3_CUSTOMBUILDSTEP_Description: + m_XMLWriter.Write( CFmtStrMax( "Description=\"%s\"", pCustomBuildTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_CUSTOMBUILDSTEP_Outputs: + m_XMLWriter.Write( CFmtStrMax( "Outputs=\"%s\"", pCustomBuildTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_CUSTOMBUILDSTEP_AdditionalDependencies: + m_XMLWriter.Write( CFmtStrMax( "AdditionalDependencies=\"%s\"", pCustomBuildTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + } + } + + m_XMLWriter.PopNode( false ); + + return true; +} + +bool CProjectGenerator_PS3::WriteSNCCompilerTool( CCompilerTool *pCompilerTool ) +{ + if ( !pCompilerTool ) + { + // not an error, some tools n/a for a config + return true; + } + + m_XMLWriter.PushNode( "Tool" ); + + m_XMLWriter.Write( "Name=\"VCCLCompilerTool\"" ); + + // aggregates or purges state as needed + CUtlString additionalOptions = ""; + + for ( int i = 0; i < pCompilerTool->m_PropertyStates.m_Properties.Count(); i++ ) + { + int nOrdinalValue = atoi( pCompilerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ); + + switch ( pCompilerTool->m_PropertyStates.m_Properties[i].m_pToolProperty->m_nPropertyId ) + { + case PS3_SNCCOMPILER_AdditionalIncludeDirectories: + m_XMLWriter.Write( CFmtStrMax( "AdditionalIncludeDirectories=\"%s\"", pCompilerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_SNCCOMPILER_PreprocessorDefinitions: + m_XMLWriter.Write( CFmtStrMax( "PreprocessorDefinitions=\"%s\"", pCompilerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_SNCCOMPILER_ForceIncludes: + m_XMLWriter.Write( CFmtStrMax( "ForcedIncludeFiles=\"%s\"", pCompilerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_SNCCOMPILER_GenerateDebugInformation: + if ( nOrdinalValue ) + { + additionalOptions += "-g "; + } + break; + + case PS3_SNCCOMPILER_Warnings: + if ( nOrdinalValue ) + { + additionalOptions += CFmtStrMax( "-Xdiag=%d ", nOrdinalValue ); + } + break; + + case PS3_SNCCOMPILER_TreatMessagesAsErrors: + if ( nOrdinalValue ) + { + additionalOptions += CFmtStrMax( "-Xquit=%d ", nOrdinalValue ); + } + break; + + case PS3_SNCCOMPILER_DisableSpecificWarnings: + m_XMLWriter.Write( CFmtStrMax( "DisableSpecificWarnings=\"%s\"", pCompilerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_SNCCOMPILER_ObjectFileName: + m_XMLWriter.Write( CFmtStrMax( "ObjectFile=\"%s\"", pCompilerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_SNCCOMPILER_CallprofHierarchicalProfiling: + if ( nOrdinalValue ) + { + additionalOptions += CFmtStrMax( "-Xcallprof=%d ", nOrdinalValue ); + } + break; + + case PS3_SNCCOMPILER_OptimizationLevel: + if ( nOrdinalValue == 0 ) + { + // lack of any -0<x> means -O0 + additionalOptions += " "; + } + else if ( nOrdinalValue == 1 ) + { + additionalOptions += "-O1 "; + } + else if ( nOrdinalValue == 2 ) + { + additionalOptions += "-O2 "; + } + else if ( nOrdinalValue == 3 ) + { + additionalOptions += "-Os "; + } + else if ( nOrdinalValue == 4 ) + { + additionalOptions += "-Od "; + } + break; + + case PS3_SNCCOMPILER_FastMath: + if ( nOrdinalValue ) + { + additionalOptions += CFmtStrMax( "-Xfastmath=%d ", nOrdinalValue ); + } + break; + + case PS3_SNCCOMPILER_RelaxAliasChecking: + if ( nOrdinalValue >= 0 ) + { + additionalOptions += CFmtStrMax( "-Xrelaxalias=%d ", nOrdinalValue ); + } + break; + + case PS3_SNCCOMPILER_BranchlessCompares: + if ( nOrdinalValue ) + { + additionalOptions += CFmtStrMax( "-Xbranchless=%d ", nOrdinalValue ); + } + break; + + case PS3_SNCCOMPILER_UnrollLoops: + if ( nOrdinalValue ) + { + additionalOptions += CFmtStrMax( "-Xunrollssa=%d ", nOrdinalValue ); + } + break; + + case PS3_SNCCOMPILER_AssumeAlignedPointers: + if ( nOrdinalValue ) + { + additionalOptions += "-Xassumecorrectalignment=1 "; + } + break; + + case PS3_SNCCOMPILER_AssumeCorrectSign: + if ( nOrdinalValue ) + { + additionalOptions += "-Xassumecorrectsign=1 "; + } + break; + + case PS3_SNCCOMPILER_TOCPointerPreservation: + if ( nOrdinalValue ) + { + additionalOptions += CFmtStrMax( "-Xnotocrestore=%d ", nOrdinalValue ); + } + break; + + case PS3_SNCCOMPILER_InitializedDataPlacement: + additionalOptions += CFmtStrMax( "-Xbss=%d ", nOrdinalValue ); + break; + + case PS3_SNCCOMPILER_PromoteFPConstantsToDoubles: + if ( nOrdinalValue ) + { + additionalOptions += "-Xfltconst=8 "; + } + break; + + case PS3_SNCCOMPILER_CCPPDialect: + if ( nOrdinalValue ) + { + if ( nOrdinalValue == 1 ) + { + additionalOptions += "-Xc=ansi "; + } + else if ( nOrdinalValue == 2 ) + { + additionalOptions += "-Xc=arm "; + } + else if ( nOrdinalValue == 3 ) + { + additionalOptions += "-Xc=cp "; + } + else if ( nOrdinalValue == 4 ) + { + additionalOptions += "-Xc=cfront "; + } + else if ( nOrdinalValue == 5 ) + { + additionalOptions += "-Xc=knr "; + } + } + break; + + case PS3_SNCCOMPILER_CPPExceptionsAndRTTIUsage: + if ( nOrdinalValue == 0 ) + { + additionalOptions += "-Xc-=rtti -Xc-=exceptions "; + } + else if ( nOrdinalValue == 1 ) + { + additionalOptions += "-Xc+=rtti -Xc-=exceptions "; + } + else if ( nOrdinalValue == 2 ) + { + additionalOptions += "-Xc+=rtti -Xc+=exceptions "; + } + break; + + case PS3_SNCCOMPILER_DefaultCharUnsigned: + if ( nOrdinalValue ) + { + additionalOptions += "-Xchar=unsigned "; + } + break; + + case PS3_SNCCOMPILER_DefaultFPConstantsAsTypeFloat: + if ( nOrdinalValue ) + { + additionalOptions += "-Xsingleconst=1 "; + } + break; + + case PS3_SNCCOMPILER_BuiltInDefinitionForWCHAR_TType: + if ( nOrdinalValue == 0 ) + { + additionalOptions += "-Xwchart=uint "; + } + else if ( nOrdinalValue == 1 ) + { + additionalOptions += "-Xwchart=ulong "; + } + else if ( nOrdinalValue == 2 ) + { + additionalOptions += "-Xwchart=ushort "; + } + else if ( nOrdinalValue == 3 ) + { + additionalOptions += "-Xwchart=uchar "; + } + else if ( nOrdinalValue == 4 ) + { + additionalOptions += "-Xwchart=int "; + } + else if ( nOrdinalValue == 5 ) + { + additionalOptions += "-Xwchart=long "; + } + else if ( nOrdinalValue == 6 ) + { + additionalOptions += "-Xwchart=short "; + } + else if ( nOrdinalValue == 7 ) + { + additionalOptions += "-Xwchart=char "; + } + else if ( nOrdinalValue == 8 ) + { + additionalOptions += "-Xwchart=schar "; + } + break; + + case PS3_SNCCOMPILER_CreateUsePrecompiledHeader: + if ( nOrdinalValue == 1 ) + { + additionalOptions += CFmtStrMax( "--create_pch="%s" ", pCompilerTool->m_PropertyStates.GetProperty( PS3_SNCCOMPILER_PrecompiledHeaderFile )->m_StringValue ); + } + else if ( nOrdinalValue == 2 ) + { + additionalOptions += "--pch --pch_dir="$(IntDir)" "; + } + else if ( nOrdinalValue == 3 ) + { + additionalOptions += CFmtStrMax( "--use_pch="%s" ", pCompilerTool->m_PropertyStates.GetProperty( PS3_SNCCOMPILER_PrecompiledHeaderFile )->m_StringValue ); + } + break; + + case PS3_SNCCOMPILER_PrecompiledHeaderFile: + // already accounted for + break; + + case PS3_SNCCOMPILER_AdditionalOptions: + if ( !pCompilerTool->m_PropertyStates.m_Properties[i].m_StringValue.IsEmpty() ) + { + additionalOptions += pCompilerTool->m_PropertyStates.m_Properties[i].m_StringValue; + additionalOptions += " "; + } + break; + } + } + + if ( !additionalOptions.IsEmpty() ) + { + m_XMLWriter.Write( CFmtStrMax( "AdditionalOptions=\"%s\"", additionalOptions.Get() ) ); + } + + m_XMLWriter.PopNode( false ); + + return true; +} + +bool CProjectGenerator_PS3::WriteGCCCompilerTool( CCompilerTool *pCompilerTool ) +{ + if ( !pCompilerTool ) + { + // not an error, some tools n/a for a config + return true; + } + + m_XMLWriter.PushNode( "Tool" ); + + m_XMLWriter.Write( "Name=\"VCCLCompilerTool\"" ); + + // aggregates or purges state as needed + CUtlString additionalOptions = ""; + + for ( int i = 0; i < pCompilerTool->m_PropertyStates.m_Properties.Count(); i++ ) + { + int nOrdinalValue = atoi( pCompilerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ); + + switch ( pCompilerTool->m_PropertyStates.m_Properties[i].m_pToolProperty->m_nPropertyId ) + { + case PS3_GCCCOMPILER_AdditionalIncludeDirectories: + m_XMLWriter.Write( CFmtStrMax( "AdditionalIncludeDirectories=\"%s\"", m_XMLWriter.FixupXMLString( pCompilerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ) ); + break; + + case PS3_GCCCOMPILER_PreprocessorDefinitions: + m_XMLWriter.Write( CFmtStrMax( "PreprocessorDefinitions=\"%s\"", pCompilerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_GCCCOMPILER_ForceIncludes: + m_XMLWriter.Write( CFmtStrMax( "ForcedIncludeFiles=\"%s\"", pCompilerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_GCCCOMPILER_GenerateDebugInformation: + if ( nOrdinalValue ) + { + additionalOptions += "-g "; + } + break; + + case PS3_GCCCOMPILER_Warnings: + if ( nOrdinalValue == 0 ) + { + additionalOptions += "-w "; + } + else if ( nOrdinalValue == 2 ) + { + additionalOptions += "-Wall "; + } + break; + + case PS3_GCCCOMPILER_ExtraWarnings: + if ( nOrdinalValue ) + { + additionalOptions += "-Wextra "; + } + break; + + case PS3_GCCCOMPILER_WarnLoadHitStores: + break; + + case PS3_GCCCOMPILER_WarnMicrocodedInstruction: + break; + + case PS3_GCCCOMPILER_TreatWarningsAsErrors: + if ( nOrdinalValue ) + { + additionalOptions += "-Werror "; + } + break; + + case PS3_GCCCOMPILER_ObjectFileName: + m_XMLWriter.Write( CFmtStrMax( "ObjectFile=\"%s\"", pCompilerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_GCCCOMPILER_CallprofHierarchicalProfiling: + break; + + case PS3_GCCCOMPILER_SPURSUsage: + if ( nOrdinalValue == 1 ) + { + additionalOptions += "-mspurs-job-initialize "; + } + else if ( nOrdinalValue == 2 ) + { + additionalOptions += "-mspurs-job "; + } + else if ( nOrdinalValue == 3 ) + { + additionalOptions += "-mspurs-task "; + } + break; + + case PS3_GCCCOMPILER_OptimizationLevel: + if ( nOrdinalValue == 0 ) + { + additionalOptions += "-O0 "; + } + else if ( nOrdinalValue == 1 ) + { + additionalOptions += "-O1 "; + } + else if ( nOrdinalValue == 2 ) + { + additionalOptions += "-O2 "; + } + else if ( nOrdinalValue == 3 ) + { + additionalOptions += "-O3 "; + } + else if ( nOrdinalValue == 4 ) + { + additionalOptions += "-Os "; + } + break; + + case PS3_GCCCOMPILER_FastMath: + if ( nOrdinalValue ) + { + additionalOptions += "-ffast-math "; + } + break; + + case PS3_GCCCOMPILER_NoStrictAliasing: + if ( nOrdinalValue ) + { + additionalOptions += "-fno-strict-aliasing "; + } + break; + + case PS3_GCCCOMPILER_UnrollLoops: + if ( nOrdinalValue ) + { + additionalOptions += "-funroll-loops "; + } + break; + + case PS3_GCCCOMPILER_InlineFunctionSizeLimit: + if ( nOrdinalValue ) + { + additionalOptions += CFmtStrMax( "-finline-limit=%d ", nOrdinalValue ); + } + break; + + case PS3_GCCCOMPILER_TOCUsage: + break; + + case PS3_GCCCOMPILER_SaveRestoreFunctions: + break; + + case PS3_GCCCOMPILER_GenerateMicrocodedInstructions: + break; + + case PS3_GCCCOMPILER_PositionIndependentCode: + if ( nOrdinalValue ) + { + additionalOptions += "-fpic "; + } + break; + + case PS3_GCCCOMPILER_FunctionSections: + if ( nOrdinalValue ) + { + additionalOptions += "-ffunction-sections "; + } + break; + + case PS3_GCCCOMPILER_DataSections: + if ( nOrdinalValue ) + { + additionalOptions += "-fdata-sections "; + } + break; + + case PS3_GCCCOMPILER_StackCheck: + if ( nOrdinalValue ) + { + additionalOptions += "-fstack-check "; + } + break; + + case PS3_GCCCOMPILER_CPPExceptionsAndRTTIUsage: + if ( nOrdinalValue == 0 ) + { + additionalOptions += "-fno-exceptions -fno-rtti "; + } + break; + + case PS3_GCCCOMPILER_CheckANSICompliance: + if ( nOrdinalValue ) + { + additionalOptions += "-ansi "; + } + break; + + case PS3_GCCCOMPILER_DefaultCharSigned: + if ( nOrdinalValue ) + { + additionalOptions += "-fsigned-char "; + } + break; + + case PS3_GCCCOMPILER_Permissive: + if ( nOrdinalValue ) + { + additionalOptions += "-fpermissive "; + } + break; + + case PS3_GCCCOMPILER_EnableMSExtensions: + break; + + case PS3_GCCCOMPILER_RelaxCPPCompliance: + if ( nOrdinalValue ) + { + additionalOptions += "-fsource-402 "; + } + break; + + case PS3_GCCCOMPILER_AdditionalOptions: + if ( !pCompilerTool->m_PropertyStates.m_Properties[i].m_StringValue.IsEmpty() ) + { + additionalOptions += pCompilerTool->m_PropertyStates.m_Properties[i].m_StringValue; + additionalOptions += " "; + } + break; + } + } + + if ( !additionalOptions.IsEmpty() ) + { + m_XMLWriter.Write( CFmtStrMax( "AdditionalOptions=\"%s\"", additionalOptions.Get() ) ); + } + + m_XMLWriter.PopNode( false ); + + return true; +} + +bool CProjectGenerator_PS3::WritePreLinkEventTool( CPreLinkEventTool *pPreLinkEventTool ) +{ + if ( !pPreLinkEventTool ) + { + // not an error, some tools n/a for aconfig + return true; + } + + m_XMLWriter.PushNode( "Tool" ); + + m_XMLWriter.Write( "Name=\"VCPreLinkEventTool\"" ); + + for ( int i = 0; i < pPreLinkEventTool->m_PropertyStates.m_Properties.Count(); i++ ) + { + switch ( pPreLinkEventTool->m_PropertyStates.m_Properties[i].m_pToolProperty->m_nPropertyId ) + { + case PS3_PRELINKEVENT_CommandLine: + m_XMLWriter.Write( CFmtStrMax( "CommandLine=\"%s\"", m_XMLWriter.FixupXMLString( pPreLinkEventTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ) ); + break; + + case PS3_PRELINKEVENT_Description: + m_XMLWriter.Write( CFmtStrMax( "Description=\"%s\"", pPreLinkEventTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_PRELINKEVENT_ExcludedFromBuild: + m_XMLWriter.Write( CFmtStrMax( "ExcludedFromBuild=\"%s\"", BoolStringToTrueFalseString( pPreLinkEventTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ) ); + break; + } + } + + m_XMLWriter.PopNode( false ); + + return true; +} + +bool CProjectGenerator_PS3::WriteSNCLinkerTool( CLinkerTool *pLinkerTool ) +{ + if ( !pLinkerTool ) + { + // not an error, some tools n/a for a config + return true; + } + + m_XMLWriter.PushNode( "Tool" ); + + m_XMLWriter.Write( "Name=\"VCLinkerTool\"" ); + + // aggregates or purges state as needed + CUtlString additionalOptions = ""; + + for ( int i = 0; i < pLinkerTool->m_PropertyStates.m_Properties.Count(); i++ ) + { + int nOrdinalValue = atoi( pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ); + + switch ( pLinkerTool->m_PropertyStates.m_Properties[i].m_pToolProperty->m_nPropertyId ) + { + case PS3_SNCLINKER_OutputFile: + m_XMLWriter.Write( CFmtStrMax( "OutputFile=\"%s\"", pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_SNCLINKER_OutputFormat: + if ( nOrdinalValue == 1 ) + { + additionalOptions += "-oformat=fself "; + } + else if ( nOrdinalValue == 2 ) + { + additionalOptions += "-oformat=fself_npdrm "; + } + else if ( nOrdinalValue == 3 ) + { + additionalOptions += "-oformat=prx -prx-with-runtime "; + } + else if ( nOrdinalValue == 4 ) + { + additionalOptions += "-oformat=fsprx -prx-with-runtime "; + } + break; + + case PS3_SNCLINKER_AdditionalDependencies: + m_XMLWriter.Write( CFmtStrMax( "AdditionalDependencies=\"%s\"", pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_SNCLINKER_AdditionalLibraryDirectories: + m_XMLWriter.Write( CFmtStrMax( "AdditionalLibraryDirectories=\"%s\"", pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_SNCLINKER_IgnoreAllDefaultLibraries: + if ( nOrdinalValue ) + { + m_XMLWriter.Write( "IgnoreAllDefaultLibraries=\"true\"" ); + } + break; + + case PS3_SNCLINKER_UsingExceptionHandling: + if ( nOrdinalValue ) + { + additionalOptions += "--exceptions "; + } + break; + + case PS3_SNCLINKER_TOCPointerElimination: + if ( nOrdinalValue ) + { + additionalOptions += "--notocrestore "; + } + break; + + case PS3_SNCLINKER_ForceSymbolReferences: + m_XMLWriter.Write( CFmtStrMax( "ForceSymbolReferences=\"%s\"", pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_SNCLINKER_CallprofHierarchicalProfiling: + if ( nOrdinalValue ) + { + additionalOptions += "--callprof "; + } + break; + + case PS3_SNCLINKER_DebugInfoAndSymbolStripping: + if ( nOrdinalValue == 1 ) + { + additionalOptions += "-S "; + } + else if ( nOrdinalValue == 2 ) + { + additionalOptions += "-s "; + } + break; + + case PS3_SNCLINKER_UnusedFunctionAndDataStripping: + if ( nOrdinalValue == 1 ) + { + additionalOptions += "-strip-unused "; + } + else if ( nOrdinalValue == 2 ) + { + additionalOptions += "-strip-unused-data "; + } + break; + + case PS3_SNCLINKER_ImportLibrary: + m_XMLWriter.Write( CFmtStrMax( "ImportLibrary=\"%s\"", pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_SNCLINKER_GenerateMapFile: + if ( nOrdinalValue == 1 ) + { + additionalOptions += CFmtStrMax( "-Map="%s" ", pLinkerTool->m_PropertyStates.GetProperty( PS3_SNCLINKER_MapFileName )->m_StringValue ); + } + else if ( nOrdinalValue == 2 ) + { + additionalOptions += CFmtStrMax( "-Map="%s" -sn-full-map ", pLinkerTool->m_PropertyStates.GetProperty( PS3_SNCLINKER_MapFileName )->m_StringValue ); + } + break; + + case PS3_SNCLINKER_MapFileName: + m_XMLWriter.Write( CFmtStrMax( "MapFileName=\"%s\"", pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_SNCLINKER_LinkLibraryDependencies: + m_XMLWriter.Write( CFmtStrMax( "LinkLibraryDependencies=\"%s\"", BoolStringToTrueFalseString( pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ) ); + break; + + case PS3_SNCLINKER_AdditionalOptions: + if ( !pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.IsEmpty() ) + { + additionalOptions += pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue; + additionalOptions += " "; + } + break; + } + } + + if ( !additionalOptions.IsEmpty() ) + { + m_XMLWriter.Write( CFmtStrMax( "AdditionalOptions=\"%s\"", additionalOptions.Get() ) ); + } + + m_XMLWriter.PopNode( false ); + + return true; +} + +bool CProjectGenerator_PS3::WriteGCCLinkerTool( CLinkerTool *pLinkerTool ) +{ + if ( !pLinkerTool ) + { + // not an error, some tools n/a for a config + return true; + } + + m_XMLWriter.PushNode( "Tool" ); + + m_XMLWriter.Write( "Name=\"VCLinkerTool\"" ); + + // aggregates or purges state as needed + CUtlString additionalOptions = ""; + + for ( int i = 0; i < pLinkerTool->m_PropertyStates.m_Properties.Count(); i++ ) + { + int nOrdinalValue = atoi( pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ); + + switch ( pLinkerTool->m_PropertyStates.m_Properties[i].m_pToolProperty->m_nPropertyId ) + { + case PS3_GCCLINKER_OutputFile: + m_XMLWriter.Write( CFmtStrMax( "OutputFile=\"%s\"", pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_GCCLINKER_AdditionalDependencies: + m_XMLWriter.Write( CFmtStrMax( "AdditionalDependencies=\"%s\"", pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_GCCLINKER_AdditionalLibraryDirectories: + m_XMLWriter.Write( CFmtStrMax( "AdditionalLibraryDirectories=\"%s\"", pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_GCCLINKER_ImportLibrary: + m_XMLWriter.Write( CFmtStrMax( "ImportLibrary=\"%s\"", pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_GCCLINKER_SPURSUsage: + if ( nOrdinalValue == 1 ) + { + additionalOptions += "-mspurs-job-initialize "; + } + else if ( nOrdinalValue == 2 ) + { + additionalOptions += "-mspurs-job "; + } + else if ( nOrdinalValue == 3 ) + { + additionalOptions += "-mspurs-task "; + } + break; + + case PS3_GCCLINKER_PositionIndependentCode: + if ( nOrdinalValue ) + { + additionalOptions += "-fpic "; + } + break; + + case PS3_GCCLINKER_EmitRelocations: + if ( nOrdinalValue ) + { + additionalOptions += "-Wl,-q "; + } + break; + + case PS3_GCCLINKER_GarbageCollection: + if ( nOrdinalValue ) + { + additionalOptions += "-Wl,--gc-sections "; + } + break; + + case PS3_GCCLINKER_GenerateMapFile: + if ( nOrdinalValue == 1 ) + { + additionalOptions += CFmtStrMax( "-Map="%s" ", pLinkerTool->m_PropertyStates.GetProperty( PS3_GCCLINKER_MapFileName )->m_StringValue ); + } + break; + + case PS3_GCCLINKER_MapFileName: + m_XMLWriter.Write( CFmtStrMax( "MapFileName=\"%s\"", pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_GCCLINKER_LinkLibraryDependencies: + m_XMLWriter.Write( CFmtStrMax( "LinkLibraryDependencies=\"%s\"", BoolStringToTrueFalseString( pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ) ); + break; + + case PS3_SNCLINKER_AdditionalOptions: + if ( !pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue.IsEmpty() ) + { + additionalOptions += pLinkerTool->m_PropertyStates.m_Properties[i].m_StringValue; + additionalOptions += " "; + } + break; + } + } + + if ( !additionalOptions.IsEmpty() ) + { + m_XMLWriter.Write( CFmtStrMax( "AdditionalOptions=\"%s\"", additionalOptions.Get() ) ); + } + + m_XMLWriter.PopNode( false ); + + return true; +} + +bool CProjectGenerator_PS3::WriteLibrarianTool( CLibrarianTool *pLibrarianTool ) +{ + if ( !pLibrarianTool ) + { + // not an error, some tools n/a for aconfig + return true; + } + + m_XMLWriter.PushNode( "Tool" ); + + m_XMLWriter.Write( "Name=\"VCLibrarianTool\"" ); + + for ( int i = 0; i < pLibrarianTool->m_PropertyStates.m_Properties.Count(); i++ ) + { + switch ( pLibrarianTool->m_PropertyStates.m_Properties[i].m_pToolProperty->m_nPropertyId ) + { + case PS3_LIBRARIAN_OutputFile: + m_XMLWriter.Write( CFmtStrMax( "OutputFile=\"%s\"", pLibrarianTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + case PS3_LIBRARIAN_AdditionalDependencies: + m_XMLWriter.Write( CFmtStrMax( "AdditionalDependencies=\"%s\"", pLibrarianTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + case PS3_LIBRARIAN_WholeArchive: + // can't decode, seems broken + break; + case PS3_LIBRARIAN_LinkLibraryDependencies: + m_XMLWriter.Write( CFmtStrMax( "LinkLibraryDependencies=\"%s\"", BoolStringToTrueFalseString( pLibrarianTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ) ); + break; + } + } + + m_XMLWriter.PopNode( false ); + + return true; +} + +bool CProjectGenerator_PS3::WritePostBuildEventTool( CPostBuildEventTool *pPostBuildEventTool ) +{ + if ( !pPostBuildEventTool ) + { + // not an error, some tools n/a for aconfig + return true; + } + + m_XMLWriter.PushNode( "Tool" ); + + m_XMLWriter.Write( "Name=\"VCPostBuildEventTool\"" ); + + for ( int i = 0; i < pPostBuildEventTool->m_PropertyStates.m_Properties.Count(); i++ ) + { + switch ( pPostBuildEventTool->m_PropertyStates.m_Properties[i].m_pToolProperty->m_nPropertyId ) + { + case PS3_POSTBUILDEVENT_CommandLine: + m_XMLWriter.Write( CFmtStrMax( "CommandLine=\"%s\"", m_XMLWriter.FixupXMLString( pPostBuildEventTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ) ); + break; + + case PS3_POSTBUILDEVENT_Description: + m_XMLWriter.Write( CFmtStrMax( "Description=\"%s\"", pPostBuildEventTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_POSTBUILDEVENT_ExcludedFromBuild: + m_XMLWriter.Write( CFmtStrMax( "ExcludedFromBuild=\"%s\"", BoolStringToTrueFalseString( pPostBuildEventTool->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ) ); + break; + } + } + + m_XMLWriter.PopNode( false ); + + return true; +} + +const char *CProjectGenerator_PS3::BoolStringToTrueFalseString( const char *pValue ) +{ + return Sys_StringToBool( pValue ) ? "true" : "false"; +} + +bool CProjectGenerator_PS3::WriteConfiguration( CProjectConfiguration *pConfig ) +{ + if ( pConfig->m_bIsFileConfig ) + { + m_XMLWriter.PushNode( "FileConfiguration" ); + } + else + { + m_XMLWriter.PushNode( "Configuration" ); + } + + const char *pOutputName = "???"; + if ( !V_stricmp( pConfig->m_Name.Get(), "debug" ) ) + { + if ( m_pVCProjGenerator->GetVSIType() == PS3_VSI_TYPE_SNC ) + { + pOutputName = "PS3SNCDebug|Win32"; + } + else if ( m_pVCProjGenerator->GetVSIType() == PS3_VSI_TYPE_GCC ) + { + pOutputName = "PS3GCCDebug|Win32"; + } + } + else if ( !V_stricmp( pConfig->m_Name.Get(), "release" ) ) + { + if ( m_pVCProjGenerator->GetVSIType() == PS3_VSI_TYPE_SNC ) + { + pOutputName = "PS3SNCRelease|Win32"; + } + else if ( m_pVCProjGenerator->GetVSIType() == PS3_VSI_TYPE_GCC ) + { + pOutputName = "PS3GCCRelease|Win32"; + } + } + else + { + return false; + } + + m_XMLWriter.Write( CFmtStrMax( "Name=\"%s\"", pOutputName ) ); + + // write configuration properties + for ( int i = 0; i < pConfig->m_PropertyStates.m_Properties.Count(); i++ ) + { + switch ( pConfig->m_PropertyStates.m_Properties[i].m_pToolProperty->m_nPropertyId ) + { + case PS3_GENERAL_ConfigurationType: + m_XMLWriter.Write( CFmtStrMax( "ConfigurationType=\"%s\"", pConfig->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_GENERAL_ExcludedFromBuild: + m_XMLWriter.Write( CFmtStrMax( "ExcludedFromBuild=\"%s\"", BoolStringToTrueFalseString( pConfig->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ) ); + break; + + case PS3_GENERAL_OutputDirectory: + m_XMLWriter.Write( CFmtStrMax( "OutputDirectory=\"%s\"", pConfig->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_GENERAL_IntermediateDirectory: + m_XMLWriter.Write( CFmtStrMax( "IntermediateDirectory=\"%s\"", pConfig->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_GENERAL_ExtensionsToDeleteOnClean: + m_XMLWriter.Write( CFmtStrMax( "DeleteExtensionsOnClean=\"%s\"", pConfig->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_GENERAL_BuildLogFile: + m_XMLWriter.Write( CFmtStrMax( "BuildLogFile=\"%s\"", pConfig->m_PropertyStates.m_Properties[i].m_StringValue.Get() ) ); + break; + + case PS3_GENERAL_SystemIncludeDependencies: + // ignoring + break; + + case PS3_GENERAL_SaveDebuggerPropertiesInProject: + // ignoring + break; + } + } + + m_XMLWriter.Write( ">" ); + + if ( !WritePreBuildEventTool( pConfig->GetPreBuildEventTool() ) ) + return false; + + if ( !WriteCustomBuildTool( pConfig->GetCustomBuildTool() ) ) + return false; + + if ( m_pVCProjGenerator->GetVSIType() == PS3_VSI_TYPE_SNC ) + { + if ( !WriteSNCCompilerTool( pConfig->GetCompilerTool() ) ) + return false; + } + else if ( m_pVCProjGenerator->GetVSIType() == PS3_VSI_TYPE_GCC ) + { + if ( !WriteGCCCompilerTool( pConfig->GetCompilerTool() ) ) + return false; + } + + if ( !WritePreLinkEventTool( pConfig->GetPreLinkEventTool() ) ) + return false; + + if ( m_pVCProjGenerator->GetVSIType() == PS3_VSI_TYPE_SNC ) + { + if ( !WriteSNCLinkerTool( pConfig->GetLinkerTool() ) ) + return false; + } + else if ( m_pVCProjGenerator->GetVSIType() == PS3_VSI_TYPE_GCC ) + { + if ( !WriteGCCLinkerTool( pConfig->GetLinkerTool() ) ) + return false; + } + + if ( !WriteLibrarianTool( pConfig->GetLibrarianTool() ) ) + return false; + + if ( !WritePostBuildEventTool( pConfig->GetPostBuildEventTool() ) ) + return false; + + m_XMLWriter.PopNode( true ); + + return true; +} + +bool CProjectGenerator_PS3::WriteToXML() +{ + m_XMLWriter.PushNode( "VisualStudioProject" ); + m_XMLWriter.Write( "ProjectType=\"Visual C++\"" ); + m_XMLWriter.Write( "Version=\"8.00\"" ); + m_XMLWriter.Write( CFmtStrMax( "Name=\"%s\"", m_pVCProjGenerator->GetProjectName().Get() ) ); + m_XMLWriter.Write( CFmtStrMax( "ProjectGUID=\"%s\"", m_pVCProjGenerator->GetGUIDString().Get() ) ); + m_XMLWriter.Write( CFmtStrMax( "RootNamespace=\"%s\"", m_pVCProjGenerator->GetProjectName().Get() ) ); + if ( g_pVPC->BUseP4SCC() ) + m_XMLWriter.Write( "SccProjectName=\"Perforce Project\"\nSccLocalPath=\"..\"\nSccProvider=\"MSSCCI:Perforce SCM\"\n" ); + m_XMLWriter.Write( ">" ); + + m_XMLWriter.PushNode( "Platforms" ); + m_XMLWriter.PushNode( "Platform" ); + m_XMLWriter.Write( "Name=\"win32\"" ); + m_XMLWriter.PopNode( false ); + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PushNode( "ToolFiles" ); + m_XMLWriter.PopNode( true ); + + CUtlVector< CUtlString > configurationNames; + m_pVCProjGenerator->GetAllConfigurationNames( configurationNames ); + + // write the root configurations + m_XMLWriter.PushNode( "Configurations" ); + for ( int i = 0; i < configurationNames.Count(); i++ ) + { + CProjectConfiguration *pConfiguration = NULL; + if ( m_pVCProjGenerator->GetRootConfiguration( configurationNames[i].Get(), &pConfiguration ) ) + { + if ( !WriteConfiguration( pConfiguration ) ) + return false; + } + } + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PushNode( "References" ); + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PushNode( "Files" ); + + CProjectFolder *pRootFolder = m_pVCProjGenerator->GetRootFolder(); + for ( int iIndex = pRootFolder->m_Folders.Head(); iIndex != pRootFolder->m_Folders.InvalidIndex(); iIndex = pRootFolder->m_Folders.Next( iIndex ) ) + { + if ( !WriteFolder( pRootFolder->m_Folders[iIndex] ) ) + return false; + } + + for ( int iIndex = pRootFolder->m_Files.Head(); iIndex != pRootFolder->m_Files.InvalidIndex(); iIndex = pRootFolder->m_Files.Next( iIndex ) ) + { + if ( !WriteFile( pRootFolder->m_Files[iIndex] ) ) + return false; + } + + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PushNode( "Globals" ); + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PopNode( true ); + + return true; +} + +bool CProjectGenerator_PS3::Save( const char *pOutputFilename ) +{ + if ( !m_XMLWriter.Open( pOutputFilename ) ) + return false; + + bool bValid = WriteToXML(); + + m_XMLWriter.Close(); + + if ( bValid ) + { + // Not sure what this file does or why, but we emit it and + // its part of a default SN project. The custom build steps + // were copied are hosted in all the vpc ps3 base scripts. + FILE *fp = fopen( "vsi.nul", "wt" ); + if ( fp ) + { + fprintf( fp, "SN Visual Studio Integration\n" ); + fprintf( fp, "IMPORTANT: Do not remove the custom build step for this file\n" ); + fclose( fp ); + } + } + + return bValid; +} + + + diff --git a/external/vpc/utils/vpc/projectgenerator_ps3.h b/external/vpc/utils/vpc/projectgenerator_ps3.h new file mode 100644 index 0000000..c217af5 --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_ps3.h @@ -0,0 +1,47 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef PROJECTGENERATOR_PS3_H +#define PROJECTGENERATOR_PS3_H +#ifdef _WIN32 +#pragma once +#endif + +#define PROPERTYNAME( X, Y ) X##_##Y, +enum PS3Properties_e +{ + #include "projectgenerator_ps3.inc" +}; + +class CProjectGenerator_PS3 : public IVCProjWriter +{ +public: + CProjectGenerator_PS3(); + IBaseProjectGenerator *GetProjectGenerator() { return m_pVCProjGenerator; } + + virtual bool Save( const char *pOutputFilename ); + +private: + bool WriteToXML(); + bool WriteFolder( CProjectFolder *pFolder ); + bool WriteFile( CProjectFile *pFile ); + bool WriteConfiguration( CProjectConfiguration *pConfig ); + bool WritePreBuildEventTool( CPreBuildEventTool *pPreBuildEventTool ); + bool WriteCustomBuildTool( CCustomBuildTool *pCustomBuildTool ); + bool WriteSNCCompilerTool( CCompilerTool *pCompilerTool ); + bool WriteGCCCompilerTool( CCompilerTool *pCompilerTool ); + bool WriteSNCLinkerTool( CLinkerTool *pLinkerTool ); + bool WriteGCCLinkerTool( CLinkerTool *pLinkerTool ); + bool WritePreLinkEventTool( CPreLinkEventTool *pPreLinkEventTool ); + bool WriteLibrarianTool( CLibrarianTool *pLibrarianTool ); + bool WritePostBuildEventTool( CPostBuildEventTool *pPostBuildEventTool ); + const char *BoolStringToTrueFalseString( const char *pValue ); + + CXMLWriter m_XMLWriter; + CVCProjGenerator *m_pVCProjGenerator; +}; + +#endif // PROJECTGENERATOR_PS3_H diff --git a/external/vpc/utils/vpc/projectgenerator_ps3.inc b/external/vpc/utils/vpc/projectgenerator_ps3.inc new file mode 100644 index 0000000..1f337f5 --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_ps3.inc @@ -0,0 +1,137 @@ + +//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Property Enumerations +// +//=====================================================================================// + +// Config +PROPERTYNAME( PS3_GENERAL, ConfigurationType ) +PROPERTYNAME( PS3_GENERAL, ExcludedFromBuild ) +PROPERTYNAME( PS3_GENERAL, OutputDirectory ) +PROPERTYNAME( PS3_GENERAL, IntermediateDirectory ) +PROPERTYNAME( PS3_GENERAL, ExtensionsToDeleteOnClean ) +PROPERTYNAME( PS3_GENERAL, BuildLogFile ) +PROPERTYNAME( PS3_GENERAL, SystemIncludeDependencies ) +PROPERTYNAME( PS3_GENERAL, SaveDebuggerPropertiesInProject ) + +// GCC Compiler +PROPERTYNAME( PS3_GCCCOMPILER, AdditionalIncludeDirectories ) +PROPERTYNAME( PS3_GCCCOMPILER, PreprocessorDefinitions ) +PROPERTYNAME( PS3_GCCCOMPILER, ForceIncludes ) +PROPERTYNAME( PS3_GCCCOMPILER, GenerateDebugInformation ) +PROPERTYNAME( PS3_GCCCOMPILER, Warnings ) +PROPERTYNAME( PS3_GCCCOMPILER, ExtraWarnings ) +PROPERTYNAME( PS3_GCCCOMPILER, WarnLoadHitStores ) +PROPERTYNAME( PS3_GCCCOMPILER, WarnMicrocodedInstruction ) +PROPERTYNAME( PS3_GCCCOMPILER, TreatWarningsAsErrors ) +PROPERTYNAME( PS3_GCCCOMPILER, ObjectFileName ) +PROPERTYNAME( PS3_GCCCOMPILER, CallprofHierarchicalProfiling ) +PROPERTYNAME( PS3_GCCCOMPILER, SPURSUsage ) +PROPERTYNAME( PS3_GCCCOMPILER, OptimizationLevel ) +PROPERTYNAME( PS3_GCCCOMPILER, FastMath ) +PROPERTYNAME( PS3_GCCCOMPILER, NoStrictAliasing ) +PROPERTYNAME( PS3_GCCCOMPILER, UnrollLoops ) +PROPERTYNAME( PS3_GCCCOMPILER, InlineFunctionSizeLimit ) +PROPERTYNAME( PS3_GCCCOMPILER, TOCUsage ) +PROPERTYNAME( PS3_GCCCOMPILER, SaveRestoreFunctions ) +PROPERTYNAME( PS3_GCCCOMPILER, GenerateMicrocodedInstructions ) +PROPERTYNAME( PS3_GCCCOMPILER, PositionIndependentCode ) +PROPERTYNAME( PS3_GCCCOMPILER, FunctionSections ) +PROPERTYNAME( PS3_GCCCOMPILER, DataSections ) +PROPERTYNAME( PS3_GCCCOMPILER, StackCheck ) +PROPERTYNAME( PS3_GCCCOMPILER, CPPExceptionsAndRTTIUsage ) +PROPERTYNAME( PS3_GCCCOMPILER, CheckANSICompliance ) +PROPERTYNAME( PS3_GCCCOMPILER, DefaultCharSigned ) +PROPERTYNAME( PS3_GCCCOMPILER, Permissive ) +PROPERTYNAME( PS3_GCCCOMPILER, EnableMSExtensions ) +PROPERTYNAME( PS3_GCCCOMPILER, RelaxCPPCompliance ) +PROPERTYNAME( PS3_GCCCOMPILER, AdditionalOptions ) + +// Librarian +PROPERTYNAME( PS3_LIBRARIAN, OutputFile ) +PROPERTYNAME( PS3_LIBRARIAN, AdditionalDependencies ) +PROPERTYNAME( PS3_LIBRARIAN, WholeArchive ) +PROPERTYNAME( PS3_LIBRARIAN, LinkLibraryDependencies ) + +// GCC Linker +PROPERTYNAME( PS3_GCCLINKER, OutputFile ) +PROPERTYNAME( PS3_GCCLINKER, AdditionalDependencies ) +PROPERTYNAME( PS3_GCCLINKER, AdditionalLibraryDirectories ) +PROPERTYNAME( PS3_GCCLINKER, ImportLibrary ) +PROPERTYNAME( PS3_GCCLINKER, SPURSUsage ) +PROPERTYNAME( PS3_GCCLINKER, PositionIndependentCode ) +PROPERTYNAME( PS3_GCCLINKER, EmitRelocations ) +PROPERTYNAME( PS3_GCCLINKER, GarbageCollection ) +PROPERTYNAME( PS3_GCCLINKER, GenerateMapFile ) +PROPERTYNAME( PS3_GCCLINKER, MapFileName ) +PROPERTYNAME( PS3_GCCLINKER, LinkLibraryDependencies ) +PROPERTYNAME( PS3_GCCLINKER, AdditionalOptions ) + +// SNC Compiler +PROPERTYNAME( PS3_SNCCOMPILER, AdditionalIncludeDirectories ) +PROPERTYNAME( PS3_SNCCOMPILER, PreprocessorDefinitions ) +PROPERTYNAME( PS3_SNCCOMPILER, ForceIncludes ) +PROPERTYNAME( PS3_SNCCOMPILER, GenerateDebugInformation ) +PROPERTYNAME( PS3_SNCCOMPILER, Warnings ) +PROPERTYNAME( PS3_SNCCOMPILER, TreatMessagesAsErrors ) +PROPERTYNAME( PS3_SNCCOMPILER, DisableSpecificWarnings ) +PROPERTYNAME( PS3_SNCCOMPILER, ObjectFileName ) +PROPERTYNAME( PS3_SNCCOMPILER, CallprofHierarchicalProfiling ) +PROPERTYNAME( PS3_SNCCOMPILER, OptimizationLevel ) +PROPERTYNAME( PS3_SNCCOMPILER, FastMath ) +PROPERTYNAME( PS3_SNCCOMPILER, RelaxAliasChecking ) +PROPERTYNAME( PS3_SNCCOMPILER, BranchlessCompares ) +PROPERTYNAME( PS3_SNCCOMPILER, UnrollLoops ) +PROPERTYNAME( PS3_SNCCOMPILER, AssumeAlignedPointers ) +PROPERTYNAME( PS3_SNCCOMPILER, AssumeCorrectSign ) +PROPERTYNAME( PS3_SNCCOMPILER, TOCPointerPreservation ) +PROPERTYNAME( PS3_SNCCOMPILER, InitializedDataPlacement ) +PROPERTYNAME( PS3_SNCCOMPILER, PromoteFPConstantsToDoubles ) +PROPERTYNAME( PS3_SNCCOMPILER, CCPPDialect ) +PROPERTYNAME( PS3_SNCCOMPILER, CPPExceptionsAndRTTIUsage ) +PROPERTYNAME( PS3_SNCCOMPILER, DefaultCharUnsigned ) +PROPERTYNAME( PS3_SNCCOMPILER, DefaultFPConstantsAsTypeFloat ) +PROPERTYNAME( PS3_SNCCOMPILER, BuiltInDefinitionForWCHAR_TType ) +PROPERTYNAME( PS3_SNCCOMPILER, CreateUsePrecompiledHeader ) +PROPERTYNAME( PS3_SNCCOMPILER, PrecompiledHeaderFile ) +PROPERTYNAME( PS3_SNCCOMPILER, AdditionalOptions ) + +// SNC Linker +PROPERTYNAME( PS3_SNCLINKER, OutputFile ) +PROPERTYNAME( PS3_SNCLINKER, OutputFormat ) +PROPERTYNAME( PS3_SNCLINKER, AdditionalDependencies ) +PROPERTYNAME( PS3_SNCLINKER, AdditionalLibraryDirectories ) +PROPERTYNAME( PS3_SNCLINKER, IgnoreAllDefaultLibraries ) +PROPERTYNAME( PS3_SNCLINKER, UsingExceptionHandling ) +PROPERTYNAME( PS3_SNCLINKER, TOCPointerElimination ) +PROPERTYNAME( PS3_SNCLINKER, ForceSymbolReferences ) +PROPERTYNAME( PS3_SNCLINKER, CallprofHierarchicalProfiling ) +PROPERTYNAME( PS3_SNCLINKER, DebugInfoAndSymbolStripping ) +PROPERTYNAME( PS3_SNCLINKER, UnusedFunctionAndDataStripping ) +PROPERTYNAME( PS3_SNCLINKER, ImportLibrary ) +PROPERTYNAME( PS3_SNCLINKER, GenerateMapFile ) +PROPERTYNAME( PS3_SNCLINKER, MapFileName ) +PROPERTYNAME( PS3_SNCLINKER, LinkLibraryDependencies ) +PROPERTYNAME( PS3_SNCLINKER, AdditionalOptions ) + +// Pre Build +PROPERTYNAME( PS3_PREBUILDEVENT, CommandLine ) +PROPERTYNAME( PS3_PREBUILDEVENT, Description ) +PROPERTYNAME( PS3_PREBUILDEVENT, ExcludedFromBuild ) + +// Pre Link +PROPERTYNAME( PS3_PRELINKEVENT, CommandLine ) +PROPERTYNAME( PS3_PRELINKEVENT, Description ) +PROPERTYNAME( PS3_PRELINKEVENT, ExcludedFromBuild ) + +// Post Build +PROPERTYNAME( PS3_POSTBUILDEVENT, CommandLine ) +PROPERTYNAME( PS3_POSTBUILDEVENT, Description ) +PROPERTYNAME( PS3_POSTBUILDEVENT, ExcludedFromBuild ) + +// Custom Build +PROPERTYNAME( PS3_CUSTOMBUILDSTEP, CommandLine ) +PROPERTYNAME( PS3_CUSTOMBUILDSTEP, Description ) +PROPERTYNAME( PS3_CUSTOMBUILDSTEP, Outputs ) +PROPERTYNAME( PS3_CUSTOMBUILDSTEP, AdditionalDependencies ) diff --git a/external/vpc/utils/vpc/projectgenerator_vcproj.cpp b/external/vpc/utils/vpc/projectgenerator_vcproj.cpp new file mode 100644 index 0000000..60a3bcf --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_vcproj.cpp @@ -0,0 +1,1939 @@ +//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: VPC +// +//=====================================================================================// + +#include "vpc.h" + +CProjectFile::CProjectFile( CVCProjGenerator *pGenerator, const char *pFilename ) +{ + m_pGenerator = pGenerator; + m_Name = pFilename; +} + +CProjectFile::~CProjectFile() +{ + m_Configs.PurgeAndDeleteElements(); +} + +bool CProjectFile::GetConfiguration( const char *pConfigName, CProjectConfiguration **ppConfig ) +{ + if ( !pConfigName || !pConfigName[0] ) + { + g_pVPC->VPCError( "Empty or bad configuration name." ); + } + + if ( ppConfig ) + { + // assume not found + *ppConfig = NULL; + } + + for ( int i = 0; i < m_Configs.Count(); i++ ) + { + if ( !V_stricmp( m_Configs[i]->m_Name.Get(), pConfigName ) ) + { + // found + if ( ppConfig ) + { + *ppConfig = m_Configs[i]; + } + return true; + } + } + + // not found + return false; +} + +bool CProjectFile::AddConfiguration( const char *pConfigName, CProjectConfiguration **ppConfig ) +{ + if ( ppConfig ) + { + // assume not found + *ppConfig = NULL; + } + + if ( GetConfiguration( pConfigName, NULL ) ) + { + // found, cannot add duplicate + return false; + } + + // add in alphabetic order + CProjectConfiguration *pNewConfig = new CProjectConfiguration( m_pGenerator, pConfigName, m_Name.Get() ); + + int iIndex = 0; + for ( iIndex = 0; iIndex < m_Configs.Count(); iIndex++ ) + { + if ( V_stricmp( pConfigName, m_Configs[iIndex]->m_Name.Get() ) < 0 ) + { + m_Configs.InsertBefore( iIndex, pNewConfig ); + break; + } + } + if ( iIndex == m_Configs.Count() ) + { + m_Configs.AddToTail( pNewConfig ); + } + + if ( ppConfig ) + { + *ppConfig = pNewConfig; + } + return true; +} + +bool CProjectFile::RemoveConfiguration( CProjectConfiguration *pConfiguration ) +{ + for ( int i = 0; i < m_Configs.Count(); i++ ) + { + if ( m_Configs[i] == pConfiguration ) + { + m_Configs.Remove( i ); + delete pConfiguration; + return true; + } + } + + return false; +} + +CProjectFolder::CProjectFolder( CVCProjGenerator *pGenerator, const char *pFolderName ) +{ + m_pGenerator = pGenerator; + m_Name = pFolderName; +} + +CProjectFolder::~CProjectFolder() +{ + m_Folders.PurgeAndDeleteElements(); + m_Files.PurgeAndDeleteElements(); +} + +bool CProjectFolder::GetFolder( const char *pFolderName, CProjectFolder **pFolder ) +{ + if ( pFolder ) + { + // assume not found + *pFolder = NULL; + } + + if ( !pFolderName || !pFolderName[0] ) + { + g_pVPC->VPCError( "Empty or bad folder name." ); + } + + for ( int iIndex = m_Folders.Head(); iIndex != m_Folders.InvalidIndex(); iIndex = m_Folders.Next( iIndex ) ) + { + if ( !V_stricmp( m_Folders[iIndex]->m_Name.Get(), pFolderName ) ) + { + // found + if ( pFolder ) + { + *pFolder = m_Folders[iIndex]; + } + return true; + } + } + + // not found + return false; +} + +bool CProjectFolder::AddFolder( const char *pFolderName, CProjectFolder **pFolder ) +{ + if ( pFolder ) + { + // assume not added + *pFolder = NULL; + } + + if ( GetFolder( pFolderName, NULL ) ) + { + // found, cannot add duplicate + return false; + } + + CProjectFolder *pNewFolder = new CProjectFolder( m_pGenerator, pFolderName ); + + // maintain sorted ascending alphabetic order + int iIndex; + for ( iIndex = m_Folders.Head(); iIndex != m_Folders.InvalidIndex(); iIndex = m_Folders.Next( iIndex ) ) + { + if ( V_stricmp( pFolderName, m_Folders[iIndex]->m_Name.Get() ) < 0 ) + { + m_Folders.InsertBefore( iIndex, pNewFolder ); + break; + } + } + if ( iIndex == m_Folders.InvalidIndex() ) + { + m_Folders.AddToTail( pNewFolder ); + } + + if ( pFolder ) + { + *pFolder = pNewFolder; + } + return true; +} + +void CProjectFolder::AddFile( const char *pFilename, CProjectFile **ppFile ) +{ + if ( !pFilename || !pFilename[0] ) + { + g_pVPC->VPCError( "Empty or bad filename." ); + } + + CProjectFile *pNewFile = new CProjectFile( m_pGenerator, pFilename ); + + // maintain sorted ascending alphabetic order + int iIndex; + for ( iIndex = m_Files.Head(); iIndex != m_Files.InvalidIndex(); iIndex = m_Files.Next( iIndex ) ) + { + if ( g_pVPC->IsPlatformDefined( "PS3" ) ) + { + // temporary legacy behavior for diff ease until I can be sure project generation is equivalent + iIndex = m_Files.InvalidIndex(); + break; + } + + // the COM layer for WIN32 sorted by filename only, and NOT the entire path + if ( V_stricmp( V_GetFileName( pFilename ), V_GetFileName( m_Files[iIndex]->m_Name.Get() ) ) < 0 ) + { + m_Files.InsertBefore( iIndex, pNewFile ); + break; + } + } + if ( iIndex == m_Files.InvalidIndex() ) + { + m_Files.AddToTail( pNewFile ); + } + + if ( ppFile ) + { + *ppFile = pNewFile; + } +} + +bool CProjectFolder::FindFile( const char *pFilename ) +{ + if ( !pFilename || !pFilename[0] ) + { + g_pVPC->VPCError( "Empty or bad filename." ); + } + + for ( int iIndex = m_Files.Head(); iIndex != m_Files.InvalidIndex(); iIndex = m_Files.Next( iIndex ) ) + { + if ( !V_stricmp( m_Files[iIndex]->m_Name.Get(), pFilename ) ) + { + // found + return true; + } + } + + return false; +} + +bool CProjectFolder::RemoveFile( const char *pFilename ) +{ + if ( !pFilename || !pFilename[0] ) + { + g_pVPC->VPCError( "Empty or bad filename." ); + } + + for ( int iIndex = m_Files.Head(); iIndex != m_Files.InvalidIndex(); iIndex = m_Files.Next( iIndex ) ) + { + if ( !V_stricmp( m_Files[iIndex]->m_Name.Get(), pFilename ) ) + { + // found, remove + delete m_Files[iIndex]; + m_Files.Unlink( iIndex ); + return true; + } + } + + return false; +} + +bool CPropertyStateLessFunc::Less( const int& lhs, const int& rhs, void *pContext ) +{ + int lhsPropertyId = (( CPropertyStates* )pContext)->m_Properties[lhs].m_pToolProperty->m_nPropertyId; + int rhsPropertyId = (( CPropertyStates* )pContext)->m_Properties[rhs].m_pToolProperty->m_nPropertyId; + + return lhsPropertyId < rhsPropertyId; +} + +CPropertyStates::CPropertyStates() +{ + m_PropertiesInOutputOrder.SetLessContext( this ); +} + +PropertyState_t *CPropertyStates::GetProperty( int nPropertyId ) +{ + for ( int i = 0 ; i < m_Properties.Count(); i++ ) + { + if ( m_Properties[i].m_pToolProperty->m_nPropertyId == nPropertyId ) + { + return &m_Properties[i]; + } + } + + return NULL; +} + +PropertyState_t *CPropertyStates::GetProperty( const char *pPropertyName ) +{ + if ( pPropertyName[0] == '$' ) + { + pPropertyName++; + } + + for ( int i = 0; i < m_Properties.Count(); i++ ) + { + const char *pParseString = m_Properties[i].m_pToolProperty->m_ParseString.Get(); + if ( pParseString[0] == '$' ) + { + pParseString++; + } + if ( !V_stricmp( pPropertyName, pParseString ) ) + { + return &m_Properties[i]; + } + + const char *pLegacyString = m_Properties[i].m_pToolProperty->m_LegacyString.Get(); + if ( pLegacyString[0] ) + { + if ( pLegacyString[0] == '$' ) + { + pLegacyString++; + } + if ( !V_stricmp( pPropertyName, pLegacyString ) ) + { + return &m_Properties[i]; + } + } + } + + return NULL; +} + +bool CPropertyStates::SetStringProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool ) +{ + // find possible current value + const char *pCurrentValue = NULL; + for ( int i = 0; i < m_Properties.Count(); i++ ) + { + if ( m_Properties[i].m_pToolProperty == pToolProperty ) + { + pCurrentValue = m_Properties[i].m_StringValue.Get(); + break; + } + } + + if ( !pCurrentValue && pRootTool ) + { + // fallback to root tool's config to find current value + for ( int i = 0; i < pRootTool->m_PropertyStates.m_Properties.Count(); i++ ) + { + if ( pRootTool->m_PropertyStates.m_Properties[i].m_pToolProperty == pToolProperty ) + { + pCurrentValue = pRootTool->m_PropertyStates.m_Properties[i].m_StringValue.Get(); + break; + } + } + } + + // feed in current value to resolve $BASE + // possibly culled or tokenized new value + char buff[MAX_SYSTOKENCHARS]; + if ( !g_pVPC->GetScript().ParsePropertyValue( pCurrentValue, buff, sizeof( buff ) ) ) + return true; + + if ( pToolProperty->m_bFixSlashes ) + { + V_FixSlashes( buff ); + } + + if ( pToolProperty->m_bPreferSemicolonNoComma ) + { + CUtlString buffCopy = buff; + V_StrSubst( buffCopy.Get(), ",", ";", buff, sizeof( buff ), false ); + } + + if ( pToolProperty->m_bPreferSemicolonNoSpace ) + { + CUtlString buffCopy = buff; + V_StrSubst( buffCopy.Get(), " ", ";", buff, sizeof( buff ), false ); + } + + if ( pToolProperty->m_bAppendSlash ) + { + int len = strlen( buff ); + if ( len >= 1 && buff[len-1] != '\\' ) + { + V_strncat( buff, "\\", sizeof( buff ) ); + } + } + + if ( !V_stricmp( pToolProperty->m_ParseString.Get(), "$CommandLine" ) && !V_strnicmp( buff, "echo ", 5 ) ) + { + // the COM layer auto appended a CR-LF for a command line with an echo + int len = strlen( buff ); + if ( ( len >= 1 && buff[len-1] != '\n' ) && + ( len >= 12 && V_stricmp( buff + len - 12, "
" ) ) ) + { + V_strncat( buff, "\n", sizeof( buff ) ); + } + } + + if ( pCurrentValue && !V_stricmp( pCurrentValue, buff ) ) + { + g_pVPC->VPCWarning( "%s matches default setting, [%s line:%d]", pToolProperty->m_ParseString.Get(), g_pVPC->GetScript().GetName(), g_pVPC->GetScript().GetLine() ); + } + + if ( pCurrentValue ) + { + // update existing state + // always replace or add strings due to case changes + for ( int i = 0; i < m_Properties.Count(); i++ ) + { + if ( m_Properties[i].m_pToolProperty == pToolProperty ) + { + m_Properties[i].m_StringValue = buff; + return true; + } + } + } + + // add + int iIndex = m_Properties.AddToTail(); + m_Properties[iIndex].m_pToolProperty = pToolProperty; + m_Properties[iIndex].m_StringValue = buff; + + m_PropertiesInOutputOrder.Insert( iIndex ); + + return true; +} + +bool CPropertyStates::SetListProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool ) +{ + char buff[MAX_SYSTOKENCHARS]; + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, buff, sizeof( buff ) ) ) + return true; + + // resolve the parsed token to an expected ordinal + const char *pNewOrdinalValue = NULL; + for ( int i = 0; i < pToolProperty->m_Ordinals.Count() ;i++ ) + { + if ( !V_stricmp( pToolProperty->m_Ordinals[i].m_ParseString.Get(), buff ) ) + { + pNewOrdinalValue = pToolProperty->m_Ordinals[i].m_ValueString.Get(); + break; + } + } + + if ( !pNewOrdinalValue && !V_stricmp( buff, "default" ) ) + { + // allow "default" if not explicitly provided + // same as empty, state stays unaffected + return true; + } + + if ( !pNewOrdinalValue ) + { + g_pVPC->VPCSyntaxError( "Unknown Ordinal for %s", pToolProperty->m_ParseString.Get() ); + } + + // find possible current value + const char *pCurrentOrdinalValue = NULL; + for ( int i = 0; i < m_Properties.Count(); i++ ) + { + if ( m_Properties[i].m_pToolProperty == pToolProperty ) + { + pCurrentOrdinalValue = m_Properties[i].m_StringValue.Get(); + break; + } + } + + if ( !pCurrentOrdinalValue && pRootTool ) + { + // fallback to root tool's config to find current value + for ( int i = 0; i < pRootTool->m_PropertyStates.m_Properties.Count(); i++ ) + { + if ( pRootTool->m_PropertyStates.m_Properties[i].m_pToolProperty == pToolProperty ) + { + pCurrentOrdinalValue = pRootTool->m_PropertyStates.m_Properties[i].m_StringValue.Get(); + break; + } + } + } + + if ( pCurrentOrdinalValue && !V_stricmp( pCurrentOrdinalValue, pNewOrdinalValue ) ) + { + g_pVPC->VPCWarning( "%s matches default setting, [%s line:%d]", pToolProperty->m_ParseString.Get(), g_pVPC->GetScript().GetName(), g_pVPC->GetScript().GetLine() ); + } + + if ( pCurrentOrdinalValue ) + { + // update existing state + for ( int i = 0; i < m_Properties.Count(); i++ ) + { + if ( m_Properties[i].m_pToolProperty == pToolProperty ) + { + m_Properties[i].m_OrdinalString = buff; + m_Properties[i].m_StringValue = pNewOrdinalValue; + return true; + } + } + } + + // add + int iIndex = m_Properties.AddToTail(); + m_Properties[iIndex].m_pToolProperty = pToolProperty; + m_Properties[iIndex].m_OrdinalString = buff; + m_Properties[iIndex].m_StringValue = pNewOrdinalValue; + + m_PropertiesInOutputOrder.Insert( iIndex ); + + return true; +} + +bool CPropertyStates::SetBoolProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool, bool bEnabled ) +{ + const char *pNewOrdinalValue = bEnabled ? "1" :"0"; + + // find possible current value + const char *pCurrentOrdinalValue = NULL; + for ( int i = 0; i < m_Properties.Count(); i++ ) + { + if ( m_Properties[i].m_pToolProperty == pToolProperty ) + { + pCurrentOrdinalValue = m_Properties[i].m_StringValue.Get(); + break; + } + } + + if ( !pCurrentOrdinalValue && pRootTool ) + { + // fallback to root tool's config to find current value + for ( int i = 0; i < pRootTool->m_PropertyStates.m_Properties.Count(); i++ ) + { + if ( pRootTool->m_PropertyStates.m_Properties[i].m_pToolProperty == pToolProperty ) + { + pCurrentOrdinalValue = pRootTool->m_PropertyStates.m_Properties[i].m_StringValue.Get(); + break; + } + } + } + + if ( pCurrentOrdinalValue && !V_stricmp( pCurrentOrdinalValue, pNewOrdinalValue ) ) + { + g_pVPC->VPCWarning( "%s matches default setting, [%s line:%d]", pToolProperty->m_ParseString.Get(), g_pVPC->GetScript().GetName(), g_pVPC->GetScript().GetLine() ); + } + + if ( pCurrentOrdinalValue ) + { + // update existing state + for ( int i = 0; i < m_Properties.Count(); i++ ) + { + if ( m_Properties[i].m_pToolProperty == pToolProperty ) + { + m_Properties[i].m_StringValue = pNewOrdinalValue; + return true; + } + } + } + + // add + int iIndex = m_Properties.AddToTail(); + m_Properties[iIndex].m_pToolProperty = pToolProperty; + m_Properties[iIndex].m_StringValue = pNewOrdinalValue; + + m_PropertiesInOutputOrder.Insert( iIndex ); + + return true; +} + +bool CPropertyStates::SetBoolProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool ) +{ + char buff[MAX_SYSTOKENCHARS]; + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, buff, sizeof( buff ) ) ) + return true; + + return SetBoolProperty( pToolProperty, pRootTool, Sys_StringToBool( buff ) ); +} + +bool CPropertyStates::SetBoolProperty( ToolProperty_t *pToolProperty, bool bEnabled ) +{ + return SetBoolProperty( pToolProperty, NULL, bEnabled ); +} + +bool CPropertyStates::SetIntegerProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool ) +{ + char buff[MAX_SYSTOKENCHARS]; + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, buff, sizeof( buff ) ) ) + return true; + + // ensure the parsed token is a real integer and not just quietly mapped to 0 + int nParsedValue = atoi( buff ); + if ( V_stricmp( CFmtStr( "%d", nParsedValue ), buff ) ) + { + g_pVPC->VPCSyntaxError( "Unrecognized integer value: %s", buff ); + } + + // find possible current value + const char *pCurrentOrdinalValue = NULL; + for ( int i = 0; i < m_Properties.Count(); i++ ) + { + if ( m_Properties[i].m_pToolProperty == pToolProperty ) + { + pCurrentOrdinalValue = m_Properties[i].m_StringValue.Get(); + break; + } + } + + if ( !pCurrentOrdinalValue && pRootTool ) + { + // fallback to root tool's config to find current value + for ( int i = 0; i < pRootTool->m_PropertyStates.m_Properties.Count(); i++ ) + { + if ( pRootTool->m_PropertyStates.m_Properties[i].m_pToolProperty == pToolProperty ) + { + pCurrentOrdinalValue = pRootTool->m_PropertyStates.m_Properties[i].m_StringValue.Get(); + break; + } + } + } + + if ( pCurrentOrdinalValue && ( atoi( pCurrentOrdinalValue ) == atoi( buff ) ) ) + { + g_pVPC->VPCWarning( "%s matches default setting, [%s line:%d]", pToolProperty->m_ParseString.Get(), g_pVPC->GetScript().GetName(), g_pVPC->GetScript().GetLine() ); + } + + if ( pCurrentOrdinalValue ) + { + // update existing state + for ( int i = 0; i < m_Properties.Count(); i++ ) + { + if ( m_Properties[i].m_pToolProperty == pToolProperty ) + { + m_Properties[i].m_StringValue = buff; + return true; + } + } + } + + // add + int iIndex = m_Properties.AddToTail(); + m_Properties[iIndex].m_pToolProperty = pToolProperty; + m_Properties[iIndex].m_StringValue = buff; + + m_PropertiesInOutputOrder.Insert( iIndex ); + + return true; +} + +bool CPropertyStates::SetProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool ) +{ + bool bHandled = false; + switch ( pToolProperty->m_nType ) + { + case PT_BOOLEAN: + bHandled = SetBoolProperty( pToolProperty, pRootTool ); + break; + + case PT_STRING: + bHandled = SetStringProperty( pToolProperty, pRootTool ); + break; + + case PT_INTEGER: + bHandled = SetIntegerProperty( pToolProperty, pRootTool ); + break; + + case PT_LIST: + bHandled = SetListProperty( pToolProperty, pRootTool ); + break; + + case PT_IGNORE: + bHandled = true; + g_pVPC->GetScript().SkipRestOfLine(); + break; + + case PT_DEPRECATED: + g_pVPC->VPCError( "SetProperty: Property %s has been deprecated and is no longer supported!", pToolProperty->m_ParseString.Get() ); + break; + + default: + g_pVPC->VPCError( "SetProperty: Unknown type for %s - requires implementation", pToolProperty->m_ParseString.Get() ); + } + + return bHandled; +} + +static bool FilesSortLessFunc( CProjectFile* const &pLHS, CProjectFile* const &pRHS ) +{ + return CaselessStringLessThan( pLHS->m_Name.Get(), pRHS->m_Name.Get() ); +} + +CProjectConfiguration::CProjectConfiguration( CVCProjGenerator *pGenerator, const char *pConfigName, const char *pFilename ) +{ + m_pGenerator = pGenerator; + m_Name = pConfigName; + m_bIsFileConfig = ( pFilename != NULL ); + + m_pDebuggingTool = NULL; + m_pCompilerTool = NULL; + m_pLibrarianTool = NULL; + m_pLinkerTool = NULL; + m_pManifestTool = NULL; + m_pXMLDocGenTool = NULL; + m_pBrowseInfoTool = NULL; + m_pResourcesTool = NULL; + m_pPreBuildEventTool = NULL; + m_pPreLinkEventTool = NULL; + m_pPostBuildEventTool = NULL; + m_pCustomBuildTool = NULL; + m_pXboxImageTool = NULL; + m_pXboxDeploymentTool = NULL; + + if ( !m_bIsFileConfig ) + { + m_pDebuggingTool = new CDebuggingTool( pGenerator ); + m_pCompilerTool = new CCompilerTool( pGenerator, pConfigName, false ); + m_pLibrarianTool = new CLibrarianTool( pGenerator ); + m_pLinkerTool = new CLinkerTool( pGenerator ); + m_pManifestTool = new CManifestTool( pGenerator ); + m_pXMLDocGenTool = new CXMLDocGenTool( pGenerator ); + m_pBrowseInfoTool = new CBrowseInfoTool( pGenerator ); + m_pResourcesTool = new CResourcesTool( pGenerator ); + m_pPreBuildEventTool = new CPreBuildEventTool( pGenerator ); + m_pPreLinkEventTool = new CPreLinkEventTool( pGenerator ); + m_pPostBuildEventTool = new CPostBuildEventTool( pGenerator ); + m_pCustomBuildTool = new CCustomBuildTool( pGenerator, pConfigName, false ); + m_pXboxImageTool = new CXboxImageTool( pGenerator ); + m_pXboxDeploymentTool = new CXboxDeploymentTool( pGenerator ); + } + else + { + // a file's config can only be the compiler or the custom build tool + const char *pExtension = V_GetFileExtension( pFilename ); + bool bIsCPP = IsCFileExtension( pExtension ); + bool bIsLib = pExtension && !V_stricmp( pExtension, "lib" ); + if ( bIsCPP ) + { + m_pCompilerTool = new CCompilerTool( pGenerator, pConfigName, true ); + } + else if ( bIsLib ) + { + m_pLibrarianTool = new CLibrarianTool( pGenerator ); + } + else + { + m_pCustomBuildTool = new CCustomBuildTool( pGenerator, pConfigName, true ); + } + } +} + +CProjectConfiguration::~CProjectConfiguration() +{ + delete m_pDebuggingTool; + delete m_pCompilerTool; + delete m_pLibrarianTool; + delete m_pLinkerTool; + delete m_pManifestTool; + delete m_pXMLDocGenTool; + delete m_pBrowseInfoTool; + delete m_pResourcesTool; + delete m_pPreBuildEventTool; + delete m_pPreLinkEventTool; + delete m_pPostBuildEventTool; + delete m_pCustomBuildTool; + delete m_pXboxImageTool; + delete m_pXboxDeploymentTool; +} + +bool CProjectConfiguration::IsEmpty() +{ + if ( m_PropertyStates.m_Properties.Count() ) + return false; + + if ( m_pDebuggingTool && m_pDebuggingTool->m_PropertyStates.m_Properties.Count() ) + return false; + + if ( m_pCompilerTool && m_pCompilerTool->m_PropertyStates.m_Properties.Count() ) + return false; + + if ( m_pLibrarianTool && m_pLibrarianTool->m_PropertyStates.m_Properties.Count() ) + return false; + + if ( m_pLinkerTool && m_pLinkerTool->m_PropertyStates.m_Properties.Count() ) + return false; + + if ( m_pManifestTool && m_pManifestTool->m_PropertyStates.m_Properties.Count() ) + return false; + + if ( m_pXMLDocGenTool && m_pXMLDocGenTool->m_PropertyStates.m_Properties.Count() ) + return false; + + if ( m_pBrowseInfoTool && m_pBrowseInfoTool->m_PropertyStates.m_Properties.Count() ) + return false; + + if ( m_pResourcesTool && m_pResourcesTool->m_PropertyStates.m_Properties.Count() ) + return false; + + if ( m_pPreBuildEventTool && m_pPreBuildEventTool->m_PropertyStates.m_Properties.Count() ) + return false; + + if ( m_pPreLinkEventTool && m_pPreLinkEventTool->m_PropertyStates.m_Properties.Count() ) + return false; + + if ( m_pPostBuildEventTool && m_pPostBuildEventTool->m_PropertyStates.m_Properties.Count() ) + return false; + + if ( m_pCustomBuildTool && m_pCustomBuildTool->m_PropertyStates.m_Properties.Count() ) + return false; + + if ( m_pXboxImageTool && m_pXboxImageTool->m_PropertyStates.m_Properties.Count() ) + return false; + + if ( m_pXboxDeploymentTool && m_pXboxDeploymentTool->m_PropertyStates.m_Properties.Count() ) + return false; + + return true; +} + +bool CProjectConfiguration::SetProperty( ToolProperty_t *pToolProperty ) +{ + bool bHandled = m_PropertyStates.SetProperty( pToolProperty ); + + // have to mimic what the COM layer used to do which is to configure itself based on the type of application its building + // VPC enforces a strict order, configuration blocks must come before any tool block to allow this to be rational + if ( bHandled && !V_stricmp( pToolProperty->m_ParseString, "$ConfigurationType" ) ) + { + PropertyState_t *pPropertyState = m_PropertyStates.GetProperty( pToolProperty->m_nPropertyId ); + if ( pPropertyState && + ( ( V_stristr( pPropertyState->m_OrdinalString.Get(), "static library" ) || !V_stricmp( pPropertyState->m_OrdinalString.Get(), "LIB" ) ) ) ) + { + // static library does not get these tools + delete m_pResourcesTool; + m_pResourcesTool = NULL; + + delete m_pManifestTool; + m_pManifestTool = NULL; + + delete m_pLinkerTool; + m_pLinkerTool = NULL; + + delete m_pXboxImageTool; + m_pXboxImageTool = NULL; + + delete m_pXboxDeploymentTool; + m_pXboxDeploymentTool = NULL; + } + else + { + // exe/dlls do not get the librarian + delete m_pLibrarianTool; + m_pLibrarianTool = NULL; + } + } + + return bHandled; +} + +bool CProjectTool::SetProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool ) +{ + return m_PropertyStates.SetProperty( pToolProperty, pRootTool ); +} + +//----------------------------------------------------------------------------- + +bool CCompilerTool::SetProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool ) +{ + if ( m_bIsFileConfig ) + { + CProjectConfiguration *pConfig; + if ( !GetGenerator()->GetRootConfiguration( m_ConfigName.Get(), &pConfig ) ) + return false; + + return CProjectTool::SetProperty( pToolProperty, pConfig->GetCompilerTool() ); + } + return CProjectTool::SetProperty( pToolProperty ); +} + + +//----------------------------------------------------------------------------- + +bool CCustomBuildTool::SetProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool ) +{ + if ( m_bIsFileConfig ) + { + CProjectConfiguration *pConfig; + if ( !GetGenerator()->GetRootConfiguration( m_ConfigName.Get(), &pConfig ) ) + return false; + + return CProjectTool::SetProperty( pToolProperty, pConfig->GetCustomBuildTool() ); + } + return CProjectTool::SetProperty( pToolProperty ); +} + +// These are the only properties we care about for makefiles. +static const char *g_pRelevantSchemaProperties[] = +{ + g_pOption_AdditionalIncludeDirectories, + g_pOption_PreprocessorDefinitions, + g_pOption_AdditionalProjectDependencies, +}; + + +CRelevantPropertyNames g_RelevantSchemaPropertyNames = +{ + g_pRelevantSchemaProperties, + V_ARRAYSIZE( g_pRelevantSchemaProperties ) +}; + + +CVCProjGenerator::CVCProjGenerator() : + BaseClass( &g_RelevantSchemaPropertyNames ) +{ + m_pGeneratorDefinition = NULL; + m_pRootFolder = NULL; + m_FileDictionary.SetLessFunc( FilesSortLessFunc ); + + Clear(); +} + +void CVCProjGenerator::Clear() +{ + m_nActivePropertySection = KEYWORD_UNKNOWN; + + m_pProjectFile = NULL; + m_pConfig = NULL; + m_pFileConfig = NULL; + + m_pDebuggingTool = NULL; + m_pCompilerTool = NULL; + m_pLibrarianTool = NULL; + m_pLinkerTool = NULL; + m_pManifestTool = NULL; + m_pXMLDocGenTool = NULL; + m_pBrowseInfoTool = NULL; + m_pResourcesTool = NULL; + m_pPreBuildEventTool = NULL; + m_pPreLinkEventTool = NULL; + m_pPostBuildEventTool = NULL; + m_pCustomBuildTool = NULL; + m_pXboxImageTool = NULL; + m_pXboxDeploymentTool = NULL; + + m_spFolderStack.Purge(); + m_spCompilerStack.Purge(); + m_spCustomBuildToolStack.Purge(); + + // undefined until set + m_VSIType = PS3_VSI_TYPE_UNDEFINED; + + m_FileDictionary.Purge(); + + // setup expected root folder + delete m_pRootFolder; + m_pRootFolder = new CProjectFolder( this, "???" ); + + // setup the root configurations + m_RootConfigurations.PurgeAndDeleteElements(); + + CProjectConfiguration *pDebugConfig = new CProjectConfiguration( this, "Debug", NULL ); + m_RootConfigurations.AddToTail( pDebugConfig ); + + CProjectConfiguration *pReleaseConfig = new CProjectConfiguration( this, "Release", NULL ); + m_RootConfigurations.AddToTail( pReleaseConfig ); +} + +void CVCProjGenerator::SetupGeneratorDefinition( IVCProjWriter *pVCProjWriter, const char *pDefinitionName, PropertyName_t *pPropertyNames ) +{ + m_pVCProjWriter = pVCProjWriter; + + delete m_pGeneratorDefinition; + m_pGeneratorDefinition = new CGeneratorDefinition(); + m_pGeneratorDefinition->LoadDefinition( pDefinitionName, pPropertyNames ); +} + +const char* CVCProjGenerator::GetProjectFileExtension() +{ + if ( g_pVPC->Is2010() ) + { + return "vcxproj"; + } + return "vcproj"; +} + +void CVCProjGenerator::StartProject() +{ + if ( !m_pGeneratorDefinition ) + { + g_pVPC->VPCError( "Missing a properly configured generator definition" ); + } + + BaseClass::StartProject(); + + // create the default project + // must have a root project for most operations + m_ProjectName = "UNNAMED"; + m_OutputFilename = g_pVPC->GetOutputFilename(); + + SetGUID( m_OutputFilename.Get() ); +} + +void CVCProjGenerator::EndProject() +{ + BaseClass::EndProject(); + + // push generator definition scripts into CRC check + CRC32_t scriptCRC = 0; + const char *pScriptName = m_pGeneratorDefinition->GetScriptName( &scriptCRC ); + char scriptPath[MAX_PATH]; + g_pVPC->ResolveMacrosInString( CFmtStr( "$SRCDIR\\%s", pScriptName ), scriptPath, sizeof( scriptPath ) ); + g_pVPC->AddScriptToCRCCheck( scriptPath, scriptCRC ); + + // done once, right before save + ApplyInternalPreprocessorDefinitions(); + + VPC_FakeKeyword_SchemaFolder( this ); + +#ifdef STEAM +#error( "NEEDS TO BE FIXED" ) + // add the perforce integration magic + bstr = "Perforce Project"; + g_spProject->put_SccProjectName( bstr ); + bstr = ".."; + g_spProject->put_SccLocalPath( bstr ); + bstr = "MSSCCI:Perforce SCM"; + g_spProject->put_SccProvider( bstr ); +#endif + + g_pVPC->VPCStatus( true, "Saving... Project: '%s' File: '%s'", GetProjectName().String(), g_pVPC->GetOutputFilename() ); + + if ( m_ProjectName.IsEmpty() ) + { + g_pVPC->VPCError( "Invalid Empty Project Name" ); + } + + if ( m_OutputFilename.IsEmpty() ) + { + g_pVPC->VPCError( "Invalid Empty Output Filename" ); + } + + if ( m_GUIDString.IsEmpty() ) + { + g_pVPC->VPCError( "Invalid Empty GUID String" ); + } + + // Save the .vcproj file. + bool bValid = m_pVCProjWriter->Save( m_OutputFilename.Get() ); + if ( !bValid ) + { + g_pVPC->VPCError( "Cannot save the specified project '%s' to '%s'", GetProjectName().Get(), m_OutputFilename.Get() ); + } + + // Expected to not be inside a property section. + Assert( m_nActivePropertySection == KEYWORD_UNKNOWN ); + + Clear(); +} + +void CVCProjGenerator::SetGUID( const char *pOutputFilename ) +{ + char szBasename[MAX_PATH]; + V_FileBase( pOutputFilename, szBasename, sizeof( szBasename ) ); + + // set the GUID + MD5Context_t ctx; + unsigned char digest[MD5_DIGEST_LENGTH]; + V_memset( &ctx, 0, sizeof( ctx ) ); + V_memset( digest, 0, sizeof( digest ) ); + MD5Init( &ctx ); + MD5Update( &ctx, (unsigned char *)szBasename, strlen( szBasename ) ); + MD5Final( digest, &ctx ); + + char szMD5[64]; + V_binarytohex( digest, MD5_DIGEST_LENGTH, szMD5, sizeof( szMD5 ) ); + V_strupr( szMD5 ); + + char szGUID[MAX_PATH]; + V_snprintf( szGUID, sizeof( szGUID ), "{%8.8s-%4.4s-%4.4s-%4.4s-%12.12s}", szMD5, &szMD5[8], &szMD5[12], &szMD5[16], &szMD5[20] ); + m_GUIDString = szGUID; +} + +CUtlString CVCProjGenerator::GetProjectName() +{ + return m_ProjectName; +} + +void CVCProjGenerator::SetProjectName( const char *pProjectName ) +{ + m_ProjectName = pProjectName; +} + +void CVCProjGenerator::StartFolder( const char *pFolderName ) +{ + BaseClass::StartFolder( pFolderName ); + + bool bValid; + CProjectFolder *pFolder = NULL; + + if ( m_spFolderStack.Count() == 0 ) + { + // add to root + bValid = AddFolder( pFolderName, NULL, &pFolder ); + } + else + { + // add as subfolder + bValid = AddFolder( pFolderName, m_spFolderStack.Top(), &pFolder ); + } + + if ( !bValid ) + { + // resolve failure + // folder already exists, not an error + // find the matching object + pFolder = NULL; + if ( m_spFolderStack.Count() == 0 ) + { + // at root + GetFolder( pFolderName, NULL, &pFolder ); + } + else + { + // at subfolder + GetFolder( pFolderName, m_spFolderStack.Top(), &pFolder ); + } + if ( !pFolder ) + { + g_pVPC->VPCError( "Cannot find expected folder %s", pFolderName ); + } + } + + m_spFolderStack.Push( pFolder ); +} + +void CVCProjGenerator::EndFolder() +{ + BaseClass::EndFolder(); + + if ( m_spFolderStack.Count() == 0 ) + { + g_pVPC->VPCError( "EndFolder called and no folder has been started." ); + } + + m_spFolderStack.Pop(); +} + +bool CVCProjGenerator::StartFile( const char *pFilename, bool bWarnIfAlreadyExists ) +{ + // normalize filename, filenames need to compare correctly + char cleanFilename[MAX_PATH]; + V_strncpy( cleanFilename, pFilename, sizeof( cleanFilename ) ); + V_RemoveDotSlashes( cleanFilename, CORRECT_PATH_SEPARATOR ); + + // some vpc scripts decided to unecessarily double quote their filenames + // remove any incoming surrounding quotes, this only causes string handling problems (i.e. extension comparison, etc) + // all files get serialized to xml output with mandatory surrounding quotes + if ( cleanFilename[0] == '\"' ) + { + int len = strlen( cleanFilename ); + if ( len > 1 && cleanFilename[len-1] == '\"' ) + { + memcpy( cleanFilename, cleanFilename+1, len - 2 ); + cleanFilename[len-2] = '\0'; + } + } + + pFilename = cleanFilename; + + BaseClass::StartFile( pFilename, bWarnIfAlreadyExists ); + + CProjectFile *pFile = NULL; + + if ( m_spFolderStack.Count() == 0 ) + { + // add at root + AddFileToFolder( pFilename, NULL, bWarnIfAlreadyExists, &pFile ); + } + else + { + // add at subfolder + AddFileToFolder( pFilename, m_spFolderStack.Top(), bWarnIfAlreadyExists, &pFile ); + } + + m_pProjectFile = pFile; + return ( pFile != NULL ); +} + +void CVCProjGenerator::EndFile() +{ + BaseClass::EndFile(); +} + +bool CVCProjGenerator::RemoveFile( const char *pFilename ) +{ + // normalize filename, filenames need to compare correctly + char cleanFilename[MAX_PATH]; + V_strncpy( cleanFilename, pFilename, sizeof( cleanFilename ) ); + V_RemoveDotSlashes( cleanFilename, CORRECT_PATH_SEPARATOR ); + pFilename = cleanFilename; + + BaseClass::RemoveFile( pFilename ); + + bool bValid; + if ( m_spFolderStack.Count() == 0 ) + { + // remove from root + bValid = RemoveFileFromFolder( pFilename, NULL ); + } + else + { + // remove at subfolder + bValid = RemoveFileFromFolder( pFilename, m_spFolderStack.Top() ); + } + + return bValid; +} + +bool CVCProjGenerator::Config_GetConfigurations( const char *pszConfigName ) +{ + CProjectConfiguration *pConfig = NULL; + bool bValid = GetRootConfiguration( pszConfigName, &pConfig ); + if ( !bValid ) + { + g_pVPC->VPCError( "Could not get configuration '%s'", pszConfigName ); + } + m_pConfig = pConfig; + + return true; +} + +void CVCProjGenerator::StartConfigurationBlock( const char *pConfigName, bool bFileSpecific ) +{ + BaseClass::StartConfigurationBlock( pConfigName, bFileSpecific ); + + if ( bFileSpecific ) + { + CProjectConfiguration *pFileConfig = NULL; + bool bValid = m_pProjectFile->GetConfiguration( pConfigName, &pFileConfig ); + if ( !bValid ) + { + // not found, must be valid config + // must match predefined configurations, prevents misspellings + if ( !IsConfigurationNameValid( pConfigName ) ) + { + g_pVPC->VPCError( "File %s, Unknown configuration '%s'", m_pProjectFile->m_Name.Get(), pConfigName ); + } + + bValid = m_pProjectFile->AddConfiguration( pConfigName, &pFileConfig ); + if ( !bValid ) + { + g_pVPC->VPCError( "File %s, Could not get file configuration '%s'", m_pProjectFile->m_Name.Get(), pConfigName ); + } + } + m_pFileConfig = pFileConfig; + } + else + { + Config_GetConfigurations( pConfigName ); + } +} + +void CVCProjGenerator::EndConfigurationBlock() +{ + BaseClass::EndConfigurationBlock(); + + if ( m_pFileConfig && m_pFileConfig->IsEmpty() ) + { + // any file configuration (after parsing) that has no property state gets purged + m_pProjectFile->RemoveConfiguration( m_pFileConfig ); + } + + m_pFileConfig = NULL; +} + +void CVCProjGenerator::FileExcludedFromBuild( bool bExcluded ) +{ + if ( !m_pFileConfig ) + { + g_pVPC->VPCSyntaxError( "Cannot set $ExcludedFromBuild unless in a $File configuration context" ); + } + + BaseClass::FileExcludedFromBuild( bExcluded ); + + ToolProperty_t* pToolProperty = m_pGeneratorDefinition->GetProperty( KEYWORD_GENERAL, "$ExcludedFromBuild" ); + if ( !pToolProperty ) + { + g_pVPC->VPCError( "Missing proper declaration for $ExcludedFromBuild" ); + } + + m_pFileConfig->m_PropertyStates.SetBoolProperty( pToolProperty, bExcluded ); +} + +bool CVCProjGenerator::StartPropertySection( configKeyword_e eKeyword, bool *pbShouldSkip ) +{ + BaseClass::StartPropertySection( eKeyword ); + + *pbShouldSkip = false; + m_nActivePropertySection = KEYWORD_UNKNOWN; + bool bHandled = false; + + switch ( eKeyword ) + { + case KEYWORD_GENERAL: + bHandled = true; + break; + + case KEYWORD_DEBUGGING: + m_pDebuggingTool = m_pConfig->GetDebuggingTool(); + if ( !m_pDebuggingTool ) + { + g_pVPC->VPCError( "Could not get %s tool interface from configuration", g_pVPC->KeywordToName( eKeyword ) ); + } + bHandled = true; + break; + + case KEYWORD_COMPILER: + case KEYWORD_PS3_SNCCOMPILER: + case KEYWORD_PS3_GCCCOMPILER: + eKeyword = SetPS3VisualStudioIntegrationType( eKeyword ); + if ( eKeyword == KEYWORD_UNKNOWN ) + { + // skip this section + break; + } + + m_spCompilerStack.Push( m_pCompilerTool ); + if ( m_pFileConfig ) + { + m_pCompilerTool = m_pFileConfig->GetCompilerTool(); + } + else + { + m_pCompilerTool = m_pConfig->GetCompilerTool(); + } + if ( !m_pCompilerTool ) + { + g_pVPC->VPCError( "Could not get %s tool interface from configuration", g_pVPC->KeywordToName( eKeyword ) ); + } + bHandled = true; + break; + + case KEYWORD_LIBRARIAN: + m_pLibrarianTool = m_pConfig->GetLibrarianTool(); + if ( !m_pLibrarianTool ) + { + g_pVPC->VPCError( "Could not get %s tool interface from configuration", g_pVPC->KeywordToName( eKeyword ) ); + } + bHandled = true; + break; + + case KEYWORD_LINKER: + case KEYWORD_PS3_SNCLINKER: + case KEYWORD_PS3_GCCLINKER: + eKeyword = SetPS3VisualStudioIntegrationType( eKeyword ); + if ( eKeyword == KEYWORD_UNKNOWN ) + { + // skip this section + break; + } + + m_pLinkerTool = m_pConfig->GetLinkerTool(); + if ( !m_pLinkerTool ) + { + g_pVPC->VPCError( "Could not get %s tool interface from configuration", g_pVPC->KeywordToName( eKeyword ) ); + } + bHandled = true; + break; + + case KEYWORD_MANIFEST: + if ( !( g_pVPC->IsPlatformDefined( "WIN32" ) || g_pVPC->IsPlatformDefined( "WIN64" ) ) ) + { + // windows specific + break; + } + + m_pManifestTool = m_pConfig->GetManifestTool(); + if ( !m_pManifestTool ) + { + g_pVPC->VPCError( "Could not get %s tool interface from configuration", g_pVPC->KeywordToName( eKeyword ) ); + } + bHandled = true; + break; + + case KEYWORD_XMLDOCGEN: + if ( !( g_pVPC->IsPlatformDefined( "WIN32" ) || g_pVPC->IsPlatformDefined( "WIN64" ) ) ) + { + // windows specific + break; + } + + m_pXMLDocGenTool = m_pConfig->GetXMLDocGenTool(); + if ( !m_pXMLDocGenTool ) + { + g_pVPC->VPCError( "Could not get %s tool interface from configuration", g_pVPC->KeywordToName( eKeyword ) ); + } + bHandled = true; + break; + + case KEYWORD_BROWSEINFO: + if ( g_pVPC->IsPlatformDefined( "PS3" ) ) + { + // not for ps3 + break; + } + + m_pBrowseInfoTool = m_pConfig->GetBrowseInfoTool(); + if ( !m_pBrowseInfoTool ) + { + g_pVPC->VPCError( "Could not get %s tool interface from configuration", g_pVPC->KeywordToName( eKeyword ) ); + } + bHandled = true; + break; + + case KEYWORD_RESOURCES: + if ( !( g_pVPC->IsPlatformDefined( "WIN32" ) || g_pVPC->IsPlatformDefined( "WIN64" ) ) ) + { + // windows specific + break; + } + + m_pResourcesTool = m_pConfig->GetResourcesTool(); + if ( !m_pResourcesTool ) + { + g_pVPC->VPCError( "Could not get %s tool interface from configuration", g_pVPC->KeywordToName( eKeyword ) ); + } + bHandled = true; + break; + + case KEYWORD_PREBUILDEVENT: + m_pPreBuildEventTool = m_pConfig->GetPreBuildEventTool(); + if ( !m_pPreBuildEventTool ) + { + g_pVPC->VPCError( "Could not get %s tool interface from configuration", g_pVPC->KeywordToName( eKeyword ) ); + } + bHandled = true; + break; + + case KEYWORD_PRELINKEVENT: + m_pPreLinkEventTool = m_pConfig->GetPreLinkEventTool(); + if ( !m_pPreLinkEventTool ) + { + g_pVPC->VPCError( "Could not get %s tool interface from configuration", g_pVPC->KeywordToName( eKeyword ) ); + } + bHandled = true; + break; + + case KEYWORD_POSTBUILDEVENT: + m_pPostBuildEventTool = m_pConfig->GetPostBuildEventTool(); + if ( !m_pPostBuildEventTool ) + { + g_pVPC->VPCError( "Could not get %s tool interface from configuration", g_pVPC->KeywordToName( eKeyword ) ); + } + bHandled = true; + break; + + case KEYWORD_CUSTOMBUILDSTEP: + m_spCustomBuildToolStack.Push( m_pCustomBuildTool ); + if ( m_pFileConfig ) + { + m_pCustomBuildTool = m_pFileConfig->GetCustomBuildTool(); + } + else + { + m_pCustomBuildTool = m_pConfig->GetCustomBuildTool(); + } + if ( !m_pCustomBuildTool ) + { + g_pVPC->VPCError( "Could not get %s tool interface from configuration", g_pVPC->KeywordToName( eKeyword ) ); + } + bHandled = true; + break; + + case KEYWORD_XBOXIMAGE: + if ( !g_pVPC->IsPlatformDefined( "X360" ) ) + { + // xbox generator specific + break; + } + + m_pXboxImageTool = m_pConfig->GetXboxImageTool(); + if ( !m_pXboxImageTool ) + { + g_pVPC->VPCError( "Could not get %s tool interface from configuration", g_pVPC->KeywordToName( eKeyword ) ); + } + bHandled = true; + break; + + case KEYWORD_XBOXDEPLOYMENT: + if ( !g_pVPC->IsPlatformDefined( "X360" ) ) + { + // xbox generator specific + break; + } + + m_pXboxDeploymentTool = m_pConfig->GetXboxDeploymentTool(); + if ( !m_pXboxDeploymentTool ) + { + g_pVPC->VPCError( "Could not get %s tool interface from configuration", g_pVPC->KeywordToName( eKeyword ) ); + } + bHandled = true; + break; + + default: + // unknown + return false; + } + + if ( bHandled ) + { + // handled + m_nActivePropertySection = eKeyword; + } + else + { + // allow other platform specifc sections to just be quietly ignored + *pbShouldSkip = true; + } + + return true; +} + +void CVCProjGenerator::EndPropertySection( configKeyword_e eKeyword ) +{ + BaseClass::EndPropertySection( eKeyword ); + + switch( eKeyword ) + { + case KEYWORD_CUSTOMBUILDSTEP: + m_spCustomBuildToolStack.Pop( m_pCustomBuildTool ); + break; + + case KEYWORD_COMPILER: + case KEYWORD_PS3_SNCCOMPILER: + case KEYWORD_PS3_GCCCOMPILER: + eKeyword = SetPS3VisualStudioIntegrationType( eKeyword ); + m_spCompilerStack.Pop( m_pCompilerTool ); + break; + } + + m_nActivePropertySection = KEYWORD_UNKNOWN; +} + +void CVCProjGenerator::HandleProperty( const char *pPropertyName, const char *pCustomScriptData ) +{ + // don't allow the baseclass to alter the script state + g_pVPC->GetScript().PushCurrentScript(); + BaseClass::HandleProperty( pPropertyName, pCustomScriptData ); + g_pVPC->GetScript().PopScript(); + + if ( pCustomScriptData ) + { + g_pVPC->GetScript().PushScript( "HandleProperty custom data", pCustomScriptData ); + } + + ToolProperty_t *pToolProperty = m_pGeneratorDefinition->GetProperty( m_nActivePropertySection, pPropertyName ); + if ( !pToolProperty ) + { + // unknown property + g_pVPC->VPCSyntaxError( "Unknown property %s", pPropertyName ); + } + + const char *pToken = g_pVPC->GetScript().PeekNextToken( false ); + if ( !pToken || !pToken[0] ) + { + // quietly ignoring any property without a value + // not an error + if ( pCustomScriptData ) + { + g_pVPC->GetScript().PopScript(); + } + return; + } + + CProjectConfiguration *pConfig = NULL; + CProjectTool *pTool = NULL; + switch ( m_nActivePropertySection ) + { + case KEYWORD_GENERAL: + pConfig = m_pConfig; + break; + + case KEYWORD_DEBUGGING: + pTool = m_pDebuggingTool; + break; + + case KEYWORD_COMPILER: + case KEYWORD_PS3_SNCCOMPILER: + case KEYWORD_PS3_GCCCOMPILER: + pTool = m_pCompilerTool; + break; + + case KEYWORD_LIBRARIAN: + pTool = m_pLibrarianTool; + break; + + case KEYWORD_LINKER: + case KEYWORD_PS3_SNCLINKER: + case KEYWORD_PS3_GCCLINKER: + pTool = m_pLinkerTool; + break; + + case KEYWORD_MANIFEST: + pTool = m_pManifestTool; + break; + + case KEYWORD_XMLDOCGEN: + pTool = m_pXMLDocGenTool; + break; + + case KEYWORD_BROWSEINFO: + pTool = m_pBrowseInfoTool; + break; + + case KEYWORD_RESOURCES: + pTool = m_pResourcesTool; + break; + + case KEYWORD_PREBUILDEVENT: + pTool = m_pPreBuildEventTool; + break; + + case KEYWORD_PRELINKEVENT: + pTool = m_pPreLinkEventTool; + break; + + case KEYWORD_POSTBUILDEVENT: + pTool = m_pPostBuildEventTool; + break; + + case KEYWORD_CUSTOMBUILDSTEP: + pTool = m_pCustomBuildTool; + break; + + case KEYWORD_XBOXIMAGE: + pTool = m_pXboxImageTool; + break; + + case KEYWORD_XBOXDEPLOYMENT: + pTool = m_pXboxDeploymentTool; + break; + + default: + g_pVPC->VPCError( "HandleProperty: No support for Tool:%s Property:%s - requires implementation", g_pVPC->KeywordToName( m_nActivePropertySection ), pPropertyName ); + } + + bool bHandled = false; + if ( pTool ) + { + bHandled = pTool->SetProperty( pToolProperty ); + } + else if ( pConfig ) + { + bHandled = pConfig->SetProperty( pToolProperty ); + } + + if ( !bHandled ) + { + g_pVPC->VPCError( "HandleProperty: Failed to set %s", pPropertyName ); + } + + if ( pCustomScriptData ) + { + g_pVPC->GetScript().PopScript(); + } +} + +bool CVCProjGenerator::GetFolder( const char *pFolderName, CProjectFolder *pParentFolder, CProjectFolder **ppOutFolder ) +{ + bool bValid; + if ( !pParentFolder ) + { + bValid = m_pRootFolder->GetFolder( pFolderName, ppOutFolder ); + } + else + { + bValid = pParentFolder->GetFolder( pFolderName, ppOutFolder ); + } + return bValid; +} + +bool CVCProjGenerator::AddFolder( const char *pFolderName, CProjectFolder *pParentFolder, CProjectFolder **ppOutFolder ) +{ + bool bValid; + if ( !pParentFolder ) + { + bValid = m_pRootFolder->AddFolder( pFolderName, ppOutFolder ); + } + else + { + bValid = pParentFolder->AddFolder( pFolderName, ppOutFolder ); + } + return bValid; +} + +bool CVCProjGenerator::FindFile( const char *pFilename, CProjectFile **ppFile ) +{ + CProjectFile findProjectFile( this, pFilename ); + + int iIndex = m_FileDictionary.Find( &findProjectFile ); + if ( iIndex != m_FileDictionary.InvalidIndex() ) + { + // found + if ( ppFile ) + { + *ppFile = m_FileDictionary[iIndex]; + } + return true; + } + + // not found + if ( ppFile ) + { + *ppFile = NULL; + } + + return false; +} + +void CVCProjGenerator::AddFileToFolder( const char *pFilename, CProjectFolder *pFolder, bool bWarnIfAlreadyExists, CProjectFile **ppFile ) +{ + if ( FindFile( pFilename, ppFile ) ) + { + // already present + if ( bWarnIfAlreadyExists ) + { + g_pVPC->VPCWarning( "File %s already exists in project", pFilename ); + } + return; + } + + CProjectFile *pFile; + if ( !pFolder ) + { + // add at root + m_pRootFolder->AddFile( pFilename, &pFile ); + } + else + { + // add at folder + pFolder->AddFile( pFilename, &pFile ); + } + + // add to dictionary + m_FileDictionary.Insert( pFile ); + if ( ppFile ) + { + *ppFile = pFile; + } +} + +bool CVCProjGenerator::RemoveFileFromFolder( const char *pFilename, CProjectFolder *pFolder ) +{ + bool bFound = false; + CProjectFile findProjectFile( this, pFilename ); + + int iIndex = m_FileDictionary.Find( &findProjectFile ); + if ( iIndex != m_FileDictionary.InvalidIndex() ) + { + bFound = true; + m_FileDictionary.RemoveAt( iIndex ); + } + + if ( !bFound ) + return false; + + if ( !pFolder ) + { + m_pRootFolder->RemoveFile( pFilename ); + } + else + { + pFolder->RemoveFile( pFilename ); + } + + return bFound; +} + +void CVCProjGenerator::GetAllConfigurationNames( CUtlVector< CUtlString > &configurationNames ) +{ + configurationNames.Purge(); + for ( int i = 0; i < m_RootConfigurations.Count(); i++ ) + { + configurationNames.AddToTail( m_RootConfigurations[i]->m_Name.Get() ); + } +} + +bool CVCProjGenerator::GetRootConfiguration( const char *pConfigName, CProjectConfiguration **ppConfig ) +{ + if ( !pConfigName || !pConfigName[0] ) + { + g_pVPC->VPCError( "Empty or bad configuration name." ); + } + + if ( ppConfig ) + { + // assume not found + *ppConfig = NULL; + } + + for ( int i = 0; i < m_RootConfigurations.Count(); i++ ) + { + if ( !V_stricmp( m_RootConfigurations[i]->m_Name.Get(), pConfigName ) ) + { + // found + if ( ppConfig ) + { + *ppConfig = m_RootConfigurations[i]; + } + return true; + } + } + + return false; +} + +bool CVCProjGenerator::IsConfigurationNameValid( const char *pConfigName ) +{ + return GetRootConfiguration( pConfigName, NULL ); +} + +configKeyword_e CVCProjGenerator::SetPS3VisualStudioIntegrationType( configKeyword_e eKeyword ) +{ + PS3VSIType_e vsiType = PS3_VSI_TYPE_UNDEFINED; + + switch ( eKeyword ) + { + case KEYWORD_COMPILER: + case KEYWORD_LINKER: + if ( !g_pVPC->IsPlatformDefined( "PS3" ) ) + { + return eKeyword; + } + + if ( m_VSIType == PS3_VSI_TYPE_UNDEFINED ) + { + // PS3 defaults to SNC, unless explictly specified + vsiType = PS3_VSI_TYPE_SNC; + } + else + { + // already set + vsiType = m_VSIType; + } + break; + + case KEYWORD_PS3_SNCCOMPILER: + case KEYWORD_PS3_SNCLINKER: + if ( !g_pVPC->IsPlatformDefined( "PS3" ) ) + { + // ps3 generator specific + // not available for other platforms + return KEYWORD_UNKNOWN; + } + vsiType = PS3_VSI_TYPE_SNC; + break; + + case KEYWORD_PS3_GCCCOMPILER: + case KEYWORD_PS3_GCCLINKER: + if ( !g_pVPC->IsPlatformDefined( "PS3" ) ) + { + // ps3 generator specific + // not available for other platforms + return KEYWORD_UNKNOWN; + } + vsiType = PS3_VSI_TYPE_GCC; + break; + + default: + g_pVPC->VPCError( "Unknown PS3 compiler/linker type" ); + break; + } + + if ( m_VSIType == PS3_VSI_TYPE_UNDEFINED ) + { + // once set, compiler/linker choice (snc or gcc) cannot be changed + m_VSIType = vsiType; + } + else if ( m_VSIType != vsiType ) + { + // cannot intermix tool properties, they must be exclusive + g_pVPC->VPCSyntaxError( "PS3 compiler/linker (GCC or SNC) already set, cannot be changed" ); + } + + // remap ambiguous compiler/linker tool to explicit SNC/GCC tool flavor + if ( eKeyword == KEYWORD_COMPILER ) + { + eKeyword = ( m_VSIType == PS3_VSI_TYPE_SNC ) ? KEYWORD_PS3_SNCCOMPILER : KEYWORD_PS3_GCCCOMPILER; + } + else if ( eKeyword == KEYWORD_LINKER ) + { + eKeyword = ( m_VSIType == PS3_VSI_TYPE_SNC ) ? KEYWORD_PS3_SNCLINKER : KEYWORD_PS3_GCCLINKER; + } + + return eKeyword; +} + +void CVCProjGenerator::ApplyInternalPreprocessorDefinitions() +{ + // prep to add in vpc generated compiler defines + CUtlVector< macro_t* > macroDefines; + g_pVPC->GetMacrosMarkedForCompilerDefines( macroDefines ); + + if ( !macroDefines.Count() ) + { + // nothing to fixup + return; + } + + // get all the vpc macros that have been marked for auto adding as compiler define + CUtlString extraDefineString; + for ( int i = 0; i < macroDefines.Count(); i++ ) + { + macro_t *pMacro = macroDefines[i]; + + CUtlString tempString; + tempString.Format( ";%s=%s", pMacro->name.String(), pMacro->value.String() ); + extraDefineString += tempString; + } + + // fixup root configurations + for ( int i = 0; i < m_RootConfigurations.Count(); i++ ) + { + CCompilerTool *pCompilerTool = m_RootConfigurations[i]->GetCompilerTool(); + if ( pCompilerTool ) + { + PropertyState_t *pPropertyState = pCompilerTool->m_PropertyStates.GetProperty( "$PreprocessorDefinitions" ); + if ( pPropertyState ) + { + pPropertyState->m_StringValue += extraDefineString; + } + } + } + + // fixup any file confiuration overrides + for ( int iIndex = m_FileDictionary.FirstInorder(); iIndex != m_FileDictionary.InvalidIndex(); iIndex = m_FileDictionary.NextInorder( iIndex ) ) + { + CProjectFile *pProjectFile = m_FileDictionary[iIndex]; + for ( int i = 0; i < pProjectFile->m_Configs.Count(); i++ ) + { + CCompilerTool *pCompilerTool = pProjectFile->m_Configs[i]->GetCompilerTool(); + if ( pCompilerTool ) + { + PropertyState_t *pPropertyState = pCompilerTool->m_PropertyStates.GetProperty( "$PreprocessorDefinitions" ); + if ( pPropertyState ) + { + pPropertyState->m_StringValue += extraDefineString; + } + } + } + } +} diff --git a/external/vpc/utils/vpc/projectgenerator_vcproj.h b/external/vpc/utils/vpc/projectgenerator_vcproj.h new file mode 100644 index 0000000..3ccf208 --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_vcproj.h @@ -0,0 +1,379 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef VCPROJGENERATOR_H +#define VCPROJGENERATOR_H +#ifdef _WIN32 +#pragma once +#endif + +class CProjectConfiguration; +class CVCProjGenerator; +class CProjectTool; + +struct PropertyState_t +{ + ToolProperty_t *m_pToolProperty; + CUtlString m_OrdinalString; + CUtlString m_StringValue; +}; + +// ps3 visual studio integration +enum PS3VSIType_e +{ + PS3_VSI_TYPE_UNDEFINED = -1, + PS3_VSI_TYPE_SNC = 0, + PS3_VSI_TYPE_GCC = 1, +}; + +class CProjectFile +{ +public: + CProjectFile( CVCProjGenerator *pGenerator, const char *pFilename ); + ~CProjectFile(); + + bool GetConfiguration( const char *pConfigName, CProjectConfiguration **ppConfig ); + bool AddConfiguration( const char *pConfigName, CProjectConfiguration **ppConfig ); + bool RemoveConfiguration( CProjectConfiguration *pConfig ); + + CUtlString m_Name; + CVCProjGenerator *m_pGenerator; + CUtlVector< CProjectConfiguration* > m_Configs; +}; + +class CProjectFolder +{ +public: + CProjectFolder( CVCProjGenerator *pGenerator, const char *pFolderName ); + ~CProjectFolder(); + + bool GetFolder( const char *pFolderName, CProjectFolder **pFolder ); + bool AddFolder( const char *pFolderName, CProjectFolder **pFolder ); + void AddFile( const char *pFilename, CProjectFile **ppFile ); + bool FindFile( const char *pFilename ); + bool RemoveFile( const char *pFilename ); + + CUtlString m_Name; + CVCProjGenerator *m_pGenerator; + CUtlLinkedList< CProjectFolder* > m_Folders; + CUtlLinkedList< CProjectFile* > m_Files; +}; + +class CPropertyStateLessFunc +{ +public: + bool Less( const int& lhs, const int& rhs, void *pContext ); +}; + +class CPropertyStates +{ +public: + CPropertyStates(); + + bool SetProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool = NULL ); + bool SetBoolProperty( ToolProperty_t *pToolProperty, bool bEnabled ); + + PropertyState_t *GetProperty( int nPropertyId ); + PropertyState_t *GetProperty( const char *pPropertyName ); + + CUtlVector< PropertyState_t > m_Properties; + CUtlSortVector< int, CPropertyStateLessFunc > m_PropertiesInOutputOrder; + +private: + bool SetStringProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool = NULL ); + bool SetListProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool = NULL ); + bool SetBoolProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool = NULL ); + bool SetBoolProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool, bool bEnabled ); + bool SetIntegerProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool = NULL ); +}; + +class CProjectTool +{ +public: + CProjectTool( CVCProjGenerator *pGenerator ) + { + m_pGenerator = pGenerator; + } + + CVCProjGenerator *GetGenerator() { return m_pGenerator; } + + // when the property belongs to the root tool (i.e. linker), no root tool is passed in + // when the property is for the file's specific configuration tool, (i.e. compiler/debug), the root tool must be supplied + virtual bool SetProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool = NULL ); + + CPropertyStates m_PropertyStates; + +private: + CVCProjGenerator *m_pGenerator; +}; + +class CDebuggingTool : public CProjectTool +{ +public: + CDebuggingTool( CVCProjGenerator *pGenerator ) : CProjectTool( pGenerator ) {} +}; + +class CCompilerTool : public CProjectTool +{ +public: + CCompilerTool( CVCProjGenerator *pGenerator, const char *pConfigName, bool bIsFileConfig ) : CProjectTool( pGenerator ) + { + m_ConfigName = pConfigName; + m_bIsFileConfig = bIsFileConfig; + } + + bool SetProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool = NULL ); + +private: + CUtlString m_ConfigName; + bool m_bIsFileConfig; +}; + +class CLibrarianTool : public CProjectTool +{ +public: + CLibrarianTool( CVCProjGenerator *pGenerator ) : CProjectTool( pGenerator ) {} +}; + +class CLinkerTool : public CProjectTool +{ +public: + CLinkerTool( CVCProjGenerator *pGenerator ) : CProjectTool( pGenerator ) {} +}; + +class CManifestTool : public CProjectTool +{ +public: + CManifestTool( CVCProjGenerator *pGenerator ) : CProjectTool( pGenerator ) {} +}; + +class CXMLDocGenTool : public CProjectTool +{ +public: + CXMLDocGenTool( CVCProjGenerator *pGenerator ) : CProjectTool( pGenerator ) {} +}; + +class CBrowseInfoTool : public CProjectTool +{ +public: + CBrowseInfoTool( CVCProjGenerator *pGenerator ) : CProjectTool( pGenerator ) {} +}; + +class CResourcesTool : public CProjectTool +{ +public: + CResourcesTool( CVCProjGenerator *pGenerator ) : CProjectTool( pGenerator ) {} +}; + +class CPreBuildEventTool : public CProjectTool +{ +public: + CPreBuildEventTool( CVCProjGenerator *pGenerator ) : CProjectTool( pGenerator ) {} +}; + +class CPreLinkEventTool : public CProjectTool +{ +public: + CPreLinkEventTool( CVCProjGenerator *pGenerator ) : CProjectTool( pGenerator ) {} +}; + +class CPostBuildEventTool : public CProjectTool +{ +public: + CPostBuildEventTool( CVCProjGenerator *pGenerator ) : CProjectTool( pGenerator ) {} +}; + +class CCustomBuildTool : public CProjectTool +{ +public: + CCustomBuildTool( CVCProjGenerator *pGenerator, const char *pConfigName, bool bIsFileConfig ) : CProjectTool( pGenerator ) + { + m_ConfigName = pConfigName; + m_bIsFileConfig = bIsFileConfig; + } + + bool SetProperty( ToolProperty_t *pToolProperty, CProjectTool *pRootTool = NULL ); + +private: + CUtlString m_ConfigName; + bool m_bIsFileConfig; +}; + +class CXboxImageTool : public CProjectTool +{ +public: + CXboxImageTool( CVCProjGenerator *pGenerator ) : CProjectTool( pGenerator ) {} +}; + +class CXboxDeploymentTool : public CProjectTool +{ +public: + CXboxDeploymentTool( CVCProjGenerator *pGenerator ) : CProjectTool( pGenerator ) {} +}; + +class CProjectConfiguration +{ +public: + CProjectConfiguration( CVCProjGenerator *pGenerator, const char *pConfigName, const char *pFilename ); + ~CProjectConfiguration(); + + CDebuggingTool *GetDebuggingTool() { return m_pDebuggingTool; } + CCompilerTool *GetCompilerTool() { return m_pCompilerTool; } + CLibrarianTool *GetLibrarianTool() { return m_pLibrarianTool; } + CLinkerTool *GetLinkerTool() { return m_pLinkerTool; } + CManifestTool *GetManifestTool() { return m_pManifestTool; } + CXMLDocGenTool *GetXMLDocGenTool() { return m_pXMLDocGenTool; } + CBrowseInfoTool *GetBrowseInfoTool() { return m_pBrowseInfoTool; } + CResourcesTool *GetResourcesTool() { return m_pResourcesTool; } + CPreBuildEventTool *GetPreBuildEventTool() { return m_pPreBuildEventTool; } + CPreLinkEventTool *GetPreLinkEventTool() { return m_pPreLinkEventTool; } + CPostBuildEventTool *GetPostBuildEventTool() { return m_pPostBuildEventTool; } + CCustomBuildTool *GetCustomBuildTool() { return m_pCustomBuildTool; } + CXboxImageTool *GetXboxImageTool() { return m_pXboxImageTool; } + CXboxDeploymentTool *GetXboxDeploymentTool() { return m_pXboxDeploymentTool; } + + bool IsEmpty(); + + bool SetProperty( ToolProperty_t *pToolProperty ); + + CVCProjGenerator *m_pGenerator; + + // type of config, and config's properties + bool m_bIsFileConfig; + CUtlString m_Name; + + CPropertyStates m_PropertyStates; + +private: + // the config's tools + CDebuggingTool *m_pDebuggingTool; + CCompilerTool *m_pCompilerTool; + CLibrarianTool *m_pLibrarianTool; + CLinkerTool *m_pLinkerTool; + CManifestTool *m_pManifestTool; + CXMLDocGenTool *m_pXMLDocGenTool; + CBrowseInfoTool *m_pBrowseInfoTool; + CResourcesTool *m_pResourcesTool; + CPreBuildEventTool *m_pPreBuildEventTool; + CPreLinkEventTool *m_pPreLinkEventTool; + CPostBuildEventTool *m_pPostBuildEventTool; + CCustomBuildTool *m_pCustomBuildTool; + CXboxImageTool *m_pXboxImageTool; + CXboxDeploymentTool *m_pXboxDeploymentTool; +}; + +class IVCProjWriter +{ +public: + virtual bool Save( const char *pOutputFilename ) = 0; +}; + +class CVCProjGenerator : public CBaseProjectDataCollector +{ +public: + typedef CBaseProjectDataCollector BaseClass; + CVCProjGenerator(); + + virtual const char *GetProjectFileExtension(); + virtual void StartProject(); + virtual void EndProject(); + virtual CUtlString GetProjectName(); + virtual void SetProjectName( const char *pProjectName ); + virtual void GetAllConfigurationNames( CUtlVector< CUtlString > &configurationNames ); + virtual void StartConfigurationBlock( const char *pConfigName, bool bFileSpecific ); + virtual void EndConfigurationBlock(); + virtual bool StartPropertySection( configKeyword_e keyword, bool *pbShouldSkip ); + virtual void HandleProperty( const char *pProperty, const char *pCustomScriptData ); + virtual void EndPropertySection( configKeyword_e keyword ); + virtual void StartFolder( const char *pFolderName ); + virtual void EndFolder(); + virtual bool StartFile( const char *pFilename, bool bWarnIfAlreadyExists ); + virtual void EndFile(); + virtual void FileExcludedFromBuild( bool bExcluded ); + virtual bool RemoveFile( const char *pFilename ); + + CGeneratorDefinition *GetGeneratorDefinition() { return m_pGeneratorDefinition; } + void SetupGeneratorDefinition( IVCProjWriter *pVCProjWriter, const char *pDefinitionName, PropertyName_t *pPropertyNames ); + + PS3VSIType_e GetVSIType() { return m_VSIType; } + + CUtlString GetGUIDString() { return m_GUIDString; } + + bool GetRootConfiguration( const char *pConfigName, CProjectConfiguration **pConfig ); + + CProjectFolder *GetRootFolder() { return m_pRootFolder; } + +private: + void Clear(); + bool Config_GetConfigurations( const char *pszConfigName ); + + // returns true if found, false otherwise + bool GetFolder( const char *pFolderName, CProjectFolder *pParentFolder, CProjectFolder **pOutFolder ); + // returns true if added, false otherwise (duplicate) + bool AddFolder( const char *pFolderName, CProjectFolder *pParentFolder, CProjectFolder **pOutFolder ); + + // returns true if found, false otherwise + bool FindFile( const char *pFilename, CProjectFile **pFile ); + void AddFileToFolder( const char *pFilename, CProjectFolder *pFolder, bool bWarnIfExists, CProjectFile **pFile ); + + // returns true if removed, false otherwise (not found) + bool RemoveFileFromFolder( const char *pFilename, CProjectFolder *pFolder ); + + bool IsConfigurationNameValid( const char *pConfigName ); + + void SetGUID( const char *pOutputFilename ); + + configKeyword_e SetPS3VisualStudioIntegrationType( configKeyword_e eKeyword ); + + void ApplyInternalPreprocessorDefinitions(); + +private: + configKeyword_e m_nActivePropertySection; + CGeneratorDefinition *m_pGeneratorDefinition; + + CDebuggingTool *m_pDebuggingTool; + CCompilerTool *m_pCompilerTool; + CLibrarianTool *m_pLibrarianTool; + CLinkerTool *m_pLinkerTool; + CManifestTool *m_pManifestTool; + CXMLDocGenTool *m_pXMLDocGenTool; + CBrowseInfoTool *m_pBrowseInfoTool; + CResourcesTool *m_pResourcesTool; + CPreBuildEventTool *m_pPreBuildEventTool; + CPreLinkEventTool *m_pPreLinkEventTool; + CPostBuildEventTool *m_pPostBuildEventTool; + CCustomBuildTool *m_pCustomBuildTool; + CXboxImageTool *m_pXboxImageTool; + CXboxDeploymentTool *m_pXboxDeploymentTool; + + CProjectConfiguration *m_pConfig; + CProjectConfiguration *m_pFileConfig; + CProjectFile *m_pProjectFile; + + CSimplePointerStack< CProjectFolder*, CProjectFolder*, 128 > m_spFolderStack; + CSimplePointerStack< CCompilerTool*, CCompilerTool*, 128 > m_spCompilerStack; + CSimplePointerStack< CCustomBuildTool*, CCustomBuildTool*, 128 > m_spCustomBuildToolStack; + + CUtlString m_ProjectName; + CUtlString m_OutputFilename; + + CProjectFolder *m_pRootFolder; + + CUtlVector< CProjectConfiguration* > m_RootConfigurations; + + // primary file dictionary + CUtlRBTree< CProjectFile*, int > m_FileDictionary; + + CUtlString m_GUIDString; + + IVCProjWriter *m_pVCProjWriter; + + // ps3 visual studio integration + PS3VSIType_e m_VSIType; +}; + +#endif // VCPROJGENERATOR_H + diff --git a/external/vpc/utils/vpc/projectgenerator_win32.cpp b/external/vpc/utils/vpc/projectgenerator_win32.cpp new file mode 100644 index 0000000..a4ba522 --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_win32.cpp @@ -0,0 +1,349 @@ +//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: VPC +// +//=====================================================================================// + +#include "vpc.h" + +#undef PROPERTYNAME +#define PROPERTYNAME( X, Y ) { X##_##Y, #X, #Y }, +static PropertyName_t s_Win32PropertyNames[] = +{ + #include "projectgenerator_win32.inc" + { -1, NULL, NULL } +}; + +IBaseProjectGenerator* GetWin32ProjectGenerator() +{ + static CProjectGenerator_Win32 *s_pProjectGenerator = NULL; + if ( !s_pProjectGenerator ) + { + s_pProjectGenerator = new CProjectGenerator_Win32(); + } + + return s_pProjectGenerator->GetProjectGenerator(); +} + +CProjectGenerator_Win32::CProjectGenerator_Win32() +{ + m_pVCProjGenerator = new CVCProjGenerator(); + m_pVCProjGenerator->SetupGeneratorDefinition( this, "win32_2005.def", s_Win32PropertyNames ); +} + +bool CProjectGenerator_Win32::WriteFile( CProjectFile *pFile ) +{ + m_XMLWriter.PushNode( "File" ); + m_XMLWriter.Write( CFmtStrMax( "RelativePath=\"%s\"", pFile->m_Name.Get() ) ); + m_XMLWriter.Write( ">" ); + + for ( int i = 0; i < pFile->m_Configs.Count(); i++ ) + { + if ( !WriteConfiguration( pFile->m_Configs[i] ) ) + return false; + } + + m_XMLWriter.PopNode( true ); + + return true; +} + +bool CProjectGenerator_Win32::WriteFolder( CProjectFolder *pFolder ) +{ + m_XMLWriter.PushNode( "Filter" ); + m_XMLWriter.Write( CFmtStrMax( "Name=\"%s\"", m_XMLWriter.FixupXMLString( pFolder->m_Name.Get() ) ) ); + m_XMLWriter.Write( ">" ); + + for ( int iIndex = pFolder->m_Files.Head(); iIndex != pFolder->m_Files.InvalidIndex(); iIndex = pFolder->m_Files.Next( iIndex ) ) + { + if ( !WriteFile( pFolder->m_Files[iIndex] ) ) + return false; + } + + for ( int iIndex = pFolder->m_Folders.Head(); iIndex != pFolder->m_Folders.InvalidIndex(); iIndex = pFolder->m_Folders.Next( iIndex ) ) + { + if ( !WriteFolder( pFolder->m_Folders[iIndex] ) ) + return false; + } + + m_XMLWriter.PopNode( true ); + + return true; +} + +bool CProjectGenerator_Win32::WriteConfiguration( CProjectConfiguration *pConfig ) +{ + const char *pTargetPlatformName = g_pVPC->IsPlatformDefined( "win64" ) ? "x64" : "Win32"; + + if ( pConfig->m_bIsFileConfig ) + { + m_XMLWriter.PushNode( "FileConfiguration" ); + } + else + { + m_XMLWriter.PushNode( "Configuration" ); + } + + const char *pOutputName = "???"; + if ( !V_stricmp( pConfig->m_Name.Get(), "debug" ) ) + { + pOutputName = "Debug"; + } + else if ( !V_stricmp( pConfig->m_Name.Get(), "release" ) ) + { + pOutputName = "Release"; + } + else + { + return false; + } + + m_XMLWriter.Write( CFmtStrMax( "Name=\"%s|%s\"", pOutputName, pTargetPlatformName ) ); + + // write configuration properties + for ( int i = 0; i < pConfig->m_PropertyStates.m_PropertiesInOutputOrder.Count(); i++ ) + { + int sortedIndex = pConfig->m_PropertyStates.m_PropertiesInOutputOrder[i]; + WriteProperty( &pConfig->m_PropertyStates.m_Properties[sortedIndex] ); + } + + m_XMLWriter.Write( ">" ); + + if ( !WriteTool( "VCPreBuildEventTool", pConfig->GetPreBuildEventTool() ) ) + return false; + + if ( !WriteTool( "VCCustomBuildTool", pConfig->GetCustomBuildTool() ) ) + return false; + + if ( !WriteNULLTool( "VCXMLDataGeneratorTool", pConfig ) ) + return false; + + if ( !WriteNULLTool( "VCWebServiceProxyGeneratorTool", pConfig ) ) + return false; + + if ( !WriteNULLTool( "VCMIDLTool", pConfig ) ) + return false; + + if ( !WriteTool( "VCCLCompilerTool", pConfig->GetCompilerTool() ) ) + return false; + + if ( !WriteNULLTool( "VCManagedResourceCompilerTool", pConfig ) ) + return false; + + if ( !WriteTool( "VCResourceCompilerTool", pConfig->GetResourcesTool() ) ) + return false; + + if ( !WriteTool( "VCPreLinkEventTool", pConfig->GetPreLinkEventTool() ) ) + return false; + + if ( !WriteTool( "VCLinkerTool", pConfig->GetLinkerTool() ) ) + return false; + + if ( !WriteTool( "VCLibrarianTool", pConfig->GetLibrarianTool() ) ) + return false; + + if ( !WriteNULLTool( "VCALinkTool", pConfig ) ) + return false; + + if ( !WriteTool( "VCManifestTool", pConfig->GetManifestTool() ) ) + return false; + + if ( !WriteTool( "VCXDCMakeTool", pConfig->GetXMLDocGenTool() ) ) + return false; + + if ( !WriteTool( "VCBscMakeTool", pConfig->GetBrowseInfoTool() ) ) + return false; + + if ( !WriteNULLTool( "VCFxCopTool", pConfig ) ) + return false; + + if ( !pConfig->GetLibrarianTool() ) + { + if ( !WriteNULLTool( "VCAppVerifierTool", pConfig ) ) + return false; + + if ( !WriteNULLTool( "VCWebDeploymentTool", pConfig ) ) + return false; + } + + if ( !WriteTool( "VCPostBuildEventTool", pConfig->GetPostBuildEventTool() ) ) + return false; + + m_XMLWriter.PopNode( true ); + + return true; +} + +bool CProjectGenerator_Win32::WriteToXML() +{ + const char *pTargetPlatformName = g_pVPC->IsPlatformDefined( "win64" ) ? "x64" : "Win32"; + + m_XMLWriter.PushNode( "VisualStudioProject" ); + m_XMLWriter.Write( "ProjectType=\"Visual C++\"" ); + + if ( g_pVPC->BUse2008() ) + m_XMLWriter.Write( "Version=\"9.00\"" ); + else + m_XMLWriter.Write( "Version=\"8.00\"" ); + + m_XMLWriter.Write( CFmtStrMax( "Name=\"%s\"", m_pVCProjGenerator->GetProjectName().Get() ) ); + m_XMLWriter.Write( CFmtStrMax( "ProjectGUID=\"%s\"", m_pVCProjGenerator->GetGUIDString().Get() ) ); + if ( g_pVPC->BUseP4SCC() ) + m_XMLWriter.Write( "SccProjectName=\"Perforce Project\"\nSccLocalPath=\"..\"\nSccProvider=\"MSSCCI:Perforce SCM\"\n" ); + m_XMLWriter.Write( ">" ); + + m_XMLWriter.PushNode( "Platforms" ); + m_XMLWriter.PushNode( "Platform" ); + m_XMLWriter.Write( CFmtStrMax( "Name=\"%s\"", pTargetPlatformName) ); + m_XMLWriter.PopNode( false ); + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PushNode( "ToolFiles" ); + m_XMLWriter.PopNode( true ); + + CUtlVector< CUtlString > configurationNames; + m_pVCProjGenerator->GetAllConfigurationNames( configurationNames ); + + // write the root configurations + m_XMLWriter.PushNode( "Configurations" ); + for ( int i = 0; i < configurationNames.Count(); i++ ) + { + CProjectConfiguration *pConfiguration = NULL; + if ( m_pVCProjGenerator->GetRootConfiguration( configurationNames[i].Get(), &pConfiguration ) ) + { + if ( !WriteConfiguration( pConfiguration ) ) + return false; + } + } + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PushNode( "References" ); + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PushNode( "Files" ); + + CProjectFolder *pRootFolder = m_pVCProjGenerator->GetRootFolder(); + + for ( int iIndex = pRootFolder->m_Folders.Head(); iIndex != pRootFolder->m_Folders.InvalidIndex(); iIndex = pRootFolder->m_Folders.Next( iIndex ) ) + { + if ( !WriteFolder( pRootFolder->m_Folders[iIndex] ) ) + return false; + } + + for ( int iIndex = pRootFolder->m_Files.Head(); iIndex != pRootFolder->m_Files.InvalidIndex(); iIndex = pRootFolder->m_Files.Next( iIndex ) ) + { + if ( !WriteFile( pRootFolder->m_Files[iIndex] ) ) + return false; + } + + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PopNode( true ); + + return true; +} + +bool CProjectGenerator_Win32::Save( const char *pOutputFilename ) +{ + if ( !m_XMLWriter.Open( pOutputFilename ) ) + return false; + + bool bValid = WriteToXML(); + + m_XMLWriter.Close(); + + return bValid; +} + +bool CProjectGenerator_Win32::WriteNULLTool( const char *pToolName, const CProjectConfiguration *pConfig ) +{ + if ( pConfig->m_bIsFileConfig ) + return true; + + m_XMLWriter.PushNode( "Tool" ); + + m_XMLWriter.Write( CFmtStr( "Name=\"%s\"", pToolName ) ); + + m_XMLWriter.PopNode( false ); + + return true; +} + +bool CProjectGenerator_Win32::WriteTool( const char *pToolName, const CProjectTool *pProjectTool ) +{ + if ( !pProjectTool ) + { + // not an error, some tools n/a for a config + return true; + } + + m_XMLWriter.PushNode( "Tool" ); + + m_XMLWriter.Write( CFmtStr( "Name=\"%s\"", pToolName ) ); + + for ( int i = 0; i < pProjectTool->m_PropertyStates.m_PropertiesInOutputOrder.Count(); i++ ) + { + int sortedIndex = pProjectTool->m_PropertyStates.m_PropertiesInOutputOrder[i]; + WriteProperty( &pProjectTool->m_PropertyStates.m_Properties[sortedIndex] ); + } + + m_XMLWriter.PopNode( false ); + + return true; +} + +bool CProjectGenerator_Win32::WriteProperty( const PropertyState_t *pPropertyState, const char *pOutputName, const char *pOutputValue ) +{ + if ( !pPropertyState ) + { + m_XMLWriter.Write( CFmtStrMax( "%s=\"%s\"", pOutputName, pOutputValue ) ); + return true; + } + + if ( !pOutputName ) + { + pOutputName = pPropertyState->m_pToolProperty->m_OutputString.Get(); + if ( !pOutputName[0] ) + { + pOutputName = pPropertyState->m_pToolProperty->m_ParseString.Get(); + if ( pOutputName[0] == '$' ) + { + pOutputName++; + } + } + } + + if ( pPropertyState ) + { + switch ( pPropertyState->m_pToolProperty->m_nType ) + { + case PT_BOOLEAN: + { + bool bEnabled = Sys_StringToBool( pPropertyState->m_StringValue.Get() ); + if ( pPropertyState->m_pToolProperty->m_bInvertOutput ) + { + bEnabled ^= 1; + } + m_XMLWriter.Write( CFmtStrMax( "%s=\"%s\"", pOutputName, bEnabled ? "true" : "false" ) ); + } + break; + + case PT_STRING: + m_XMLWriter.Write( CFmtStrMax( "%s=\"%s\"", pOutputName, m_XMLWriter.FixupXMLString( pPropertyState->m_StringValue.Get() ) ) ); + break; + + case PT_LIST: + case PT_INTEGER: + m_XMLWriter.Write( CFmtStrMax( "%s=\"%s\"", pOutputName, pPropertyState->m_StringValue.Get() ) ); + break; + + case PT_IGNORE: + break; + + default: + g_pVPC->VPCError( "CProjectGenerator_Win32: WriteProperty, %s - not implemented", pOutputName ); + } + } + + return true; +} diff --git a/external/vpc/utils/vpc/projectgenerator_win32.h b/external/vpc/utils/vpc/projectgenerator_win32.h new file mode 100644 index 0000000..01048bf --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_win32.h @@ -0,0 +1,41 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef PROJECTGENERATOR_WIN32_H +#define PROJECTGENERATOR_WIN32_H +#ifdef _WIN32 +#pragma once +#endif + +#define PROPERTYNAME( X, Y ) X##_##Y, +enum Win32Properties_e +{ + #include "projectgenerator_win32.inc" +}; + +class CProjectGenerator_Win32 : public IVCProjWriter +{ +public: + CProjectGenerator_Win32(); + IBaseProjectGenerator *GetProjectGenerator() { return m_pVCProjGenerator; } + + virtual bool Save( const char *pOutputFilename ); + +private: + bool WriteToXML(); + + bool WriteFolder( CProjectFolder *pFolder ); + bool WriteFile( CProjectFile *pFile ); + bool WriteConfiguration( CProjectConfiguration *pConfig ); + bool WriteProperty( const PropertyState_t *pPropertyState, const char *pOutputName = NULL, const char *pValue = NULL ); + bool WriteTool( const char *pToolName, const CProjectTool *pProjectTool ); + bool WriteNULLTool( const char *pToolName, const CProjectConfiguration *pConfig ); + + CXMLWriter m_XMLWriter; + CVCProjGenerator *m_pVCProjGenerator; +}; + +#endif // PROJECTGENERATOR_WIN32_H diff --git a/external/vpc/utils/vpc/projectgenerator_win32.inc b/external/vpc/utils/vpc/projectgenerator_win32.inc new file mode 100644 index 0000000..65d2929 --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_win32.inc @@ -0,0 +1,252 @@ + +//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Property Enumerations +// +//=====================================================================================// + +// Config +PROPERTYNAME( WIN32_GENERAL, ExcludedFromBuild ) +PROPERTYNAME( WIN32_GENERAL, OutputDirectory ) +PROPERTYNAME( WIN32_GENERAL, IntermediateDirectory ) +PROPERTYNAME( WIN32_GENERAL, ConfigurationType ) +PROPERTYNAME( WIN32_GENERAL, CharacterSet ) +PROPERTYNAME( WIN32_GENERAL, WholeProgramOptimization ) +PROPERTYNAME( WIN32_GENERAL, ExtensionsToDeleteOnClean ) +PROPERTYNAME( WIN32_GENERAL, BuildLogFile ) +PROPERTYNAME( WIN32_GENERAL, InheritedProjectPropertySheets ) +PROPERTYNAME( WIN32_GENERAL, UseOfMFC ) +PROPERTYNAME( WIN32_GENERAL, UseOfATL ) +PROPERTYNAME( WIN32_GENERAL, MinimizeCRTUseInATL ) + +// Debugging +PROPERTYNAME( WIN32_DEBUGGING, Command ) +PROPERTYNAME( WIN32_DEBUGGING, CommandArguments ) +PROPERTYNAME( WIN32_DEBUGGING, RemoteMachine ) +PROPERTYNAME( WIN32_DEBUGGING, WorkingDirectory ) +PROPERTYNAME( WIN32_DEBUGGING, Attach ) +PROPERTYNAME( WIN32_DEBUGGING, DebuggerType ) +PROPERTYNAME( WIN32_DEBUGGING, Environment ) +PROPERTYNAME( WIN32_DEBUGGING, MergeEnvironment ) +PROPERTYNAME( WIN32_DEBUGGING, SQLDebugging ) + +// Compiler +PROPERTYNAME( WIN32_COMPILER, UseUNICODEResponseFiles ) +PROPERTYNAME( WIN32_COMPILER, AdditionalOptions ) +PROPERTYNAME( WIN32_COMPILER, Optimization ) +PROPERTYNAME( WIN32_COMPILER, InlineFunctionExpansion ) +PROPERTYNAME( WIN32_COMPILER, EnableIntrinsicFunctions ) +PROPERTYNAME( WIN32_COMPILER, FavorSizeOrSpeed ) +PROPERTYNAME( WIN32_COMPILER, EnableFiberSafeOptimizations ) +PROPERTYNAME( WIN32_COMPILER, WholeProgramOptimization ) +PROPERTYNAME( WIN32_COMPILER, AdditionalIncludeDirectories ) +PROPERTYNAME( WIN32_COMPILER, PreprocessorDefinitions ) +PROPERTYNAME( WIN32_COMPILER, IgnoreStandardIncludePath ) +PROPERTYNAME( WIN32_COMPILER, GeneratePreprocessedFile ) +PROPERTYNAME( WIN32_COMPILER, KeepComments ) +PROPERTYNAME( WIN32_COMPILER, EnableStringPooling ) +PROPERTYNAME( WIN32_COMPILER, EnableMinimalRebuild ) +PROPERTYNAME( WIN32_COMPILER, EnableCPPExceptions ) +PROPERTYNAME( WIN32_COMPILER, BasicRuntimeChecks ) +PROPERTYNAME( WIN32_COMPILER, SmallerTypeCheck ) +PROPERTYNAME( WIN32_COMPILER, RuntimeLibrary ) +PROPERTYNAME( WIN32_COMPILER, StructMemberAlignment ) +PROPERTYNAME( WIN32_COMPILER, BufferSecurityCheck ) +PROPERTYNAME( WIN32_COMPILER, EnableFunctionLevelLinking ) +PROPERTYNAME( WIN32_COMPILER, EnableEnhancedInstructionSet ) +PROPERTYNAME( WIN32_COMPILER, FloatingPointModel ) +PROPERTYNAME( WIN32_COMPILER, EnableFloatingPointExceptions ) +PROPERTYNAME( WIN32_COMPILER, DisableLanguageExtensions ) +PROPERTYNAME( WIN32_COMPILER, DefaultCharUnsigned ) +PROPERTYNAME( WIN32_COMPILER, TreatWCHAR_TAsBuiltInType ) +PROPERTYNAME( WIN32_COMPILER, ForceConformanceInForLoopScope ) +PROPERTYNAME( WIN32_COMPILER, EnableRunTimeTypeInfo ) +PROPERTYNAME( WIN32_COMPILER, OpenMPSupport ) +PROPERTYNAME( WIN32_COMPILER, CreateUsePrecompiledHeader ) +PROPERTYNAME( WIN32_COMPILER, CreateUsePCHThroughFile ) +PROPERTYNAME( WIN32_COMPILER, PrecompiledHeaderFile ) +PROPERTYNAME( WIN32_COMPILER, ExpandAttributedSource ) +PROPERTYNAME( WIN32_COMPILER, AssemblerOutput ) +PROPERTYNAME( WIN32_COMPILER, ASMListLocation ) +PROPERTYNAME( WIN32_COMPILER, ObjectFileName ) +PROPERTYNAME( WIN32_COMPILER, ProgramDatabaseFileName ) +PROPERTYNAME( WIN32_COMPILER, GenerateXMLDocumentationFiles ) +PROPERTYNAME( WIN32_COMPILER, EnableBrowseInformation ) +PROPERTYNAME( WIN32_COMPILER, BrowseFile ) +PROPERTYNAME( WIN32_COMPILER, WarningLevel ) +PROPERTYNAME( WIN32_COMPILER, TreatWarningsAsErrors ) +PROPERTYNAME( WIN32_COMPILER, Detect64bitPortabilityIssues ) +PROPERTYNAME( WIN32_COMPILER, SuppressStartupBanner ) +PROPERTYNAME( WIN32_COMPILER, DebugInformationFormat ) +PROPERTYNAME( WIN32_COMPILER, CompileAs ) +PROPERTYNAME( WIN32_COMPILER, ForceIncludes ) +PROPERTYNAME( WIN32_COMPILER, ShowIncludes ) +PROPERTYNAME( WIN32_COMPILER, UndefineAllPreprocessorDefinitions ) +PROPERTYNAME( WIN32_COMPILER, UndefinePreprocessorDefinitions ) +PROPERTYNAME( WIN32_COMPILER, UseFullPaths ) +PROPERTYNAME( WIN32_COMPILER, OmitDefaultLibraryNames ) +PROPERTYNAME( WIN32_COMPILER, TrapIntegerDividesOptimization ) +PROPERTYNAME( WIN32_COMPILER, PreschedulingOptimization ) +PROPERTYNAME( WIN32_COMPILER, InlineAssemblyOptimization ) +PROPERTYNAME( WIN32_COMPILER, RegisterReservation ) +PROPERTYNAME( WIN32_COMPILER, Stalls ) +PROPERTYNAME( WIN32_COMPILER, CallAttributedProfiling ) +PROPERTYNAME( WIN32_COMPILER, XMLDocumentationFileName ) +PROPERTYNAME( WIN32_COMPILER, DisableSpecificWarnings ) +PROPERTYNAME( WIN32_COMPILER, ResolveUsingReferences ) +PROPERTYNAME( WIN32_COMPILER, OmitFramePointers ) +PROPERTYNAME( WIN32_COMPILER, CallingConvention ) +PROPERTYNAME( WIN32_COMPILER, ForceUsing ) +PROPERTYNAME( WIN32_COMPILER, ErrorReporting ) + +// Librarian +PROPERTYNAME( WIN32_LIBRARIAN, UseUNICODEResponseFiles ) +PROPERTYNAME( WIN32_LIBRARIAN, AdditionalDependencies ) +PROPERTYNAME( WIN32_LIBRARIAN, OutputFile ) +PROPERTYNAME( WIN32_LIBRARIAN, AdditionalLibraryDirectories ) +PROPERTYNAME( WIN32_LIBRARIAN, SuppressStartupBanner ) +PROPERTYNAME( WIN32_LIBRARIAN, ModuleDefinitionFileName ) +PROPERTYNAME( WIN32_LIBRARIAN, IgnoreAllDefaultLibraries ) +PROPERTYNAME( WIN32_LIBRARIAN, IgnoreSpecificLibrary ) +PROPERTYNAME( WIN32_LIBRARIAN, ExportNamedFunctions ) +PROPERTYNAME( WIN32_LIBRARIAN, ForceSymbolReferences ) +PROPERTYNAME( WIN32_LIBRARIAN, LinkLibraryDependencies ) +PROPERTYNAME( WIN32_LIBRARIAN, AdditionalOptions ) + +// Linker +PROPERTYNAME( WIN32_LINKER, IgnoreImportLibrary ) +PROPERTYNAME( WIN32_LINKER, UseUNICODEResponseFiles ) +PROPERTYNAME( WIN32_LINKER, AdditionalOptions ) +PROPERTYNAME( WIN32_LINKER, AdditionalDependencies ) +PROPERTYNAME( WIN32_LINKER, ShowProgress ) +PROPERTYNAME( WIN32_LINKER, OutputFile ) +PROPERTYNAME( WIN32_LINKER, Version ) +PROPERTYNAME( WIN32_LINKER, EnableIncrementalLinking ) +PROPERTYNAME( WIN32_LINKER, SuppressStartupBanner ) +PROPERTYNAME( WIN32_LINKER, AdditionalLibraryDirectories ) +PROPERTYNAME( WIN32_LINKER, GenerateManifest ) +PROPERTYNAME( WIN32_LINKER, IgnoreAllDefaultLibraries ) +PROPERTYNAME( WIN32_LINKER, IgnoreSpecificLibrary ) +PROPERTYNAME( WIN32_LINKER, ModuleDefinitionFile ) +PROPERTYNAME( WIN32_LINKER, GenerateDebugInfo ) +PROPERTYNAME( WIN32_LINKER, DebuggableAssembly ) +PROPERTYNAME( WIN32_LINKER, GenerateProgramDatabaseFile ) +PROPERTYNAME( WIN32_LINKER, GenerateMapFile ) +PROPERTYNAME( WIN32_LINKER, MapFileName ) +PROPERTYNAME( WIN32_LINKER, SubSystem ) +PROPERTYNAME( WIN32_LINKER, EnableLargeAddresses ) +PROPERTYNAME( WIN32_LINKER, MapExports ) +PROPERTYNAME( WIN32_LINKER, StackReserveSize ) +PROPERTYNAME( WIN32_LINKER, StackCommitSize ) +PROPERTYNAME( WIN32_LINKER, References ) +PROPERTYNAME( WIN32_LINKER, EnableCOMDATFolding ) +PROPERTYNAME( WIN32_LINKER, LinkTimeCodeGeneration ) +PROPERTYNAME( WIN32_LINKER, EntryPoint ) +PROPERTYNAME( WIN32_LINKER, NoEntryPoint ) +PROPERTYNAME( WIN32_LINKER, SetChecksum ) +PROPERTYNAME( WIN32_LINKER, BaseAddress ) +PROPERTYNAME( WIN32_LINKER, ImportLibrary ) +PROPERTYNAME( WIN32_LINKER, TargetMachine ) +PROPERTYNAME( WIN32_LINKER, FixedBaseAddress ) +PROPERTYNAME( WIN32_LINKER, ErrorReporting ) +PROPERTYNAME( WIN32_LINKER, FunctionOrder ) +PROPERTYNAME( WIN32_LINKER, LinkLibraryDependencies ) +PROPERTYNAME( WIN32_LINKER, UseLibraryDependencyInputs ) +PROPERTYNAME( WIN32_LINKER, ForceSymbolReferences ) +PROPERTYNAME( WIN32_LINKER, StripPrivateSymbols ) +PROPERTYNAME( WIN32_LINKER, ProfileGuidedDatabase ) +PROPERTYNAME( WIN32_LINKER, MergeSections ) +PROPERTYNAME( WIN32_LINKER, RegisterOutput ) +PROPERTYNAME( WIN32_LINKER, AddModuleToAssembly ) +PROPERTYNAME( WIN32_LINKER, EmbedManagedResourceFile ) +PROPERTYNAME( WIN32_LINKER, DelayLoadedDLLs ) +PROPERTYNAME( WIN32_LINKER, AssemblyLinkResource ) +PROPERTYNAME( WIN32_LINKER, ManifestFile ) +PROPERTYNAME( WIN32_LINKER, AdditionalManifestDependencies ) +PROPERTYNAME( WIN32_LINKER, AllowIsolation ) +PROPERTYNAME( WIN32_LINKER, HeapReserveSize ) +PROPERTYNAME( WIN32_LINKER, HeapCommitSize ) +PROPERTYNAME( WIN32_LINKER, TerminalServer ) +PROPERTYNAME( WIN32_LINKER, SwapRunFromCD ) +PROPERTYNAME( WIN32_LINKER, SwapRunFromNetwork ) +PROPERTYNAME( WIN32_LINKER, Driver ) +PROPERTYNAME( WIN32_LINKER, OptimizeForWindows98 ) +PROPERTYNAME( WIN32_LINKER, MIDLCommands ) +PROPERTYNAME( WIN32_LINKER, IgnoreEmbeddedIDL ) +PROPERTYNAME( WIN32_LINKER, MergeIDLBaseFileName ) +PROPERTYNAME( WIN32_LINKER, TypeLibrary ) +PROPERTYNAME( WIN32_LINKER, TypeLibResourceID ) +PROPERTYNAME( WIN32_LINKER, TurnOffAssemblyGeneration ) +PROPERTYNAME( WIN32_LINKER, DelayLoadedDLL ) +PROPERTYNAME( WIN32_LINKER, Profile ) +PROPERTYNAME( WIN32_LINKER, CLRThreadAttribute ) +PROPERTYNAME( WIN32_LINKER, CLRImageType ) +PROPERTYNAME( WIN32_LINKER, KeyFile ) +PROPERTYNAME( WIN32_LINKER, KeyContainer ) +PROPERTYNAME( WIN32_LINKER, DelaySign ) +PROPERTYNAME( WIN32_LINKER, CLRUnmanagedCodeCheck ) + +// Manifest +PROPERTYNAME( WIN32_MANIFESTTOOL, UseUNICODEResponseFiles ) +PROPERTYNAME( WIN32_MANIFESTTOOL, SuppressStartupBanner ) +PROPERTYNAME( WIN32_MANIFESTTOOL, VerboseOutput ) +PROPERTYNAME( WIN32_MANIFESTTOOL, AssemblyIdentity ) +PROPERTYNAME( WIN32_MANIFESTTOOL, UseFAT32WorkAround ) +PROPERTYNAME( WIN32_MANIFESTTOOL, AdditionalManifestFiles ) +PROPERTYNAME( WIN32_MANIFESTTOOL, InputResourceManifests ) +PROPERTYNAME( WIN32_MANIFESTTOOL, EmbedManifest ) +PROPERTYNAME( WIN32_MANIFESTTOOL, OutputManifestFile ) +PROPERTYNAME( WIN32_MANIFESTTOOL, ManifestResourceFile ) +PROPERTYNAME( WIN32_MANIFESTTOOL, GenerateCatalogFiles ) +PROPERTYNAME( WIN32_MANIFESTTOOL, DependencyInformationFile ) +PROPERTYNAME( WIN32_MANIFESTTOOL, TypeLibraryFile ) +PROPERTYNAME( WIN32_MANIFESTTOOL, RegistrarScriptFile ) +PROPERTYNAME( WIN32_MANIFESTTOOL, ComponentFileName ) +PROPERTYNAME( WIN32_MANIFESTTOOL, ReplacementsFile ) +PROPERTYNAME( WIN32_MANIFESTTOOL, UpdateFileHashes ) +PROPERTYNAME( WIN32_MANIFESTTOOL, UpdateFileHashesSearchPath ) +PROPERTYNAME( WIN32_MANIFESTTOOL, AdditionalOptions ) + +// XML Document Generator +PROPERTYNAME( WIN32_XMLDOCUMENTGENERATOR, UseUNICODEResponseFiles ) +PROPERTYNAME( WIN32_XMLDOCUMENTGENERATOR, SuppressStartupBanner ) +PROPERTYNAME( WIN32_XMLDOCUMENTGENERATOR, ValidateIntelliSense ) +PROPERTYNAME( WIN32_XMLDOCUMENTGENERATOR, AdditionalDocumentFiles ) +PROPERTYNAME( WIN32_XMLDOCUMENTGENERATOR, OutputDocumentFile ) +PROPERTYNAME( WIN32_XMLDOCUMENTGENERATOR, DocumentLibraryDependencies ) +PROPERTYNAME( WIN32_XMLDOCUMENTGENERATOR, AdditionalOptions ) + +// Browse Information +PROPERTYNAME( WIN32_BROWSEINFORMATION, SuppressStartupBanner ) +PROPERTYNAME( WIN32_BROWSEINFORMATION, OutputFile ) +PROPERTYNAME( WIN32_BROWSEINFORMATION, AdditionalOptions ) + +// Resources +PROPERTYNAME( WIN32_RESOURCES, PreprocessorDefinitions ) +PROPERTYNAME( WIN32_RESOURCES, Culture ) +PROPERTYNAME( WIN32_RESOURCES, AdditionalIncludeDirectories ) +PROPERTYNAME( WIN32_RESOURCES, IgnoreStandardIncludePath ) +PROPERTYNAME( WIN32_RESOURCES, ShowProgress ) +PROPERTYNAME( WIN32_RESOURCES, ResourceFileName ) +PROPERTYNAME( WIN32_RESOURCES, AdditionalOptions ) + +// Pre Build +PROPERTYNAME( WIN32_PREBUILDEVENT, Description ) +PROPERTYNAME( WIN32_PREBUILDEVENT, CommandLine ) +PROPERTYNAME( WIN32_PREBUILDEVENT, ExcludedFromBuild ) + +// Pre Link +PROPERTYNAME( WIN32_PRELINKEVENT, Description ) +PROPERTYNAME( WIN32_PRELINKEVENT, CommandLine ) +PROPERTYNAME( WIN32_PRELINKEVENT, ExcludedFromBuild ) + +// Post Build +PROPERTYNAME( WIN32_POSTBUILDEVENT, Description ) +PROPERTYNAME( WIN32_POSTBUILDEVENT, CommandLine ) +PROPERTYNAME( WIN32_POSTBUILDEVENT, ExcludedFromBuild ) + +// Custom Build +PROPERTYNAME( WIN32_CUSTOMBUILDSTEP, Description ) +PROPERTYNAME( WIN32_CUSTOMBUILDSTEP, CommandLine ) +PROPERTYNAME( WIN32_CUSTOMBUILDSTEP, AdditionalDependencies ) +PROPERTYNAME( WIN32_CUSTOMBUILDSTEP, Outputs ) diff --git a/external/vpc/utils/vpc/projectgenerator_win32_2010.cpp b/external/vpc/utils/vpc/projectgenerator_win32_2010.cpp new file mode 100644 index 0000000..62a9eed --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_win32_2010.cpp @@ -0,0 +1,625 @@ +//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: VPC +// +//=====================================================================================// + +#include "vpc.h" + +#undef PROPERTYNAME +#define PROPERTYNAME( X, Y ) { X##_##Y, #X, #Y }, +static PropertyName_t s_Win32PropertyNames_2010[] = +{ + #include "projectgenerator_win32_2010.inc" + { -1, NULL, NULL } +}; + +IBaseProjectGenerator* GetWin32ProjectGenerator_2010() +{ + static CProjectGenerator_Win32_2010 *s_pProjectGenerator = NULL; + if ( !s_pProjectGenerator ) + { + s_pProjectGenerator = new CProjectGenerator_Win32_2010(); + } + + return s_pProjectGenerator->GetProjectGenerator(); +} + +CProjectGenerator_Win32_2010::CProjectGenerator_Win32_2010() +{ + m_pVCProjGenerator = new CVCProjGenerator(); + m_pVCProjGenerator->SetupGeneratorDefinition( this, "win32_2010.def", s_Win32PropertyNames_2010 ); +} + +enum TypeKeyNames_e +{ + TKN_LIBRARY = 0, + TKN_INCLUDE, + TKN_COMPILE, + TKN_RESOURCECOMPILE, + TKN_CUSTOMBUILD, + TKN_NONE, + TKN_MAX_COUNT, +}; + +static const char *s_TypeKeyNames[] = +{ + "Library", + "ClInclude", + "ClCompile", + "ResourceCompile", + "CustomBuild", + "None" +}; + +const char *CProjectGenerator_Win32_2010::GetKeyNameForFile( CProjectFile *pFile ) +{ + COMPILE_TIME_ASSERT( ARRAYSIZE( s_TypeKeyNames ) == TKN_MAX_COUNT ); + + const char *pExtension = V_GetFileExtension( pFile->m_Name.Get() ); + + const char *pKeyName = s_TypeKeyNames[TKN_NONE]; + if ( pExtension ) + { + if ( pFile->m_Configs.Count() && pFile->m_Configs[0]->GetCustomBuildTool() ) + { + pKeyName = s_TypeKeyNames[TKN_CUSTOMBUILD]; + } + else if ( IsCFileExtension( pExtension ) ) + { + pKeyName = s_TypeKeyNames[TKN_COMPILE]; + } + else if ( IsHFileExtension( pExtension ) ) + { + pKeyName = s_TypeKeyNames[TKN_INCLUDE]; + } + else if ( !V_stricmp( pExtension, "lib" ) ) + { + pKeyName = s_TypeKeyNames[TKN_LIBRARY]; + } + else if ( !V_stricmp( pExtension, "rc" ) ) + { + pKeyName = s_TypeKeyNames[TKN_RESOURCECOMPILE]; + } + } + + return pKeyName; +} + +bool CProjectGenerator_Win32_2010::WritePropertyGroupTool( CProjectTool *pProjectTool, CProjectConfiguration *pConfiguration ) +{ + if ( !pProjectTool ) + return true; + + for ( int i = 0; i < pProjectTool->m_PropertyStates.m_PropertiesInOutputOrder.Count(); i++ ) + { + int sortedIndex = pProjectTool->m_PropertyStates.m_PropertiesInOutputOrder[i]; + if ( !pProjectTool->m_PropertyStates.m_Properties[sortedIndex].m_pToolProperty->m_bEmitAsGlobalProperty ) + continue; + + if ( !WriteProperty( &pProjectTool->m_PropertyStates.m_Properties[sortedIndex], true, pConfiguration->m_Name.Get() ) ) + return false; + } + + return true; +} + +bool CProjectGenerator_Win32_2010::WriteFile( CProjectFile *pFile, const char *pFileTypeName ) +{ + const char *pKeyName = GetKeyNameForFile( pFile ); + if ( V_stricmp( pFileTypeName, pKeyName ) ) + { + // skip it + return true; + } + + if ( !pFile->m_Configs.Count() ) + { + m_XMLWriter.Write( CFmtStrMax( "<%s Include=\"%s\" />", pKeyName, pFile->m_Name.Get() ) ); + } + else + { + m_XMLWriter.PushNode( pKeyName, CFmtStr( "Include=\"%s\"", pFile->m_Name.Get() ) ); + + for ( int i = 0; i < pFile->m_Configs.Count(); i++ ) + { + if ( !WriteConfiguration( pFile->m_Configs[i] ) ) + return false; + } + + m_XMLWriter.PopNode( true ); + } + + return true; +} + +bool CProjectGenerator_Win32_2010::WriteFolder( CProjectFolder *pFolder, const char *pFileTypeName, int nDepth ) +{ + if ( !nDepth ) + { + m_XMLWriter.PushNode( "ItemGroup" ); + } + + for ( int iIndex = pFolder->m_Files.Head(); iIndex != pFolder->m_Files.InvalidIndex(); iIndex = pFolder->m_Files.Next( iIndex ) ) + { + if ( !WriteFile( pFolder->m_Files[iIndex], pFileTypeName ) ) + return false; + } + + for ( int iIndex = pFolder->m_Folders.Head(); iIndex != pFolder->m_Folders.InvalidIndex(); iIndex = pFolder->m_Folders.Next( iIndex ) ) + { + if ( !WriteFolder( pFolder->m_Folders[iIndex], pFileTypeName, nDepth+1 ) ) + return false; + } + + if ( !nDepth ) + { + m_XMLWriter.PopNode( true ); + } + + return true; +} + +bool CProjectGenerator_Win32_2010::WriteConfiguration( CProjectConfiguration *pConfig ) +{ + if ( !pConfig->m_bIsFileConfig ) + { + const char *pTargetPlatformName = g_pVPC->IsPlatformDefined( "win64" ) ? "x64" : "Win32"; + + m_XMLWriter.PushNode( "PropertyGroup", CFmtStr( "Condition=\"'$(Configuration)|$(Platform)'=='%s|%s'\" Label=\"Configuration\"", pConfig->m_Name.Get(), pTargetPlatformName ) ); + + for ( int i = 0; i < pConfig->m_PropertyStates.m_PropertiesInOutputOrder.Count(); i++ ) + { + int sortedIndex = pConfig->m_PropertyStates.m_PropertiesInOutputOrder[i]; + if ( pConfig->m_PropertyStates.m_Properties[sortedIndex].m_pToolProperty->m_bEmitAsGlobalProperty ) + continue; + + if ( !WriteProperty( &pConfig->m_PropertyStates.m_Properties[sortedIndex] ) ) + return false; + } + + m_XMLWriter.PopNode( true ); + } + else + { + for ( int i = 0; i < pConfig->m_PropertyStates.m_PropertiesInOutputOrder.Count(); i++ ) + { + int sortedIndex = pConfig->m_PropertyStates.m_PropertiesInOutputOrder[i]; + if ( !WriteProperty( &pConfig->m_PropertyStates.m_Properties[sortedIndex], true, pConfig->m_Name.Get() ) ) + return false; + } + + if ( !WriteTool( "ClCompile", pConfig->GetCompilerTool(), pConfig ) ) + return false; + + if ( !WriteTool( "CustomBuildStep", pConfig->GetCustomBuildTool(), pConfig ) ) + return false; + } + + return true; +} + +bool CProjectGenerator_Win32_2010::WriteTools( CProjectConfiguration *pConfig ) +{ + const char *pTargetPlatformName = g_pVPC->IsPlatformDefined( "win64" ) ? "x64" : "Win32"; + + m_XMLWriter.PushNode( "ItemDefinitionGroup", CFmtStr( "Condition=\"'$(Configuration)|$(Platform)'=='%s|%s'\"", pConfig->m_Name.Get(), pTargetPlatformName ) ); + + if ( !WriteTool( "PreBuildEvent", pConfig->GetPreBuildEventTool(), pConfig ) ) + return false; + + if ( !WriteTool( "ClCompile", pConfig->GetCompilerTool(), pConfig ) ) + return false; + + if ( !WriteTool( "ResourceCompile", pConfig->GetResourcesTool(), pConfig ) ) + return false; + + if ( !WriteTool( "PreLinkEvent", pConfig->GetPreLinkEventTool(), pConfig ) ) + return false; + + if ( !WriteTool( "Link", pConfig->GetLinkerTool(), pConfig ) ) + return false; + + if ( !WriteTool( "Lib", pConfig->GetLibrarianTool(), pConfig ) ) + return false; + + if ( !WriteTool( "Manifest", pConfig->GetManifestTool(), pConfig ) ) + return false; + + if ( !WriteTool( "Xdcmake", pConfig->GetXMLDocGenTool(), pConfig ) ) + return false; + + if ( !WriteTool( "Bscmake", pConfig->GetBrowseInfoTool(), pConfig ) ) + return false; + + if ( !WriteTool( "PostBuildEvent", pConfig->GetPostBuildEventTool(), pConfig ) ) + return false; + + if ( !WriteTool( "CustomBuildStep", pConfig->GetCustomBuildTool(), pConfig ) ) + return false; + + m_XMLWriter.PopNode( true ); + + return true; +} + +bool CProjectGenerator_Win32_2010::WritePrimaryXML( const char *pOutputFilename ) +{ + if ( !m_XMLWriter.Open( pOutputFilename, true ) ) + return false; + + const char *pTargetPlatformName = g_pVPC->IsPlatformDefined( "win64" ) ? "x64" : "Win32"; + + m_XMLWriter.PushNode( "Project", "DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\"" ); + + m_XMLWriter.PushNode( "ItemGroup", "Label=\"ProjectConfigurations\"" ); + CUtlVector< CUtlString > configurationNames; + m_pVCProjGenerator->GetAllConfigurationNames( configurationNames ); + const char *pPlatformString = "Win32"; + if ( g_pVPC->IsPlatformDefined( "WIN64" ) ) + pPlatformString = "x64"; + for ( int i = 0; i < configurationNames.Count(); i++ ) + { + m_XMLWriter.PushNode( "ProjectConfiguration", CFmtStr( "Include=\"%s|%s\"", configurationNames[i].Get(), pTargetPlatformName ) ); + m_XMLWriter.WriteLineNode( "Configuration", "", configurationNames[i].Get() ); + m_XMLWriter.WriteLineNode( "Platform", "", CFmtStr( "%s", pTargetPlatformName ) ); + m_XMLWriter.PopNode( true ); + } + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PushNode( "PropertyGroup", "Label=\"Globals\"" ); + m_XMLWriter.WriteLineNode( "ProjectName", "", m_pVCProjGenerator->GetProjectName().Get() ); + m_XMLWriter.WriteLineNode( "ProjectGuid", "", m_pVCProjGenerator->GetGUIDString().Get() ); + if ( g_pVPC->BUseP4SCC() ) + { + m_XMLWriter.WriteLineNode( "SccProjectName", "", "Perforce Project" ); + // it looks like 2k10 (at least) doesn't hook files in the project but not under + // the project root into source control, so make all the projects local paths + // the solution dir + char szCurrentDirectory[MAX_PATH]; + V_GetCurrentDirectory( szCurrentDirectory, V_ARRAYSIZE( szCurrentDirectory ) ); + char szRelativeFilename[MAX_PATH]; + if ( !V_MakeRelativePath( g_pVPC->GetStartDirectory(), szCurrentDirectory, szRelativeFilename, sizeof( szRelativeFilename ) ) ) + V_strncpy( szRelativeFilename, ".", V_ARRAYSIZE( szRelativeFilename ) ); + m_XMLWriter.WriteLineNode( "SccLocalPath", "", szRelativeFilename ); + m_XMLWriter.WriteLineNode( "SccProvider", "", "MSSCCI:Perforce SCM" ); + } + m_XMLWriter.PopNode( true ); + + m_XMLWriter.Write( "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />" ); + + // When building 64 bit, use 64 bit toolchain (there is no 64 bit toolchain for 32 bit projects). + // This property is written early/specially to ensure it is written prior to Microsoft.Cpp.props + if ( g_pVPC->IsPlatformDefined( "win64" ) && !g_pVPC->BUse32BitTools() ) + { + m_XMLWriter.PushNode( "PropertyGroup" ); + m_XMLWriter.WriteLineNode( "PreferredToolArchitecture", NULL, "x64" ); + m_XMLWriter.PopNode( true ); + } + + // write the root configurations + for ( int i = 0; i < configurationNames.Count(); i++ ) + { + CProjectConfiguration *pConfiguration = NULL; + if ( m_pVCProjGenerator->GetRootConfiguration( configurationNames[i].Get(), &pConfiguration ) ) + { + if ( !WriteConfiguration( pConfiguration ) ) + return false; + } + } + + m_XMLWriter.Write( "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />" ); + m_XMLWriter.PushNode( "ImportGroup", "Label=\"ExtensionSettings\"" ); + m_XMLWriter.PopNode( true ); + + for ( int i = 0; i < configurationNames.Count(); i++ ) + { + m_XMLWriter.PushNode( "ImportGroup", CFmtStr( "Condition=\"'$(Configuration)|$(Platform)'=='%s|%s'\" Label=\"PropertySheets\"", configurationNames[i].Get(), pTargetPlatformName ) ); + m_XMLWriter.Write( "<Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />" ); + m_XMLWriter.PopNode( true ); + } + + m_XMLWriter.Write( "<PropertyGroup Label=\"UserMacros\" />" ); + + m_XMLWriter.PushNode( "PropertyGroup" ); + m_XMLWriter.WriteLineNode( "_ProjectFileVersion", "", "10.0.30319.1" ); + for ( int i = 0; i < configurationNames.Count(); i++ ) + { + CProjectConfiguration *pConfiguration = NULL; + if ( m_pVCProjGenerator->GetRootConfiguration( configurationNames[i].Get(), &pConfiguration ) ) + { + for ( int j = 0; j < pConfiguration->m_PropertyStates.m_PropertiesInOutputOrder.Count(); j++ ) + { + int sortedIndex = pConfiguration->m_PropertyStates.m_PropertiesInOutputOrder[j]; + if ( !pConfiguration->m_PropertyStates.m_Properties[sortedIndex].m_pToolProperty->m_bEmitAsGlobalProperty ) + continue; + + if ( !WriteProperty( &pConfiguration->m_PropertyStates.m_Properties[sortedIndex], true, pConfiguration->m_Name.Get() ) ) + return false; + } + + if ( !WritePropertyGroupTool( pConfiguration->GetPreBuildEventTool(), pConfiguration ) ) + return false; + + if ( !WritePropertyGroupTool( pConfiguration->GetPreLinkEventTool(), pConfiguration ) ) + return false; + + if ( !WritePropertyGroupTool( pConfiguration->GetLinkerTool(), pConfiguration ) ) + return false; + + if ( !WritePropertyGroupTool( pConfiguration->GetLibrarianTool(), pConfiguration ) ) + return false; + + if ( !WritePropertyGroupTool( pConfiguration->GetPostBuildEventTool(), pConfiguration ) ) + return false; + } + } + m_XMLWriter.PopNode( true ); + + // write the tool configurations + for ( int i = 0; i < configurationNames.Count(); i++ ) + { + CProjectConfiguration *pConfiguration = NULL; + if ( m_pVCProjGenerator->GetRootConfiguration( configurationNames[i].Get(), &pConfiguration ) ) + { + if ( !WriteTools( pConfiguration ) ) + return false; + } + } + + // write root folders + for ( int i = 0; i < TKN_MAX_COUNT; i++ ) + { + if ( !WriteFolder( m_pVCProjGenerator->GetRootFolder(), s_TypeKeyNames[i], 0 ) ) + return false; + } + + m_XMLWriter.Write( "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />" ); + m_XMLWriter.PushNode( "ImportGroup", "Label=\"ExtensionTargets\"" ); + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PopNode( true ); + + m_XMLWriter.Close(); + + return true; +} + +bool CProjectGenerator_Win32_2010::WriteFolderToSecondaryXML( CProjectFolder *pFolder, const char *pParentPath ) +{ + CUtlString parentPath = CFmtStr( "%s%s%s", pParentPath, pParentPath[0] ? "\\" : "", pFolder->m_Name.Get() ); + + MD5Context_t ctx; + unsigned char digest[MD5_DIGEST_LENGTH]; + V_memset( &ctx, 0, sizeof( ctx ) ); + V_memset( digest, 0, sizeof( digest ) ); + MD5Init( &ctx ); + MD5Update( &ctx, (unsigned char *)parentPath.Get(), strlen( parentPath.Get() ) ); + MD5Final( digest, &ctx ); + + char szMD5[64]; + V_binarytohex( digest, MD5_DIGEST_LENGTH, szMD5, sizeof( szMD5 ) ); + V_strupr( szMD5 ); + + char szGUID[MAX_PATH]; + V_snprintf( szGUID, sizeof( szGUID ), "{%8.8s-%4.4s-%4.4s-%4.4s-%12.12s}", szMD5, &szMD5[8], &szMD5[12], &szMD5[16], &szMD5[20] ); + + m_XMLFilterWriter.PushNode( "Filter", CFmtStr( "Include=\"%s\"", parentPath.Get() ) ); + m_XMLFilterWriter.WriteLineNode( "UniqueIdentifier", "", szGUID ); + m_XMLFilterWriter.PopNode( true ); + + for ( int iIndex = pFolder->m_Folders.Head(); iIndex != pFolder->m_Folders.InvalidIndex(); iIndex = pFolder->m_Folders.Next( iIndex ) ) + { + if ( !WriteFolderToSecondaryXML( pFolder->m_Folders[iIndex], parentPath.Get() ) ) + return false; + } + + return true; +} + +bool CProjectGenerator_Win32_2010::WriteFileToSecondaryXML( CProjectFile *pFile, const char *pParentPath, const char *pFileTypeName ) +{ + const char *pKeyName = GetKeyNameForFile( pFile ); + if ( V_stricmp( pFileTypeName, pKeyName ) ) + { + // skip it + return true; + } + + if ( pParentPath ) + { + m_XMLFilterWriter.PushNode( pKeyName, CFmtStr( "Include=\"%s\"", pFile->m_Name.Get() ) ); + m_XMLFilterWriter.WriteLineNode( "Filter", "", pParentPath ); + m_XMLFilterWriter.PopNode( true ); + } + else + { + m_XMLFilterWriter.Write( CFmtStr( "<%s Include=\"%s\" />", pKeyName, pFile->m_Name.Get() ) ); + } + + return true; +} + +bool CProjectGenerator_Win32_2010::WriteFolderContentsToSecondaryXML( CProjectFolder *pFolder, const char *pParentPath, const char *pFileTypeName, int nDepth ) +{ + CUtlString parentPath; + if ( pParentPath ) + { + parentPath = CFmtStr( "%s%s%s", pParentPath, pParentPath[0] ? "\\" : "", pFolder->m_Name.Get() ); + } + + if ( !nDepth ) + { + m_XMLFilterWriter.PushNode( "ItemGroup", NULL ); + } + + for ( int iIndex = pFolder->m_Files.Head(); iIndex != pFolder->m_Files.InvalidIndex(); iIndex = pFolder->m_Files.Next( iIndex ) ) + { + if ( !WriteFileToSecondaryXML( pFolder->m_Files[iIndex], parentPath.Get(), pFileTypeName ) ) + return false; + } + + for ( int iIndex = pFolder->m_Folders.Head(); iIndex != pFolder->m_Folders.InvalidIndex(); iIndex = pFolder->m_Folders.Next( iIndex ) ) + { + if ( !WriteFolderContentsToSecondaryXML( pFolder->m_Folders[iIndex], parentPath.Get(), pFileTypeName, nDepth+1 ) ) + return false; + } + + if ( !nDepth ) + { + m_XMLFilterWriter.PopNode( true ); + } + + return true; +} + +bool CProjectGenerator_Win32_2010::WriteSecondaryXML( const char *pOutputFilename ) +{ + if ( !m_XMLFilterWriter.Open( pOutputFilename, true ) ) + return false; + + m_XMLFilterWriter.PushNode( "Project", "ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\"" ); + + // write the root folders + m_XMLFilterWriter.PushNode( "ItemGroup", NULL ); + CProjectFolder *pRootFolder = m_pVCProjGenerator->GetRootFolder(); + for ( int iIndex = pRootFolder->m_Folders.Head(); iIndex != pRootFolder->m_Folders.InvalidIndex(); iIndex = pRootFolder->m_Folders.Next( iIndex ) ) + { + if ( !WriteFolderToSecondaryXML( pRootFolder->m_Folders[iIndex], "" ) ) + return false; + } + m_XMLFilterWriter.PopNode( true ); + + // write folder contents + for ( int i = 0; i < TKN_MAX_COUNT; i++ ) + { + if ( !WriteFolderContentsToSecondaryXML( pRootFolder, NULL, s_TypeKeyNames[i], 0 ) ) + return false; + } + + m_XMLFilterWriter.PopNode( true ); + + m_XMLFilterWriter.Close(); + + return true; +} + +bool CProjectGenerator_Win32_2010::WriteTool( const char *pToolName, const CProjectTool *pProjectTool, CProjectConfiguration *pConfig ) +{ + if ( !pProjectTool ) + { + // not an error, some tools n/a for a config + return true; + } + + if ( !pConfig->m_bIsFileConfig ) + { + m_XMLWriter.PushNode( pToolName, NULL ); + } + + for ( int i = 0; i < pProjectTool->m_PropertyStates.m_PropertiesInOutputOrder.Count(); i++ ) + { + int sortedIndex = pProjectTool->m_PropertyStates.m_PropertiesInOutputOrder[i]; + if ( !pConfig->m_bIsFileConfig ) + { + if ( pProjectTool->m_PropertyStates.m_Properties[sortedIndex].m_pToolProperty->m_bEmitAsGlobalProperty ) + continue; + + if ( !WriteProperty( &pProjectTool->m_PropertyStates.m_Properties[sortedIndex] ) ) + return false; + } + else + { + if ( !WriteProperty( &pProjectTool->m_PropertyStates.m_Properties[sortedIndex], true, pConfig->m_Name.Get() ) ) + return false; + } + } + + if ( !pConfig->m_bIsFileConfig ) + { + m_XMLWriter.PopNode( true ); + } + + return true; +} + +bool CProjectGenerator_Win32_2010::WriteProperty( const PropertyState_t *pPropertyState, bool bEmitConfiguration, const char *pConfigName, const char *pOutputName, const char *pOutputValue ) +{ + if ( !pPropertyState ) + { + m_XMLWriter.WriteLineNode( pOutputName, "", pOutputValue ); + return true; + } + + if ( !pOutputName ) + { + pOutputName = pPropertyState->m_pToolProperty->m_OutputString.Get(); + if ( !pOutputName[0] ) + { + pOutputName = pPropertyState->m_pToolProperty->m_ParseString.Get(); + if ( pOutputName[0] == '$' ) + { + pOutputName++; + } + } + } + + const char *pCondition = ""; + CUtlString conditionString; + if ( bEmitConfiguration ) + { + const char *pTargetPlatformName = g_pVPC->IsPlatformDefined( "win64" ) ? "x64" : "Win32"; + + conditionString = CFmtStr( " Condition=\"'$(Configuration)|$(Platform)'=='%s|%s'\"", pConfigName, pTargetPlatformName ); + pCondition = conditionString.Get(); + } + + if ( pPropertyState ) + { + switch ( pPropertyState->m_pToolProperty->m_nType ) + { + case PT_BOOLEAN: + { + bool bEnabled = Sys_StringToBool( pPropertyState->m_StringValue.Get() ); + if ( pPropertyState->m_pToolProperty->m_bInvertOutput ) + { + bEnabled ^= 1; + } + m_XMLWriter.WriteLineNode( pOutputName, pCondition, bEnabled ? "true" : "false" ); + } + break; + + case PT_STRING: + m_XMLWriter.WriteLineNode( pOutputName, pCondition, m_XMLWriter.FixupXMLString( pPropertyState->m_StringValue.Get() ) ); + break; + + case PT_LIST: + case PT_INTEGER: + m_XMLWriter.WriteLineNode( pOutputName, pCondition, pPropertyState->m_StringValue.Get() ); + break; + + case PT_IGNORE: + break; + + default: + g_pVPC->VPCError( "CProjectGenerator_Win32_2010: WriteProperty, %s - not implemented", pOutputName ); + } + } + + return true; +} + +bool CProjectGenerator_Win32_2010::Save( const char *pOutputFilename ) +{ + bool bValid = WritePrimaryXML( pOutputFilename ); + if ( bValid ) + { + bValid = WriteSecondaryXML( CFmtStr( "%s.filters", pOutputFilename ) ); + if ( !bValid ) + { + g_pVPC->VPCError( "Cannot save to the specified project '%s'", pOutputFilename ); + } + } + + return bValid; +} diff --git a/external/vpc/utils/vpc/projectgenerator_win32_2010.h b/external/vpc/utils/vpc/projectgenerator_win32_2010.h new file mode 100644 index 0000000..ac5f44f --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_win32_2010.h @@ -0,0 +1,54 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef PROJECTGENERATOR_WIN32_2010_H +#define PROJECTGENERATOR_WIN32_2010_H +#ifdef _WIN32 +#pragma once +#endif + +#define PROPERTYNAME( X, Y ) X##_##Y, +enum Win32_2010_Properties_e +{ + #include "projectgenerator_win32_2010.inc" +}; + +class CProjectGenerator_Win32_2010 : public IVCProjWriter +{ +public: + CProjectGenerator_Win32_2010(); + IBaseProjectGenerator *GetProjectGenerator() { return m_pVCProjGenerator; } + + virtual bool Save( const char *pOutputFilename ); + +private: + // primary XML - foo.vcxproj + bool WritePrimaryXML( const char *pOutputFilename ); + bool WriteFolder( CProjectFolder *pFolder, const char *pFileTypeName, int nDepth ); + bool WriteFile( CProjectFile *pFile, const char *pFileTypeName ); + bool WriteConfiguration( CProjectConfiguration *pConfig ); + bool WriteTools( CProjectConfiguration *pConfig ); + bool WriteProperty( const PropertyState_t *pPropertyState, bool bEmitConfiguration = false, const char *pConfigurationName = NULL, const char *pOutputName = NULL, const char *pValue = NULL ); + bool WriteTool( const char *pToolName, const CProjectTool *pProjectTool, CProjectConfiguration *pConfig ); + bool WriteNULLTool( const char *pToolName, const CProjectConfiguration *pConfig ); + bool WritePropertyGroupTool( CProjectTool *pProjectTool, CProjectConfiguration *pConfiguration ); + bool WritePropertyGroup(); + + // secondary XML - foo.vcxproj.filters + bool WriteSecondaryXML( const char *pOutputFilename ); + bool WriteFolderToSecondaryXML( CProjectFolder *pFolder, const char *pParentPath ); + bool WriteFolderContentsToSecondaryXML( CProjectFolder *pFolder, const char *pParentPath, const char *pFileTypeName, int nDepth ); + bool WriteFileToSecondaryXML( CProjectFile *pFile, const char *pParentPath, const char *pFileTypeName ); + + const char *GetKeyNameForFile( CProjectFile *pFile ); + + CXMLWriter m_XMLWriter; + CXMLWriter m_XMLFilterWriter; + + CVCProjGenerator *m_pVCProjGenerator; +}; + +#endif // PROJECTGENERATOR_WIN32_2010_H diff --git a/external/vpc/utils/vpc/projectgenerator_win32_2010.inc b/external/vpc/utils/vpc/projectgenerator_win32_2010.inc new file mode 100644 index 0000000..dcf1143 --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_win32_2010.inc @@ -0,0 +1,299 @@ + +//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Property Enumerations +// +//=====================================================================================// + +// Config +PROPERTYNAME( WIN32_2010_GENERAL, ExcludedFromBuild ) +PROPERTYNAME( WIN32_2010_GENERAL, OutputDirectory ) +PROPERTYNAME( WIN32_2010_GENERAL, IntermediateDirectory ) +PROPERTYNAME( WIN32_2010_GENERAL, ConfigurationType ) +PROPERTYNAME( WIN32_2010_GENERAL, CharacterSet ) +PROPERTYNAME( WIN32_2010_GENERAL, WholeProgramOptimization ) +PROPERTYNAME( WIN32_2010_GENERAL, ExtensionsToDeleteOnClean ) +PROPERTYNAME( WIN32_2010_GENERAL, BuildLogFile ) +PROPERTYNAME( WIN32_2010_GENERAL, InheritedProjectPropertySheets ) +PROPERTYNAME( WIN32_2010_GENERAL, UseOfMFC ) +PROPERTYNAME( WIN32_2010_GENERAL, UseOfATL ) +PROPERTYNAME( WIN32_2010_GENERAL, MinimizeCRTUseInATL ) +PROPERTYNAME( WIN32_2010_GENERAL, TargetName ) +PROPERTYNAME( WIN32_2010_GENERAL, TargetExtension ) +PROPERTYNAME( WIN32_2010_GENERAL, PlatformToolset ) +PROPERTYNAME( WIN32_2010_GENERAL, ExecutableDirectories ) + +// Debugging +PROPERTYNAME( WIN32_2010_DEBUGGING, Command ) +PROPERTYNAME( WIN32_2010_DEBUGGING, CommandArguments ) +PROPERTYNAME( WIN32_2010_DEBUGGING, RemoteMachine ) +PROPERTYNAME( WIN32_2010_DEBUGGING, WorkingDirectory ) +PROPERTYNAME( WIN32_2010_DEBUGGING, Attach ) +PROPERTYNAME( WIN32_2010_DEBUGGING, DebuggerType ) +PROPERTYNAME( WIN32_2010_DEBUGGING, Environment ) +PROPERTYNAME( WIN32_2010_DEBUGGING, MergeEnvironment ) +PROPERTYNAME( WIN32_2010_DEBUGGING, SQLDebugging ) + +// Compiler +PROPERTYNAME( WIN32_2010_COMPILER, UseUNICODEResponseFiles ) +PROPERTYNAME( WIN32_2010_COMPILER, AdditionalOptions ) +PROPERTYNAME( WIN32_2010_COMPILER, Optimization ) +PROPERTYNAME( WIN32_2010_COMPILER, InlineFunctionExpansion ) +PROPERTYNAME( WIN32_2010_COMPILER, EnableIntrinsicFunctions ) +PROPERTYNAME( WIN32_2010_COMPILER, FavorSizeOrSpeed ) +PROPERTYNAME( WIN32_2010_COMPILER, EnableFiberSafeOptimizations ) +PROPERTYNAME( WIN32_2010_COMPILER, WholeProgramOptimization ) +PROPERTYNAME( WIN32_2010_COMPILER, AdditionalIncludeDirectories ) +PROPERTYNAME( WIN32_2010_COMPILER, PreprocessorDefinitions ) +PROPERTYNAME( WIN32_2010_COMPILER, IgnoreStandardIncludePath ) +PROPERTYNAME( WIN32_2010_COMPILER, GeneratePreprocessedFile ) +PROPERTYNAME( WIN32_2010_COMPILER, KeepComments ) +PROPERTYNAME( WIN32_2010_COMPILER, EnableStringPooling ) +PROPERTYNAME( WIN32_2010_COMPILER, EnableMinimalRebuild ) +PROPERTYNAME( WIN32_2010_COMPILER, EnableCPPExceptions ) +PROPERTYNAME( WIN32_2010_COMPILER, BasicRuntimeChecks ) +PROPERTYNAME( WIN32_2010_COMPILER, SmallerTypeCheck ) +PROPERTYNAME( WIN32_2010_COMPILER, RuntimeLibrary ) +PROPERTYNAME( WIN32_2010_COMPILER, StructMemberAlignment ) +PROPERTYNAME( WIN32_2010_COMPILER, BufferSecurityCheck ) +PROPERTYNAME( WIN32_2010_COMPILER, EnableFunctionLevelLinking ) +PROPERTYNAME( WIN32_2010_COMPILER, EnableEnhancedInstructionSet ) +PROPERTYNAME( WIN32_2010_COMPILER, FloatingPointModel ) +PROPERTYNAME( WIN32_2010_COMPILER, EnableFloatingPointExceptions ) +PROPERTYNAME( WIN32_2010_COMPILER, DisableLanguageExtensions ) +PROPERTYNAME( WIN32_2010_COMPILER, DefaultCharUnsigned ) +PROPERTYNAME( WIN32_2010_COMPILER, TreatWCHAR_TAsBuiltInType ) +PROPERTYNAME( WIN32_2010_COMPILER, ForceConformanceInForLoopScope ) +PROPERTYNAME( WIN32_2010_COMPILER, EnableRunTimeTypeInfo ) +PROPERTYNAME( WIN32_2010_COMPILER, OpenMPSupport ) +PROPERTYNAME( WIN32_2010_COMPILER, PrecompiledHeader ) +PROPERTYNAME( WIN32_2010_COMPILER, PrecompiledHeaderFile ) +PROPERTYNAME( WIN32_2010_COMPILER, PrecompiledHeaderOutputFile ) +PROPERTYNAME( WIN32_2010_COMPILER, ExpandAttributedSource ) +PROPERTYNAME( WIN32_2010_COMPILER, AssemblerOutput ) +PROPERTYNAME( WIN32_2010_COMPILER, ASMListLocation ) +PROPERTYNAME( WIN32_2010_COMPILER, ObjectFileName ) +PROPERTYNAME( WIN32_2010_COMPILER, ProgramDatabaseFileName ) +PROPERTYNAME( WIN32_2010_COMPILER, GenerateXMLDocumentationFiles ) +PROPERTYNAME( WIN32_2010_COMPILER, EnableBrowseInformation ) +PROPERTYNAME( WIN32_2010_COMPILER, BrowseFile ) +PROPERTYNAME( WIN32_2010_COMPILER, WarningLevel ) +PROPERTYNAME( WIN32_2010_COMPILER, TreatWarningsAsErrors ) +PROPERTYNAME( WIN32_2010_COMPILER, Detect64bitPortabilityIssues ) +PROPERTYNAME( WIN32_2010_COMPILER, SuppressStartupBanner ) +PROPERTYNAME( WIN32_2010_COMPILER, DebugInformationFormat ) +PROPERTYNAME( WIN32_2010_COMPILER, CompileAs ) +PROPERTYNAME( WIN32_2010_COMPILER, ForceIncludes ) +PROPERTYNAME( WIN32_2010_COMPILER, ShowIncludes ) +PROPERTYNAME( WIN32_2010_COMPILER, UndefineAllPreprocessorDefinitions ) +PROPERTYNAME( WIN32_2010_COMPILER, UndefinePreprocessorDefinitions ) +PROPERTYNAME( WIN32_2010_COMPILER, UseFullPaths ) +PROPERTYNAME( WIN32_2010_COMPILER, OmitDefaultLibraryNames ) +PROPERTYNAME( WIN32_2010_COMPILER, TrapIntegerDividesOptimization ) +PROPERTYNAME( WIN32_2010_COMPILER, PreschedulingOptimization ) +PROPERTYNAME( WIN32_2010_COMPILER, InlineAssemblyOptimization ) +PROPERTYNAME( WIN32_2010_COMPILER, RegisterReservation ) +PROPERTYNAME( WIN32_2010_COMPILER, Stalls ) +PROPERTYNAME( WIN32_2010_COMPILER, CallAttributedProfiling ) +PROPERTYNAME( WIN32_2010_COMPILER, XMLDocumentationFileName ) +PROPERTYNAME( WIN32_2010_COMPILER, DisableSpecificWarnings ) +PROPERTYNAME( WIN32_2010_COMPILER, ResolveUsingReferences ) +PROPERTYNAME( WIN32_2010_COMPILER, OmitFramePointers ) +PROPERTYNAME( WIN32_2010_COMPILER, CallingConvention ) +PROPERTYNAME( WIN32_2010_COMPILER, ForceUsing ) +PROPERTYNAME( WIN32_2010_COMPILER, ErrorReporting ) +PROPERTYNAME( WIN32_2010_COMPILER, CommonLanguageRuntimeSupport ) +PROPERTYNAME( WIN32_2010_COMPILER, MultiProcessorCompilation ) +PROPERTYNAME( WIN32_2010_COMPILER, UseUnicodeForAssemblerListing ) +PROPERTYNAME( WIN32_2010_COMPILER, IgnoreStandardIncludePaths ) +PROPERTYNAME( WIN32_2010_COMPILER, PreprocessToAFile ) +PROPERTYNAME( WIN32_2010_COMPILER, PreprocessSuppressLineNumbers ) +PROPERTYNAME( WIN32_2010_COMPILER, CreateHotpatchableImage ) +PROPERTYNAME( WIN32_2010_COMPILER, BrowseInformationFile ) +PROPERTYNAME( WIN32_2010_COMPILER, ForcedIncludeFile ) +PROPERTYNAME( WIN32_2010_COMPILER, ForcedUsingFile ) +PROPERTYNAME( WIN32_2010_COMPILER, OmitDefaultLibName ) +PROPERTYNAME( WIN32_2010_COMPILER, InternalCompilerErrorReporting ) +PROPERTYNAME( WIN32_2010_COMPILER, TreatSpecificWarningsAsErrors ) + +// Librarian +PROPERTYNAME( WIN32_2010_LIBRARIAN, UseUNICODEResponseFiles ) +PROPERTYNAME( WIN32_2010_LIBRARIAN, AdditionalDependencies ) +PROPERTYNAME( WIN32_2010_LIBRARIAN, OutputFile ) +PROPERTYNAME( WIN32_2010_LIBRARIAN, AdditionalLibraryDirectories ) +PROPERTYNAME( WIN32_2010_LIBRARIAN, SuppressStartupBanner ) +PROPERTYNAME( WIN32_2010_LIBRARIAN, ModuleDefinitionFileName ) +PROPERTYNAME( WIN32_2010_LIBRARIAN, IgnoreAllDefaultLibraries ) +PROPERTYNAME( WIN32_2010_LIBRARIAN, IgnoreSpecificLibrary ) +PROPERTYNAME( WIN32_2010_LIBRARIAN, ExportNamedFunctions ) +PROPERTYNAME( WIN32_2010_LIBRARIAN, ForceSymbolReferences ) +PROPERTYNAME( WIN32_2010_LIBRARIAN, LinkLibraryDependencies ) +PROPERTYNAME( WIN32_2010_LIBRARIAN, TargetMachine ) +PROPERTYNAME( WIN32_2010_LIBRARIAN, AdditionalOptions ) + +// Linker +PROPERTYNAME( WIN32_2010_LINKER, IgnoreImportLibrary ) +PROPERTYNAME( WIN32_2010_LINKER, UseUNICODEResponseFiles ) +PROPERTYNAME( WIN32_2010_LINKER, AdditionalOptions ) +PROPERTYNAME( WIN32_2010_LINKER, AdditionalDependencies ) +PROPERTYNAME( WIN32_2010_LINKER, ShowProgress ) +PROPERTYNAME( WIN32_2010_LINKER, OutputFile ) +PROPERTYNAME( WIN32_2010_LINKER, Version ) +PROPERTYNAME( WIN32_2010_LINKER, EnableIncrementalLinking ) +PROPERTYNAME( WIN32_2010_LINKER, SuppressStartupBanner ) +PROPERTYNAME( WIN32_2010_LINKER, AdditionalLibraryDirectories ) +PROPERTYNAME( WIN32_2010_LINKER, IgnoreSpecificDefaultLibraries ) +PROPERTYNAME( WIN32_2010_LINKER, GenerateManifest ) +PROPERTYNAME( WIN32_2010_LINKER, IgnoreAllDefaultLibraries ) +PROPERTYNAME( WIN32_2010_LINKER, IgnoreSpecificLibrary ) +PROPERTYNAME( WIN32_2010_LINKER, ModuleDefinitionFile ) +PROPERTYNAME( WIN32_2010_LINKER, GenerateDebugInfo ) +PROPERTYNAME( WIN32_2010_LINKER, DebuggableAssembly ) +PROPERTYNAME( WIN32_2010_LINKER, GenerateProgramDatabaseFile ) +PROPERTYNAME( WIN32_2010_LINKER, GenerateMapFile ) +PROPERTYNAME( WIN32_2010_LINKER, MapFileName ) +PROPERTYNAME( WIN32_2010_LINKER, SubSystem ) +PROPERTYNAME( WIN32_2010_LINKER, EnableLargeAddresses ) +PROPERTYNAME( WIN32_2010_LINKER, MapExports ) +PROPERTYNAME( WIN32_2010_LINKER, StackReserveSize ) +PROPERTYNAME( WIN32_2010_LINKER, StackCommitSize ) +PROPERTYNAME( WIN32_2010_LINKER, References ) +PROPERTYNAME( WIN32_2010_LINKER, EnableCOMDATFolding ) +PROPERTYNAME( WIN32_2010_LINKER, LinkTimeCodeGeneration ) +PROPERTYNAME( WIN32_2010_LINKER, EntryPoint ) +PROPERTYNAME( WIN32_2010_LINKER, NoEntryPoint ) +PROPERTYNAME( WIN32_2010_LINKER, SetChecksum ) +PROPERTYNAME( WIN32_2010_LINKER, BaseAddress ) +PROPERTYNAME( WIN32_2010_LINKER, ImportLibrary ) +PROPERTYNAME( WIN32_2010_LINKER, TargetMachine ) +PROPERTYNAME( WIN32_2010_LINKER, FixedBaseAddress ) +PROPERTYNAME( WIN32_2010_LINKER, ErrorReporting ) +PROPERTYNAME( WIN32_2010_LINKER, FunctionOrder ) +PROPERTYNAME( WIN32_2010_LINKER, LinkLibraryDependencies ) +PROPERTYNAME( WIN32_2010_LINKER, UseLibraryDependencyInputs ) +PROPERTYNAME( WIN32_2010_LINKER, ForceSymbolReferences ) +PROPERTYNAME( WIN32_2010_LINKER, StripPrivateSymbols ) +PROPERTYNAME( WIN32_2010_LINKER, ProfileGuidedDatabase ) +PROPERTYNAME( WIN32_2010_LINKER, MergeSections ) +PROPERTYNAME( WIN32_2010_LINKER, RegisterOutput ) +PROPERTYNAME( WIN32_2010_LINKER, AddModuleToAssembly ) +PROPERTYNAME( WIN32_2010_LINKER, EmbedManagedResourceFile ) +PROPERTYNAME( WIN32_2010_LINKER, DelayLoadedDLLs ) +PROPERTYNAME( WIN32_2010_LINKER, AssemblyLinkResource ) +PROPERTYNAME( WIN32_2010_LINKER, ManifestFile ) +PROPERTYNAME( WIN32_2010_LINKER, AdditionalManifestDependencies ) +PROPERTYNAME( WIN32_2010_LINKER, AllowIsolation ) +PROPERTYNAME( WIN32_2010_LINKER, HeapReserveSize ) +PROPERTYNAME( WIN32_2010_LINKER, HeapCommitSize ) +PROPERTYNAME( WIN32_2010_LINKER, TerminalServer ) +PROPERTYNAME( WIN32_2010_LINKER, SwapRunFromCD ) +PROPERTYNAME( WIN32_2010_LINKER, SwapRunFromNetwork ) +PROPERTYNAME( WIN32_2010_LINKER, Driver ) +PROPERTYNAME( WIN32_2010_LINKER, OptimizeForWindows98 ) +PROPERTYNAME( WIN32_2010_LINKER, MIDLCommands ) +PROPERTYNAME( WIN32_2010_LINKER, IgnoreEmbeddedIDL ) +PROPERTYNAME( WIN32_2010_LINKER, MergeIDLBaseFileName ) +PROPERTYNAME( WIN32_2010_LINKER, TypeLibrary ) +PROPERTYNAME( WIN32_2010_LINKER, TypeLibResourceID ) +PROPERTYNAME( WIN32_2010_LINKER, TurnOffAssemblyGeneration ) +PROPERTYNAME( WIN32_2010_LINKER, DelayLoadedDLL ) +PROPERTYNAME( WIN32_2010_LINKER, Profile ) +PROPERTYNAME( WIN32_2010_LINKER, CLRThreadAttribute ) +PROPERTYNAME( WIN32_2010_LINKER, CLRImageType ) +PROPERTYNAME( WIN32_2010_LINKER, KeyFile ) +PROPERTYNAME( WIN32_2010_LINKER, KeyContainer ) +PROPERTYNAME( WIN32_2010_LINKER, DelaySign ) +PROPERTYNAME( WIN32_2010_LINKER, CLRUnmanagedCodeCheck ) +PROPERTYNAME( WIN32_2010_LINKER, PerUserRedirection ) +PROPERTYNAME( WIN32_2010_LINKER, LinkStatus ) +PROPERTYNAME( WIN32_2010_LINKER, PreventDllBinding ) +PROPERTYNAME( WIN32_2010_LINKER, TreatLinkerWarningsAsErrors ) +PROPERTYNAME( WIN32_2010_LINKER, ForceFileOutput ) +PROPERTYNAME( WIN32_2010_LINKER, CreateHotpatchableImage ) +PROPERTYNAME( WIN32_2010_LINKER, SpecifySectionAttributes ) +PROPERTYNAME( WIN32_2010_LINKER, EnableUserAccountControl ) +PROPERTYNAME( WIN32_2010_LINKER, UACExecutionLevel ) +PROPERTYNAME( WIN32_2010_LINKER, UACBypassUIProtection ) +PROPERTYNAME( WIN32_2010_LINKER, MinimumRequiredVersion ) +PROPERTYNAME( WIN32_2010_LINKER, RandomizedBaseAddress ) +PROPERTYNAME( WIN32_2010_LINKER, DataExecutionPrevention ) +PROPERTYNAME( WIN32_2010_LINKER, UnloaddelayloadedDLL ) +PROPERTYNAME( WIN32_2010_LINKER, NobinddelayloadedDLL ) +PROPERTYNAME( WIN32_2010_LINKER, SectionAlignment ) +PROPERTYNAME( WIN32_2010_LINKER, PreserveLastErrorCodeforPInvokeCalls ) +PROPERTYNAME( WIN32_2010_LINKER, ImageHasSafeExceptionHandlers ) + +// Manifest +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, UseUNICODEResponseFiles ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, SuppressStartupBanner ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, VerboseOutput ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, AssemblyIdentity ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, UseFAT32WorkAround ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, AdditionalManifestFiles ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, InputResourceManifests ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, EmbedManifest ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, OutputManifestFile ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, ManifestResourceFile ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, GenerateCatalogFiles ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, DependencyInformationFile ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, TypeLibraryFile ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, RegistrarScriptFile ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, ComponentFileName ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, ReplacementsFile ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, UpdateFileHashes ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, UpdateFileHashesSearchPath ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, AdditionalOptions ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, GenerateManifestFromManagedAssembly ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, SuppressDependencyElement ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, GenerateCategoryTags ) +PROPERTYNAME( WIN32_2010_MANIFESTTOOL, EnableDPIAwareness ) + +// XML Document Generator +PROPERTYNAME( WIN32_2010_XMLDOCUMENTGENERATOR, UseUNICODEResponseFiles ) +PROPERTYNAME( WIN32_2010_XMLDOCUMENTGENERATOR, SuppressStartupBanner ) +PROPERTYNAME( WIN32_2010_XMLDOCUMENTGENERATOR, ValidateIntelliSense ) +PROPERTYNAME( WIN32_2010_XMLDOCUMENTGENERATOR, AdditionalDocumentFiles ) +PROPERTYNAME( WIN32_2010_XMLDOCUMENTGENERATOR, OutputDocumentFile ) +PROPERTYNAME( WIN32_2010_XMLDOCUMENTGENERATOR, DocumentLibraryDependencies ) +PROPERTYNAME( WIN32_2010_XMLDOCUMENTGENERATOR, AdditionalOptions ) + +// Browse Information +PROPERTYNAME( WIN32_2010_BROWSEINFORMATION, SuppressStartupBanner ) +PROPERTYNAME( WIN32_2010_BROWSEINFORMATION, OutputFile ) +PROPERTYNAME( WIN32_2010_BROWSEINFORMATION, AdditionalOptions ) +PROPERTYNAME( WIN32_2010_BROWSEINFORMATION, PreserveSBRFiles ) + +// Resources +PROPERTYNAME( WIN32_2010_RESOURCES, PreprocessorDefinitions ) +PROPERTYNAME( WIN32_2010_RESOURCES, Culture ) +PROPERTYNAME( WIN32_2010_RESOURCES, AdditionalIncludeDirectories ) +PROPERTYNAME( WIN32_2010_RESOURCES, IgnoreStandardIncludePath ) +PROPERTYNAME( WIN32_2010_RESOURCES, ShowProgress ) +PROPERTYNAME( WIN32_2010_RESOURCES, ResourceFileName ) +PROPERTYNAME( WIN32_2010_RESOURCES, AdditionalOptions ) + +// Pre Build +PROPERTYNAME( WIN32_2010_PREBUILDEVENT, Description ) +PROPERTYNAME( WIN32_2010_PREBUILDEVENT, CommandLine ) +PROPERTYNAME( WIN32_2010_PREBUILDEVENT, ExcludedFromBuild ) +PROPERTYNAME( WIN32_2010_PREBUILDEVENT, UseInBuild ) + +// Pre Link +PROPERTYNAME( WIN32_2010_PRELINKEVENT, Description ) +PROPERTYNAME( WIN32_2010_PRELINKEVENT, CommandLine ) +PROPERTYNAME( WIN32_2010_PRELINKEVENT, ExcludedFromBuild ) +PROPERTYNAME( WIN32_2010_PRELINKEVENT, UseInBuild ) + +// Post Build +PROPERTYNAME( WIN32_2010_POSTBUILDEVENT, Description ) +PROPERTYNAME( WIN32_2010_POSTBUILDEVENT, CommandLine ) +PROPERTYNAME( WIN32_2010_POSTBUILDEVENT, ExcludedFromBuild ) +PROPERTYNAME( WIN32_2010_POSTBUILDEVENT, UseInBuild ) + +// Custom Build +PROPERTYNAME( WIN32_2010_CUSTOMBUILDSTEP, Description ) +PROPERTYNAME( WIN32_2010_CUSTOMBUILDSTEP, CommandLine ) +PROPERTYNAME( WIN32_2010_CUSTOMBUILDSTEP, AdditionalDependencies ) +PROPERTYNAME( WIN32_2010_CUSTOMBUILDSTEP, Outputs ) +PROPERTYNAME( WIN32_2010_CUSTOMBUILDSTEP, ExecuteAfter ) +PROPERTYNAME( WIN32_2010_CUSTOMBUILDSTEP, ExecuteBefore ) diff --git a/external/vpc/utils/vpc/projectgenerator_xbox360.cpp b/external/vpc/utils/vpc/projectgenerator_xbox360.cpp new file mode 100644 index 0000000..96998f9 --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_xbox360.cpp @@ -0,0 +1,343 @@ +//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: VPC +// +//=====================================================================================// + +#include "vpc.h" + +#undef PROPERTYNAME +#define PROPERTYNAME( X, Y ) { X##_##Y, #X, #Y }, +static PropertyName_t s_Xbox360PropertyNames[] = +{ + #include "projectgenerator_xbox360.inc" + { -1, NULL, NULL } +}; + +IBaseProjectGenerator* GetXbox360ProjectGenerator() +{ + static CProjectGenerator_Xbox360 *s_pProjectGenerator = NULL; + if ( !s_pProjectGenerator ) + { + s_pProjectGenerator = new CProjectGenerator_Xbox360(); + } + + return s_pProjectGenerator->GetProjectGenerator(); +} + +CProjectGenerator_Xbox360::CProjectGenerator_Xbox360() +{ + m_pVCProjGenerator = new CVCProjGenerator(); + m_pVCProjGenerator->SetupGeneratorDefinition( this, "xbox360.def", s_Xbox360PropertyNames ); +} + +bool CProjectGenerator_Xbox360::WriteFile( CProjectFile *pFile ) +{ + m_XMLWriter.PushNode( "File" ); + m_XMLWriter.Write( CFmtStrMax( "RelativePath=\"%s\"", pFile->m_Name.Get() ) ); + m_XMLWriter.Write( ">" ); + + for ( int i = 0; i < pFile->m_Configs.Count(); i++ ) + { + if ( !WriteConfiguration( pFile->m_Configs[i] ) ) + return false; + } + + m_XMLWriter.PopNode( true ); + + return true; +} + +bool CProjectGenerator_Xbox360::WriteFolder( CProjectFolder *pFolder ) +{ + m_XMLWriter.PushNode( "Filter" ); + m_XMLWriter.Write( CFmtStrMax( "Name=\"%s\"", m_XMLWriter.FixupXMLString( pFolder->m_Name.Get() ) ) ); + m_XMLWriter.Write( ">" ); + + for ( int iIndex = pFolder->m_Files.Head(); iIndex != pFolder->m_Files.InvalidIndex(); iIndex = pFolder->m_Files.Next( iIndex ) ) + { + if ( !WriteFile( pFolder->m_Files[iIndex] ) ) + return false; + } + + for ( int iIndex = pFolder->m_Folders.Head(); iIndex != pFolder->m_Folders.InvalidIndex(); iIndex = pFolder->m_Folders.Next( iIndex ) ) + { + if ( !WriteFolder( pFolder->m_Folders[iIndex] ) ) + return false; + } + + m_XMLWriter.PopNode( true ); + + return true; +} + +bool CProjectGenerator_Xbox360::WriteConfiguration( CProjectConfiguration *pConfig ) +{ + if ( pConfig->m_bIsFileConfig ) + { + m_XMLWriter.PushNode( "FileConfiguration" ); + } + else + { + m_XMLWriter.PushNode( "Configuration" ); + } + + const char *pOutputName = "???"; + if ( !V_stricmp( pConfig->m_Name.Get(), "debug" ) ) + { + pOutputName = "Debug|Xbox 360"; + } + else if ( !V_stricmp( pConfig->m_Name.Get(), "release" ) ) + { + pOutputName = "Release|Xbox 360"; + } + else + { + return false; + } + + m_XMLWriter.Write( CFmtStrMax( "Name=\"%s\"", pOutputName ) ); + + // write configuration properties + for ( int i = 0; i < pConfig->m_PropertyStates.m_PropertiesInOutputOrder.Count(); i++ ) + { + int sortedIndex = pConfig->m_PropertyStates.m_PropertiesInOutputOrder[i]; + WriteProperty( &pConfig->m_PropertyStates.m_Properties[sortedIndex] ); + } + + if ( !pConfig->m_bIsFileConfig && pConfig->m_PropertyStates.m_Properties.Count() ) + { + WriteProperty( NULL, "UseOfMFC", "-1" ); + WriteProperty( NULL, "UseOfATL", "0" ); + } + + m_XMLWriter.Write( ">" ); + + if ( !WriteTool( "VCPreBuildEventTool", pConfig->GetPreBuildEventTool() ) ) + return false; + + if ( !WriteTool( "VCCustomBuildTool", pConfig->GetCustomBuildTool() ) ) + return false; + + if ( !WriteNULLTool( "VCXMLDataGeneratorTool", pConfig ) ) + return false; + + if ( !WriteNULLTool( "VCWebServiceProxyGeneratorTool", pConfig ) ) + return false; + + if ( !WriteNULLTool( "VCMIDLTool", pConfig ) ) + return false; + + if ( !WriteTool( "VCCLX360CompilerTool", pConfig->GetCompilerTool() ) ) + return false; + + if ( !WriteNULLTool( "VCManagedResourceCompilerTool", pConfig ) ) + return false; + + if ( !WriteNULLTool( "VCResourceCompilerTool", pConfig ) ) + return false; + + if ( !WriteTool( "VCPreLinkEventTool", pConfig->GetPreLinkEventTool() ) ) + return false; + + if ( !WriteTool( "VCX360LinkerTool", pConfig->GetLinkerTool() ) ) + return false; + + if ( !WriteTool( "VCLibrarianTool", pConfig->GetLibrarianTool() ) ) + return false; + + if ( !WriteNULLTool( "VCALinkTool", pConfig ) ) + return false; + + if ( !WriteTool( "VCX360ImageTool", pConfig->GetXboxImageTool() ) ) + return false; + + if ( !WriteTool( "VCBscMakeTool", pConfig->GetBrowseInfoTool() ) ) + return false; + + if ( !WriteTool( "VCX360DeploymentTool", pConfig->GetXboxDeploymentTool() ) ) + return false; + + if ( !WriteTool( "VCPostBuildEventTool", pConfig->GetPostBuildEventTool() ) ) + return false; + + if ( !pConfig->m_bIsFileConfig ) + { + m_XMLWriter.PushNode( "DebuggerTool" ); + m_XMLWriter.PopNode( false ); + } + + m_XMLWriter.PopNode( true ); + + return true; +} + +bool CProjectGenerator_Xbox360::WriteToXML() +{ + m_XMLWriter.PushNode( "VisualStudioProject" ); + m_XMLWriter.Write( "ProjectType=\"Visual C++\"" ); + + if ( g_pVPC->BUse2008() ) + m_XMLWriter.Write( "Version=\"9.00\"" ); + else + m_XMLWriter.Write( "Version=\"8.00\"" ); + + m_XMLWriter.Write( CFmtStrMax( "Name=\"%s\"", m_pVCProjGenerator->GetProjectName().Get() ) ); + m_XMLWriter.Write( CFmtStrMax( "ProjectGUID=\"%s\"", m_pVCProjGenerator->GetGUIDString().Get() ) ); + m_XMLWriter.Write( ">" ); + + m_XMLWriter.PushNode( "Platforms" ); + m_XMLWriter.PushNode( "Platform" ); + m_XMLWriter.Write( "Name=\"Xbox 360\"" ); + m_XMLWriter.PopNode( false ); + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PushNode( "ToolFiles" ); + m_XMLWriter.PopNode( true ); + + CUtlVector< CUtlString > configurationNames; + m_pVCProjGenerator->GetAllConfigurationNames( configurationNames ); + + // write the root configurations + m_XMLWriter.PushNode( "Configurations" ); + for ( int i = 0; i < configurationNames.Count(); i++ ) + { + CProjectConfiguration *pConfiguration = NULL; + if ( m_pVCProjGenerator->GetRootConfiguration( configurationNames[i].Get(), &pConfiguration ) ) + { + if ( !WriteConfiguration( pConfiguration ) ) + return false; + } + } + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PushNode( "References" ); + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PushNode( "Files" ); + + CProjectFolder *pRootFolder = m_pVCProjGenerator->GetRootFolder(); + + for ( int iIndex = pRootFolder->m_Folders.Head(); iIndex != pRootFolder->m_Folders.InvalidIndex(); iIndex = pRootFolder->m_Folders.Next( iIndex ) ) + { + if ( !WriteFolder( pRootFolder->m_Folders[iIndex] ) ) + return false; + } + + for ( int iIndex = pRootFolder->m_Files.Head(); iIndex != pRootFolder->m_Files.InvalidIndex(); iIndex = pRootFolder->m_Files.Next( iIndex ) ) + { + if ( !WriteFile( pRootFolder->m_Files[iIndex] ) ) + return false; + } + + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PopNode( true ); + + return true; +} + +bool CProjectGenerator_Xbox360::Save( const char *pOutputFilename ) +{ + if ( !m_XMLWriter.Open( pOutputFilename ) ) + return false; + + bool bValid = WriteToXML(); + + m_XMLWriter.Close(); + + return bValid; +} + +bool CProjectGenerator_Xbox360::WriteNULLTool( const char *pToolName, const CProjectConfiguration *pConfig ) +{ + if ( pConfig->m_bIsFileConfig ) + return true; + + m_XMLWriter.PushNode( "Tool" ); + + m_XMLWriter.Write( CFmtStr( "Name=\"%s\"", pToolName ) ); + + m_XMLWriter.PopNode( false ); + + return true; +} + +bool CProjectGenerator_Xbox360::WriteTool( const char *pToolName, const CProjectTool *pProjectTool ) +{ + if ( !pProjectTool ) + { + // not an error, some tools n/a for a config + return true; + } + + m_XMLWriter.PushNode( "Tool" ); + + m_XMLWriter.Write( CFmtStr( "Name=\"%s\"", pToolName ) ); + + for ( int i = 0; i < pProjectTool->m_PropertyStates.m_PropertiesInOutputOrder.Count(); i++ ) + { + int sortedIndex = pProjectTool->m_PropertyStates.m_PropertiesInOutputOrder[i]; + WriteProperty( &pProjectTool->m_PropertyStates.m_Properties[sortedIndex] ); + } + + m_XMLWriter.PopNode( false ); + + return true; +} + +bool CProjectGenerator_Xbox360::WriteProperty( const PropertyState_t *pPropertyState, const char *pOutputName, const char *pOutputValue ) +{ + if ( !pPropertyState ) + { + m_XMLWriter.Write( CFmtStrMax( "%s=\"%s\"", pOutputName, pOutputValue ) ); + return true; + } + + if ( !pOutputName ) + { + pOutputName = pPropertyState->m_pToolProperty->m_OutputString.Get(); + if ( !pOutputName[0] ) + { + pOutputName = pPropertyState->m_pToolProperty->m_ParseString.Get(); + if ( pOutputName[0] == '$' ) + { + pOutputName++; + } + } + } + + if ( pPropertyState ) + { + switch ( pPropertyState->m_pToolProperty->m_nType ) + { + case PT_BOOLEAN: + { + bool bEnabled = Sys_StringToBool( pPropertyState->m_StringValue.Get() ); + if ( pPropertyState->m_pToolProperty->m_bInvertOutput ) + { + bEnabled ^= 1; + } + m_XMLWriter.Write( CFmtStrMax( "%s=\"%s\"", pOutputName, bEnabled ? "true" : "false" ) ); + } + break; + + case PT_STRING: + m_XMLWriter.Write( CFmtStrMax( "%s=\"%s\"", pOutputName, m_XMLWriter.FixupXMLString( pPropertyState->m_StringValue.Get() ) ) ); + break; + + case PT_LIST: + case PT_INTEGER: + m_XMLWriter.Write( CFmtStrMax( "%s=\"%s\"", pOutputName, pPropertyState->m_StringValue.Get() ) ); + break; + + case PT_IGNORE: + break; + + default: + g_pVPC->VPCError( "CProjectGenerator_Xbox360: WriteProperty, %s - not implemented", pOutputName ); + } + } + + return true; +} diff --git a/external/vpc/utils/vpc/projectgenerator_xbox360.h b/external/vpc/utils/vpc/projectgenerator_xbox360.h new file mode 100644 index 0000000..78f4ece --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_xbox360.h @@ -0,0 +1,41 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef PROJECTGENERATOR_XBOX360_H +#define PROJECTGENERATOR_XBOX360_H +#ifdef _WIN32 +#pragma once +#endif + +#define PROPERTYNAME( X, Y ) X##_##Y, +enum Xbox360Properties_e +{ + #include "projectgenerator_xbox360.inc" +}; + +class CProjectGenerator_Xbox360 : public IVCProjWriter +{ +public: + CProjectGenerator_Xbox360(); + IBaseProjectGenerator *GetProjectGenerator() { return m_pVCProjGenerator; } + + virtual bool Save( const char *pOutputFilename ); + +private: + bool WriteToXML(); + + bool WriteFolder( CProjectFolder *pFolder ); + bool WriteFile( CProjectFile *pFile ); + bool WriteConfiguration( CProjectConfiguration *pConfig ); + bool WriteProperty( const PropertyState_t *pPropertyState, const char *pOutputName = NULL, const char *pValue = NULL ); + bool WriteTool( const char *pToolName, const CProjectTool *pProjectTool ); + bool WriteNULLTool( const char *pToolName, const CProjectConfiguration *pConfig ); + + CXMLWriter m_XMLWriter; + CVCProjGenerator *m_pVCProjGenerator; +}; + +#endif // PROJECTGENERATOR_XBOX360_H diff --git a/external/vpc/utils/vpc/projectgenerator_xbox360.inc b/external/vpc/utils/vpc/projectgenerator_xbox360.inc new file mode 100644 index 0000000..4a18aca --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_xbox360.inc @@ -0,0 +1,192 @@ + +//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Property Enumerations +// +//=====================================================================================// + +// Config +PROPERTYNAME( XBOX360_GENERAL, ExcludedFromBuild ) +PROPERTYNAME( XBOX360_GENERAL, OutputDirectory ) +PROPERTYNAME( XBOX360_GENERAL, IntermediateDirectory ) +PROPERTYNAME( XBOX360_GENERAL, ConfigurationType ) +PROPERTYNAME( XBOX360_GENERAL, CharacterSet ) +PROPERTYNAME( XBOX360_GENERAL, WholeProgramOptimization ) +PROPERTYNAME( XBOX360_GENERAL, ExtensionsToDeleteOnClean ) +PROPERTYNAME( XBOX360_GENERAL, BuildLogFile ) +PROPERTYNAME( XBOX360_GENERAL, InheritedProjectPropertySheets ) + +// Debugging +PROPERTYNAME( XBOX360_DEBUGGING, Command ) +PROPERTYNAME( XBOX360_DEBUGGING, CommandArguments ) +PROPERTYNAME( XBOX360_DEBUGGING, RemoteMachine ) + +// Compiler +PROPERTYNAME( XBOX360_COMPILER, AdditionalOptions ) +PROPERTYNAME( XBOX360_COMPILER, Optimization ) +PROPERTYNAME( XBOX360_COMPILER, InlineFunctionExpansion ) +PROPERTYNAME( XBOX360_COMPILER, EnableIntrinsicFunctions ) +PROPERTYNAME( XBOX360_COMPILER, FavorSizeOrSpeed ) +PROPERTYNAME( XBOX360_COMPILER, EnableFiberSafeOptimizations ) +PROPERTYNAME( XBOX360_COMPILER, WholeProgramOptimization ) +PROPERTYNAME( XBOX360_COMPILER, AdditionalIncludeDirectories ) +PROPERTYNAME( XBOX360_COMPILER, PreprocessorDefinitions ) +PROPERTYNAME( XBOX360_COMPILER, IgnoreStandardIncludePath ) +PROPERTYNAME( XBOX360_COMPILER, GeneratePreprocessedFile ) +PROPERTYNAME( XBOX360_COMPILER, KeepComments ) +PROPERTYNAME( XBOX360_COMPILER, EnableStringPooling ) +PROPERTYNAME( XBOX360_COMPILER, EnableMinimalRebuild ) +PROPERTYNAME( XBOX360_COMPILER, EnableCPPExceptions ) +PROPERTYNAME( XBOX360_COMPILER, BasicRuntimeChecks ) +PROPERTYNAME( XBOX360_COMPILER, SmallerTypeCheck ) +PROPERTYNAME( XBOX360_COMPILER, RuntimeLibrary ) +PROPERTYNAME( XBOX360_COMPILER, StructMemberAlignment ) +PROPERTYNAME( XBOX360_COMPILER, BufferSecurityCheck ) +PROPERTYNAME( XBOX360_COMPILER, EnableFunctionLevelLinking ) +PROPERTYNAME( XBOX360_COMPILER, FloatingPointModel ) +PROPERTYNAME( XBOX360_COMPILER, EnableFloatingPointExceptions ) +PROPERTYNAME( XBOX360_COMPILER, DisableLanguageExtensions ) +PROPERTYNAME( XBOX360_COMPILER, DefaultCharUnsigned ) +PROPERTYNAME( XBOX360_COMPILER, TreatWCHAR_TAsBuiltInType ) +PROPERTYNAME( XBOX360_COMPILER, ForceConformanceInForLoopScope ) +PROPERTYNAME( XBOX360_COMPILER, EnableRunTimeTypeInfo ) +PROPERTYNAME( XBOX360_COMPILER, OpenMPSupport ) +PROPERTYNAME( XBOX360_COMPILER, CreateUsePrecompiledHeader ) +PROPERTYNAME( XBOX360_COMPILER, CreateUsePCHThroughFile ) +PROPERTYNAME( XBOX360_COMPILER, PrecompiledHeaderFile ) +PROPERTYNAME( XBOX360_COMPILER, ExpandAttributedSource ) +PROPERTYNAME( XBOX360_COMPILER, AssemblerOutput ) +PROPERTYNAME( XBOX360_COMPILER, ASMListLocation ) +PROPERTYNAME( XBOX360_COMPILER, ObjectFileName ) +PROPERTYNAME( XBOX360_COMPILER, ProgramDatabaseFileName ) +PROPERTYNAME( XBOX360_COMPILER, EnableBrowseInformation ) +PROPERTYNAME( XBOX360_COMPILER, BrowseFile ) +PROPERTYNAME( XBOX360_COMPILER, WarningLevel ) +PROPERTYNAME( XBOX360_COMPILER, TreatWarningsAsErrors ) +PROPERTYNAME( XBOX360_COMPILER, SuppressStartupBanner ) +PROPERTYNAME( XBOX360_COMPILER, DebugInformationFormat ) +PROPERTYNAME( XBOX360_COMPILER, CompileAs ) +PROPERTYNAME( XBOX360_COMPILER, ForceIncludes ) +PROPERTYNAME( XBOX360_COMPILER, ShowIncludes ) +PROPERTYNAME( XBOX360_COMPILER, UndefineAllPreprocessorDefinitions ) +PROPERTYNAME( XBOX360_COMPILER, UndefinePreprocessorDefinitions ) +PROPERTYNAME( XBOX360_COMPILER, UseFullPaths ) +PROPERTYNAME( XBOX360_COMPILER, OmitDefaultLibraryNames ) +PROPERTYNAME( XBOX360_COMPILER, TrapIntegerDividesOptimization ) +PROPERTYNAME( XBOX360_COMPILER, PreschedulingOptimization ) +PROPERTYNAME( XBOX360_COMPILER, InlineAssemblyOptimization ) +PROPERTYNAME( XBOX360_COMPILER, RegisterReservation ) +PROPERTYNAME( XBOX360_COMPILER, Stalls ) +PROPERTYNAME( XBOX360_COMPILER, CallAttributedProfiling ) +PROPERTYNAME( XBOX360_COMPILER, UseUNICODEResponseFiles ) +PROPERTYNAME( XBOX360_COMPILER, GenerateXMLDocumentationFiles ) +PROPERTYNAME( XBOX360_COMPILER, XMLDocumentationFileName ) +PROPERTYNAME( XBOX360_COMPILER, DisableSpecificWarnings ) + +// Librarian +PROPERTYNAME( XBOX360_LIBRARIAN, OutputFile ) +PROPERTYNAME( XBOX360_LIBRARIAN, AdditionalDependencies ) +PROPERTYNAME( XBOX360_LIBRARIAN, AdditionalLibraryDirectories ) +PROPERTYNAME( XBOX360_LIBRARIAN, SuppressStartupBanner ) +PROPERTYNAME( XBOX360_LIBRARIAN, ModuleDefinitionFileName ) +PROPERTYNAME( XBOX360_LIBRARIAN, IgnoreAllDefaultLibraries ) +PROPERTYNAME( XBOX360_LIBRARIAN, IgnoreSpecificLibrary ) +PROPERTYNAME( XBOX360_LIBRARIAN, ExportNamedFunctions ) +PROPERTYNAME( XBOX360_LIBRARIAN, ForceSymbolReferences ) +PROPERTYNAME( XBOX360_LIBRARIAN, UseUNICODEResponseFiles ) +PROPERTYNAME( XBOX360_LIBRARIAN, LinkLibraryDependencies ) +PROPERTYNAME( XBOX360_LIBRARIAN, AdditionalOptions ) + +// Linker +PROPERTYNAME( XBOX360_LINKER, IgnoreImportLibrary ) +PROPERTYNAME( XBOX360_LINKER, AdditionalOptions ) +PROPERTYNAME( XBOX360_LINKER, AdditionalDependencies ) +PROPERTYNAME( XBOX360_LINKER, ShowProgress ) +PROPERTYNAME( XBOX360_LINKER, OutputFile ) +PROPERTYNAME( XBOX360_LINKER, EnableIncrementalLinking ) +PROPERTYNAME( XBOX360_LINKER, SuppressStartupBanner ) +PROPERTYNAME( XBOX360_LINKER, AdditionalLibraryDirectories ) +PROPERTYNAME( XBOX360_LINKER, IgnoreAllDefaultLibraries ) +PROPERTYNAME( XBOX360_LINKER, IgnoreSpecificLibrary ) +PROPERTYNAME( XBOX360_LINKER, ModuleDefinitionFile ) +PROPERTYNAME( XBOX360_LINKER, GenerateDebugInfo ) +PROPERTYNAME( XBOX360_LINKER, GenerateProgramDatabaseFile ) +PROPERTYNAME( XBOX360_LINKER, GenerateMapFile ) +PROPERTYNAME( XBOX360_LINKER, MapFileName ) +PROPERTYNAME( XBOX360_LINKER, MapExports ) +PROPERTYNAME( XBOX360_LINKER, StackReserveSize ) +PROPERTYNAME( XBOX360_LINKER, StackCommitSize ) +PROPERTYNAME( XBOX360_LINKER, References ) +PROPERTYNAME( XBOX360_LINKER, EnableCOMDATFolding ) +PROPERTYNAME( XBOX360_LINKER, LinkTimeCodeGeneration ) +PROPERTYNAME( XBOX360_LINKER, EntryPoint ) +PROPERTYNAME( XBOX360_LINKER, NoEntryPoint ) +PROPERTYNAME( XBOX360_LINKER, SetChecksum ) +PROPERTYNAME( XBOX360_LINKER, BaseAddress ) +PROPERTYNAME( XBOX360_LINKER, ImportLibrary ) +PROPERTYNAME( XBOX360_LINKER, FixedBaseAddress ) +PROPERTYNAME( XBOX360_LINKER, ErrorReporting ) +PROPERTYNAME( XBOX360_LINKER, FunctionOrder ) +PROPERTYNAME( XBOX360_LINKER, Version ) +PROPERTYNAME( XBOX360_LINKER, LinkLibraryDependencies ) +PROPERTYNAME( XBOX360_LINKER, UseLibraryDependencyInputs ) +PROPERTYNAME( XBOX360_LINKER, UseUNICODEResponseFiles ) +PROPERTYNAME( XBOX360_LINKER, ForceSymbolReferences ) +PROPERTYNAME( XBOX360_LINKER, StripPrivateSymbols ) +PROPERTYNAME( XBOX360_LINKER, ProfileGuidedDatabase ) +PROPERTYNAME( XBOX360_LINKER, MergeSections ) + +// Browse Information +PROPERTYNAME( XBOX360_BROWSEINFORMATION, SuppressStartupBanner ) +PROPERTYNAME( XBOX360_BROWSEINFORMATION, OutputFile ) +PROPERTYNAME( XBOX360_BROWSEINFORMATION, AdditionalOptions ) + +// Pre Build +PROPERTYNAME( XBOX360_PREBUILDEVENT, Description ) +PROPERTYNAME( XBOX360_PREBUILDEVENT, CommandLine ) +PROPERTYNAME( XBOX360_PREBUILDEVENT, ExcludedFromBuild ) + +// Pre Link +PROPERTYNAME( XBOX360_PRELINKEVENT, Description ) +PROPERTYNAME( XBOX360_PRELINKEVENT, CommandLine ) +PROPERTYNAME( XBOX360_PRELINKEVENT, ExcludedFromBuild ) + +// Post Build +PROPERTYNAME( XBOX360_POSTBUILDEVENT, Description ) +PROPERTYNAME( XBOX360_POSTBUILDEVENT, CommandLine ) +PROPERTYNAME( XBOX360_POSTBUILDEVENT, ExcludedFromBuild ) + +// Custom Build +PROPERTYNAME( XBOX360_CUSTOMBUILDSTEP, Description ) +PROPERTYNAME( XBOX360_CUSTOMBUILDSTEP, CommandLine ) +PROPERTYNAME( XBOX360_CUSTOMBUILDSTEP, Outputs ) +PROPERTYNAME( XBOX360_CUSTOMBUILDSTEP, AdditionalDependencies ) + +// Image Conversion +PROPERTYNAME( XBOX360_XBOX360IMAGECONVERSION, OutputFile ) +PROPERTYNAME( XBOX360_XBOX360IMAGECONVERSION, SuppressStartupBanner ) +PROPERTYNAME( XBOX360_XBOX360IMAGECONVERSION, ProjectDefaults ) +PROPERTYNAME( XBOX360_XBOX360IMAGECONVERSION, WorkspaceSize ) +PROPERTYNAME( XBOX360_XBOX360IMAGECONVERSION, ExportByName ) +PROPERTYNAME( XBOX360_XBOX360IMAGECONVERSION, OpticalDiscDriveMapping ) +PROPERTYNAME( XBOX360_XBOX360IMAGECONVERSION, PAL50Incompatible ) +PROPERTYNAME( XBOX360_XBOX360IMAGECONVERSION, TitleID ) +PROPERTYNAME( XBOX360_XBOX360IMAGECONVERSION, LANKey ) +PROPERTYNAME( XBOX360_XBOX360IMAGECONVERSION, BaseAddress ) +PROPERTYNAME( XBOX360_XBOX360IMAGECONVERSION, HeapSize ) +PROPERTYNAME( XBOX360_XBOX360IMAGECONVERSION, AdditionalSections ) +PROPERTYNAME( XBOX360_XBOX360IMAGECONVERSION, AdditionalOptions ) + +// Console Deployment +PROPERTYNAME( XBOX360_CONSOLEDEPLOYMENT, ExcludedFromBuild ) +PROPERTYNAME( XBOX360_CONSOLEDEPLOYMENT, SuppressStartupBanner ) +PROPERTYNAME( XBOX360_CONSOLEDEPLOYMENT, DeploymentRoot ) +PROPERTYNAME( XBOX360_CONSOLEDEPLOYMENT, DeploymentFiles ) +PROPERTYNAME( XBOX360_CONSOLEDEPLOYMENT, Progress ) +PROPERTYNAME( XBOX360_CONSOLEDEPLOYMENT, ForceCopy ) +PROPERTYNAME( XBOX360_CONSOLEDEPLOYMENT, DeploymentType ) +PROPERTYNAME( XBOX360_CONSOLEDEPLOYMENT, EmulationType ) +PROPERTYNAME( XBOX360_CONSOLEDEPLOYMENT, Layout ) +PROPERTYNAME( XBOX360_CONSOLEDEPLOYMENT, LayoutRoot ) +PROPERTYNAME( XBOX360_CONSOLEDEPLOYMENT, AdditionalOptions ) + diff --git a/external/vpc/utils/vpc/projectgenerator_xbox360_2010.cpp b/external/vpc/utils/vpc/projectgenerator_xbox360_2010.cpp new file mode 100644 index 0000000..285285c --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_xbox360_2010.cpp @@ -0,0 +1,596 @@ +//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: VPC +// +//=====================================================================================// + +#include "vpc.h" + +#undef PROPERTYNAME +#define PROPERTYNAME( X, Y ) { X##_##Y, #X, #Y }, +static PropertyName_t s_Xbox360PropertyNames_2010[] = +{ + #include "projectgenerator_xbox360_2010.inc" + { -1, NULL, NULL } +}; + +IBaseProjectGenerator* GetXbox360ProjectGenerator_2010() +{ + static CProjectGenerator_Xbox360_2010 *s_pProjectGenerator = NULL; + if ( !s_pProjectGenerator ) + { + s_pProjectGenerator = new CProjectGenerator_Xbox360_2010(); + } + + return s_pProjectGenerator->GetProjectGenerator(); +} + +CProjectGenerator_Xbox360_2010::CProjectGenerator_Xbox360_2010() +{ + m_pVCProjGenerator = new CVCProjGenerator(); + m_pVCProjGenerator->SetupGeneratorDefinition( this, "xbox360_2010.def", s_Xbox360PropertyNames_2010 ); +} + +enum TypeKeyNames_e +{ + TKN_LIBRARY = 0, + TKN_INCLUDE, + TKN_COMPILE, + TKN_RESOURCECOMPILE, + TKN_CUSTOMBUILD, + TKN_NONE, + TKN_MAX_COUNT, +}; + +static const char *s_TypeKeyNames[] = +{ + "Library", + "ClInclude", + "ClCompile", + "ResourceCompile", + "CustomBuild", + "None" +}; + +const char *CProjectGenerator_Xbox360_2010::GetKeyNameForFile( CProjectFile *pFile ) +{ + COMPILE_TIME_ASSERT( ARRAYSIZE( s_TypeKeyNames ) == TKN_MAX_COUNT ); + + const char *pExtension = V_GetFileExtension( pFile->m_Name.Get() ); + + const char *pKeyName = s_TypeKeyNames[TKN_NONE]; + if ( pExtension ) + { + if ( pFile->m_Configs.Count() && pFile->m_Configs[0]->GetCustomBuildTool() ) + { + pKeyName = s_TypeKeyNames[TKN_CUSTOMBUILD]; + } + else if ( IsCFileExtension( pExtension ) ) + { + pKeyName = s_TypeKeyNames[TKN_COMPILE]; + } + else if ( IsHFileExtension( pExtension ) ) + { + pKeyName = s_TypeKeyNames[TKN_INCLUDE]; + } + else if ( !V_stricmp( pExtension, "lib" ) ) + { + pKeyName = s_TypeKeyNames[TKN_LIBRARY]; + } + else if ( !V_stricmp( pExtension, "rc" ) ) + { + pKeyName = s_TypeKeyNames[TKN_RESOURCECOMPILE]; + } + } + + return pKeyName; +} + +bool CProjectGenerator_Xbox360_2010::WritePropertyGroupTool( CProjectTool *pProjectTool, CProjectConfiguration *pConfiguration ) +{ + if ( !pProjectTool ) + return true; + + for ( int i = 0; i < pProjectTool->m_PropertyStates.m_PropertiesInOutputOrder.Count(); i++ ) + { + int sortedIndex = pProjectTool->m_PropertyStates.m_PropertiesInOutputOrder[i]; + if ( !pProjectTool->m_PropertyStates.m_Properties[sortedIndex].m_pToolProperty->m_bEmitAsGlobalProperty ) + continue; + + if ( !WriteProperty( &pProjectTool->m_PropertyStates.m_Properties[sortedIndex], true, pConfiguration->m_Name.Get() ) ) + return false; + } + + return true; +} + +bool CProjectGenerator_Xbox360_2010::WriteFile( CProjectFile *pFile, const char *pFileTypeName ) +{ + const char *pKeyName = GetKeyNameForFile( pFile ); + if ( V_stricmp( pFileTypeName, pKeyName ) ) + { + // skip it + return true; + } + + if ( !pFile->m_Configs.Count() ) + { + m_XMLWriter.Write( CFmtStrMax( "<%s Include=\"%s\" />", pKeyName, pFile->m_Name.Get() ) ); + } + else + { + m_XMLWriter.PushNode( pKeyName, CFmtStr( "Include=\"%s\"", pFile->m_Name.Get() ) ); + + for ( int i = 0; i < pFile->m_Configs.Count(); i++ ) + { + if ( !WriteConfiguration( pFile->m_Configs[i] ) ) + return false; + } + + m_XMLWriter.PopNode( true ); + } + + return true; +} + +bool CProjectGenerator_Xbox360_2010::WriteFolder( CProjectFolder *pFolder, const char *pFileTypeName, int nDepth ) +{ + if ( !nDepth ) + { + m_XMLWriter.PushNode( "ItemGroup" ); + } + + for ( int iIndex = pFolder->m_Files.Head(); iIndex != pFolder->m_Files.InvalidIndex(); iIndex = pFolder->m_Files.Next( iIndex ) ) + { + if ( !WriteFile( pFolder->m_Files[iIndex], pFileTypeName ) ) + return false; + } + + for ( int iIndex = pFolder->m_Folders.Head(); iIndex != pFolder->m_Folders.InvalidIndex(); iIndex = pFolder->m_Folders.Next( iIndex ) ) + { + if ( !WriteFolder( pFolder->m_Folders[iIndex], pFileTypeName, nDepth+1 ) ) + return false; + } + + if ( !nDepth ) + { + m_XMLWriter.PopNode( true ); + } + + return true; +} + +bool CProjectGenerator_Xbox360_2010::WriteConfiguration( CProjectConfiguration *pConfig ) +{ + if ( !pConfig->m_bIsFileConfig ) + { + m_XMLWriter.PushNode( "PropertyGroup", CFmtStr( "Condition=\"'$(Configuration)|$(Platform)'=='%s|Xbox 360'\" Label=\"Configuration\"", pConfig->m_Name.Get() ) ); + + for ( int i = 0; i < pConfig->m_PropertyStates.m_PropertiesInOutputOrder.Count(); i++ ) + { + int sortedIndex = pConfig->m_PropertyStates.m_PropertiesInOutputOrder[i]; + if ( pConfig->m_PropertyStates.m_Properties[sortedIndex].m_pToolProperty->m_bEmitAsGlobalProperty ) + continue; + + if ( !WriteProperty( &pConfig->m_PropertyStates.m_Properties[sortedIndex] ) ) + return false; + } + + WriteProperty( NULL, false, NULL, "UseOfAtl", "false" ); + + m_XMLWriter.PopNode( true ); + } + else + { + for ( int i = 0; i < pConfig->m_PropertyStates.m_PropertiesInOutputOrder.Count(); i++ ) + { + int sortedIndex = pConfig->m_PropertyStates.m_PropertiesInOutputOrder[i]; + if ( !WriteProperty( &pConfig->m_PropertyStates.m_Properties[sortedIndex], true, pConfig->m_Name.Get() ) ) + return false; + } + + if ( !WriteTool( "ClCompile", pConfig->GetCompilerTool(), pConfig ) ) + return false; + + if ( !WriteTool( "CustomBuildStep", pConfig->GetCustomBuildTool(), pConfig ) ) + return false; + } + + return true; +} + +bool CProjectGenerator_Xbox360_2010::WriteTools( CProjectConfiguration *pConfig ) +{ + m_XMLWriter.PushNode( "ItemDefinitionGroup", CFmtStr( "Condition=\"'$(Configuration)|$(Platform)'=='%s|Xbox 360'\"", pConfig->m_Name.Get() ) ); + + if ( !WriteTool( "PreBuildEvent", pConfig->GetPreBuildEventTool(), pConfig ) ) + return false; + + if ( !WriteTool( "CustomBuildStep", pConfig->GetCustomBuildTool(), pConfig ) ) + return false; + + if ( !WriteTool( "ClCompile", pConfig->GetCompilerTool(), pConfig ) ) + return false; + + if ( !WriteTool( "PreLinkEvent", pConfig->GetPreLinkEventTool(), pConfig ) ) + return false; + + if ( !WriteTool( "Link", pConfig->GetLinkerTool(), pConfig ) ) + return false; + + if ( !WriteTool( "Lib", pConfig->GetLibrarianTool(), pConfig ) ) + return false; + + if ( !WriteTool( "ImageXex", pConfig->GetXboxImageTool(), pConfig ) ) + return false; + + if ( !WriteTool( "Bscmake", pConfig->GetBrowseInfoTool(), pConfig ) ) + return false; + + if ( !WriteTool( "Deploy", pConfig->GetXboxDeploymentTool(), pConfig ) ) + return false; + + if ( !WriteTool( "PostBuildEvent", pConfig->GetPostBuildEventTool(), pConfig ) ) + return false; + + m_XMLWriter.PopNode( true ); + + return true; +} + +bool CProjectGenerator_Xbox360_2010::WritePrimaryXML( const char *pOutputFilename ) +{ + if ( !m_XMLWriter.Open( pOutputFilename, true ) ) + return false; + + m_XMLWriter.PushNode( "Project", "DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\"" ); + + m_XMLWriter.PushNode( "ItemGroup", "Label=\"ProjectConfigurations\"" ); + CUtlVector< CUtlString > configurationNames; + m_pVCProjGenerator->GetAllConfigurationNames( configurationNames ); + for ( int i = 0; i < configurationNames.Count(); i++ ) + { + m_XMLWriter.PushNode( "ProjectConfiguration", CFmtStr( "Include=\"%s|Xbox 360\"", configurationNames[i].Get() ) ); + m_XMLWriter.WriteLineNode( "Configuration", "", configurationNames[i].Get() ); + m_XMLWriter.WriteLineNode( "Platform", "", "Xbox 360" ); + m_XMLWriter.PopNode( true ); + } + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PushNode( "PropertyGroup", "Label=\"Globals\"" ); + m_XMLWriter.WriteLineNode( "ProjectName", "", m_pVCProjGenerator->GetProjectName().Get() ); + m_XMLWriter.WriteLineNode( "ProjectGuid", "", m_pVCProjGenerator->GetGUIDString().Get() ); + m_XMLWriter.PopNode( true ); + + m_XMLWriter.Write( "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />" ); + + // write the root configurations + for ( int i = 0; i < configurationNames.Count(); i++ ) + { + CProjectConfiguration *pConfiguration = NULL; + if ( m_pVCProjGenerator->GetRootConfiguration( configurationNames[i].Get(), &pConfiguration ) ) + { + if ( !WriteConfiguration( pConfiguration ) ) + return false; + } + } + + m_XMLWriter.Write( "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />" ); + m_XMLWriter.PushNode( "ImportGroup", "Label=\"ExtensionSettings\"" ); + m_XMLWriter.PopNode( true ); + + for ( int i = 0; i < configurationNames.Count(); i++ ) + { + m_XMLWriter.PushNode( "ImportGroup", CFmtStr( "Condition=\"'$(Configuration)|$(Platform)'=='%s|Xbox 360'\" Label=\"PropertySheets\"", configurationNames[i].Get() ) ); + m_XMLWriter.Write( "<Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />" ); + m_XMLWriter.PopNode( true ); + } + + m_XMLWriter.Write( "<PropertyGroup Label=\"UserMacros\" />" ); + + m_XMLWriter.PushNode( "PropertyGroup" ); + m_XMLWriter.WriteLineNode( "_ProjectFileVersion", "", "10.0.30319.1" ); + for ( int i = 0; i < configurationNames.Count(); i++ ) + { + CProjectConfiguration *pConfiguration = NULL; + if ( m_pVCProjGenerator->GetRootConfiguration( configurationNames[i].Get(), &pConfiguration ) ) + { + for ( int j = 0; j < pConfiguration->m_PropertyStates.m_PropertiesInOutputOrder.Count(); j++ ) + { + int sortedIndex = pConfiguration->m_PropertyStates.m_PropertiesInOutputOrder[j]; + if ( !pConfiguration->m_PropertyStates.m_Properties[sortedIndex].m_pToolProperty->m_bEmitAsGlobalProperty ) + continue; + + if ( !WriteProperty( &pConfiguration->m_PropertyStates.m_Properties[sortedIndex], true, pConfiguration->m_Name.Get() ) ) + return false; + } + + if ( !WritePropertyGroupTool( pConfiguration->GetPreBuildEventTool(), pConfiguration ) ) + return false; + + if ( !WritePropertyGroupTool( pConfiguration->GetPreLinkEventTool(), pConfiguration ) ) + return false; + + if ( !WritePropertyGroupTool( pConfiguration->GetLinkerTool(), pConfiguration ) ) + return false; + + if ( !WritePropertyGroupTool( pConfiguration->GetLibrarianTool(), pConfiguration ) ) + return false; + + if ( !WritePropertyGroupTool( pConfiguration->GetPostBuildEventTool(), pConfiguration ) ) + return false; + + if ( !WritePropertyGroupTool( pConfiguration->GetXboxImageTool(), pConfiguration ) ) + return false; + + if ( !WritePropertyGroupTool( pConfiguration->GetXboxDeploymentTool(), pConfiguration ) ) + return false; + } + } + m_XMLWriter.PopNode( true ); + + // write the tool configurations + for ( int i = 0; i < configurationNames.Count(); i++ ) + { + CProjectConfiguration *pConfiguration = NULL; + if ( m_pVCProjGenerator->GetRootConfiguration( configurationNames[i].Get(), &pConfiguration ) ) + { + if ( !WriteTools( pConfiguration ) ) + return false; + } + } + + // write root folders + for ( int i = 0; i < TKN_MAX_COUNT; i++ ) + { + if ( !WriteFolder( m_pVCProjGenerator->GetRootFolder(), s_TypeKeyNames[i], 0 ) ) + return false; + } + + m_XMLWriter.Write( "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />" ); + m_XMLWriter.PushNode( "ImportGroup", "Label=\"ExtensionTargets\"" ); + m_XMLWriter.PopNode( true ); + + m_XMLWriter.PopNode( true ); + + m_XMLWriter.Close(); + + return true; +} + +bool CProjectGenerator_Xbox360_2010::WriteFolderToSecondaryXML( CProjectFolder *pFolder, const char *pParentPath ) +{ + CUtlString parentPath = CFmtStr( "%s%s%s", pParentPath, pParentPath[0] ? "\\" : "", pFolder->m_Name.Get() ); + + MD5Context_t ctx; + unsigned char digest[MD5_DIGEST_LENGTH]; + V_memset( &ctx, 0, sizeof( ctx ) ); + V_memset( digest, 0, sizeof( digest ) ); + MD5Init( &ctx ); + MD5Update( &ctx, (unsigned char *)parentPath.Get(), strlen( parentPath.Get() ) ); + MD5Final( digest, &ctx ); + + char szMD5[64]; + V_binarytohex( digest, MD5_DIGEST_LENGTH, szMD5, sizeof( szMD5 ) ); + V_strupr( szMD5 ); + + char szGUID[MAX_PATH]; + V_snprintf( szGUID, sizeof( szGUID ), "{%8.8s-%4.4s-%4.4s-%4.4s-%12.12s}", szMD5, &szMD5[8], &szMD5[12], &szMD5[16], &szMD5[20] ); + + m_XMLFilterWriter.PushNode( "Filter", CFmtStr( "Include=\"%s\"", parentPath.Get() ) ); + m_XMLFilterWriter.WriteLineNode( "UniqueIdentifier", "", szGUID ); + m_XMLFilterWriter.PopNode( true ); + + for ( int iIndex = pFolder->m_Folders.Head(); iIndex != pFolder->m_Folders.InvalidIndex(); iIndex = pFolder->m_Folders.Next( iIndex ) ) + { + if ( !WriteFolderToSecondaryXML( pFolder->m_Folders[iIndex], parentPath.Get() ) ) + return false; + } + + return true; +} + +bool CProjectGenerator_Xbox360_2010::WriteFileToSecondaryXML( CProjectFile *pFile, const char *pParentPath, const char *pFileTypeName ) +{ + const char *pKeyName = GetKeyNameForFile( pFile ); + if ( V_stricmp( pFileTypeName, pKeyName ) ) + { + // skip it + return true; + } + + if ( pParentPath ) + { + m_XMLFilterWriter.PushNode( pKeyName, CFmtStr( "Include=\"%s\"", pFile->m_Name.Get() ) ); + m_XMLFilterWriter.WriteLineNode( "Filter", "", pParentPath ); + m_XMLFilterWriter.PopNode( true ); + } + else + { + m_XMLFilterWriter.Write( CFmtStr( "<%s Include=\"%s\" />", pKeyName, pFile->m_Name.Get() ) ); + } + + return true; +} + +bool CProjectGenerator_Xbox360_2010::WriteFolderContentsToSecondaryXML( CProjectFolder *pFolder, const char *pParentPath, const char *pFileTypeName, int nDepth ) +{ + CUtlString parentPath; + if ( pParentPath ) + { + parentPath = CFmtStr( "%s%s%s", pParentPath, pParentPath[0] ? "\\" : "", pFolder->m_Name.Get() ); + } + + if ( !nDepth ) + { + m_XMLFilterWriter.PushNode( "ItemGroup", NULL ); + } + + for ( int iIndex = pFolder->m_Files.Head(); iIndex != pFolder->m_Files.InvalidIndex(); iIndex = pFolder->m_Files.Next( iIndex ) ) + { + if ( !WriteFileToSecondaryXML( pFolder->m_Files[iIndex], parentPath.Get(), pFileTypeName ) ) + return false; + } + + for ( int iIndex = pFolder->m_Folders.Head(); iIndex != pFolder->m_Folders.InvalidIndex(); iIndex = pFolder->m_Folders.Next( iIndex ) ) + { + if ( !WriteFolderContentsToSecondaryXML( pFolder->m_Folders[iIndex], parentPath.Get(), pFileTypeName, nDepth+1 ) ) + return false; + } + + if ( !nDepth ) + { + m_XMLFilterWriter.PopNode( true ); + } + + return true; +} + +bool CProjectGenerator_Xbox360_2010::WriteSecondaryXML( const char *pOutputFilename ) +{ + if ( !m_XMLFilterWriter.Open( pOutputFilename, true ) ) + return false; + + m_XMLFilterWriter.PushNode( "Project", "ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\"" ); + + // write the root folders + m_XMLFilterWriter.PushNode( "ItemGroup", NULL ); + CProjectFolder *pRootFolder = m_pVCProjGenerator->GetRootFolder(); + for ( int iIndex = pRootFolder->m_Folders.Head(); iIndex != pRootFolder->m_Folders.InvalidIndex(); iIndex = pRootFolder->m_Folders.Next( iIndex ) ) + { + if ( !WriteFolderToSecondaryXML( pRootFolder->m_Folders[iIndex], "" ) ) + return false; + } + m_XMLFilterWriter.PopNode( true ); + + // write folder contents + for ( int i = 0; i < TKN_MAX_COUNT; i++ ) + { + if ( !WriteFolderContentsToSecondaryXML( pRootFolder, NULL, s_TypeKeyNames[i], 0 ) ) + return false; + } + + m_XMLFilterWriter.PopNode( true ); + + m_XMLFilterWriter.Close(); + + return true; +} + +bool CProjectGenerator_Xbox360_2010::WriteTool( const char *pToolName, const CProjectTool *pProjectTool, CProjectConfiguration *pConfig ) +{ + if ( !pProjectTool ) + { + // not an error, some tools n/a for a config + return true; + } + + if ( !pConfig->m_bIsFileConfig ) + { + m_XMLWriter.PushNode( pToolName, NULL ); + } + + for ( int i = 0; i < pProjectTool->m_PropertyStates.m_PropertiesInOutputOrder.Count(); i++ ) + { + int sortedIndex = pProjectTool->m_PropertyStates.m_PropertiesInOutputOrder[i]; + if ( !pConfig->m_bIsFileConfig ) + { + if ( pProjectTool->m_PropertyStates.m_Properties[sortedIndex].m_pToolProperty->m_bEmitAsGlobalProperty ) + continue; + + if ( !WriteProperty( &pProjectTool->m_PropertyStates.m_Properties[sortedIndex] ) ) + return false; + } + else + { + if ( !WriteProperty( &pProjectTool->m_PropertyStates.m_Properties[sortedIndex], true, pConfig->m_Name.Get() ) ) + return false; + } + } + + if ( !pConfig->m_bIsFileConfig ) + { + m_XMLWriter.PopNode( true ); + } + + return true; +} + +bool CProjectGenerator_Xbox360_2010::WriteProperty( const PropertyState_t *pPropertyState, bool bEmitConfiguration, const char *pConfigName, const char *pOutputName, const char *pOutputValue ) +{ + if ( !pPropertyState ) + { + m_XMLWriter.WriteLineNode( pOutputName, "", pOutputValue ); + return true; + } + + if ( !pOutputName ) + { + pOutputName = pPropertyState->m_pToolProperty->m_OutputString.Get(); + if ( !pOutputName[0] ) + { + pOutputName = pPropertyState->m_pToolProperty->m_ParseString.Get(); + if ( pOutputName[0] == '$' ) + { + pOutputName++; + } + } + } + + const char *pCondition = ""; + CUtlString conditionString; + if ( bEmitConfiguration ) + { + conditionString = CFmtStr( " Condition=\"'$(Configuration)|$(Platform)'=='%s|Xbox 360'\"", pConfigName ); + pCondition = conditionString.Get(); + } + + if ( pPropertyState ) + { + switch ( pPropertyState->m_pToolProperty->m_nType ) + { + case PT_BOOLEAN: + { + bool bEnabled = Sys_StringToBool( pPropertyState->m_StringValue.Get() ); + if ( pPropertyState->m_pToolProperty->m_bInvertOutput ) + { + bEnabled ^= 1; + } + m_XMLWriter.WriteLineNode( pOutputName, pCondition, bEnabled ? "true" : "false" ); + } + break; + + case PT_STRING: + m_XMLWriter.WriteLineNode( pOutputName, pCondition, m_XMLWriter.FixupXMLString( pPropertyState->m_StringValue.Get() ) ); + break; + + case PT_LIST: + case PT_INTEGER: + m_XMLWriter.WriteLineNode( pOutputName, pCondition, pPropertyState->m_StringValue.Get() ); + break; + + case PT_IGNORE: + break; + + default: + g_pVPC->VPCError( "CProjectGenerator_Xbox360_2010: WriteProperty, %s - not implemented", pOutputName ); + } + } + + return true; +} + +bool CProjectGenerator_Xbox360_2010::Save( const char *pOutputFilename ) +{ + bool bValid = WritePrimaryXML( pOutputFilename ); + if ( bValid ) + { + bValid = WriteSecondaryXML( CFmtStr( "%s.filters", pOutputFilename ) ); + if ( !bValid ) + { + g_pVPC->VPCError( "Cannot save to the specified project '%s'", pOutputFilename ); + } + } + + return bValid; +} diff --git a/external/vpc/utils/vpc/projectgenerator_xbox360_2010.h b/external/vpc/utils/vpc/projectgenerator_xbox360_2010.h new file mode 100644 index 0000000..ce88157 --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_xbox360_2010.h @@ -0,0 +1,54 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef PROJECTGENERATOR_XBOX360_2010_H +#define PROJECTGENERATOR_XBOX360_2010_H +#ifdef _WIN32 +#pragma once +#endif + +#define PROPERTYNAME( X, Y ) X##_##Y, +enum Xbox360_2010_Properties_e +{ + #include "projectgenerator_xbox360_2010.inc" +}; + +class CProjectGenerator_Xbox360_2010 : public IVCProjWriter +{ +public: + CProjectGenerator_Xbox360_2010(); + IBaseProjectGenerator *GetProjectGenerator() { return m_pVCProjGenerator; } + + virtual bool Save( const char *pOutputFilename ); + +private: + // primary XML - foo.vcxproj + bool WritePrimaryXML( const char *pOutputFilename ); + bool WriteFolder( CProjectFolder *pFolder, const char *pFileTypeName, int nDepth ); + bool WriteFile( CProjectFile *pFile, const char *pFileTypeName ); + bool WriteConfiguration( CProjectConfiguration *pConfig ); + bool WriteTools( CProjectConfiguration *pConfig ); + bool WriteProperty( const PropertyState_t *pPropertyState, bool bEmitConfiguration = false, const char *pConfigurationName = NULL, const char *pOutputName = NULL, const char *pValue = NULL ); + bool WriteTool( const char *pToolName, const CProjectTool *pProjectTool, CProjectConfiguration *pConfig ); + bool WriteNULLTool( const char *pToolName, const CProjectConfiguration *pConfig ); + bool WritePropertyGroupTool( CProjectTool *pProjectTool, CProjectConfiguration *pConfiguration ); + bool WritePropertyGroup(); + + // secondary XML - foo.vcxproj.filters + bool WriteSecondaryXML( const char *pOutputFilename ); + bool WriteFolderToSecondaryXML( CProjectFolder *pFolder, const char *pParentPath ); + bool WriteFolderContentsToSecondaryXML( CProjectFolder *pFolder, const char *pParentPath, const char *pFileTypeName, int nDepth ); + bool WriteFileToSecondaryXML( CProjectFile *pFile, const char *pParentPath, const char *pFileTypeName ); + + const char *GetKeyNameForFile( CProjectFile *pFile ); + + CXMLWriter m_XMLWriter; + CXMLWriter m_XMLFilterWriter; + + CVCProjGenerator *m_pVCProjGenerator; +}; + +#endif // PROJECTGENERATOR_XBOX360_2010_H diff --git a/external/vpc/utils/vpc/projectgenerator_xbox360_2010.inc b/external/vpc/utils/vpc/projectgenerator_xbox360_2010.inc new file mode 100644 index 0000000..78525b8 --- /dev/null +++ b/external/vpc/utils/vpc/projectgenerator_xbox360_2010.inc @@ -0,0 +1,210 @@ + +//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Property Enumerations +// +//=====================================================================================// + +// Config +PROPERTYNAME( XBOX360_2010_GENERAL, ExcludedFromBuild ) +PROPERTYNAME( XBOX360_2010_GENERAL, OutputDirectory ) +PROPERTYNAME( XBOX360_2010_GENERAL, IntermediateDirectory ) +PROPERTYNAME( XBOX360_2010_GENERAL, ConfigurationType ) +PROPERTYNAME( XBOX360_2010_GENERAL, CharacterSet ) +PROPERTYNAME( XBOX360_2010_GENERAL, WholeProgramOptimization ) +PROPERTYNAME( XBOX360_2010_GENERAL, ExtensionsToDeleteOnClean ) +PROPERTYNAME( XBOX360_2010_GENERAL, BuildLogFile ) +PROPERTYNAME( XBOX360_2010_GENERAL, PlatformToolset ) + +// Debugging +PROPERTYNAME( XBOX360_2010_DEBUGGING, Command ) +PROPERTYNAME( XBOX360_2010_DEBUGGING, CommandArguments ) +PROPERTYNAME( XBOX360_2010_DEBUGGING, RemoteMachine ) +PROPERTYNAME( XBOX360_2010_DEBUGGING, MapDVDDrive ) +PROPERTYNAME( XBOX360_2010_DEBUGGING, CheckUpToDate ) + +// Compiler +PROPERTYNAME( XBOX360_2010_COMPILER, AdditionalOptions ) +PROPERTYNAME( XBOX360_2010_COMPILER, Optimization ) +PROPERTYNAME( XBOX360_2010_COMPILER, InlineFunctionExpansion ) +PROPERTYNAME( XBOX360_2010_COMPILER, EnableIntrinsicFunctions ) +PROPERTYNAME( XBOX360_2010_COMPILER, FavorSizeOrSpeed ) +PROPERTYNAME( XBOX360_2010_COMPILER, EnableFiberSafeOptimizations ) +PROPERTYNAME( XBOX360_2010_COMPILER, WholeProgramOptimization ) +PROPERTYNAME( XBOX360_2010_COMPILER, AdditionalIncludeDirectories ) +PROPERTYNAME( XBOX360_2010_COMPILER, PreprocessorDefinitions ) +PROPERTYNAME( XBOX360_2010_COMPILER, IgnoreStandardIncludePaths ) +PROPERTYNAME( XBOX360_2010_COMPILER, PreprocessToAFile ) +PROPERTYNAME( XBOX360_2010_COMPILER, PreprocessSuppressLineNumbers ) +PROPERTYNAME( XBOX360_2010_COMPILER, KeepComments ) +PROPERTYNAME( XBOX360_2010_COMPILER, EnableStringPooling ) +PROPERTYNAME( XBOX360_2010_COMPILER, EnableMinimalRebuild ) +PROPERTYNAME( XBOX360_2010_COMPILER, EnableCPPExceptions ) +PROPERTYNAME( XBOX360_2010_COMPILER, BasicRuntimeChecks ) +PROPERTYNAME( XBOX360_2010_COMPILER, RuntimeLibrary ) +PROPERTYNAME( XBOX360_2010_COMPILER, StructMemberAlignment ) +PROPERTYNAME( XBOX360_2010_COMPILER, BufferSecurityCheck ) +PROPERTYNAME( XBOX360_2010_COMPILER, EnableFunctionLevelLinking ) +PROPERTYNAME( XBOX360_2010_COMPILER, FloatingPointModel ) +PROPERTYNAME( XBOX360_2010_COMPILER, EnableFloatingPointExceptions ) +PROPERTYNAME( XBOX360_2010_COMPILER, DisableLanguageExtensions ) +PROPERTYNAME( XBOX360_2010_COMPILER, TreatWCHAR_TAsBuiltInType ) +PROPERTYNAME( XBOX360_2010_COMPILER, ForceConformanceInForLoopScope ) +PROPERTYNAME( XBOX360_2010_COMPILER, EnableRunTimeTypeInfo ) +PROPERTYNAME( XBOX360_2010_COMPILER, OpenMPSupport ) +PROPERTYNAME( XBOX360_2010_COMPILER, PrecompiledHeader ) +PROPERTYNAME( XBOX360_2010_COMPILER, PrecompiledHeaderFile ) +PROPERTYNAME( XBOX360_2010_COMPILER, PrecompiledHeaderOutputFile ) +PROPERTYNAME( XBOX360_2010_COMPILER, ExpandAttributedSource ) +PROPERTYNAME( XBOX360_2010_COMPILER, AssemblerOutput ) +PROPERTYNAME( XBOX360_2010_COMPILER, ASMListLocation ) +PROPERTYNAME( XBOX360_2010_COMPILER, ObjectFileName ) +PROPERTYNAME( XBOX360_2010_COMPILER, ProgramDatabaseFileName ) +PROPERTYNAME( XBOX360_2010_COMPILER, EnableBrowseInformation ) +PROPERTYNAME( XBOX360_2010_COMPILER, BrowseInformationFile ) +PROPERTYNAME( XBOX360_2010_COMPILER, WarningLevel ) +PROPERTYNAME( XBOX360_2010_COMPILER, TreatWarningsAsErrors ) +PROPERTYNAME( XBOX360_2010_COMPILER, SuppressStartupBanner ) +PROPERTYNAME( XBOX360_2010_COMPILER, DebugInformationFormat ) +PROPERTYNAME( XBOX360_2010_COMPILER, CompileAs ) +PROPERTYNAME( XBOX360_2010_COMPILER, ForcedIncludeFile ) +PROPERTYNAME( XBOX360_2010_COMPILER, ShowIncludes ) +PROPERTYNAME( XBOX360_2010_COMPILER, UndefineAllPreprocessorDefinitions ) +PROPERTYNAME( XBOX360_2010_COMPILER, UndefinePreprocessorDefinitions ) +PROPERTYNAME( XBOX360_2010_COMPILER, UseFullPaths ) +PROPERTYNAME( XBOX360_2010_COMPILER, OmitDefaultLibraryName ) +PROPERTYNAME( XBOX360_2010_COMPILER, TrapIntegerDividesOptimization ) +PROPERTYNAME( XBOX360_2010_COMPILER, PreschedulingOptimization ) +PROPERTYNAME( XBOX360_2010_COMPILER, InlineAssemblyOptimization ) +PROPERTYNAME( XBOX360_2010_COMPILER, RegisterReservation ) +PROPERTYNAME( XBOX360_2010_COMPILER, AnalyzeStalls ) +PROPERTYNAME( XBOX360_2010_COMPILER, CallAttributedProfiling ) +PROPERTYNAME( XBOX360_2010_COMPILER, SmallerTypeCheck ) +PROPERTYNAME( XBOX360_2010_COMPILER, DisableSpecificWarnings ) +PROPERTYNAME( XBOX360_2010_COMPILER, MultiProcessorCompilation ) +PROPERTYNAME( XBOX360_2010_COMPILER, UseUnicodeForAssemblerListing ) +PROPERTYNAME( XBOX360_2010_COMPILER, ForcedUsingFile ) +PROPERTYNAME( XBOX360_2010_COMPILER, DeduceVariableType ) +PROPERTYNAME( XBOX360_2010_COMPILER, CodeAnalysisForCCPP ) +PROPERTYNAME( XBOX360_2010_COMPILER, DisabledWarningDirectories ) + +// Librarian +PROPERTYNAME( XBOX360_2010_LIBRARIAN, UseUNICODEResponseFiles ) +PROPERTYNAME( XBOX360_2010_LIBRARIAN, AdditionalDependencies ) +PROPERTYNAME( XBOX360_2010_LIBRARIAN, OutputFile ) +PROPERTYNAME( XBOX360_2010_LIBRARIAN, AdditionalLibraryDirectories ) +PROPERTYNAME( XBOX360_2010_LIBRARIAN, SuppressStartupBanner ) +PROPERTYNAME( XBOX360_2010_LIBRARIAN, ModuleDefinitionFileName ) +PROPERTYNAME( XBOX360_2010_LIBRARIAN, IgnoreAllDefaultLibraries ) +PROPERTYNAME( XBOX360_2010_LIBRARIAN, IgnoreSpecificDefaultLibraries ) +PROPERTYNAME( XBOX360_2010_LIBRARIAN, ExportNamedFunctions ) +PROPERTYNAME( XBOX360_2010_LIBRARIAN, ForceSymbolReferences ) +PROPERTYNAME( XBOX360_2010_LIBRARIAN, LinkLibraryDependencies ) +PROPERTYNAME( XBOX360_2010_LIBRARIAN, AdditionalOptions ) + +// Linker +PROPERTYNAME( XBOX360_2010_LINKER, IgnoreImportLibrary ) +PROPERTYNAME( XBOX360_2010_LINKER, AdditionalOptions ) +PROPERTYNAME( XBOX360_2010_LINKER, AdditionalDependencies ) +PROPERTYNAME( XBOX360_2010_LINKER, ShowProgress ) +PROPERTYNAME( XBOX360_2010_LINKER, OutputFile ) +PROPERTYNAME( XBOX360_2010_LINKER, Version ) +PROPERTYNAME( XBOX360_2010_LINKER, EnableIncrementalLinking ) +PROPERTYNAME( XBOX360_2010_LINKER, SuppressStartupBanner ) +PROPERTYNAME( XBOX360_2010_LINKER, AdditionalLibraryDirectories ) +PROPERTYNAME( XBOX360_2010_LINKER, IgnoreAllDefaultLibraries ) +PROPERTYNAME( XBOX360_2010_LINKER, IgnoreSpecificDefaultLibraries ) +PROPERTYNAME( XBOX360_2010_LINKER, ModuleDefinitionFile ) +PROPERTYNAME( XBOX360_2010_LINKER, GenerateDebugInfo ) +PROPERTYNAME( XBOX360_2010_LINKER, GenerateProgramDatabaseFile ) +PROPERTYNAME( XBOX360_2010_LINKER, GenerateMapFile ) +PROPERTYNAME( XBOX360_2010_LINKER, MapFileName ) +PROPERTYNAME( XBOX360_2010_LINKER, MapExports ) +PROPERTYNAME( XBOX360_2010_LINKER, StackCommitSize ) +PROPERTYNAME( XBOX360_2010_LINKER, References ) +PROPERTYNAME( XBOX360_2010_LINKER, EnableCOMDATFolding ) +PROPERTYNAME( XBOX360_2010_LINKER, LinkTimeCodeGeneration ) +PROPERTYNAME( XBOX360_2010_LINKER, EntryPoint ) +PROPERTYNAME( XBOX360_2010_LINKER, NoEntryPoint ) +PROPERTYNAME( XBOX360_2010_LINKER, SetChecksum ) +PROPERTYNAME( XBOX360_2010_LINKER, BaseAddress ) +PROPERTYNAME( XBOX360_2010_LINKER, ImportLibrary ) +PROPERTYNAME( XBOX360_2010_LINKER, FixedBaseAddress ) +PROPERTYNAME( XBOX360_2010_LINKER, ErrorReporting ) +PROPERTYNAME( XBOX360_2010_LINKER, FunctionOrder ) +PROPERTYNAME( XBOX360_2010_LINKER, LinkLibraryDependencies ) +PROPERTYNAME( XBOX360_2010_LINKER, UseLibraryDependencyInputs ) +PROPERTYNAME( XBOX360_2010_LINKER, ForceSymbolReferences ) +PROPERTYNAME( XBOX360_2010_LINKER, StripPrivateSymbols ) +PROPERTYNAME( XBOX360_2010_LINKER, ProfileGuidedDatabase ) +PROPERTYNAME( XBOX360_2010_LINKER, MergeSections ) +PROPERTYNAME( XBOX360_2010_LINKER, AutomaticModuleDefinitionFile ) + +// Browse Information +PROPERTYNAME( XBOX360_2010_BROWSEINFORMATION, SuppressStartupBanner ) +PROPERTYNAME( XBOX360_2010_BROWSEINFORMATION, OutputFile ) +PROPERTYNAME( XBOX360_2010_BROWSEINFORMATION, AdditionalOptions ) +PROPERTYNAME( XBOX360_2010_BROWSEINFORMATION, PreserveSBRFiles ) + +// Pre Build +PROPERTYNAME( XBOX360_2010_PREBUILDEVENT, Description ) +PROPERTYNAME( XBOX360_2010_PREBUILDEVENT, CommandLine ) +PROPERTYNAME( XBOX360_2010_PREBUILDEVENT, ExcludedFromBuild ) +PROPERTYNAME( XBOX360_2010_PREBUILDEVENT, UseInBuild ) + +// Pre Link +PROPERTYNAME( XBOX360_2010_PRELINKEVENT, Description ) +PROPERTYNAME( XBOX360_2010_PRELINKEVENT, CommandLine ) +PROPERTYNAME( XBOX360_2010_PRELINKEVENT, ExcludedFromBuild ) +PROPERTYNAME( XBOX360_2010_PRELINKEVENT, UseInBuild ) + +// Post Build +PROPERTYNAME( XBOX360_2010_POSTBUILDEVENT, Description ) +PROPERTYNAME( XBOX360_2010_POSTBUILDEVENT, CommandLine ) +PROPERTYNAME( XBOX360_2010_POSTBUILDEVENT, ExcludedFromBuild ) +PROPERTYNAME( XBOX360_2010_POSTBUILDEVENT, UseInBuild ) + +// Custom Build +PROPERTYNAME( XBOX360_2010_CUSTOMBUILDSTEP, Description ) +PROPERTYNAME( XBOX360_2010_CUSTOMBUILDSTEP, CommandLine ) +PROPERTYNAME( XBOX360_2010_CUSTOMBUILDSTEP, AdditionalDependencies ) +PROPERTYNAME( XBOX360_2010_CUSTOMBUILDSTEP, Outputs ) +PROPERTYNAME( XBOX360_2010_CUSTOMBUILDSTEP, ExecuteAfter ) +PROPERTYNAME( XBOX360_2010_CUSTOMBUILDSTEP, ExecuteBefore ) + +// Image Conversion +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, SuppressStartupBanner ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, ConfigurationFile ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, OutputFile ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, TitleID ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, LANKey ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, BaseAddress ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, HeapSize ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, WorkspaceSize ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, AdditionalSections ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, ExportByName ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, OpticalDiscDriveMapping ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, PAL50Incompatible ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, MultidiscTitle ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, PreferBigButtonInput ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, CrossPlatformSystemLink ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, AllowAvatarGetMetadataByXUID ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, AllowControllerSwapping ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, RequireFullExperience ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, GameVoiceRequiredUI ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, KinectElevationControl ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, SkeletalTrackingRequirement ) +PROPERTYNAME( XBOX360_2010_XBOX360IMAGECONVERSION, AdditionalOptions ) + +// Console Deployment +PROPERTYNAME( XBOX360_2010_CONSOLEDEPLOYMENT, ExcludedFromBuild ) +PROPERTYNAME( XBOX360_2010_CONSOLEDEPLOYMENT, SuppressStartupBanner ) +PROPERTYNAME( XBOX360_2010_CONSOLEDEPLOYMENT, DeploymentFiles ) +PROPERTYNAME( XBOX360_2010_CONSOLEDEPLOYMENT, Progress ) +PROPERTYNAME( XBOX360_2010_CONSOLEDEPLOYMENT, ForceCopy ) +PROPERTYNAME( XBOX360_2010_CONSOLEDEPLOYMENT, DeploymentType ) +PROPERTYNAME( XBOX360_2010_CONSOLEDEPLOYMENT, DeploymentRoot ) +PROPERTYNAME( XBOX360_2010_CONSOLEDEPLOYMENT, EmulationType ) +PROPERTYNAME( XBOX360_2010_CONSOLEDEPLOYMENT, LayoutFile ) +PROPERTYNAME( XBOX360_2010_CONSOLEDEPLOYMENT, AdditionalOptions ) + diff --git a/external/vpc/utils/vpc/projectscript.cpp b/external/vpc/utils/vpc/projectscript.cpp new file mode 100644 index 0000000..a6402d2 --- /dev/null +++ b/external/vpc/utils/vpc/projectscript.cpp @@ -0,0 +1,2484 @@ +//========= Copyright 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: VPC +// +//=====================================================================================// + +#include "vpc.h" +#include "tier1/utldict.h" +#include "tier1/keyvalues.h" +#include "baseprojectdatacollector.h" + +#ifndef STEAM + bool V_StrSubstInPlace( char *pchInOut, int cchInOut, const char *pMatch, const char *pReplaceWith, bool bCaseSensitive ) +{ + bool bRet = false; + char *pchT = (char *)malloc( cchInOut ); + if ( V_StrSubst( pchInOut, pMatch, pReplaceWith, pchT, cchInOut, bCaseSensitive ) ) + { + V_strncpy( pchInOut, pchT, cchInOut ); + bRet = true; + } + free( pchT ); + return bRet; +} +#endif + +void VPC_ParseFileSection( bool *pbHadConfigSection = NULL ) +{ + if ( pbHadConfigSection ) + *pbHadConfigSection = false; + + while ( 1 ) + { + const char *pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] ) + break; + + if ( !V_stricmp( pToken, "}" ) ) + { + // end of section + break; + } + if ( !V_stricmp( pToken, "$configuration" ) ) + { + VPC_Keyword_FileConfiguration( ); + if ( pbHadConfigSection ) + *pbHadConfigSection = true; + } + } +} + +//----------------------------------------------------------------------------- +// VPC_TrackSchemaFile +// +//----------------------------------------------------------------------------- + +void VPC_TrackSchemaFile( const char *pName, bool bRemove, const char *pFileFlag ) +{ +#ifdef STEAM + return; +#else + if ( !bRemove && (!pFileFlag || !V_stristr( pFileFlag, "schema" )) ) + { + // adding something that's not schema - ignore + return; + } + + for ( int i = 0; i < g_pVPC->m_SchemaFiles.Count(); i++ ) + { + if ( !g_pVPC->m_SchemaFiles[i].String() ) + continue; + + if ( !V_stricmp( pName, g_pVPC->m_SchemaFiles[i].String() ) ) + { + if ( bRemove ) + { + g_pVPC->m_SchemaFiles.Remove( i ); + } + return; + } + } + + if ( bRemove ) + { + // not found, nothing to do + return; + } + + g_pVPC->m_SchemaFiles.AddToTail( pName ); + + // suppress building of schematized cpp files + // (they get #included by an auto-generated cpp that is built instead) + const char *pExt = V_GetFileExtension(pName); + if ( pExt && !V_stricmp( pExt, "cpp" ) ) + { + CUtlVector< CUtlString > configurationNames; + g_pVPC->GetProjectGenerator()->GetAllConfigurationNames( configurationNames ); + for ( int i=0; i < configurationNames.Count(); i++ ) + { + g_pVPC->GetProjectGenerator()->StartConfigurationBlock( configurationNames[i].String(), true ); + g_pVPC->GetProjectGenerator()->FileIsSchema( true ); + g_pVPC->GetProjectGenerator()->FileExcludedFromBuild( true ); + g_pVPC->GetProjectGenerator()->EndConfigurationBlock(); + } + } + +#endif +} + +static char *ResolveCandidate( const char *pszFile, const char *pszPlatform ) +{ + char szPath[MAX_PATH]; + char szPathExpanded[MAX_PATH]; + + V_ComposeFileName( g_pVPC->GetProjectPath(), pszFile, szPath, sizeof(szPath) ); + Sys_ReplaceString( szPath, "$os", pszPlatform, szPathExpanded, sizeof(szPathExpanded) ); + V_FixSlashes( szPathExpanded ); + V_RemoveDotSlashes( szPathExpanded ); + V_FixDoubleSlashes( szPathExpanded ); + + if ( Sys_Exists( szPathExpanded ) ) + { + char *pszResolvedFilename = (char*)malloc( MAX_PATH ); + Sys_ReplaceString( pszFile, "$os", pszPlatform, pszResolvedFilename, MAX_PATH ); + return pszResolvedFilename; + } + + return NULL; +} + +// No particular order, but must not change without changing the arrPlatformChains matrix +const char *g_szArrPlatforms[] = +{ + "win32", // 0 + "win64", // 1 + "osx32", // 2 + "osx64", // 3 + "linux32", // 4 + "linux64", // 5 + "cygwin", // 6 + "ps3", // 7 + "x360", // 8 + "win", // 9 + "osx", // 10 + "linux", // 11 + "posix", // 12 + "any", // 13 + NULL +}; + +//----------------------------------------------------------------------------- +// ResolveFilename +// Utility to expand $OS if present +// Returns expanded filename to a file that exists on disk, or NULL otherwise +// vecBonusFiles will contain a list of valid OS files that are on disk but did not +// match the current target platform. +//----------------------------------------------------------------------------- +static char *ResolveFilename( const char *pszFile, CUtlVector<CUtlString> &vecBonusFiles ) +{ + static const int k_lastRealPlatform = 8; // index, not count + static const int k_AnyPlatform = 13; // index + + static const int arrPlatformChains[][9] = + { + { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, // the raw platforms + { 9, 9, 10, 10, 11, 11, 12, 12, 9 }, // first fallback + { 13, 13, 12, 12, 12, 12, 13, 13, 13 }, // 2nd fallback + { 13, 13, 13, 13, 13, 13, 13, 13, 13 }, // 3rd fallback + }; + + // Don't want the actual backing store to be const since we aren't compile-time init'ing, + // but it is single-instance initialized, so make a const ref to it that everyone except + // the init codes uses to make sure it doesn't get mucked with. + static bool bInited = false; + static char _szPlatformStore[128]; + static const char (&szPlatform)[128] = _szPlatformStore; + + if ( !bInited ) + { + bInited = true; + const char *pszPlatform = g_pVPC->GetTargetPlatformName(); + V_strncpy( _szPlatformStore, pszPlatform, sizeof( szPlatform ) ); + V_strlower( _szPlatformStore ); + } + + vecBonusFiles.RemoveAll(); + + int nPlatformColumn = -1; + for ( int i = 0; i <= k_lastRealPlatform; i++ ) + { + if ( V_strcmp( szPlatform, g_szArrPlatforms[i] ) == 0 ) + { + nPlatformColumn = i; + break; + } + } + + if ( nPlatformColumn < 0 ) + { + g_pVPC->VPCWarning( "Internal Error: Target Platform: '%s' unrecognized while expanding $os!", szPlatform ); + return NULL; + } + + // Now walk the chain of potential platform matches from strongest to weakest + char *pszResolved = NULL; + int nPlatformToCheck = -1; + int nCurrentPlatformRow = -1; + do + { + nCurrentPlatformRow++; + nPlatformToCheck = arrPlatformChains[nCurrentPlatformRow][nPlatformColumn]; + pszResolved = ResolveCandidate( pszFile, g_szArrPlatforms[ nPlatformToCheck ] ); + if ( pszResolved ) + break; + } + while ( arrPlatformChains[nCurrentPlatformRow][nPlatformColumn] != k_AnyPlatform ); + + // Now go pickup the any files that exist, but were non-matches + for ( int i = 0; g_szArrPlatforms[i] != NULL; i++ ) + { + // Don't pick up the actual found platform + if ( i != nPlatformToCheck ) + { + CUtlString file( ResolveCandidate( pszFile, g_szArrPlatforms[ i ] ) ); + if ( !file.IsEmpty() ) + vecBonusFiles.AddToTail( file ); + } + } + return pszResolved; +} + +//----------------------------------------------------------------------------- +// VPC_Keyword_AddFile +// +//----------------------------------------------------------------------------- +void VPC_Keyword_AddFilesByPattern() +{ + CUtlVector<CUtlString> files; + + while ( 1 ) + { + const char *pToken = g_pVPC->GetScript().GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + + // Is this a conditional expression? + if ( pToken[0] == '[' ) + { + if ( files.Count() == 0 ) + { + g_pVPC->VPCSyntaxError( "Conditional specified on a $FilePattern without any pattern preceding it." ); + } + + if ( !g_pVPC->EvaluateConditionalExpression( pToken ) ) + { + // we did all that work for no reason, time to bail out + return; + } + } + + char szFilename[MAX_PATH]; + g_pVPC->ResolveMacrosInString( pToken, szFilename, sizeof( szFilename ) ); + + V_FixSlashes( szFilename ); + + CUtlVector< CUtlString > vecResults; + Sys_ExpandFilePattern( szFilename, vecResults ); + + for ( int i=0; i < vecResults.Count(); i++ ) + { + g_pVPC->VPCStatus( false, "glob: adding '%s' to project", vecResults[i].String() ); + g_pVPC->GetProjectGenerator()->StartFile( vecResults[i].String(), true ); + g_pVPC->GetProjectGenerator()->EndFile(); + } + } + +} + +// forward decl we need in the add file code +void VPC_Keyword_Folder( bool bUnity, const folderConfig_t *pInheritedFolderConfig = NULL ); + +//----------------------------------------------------------------------------- +// VPC_Keyword_AddFile +// +//----------------------------------------------------------------------------- +void VPC_Keyword_AddFile( const char *pFileFlag = NULL, const folderConfig_t *pFolderConfig = NULL ) +{ + bool bAllowNextLine = false; + CUtlVector<CUtlString> files; + CUtlVector<CUtlString> unbuiltFiles; + + bool bHasConditional = false; + while ( 1 ) + { + const char *pToken = g_pVPC->GetScript().GetToken( bAllowNextLine ); + if ( !pToken || !pToken[0] ) + break; + + // Is this a conditional expression? + if ( pToken[0] == '[' ) + { + if ( files.Count() == 0 ) + { + g_pVPC->VPCSyntaxError( "Conditional specified on a $File without any file preceding it." ); + } + + if ( !g_pVPC->EvaluateConditionalExpression( pToken ) ) + { + // DO NOT INTEGRATE OR TAKE THIS TO STEAM + // Steam VPC differs in conditional handling inside grouped files + unbuiltFiles.AddToTail( files[files.Count() - 1] ); + files.Remove( files.Count() - 1 ); + //unbuiltFiles.AddMultipleToTail( files.Count(), files.Base() ); + //files.RemoveAll(); + } + + bHasConditional = true; + continue; + } + + char szFilename[MAX_PATH]; + g_pVPC->ResolveMacrosInString( pToken, szFilename, sizeof( szFilename ) ); + + if ( !V_stricmp( pToken, "\\" ) ) + { + bAllowNextLine = true; + continue; + } + else + { + bAllowNextLine = false; + } + + V_FixSlashes( szFilename ); + + CUtlString string = szFilename; + files.AddToTail( string ); + + // check for another optional file + pToken = g_pVPC->GetScript().PeekNextToken( bAllowNextLine ); + if ( !pToken || !pToken[0] ) + break; + } + + // check for optional section + bool bHasSection = false; + const char *pToken = g_pVPC->GetScript().PeekNextToken( true ); + if ( pToken && pToken[0] && !V_stricmp( pToken, "{" ) ) + { + bHasSection = true; + } + + // dynamic files need to opt out of strict file presence check + bool bDynamicFile = pFileFlag && V_stristr( pFileFlag, "dynamic" ); + + // need to check files early to handle possible rejected section + if ( g_pVPC->IsCheckFiles() && !bDynamicFile ) + { + for ( int i=0; i<files.Count(); i++ ) + { + const char *pFilename = files[i].String(); + if ( !Sys_Exists( pFilename ) && !V_stristr( pFilename, "$os" ) ) + { +#if defined( POSIX ) + // We have a _lot_ of vpc files that contain header files with the incorrect casing. + // So try to lowercase the filename here and if it exists, replace it and carry on. + // + CUtlString FileNameLower = files[ i ]; + + V_strlower( FileNameLower.Get() ); + if( Sys_Exists( FileNameLower ) ) + { + files[ i ] = FileNameLower; + continue; + } +#endif + + // Hack around all the libraries which are listed as $File instead of $Lib + const char* extension = strrchr( pFilename, '.' ); + if ( !extension || stricmp( extension, ".lib" ) ) + { + g_pVPC->VPCWarning( "File '%s' does not exist. Not adding to project.", pFilename ); + g_pVPC->IncrementFileMissing(); + files.Remove( i ); + } + else + { + // don't complain about libs that contain $(Configuration) in their path + if ( !V_stristr( pFilename, "$(Configuration)" ) ) + g_pVPC->VPCWarning( "Library '%s' does not exist. Adding to project anyway.", pFilename ); + } + } + } + } + + if ( g_pVPC->IsShowCaseIssues() && !bDynamicFile ) + { + for ( int i = 0; i < files.Count(); i++ ) + { + const char *pFilename = files[i].String(); + char actualFilename[MAX_PATH]; + if ( !Sys_IsFilenameCaseConsistent( pFilename, actualFilename, sizeof( actualFilename ) ) ) + { + g_pVPC->VPCWarning( "Case Consistency Issue! File '%s' specified in '%s' is inconsistent with OS version '%s'.", pFilename, g_pVPC->GetProjectName(), actualFilename ); + + // need script stack to assist in tracking down missing file + g_pVPC->GetScript().SpewScriptStack(); + } + } + } + + if ( !files.Count() && bHasSection ) + { + // optional section has been conditionally removed + g_pVPC->GetScript().SkipBracedSection(); + return; + } + + for ( int i=0; i < unbuiltFiles.Count(); i++ ) + { + const char *pExcludedFilename = unbuiltFiles[i].String(); + + g_pVPC->GetProjectGenerator()->StartFile( pExcludedFilename, true ); + CUtlVector< CUtlString > configurationNames; + g_pVPC->GetProjectGenerator()->GetAllConfigurationNames( configurationNames ); + for ( int i=0; i < configurationNames.Count(); i++ ) + { + g_pVPC->GetProjectGenerator()->StartConfigurationBlock( configurationNames[i].String(), true ); + g_pVPC->GetProjectGenerator()->FileExcludedFromBuild( true ); + g_pVPC->GetProjectGenerator()->EndConfigurationBlock(); + } + g_pVPC->GetProjectGenerator()->EndFile(); + } + + if ( bHasSection ) + { + // found optional section, parse opening brace + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] || V_stricmp( pToken, "{" ) ) + g_pVPC->VPCSyntaxError(); + } + + // Handle $OS expansion + // save parser state + CScriptSource startingScriptSource = g_pVPC->GetScript().GetCurrentScript(); + + for ( int i=0; i<files.Count(); i++ ) + { + const char *pFilename = files[i].String(); + + CUtlString filename; + if ( !g_pVPC->m_bInMkSlnPass && V_stristr( pFilename, "$os" ) ) + { + CUtlVector< CUtlString > vecExcludedFiles; + filename = ResolveFilename( pFilename, vecExcludedFiles ); + char rgchRejectList[4096]; rgchRejectList[0]='\0'; + if ( vecExcludedFiles.Count() ) + { + for ( int i=0; i<files.Count(); i++ ) + { + V_strncat( rgchRejectList, files[i].String(), V_ARRAYSIZE( rgchRejectList ) ); + V_strncat( rgchRejectList, ",", V_ARRAYSIZE( rgchRejectList ) ); + } + } + g_pVPC->VPCStatus( false, "$OS: Resolved %s -> %s, rejected %s", pFilename, filename.String(), rgchRejectList ); + + if ( filename.IsEmpty() ) + { + g_pVPC->VPCWarning( "$File %s did not resolve to an existing file, skipping!", pFilename ); + continue; + } + + for ( i=0; i < vecExcludedFiles.Count(); i++ ) + { + const char *pExcludedFilename = vecExcludedFiles[i].String(); + const char *pExcludedExtension = V_GetFileExtension( pExcludedFilename ); + if ( !pExcludedExtension ) + { + pExcludedExtension = ""; + } + if ( pExcludedExtension && !V_stricmp( pExcludedExtension, "cpp" ) ) + { + g_pVPC->VPCStatus( false, "excluding '%s' from build", pExcludedFilename ); + g_pVPC->GetProjectGenerator()->StartFile( pExcludedFilename, true ); + CUtlVector< CUtlString > configurationNames; + g_pVPC->GetProjectGenerator()->GetAllConfigurationNames( configurationNames ); + for ( int i=0; i < configurationNames.Count(); i++ ) + { + g_pVPC->GetProjectGenerator()->StartConfigurationBlock( configurationNames[i].String(), true ); + g_pVPC->GetProjectGenerator()->FileExcludedFromBuild( true ); + g_pVPC->GetProjectGenerator()->EndConfigurationBlock(); + } + g_pVPC->GetProjectGenerator()->EndFile(); + } + } + + pFilename = filename.String(); + } + + bool bAdded = g_pVPC->GetProjectGenerator()->StartFile( pFilename, true ); + + if ( bDynamicFile ) + { + CUtlVector< CUtlString > configurationNames; + g_pVPC->GetProjectGenerator()->GetAllConfigurationNames( configurationNames ); + for ( int i=0; i < configurationNames.Count(); i++ ) + { + g_pVPC->GetProjectGenerator()->StartConfigurationBlock( configurationNames[i].String(), true ); + g_pVPC->GetProjectGenerator()->FileIsDynamic( true ); + g_pVPC->GetProjectGenerator()->EndConfigurationBlock(); + } + } + + // Lookup extension for a custom build script + const char *pExtension = V_GetFileExtension( pFilename ); + if ( !pExtension ) + { + pExtension = ""; + } + + if ( !g_pVPC->m_sUnityCurrent.IsEmpty() && !V_stricmp( pExtension, "cpp" ) && !bHasSection && !bHasConditional ) + { + bool bEmitUnityFiles = ( !g_pVPC->m_bInMkSlnPass && ( g_pVPC->IsForceGenerate() || !g_pVPC->IsProjectCurrent( g_pVPC->GetOutputFilename(), false ) ) ); + if ( bEmitUnityFiles ) + { + // append to the unity file + g_pVPC->VPCStatus( false, "Unity: adding '%s' to unity file '%s'", pFilename, g_pVPC->m_sUnityCurrent.String() ); + FILE *fp = fopen( g_pVPC->m_sUnityCurrent.String(), "at" ); + if ( !fp ) + { + g_pVPC->VPCError( "Cannot open %s for appending", g_pVPC->m_sUnityCurrent.String() ); + } + else + { + char pFixedFilename[MAX_PATH]; + V_strncpy( pFixedFilename, pFilename, sizeof(pFixedFilename) ); + V_FixSlashes( pFixedFilename, '/' ); + fprintf( fp, "#include \"%s\"\n", pFixedFilename ); + fclose( fp ); + } + } + + g_pVPC->VPCStatus( false, "Unity: excluding '%s' from build", pFilename ); + CUtlVector< CUtlString > configurationNames; + g_pVPC->GetProjectGenerator()->GetAllConfigurationNames( configurationNames ); + for ( int i=0; i < configurationNames.Count(); i++ ) + { + g_pVPC->GetProjectGenerator()->StartConfigurationBlock( configurationNames[i].String(), true ); + g_pVPC->GetProjectGenerator()->FileExcludedFromBuild( true ); + g_pVPC->GetProjectGenerator()->EndConfigurationBlock(); + } + } + else + { + bool bHadConfigSection = false; + + int index = g_pVPC->m_CustomBuildSteps.Find( pExtension ); + if ( g_pVPC->m_CustomBuildSteps.IsValidIndex( index ) ) + { + CUtlString buildsteps = g_pVPC->m_CustomBuildSteps[index]; + const char *pBuffer = buildsteps.Get(); + + CUtlString scriptName; + scriptName = pExtension; + scriptName += " custom build step"; + + // save parser state + g_pVPC->GetScript().PushScript( g_pVPC->GetScript().GetName(), pBuffer ); + + // parse injected buildstep + VPC_ParseFileSection( &bHadConfigSection ); + + // restore parser state + g_pVPC->GetScript().PopScript(); + g_pVPC->GetScript().RestoreScript( startingScriptSource ); + } + + // apply optional section to each file + if ( bHasSection && bAdded ) + { + // restore parser state + g_pVPC->GetScript().RestoreScript( startingScriptSource ); + VPC_ParseFileSection( &bHadConfigSection ); + } + + // if this file doesn't have a file-specific config, but the folder we're in has a config + // apply that folder config to the file here + if ( !bHadConfigSection && pFolderConfig ) + VPC_ApplyFolderConfigurationToFile( *pFolderConfig ); + + } + + VPC_TrackSchemaFile( pFilename, false, pFileFlag ); + + if ( bAdded ) + g_pVPC->GetProjectGenerator()->EndFile(); + } +} + +// parse a list of filenames from the current token, handling conditionals, macro expansion, \\, fixslashes, etc +static void VPC_ParseFileList( CUtlStringList &files ) +{ + bool bAllowNextLine = false; + + while ( 1 ) + { + const char *pToken = g_pVPC->GetScript().GetToken( bAllowNextLine ); + if ( !pToken || !pToken[0] ) + g_pVPC->VPCSyntaxError(); + + const char *pNextToken = g_pVPC->GetScript().PeekNextToken( false ); + if ( !pNextToken || !pNextToken[0] ) + { + // current token is last token + // last token can be optional conditional, need to identify + // backup and reparse up to last token + if ( pToken && pToken[0] == '[' ) + { + if ( files.Count() == 0 ) + { + g_pVPC->VPCSyntaxError( "Conditional specified on a file list without any file preceding it." ); + } + // last token is an optional conditional + bool bResult = g_pVPC->EvaluateConditionalExpression( pToken ); + if ( !bResult ) // was conditional false? + { + files.PurgeAndDeleteElements(); + } + return; + } + } + + char szFilename[MAX_PATH]; + g_pVPC->ResolveMacrosInString( pToken, szFilename, sizeof( szFilename ) ); + V_FixSlashes( szFilename ); + + if ( !V_stricmp( pToken, "\\" ) ) + { + bAllowNextLine = true; + continue; + } + else + { + bAllowNextLine = false; + } + + files.CopyAndAddToTail( szFilename ); + + // check for another optional file + pToken = g_pVPC->GetScript().PeekNextToken( bAllowNextLine ); + if ( !pToken || !pToken[0] ) + break; + } +} + +// add or remove .lib or dll import files, automatically adding prefixes and suffices to the name +static void VPC_HandleLibraryExpansion( char const *pDefaultPath, char const *pFileNamePrefix, char const *pSuffix, bool bRemove ) +{ + if ( !pFileNamePrefix ) + { + pFileNamePrefix = ""; + } + char szResolvedFilePrefix[MAX_PATH]; + g_pVPC->ResolveMacrosInString( pFileNamePrefix, szResolvedFilePrefix, sizeof(szResolvedFilePrefix) ); + + CUtlStringList impFiles; + VPC_ParseFileList( impFiles ); + for( int i = 0; i < impFiles.Count(); i++ ) + { + char szFilename[MAX_PATH]; + char const *pPathPrefixToUse = pDefaultPath; + + // do not add the path prefix if the filename contains path information already, or if null was passed. + char impFile[MAX_PATH]; + V_strncpy( impFile, impFiles[i], sizeof( impFile ) ); + V_RemoveDotSlashes( impFile ); + + char *pLastSlash = (char*)MAX( strrchr( impFile, '\\' ), strrchr( impFile, '/' ) ); + if ( pLastSlash ) + { + *pLastSlash = 0; + const char *pFilenamePart = pLastSlash + 1; + // don't prepend the prefix if the filename already starts with it + bool bAddPrefix = true; + if ( V_strlen(szResolvedFilePrefix) && !V_strnicmp( pFilenamePart, szResolvedFilePrefix, V_strlen(szResolvedFilePrefix) ) ) + bAddPrefix = false; + sprintf( szFilename, "%s/%s%s%s", impFile, bAddPrefix ? pFileNamePrefix : "", pFilenamePart, pSuffix ); + } + else + { + bool bAddPrefix = true; + if ( V_strlen(szResolvedFilePrefix) && !V_strnicmp( impFiles[i], szResolvedFilePrefix, V_strlen(szResolvedFilePrefix) ) ) + bAddPrefix = false; + sprintf( szFilename, "%s%s%s%s", pPathPrefixToUse, bAddPrefix ? pFileNamePrefix : "", impFiles[i], pSuffix ); + } + + char szFilename1[MAX_PATH]; + g_pVPC->ResolveMacrosInString( szFilename, szFilename1, sizeof( szFilename1 ) ); + + // Replace forward slashes with backslashes regardless of target platform + V_FixSlashes( szFilename1 ); + V_RemoveDotSlashes( szFilename1 ); + + if ( bRemove ) + { + bool bSucc = g_pVPC->GetProjectGenerator()->RemoveFile( szFilename1 ); + if ( !bSucc ) + { + g_pVPC->VPCError( "Broken $implib command. Failed to remove file %s from project.", szFilename1 ); + } + } + else + { + bool bAdded = g_pVPC->GetProjectGenerator()->StartFile( szFilename1, true ); + if ( !bAdded ) + { + g_pVPC->VPCError( "couldn't add %s", szFilename1 ); + } + g_pVPC->GetProjectGenerator()->EndFile(); + } + } +} + +enum EVPCKeywordFlag +{ + k_eVPCKeywordFlag_Remove = 0x00000001, + k_eVPCKeywordFlag_External = 0x00000002, +}; + +static void VPC_Keyword_ImportLibrary( uint32 Flags ) +{ + char const *pSuffix = "$_IMPLIB_EXT"; + bool bRemove = !!(Flags & k_eVPCKeywordFlag_Remove ); + + if( ( Flags & k_eVPCKeywordFlag_External ) && + g_pVPC->FindOrCreateMacro( "_EXTERNAL_IMPLIB_EXT", false, NULL ) ) + { + pSuffix = "$_EXTERNAL_IMPLIB_EXT"; + } + + VPC_HandleLibraryExpansion( "$LIBPUBLIC\\", "$_IMPLIB_PREFIX", pSuffix, bRemove ); +} + +static void VPC_Keyword_LinkerLibrary( uint32 Flags ) +{ + char const *pSuffix = "$_STATICLIB_EXT"; + bool bRemove = !!(Flags & k_eVPCKeywordFlag_Remove ); + + if( ( Flags & k_eVPCKeywordFlag_External ) && + g_pVPC->FindOrCreateMacro( "_EXTERNAL_STATICLIB_EXT", false, NULL ) ) + { + pSuffix = "$_EXTERNAL_STATICLIB_EXT"; + } + + VPC_HandleLibraryExpansion( "$LIBPUBLIC\\", "$_STATICLIB_PREFIX", pSuffix, bRemove ); +} + +//----------------------------------------------------------------------------- +// VPC_Keyword_RemoveFile +// +//----------------------------------------------------------------------------- +void VPC_Keyword_RemoveFile() +{ + CUtlStringList filesToRemove; + VPC_ParseFileList( filesToRemove ); + for ( int i = 0; i < filesToRemove.Count(); i++ ) + { + bool bSucc = g_pVPC->GetProjectGenerator()->RemoveFile( filesToRemove[i] ); + if ( !bSucc ) + { + g_pVPC->VPCWarning( "Failed to remove file %s from project", filesToRemove[i] ); + } + + VPC_TrackSchemaFile( filesToRemove[i], true, NULL ); + } +} + +//----------------------------------------------------------------------------- +// VPC_Keyword_Folder +// +//----------------------------------------------------------------------------- +void VPC_Keyword_Folder( bool bUnity, const folderConfig_t *pInheritedFolderConfig /* = NULL */ ) +{ + const char *pToken; + char folderName[MAX_PATH]; + folderConfig_t folderConfig; + + // by default, our active config is any config that we inherited from the parent. + const folderConfig_t *pActiveFolderConfig = pInheritedFolderConfig; + + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, folderName, sizeof( folderName ) ) ) + { + g_pVPC->GetScript().SkipBracedSection(); + return; + } + + g_pVPC->GetProjectGenerator()->StartFolder( folderName ); + + bool bEmitUnityFiles = ( !g_pVPC->m_bInMkSlnPass && ( g_pVPC->IsForceGenerate() || !g_pVPC->IsProjectCurrent( g_pVPC->GetOutputFilename(), false ) ) ); + if ( bUnity ) + { + // generate a .cpp file from the folderName + char unityName[MAX_PATH]; + V_snprintf( unityName, sizeof(unityName), "%s_%s_unity.cpp", folderName, g_pVPC->GetProjectName() ); + V_StrSubstInPlace( unityName, sizeof(unityName), " ", "_", false ); + + // make sure we have a unique file name, we don't want to tread on another projects unity + g_pVPC->m_sUnityCurrent = unityName; + int cAttempt = 1; + while ( g_pVPC->m_UnityFilesSeen.Find( g_pVPC->m_sUnityCurrent ) != g_pVPC->m_UnityFilesSeen.InvalidIndex() ) + { + V_snprintf( unityName, sizeof(unityName), "%s_%s_unity_%d.cpp", folderName, g_pVPC->GetProjectName(), ++cAttempt ); + V_StrSubstInPlace( unityName, sizeof(unityName), " ", "_", false ); + g_pVPC->m_sUnityCurrent = unityName; + } + + g_pVPC->m_UnityStack.Push( g_pVPC->m_sUnityCurrent ); + + if ( bEmitUnityFiles ) + { + g_pVPC->VPCStatus( false, "Unity: emitting '%s' in project: '%s'", unityName, g_pVPC->GetProjectName() ); + + // always add the stdafx.h at the top (if we're using a precompiled header, what if we're not?) + FILE *fp = fopen( g_pVPC->m_sUnityCurrent.String(), "wt" ); + if ( !fp ) + { + g_pVPC->VPCError( "Cannot open %s for writing", g_pVPC->m_sUnityCurrent.String() ); + } + else + { + const char *pStdAfx = g_pVPC->GetMacroValue( "STDAFX" ); + if ( pStdAfx && *pStdAfx ) + { + fprintf( fp, "#include \"%s\"\n", pStdAfx ); + } + fclose( fp ); + } + } + + g_pVPC->m_UnityFilesSeen.Insert( g_pVPC->m_sUnityCurrent ); + + // Msg( "pushing unity file %s\n", g_sUnityCurrent ); + g_pVPC->GetProjectGenerator()->StartFile( g_pVPC->m_sUnityCurrent, true ); + g_pVPC->GetProjectGenerator()->EndFile(); + } + + // Now parse all the files and subfolders.. + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] || V_stricmp( pToken, "{" ) ) + g_pVPC->VPCSyntaxError(); + + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] ) + break; + + if ( !V_stricmp( pToken, "}" ) ) + { + // pop + break; + } + else if ( !V_stricmp( pToken, "$file" ) || !V_stricmp( pToken, "$schemafile" ) || !V_stricmp( pToken, "$entschemafile" ) ) + { + // add file + VPC_Keyword_AddFile( NULL, pActiveFolderConfig ); + } + else if ( !V_stricmp( pToken, "$DynamicFile" ) ) + { + // add file + VPC_Keyword_AddFile( "dynamic", pActiveFolderConfig ); + } + else if ( !V_stricmp( pToken, "$FilePattern" ) ) + { + // glob the given pattern, add all files + VPC_Keyword_AddFilesByPattern(); + } +// THIS IS A LEGACY INCORRECT IMPLEMENTATION +// else if ( !V_stricmp( pToken, "$schemafile" ) ) +// { +// // add file +// VPC_Keyword_AddFile( "schema" ); +// } + else if ( !V_stricmp( pToken, "$implib" ) || + !V_stricmp( pToken, "$implibexternal" ) || + !V_stricmp( pToken, "-$implib" ) || + !V_stricmp( pToken, "-$implibexternal" ) ) + { + uint32 KeywordFlags = ( pToken[ 0 ] == '-' ) ? k_eVPCKeywordFlag_Remove : 0; + + if( V_stristr( pToken, "external" ) ) + KeywordFlags |= k_eVPCKeywordFlag_External; + + VPC_Keyword_ImportLibrary( KeywordFlags ); + } + else if ( !V_stricmp( pToken, "$lib" ) || + !V_stricmp( pToken, "$libexternal" ) || + !V_stricmp( pToken, "-$lib" ) || + !V_stricmp( pToken, "-$libexternal" ) ) + { + uint32 KeywordFlags = ( pToken[ 0 ] == '-' ) ? k_eVPCKeywordFlag_Remove : 0; + + if( V_stristr( pToken, "external" ) ) + KeywordFlags |= k_eVPCKeywordFlag_External; + + VPC_Keyword_LinkerLibrary( KeywordFlags ); + } + else if ( !V_stricmp( pToken, "-$file" ) ) + { + // remove file + VPC_Keyword_RemoveFile(); + } + else if ( !V_stricmp( pToken, "$folder" ) ) + { + // descend into subdirectory + VPC_Keyword_Folder( false, pActiveFolderConfig ); + } + else if ( !V_stricmp( pToken, "$unity" ) ) + { + VPC_Keyword_Folder( g_pVPC->IsUnity(), pActiveFolderConfig ); + } + else if ( !V_stricmp( pToken, "$configuration" ) ) + { + // read the folder-specific configuration. + VPC_Keyword_FolderConfiguration( &folderConfig ); + + // if we found a new config section, make it active and apply it to subsequent files + if ( folderConfig.BHasConfig() ) + pActiveFolderConfig = &folderConfig; + else + pActiveFolderConfig = NULL; + } + else + { + g_pVPC->VPCSyntaxError(); + } + } + + if ( bUnity ) + { + // Msg( "popping unity file %s\n", g_sUnityCurrent ); + g_pVPC->m_UnityStack.Pop(); + + if ( g_pVPC->m_UnityStack.Count() == 0 ) + g_pVPC->m_sUnityCurrent = NULL; + else + g_pVPC->m_sUnityCurrent = g_pVPC->m_UnityStack.Top(); + } + g_pVPC->GetProjectGenerator()->EndFolder(); +} + +//----------------------------------------------------------------------------- +// VPC_Keyword_Shaders +// +//----------------------------------------------------------------------------- +void VPC_Keyword_Shaders( int depth ) +{ + const char *pToken; + char shadersName[MAX_PATH]; + CUtlBuffer vpcBuffer; + CUtlVector< CUtlString > fxcList; + CUtlVector< CUtlString > vshList; + CUtlVector< CUtlString > pshList; + CUtlVector< CUtlString > vfxList; + CUtlVector< CUtlString > otherList; + int i; + bool bIgnoreRedundancyWarning; + + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, shadersName, sizeof( shadersName ) ) ) + { + return; + } + + g_pVPC->VPCStatus( false, "Parsing: %s", shadersName ); + g_pVPC->GetScript().PushScript( shadersName ); + + // parse the shader list file into types (fxc,vsh,psh) + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] ) + { + // end of file + break; + } + + if ( V_stristr( pToken, ".fxc" ) ) + { + fxcList.AddToTail( pToken ); + } + else if ( V_stristr( pToken, ".vsh" ) ) + { + vshList.AddToTail( pToken ); + } + else if ( V_stristr( pToken, ".psh" ) ) + { + pshList.AddToTail( pToken ); + } + else if ( V_stristr( pToken, ".vfx" ) ) + { + vfxList.AddToTail( pToken ); + } + else + { + otherList.AddToTail( pToken ); + } + } + + g_pVPC->GetScript().PopScript(); + + if ( !fxcList.Count() && + !vshList.Count() && + !pshList.Count() && + !vfxList.Count() && + !otherList.Count() ) + { + g_pVPC->VPCWarning( "No shaders found in %s", shadersName ); + return; + } + + // generate a vpc compatible file to generate the shader file hierarchy + vpcBuffer.SetBufferType( true, true ); + vpcBuffer.Printf( "$Folder \"Shader Source\" \n" ); + vpcBuffer.Printf( "{\n" ); + + // add the shader file as a convienence + vpcBuffer.Printf( "$file \"%s\"\n", shadersName ); + vpcBuffer.Printf( "{\n" ); + vpcBuffer.Printf( "$Configuration\n" ); + vpcBuffer.Printf( "{\n" ); + vpcBuffer.Printf( "$ExcludedFromBuild \"Yes\"\n" ); + vpcBuffer.Printf( "}\n" ); + vpcBuffer.Printf( "}\n" ); + + // fxc files + if ( fxcList.Count() ) + { + vpcBuffer.Printf( "$Folder \"fxc\" \n" ); + vpcBuffer.Printf( "{\n" ); + for ( i=0; i<fxcList.Count(); i++ ) + { + vpcBuffer.Printf( "$file \"%s\"\n", fxcList[i].String() ); + vpcBuffer.Printf( "{\n" ); + vpcBuffer.Printf( "$Configuration\n" ); + vpcBuffer.Printf( "{\n" ); + vpcBuffer.Printf( "$ExcludedFromBuild \"Yes\"\n" ); + vpcBuffer.Printf( "}\n" ); + vpcBuffer.Printf( "}\n" ); + } + vpcBuffer.Printf( "}\n" ); + } + + // vsh files + if ( vshList.Count() ) + { + vpcBuffer.Printf( "$Folder \"vsh\" \n" ); + vpcBuffer.Printf( "{\n" ); + for ( i=0; i<vshList.Count(); i++ ) + { + vpcBuffer.Printf( "$file \"%s\"\n", vshList[i].String() ); + vpcBuffer.Printf( "{\n" ); + vpcBuffer.Printf( "$Configuration\n" ); + vpcBuffer.Printf( "{\n" ); + vpcBuffer.Printf( "$ExcludedFromBuild \"Yes\"\n" ); + vpcBuffer.Printf( "}\n" ); + vpcBuffer.Printf( "}\n" ); + } + vpcBuffer.Printf( "}\n" ); + } + + // psh files + if ( pshList.Count() ) + { + vpcBuffer.Printf( "$Folder \"psh\" \n" ); + vpcBuffer.Printf( "{\n" ); + for ( i=0; i<pshList.Count(); i++ ) + { + vpcBuffer.Printf( "$file \"%s\"\n", pshList[i].String() ); + vpcBuffer.Printf( "{\n" ); + vpcBuffer.Printf( "$Configuration\n" ); + vpcBuffer.Printf( "{\n" ); + vpcBuffer.Printf( "$ExcludedFromBuild \"Yes\"\n" ); + vpcBuffer.Printf( "}\n" ); + vpcBuffer.Printf( "}\n" ); + } + vpcBuffer.Printf( "}\n" ); + } + + // vfx files + if ( vfxList.Count() ) + { + vpcBuffer.Printf( "$Folder \"vfx\" \n" ); + vpcBuffer.Printf( "{\n" ); + for ( i=0; i<vfxList.Count(); i++ ) + { + vpcBuffer.Printf( "$file \"%s\"\n", vfxList[i].String() ); + vpcBuffer.Printf( "{\n" ); + vpcBuffer.Printf( "$Configuration\n" ); + vpcBuffer.Printf( "{\n" ); + vpcBuffer.Printf( "$ExcludedFromBuild \"Yes\"\n" ); + vpcBuffer.Printf( "}\n" ); + vpcBuffer.Printf( "}\n" ); + } + vpcBuffer.Printf( "}\n" ); + } + + // other files + if ( otherList.Count() ) + { + // psh files + vpcBuffer.Printf( "$Folder \"other\" \n" ); + vpcBuffer.Printf( "{\n" ); + for ( i=0; i<otherList.Count(); i++ ) + { + vpcBuffer.Printf( "$file \"%s\"\n", otherList[i].String() ); + vpcBuffer.Printf( "{\n" ); + vpcBuffer.Printf( "$Configuration\n" ); + vpcBuffer.Printf( "{\n" ); + vpcBuffer.Printf( "$ExcludedFromBuild \"Yes\"\n" ); + vpcBuffer.Printf( "}\n" ); + vpcBuffer.Printf( "}\n" ); + } + vpcBuffer.Printf( "}\n" ); + } + + // end of shader folder + vpcBuffer.Printf( "}\n" ); + + // save parser + bIgnoreRedundancyWarning = g_pVPC->IsIgnoreRedundancyWarning(); + g_pVPC->SetIgnoreRedundancyWarning( true ); + + g_pVPC->GetScript().PushScript( "Internal List", (char*)vpcBuffer.Base() ); + + pToken = g_pVPC->GetScript().GetToken( true ); + if ( pToken && pToken[0] && !V_stricmp( pToken, "$folder" ) ) + { + VPC_Keyword_Folder( false ); + } + + // restore parser + g_pVPC->GetScript().PopScript(); + g_pVPC->SetIgnoreRedundancyWarning( bIgnoreRedundancyWarning ); +} + +//----------------------------------------------------------------------------- +// VPC_Keyword_Macro +// +//----------------------------------------------------------------------------- +enum MacroType_t { VPC_MACRO_VALUE, VPC_MACRO_EMPTY_STRING }; +void VPC_Keyword_Macro( MacroType_t eMacroType ) +{ + const char *pToken; + char macro[MAX_SYSTOKENCHARS]; + char value[MAX_SYSTOKENCHARS]; + + pToken = g_pVPC->GetScript().GetToken( false ); + if ( !pToken || !pToken[0] ) + g_pVPC->VPCSyntaxError(); + strcpy( macro, pToken ); + + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, value, sizeof( value ) ) ) + { + return; + } + + char environmentValue[MAX_SYSTOKENCHARS]; + if ( Sys_EvaluateEnvironmentExpression( value, "", environmentValue, sizeof( environmentValue ) ) ) + { + V_strncpy( value, environmentValue, sizeof( value ) ); + } + + g_pVPC->FindOrCreateMacro( macro, true, ( eMacroType == VPC_MACRO_VALUE ) ? value : "" ); +} + +//----------------------------------------------------------------------------- +// $MacroRequired <Macro> [DefaultValue] [Condition] +// $MacroRequiredAllowEmpty <Macro> [DefaultValue] [Condition] +// +// Forces a script to error if a macro that it depends on was not set. +// The Default will be used if the macro was not defined, otherwise error. +// This is to allow a required macro in a base script to have a concept +// of a default initialization value. +//----------------------------------------------------------------------------- +enum MacroRequiredType_t { VPC_MACRO_REQUIRED_NOT_EMPTY, VPC_MACRO_REQUIRED_ALLOW_EMPTY }; +void VPC_Keyword_MacroRequired( MacroRequiredType_t eMacroRequiredType ) +{ + char macroName[MAX_SYSTOKENCHARS]; + char macroDefaultValue[MAX_SYSTOKENCHARS]; + const char *pToken; + + macroDefaultValue[0] = '\0'; + + pToken = g_pVPC->GetScript().GetToken( false ); + if ( !pToken || !pToken[0] ) + { + g_pVPC->VPCSyntaxError(); + } + strcpy( macroName, pToken ); + + // optional default macro value or conditional + pToken = g_pVPC->GetScript().PeekNextToken( false ); + if ( pToken && pToken[0] ) + { + if ( pToken[0] == '[' ) + { + // evaulate argument as conditional + if ( !g_pVPC->EvaluateConditionalExpression( pToken ) ) + { + return; + } + } + else + { + // argument is a default macro value + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, macroDefaultValue, sizeof( macroDefaultValue ) ) ) + { + return; + } + } + } + + // find macro, needs to be present and non-empty + macro_t *pMacro = g_pVPC->FindOrCreateMacro( macroName, false, NULL ); + if ( !pMacro || ( eMacroRequiredType == VPC_MACRO_REQUIRED_NOT_EMPTY && !strlen( pMacro->value.String() ) ) ) + { + if ( macroDefaultValue[0] || ( eMacroRequiredType == VPC_MACRO_REQUIRED_ALLOW_EMPTY ) ) + { + g_pVPC->FindOrCreateMacro( macroName, true, macroDefaultValue ); + } + else + { + // In case we're in mksln showing a pacifier of dots. Make sure to show the error on a new line. + g_pVPC->VPCSyntaxError( "\n\nRequired Macro '%s', not defined or empty", macroName ); + } + } +} + +//----------------------------------------------------------------------------- +// VPC_Keyword_LoadAddressMacro +// +// $LoadAddressMacro <MacroName> +// { +// <ProjectName> <BaseAddress> +// } +// +// Specialized instruction to populate the load address macro based on a project +// name. +//----------------------------------------------------------------------------- +void VPC_Keyword_LoadAddressMacro( void ) +{ + char szProjectName[MAX_SYSTOKENCHARS]; + char szMacroName[MAX_SYSTOKENCHARS]; + char szBaseAddress[MAX_SYSTOKENCHARS]; + const char *pToken; + + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, szMacroName, sizeof( szMacroName ) ) ) + { + g_pVPC->GetScript().SkipBracedSection(); + return; + } + + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] || V_stricmp( pToken, "{" ) ) + { + g_pVPC->VPCSyntaxError(); + } + + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] ) + { + break; + } + strcpy( szProjectName, pToken ); + + if ( !V_stricmp( pToken, "}" ) ) + { + break; + } + else + { + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, szBaseAddress, sizeof( szBaseAddress ) ) ) + { + continue; + } + + if ( !V_stricmp( szProjectName, g_pVPC->GetLoadAddressName() ) ) + { + // set Macro + g_pVPC->FindOrCreateMacro( szMacroName, true, szBaseAddress ); + } + } + } +} + +//----------------------------------------------------------------------------- +// VPC_Keyword_LoadAddressMacroAlias +// +// $LoadAddressMacroAlias <Alias> +// { +// <ProjectName> +// } +// +// When evaluating $LoadAddressMacro/$LoadAddressMacroAuto, substitute all listed <ProjectName> entries with <Alias> +//----------------------------------------------------------------------------- +void VPC_Keyword_LoadAddressMacroAlias( void ) +{ + char szProjectName[MAX_SYSTOKENCHARS]; + char szAlias[MAX_SYSTOKENCHARS]; + const char *pToken; + + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, szAlias, sizeof( szAlias ) ) ) + { + g_pVPC->GetScript().SkipBracedSection(); + return; + } + + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] || V_stricmp( pToken, "{" ) ) + { + g_pVPC->VPCSyntaxError(); + } + + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] ) + { + break; + } + strcpy( szProjectName, pToken ); + + if ( !V_stricmp( pToken, "}" ) ) + { + break; + } + else + { + if ( !V_stricmp( szProjectName, g_pVPC->GetProjectName() ) ) + { + // set Macro and alias + g_pVPC->FindOrCreateMacro( "LOADADDRESSNAME", true, szAlias ); + g_pVPC->SetLoadAddressName( szAlias ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Internal_LoadAddressMacroAuto +// +// bPad - Differentiate between $LoadAddressMacroAuto and $LoadAddressMacroAuto_Padded +// implementations +// +// Specialized instruction to populate the load address macro based on a project +// name. +//----------------------------------------------------------------------------- +void Internal_LoadAddressMacroAuto( bool bPad ) +{ + char szProjectName[MAX_SYSTOKENCHARS]; + char szMacroName[MAX_SYSTOKENCHARS]; + char szBaseAddress[MAX_SYSTOKENCHARS]; + char szLength[MAX_SYSTOKENCHARS]; + const char *pToken; + + pToken = g_pVPC->GetScript().GetToken( false ); + if ( !pToken || !pToken[0] ) + { + g_pVPC->VPCSyntaxError(); + } + strcpy( szMacroName, pToken ); + + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, szBaseAddress, sizeof( szBaseAddress ) ) ) + { + g_pVPC->GetScript().SkipBracedSection(); + return; + } + unsigned int baseAddress = 0; + sscanf( szBaseAddress, "%x", &baseAddress ); + unsigned int iInitialBaseAddress = baseAddress; + + macro_t *pMacro = NULL; + int iSetEntryNum = 0; + int iSetBaseAddress = 0; + + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] || V_stricmp( pToken, "{" ) ) + { + g_pVPC->VPCSyntaxError(); + } + + int iEntryNum = 0; + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] ) + { + break; + } + strcpy( szProjectName, pToken ); + + if ( !V_stricmp( szProjectName, g_pVPC->GetLoadAddressName() ) ) + { + // set Macro + char szMacroValue[MAX_SYSTOKENCHARS]; + sprintf( szMacroValue, "0x%8.8x", baseAddress ); + + iSetEntryNum = iEntryNum; + iSetBaseAddress = baseAddress; + pMacro = g_pVPC->FindOrCreateMacro( szMacroName, true, szMacroValue ); + } + + if ( !V_stricmp( pToken, "}" ) ) + { + break; + } + else + { + unsigned int dllLength = 0; + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, szLength, sizeof( szLength ) ) ) + { + continue; + } + if ( strstr( szLength, "." ) ) + { + // assume float format + float fLength = 0; + sscanf( szLength, "%f", &fLength ); + dllLength = fLength * 1024.0f * 1024.0f; + } + else + { + sscanf( szLength, "%d", &dllLength ); + } + + if ( !bPad ) + { + dllLength = AlignValue( dllLength, 64 * 1024 ); //will align later when we actually set the darn thing + } + + if ( dllLength == 0 ) + { + g_pVPC->VPCSyntaxError( "$LoadAddressMacroAuto no longer supports 0 size dlls. Use $LoadAddressMacroAlias to have two orthogonal projects load in the same space" ); + } + + baseAddress += dllLength; + } + + ++iEntryNum; + } + + if ( bPad && pMacro ) + { + unsigned int iEndAddress; + if ( (iInitialBaseAddress >= 0x82000000) && (iInitialBaseAddress < 0x8C000000) ) + { + iEndAddress = 0x8BFFFFFF; + } + else + { + iEndAddress = 0x9BFFFFFF; + } + + // compute leftover unused address space + unsigned int iRemainingSpace = iEndAddress - baseAddress; + + int iPadPerEntry = iRemainingSpace / iEntryNum; + //iPadPerEntry = iPadPerEntry & ~(64 * 1024); //align DOWN to 64k + if ( iPadPerEntry > 0 ) + { + // set the base address again with padding added + iSetBaseAddress += iPadPerEntry * iSetEntryNum; + iSetBaseAddress = AlignValue( iSetBaseAddress, 64 * 1024 ); + + char szMacroValue[MAX_SYSTOKENCHARS]; + sprintf( szMacroValue, "0x%8.8x", iSetBaseAddress ); + + pMacro->value = szMacroValue; + } + } +} + +//----------------------------------------------------------------------------- +// VPC_Keyword_LoadAddressMacroAuto +// +// $LoadAddressMacroAuto <MacroName> <BaseAddress> +// { +// <ProjectName> <Length> +// } +// +// Specialized instruction to populate the load address macro based on a project +// name. +//----------------------------------------------------------------------------- +void VPC_Keyword_LoadAddressMacroAuto( void ) +{ + Internal_LoadAddressMacroAuto( false ); +} + +//----------------------------------------------------------------------------- +// VPC_Keyword_LoadAddressMacroAuto_Padded +// +// $LoadAddressMacroAuto_Padded <MacroName> <BaseAddress> +// { +// <ProjectName> <Length> +// } +// +// Specialized instruction to populate the load address macro based on a project +// name. Assumes the contained list is minimally packed and has free reign of +// space up to the limit. Finds unused space spreads it out evenly between +// each project +//----------------------------------------------------------------------------- +void VPC_Keyword_LoadAddressMacroAuto_Padded( void ) +{ + Internal_LoadAddressMacroAuto( true ); +} + +//----------------------------------------------------------------------------- +// VPC_SharedKeyword_Conditional +// $Conditional "CONDITIONNAME" "VALUE" +// +// Sets a conditional that can be used later in the script to affect later keywords. +// This works in both project and group scripts. +//----------------------------------------------------------------------------- +void VPC_SharedKeyword_Conditional() +{ + const char *pToken = g_pVPC->GetScript().GetToken( false ); + if ( !pToken || !pToken[0] ) + g_pVPC->VPCSyntaxError(); + + char name[MAX_SYSTOKENCHARS]; + if ( pToken[0] == '$' ) + { + // being nice to users, quietly remove the unwanted conditional prefix '$' + pToken++; + } + strcpy( name, pToken ); + + char value[MAX_SYSTOKENCHARS]; + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, value, sizeof( value ) ) ) + { + return; + } + + conditional_t *pConditional = g_pVPC->FindOrCreateConditional( name, true, CONDITIONAL_CUSTOM ); + if ( pConditional->type != CONDITIONAL_CUSTOM ) + { + // scripts cannot change any platform or game conditionals + g_pVPC->VPCSyntaxError( "$Conditional cannot be used on the reserved '$%s'", pConditional->upperCaseName.Get() ); + } + + char environmentValue[MAX_SYSTOKENCHARS]; + if ( Sys_EvaluateEnvironmentExpression( value, "0", environmentValue, sizeof( environmentValue ) ) ) + { + V_strncpy( value, environmentValue, sizeof( value ) ); + } + + g_pVPC->SetConditional( name, Sys_StringToBool( value ) ); +} + +//----------------------------------------------------------------------------- +// VPC_Keyword_IgnoreRedundancyWarning +// +//----------------------------------------------------------------------------- +void VPC_Keyword_IgnoreRedundancyWarning( void ) +{ + char value[MAX_SYSTOKENCHARS]; + + if ( !g_pVPC->GetScript().ParsePropertyValue( NULL, value, sizeof( value ) ) ) + { + return; + } + + bool bVal = Sys_StringToBool( value ); + g_pVPC->SetIgnoreRedundancyWarning( bVal ); +} + +//----------------------------------------------------------------------------- +// VPC_Keyword_Linux +// +//----------------------------------------------------------------------------- +void VPC_Keyword_Linux( void ) +{ + // always ignore everything in this block + // parsed and processed by a different tool + g_pVPC->GetScript().SkipBracedSection(); +} + +void VPC_PrepareToReadScript( const char *pInputScriptName, int depth, bool bQuiet, char* &pScriptBuffer, char szScriptName[MAX_PATH] ) +{ + if ( !depth ) + { + // startup initialization + g_pVPC->GetProjectGenerator()->StartProject(); + } + + V_strncpy( szScriptName, pInputScriptName, MAX_PATH ); + V_FixSlashes( szScriptName ); + + // always spew the root script + if ( !bQuiet ) + { + bool bSpew = ( depth == 0 ); + g_pVPC->VPCStatus( bSpew, "Parsing: %s", szScriptName ); + } + + // parse the text script + if ( !Sys_Exists( szScriptName ) ) + { + g_pVPC->VPCError( "Cannot open %s", szScriptName ); + } + + // load it with the file expansions to compute it's CRC, so we notice if new matching files appear on disk + // and regenerate the project correctly. + int scriptLen = Sys_LoadTextFileWithIncludes( szScriptName, &pScriptBuffer, true ); + if ( scriptLen < 0 ) + { + // unexpected due to existence check + g_pVPC->VPCError( "Cannot open %s", szScriptName ); + } + + g_pVPC->AddScriptToCRCCheck( szScriptName, CRC32_ProcessSingleBuffer( pScriptBuffer, scriptLen ) ); + + delete pScriptBuffer; + Sys_LoadTextFileWithIncludes( szScriptName, &pScriptBuffer, false ); + + g_pVPC->GetScript().PushScript( szScriptName, pScriptBuffer ); +} + +//----------------------------------------------------------------------------- +// Adds the current VPC file to the 'VPC Script' file, setting all the +// custom builds steps needed to verify the .vcproj is up to date +//----------------------------------------------------------------------------- +void VPC_AddCurrentVPCScriptToProjectFolder( bool bDoCRCCheck ) +{ + // skip including VPC scripts if NOVPC is defined + if( g_pVPC->EvaluateConditionalExpression( "$NOVPC" ) ) + return; + + g_pVPC->GetProjectGenerator()->StartFolder( "VPC Scripts" ); + g_pVPC->GetProjectGenerator()->StartFile( g_pVPC->GetScript().GetName(), false ); + + // only emit the extra information on windows, and only for the project vpc + if ( bDoCRCCheck && g_pVPC->EvaluateConditionalExpression( "$WINDOWS" ) ) + { + CUtlString sSentinel = CFmtStr( "$PROJECTDIR\\%s.sentinel", g_pVPC->GetScript().GetName() ).Access(); + bool bShouldSkip; + + CUtlVector< CUtlString > configurationNames; + g_pVPC->GetProjectGenerator()->GetAllConfigurationNames( configurationNames ); + char rgchCRCCheckExpanded[2048]; rgchCRCCheckExpanded[0] = '\0'; + for ( int i=0; i < configurationNames.Count(); i++ ) + { + g_pVPC->GetProjectGenerator()->StartConfigurationBlock( configurationNames[i], true ); + g_pVPC->GetProjectGenerator()->StartPropertySection( KEYWORD_CUSTOMBUILDSTEP, &bShouldSkip ); + // this will write a sentinel file so we have a clear build target so we can know the last time we checked + g_pVPC->GetProjectGenerator()->HandleProperty( "$Description", CFmtStr("\"Running VPC CRC Check - %s\"", g_pVPC->GetScript().GetName() ) ); + g_pVPC->GetProjectGenerator()->HandleProperty( "$CommandLine", CFmtStr( "\"rem IncrediBuild_AllowOverlap\n%s\necho crc_complete > %s\"", g_pVPC->GetMacroValue( "CRCCHECK" ), sSentinel.Get() ) ); + g_pVPC->GetProjectGenerator()->HandleProperty( "$Outputs", sSentinel ); + g_pVPC->GetProjectGenerator()->EndPropertySection( KEYWORD_CUSTOMBUILDSTEP ); + g_pVPC->GetProjectGenerator()->EndConfigurationBlock(); + } + } + + g_pVPC->GetProjectGenerator()->EndFile(); + g_pVPC->GetProjectGenerator()->EndFolder(); +} + +void VPC_HandleIncludeStatement( int depth, bool bQuiet, void (*CallbackFn)( const char *pScriptName, int depth, bool bQuiet ) ) +{ + char szBigBuffer[MAX_SYSTOKENCHARS]; + if ( g_pVPC->GetScript().ParsePropertyValue( NULL, szBigBuffer, sizeof( szBigBuffer ) ) ) + { + // recurse into and run + char *pScriptBuffer; + char szFixedScriptName[MAX_PATH]; + VPC_PrepareToReadScript( szBigBuffer, depth+1, bQuiet, pScriptBuffer, szFixedScriptName ); + + VPC_AddCurrentVPCScriptToProjectFolder( false ); + + CallbackFn( szBigBuffer, depth+1, bQuiet ); + free( pScriptBuffer ); + + // restore state + g_pVPC->GetScript().PopScript(); + } +} + +void VPC_HandleProjectCommands( const char *pUnusedScriptName, int depth, bool bQuiet ) +{ + const char *pToken; + + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] ) + break; + + if ( !V_stricmp( pToken, "}" ) ) + { + break; + } + else if ( !V_stricmp( pToken, "$include" ) ) + { + VPC_HandleIncludeStatement( depth, bQuiet, VPC_HandleProjectCommands ); + } + else if ( !V_stricmp( pToken, "$Folder" ) ) + { + // root level folder + VPC_Keyword_Folder( false ); + } + else if ( !V_stricmp( pToken, "$Unity" ) ) + { + // root level folder + VPC_Keyword_Folder( g_pVPC->IsUnity() ); + } + else if ( !V_stricmp( pToken, "$File" ) ) + { + // add root level file + VPC_Keyword_AddFile(); + } + else if ( !V_stricmp( pToken, "$SchemaFile" ) ) + { + // add root level file + VPC_Keyword_AddFile( "schema" ); + } + else if ( !V_stricmp( pToken, "-$File" ) ) + { + // remove root level file + VPC_Keyword_RemoveFile(); + } + else if ( !V_stricmp( pToken, "$Shaders" ) ) + { + // add root level shaders folder + VPC_Keyword_Shaders( 0 ); + } + else if ( !V_stricmp( pToken, "$macro" ) ) + { + VPC_Keyword_Macro( VPC_MACRO_VALUE ); + } + else + { + g_pVPC->VPCSyntaxError(); + } + } +} + + +void WriteCRCCheckFile( const char *pVCProjFilename ) +{ + char szFilename[MAX_PATH]; + V_snprintf( szFilename, sizeof( szFilename ), "%s." VPCCRCCHECK_FILE_EXTENSION, pVCProjFilename ); + + FILE *fp = fopen( szFilename, "wt" ); + if ( !fp ) + { + g_pVPC->VPCError( "Unable to open %s to write CRCs into.", szFilename ); + } + + fprintf( fp, "%s\n", VPCCRCCHECK_FILE_VERSION_STRING ); + // add the executable crc + char vpcExeAbsPath[MAX_PATH]; vpcExeAbsPath[0] = '\0'; + CRC32_t nCRCFromFileContents = 0; + if ( Sys_GetExecutablePath( vpcExeAbsPath, sizeof( vpcExeAbsPath ) ) ) + { + char *pBuffer; + int cbVPCExe = Sys_LoadFile( vpcExeAbsPath, (void**)&pBuffer ); + + // Calculate the CRC from the contents of the file. + nCRCFromFileContents = CRC32_ProcessSingleBuffer( pBuffer, cbVPCExe ); + delete [] pBuffer; + } + + const char *vpcExePath = vpcExeAbsPath; + + char vpcExeRelPath[MAX_PATH]; vpcExeRelPath[0] = '\0'; + if ( V_MakeRelativePath( vpcExeAbsPath, g_pVPC->GetProjectPath(), vpcExeRelPath, sizeof( vpcExeRelPath ) ) ) + { + vpcExePath = vpcExeRelPath; + } + + fprintf( fp, "%8.8x %s\n", ( unsigned int ) nCRCFromFileContents, vpcExePath ); + + // add the supplemental string crc + fprintf( fp, "%s\n", g_pVPC->GetCRCString() ); + + CUtlDict<int, int> filenameDict( k_eDictCompareTypeFilenames ); + for ( int i=0; i < g_pVPC->m_ScriptList.Count(); i++ ) + { + scriptList_t *pScript = &g_pVPC->m_ScriptList[i]; + + // Use the dictionary to prevent duplicate file CRCs being written in here. + if ( filenameDict.Find( pScript->m_scriptName.String() ) == filenameDict.InvalidIndex() ) + { + filenameDict.Insert( pScript->m_scriptName.String(), 1 ); + + // [crc] [filename] + fprintf( fp, "%8.8x %s\n", ( unsigned int ) pScript->m_crc, pScript->m_scriptName.Get() ); + } + } + + fclose( fp ); +} + + +// +// This is called when it's done parsing a project. If there were any $SchemaFile +// entries in the project, then we will make this project depend on schemacompiler +// (via $AdditionalProjectDependencies). +// +// This fixes full rebuild problems where it's building a project that uses schemacompiler +// at the same time as it's building schemacompiler. This usually screws up when +// it tries to copy the new schemacompiler.exe to game\bin but it's in use. +// +void VPC_ForceAdditionalSchemaDependencies( const char *pProjectName ) +{ + if ( g_pVPC->m_SchemaFiles.Count() == 0 ) + return; + + // Add "$BASE;SchemaCompiler" to $AdditionalProjectDependencies. + CUtlVector< CUtlString > configurationNames; + g_pVPC->GetProjectGenerator()->GetAllConfigurationNames( configurationNames ); + for ( int i=0; i < configurationNames.Count(); i++ ) + { + g_pVPC->GetProjectGenerator()->StartConfigurationBlock( configurationNames[i].String(), false ); + g_pVPC->GetProjectGenerator()->StartPropertySection( KEYWORD_GENERAL, NULL ); + + g_pVPC->GetProjectGenerator()->HandleProperty( g_pOption_AdditionalProjectDependencies, "$BASE;SchemaCompiler" ); + + g_pVPC->GetProjectGenerator()->EndPropertySection( KEYWORD_GENERAL ); + g_pVPC->GetProjectGenerator()->EndConfigurationBlock(); + } +} + + +//----------------------------------------------------------------------------- +// VPC_Keyword_Project +// +//----------------------------------------------------------------------------- +void VPC_Keyword_Project( int depth, bool bQuiet ) +{ + char szProjectName[MAX_PATH]; + + // check for optional project name + const char *pToken = g_pVPC->GetScript().PeekNextToken( false ); + + if ( pToken && pToken[0] && V_stricmp( pToken, "{" ) ) + { + // get optional project name + pToken = g_pVPC->GetScript().GetToken( false ); + if ( !pToken || !pToken[0] ) + { + g_pVPC->VPCSyntaxError(); + } + + g_pVPC->ResolveMacrosInString( pToken, szProjectName, sizeof( szProjectName ) ); + + if ( g_pVPC->IsDecorateProject() ) + { + g_pVPC->DecorateProjectName( szProjectName ); + } + } + else + { + CUtlString strName = g_pVPC->GetProjectGenerator()->GetProjectName(); + V_strncpy( szProjectName, strName.String(), sizeof( szProjectName ) ); + } + + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] || V_stricmp( pToken, "{" ) ) + g_pVPC->VPCSyntaxError(); + + VPC_HandleProjectCommands( NULL, depth, bQuiet ); + + // the unnamed project does not get written, once it is named it will be written on closing scope + if ( V_stricmp( szProjectName, "UNNAMED" ) ) + { + VPC_ForceAdditionalSchemaDependencies( szProjectName ); + + // change name + g_pVPC->GetProjectGenerator()->SetProjectName( szProjectName ); + + // need to do this at the end of parsing the project, so we have all the macros needed + VPC_AddCurrentVPCScriptToProjectFolder( true ); + + g_pVPC->GetProjectGenerator()->EndProject(); + g_pVPC->m_bGeneratedProject = true; + } +} + +static const char* fileTypes[] = +{ + "c", "cpp", "cxx", "cc", + "h", "hh", "hxx", "hpp", "" +}; +bool VPC_IsBuiltInFileType( const char *extension ) +{ + for (int i = 0; i < V_ARRAYSIZE(fileTypes); i++) + { + if ( !V_stricmp( fileTypes[i], extension ) ) + return true; + } + + return false; +} + +void VPC_Keyword_CustomBuildStep( void ) +{ + bool bAllowNextLine = false; + CUtlVector<CUtlString> extensions; + + const char *pToken = NULL; + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( bAllowNextLine ); + if ( !pToken || !pToken[0] ) + break; + + // Is this a conditional expression? + if ( pToken[0] == '[' ) + { + if ( extensions.Count() == 0 ) + { + g_pVPC->VPCSyntaxError( "Conditional specified on a $CustomBuildStep without any extensions preceding it." ); + } + + if ( !g_pVPC->EvaluateConditionalExpression( pToken ) ) + { + extensions.Remove( extensions.Count() - 1 ); + } + + continue; + } + + if ( !V_stricmp( pToken, "\\" ) ) + { + bAllowNextLine = true; + continue; + } + else + { + bAllowNextLine = false; + } + + if ( VPC_IsBuiltInFileType( pToken ) ) + { + g_pVPC->VPCSyntaxError( "Cannot define custom build steps for built in file type: %s", pToken); + } + + CUtlString string = pToken; + extensions.AddToTail( string ); + + // check for another optional file + pToken = g_pVPC->GetScript().PeekNextToken( bAllowNextLine ); + if ( !pToken || !pToken[0] ) + break; + } + + + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] || V_strcmp( pToken, "{" ) ) + { + g_pVPC->VPCSyntaxError( "Missing section for CustomBuildStep" ); + } + else if ( extensions.Count() == 0 ) + { + g_pVPC->GetScript().SkipBracedSection(); + return; + } + else + { + const char *pScriptSave = g_pVPC->GetScript().GetData(); + while ( 1 ) + { + pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] ) + break; + + if ( !V_stricmp( pToken, "}" ) ) + { + // end of section + break; + } + } + + CUtlString buildsteps; + if ( g_pVPC->GetScript().GetData() > pScriptSave ) + { + CUtlString tempString; + tempString.SetDirect( pScriptSave, int( g_pVPC->GetScript().GetData() - pScriptSave - 1 ) ); + buildsteps += "$Configuration\n{\n$CustomBuildStep\n{"; + buildsteps += tempString + "}\n}\n"; + } + + if ( !buildsteps.IsEmpty() ) + { + FOR_EACH_VEC( extensions, i ) + { + g_pVPC->m_CustomBuildSteps.Insert( extensions[i], buildsteps ); + } + } + } +} + +void VPC_ParseProjectScriptParameters( const char *szScriptName, int depth, bool bQuiet ) +{ + while ( 1 ) + { + const char *pToken = g_pVPC->GetScript().GetToken( true ); + if ( !pToken || !pToken[0] ) + { + // end of file + break; + } + + if ( !V_stricmp( pToken, "$include" ) ) + { + VPC_HandleIncludeStatement( depth, bQuiet, VPC_ParseProjectScriptParameters ); + } + else if ( !V_stricmp( pToken, "$configuration" ) ) + { + VPC_Keyword_Configuration(); + } + else if ( !V_stricmp( pToken, "$project" ) ) + { + VPC_Keyword_Project( depth, bQuiet ); + } + else if ( !V_stricmp( pToken, "$macro" ) ) + { + VPC_Keyword_Macro( VPC_MACRO_VALUE ); + } + else if ( !V_stricmp( pToken, "$MacroEmptyString" ) ) + { + VPC_Keyword_Macro( VPC_MACRO_EMPTY_STRING ); + } + else if ( !V_stricmp( pToken, "$MacroRequired" ) ) + { + VPC_Keyword_MacroRequired( VPC_MACRO_REQUIRED_NOT_EMPTY ); + } + else if ( !V_stricmp( pToken, "$MacroRequiredAllowEmpty" ) ) + { + VPC_Keyword_MacroRequired( VPC_MACRO_REQUIRED_ALLOW_EMPTY ); + } + else if ( !V_stricmp( pToken, "$LoadAddressMacro" ) ) + { + VPC_Keyword_LoadAddressMacro(); + } + else if ( !V_stricmp( pToken, "$LoadAddressMacroAlias" ) ) + { + VPC_Keyword_LoadAddressMacroAlias(); + } + else if ( !V_stricmp( pToken, "$LoadAddressMacroAuto" ) ) + { + VPC_Keyword_LoadAddressMacroAuto(); + } + else if ( !V_stricmp( pToken, "$LoadAddressMacroAuto_Padded" ) ) + { + VPC_Keyword_LoadAddressMacroAuto_Padded(); + } + else if ( !V_stricmp( pToken, "$IgnoreRedundancyWarning" ) ) + { + VPC_Keyword_IgnoreRedundancyWarning(); + } + else if ( !V_stricmp( pToken, "$Linux" ) ) + { + VPC_Keyword_Linux(); + } + else if ( !V_stricmp( pToken, "$CustomBuildStep" ) ) + { + VPC_Keyword_CustomBuildStep(); + } + else if ( !V_stricmp( pToken, "$Conditional" ) ) + { + VPC_SharedKeyword_Conditional(); + } + else + { + g_pVPC->VPCSyntaxError(); + } + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CVPC::ParseProjectScript( const char *pScriptName, int depth, bool bQuiet, bool bWriteCRCCheckFile ) +{ + char *pScriptBuffer; + char szScriptName[MAX_PATH]; + + VPC_PrepareToReadScript( pScriptName, depth, bQuiet, pScriptBuffer, szScriptName ); + + int cMissingFilesPreParse = g_pVPC->GetMissingFilesCount(); + + if ( !depth ) + { + // create reserved $ROOTSCRIPT - tracks the root script + FindOrCreateMacro( "ROOTSCRIPT", true, szScriptName ); + + // create reserved $PROJECTNAME - tracks the undecorated pure project name + // $(ProjectName) can be auto-decorated, making it unuseable by scripts expecting a pure project name + FindOrCreateMacro( "PROJECTNAME", true, g_pVPC->GetProjectName() ); + + // create reserved $LOADADDRESSNAME - defaults to project name but can be aliased with $LoadAddressMacroAlias + FindOrCreateMacro( "LOADADDRESSNAME", true, g_pVPC->GetLoadAddressName() ); + + // create reserved $CRCCHECK + // The CRCs themselves are dumped into theproject.vcproj.vpc_crc (in VPC_WriteCRCCheckFile), so all this does + // is point vpccrccheck.exe at it with "vpccrccheck.exe -crc2 theproject.vcproj" + // scripts add the terminal /n if they append, after referencing $CRCCHECK + // needs to be quoted to work with /dp which puts " (platform) " in project names, + + CUtlString crcCheckString; + crcCheckString = "if exist $QUOTE$SRCDIR\\devtools\\bin\\" VPCCRCCHECK_EXE_FILENAME "$QUOTE $QUOTE$SRCDIR\\devtools\\bin\\" VPCCRCCHECK_EXE_FILENAME "$QUOTE -crc2 $QUOTE"; + crcCheckString += g_pVPC->GetOutputFilename(); + crcCheckString += "$QUOTE\nif ERRORLEVEL 1 exit /b 1"; + g_pVPC->FindOrCreateMacro( "CRCCHECK", true, crcCheckString.Get() ); + + // create reserved $PROJECTDIR + char szProjectRootPath[MAX_PATH]; + V_snprintf( szProjectRootPath, sizeof( szProjectRootPath ), "%s", g_pVPC->GetProjectPath() ); + V_RemoveDotSlashes( szProjectRootPath ); + SetMacro( "PROJECTDIR", szProjectRootPath, true ); + + // reset + g_pVPC->m_SchemaFiles.Purge(); + + // reset unity file tracking (it's per project) + g_pVPC->m_UnityFilesSeen.RemoveAll(); + g_pVPC->m_UnityStack.Clear(); + g_pVPC->m_sUnityCurrent = NULL; + } + + VPC_ParseProjectScriptParameters( szScriptName, depth, bQuiet ); + + free( pScriptBuffer ); + + // for safety, force callers to restore to proper state + g_pVPC->GetScript().PopScript(); + + if ( !depth ) + { + // at end of all processing, don't write crc checks if we're missing files + if ( bWriteCRCCheckFile && g_pVPC->GetMissingFilesCount() == cMissingFilesPreParse ) + { + // Finally write out the file with all the CRCs in it. This is referenced by the $CRCCHECK macro in the prebuild steps. + WriteCRCCheckFile( g_pVPC->GetOutputFilename() ); + } + + g_pVPC->m_ScriptList.Purge(); + g_pVPC->RemoveScriptCreatedMacros(); // Remove any macros that came from the script file. + } + + return true; +} + +void CVPC::AddScriptToCRCCheck( const char *pScriptName, CRC32_t crc ) +{ + for ( int i = 0; i < m_ScriptList.Count(); i++ ) + { + if ( !V_stricmp( m_ScriptList[i].m_scriptName, pScriptName ) ) + { + // update + g_pVPC->m_ScriptList[i].m_crc = crc; + return; + } + } + + int index = g_pVPC->m_ScriptList.AddToTail(); + g_pVPC->m_ScriptList[index].m_scriptName = pScriptName; + g_pVPC->m_ScriptList[index].m_crc = crc; +} + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +// +// Schema Script Generation +// +// Temporary - Once the schema workflow settles down, this schema-specific code should be +// at minimum moved into its own file, and ideally generalized so that VPC +// has a minimum of embedded schema-specific logic. +// +// +// +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// + +KeyValues *ConfigPreprocessorSettingsAsKV( CSpecificConfig *pConfig ); +struct SchemaFileInfo_t +{ + bool bIsCppFile; + char szFile[MAX_PATH]; + char szGeneratedFile[MAX_PATH]; +}; + +void VPC_FakeKeyword_SchemaFolder( CBaseProjectDataCollector *pDataCollector ) +{ + if ( g_pVPC->m_SchemaFiles.Count() == 0 ) + return; + + macro_t *pMacro = g_pVPC->FindOrCreateMacro( "NOSCHEMACOMPILER", false, NULL ); + if ( pMacro && atoi( pMacro->value.Get() ) ) + return; + + CUtlString platformName = g_pVPC->GetTargetPlatformName(); + V_strlower( platformName.Get() ); + const char *pPlatformName = platformName.String(); + + CUtlVector<SchemaFileInfo_t> schemaFileInfos; + schemaFileInfos.AddMultipleToTail( g_pVPC->m_SchemaFiles.Count() ); + + char schemaCompilerPath[MAX_PATH]; + g_pVPC->ResolveMacrosInString( "$SRCDIR/devtools/bin/schemacompiler.dll", schemaCompilerPath, sizeof( schemaCompilerPath ) ); + + CUtlString schemaInputs; + CUtlString schemaOutputs; + char szExt[MAX_PATH]; + + schemaInputs += schemaCompilerPath; + + for ( int i = 0; i < g_pVPC->m_SchemaFiles.Count(); i++ ) + { + if ( !g_pVPC->m_SchemaFiles[i].String() ) + continue; + + schemaInputs += ";"; + schemaInputs += g_pVPC->m_SchemaFiles[i]; + + V_ExtractFileExtension( g_pVPC->m_SchemaFiles[i], szExt, sizeof(szExt) ); + SchemaFileInfo_t &fileInfo = schemaFileInfos[i]; + + V_strncpy( fileInfo.szFile, g_pVPC->m_SchemaFiles[i], sizeof(fileInfo.szFile) ); + V_FixSlashes( fileInfo.szFile, '/' ); + + char szNoExt[MAX_PATH]; + V_StripExtension( fileInfo.szFile, szNoExt, sizeof(szNoExt) ); + char szBase[MAX_PATH]; + V_FileBase( fileInfo.szFile, szBase, sizeof(szBase) ); + char szPath[MAX_PATH]; + V_ExtractFilePath( fileInfo.szFile, szPath, sizeof(szPath) ); + + char szGenRelPath[MAX_PATH]; + + if ( IsCFileExtension( szExt ) ) + { + fileInfo.bIsCppFile = true; + V_snprintf( szGenRelPath, sizeof(szGenRelPath), + "generated_code_%s_%s/%s_schema_cpp_gen.cpp", g_pVPC->GetProjectName(), pPlatformName, szBase ); + } + else + { + fileInfo.bIsCppFile = false; + V_snprintf( szGenRelPath, sizeof(szGenRelPath), + "generated_code_%s_%s/%s_schema_gen.cpp", g_pVPC->GetProjectName(), pPlatformName, szBase ); + } + + V_strncpy( fileInfo.szGeneratedFile, szGenRelPath, sizeof(fileInfo.szGeneratedFile) ); + V_FixSlashes( fileInfo.szGeneratedFile, '/' ); + + schemaOutputs += fileInfo.szGeneratedFile; + schemaOutputs += ";"; + } + + char szSchemaOutAnchorPath[MAX_PATH]; + V_snprintf( szSchemaOutAnchorPath, sizeof( szSchemaOutAnchorPath ), + "generated_code_%s_%s/%s_schema_anchor.cpp", g_pVPC->GetProjectName(), pPlatformName, g_pVPC->GetProjectName() ); + V_FixSlashes( szSchemaOutAnchorPath, '/' ); + schemaOutputs += szSchemaOutAnchorPath; + schemaOutputs += ";"; + + char szSchemaPath[MAX_PATH]; + V_snprintf( szSchemaPath, sizeof( szSchemaPath ), "%s_%s.schproj", g_pVPC->GetProjectName(), pPlatformName ); + + ////////////////////////////////////////////////////////////////////////// + + CUtlBuffer vpcBuffer; + + char schemaCompilerExePath[MAX_PATH]; + g_pVPC->ResolveMacrosInString( "$SRCDIR/devtools/bin/schemacompiler.exe", schemaCompilerExePath, sizeof( schemaCompilerExePath ) ); + V_FixSlashes( schemaCompilerExePath ); + + vpcBuffer.SetBufferType( true, true ); + vpcBuffer.Printf( "$Folder \"Autogenerated Schema Files\" \n" ); + vpcBuffer.Printf( "{\n" ); + vpcBuffer.Printf( + "$File \"%s\"\n" + "{\n" + " $Configuration\n" + " {\n" + " $CustomBuildStep\n" + " {\n" + " $CommandLine \"%s -schproj $(InputPath) -config $(ConfigurationName)\"\n" + " $Description \"Schema Compiler for [$(ConfigurationName)] $(InputName)\"\n" + " $Outputs \"%s\"\n" + " $AdditionalDependencies \"%s\"\n" + " }\n" + " }\n" + "}\n", szSchemaPath, schemaCompilerExePath, schemaOutputs.Get(), schemaInputs.Get() ); + + static const char *schemaConfiguration = + "{\n" + " $Configuration\n" + " {\n" + " $Compiler\n" + " {\n" + //" $PreprocessorDefinitions \"NO_MEMOVERRIDE_NEW_DELETE\"\n" + " $Create/UsePrecompiledHeader \"Not Using Precompiled Headers\"\n" + " }\n" + " }\n" + "}\n"; + + vpcBuffer.Printf( "$Folder \"Cpp Schema Wrappers\" \n" ); + { + vpcBuffer.Printf( "{\n" ); + + for ( int i = 0; i < schemaFileInfos.Count(); ++i ) + { + if ( schemaFileInfos[i].bIsCppFile ) + { + vpcBuffer.Printf( "$File \"%s\"\n", schemaFileInfos[i].szGeneratedFile ); + vpcBuffer.Printf( schemaConfiguration ); + } + } + + vpcBuffer.Printf( "}\n" ); + } + + vpcBuffer.Printf( "$Folder \"Header-Generated Files\" \n" ); + { + vpcBuffer.Printf( "{\n" ); + + for ( int i = 0; i < schemaFileInfos.Count(); ++i ) + { + if ( !schemaFileInfos[i].bIsCppFile ) + { + vpcBuffer.Printf( "$File \"%s\"\n", schemaFileInfos[i].szGeneratedFile ); + vpcBuffer.Printf( schemaConfiguration ); + } + } + + vpcBuffer.Printf( "}\n" ); + } + + vpcBuffer.Printf( "$File \"%s\"\n", szSchemaOutAnchorPath ); + vpcBuffer.Printf( schemaConfiguration ); + vpcBuffer.Printf( "}\n" ); + + // save parser + bool bIgnoreRedundancyWarning = g_pVPC->IsIgnoreRedundancyWarning(); + g_pVPC->SetIgnoreRedundancyWarning( true ); + g_pVPC->GetScript().PushScript( "Internal List [Schema]", (char*)vpcBuffer.Base() ); + + const char *pToken = g_pVPC->GetScript().GetToken( true ); + if ( pToken && pToken[0] && !V_stricmp( pToken, "$folder" ) ) + { + VPC_Keyword_Folder( false ); + } + + // restore parser + g_pVPC->GetScript().PopScript(); + g_pVPC->SetIgnoreRedundancyWarning( bIgnoreRedundancyWarning ); + + ////////////////////////////////////////////////////////////////////////// + + KeyValues *pOutKeyValues = new KeyValues("schproj"); + pOutKeyValues->SetString( "project_name", g_pVPC->GetProjectName() ); + pOutKeyValues->SetString( "platform_name", pPlatformName ); + pOutKeyValues->SetString( "anchor_path", szSchemaOutAnchorPath ); + char dmeTargetFolder[MAX_PATH]; + g_pVPC->ResolveMacrosInString( "$SRCDIR\\public", dmeTargetFolder, sizeof( dmeTargetFolder ) ); + pOutKeyValues->SetString( "dme_target_folder", dmeTargetFolder ); + + KeyValues *pOutAllConfigs = new KeyValues( "configs" ); + pOutKeyValues->AddSubKey( pOutAllConfigs ); + + for ( int i = pDataCollector->m_BaseConfigData.m_Configurations.First(); + i != pDataCollector->m_BaseConfigData.m_Configurations.InvalidIndex(); + i = pDataCollector->m_BaseConfigData.m_Configurations.Next( i ) ) + { + CSpecificConfig *pConfig = pDataCollector->m_BaseConfigData.m_Configurations[i]; + pOutAllConfigs->AddSubKey( ConfigPreprocessorSettingsAsKV( pConfig ) ); + } + + char szNum[64]; + { + KeyValues *pOutInputs = new KeyValues( "inputs" ); + int nInput = 0; + pOutKeyValues->AddSubKey( pOutInputs ); + for ( int i = 0; i < schemaFileInfos.Count(); i++ ) + { + V_snprintf( szNum, sizeof(szNum), "%03d", nInput++ ); + + SchemaFileInfo_t &fileInfo = schemaFileInfos[i]; + + KeyValues *pOutFile = new KeyValues( szNum ); + pOutInputs->AddSubKey( pOutFile ); + + pOutFile->SetString( "generation_target", fileInfo.szGeneratedFile ); + pOutFile->SetBool( "is_cpp", fileInfo.bIsCppFile ); + pOutFile->SetString( "input", fileInfo.szFile ); + } + } + CUtlBuffer tmpBuf; + tmpBuf.SetBufferType( true, true ); + pOutKeyValues->RecursiveSaveToFile( tmpBuf, 0 ); + pOutKeyValues->deleteThis(); + + FILE *fp = fopen( szSchemaPath, "wt" ); + if ( !fp ) + { + g_pVPC->VPCStatus( true, "Error Saving File: '%s'", szSchemaPath ); + } + else + { + fwrite( tmpBuf.Base(), sizeof(char), tmpBuf.TellMaxPut(), fp ); + fclose( fp ); + } +} + +KeyValues *ConfigPreprocessorSettingsAsKV( CSpecificConfig * pConfig ) +{ + KeyValues *pOutConfig = new KeyValues( pConfig->GetConfigName() ); + + char szNum[64]; + KeyValues *pInConfigKV = pConfig->m_pKV; + + ////////////////////////////////////////////////////////////////////////// + // write defines + + { + KeyValues *pOutDefines = new KeyValues( "defines" ); + pOutConfig->AddSubKey( pOutDefines ); + + CSplitString outStrings( pInConfigKV->GetString( g_pOption_PreprocessorDefinitions ), + (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + + int nDefine = 0; + + for ( int i=0; i < outStrings.Count(); i++ ) + { + V_snprintf( szNum, sizeof(szNum), "%03d", nDefine++ ); + pOutDefines->SetString( szNum, outStrings[i] ); + } + + // change #1001922 from source2 did the pBuf... + char pBuf[512]; + for ( int i=0; i < g_pVPC->m_Macros.Count(); i++ ) + { + macro_t *pMacro = &g_pVPC->m_Macros[i]; + + if ( pMacro->m_bSetupDefineInProjectFile ) + { + V_snprintf( szNum, sizeof(szNum), "%03d", nDefine++ ); + V_snprintf( pBuf, sizeof(pBuf), "%s=%s", pMacro->name.Get(), pMacro->value.Get() ); + pOutDefines->SetString( szNum, pBuf ); + } + } + } + + ////////////////////////////////////////////////////////////////////////// + // write includes + + KeyValues *pOutIncludes = new KeyValues( "includes" ); + pOutConfig->AddSubKey( pOutIncludes ); + + int nInclude = 0; + + CSplitString outStrings( pInConfigKV->GetString( g_pOption_AdditionalIncludeDirectories ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < outStrings.Count(); i++ ) + { + V_snprintf( szNum, sizeof(szNum), "%03d", nInclude++ ); + + char sDir[MAX_PATH]; + V_StrSubst( outStrings[i], "$(IntDir)", "$(OBJ_DIR)", sDir, sizeof( sDir ) ); + V_FixSlashes( sDir, '/' ); + pOutIncludes->SetString( szNum, sDir ); + } + + return pOutConfig; +} diff --git a/external/vpc/utils/vpc/scriptsource.cpp b/external/vpc/utils/vpc/scriptsource.cpp new file mode 100644 index 0000000..82583e0 --- /dev/null +++ b/external/vpc/utils/vpc/scriptsource.cpp @@ -0,0 +1,565 @@ +//===================== Copyright (c) Valve Corporation. All Rights Reserved. ====================== +// +// +// +//================================================================================================== + +#include "vpc.h" + +#define MAX_SCRIPT_STACK_SIZE 32 + +CScript::CScript() +{ + m_ScriptName = "(empty)"; + m_nScriptLine = 0; + m_pScriptData = NULL; + m_pScriptLine = &m_nScriptLine; + + m_Token[0] = '\0'; + m_PeekToken[0] = '\0'; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +const char *CScript::SkipWhitespace( const char *data, bool *pHasNewLines, int* pNumLines ) +{ + int c; + + while ( ( c = *data ) <= ' ' ) + { + if ( c == '\n' ) + { + if ( pNumLines ) + { + (*pNumLines)++; + } + + if ( pHasNewLines ) + { + *pHasNewLines = true; + } + } + else if ( !c ) + { + return ( NULL ); + } + + data++; + } + + return data; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +const char *CScript::SkipToValidToken( const char *data, bool *pHasNewLines, int* pNumLines ) +{ + int c; + + for ( ;; ) + { + data = SkipWhitespace( data, pHasNewLines, pNumLines ); + + c = *data; + if ( !c ) + { + break; + } + + if ( c == '/' && data[1] == '/' ) + { + // skip double slash comments + data += 2; + while ( *data && *data != '\n' ) + { + data++; + } + if ( *data && *data == '\n' ) + { + data++; + if ( pNumLines ) + { + (*pNumLines)++; + } + if ( pHasNewLines ) + { + *pHasNewLines = true; + } + } + } + else if ( c == '/' && data[1] == '*' ) + { + // skip /* */ comments + data += 2; + while ( *data && ( *data != '*' || data[1] != '/' ) ) + { + if ( *data == '\n' ) + { + if ( pNumLines ) + { + (*pNumLines)++; + } + if ( pHasNewLines ) + { + *pHasNewLines = true; + } + } + data++; + } + + if ( *data ) + { + data += 2; + } + } + else + { + break; + } + } + + return data; +} + +//----------------------------------------------------------------------------- +// The next token should be an open brace. +// Skips until a matching close brace is found. +// Internal brace depths are properly skipped. +//----------------------------------------------------------------------------- +void CScript::SkipBracedSection( const char** dataptr, int* numlines ) +{ + const char* token; + int depth; + + depth = 0; + do + { + token = GetToken( dataptr, true, numlines ); + if ( token[1] == '\0' ) + { + if ( token[0] == '{' ) + depth++; + else if ( token[0] == '}' ) + depth--; + } + } + while( depth && *dataptr ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CScript::SkipRestOfLine( const char** dataptr, int* numlines ) +{ + const char* p; + int c; + + p = *dataptr; + while ( ( c = *p++ ) != '\0' ) + { + if ( c == '\n' ) + { + if ( numlines ) + ( *numlines )++; + break; + } + } + *dataptr = p; +} + +//----------------------------------------------------------------------------- +// Does not corrupt results obtained with GetToken(). +//----------------------------------------------------------------------------- +const char* CScript::PeekNextToken( const char *dataptr, bool bAllowLineBreaks ) +{ + // save the primary token, about to be corrupted + char savedToken[MAX_SYSTOKENCHARS]; + V_strncpy( savedToken, m_Token, MAX_SYSTOKENCHARS ); + + const char *pSaved = dataptr; + const char *pToken = GetToken( &pSaved, bAllowLineBreaks, NULL ); + + // restore + V_strncpy( m_PeekToken, pToken, MAX_SYSTOKENCHARS ); + V_strncpy( m_Token, savedToken, MAX_SYSTOKENCHARS ); + + return m_PeekToken; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +const char *CScript::GetToken( const char **dataptr, bool allowLineBreaks, int *pNumLines ) +{ + char c; + char endSymbol; + int len; + bool hasNewLines; + const char* data; + + c = 0; + data = *dataptr; + len = 0; + m_Token[0] = 0; + hasNewLines = false; + + // make sure incoming data is valid + if ( !data ) + { + *dataptr = NULL; + return m_Token; + } + + for ( ;; ) + { + // skip whitespace + data = SkipWhitespace( data, &hasNewLines, pNumLines ); + if ( !data ) + { + *dataptr = NULL; + return m_Token; + } + + if ( hasNewLines && !allowLineBreaks ) + { + *dataptr = data; + return m_Token; + } + + c = *data; + + if ( c == '/' && data[1] == '/' ) + { + // skip double slash comments + data += 2; + while ( *data && *data != '\n' ) + { + data++; + } + if ( *data && *data == '\n' ) + { + if ( !allowLineBreaks ) + continue; + + data++; + if ( pNumLines ) + { + (*pNumLines)++; + } + } + } + else if ( c =='/' && data[1] == '*' ) + { + // skip /* */ comments + data += 2; + while ( *data && ( *data != '*' || data[1] != '/' ) ) + { + if ( *data == '\n' && pNumLines ) + { + (*pNumLines)++; + } + data++; + } + + if ( *data ) + { + data += 2; + } + } + else + break; + } + + // handle scoped strings "???" <???> [???] + if ( c == '\"' || c == '<' || c == '[') + { + bool bConditionalExpression = false; + endSymbol = '\0'; + switch ( c ) + { + case '\"': + endSymbol = '\"'; + break; + case '<': + endSymbol = '>'; + break; + case '[': + bConditionalExpression = true; + endSymbol = ']'; + break; + } + + // want to preserve entire conditional expession [blah...blah...blah] + // maintain a conditional's open/close scope characters + if ( !bConditionalExpression ) + { + // skip past scope character + data++; + } + + for ( ;; ) + { + c = *data++; + + if ( c == endSymbol || !c ) + { + if ( c == endSymbol && bConditionalExpression ) + { + // keep end symbol + m_Token[len++] = c; + } + + m_Token[len] = 0; + *dataptr = (char*)data; + return m_Token; + } + + if ( len < MAX_SYSTOKENCHARS-1 ) + { + m_Token[len++] = c; + } + } + } + + // parse a regular word + do + { + if ( len < MAX_SYSTOKENCHARS ) + { + m_Token[len++] = c; + } + + data++; + c = *data; + } + while ( c > ' ' ); + + if ( len >= MAX_SYSTOKENCHARS ) + { + len = 0; + } + + m_Token[len] = '\0'; + *dataptr = (char*)data; + + return m_Token; +} + +void CScript::PushScript( const char *pFilename ) +{ + // parse the text script + if ( !Sys_Exists( pFilename ) ) + { + g_pVPC->VPCError( "Cannot open %s", pFilename ); + } + + char *pScriptBuffer; + Sys_LoadTextFileWithIncludes( pFilename, &pScriptBuffer, false ); + + PushScript( pFilename, pScriptBuffer, 1, true ); +} + +void CScript::PushScript( const char *pScriptName, const char *pScriptData, int nScriptLine, bool bFreeScriptAtPop ) +{ + if ( m_ScriptStack.Count() > MAX_SCRIPT_STACK_SIZE ) + { + g_pVPC->VPCError( "PushScript( scriptname=%s ) - stack overflow\n", pScriptName ); + } + + // Push the current state onto the stack. + m_ScriptStack.Push( GetCurrentScript() ); + + // Set their state as the current state. + m_ScriptName = pScriptName; + m_pScriptData = pScriptData; + m_nScriptLine = nScriptLine; + m_bFreeScriptAtPop = bFreeScriptAtPop; +} + +void CScript::PushCurrentScript() +{ + PushScript( m_ScriptName.Get(), m_pScriptData, m_nScriptLine, m_bFreeScriptAtPop ); +} + +CScriptSource CScript::GetCurrentScript() +{ + return CScriptSource( m_ScriptName.Get(), m_pScriptData, m_nScriptLine, m_bFreeScriptAtPop ); +} + +void CScript::RestoreScript( const CScriptSource &scriptSource ) +{ + m_ScriptName = scriptSource.GetName(); + m_pScriptData = scriptSource.GetData(); + m_nScriptLine = scriptSource.GetLine(); + m_bFreeScriptAtPop = scriptSource.IsFreeScriptAtPop(); +} + +void CScript::PopScript() +{ + if ( m_ScriptStack.Count() == 0 ) + { + g_pVPC->VPCError( "PopScript(): stack is empty" ); + } + + if ( m_bFreeScriptAtPop && m_pScriptData ) + { + free( (void *)m_pScriptData ); + } + + // Restore the top entry on the stack and pop it off. + const CScriptSource &state = m_ScriptStack.Top(); + m_ScriptName = state.GetName(); + m_pScriptData = state.GetData(); + m_nScriptLine = state.GetLine(); + m_bFreeScriptAtPop = state.IsFreeScriptAtPop(); + + m_ScriptStack.Pop(); +} + +void CScript::EnsureScriptStackEmpty() +{ + if ( m_ScriptStack.Count() != 0 ) + { + g_pVPC->VPCError( "EnsureScriptStackEmpty(): script stack is not empty!" ); + } +} + +void CScript::SpewScriptStack() +{ + if ( m_ScriptStack.Count() ) + { + CUtlString str; + + // emit stack with current at top + str += "Script Stack:\n"; + str += CFmtStr( " %s Line:%d\n", m_ScriptName.String(), m_nScriptLine ); + for ( int i = m_ScriptStack.Count() - 1; i >= 0; i-- ) + { + if ( i == 0 && !m_ScriptStack[i].GetData() && m_ScriptStack[i].GetLine() <= 0 ) + { + // ignore empty bottom of stack + break; + } + + str += CFmtStr( " %s Line:%d\n", m_ScriptStack[i].GetName(), m_ScriptStack[i].GetLine() ); + } + str += "\n"; + + Log_Msg( LOG_VPC, "%s", str.String() ); + } +} + +const char *CScript::GetToken( bool bAllowLineBreaks ) +{ + return GetToken( &m_pScriptData, bAllowLineBreaks, m_pScriptLine ); +} + +const char *CScript::PeekNextToken( bool bAllowLineBreaks ) +{ + return PeekNextToken( m_pScriptData, bAllowLineBreaks ); +} + +void CScript::SkipRestOfLine() +{ + SkipRestOfLine( &m_pScriptData, m_pScriptLine ); +} + +void CScript::SkipBracedSection() +{ + SkipBracedSection( &m_pScriptData, m_pScriptLine ); +} + +void CScript::SkipToValidToken() +{ + m_pScriptData = SkipToValidToken( m_pScriptData, NULL, m_pScriptLine ); +} + +//----------------------------------------------------------------------------- +// Handles expressions of the form <$BASE> <xxx> ... <xxx> [condition] +// Output is a concatenated string. +// +// Returns true if expression should be used, false if it should be ignored due +// to an optional condition that evaluated false. +//----------------------------------------------------------------------------- +bool CScript::ParsePropertyValue( const char *pBaseString, char *pOutBuff, int outBuffSize ) +{ + const char **pScriptData = &m_pScriptData; + int *pScriptLine = m_pScriptLine; + + const char *pToken; + const char *pNextToken; + char *pOut = pOutBuff; + int remaining = outBuffSize-1; + int len; + bool bAllowNextLine = false; + char buffer1[MAX_SYSTOKENCHARS]; + char buffer2[MAX_SYSTOKENCHARS]; + bool bResult = true; + + while ( 1 ) + { + pToken = GetToken( pScriptData, bAllowNextLine, pScriptLine ); + if ( !pToken || !pToken[0] ) + g_pVPC->VPCSyntaxError(); + + pNextToken = PeekNextToken( *pScriptData, false ); + if ( !pNextToken || !pNextToken[0] ) + { + // current token is last token + // last token can be optional conditional, need to identify + // backup and reparse up to last token + if ( pToken && pToken[0] == '[' ) + { + // last token is an optional conditional + bResult = g_pVPC->EvaluateConditionalExpression( pToken ); + break; + } + } + + if ( !V_stricmp( pToken, "\\" ) ) + { + bAllowNextLine = true; + continue; + } + else + { + bAllowNextLine = false; + } + + if ( !V_stricmp( pToken, "\\n" ) ) + { + pToken = "\n"; + } + + if ( pToken[0] ) + { + // handle reserved macro + if ( !pBaseString ) + pBaseString = ""; + strcpy( buffer1, pToken ); + Sys_ReplaceString( buffer1, "$base", pBaseString, buffer2, sizeof( buffer2 ) ); + + g_pVPC->ResolveMacrosInString( buffer2, buffer1, sizeof( buffer1 ) ); + + len = strlen( buffer1 ); + if ( remaining < len ) + len = remaining; + + if ( len > 0 ) + { + memcpy( pOut, buffer1, len ); + pOut += len; + remaining -= len; + } + } + + pToken = PeekNextToken( *pScriptData, false ); + if ( !pToken || !pToken[0] || !V_stricmp( pNextToken, "}" ) ) + break; + } + + *pOut++ = '\0'; + + if ( !pOutBuff[0] ) + g_pVPC->VPCSyntaxError(); + + return bResult; +}
\ No newline at end of file diff --git a/external/vpc/utils/vpc/scriptsource.h b/external/vpc/utils/vpc/scriptsource.h new file mode 100644 index 0000000..4564eb1 --- /dev/null +++ b/external/vpc/utils/vpc/scriptsource.h @@ -0,0 +1,95 @@ +//===================== Copyright (c) Valve Corporation. All Rights Reserved. ====================== +// +// This module manages a stack of "script sources". +// +//================================================================================================== + +#ifndef SCRIPTSOURCE_H +#define SCRIPTSOURCE_H +#ifdef _WIN32 +#pragma once +#endif + +#define MAX_SYSPRINTMSG 4096 +#define MAX_SYSTOKENCHARS 4096 + +class CScriptSource +{ +public: + CScriptSource() + { + Set( "", NULL, 0, false ); + } + + CScriptSource( const char *pScriptName, const char *pScriptData, int nScriptLine, bool bFreeScriptAtPop ) + { + Set( pScriptName, pScriptData, nScriptLine, bFreeScriptAtPop ); + } + + void Set( const char *pScriptName, const char *pScriptData, int nScriptLine, bool bFreeScriptAtPop ) + { + m_ScriptName = pScriptName; + m_pScriptData = pScriptData; + m_nScriptLine = nScriptLine; + m_bFreeScriptAtPop = bFreeScriptAtPop; + } + + const char *GetName() const { return m_ScriptName.Get(); } + const char *GetData() const { return m_pScriptData; } + int GetLine() const { return m_nScriptLine; } + bool IsFreeScriptAtPop() const { return m_bFreeScriptAtPop; } + +private: + CUtlString m_ScriptName; + const char *m_pScriptData; + int m_nScriptLine; + bool m_bFreeScriptAtPop; +}; + +class CScript +{ +public: + CScript(); + + void PushScript( const char *pFilename ); + void PushScript( const char *pScriptName, const char *ppScriptData, int nScriptLine = 1, bool bFreeScriptAtPop = false ); + void PushCurrentScript(); + void PopScript(); + CScriptSource GetCurrentScript(); + void RestoreScript( const CScriptSource &scriptSource ); + void EnsureScriptStackEmpty(); + void SpewScriptStack(); + + const char *GetName() const { return m_ScriptName.Get(); } + const char *GetData() const { return m_pScriptData; } + int GetLine() const { return m_nScriptLine; } + + const char *GetToken( bool bAllowLineBreaks ); + const char *PeekNextToken( bool bAllowLineBreaks ); + void SkipRestOfLine(); + void SkipBracedSection(); + void SkipToValidToken(); + + bool ParsePropertyValue( const char *pBaseString, char *pOutBuff, int outBuffSize ); + +private: + const char *SkipWhitespace( const char *data, bool *pHasNewLines, int *pNumLines ); + const char *SkipToValidToken( const char *data, bool *pHasNewLines, int *pNumLines ); + void SkipBracedSection( const char **dataptr, int *numlines ); + void SkipRestOfLine( const char **dataptr, int *numlines ); + const char *PeekNextToken( const char *dataptr, bool bAllowLineBreaks ); + const char *GetToken( const char **dataptr, bool allowLineBreaks, int *pNumLines ); + + CUtlStack< CScriptSource > m_ScriptStack; + + int m_nScriptLine; + int *m_pScriptLine; + const char *m_pScriptData; + CUtlString m_ScriptName; + bool m_bFreeScriptAtPop; + + char m_Token[MAX_SYSTOKENCHARS]; + char m_PeekToken[MAX_SYSTOKENCHARS]; +}; + +#endif // SCRIPTSOURCE_H diff --git a/external/vpc/utils/vpc/solutiongenerator_codelite.cpp b/external/vpc/utils/vpc/solutiongenerator_codelite.cpp new file mode 100644 index 0000000..604d861 --- /dev/null +++ b/external/vpc/utils/vpc/solutiongenerator_codelite.cpp @@ -0,0 +1,285 @@ +//====== Copyright 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#include "vpc.h" +#include "dependencies.h" +#include "utlgraph.h" + +class CSolutionGenerator_CodeLite : public IBaseSolutionGenerator { +public: + CSolutionGenerator_CodeLite() { + m_nIndent = 0; + m_fp = NULL; + } + + virtual void GenerateSolutionFile( const char *pSolutionFilename, CUtlVector<CDependency_Project*> &projects ) { + char szSolutionName[MAX_PATH]; + V_FileBase( pSolutionFilename, szSolutionName, MAX_PATH ); + + char szSolutionFileBaseName[MAX_PATH]; + + // Default extension. + char szTmpSolutionFilename[MAX_PATH]; + if ( !V_GetFileExtension( pSolutionFilename ) ) { + V_strncpy( szSolutionFileBaseName, pSolutionFilename, sizeof( szSolutionFileBaseName ) ); + V_snprintf( szTmpSolutionFilename, sizeof( szTmpSolutionFilename ), "%s.workspace", pSolutionFilename ); + pSolutionFilename = szTmpSolutionFilename; + } else { + V_StripExtension( pSolutionFilename, szSolutionFileBaseName, sizeof( szSolutionFileBaseName ) ); + } + + Msg( "\nWriting CodeLite workspace %s.\n\n", pSolutionFilename ); + + // Write the file. + m_fp = fopen( pSolutionFilename, "wt" ); + if ( !m_fp ) + g_pVPC->VPCError( "Can't open %s for writing.", pSolutionFilename ); + + Write( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" ); + Write( "<CodeLite_Workspace Name=\"%s\" Database=\"%s.tags\">\n", szSolutionName, szSolutionFileBaseName ); + + ++m_nIndent; + Write( "<Project Name=\"all\" Path=\"%s.project\" Active=\"Yes\"/>\n", szSolutionFileBaseName); + for ( int i=0; i < projects.Count(); i++ ) { + CDependency_Project *pCurProject = projects[i]; + project_t *pProjectT = &g_pVPC->m_Projects[ pCurProject->m_iProjectIndex ]; + + char szProjectFileBaseName[MAX_PATH]; + V_StripExtension( pCurProject->m_ProjectFilename.String(), szProjectFileBaseName, sizeof( szProjectFileBaseName ) ); + + Write( "<Project Name=\"%s\" Path=\"%s.project\"/>\n", pProjectT->name.String(), szProjectFileBaseName ); + } + + Write( "<BuildMatrix>\n" ); + ++m_nIndent; + Write( "<WorkspaceConfiguration Name=\"Debug\" Selected=\"no\">\n" ); + ++m_nIndent; + Write( "<Project Name=\"all\" ConfigName=\"Debug\"/>\n" ); + for ( int i=0; i < projects.Count(); i++ ) { + CDependency_Project *pCurProject = projects[i]; + project_t *pProjectT = &g_pVPC->m_Projects[ pCurProject->m_iProjectIndex ]; + + Write( "<Project Name=\"%s\" ConfigName=\"Debug\"/>\n", pProjectT->name.String() ); + } + --m_nIndent; + Write( "</WorkspaceConfiguration>\n" ); + + Write( "<WorkspaceConfiguration Name=\"Release\" Selected=\"yes\">\n" ); + ++m_nIndent; + Write( "<Project Name=\"all\" ConfigName=\"Release\"/>\n" ); + for ( int i=0; i < projects.Count(); i++ ) { + CDependency_Project *pCurProject = projects[i]; + project_t *pProjectT = &g_pVPC->m_Projects[ pCurProject->m_iProjectIndex ]; + + Write( "<Project Name=\"%s\" ConfigName=\"Release\"/>\n", pProjectT->name.String() ); + } + --m_nIndent; + Write( "</WorkspaceConfiguration>\n" ); + --m_nIndent; + Write( "</BuildMatrix>\n" ); + --m_nIndent; + Write( "</CodeLite_Workspace>\n" ); + + fclose( m_fp ); + + WriteBuildOrderProject( szSolutionFileBaseName, projects ); + } + + void WriteBuildOrderProject( const char *pszSolutionFileBaseName, CUtlVector<CDependency_Project*> &projects ) { + // write out a project with no files to encode the build order (dependencies) + char szProjectFileName[MAX_PATH]; + V_snprintf( szProjectFileName, sizeof( szProjectFileName ), "%s.project", pszSolutionFileBaseName ); + + m_nIndent = 0; + m_fp = fopen( szProjectFileName, "wt" ); + if ( !m_fp ) + g_pVPC->VPCError( "Can't open %s for writing.", szProjectFileName ); + + Write( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" ); + Write( "<CodeLite_Project Name=\"all\" InternalType=\"\">\n" ); + { + ++m_nIndent; + Write( "<Description/>\n" ); + Write( "<Dependencies/>\n" ); + Write( "<Settings Type=\"Static Library\">\n" ); + { + ++m_nIndent; + Write( "<GlobalSettings>\n" ); + ++m_nIndent; + Write( "<Compiler Options=\"\" C_Options=\"\">\n" ); + ++m_nIndent; + Write( "<IncludePath Value=\"\"/>\n" ); + --m_nIndent; + Write( "</Compiler>\n" ); + Write( "<Linker Options=\"\">\n" ); + ++m_nIndent; + Write( "<LibraryPath Value=\"\"/>\n" ); + --m_nIndent; + Write( "</Linker>\n" ); + Write( "<ResourceCompiler Options=\"\"/>\n" ); + --m_nIndent; + Write( "</GlobalSettings>\n" ); + + Write( "<Configuration Name=\"Debug\" CompilerType=\"gnu g++\" DebuggerType=\"GNU gdb debugger\" Type=\"Executable\" BuildCmpWithGlobalSettings=\"append\" BuildLnkWithGlobalSettings=\"append\" BuildResWithGlobalSettings=\"append\">\n" ); +#if 0 + ++m_nIndent; + Write( "<Compiler Options=\"-g\" C_Options="" Required="yes" PreCompiledHeader="">\n" ); + ++m_nIndent; + Write( "<IncludePath Value=\"\"/>" ); + --m_nIndent; + --m_nIndent; +#endif + Write( "</Configuration>\n" ); + + Write( "<Configuration Name=\"Release\" CompilerType=\"gnu g++\" DebuggerType=\"GNU gdb debugger\" Type=\"Executable\" BuildCmpWithGlobalSettings=\"append\" BuildLnkWithGlobalSettings=\"append\" BuildResWithGlobalSettings=\"append\">\n" ); +#if 0 + ++m_nIndent; + Write( "<Compiler Options=\"-g\" C_Options="" Required="yes" PreCompiledHeader="">\n" ); + ++m_nIndent; + Write( "<IncludePath Value=\"\"/>" ); + --m_nIndent; + --m_nIndent; +#endif + Write( "</Configuration>\n" ); + + --m_nIndent; + } + Write( "</Settings>\n" ); + + --m_nIndent; + + CUtlGraph<int, int> dependencyGraph; + + // walk the project list building a dependency graph + for ( int i=0; i < projects.Count(); i++ ) + { + + CDependency_Project *pCurProject = projects[i]; + + CUtlVector<CDependency_Project*> additionalProjectDependencies; + ResolveAdditionalProjectDependencies( pCurProject, projects, additionalProjectDependencies ); + + //project_t *pProjectT = &g_projects[ pCurProject->m_iProjectIndex ]; + //printf( "%s depends on\n", pProjectT->name.String() ); + + for ( int iTestProject=0; iTestProject < projects.Count(); iTestProject++ ) { + if ( i == iTestProject ) + continue; + + // do I depend on anyone? + CDependency_Project *pTestProject = projects[iTestProject]; + int dependsOnFlags = k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse; + if ( pCurProject->DependsOn( pTestProject, dependsOnFlags ) || additionalProjectDependencies.Find( pTestProject ) != additionalProjectDependencies.InvalidIndex() ) { + // add an edge from this project to the one it depends on + dependencyGraph.AddEdge( i, iTestProject, 1 ); + //printf( " %s -> %s\n", projects[ i ]->m_ProjectName.String(), + // projects[ iTestProject ]->m_ProjectName.String() ); + + } + } + } + + Write( "<Dependencies Name=\"Debug\">\n" ); + ++m_nIndent; + + CUtlVector<int> visitedList; + for( int i = 0; i < projects.Count(); i++ ) { + TraverseFrom( projects, dependencyGraph, visitedList, i ); + } + --m_nIndent; + Write( "</Dependencies>\n" ); + + Write( "<Dependencies Name=\"Release\">\n" ); + ++m_nIndent; + visitedList.Purge(); + for( int i = 0; i < projects.Count(); i++ ) { + TraverseFrom( projects, dependencyGraph, visitedList, i ); + } + --m_nIndent; + Write( "</Dependencies>\n" ); + + } + Write( "</CodeLite_Project>\n" ); + fclose( m_fp ); + } + + void TraverseFrom( CUtlVector<CDependency_Project*> &projects, CUtlGraph<int, int> &dependencyGraph, CUtlVector<int> &visitedList, int root ) { + CUtlGraphVisitor<int> visitor( dependencyGraph ); + + if ( visitedList.Find( root ) != visitedList.InvalidIndex() ) + return; + + // this project has no dependencies, just emit it + if ( !visitor.Begin( root ) ) + { + Write( "<Project Name=\"%s\"/>\n", projects[ root ]->m_ProjectName.String() ); + visitedList.AddToTail( root ); + return; + } + + // printf( "considering %i (%s)\n", root, projects[ root ]->m_ProjectName.String() ); + + while ( visitor.Advance() ) { + // printf( "%i (%s) depends on %i (%s)\n", root, projects[ root ]->m_ProjectName.String(), visitor.CurrentNode(), projects[ visitor.CurrentNode() ]->m_ProjectName.String() ); + TraverseFrom( projects, dependencyGraph, visitedList, visitor.CurrentNode() ); + } + + Write( "<Project Name=\"%s\"/>\n", projects[ root ]->m_ProjectName.String() ); + visitedList.AddToTail( root ); + // printf( "emitting %i (%s)\n", root, projects[ root ]->m_ProjectName.String() ); + } + + void ResolveAdditionalProjectDependencies( + CDependency_Project *pCurProject, + CUtlVector<CDependency_Project*> &projects, + CUtlVector<CDependency_Project*> &additionalProjectDependencies ) { + for ( int i=0; i < pCurProject->m_AdditionalProjectDependencies.Count(); i++ ) { + const char *pLookingFor = pCurProject->m_AdditionalProjectDependencies[i].String(); + + int j; + for ( j=0; j < projects.Count(); j++ ) { + if ( V_stricmp( projects[j]->m_ProjectName.String(), pLookingFor ) == 0 ) + break; + } + + if ( j == projects.Count() ) + g_pVPC->VPCError( "Project %s lists '%s' in its $AdditionalProjectDependencies, but there is no project by that name in the selected projects.", pCurProject->GetName(), pLookingFor ); + + additionalProjectDependencies.AddToTail( projects[j] ); + } + } + + const char* FindInFile( const char *pFilename, const char *pFileData, const char *pSearchFor ) { + const char *pPos = V_stristr( pFileData, pSearchFor ); + if ( !pPos ) + g_pVPC->VPCError( "Can't find ProjectGUID in %s.", pFilename ); + + return pPos + V_strlen( pSearchFor ); + } + + void Write( const char *pMsg, ... ) { + char sOut[8192]; + + va_list marker; + va_start( marker, pMsg ); + V_vsnprintf( sOut, sizeof( sOut ), pMsg, marker ); + va_end( marker ); + + for ( int i=0; i < m_nIndent; i++ ) + fprintf( m_fp, " " ); + + fprintf( m_fp, "%s", sOut ); + } + + FILE *m_fp; + int m_nIndent; +}; + + +static CSolutionGenerator_CodeLite g_SolutionGenerator_CodeLite; +IBaseSolutionGenerator* GetSolutionGenerator_CodeLite() { + return &g_SolutionGenerator_CodeLite; +} diff --git a/external/vpc/utils/vpc/solutiongenerator_makefile.cpp b/external/vpc/utils/vpc/solutiongenerator_makefile.cpp new file mode 100644 index 0000000..827d930 --- /dev/null +++ b/external/vpc/utils/vpc/solutiongenerator_makefile.cpp @@ -0,0 +1,341 @@ +//====== Copyright 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#include "vpc.h" +#include "dependencies.h" + + +extern void V_MakeAbsoluteCygwinPath( char *pOut, int outLen, const char *pRelativePath ); + +extern void MakeFriendlyProjectName( char *pchProject ) +{ + int strLen = V_strlen( pchProject ); + for ( int j = 0; j < strLen; j++ ) + { + if ( pchProject[j] == ' ' ) + pchProject[j] = '_'; + if ( pchProject[j] == '(' || pchProject[j] == ')' ) + { + V_memmove( pchProject+j, pchProject+j+1, strLen - j ); + strLen--; + } + } +} + + +class CSolutionGenerator_Makefile : public IBaseSolutionGenerator +{ +private: + void GenerateProjectNames( CUtlVector<CUtlString> &projNames, CUtlVector<CDependency_Project*> &projects ) + { + for ( int i=0; i < projects.Count(); i++ ) + { + CDependency_Project *pCurProject = projects[i]; + char szFriendlyName[256]; + V_strncpy( szFriendlyName, pCurProject->m_ProjectName.String(), sizeof(szFriendlyName) ); + MakeFriendlyProjectName( szFriendlyName ); + projNames[ projNames.AddToTail() ] = szFriendlyName; + } + } + +public: + virtual void GenerateSolutionFile( const char *pSolutionFilename, CUtlVector<CDependency_Project*> &projects ) + { + // Default extension. + char szTmpSolutionFilename[MAX_PATH]; + if ( !V_GetFileExtension( pSolutionFilename ) ) + { + V_snprintf( szTmpSolutionFilename, sizeof( szTmpSolutionFilename ), "%s.mak", pSolutionFilename ); + pSolutionFilename = szTmpSolutionFilename; + } + + const char *pTargetPlatformName; + // forestw: if PLATFORM macro exists we should use its value, this accommodates overrides of PLATFORM in .vpc files + macro_t *pMacro = g_pVPC->FindOrCreateMacro( "PLATFORM", false, NULL ); + if ( pMacro ) + pTargetPlatformName = pMacro->value.String(); + else + pTargetPlatformName = g_pVPC->GetTargetPlatformName(); + + Msg( "\nWriting master makefile %s.\n\n", pSolutionFilename ); + + // Write the file. + FILE *fp = fopen( pSolutionFilename, "wt" ); + if ( !fp ) + g_pVPC->VPCError( "Can't open %s for writing.", pSolutionFilename ); + + fprintf( fp, "# VPC MASTER MAKEFILE\n\n" ); + + fprintf( fp, "# Disable built-in rules/variables. We don't depend on them, and they slow down make processing.\n" ); + fprintf( fp, "MAKEFLAGS += --no-builtin-rules --no-builtin-variables\n" ); + fprintf( fp, "ifeq ($(MAKE_VERBOSE),)\n" ); + fprintf( fp, "MAKEFLAGS += --no-print-directory\n" ); + fprintf( fp, "endif\n\n" ); + + fprintf( fp, "ifneq \"$(LINUX_TOOLS_PATH)\" \"\"\n" ); + fprintf( fp, " TOOL_PATH = $(LINUX_TOOLS_PATH)/\n" ); + fprintf( fp, " SHELL := $(TOOL_PATH)bash\n" ); + fprintf( fp, "else\n" ); + fprintf( fp, " SHELL := /bin/bash\n" ); + fprintf( fp, "endif\n" ); + + fprintf( fp, "ifndef NO_CHROOT\n" ); + if ( V_stristr( pTargetPlatformName, "64" ) ) + { + fprintf( fp, " export CHROOT_NAME ?= $(subst /,_,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))amd64\n"); + fprintf( fp, " RUNTIME_NAME ?= steamrt_scout_amd64\n"); + fprintf( fp, " CHROOT_PERSONALITY ?= linux\n"); + } + else if ( V_stristr( pTargetPlatformName, "32" ) ) + { + fprintf( fp, " export CHROOT_NAME ?= $(subst /,_,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))\n"); + fprintf( fp, " RUNTIME_NAME ?= steamrt_scout_i386\n"); + fprintf( fp, " CHROOT_PERSONALITY ?= linux32\n"); + } + else + { + g_pVPC->VPCError( "TargetPlatform (%s) doesn't seem to be 32 or 64 bit, can't configure chroot parameters", pTargetPlatformName ); + } + fprintf( fp, " CHROOT_CONF := /etc/schroot/chroot.d/$(CHROOT_NAME).conf\n"); + fprintf( fp, " CHROOT_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))/tools/runtime/linux)\n\n"); + + fprintf( fp, " export MAKE_CHROOT = 1\n" ); + fprintf( fp, " ifneq (\"$(SCHROOT_CHROOT_NAME)\", \"$(CHROOT_NAME)\")\n"); + fprintf( fp, " SHELL := schroot --chroot $(CHROOT_NAME) -- /bin/bash\n"); + fprintf( fp, " endif\n"); + fprintf( fp, "endif\n\n" ); // NO_CHROOT + + fprintf( fp, "ECHO = $(TOOL_PATH)echo\n" ); + fprintf( fp, "ETAGS = $(TOOL_PATH)etags\n" ); + fprintf( fp, "FIND = $(TOOL_PATH)find\n" ); + fprintf( fp, "UNAME = $(TOOL_PATH)uname\n" ); + fprintf( fp, "XARGS = $(TOOL_PATH)xargs\n" ); + fprintf( fp, "\n"); + + fprintf( fp, "# to control parallelism, set the MAKE_JOBS environment variable\n" ); + fprintf( fp, "ifeq ($(strip $(MAKE_JOBS)),)\n"); + fprintf( fp, " ifeq ($(shell $(UNAME)),Darwin)\n" ); + fprintf( fp, " CPUS := $(shell /usr/sbin/sysctl -n hw.ncpu)\n" ); + fprintf( fp, " endif\n"); + fprintf( fp, " ifeq ($(shell $(UNAME)),Linux)\n" ); + fprintf( fp, " CPUS := $(shell $(TOOL_PATH)grep processor /proc/cpuinfo | $(TOOL_PATH)wc -l)\n" ); + fprintf( fp, " endif\n"); + fprintf( fp, " MAKE_JOBS := $(CPUS)\n" ); + fprintf( fp, "endif\n\n" ); + + fprintf( fp, "ifeq ($(strip $(MAKE_JOBS)),)\n"); + fprintf( fp, " MAKE_JOBS := 8\n" ); + fprintf( fp, "endif\n\n" ); + // Handle VALVE_NO_PROJECT_DEPS + fprintf( fp, "# make VALVE_NO_PROJECT_DEPS 1 or empty (so VALVE_NO_PROJECT_DEPS=0 works as expected)\n"); + fprintf( fp, "ifeq ($(strip $(VALVE_NO_PROJECT_DEPS)),1)\n"); + fprintf( fp, "\tVALVE_NO_PROJECT_DEPS := 1\n"); + fprintf( fp, "else\n"); + fprintf( fp, "\tVALVE_NO_PROJECT_DEPS :=\n"); + fprintf( fp, "endif\n\n"); + + // Handle VALVE_NO_PROJECT_DEPS + fprintf( fp, "# make VALVE_NO_PROJECT_DEPS 1 or empty (so VALVE_NO_PROJECT_DEPS=0 works as expected)\n"); + fprintf( fp, "ifeq ($(strip $(VALVE_NO_PROJECT_DEPS)),1)\n"); + fprintf( fp, "\tVALVE_NO_PROJECT_DEPS := 1\n"); + fprintf( fp, "else\n"); + fprintf( fp, "\tVALVE_NO_PROJECT_DEPS :=\n"); + fprintf( fp, "endif\n\n"); + + // First, make a target with all the project names. + fprintf( fp, "# All projects (default target)\n" ); + fprintf( fp, "all: $(CHROOT_CONF)\n" ); + fprintf( fp, "\t$(MAKE) -f $(lastword $(MAKEFILE_LIST)) -j$(MAKE_JOBS) all-targets\n\n" ); + + fprintf( fp, "all-targets : " ); + + CUtlVector<CUtlString> projNames; + GenerateProjectNames( projNames, projects ); + + for ( int i=0; i < projects.Count(); i++ ) + { + fprintf( fp, "%s ", projNames[i].String() ); + } + + fprintf( fp, "\n\n\n# Individual projects + dependencies\n\n" ); + + for ( int i=0; i < projects.Count(); i++ ) + { + CDependency_Project *pCurProject = projects[i]; + + CUtlVector<CDependency_Project*> additionalProjectDependencies; + ResolveAdditionalProjectDependencies( pCurProject, projects, additionalProjectDependencies ); + + fprintf( fp, "%s : $(if $(VALVE_NO_PROJECT_DEPS),,$(CHROOT_CONF) ", projNames[i].String() ); + + for ( int iTestProject=0; iTestProject < projects.Count(); iTestProject++ ) + { + if ( i == iTestProject ) + continue; + + CDependency_Project *pTestProject = projects[iTestProject]; + int dependsOnFlags = k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse; + if ( pCurProject->DependsOn( pTestProject, dependsOnFlags ) || additionalProjectDependencies.Find( pTestProject ) != additionalProjectDependencies.InvalidIndex() ) + { + fprintf( fp, "%s ", projNames[iTestProject].String() ); + } + } + + fprintf( fp, ")" ); // Closing $(if) above + + // Now add the code to build this thing. + char sDirTemp[MAX_PATH], sDir[MAX_PATH]; + V_strncpy( sDirTemp, pCurProject->m_ProjectFilename.String(), sizeof( sDirTemp ) ); + V_StripFilename( sDirTemp ); + V_MakeAbsoluteCygwinPath( sDir, sizeof( sDir ), sDirTemp ); + + const char *pFilename = V_UnqualifiedFileName( pCurProject->m_ProjectFilename.String() ); + + fprintf( fp, "\n\t@echo \"Building: %s\"", projNames[i].String()); + fprintf( fp, "\n\t@+cd %s && $(MAKE) -f %s $(SUBMAKE_PARAMS) $(CLEANPARAM)", sDir, pFilename ); + + fprintf( fp, "\n\n" ); + } + + fprintf( fp, "# this is a bit over-inclusive, but the alternative (actually adding each referenced c/cpp/h file to\n" ); + fprintf( fp, "# the tags file) seems like more work than it's worth. feel free to fix that up if it bugs you. \n" ); + fprintf( fp, "TAGS:\n" ); + fprintf( fp, "\t@rm -f TAGS\n" ); + for ( int i=0; i < projects.Count(); i++ ) + { + CDependency_Project *pCurProject = projects[i]; + char sDirTemp[MAX_PATH], sDir[MAX_PATH]; + V_strncpy( sDirTemp, pCurProject->m_ProjectFilename.String(), sizeof( sDirTemp ) ); + V_StripFilename( sDirTemp ); + V_MakeAbsoluteCygwinPath( sDir, sizeof( sDir ), sDirTemp ); + fprintf( fp, "\t@$(FIND) %s -name \'*.cpp\' -print0 | $(XARGS) -0 $(ETAGS) --declarations --ignore-indentation --append\n", sDir ); + fprintf( fp, "\t@$(FIND) %s -name \'*.h\' -print0 | $(XARGS) -0 $(ETAGS) --language=c++ --declarations --ignore-indentation --append\n", sDir ); + fprintf( fp, "\t@$(FIND) %s -name \'*.c\' -print0 | $(XARGS) -0 $(ETAGS) --declarations --ignore-indentation --append\n", sDir ); + } + fprintf( fp, "\n\n" ); + + fprintf( fp, "\n# Mark all the projects as phony or else make will see the directories by the same name and think certain targets \n\n" ); + fprintf( fp, ".PHONY: TAGS showtargets regen showregen clean cleantargets cleanandremove relink " ); + for ( int i=0; i < projects.Count(); i++ ) + { + fprintf( fp, "%s ", projNames[i].String() ); + } + fprintf( fp, "\n\n\n" ); + + fprintf( fp, "\n# The standard clean command to clean it all out.\n" ); + fprintf( fp, "\nclean: \n" ); + fprintf( fp, "\t@$(MAKE) -f $(lastword $(MAKEFILE_LIST)) -j$(MAKE_JOBS) all-targets CLEANPARAM=clean\n\n\n" ); + + fprintf( fp, "\n# clean targets, so we re-link next time.\n" ); + fprintf( fp, "\ncleantargets: \n" ); + fprintf( fp, "\t@$(MAKE) -f $(lastword $(MAKEFILE_LIST)) -j$(MAKE_JOBS) all-targets CLEANPARAM=cleantargets\n\n\n" ); + + fprintf( fp, "\n# p4 edit and remove targets, so we get an entirely clean build.\n" ); + fprintf( fp, "\ncleanandremove: \n" ); + fprintf( fp, "\t@$(MAKE) -f $(lastword $(MAKEFILE_LIST)) -j$(MAKE_JOBS) all-targets CLEANPARAM=cleanandremove\n\n\n" ); + + fprintf( fp, "\n#relink\n" ); + fprintf( fp, "\nrelink: cleantargets \n" ); + fprintf( fp, "\t@$(MAKE) -f $(lastword $(MAKEFILE_LIST)) -j$(MAKE_JOBS) all-targets\n\n\n" ); + + + + // Create the showtargets target. + fprintf( fp, "\n# Here's a command to list out all the targets\n\n" ); + fprintf( fp, "\nshowtargets: \n" ); + fprintf( fp, "\t@$(ECHO) '-------------------' && \\\n" ); + fprintf( fp, "\t$(ECHO) '----- TARGETS -----' && \\\n" ); + fprintf( fp, "\t$(ECHO) '-------------------' && \\\n" ); + fprintf( fp, "\t$(ECHO) 'clean' && \\\n" ); + fprintf( fp, "\t$(ECHO) 'regen' && \\\n" ); + fprintf( fp, "\t$(ECHO) 'showregen' && \\\n" ); + for ( int i=0; i < projects.Count(); i++ ) + { + fprintf( fp, "\t$(ECHO) '%s'", projNames[i].String() ); + if ( i != projects.Count()-1 ) + fprintf( fp, " && \\" ); + fprintf( fp, "\n" ); + } + fprintf( fp, "\n\n" ); + + + // Create the regen target. + fprintf( fp, "\n# Here's a command to regenerate this makefile\n\n" ); + fprintf( fp, "\nregen: \n" ); + fprintf( fp, "\t" ); + ICommandLine *pCommandLine = CommandLine(); + for ( int i=0; i < pCommandLine->ParmCount(); i++ ) + { + fprintf( fp, "%s ", pCommandLine->GetParm( i ) ); + } + fprintf( fp, "\n\n" ); + + + // Create the showregen target. + fprintf( fp, "\n# Here's a command to list out all the targets\n\n" ); + fprintf( fp, "\nshowregen: \n" ); + fprintf( fp, "\t@$(ECHO) " ); + for ( int i=0; i < pCommandLine->ParmCount(); i++ ) + { + fprintf( fp, "%s ", pCommandLine->GetParm( i ) ); + } + fprintf( fp, "\n\n" ); + + // Auto-create the chroot if it's not there + fprintf( fp, "ifdef CHROOT_CONF\n" + "$(CHROOT_CONF): $(CHROOT_DIR)/$(RUNTIME_NAME)/timestamp\n" + "$(CHROOT_CONF): SHELL = /bin/bash\n" + "$(CHROOT_DIR)/$(RUNTIME_NAME)/timestamp: $(CHROOT_DIR)/$(RUNTIME_NAME).tar.xz\n" + "\t@echo \"Configuring schroot at $(CHROOT_DIR) (requires sudo)\"\n" + "\tsudo $(CHROOT_DIR)/configure_runtime.sh ${CHROOT_NAME} $(RUNTIME_NAME) $(CHROOT_PERSONALITY)\n" + "endif\n"); + + + fclose( fp ); + } + + void ResolveAdditionalProjectDependencies( + CDependency_Project *pCurProject, + CUtlVector<CDependency_Project*> &projects, + CUtlVector<CDependency_Project*> &additionalProjectDependencies ) + { + for ( int i=0; i < pCurProject->m_AdditionalProjectDependencies.Count(); i++ ) + { + const char *pLookingFor = pCurProject->m_AdditionalProjectDependencies[i].String(); + + int j; + for ( j=0; j < projects.Count(); j++ ) + { + if ( V_stricmp( projects[j]->m_ProjectName.String(), pLookingFor ) == 0 ) + break; + } + + if ( j == projects.Count() ) + g_pVPC->VPCError( "Project %s lists '%s' in its $AdditionalProjectDependencies, but there is no project by that name in the selected projects.", pCurProject->GetName(), pLookingFor ); + + additionalProjectDependencies.AddToTail( projects[j] ); + } + } + + const char* FindInFile( const char *pFilename, const char *pFileData, const char *pSearchFor ) + { + const char *pPos = V_stristr( pFileData, pSearchFor ); + if ( !pPos ) + g_pVPC->VPCError( "Can't find ProjectGUID in %s.", pFilename ); + + return pPos + V_strlen( pSearchFor ); + } +}; + + +static CSolutionGenerator_Makefile g_SolutionGenerator_Makefile; +IBaseSolutionGenerator* GetMakefileSolutionGenerator() +{ + return &g_SolutionGenerator_Makefile; +} + + + diff --git a/external/vpc/utils/vpc/solutiongenerator_win32.cpp b/external/vpc/utils/vpc/solutiongenerator_win32.cpp new file mode 100644 index 0000000..9314795 --- /dev/null +++ b/external/vpc/utils/vpc/solutiongenerator_win32.cpp @@ -0,0 +1,370 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#include "vpc.h" +#include "dependencies.h" +#include "tier1/checksum_md5.h" + +class CVCProjInfo +{ +public: + CUtlString m_ProjectName; + CUtlString m_ProjectGUID; +}; + + +struct RegStartPoint +{ + HKEY baseKey; + const char* const baseDir; +}; + +class CSolutionGenerator_Win32 : public IBaseSolutionGenerator +{ +public: + void GetVCPROJSolutionGUID( char (&szSolutionGUID)[256] ) + { + HKEY hKey; + int firstVer = 8; + const int lastVer = 14; // Handle up to VS 14, AKA VS 2015 + if ( g_pVPC->Is2010() ) + { + firstVer = 10; + } + else if ( g_pVPC->BUse2008() ) + { + firstVer = 9; + } + for ( int vsVer = firstVer; vsVer <= lastVer; ++vsVer ) + { + // Handle both VisualStudio and VCExpress (used by some SourceSDK customers) + RegStartPoint searchPoints[] = + { + { HKEY_LOCAL_MACHINE, "Software\\Microsoft\\VisualStudio\\%d.0\\Projects" }, // Visual Studio Professional + { HKEY_LOCAL_MACHINE, "Software\\Microsoft\\VCExpress\\%d.0\\Projects" }, // VC Express 2010 and 2012 + { HKEY_CURRENT_USER, "Software\\Microsoft\\WDExpress\\%d.0_Config\\Projects" }, // WinDev Express -- VS Express starting with VS 2013 + }; + for ( int j = 0; j < ARRAYSIZE(searchPoints); ++j ) + { + RegStartPoint& searchPoint = searchPoints[ j ]; + char pRegKeyName[1000]; + V_snprintf( pRegKeyName, ARRAYSIZE(pRegKeyName), searchPoint.baseDir, vsVer ); + LONG ret = RegOpenKeyEx( searchPoint.baseKey, pRegKeyName, 0, KEY_READ, &hKey ); + //if ( ret != ERROR_SUCCESS ) + // g_pVPC->VPCError( "Unable to open registry key %s.", pRegKeyName ); + + for ( int i=0; i < 200; i++ ) + { + char szKeyName[MAX_PATH]; + DWORD dwKeyNameSize = sizeof( szKeyName ); + ret = RegEnumKeyEx( hKey, i, szKeyName, &dwKeyNameSize, NULL, NULL, NULL, NULL ); + if ( ret == ERROR_NO_MORE_ITEMS ) + break; + + HKEY hSubKey; + LONG ret = RegOpenKeyEx( hKey, szKeyName, 0, KEY_READ, &hSubKey ); + if ( ret == ERROR_SUCCESS ) + { + DWORD dwType; + char ext[MAX_PATH]; + DWORD dwExtLen = sizeof( ext ); + ret = RegQueryValueEx( hSubKey, "DefaultProjectExtension", NULL, &dwType, (BYTE*)ext, &dwExtLen ); + RegCloseKey( hSubKey ); + + // VS 2012 and beyond has the DefaultProjectExtension as vcxproj instead of vcproj + if ( ret == ERROR_SUCCESS && dwType == REG_SZ && ( V_stricmp( ext, "vcproj" ) == 0 || V_stricmp( ext, "vcxproj" ) == 0 ) ) + { + V_strncpy( szSolutionGUID, szKeyName, ARRAYSIZE(szSolutionGUID) ); + RegCloseKey( hKey ); + return; + } + } + } + + RegCloseKey( hKey ); + } + } + g_pVPC->VPCError( "Unable to find RegKey for .vcproj or .vcxproj files in solutions." ); + } + + virtual void GenerateSolutionFile( const char *pSolutionFilename, CUtlVector<CDependency_Project*> &projects ) + { + // Default extension. + char szTmpSolutionFilename[MAX_PATH]; + if ( !V_GetFileExtension( pSolutionFilename ) ) + { + V_snprintf( szTmpSolutionFilename, sizeof( szTmpSolutionFilename ), "%s.sln", pSolutionFilename ); + pSolutionFilename = szTmpSolutionFilename; + } + + Msg( "\nWriting solution file %s.\n\n", pSolutionFilename ); + + char szSolutionGUID[256]; + GetVCPROJSolutionGUID( szSolutionGUID ); + + CUtlVector<CVCProjInfo> vcprojInfos; + GetProjectInfos( projects, vcprojInfos ); + + // Write the file. + FILE *fp = fopen( pSolutionFilename, "wt" ); + if ( !fp ) + g_pVPC->VPCError( "Can't open %s for writing.", pSolutionFilename ); + + + if ( g_pVPC->Is2015() ) + { + fprintf( fp, "\xef\xbb\xbf\nMicrosoft Visual Studio Solution File, Format Version 12.00\n" ); // still on 12 + fprintf( fp, "# Visual Studio 2015\n" ); + } + else if ( g_pVPC->Is2013() ) + { + fprintf( fp, "\xef\xbb\xbf\nMicrosoft Visual Studio Solution File, Format Version 12.00\n" ); // Format didn't change from VS 2012 to VS 2013 + fprintf( fp, "# Visual Studio 2013\n" ); + } + else if ( g_pVPC->Is2012() ) + { + fprintf( fp, "\xef\xbb\xbf\nMicrosoft Visual Studio Solution File, Format Version 12.00\n" ); + fprintf( fp, "# Visual Studio 2012\n" ); + } + else if ( g_pVPC->Is2010() ) + { + fprintf( fp, "\xef\xbb\xbf\nMicrosoft Visual Studio Solution File, Format Version 11.00\n" ); + fprintf( fp, "# Visual Studio 2010\n" ); + } + else if ( g_pVPC->BUse2008() ) + { + fprintf( fp, "\xef\xbb\xbf\nMicrosoft Visual Studio Solution File, Format Version 10.00\n" ); + fprintf( fp, "# Visual Studio 2008\n" ); + } + else + { + fprintf( fp, "\xef\xbb\xbf\nMicrosoft Visual Studio Solution File, Format Version 9.00\n" ); + fprintf( fp, "# Visual Studio 2005\n" ); + } + fprintf( fp, "#\n" ); + fprintf( fp, "# Automatically generated solution:\n" ); + fprintf( fp, "# devtools\\bin\\vpc " ); + for ( int k = 1; k < __argc; ++ k ) + fprintf( fp, "%s ", __argv[k] ); + fprintf( fp, "\n" ); + fprintf( fp, "#\n" ); + fprintf( fp, "#\n" ); + + if ( !g_pVPC->Is2010() ) + { + // if /slnItems <filename> is passed on the command line, build a Solution Items project + const char *pSolutionItemsFilename = g_pVPC->GetSolutionItemsFilename(); + if ( pSolutionItemsFilename[0] != '\0' ) + { + fprintf( fp, "Project(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Solution Items\", \"Solution Items\", \"{AAAAAAAA-8B4A-11D0-8D11-90A07D6D6F7D}\"\n" ); + fprintf( fp, "\tProjectSection(SolutionItems) = preProject\n" ); + WriteSolutionItems( fp ); + fprintf( fp, "\tEndProjectSection\n" ); + fprintf( fp, "EndProject\n" ); + } + } + + for ( int i=0; i < projects.Count(); i++ ) + { + CDependency_Project *pCurProject = projects[i]; + CVCProjInfo *pProjInfo = &vcprojInfos[i]; + + // Get a relative filename for the vcproj file. + const char *pFullProjectFilename = pCurProject->m_ProjectFilename.String(); + char szRelativeFilename[MAX_PATH]; + if ( !V_MakeRelativePath( pFullProjectFilename, g_pVPC->GetSourcePath(), szRelativeFilename, sizeof( szRelativeFilename ) ) ) + g_pVPC->VPCError( "Can't make a relative path (to the base source directory) for %s.", pFullProjectFilename ); + + fprintf( fp, "Project(\"%s\") = \"%s\", \"%s\", \"{%s}\"\n", szSolutionGUID, pProjInfo->m_ProjectName.String(), szRelativeFilename, pProjInfo->m_ProjectGUID.String() ); + bool bHasDependencies = false; + + for ( int iTestProject=0; iTestProject < projects.Count(); iTestProject++ ) + { + if ( i == iTestProject ) + continue; + + CDependency_Project *pTestProject = projects[iTestProject]; + if ( pCurProject->DependsOn( pTestProject, k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagRecurse ) || + pCurProject->DependsOn( pTestProject, k_EDependsOnFlagCheckAdditionalDependencies | k_EDependsOnFlagTraversePastLibs ) ) + { + if ( !bHasDependencies ) + { + fprintf( fp, "\tProjectSection(ProjectDependencies) = postProject\n" ); + bHasDependencies = true; + } + fprintf( fp, "\t\t{%s} = {%s}\n", vcprojInfos[iTestProject].m_ProjectGUID.String(), vcprojInfos[iTestProject].m_ProjectGUID.String() ); + } + } + if ( bHasDependencies ) + fprintf( fp, "\tEndProjectSection\n" ); + + fprintf( fp, "EndProject\n" ); + } + + fclose( fp ); + Sys_CopyToMirror( pSolutionFilename ); + } + + const char* FindInFile( const char *pFilename, const char *pFileData, const char *pSearchFor ) + { + const char *pPos = V_stristr( pFileData, pSearchFor ); + if ( !pPos ) + { + g_pVPC->VPCError( "Can't find %s in %s.", pSearchFor, pFilename ); + } + + return pPos + V_strlen( pSearchFor ); + } + + void GetProjectInfos( CUtlVector<CDependency_Project*> &projects, CUtlVector<CVCProjInfo> &vcprojInfos ) + { + for ( int i=0; i < projects.Count(); i++ ) + { + CDependency_Project *pCurProject = projects[i]; + const char *pFilename = pCurProject->m_ProjectFilename.String(); + + CVCProjInfo vcprojInfo; + + char *pFileData; + int nResult = Sys_LoadFile( pFilename, (void**)&pFileData, false ); + if ( nResult == -1 ) + g_pVPC->VPCError( "Can't open %s to get ProjectGUID.", pFilename ); + + const char *pSearchFor; + if ( g_pVPC->Is2010() ) + { + pSearchFor = "<ProjectGuid>{"; + } + else + { + pSearchFor = "ProjectGUID=\"{"; + } + + const char *pPos = FindInFile( pFilename, pFileData, pSearchFor ); + char szGuid[37]; + const char *pGuid = pPos; + V_strncpy( szGuid, pGuid, sizeof( szGuid ) ); + vcprojInfo.m_ProjectGUID = szGuid; + + const char *pEnd; + if ( g_pVPC->Is2010() ) + { + pPos = FindInFile( pFilename, pFileData, "<ProjectName>" ); + pEnd = V_stristr( pPos, "<" ); + } + else + { + pPos = FindInFile( pFilename, pFileData, "Name=\"" ); + pEnd = V_stristr( pPos, "\"" ); + } + + if ( !pEnd || (pEnd - pPos) > 1024 || (pEnd - pPos) <= 0 ) + g_pVPC->VPCError( "Can't find valid 'Name=' in %s.", pFilename ); + + char szName[256]; + V_strncpy( szName, pPos, (pEnd - pPos) + 1 ); + vcprojInfo.m_ProjectName = szName; + + vcprojInfos.AddToTail( vcprojInfo ); + + free( pFileData ); + } + } + + // Parse g_SolutionItemsFilename, reading in filenames (including wildcards), + // and add them to the Solution Items project we're already writing. + void WriteSolutionItems( FILE *fp ) + { + char szFullSolutionItemsPath[MAX_PATH]; + if ( V_IsAbsolutePath( g_pVPC->GetSolutionItemsFilename() ) ) + V_strncpy( szFullSolutionItemsPath, g_pVPC->GetSolutionItemsFilename(), sizeof( szFullSolutionItemsPath ) ); + else + V_ComposeFileName( g_pVPC->GetStartDirectory(), g_pVPC->GetSolutionItemsFilename(), szFullSolutionItemsPath, sizeof( szFullSolutionItemsPath ) ); + + g_pVPC->GetScript().PushScript( szFullSolutionItemsPath ); + + int numSolutionItems = 0; + while ( g_pVPC->GetScript().GetData() ) + { + // read a line + const char *pToken = g_pVPC->GetScript().GetToken( false ); + + // strip out \r\n chars + char *end = V_strstr( pToken, "\n" ); + if ( end ) + { + *end = '\0'; + } + end = V_strstr( pToken, "\r" ); + if ( end ) + { + *end = '\0'; + } + + // bail on strings too small to be paths + if ( V_strlen( pToken ) < 3 ) + continue; + + // compose an absolute path w/o any ../ + char szFullPath[MAX_PATH]; + if ( V_IsAbsolutePath( pToken ) ) + V_strncpy( szFullPath, pToken, sizeof( szFullPath ) ); + else + V_ComposeFileName( g_pVPC->GetStartDirectory(), pToken, szFullPath, sizeof( szFullPath ) ); + + if ( !V_RemoveDotSlashes( szFullPath ) ) + continue; + + if ( V_strstr( szFullPath, "*" ) != NULL ) + { + // wildcard! + char szWildcardPath[MAX_PATH]; + V_strncpy( szWildcardPath, szFullPath, sizeof( szWildcardPath ) ); + V_StripFilename( szWildcardPath ); + + struct _finddata32_t data; + intptr_t handle = _findfirst32( szFullPath, &data ); + if ( handle != -1L ) + { + do + { + if ( ( data.attrib & _A_SUBDIR ) == 0 ) + { + // not a dir, just a filename - add it + V_ComposeFileName( szWildcardPath, data.name, szFullPath, sizeof( szFullPath ) ); + + if ( V_RemoveDotSlashes( szFullPath ) ) + { + fprintf( fp, "\t\t%s = %s\n", szFullPath, szFullPath ); + ++numSolutionItems; + } + } + } while ( _findnext32( handle, &data ) == 0 ); + + _findclose( handle ); + } + } + else + { + // just a file - add it + fprintf( fp, "\t\t%s = %s\n", szFullPath, szFullPath ); + ++numSolutionItems; + } + } + + g_pVPC->GetScript().PopScript(); + + Msg( "Found %d solution files in %s\n", numSolutionItems, g_pVPC->GetSolutionItemsFilename() ); + } +}; + + +static CSolutionGenerator_Win32 g_SolutionGenerator_Win32; +IBaseSolutionGenerator* GetSolutionGenerator_Win32() +{ + return &g_SolutionGenerator_Win32; +} + diff --git a/external/vpc/utils/vpc/solutiongenerator_xcode.cpp b/external/vpc/utils/vpc/solutiongenerator_xcode.cpp new file mode 100644 index 0000000..f061ed4 --- /dev/null +++ b/external/vpc/utils/vpc/solutiongenerator_xcode.cpp @@ -0,0 +1,2806 @@ +//====== Copyright 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#include "vpc.h" +#include "dependencies.h" +#include "baseprojectdatacollector.h" +#include "utlsortvector.h" +#include "checksum_md5.h" + +#ifdef WIN32 +#include <direct.h> +#define mkdir(dir, mode) _mkdir(dir) +#define getcwd _getcwd +#define snprintf _snprintf +typedef unsigned __int64 uint64_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int8 uint8_t; +typedef signed __int16 int16_t; +#else +#include <stdint.h> +#endif + +static const int k_nShellScriptPhasesPerAggregateTarget = 8; + +#ifndef STEAM +bool V_StrSubstInPlace( char *pchInOut, int cchInOut, const char *pMatch, const char *pReplaceWith, bool bCaseSensitive ); +#endif + +static const char *k_pchProjects = "Projects"; +static const char *k_pchLegacyTarget = "build with make"; +static const char *k_rgchConfigNames[] = { "Debug", "Release" }; + +static const char *g_pOption_AdditionalDependencies = "$AdditionalDependencies"; +static const char *g_pOption_BufferSecurityCheck = "$BufferSecurityCheck"; +static const char *g_pOption_BuildMultiArch = "$BuildMultiArch"; +static const char *g_pOption_BuildX64Only = "$BuildX64Only"; +static const char *g_pOption_CompileAs = "$CompileAs"; +static const char *g_pOption_PreBuildEventCommandLine = "$PreBuildEvent/$CommandLine"; +static const char *g_pOption_CustomBuildStepCommandLine = "$CustomBuildStep/$CommandLine"; +static const char *g_pOption_PostBuildEventCommandLine = "$PostBuildEvent/$CommandLine"; +static const char *g_pOption_ConfigurationType = "$ConfigurationType"; +static const char *g_pOption_Description = "$Description"; +static const char *g_pOption_ExtraCompilerFlags = "$GCC_ExtraCompilerFlags"; +static const char *g_pOption_ExtraLinkerFlags = "$GCC_ExtraLinkerFlags"; +static const char *g_pOption_ForceInclude = "$ForceIncludes"; +static const char *g_pOption_LinkAsBundle = "$LinkAsBundle"; +static const char *g_pOption_LocalFrameworks = "$LocalFrameworks"; +static const char *g_pOption_LowerCaseFileNames = "$LowerCaseFileNames"; +static const char *g_pOption_OptimizerLevel = "$OptimizerLevel"; +static const char *g_pOption_OutputDirectory = "$OutputDirectory"; +static const char *g_pOption_Outputs = "$Outputs"; +static const char *g_pOption_PostBuildEvent = "$PostBuildEvent"; +static const char *g_pOption_PrecompiledHeader = "$Create/UsePrecompiledHeader"; +static const char *g_pOption_PrecompiledHeaderFile = "$PrecompiledHeaderFile"; +static const char *g_pOption_SymbolVisibility = "$SymbolVisibility"; +static const char *g_pOption_SystemFrameworks = "$SystemFrameworks"; +static const char *g_pOption_SystemLibraries = "$SystemLibraries"; +static const char *g_pOption_UsePCHThroughFile = "$Create/UsePCHThroughFile"; +static const char *g_pOption_AdditionalLibraryDirectories = "$AdditionalLibraryDirectories"; +static const char *g_pOption_TargetCopies = "$TargetCopies"; +static const char *g_pOption_TreatWarningsAsErrors = "$TreatWarningsAsErrors"; + +// These are the only properties we care about for xcodeprojects. +static const char *g_pRelevantProperties[] = +{ + g_pOption_AdditionalDependencies, + g_pOption_AdditionalIncludeDirectories, + g_pOption_AdditionalLibraryDirectories, + g_pOption_BufferSecurityCheck, + g_pOption_CompileAs, + g_pOption_OptimizerLevel, + g_pOption_OutputFile, + g_pOption_GameOutputFile, + g_pOption_SymbolVisibility, + g_pOption_PreprocessorDefinitions, + g_pOption_ConfigurationType, + g_pOption_ImportLibrary, + g_pOption_LinkAsBundle, + g_pOption_PrecompiledHeader, + g_pOption_UsePCHThroughFile, + g_pOption_PrecompiledHeaderFile, + g_pOption_PreBuildEventCommandLine, + g_pOption_CustomBuildStepCommandLine, + g_pOption_PostBuildEventCommandLine, + g_pOption_OutputDirectory, + g_pOption_Outputs, + g_pOption_Description, + g_pOption_SystemLibraries, + g_pOption_SystemFrameworks, + g_pOption_LocalFrameworks, + g_pOption_BuildMultiArch, + g_pOption_BuildX64Only, + g_pOption_ExtraCompilerFlags, + g_pOption_ExtraLinkerFlags, + g_pOption_ForceInclude, + g_pOption_TargetCopies, + g_pOption_TreatWarningsAsErrors, +}; + + +static CRelevantPropertyNames g_RelevantPropertyNames = +{ + g_pRelevantProperties, + V_ARRAYSIZE( g_pRelevantProperties ) +}; + + +static const char *k_rgchXCConfigFiles[] = { "debug.xcconfig", "release.xcconfig", "base.xcconfig" }; + +static int k_oidBuildConfigList = 0xc0de; +static int k_rgOidBuildConfigs[] = { 0x1c0de, 0x1c0e0 }; + +class CProjectGenerator_Xcode : public CBaseProjectDataCollector +{ + typedef CBaseProjectDataCollector BaseClass; +public: + CProjectGenerator_Xcode() : BaseClass( &g_RelevantPropertyNames ) + { + m_bIsCurrent = false; + m_nShellScriptPhases = 0; + m_nCustomBuildRules = 0; + m_nPreBuildEvents = 0; + } + + virtual void Setup() {} + + virtual const char *GetProjectFileExtension() { return ""; } + + virtual void EndProject() + { + m_OutputFilename = g_pVPC->GetOutputFilename(); + // we need the "project file" to exist for crc checking + if ( !Sys_Exists( m_OutputFilename ) ) + Sys_Touch( m_OutputFilename ); + + // remember if we needed rebuild according to vpc + m_bIsCurrent = g_pVPC->IsProjectCurrent( g_pVPC->GetOutputFilename(), false ); + + // and update the mod time on the file if we needed rebuild + if ( !m_bIsCurrent ) + Sys_Touch( m_OutputFilename ); + + extern CUtlVector<CBaseProjectDataCollector*> g_vecPGenerators; + g_vecPGenerators.AddToTail( this ); + + extern IBaseProjectGenerator *g_pGenerator; + g_pVPC->SetProjectGenerator( new CProjectGenerator_Xcode() ); + } + + bool m_bIsCurrent; + int m_nShellScriptPhases; + int m_nCustomBuildRules; + int m_nPreBuildEvents; + CUtlString m_OutputFilename; +}; + +// we assume (and assert) that the order of this vector is the same as the order of the projects vector +extern CUtlVector<CBaseProjectDataCollector*> g_vecPGenerators; + +class CSolutionGenerator_Xcode : public IBaseSolutionGenerator +{ +public: + virtual void GenerateSolutionFile( const char *pSolutionFilename, CUtlVector<CDependency_Project*> &projects ); +private: + void XcodeFileTypeFromFileName( const char *pszFileName, char *pchOutBuf, int cchOutBuf ); + void XcodeProductTypeFromFileName( const char *pszFileName, char *pchOutBuf, int cchOutBuf ); + void EmitBuildSettings( const char *pszProjectName, const char *pszProjectDir, CUtlDict<CFileConfig *,int> *pDictFiles, KeyValues *pConfigKV, KeyValues *pReleaseKV, bool bIsDebug ); + void WriteFilesFolder( uint64_t oid, const char *pFolderName, const char *pExtensions, CBaseProjectDataCollector *pProject ); + + void Write( const char *pMsg, ... ); + FILE *m_fp; + int m_nIndent; + +}; + +enum EOIDType +{ + EOIDTypeProject = 0x00001d00, + EOIDTypeGroup, + EOIDTypeFileReference, + EOIDTypeBuildFile, + EOIDTypeSourcesBuildPhase, + EOIDTypeFrameworksBuildPhase, + EOIDTypeCopyFilesBuildPhase, + EOIDTypeHeadersBuildPhase, + EOIDTypePreBuildPhase, + EOIDTypeShellScriptBuildPhase, + EOIDTypePostBuildPhase, + EOIDTypeNativeTarget, + EOIDTypeAggregateTarget, + EOIDTypeTargetDependency, + EOIDTypeContainerItemProxy, + EOIDTypeBuildConfiguration, + EOIDTypeConfigurationList, + EOIDTypeCustomBuildRule, +}; + +// Make an OID from raw data. You probably want makeoid/makeoid2 below. +uint64_t makeoid_raw( const char *pData, int nDataLen, EOIDType type, int16_t ordinal = 0 ) +{ + static unsigned int unOIDSalt = 0; + static bool bOIDSaltSet = false; + // Since the string passed to makeoid() doesn't change based on all parameters of the object it + // is representing, we need to regenerate them per-run. There isn't currently much value in + // perserving OIDs that refer to the same object in terms of xcode functionality. If we wanted + // deterministic OIDs, we should be hashing all parameters of the object that they represent, + // which is a non-trivial refactor. + if ( !bOIDSaltSet ) + { + // Define this to generate xcode projects with deterministic OIDs (based on solution/project + // names, see makeoid callers). See above comment for why this is for debugging only. +#if defined( VPC_DETERMINISTIC_XCODE_OIDS ) + unOIDSalt = 0; + Msg( "DEBUG: Generating deterministic OIDs per project/solution name (salt -> 0).\n" ); +#else + // You'd think our random API would be better here, but it doesn't actually have a function + // to return a full-range int and uses the below code to seed itself. Except in tools where + // it is un-seeded without a warning that that is the case. + float flAppTime = Plat_FloatTime(); + ThreadId_t threadId = ThreadGetCurrentId(); + COMPILE_TIME_ASSERT( sizeof( flAppTime ) <= sizeof( unOIDSalt ) ); + memcpy( &unOIDSalt, &flAppTime, sizeof( float ) ); + unOIDSalt ^= threadId; +#endif // defined( VPC_DETERMINISTIC_XCODE_OIDS ) + +#ifdef VPC_DEBUG_XCODE_OIDS + Msg( "XCode Solution: Using random salt for OIDs of %u\n", unOIDSalt ); +#endif + bOIDSaltSet = true; + } + + // Lower 32bits of OID is hash of identifier string + salt, upper 32bits is type and ordinal. + MD5Context_t md5Context; + unsigned char hash[ MD5_DIGEST_LENGTH ] = { 0 }; + MD5Init( &md5Context ); + MD5Update( &md5Context, (const unsigned char *)&unOIDSalt, sizeof( unOIDSalt ) ); + MD5Update( &md5Context, (const unsigned char *)pData, nDataLen ); + MD5Final( hash, &md5Context ); + + // Take lower 32bits of md5 + COMPILE_TIME_ASSERT( MD5_DIGEST_LENGTH >= sizeof( uint32_t ) ); + uint32_t lowerHash = 0; + memcpy( &lowerHash, hash, sizeof( lowerHash ) ); + + uint64_t oid = (uint64_t)lowerHash + ((uint64_t)type << 32) + ((uint64_t)(ordinal+1) << 52); +#ifdef VPC_DEBUG_XCODE_OIDS + Msg( "XCode Solution: Produced OID 0x%llx for \"%s\" with salt %u\n", oid, pszIdentifier, unOIDSalt ); +#endif + return oid; +} + +// Make an oid for a unique string identifier, per type, per ordinal +uint64_t makeoid( const char *pszIdentifier, EOIDType type, int16_t ordinal = 0 ) +{ + CFmtStr oidStr( "oid1.%s", pszIdentifier ); + return makeoid_raw( oidStr.Access(), oidStr.Length(), type, ordinal ); +} + +// Make an oid for a unique string tuple, per type, per ordinal +uint64_t makeoid2( const char *pszIdentifierA, const char *pszIdentifierB, EOIDType type, int16_t ordinal = 0 ) +{ + CFmtStr oidStr( "oid2.%s.%s", pszIdentifierA, pszIdentifierB ); + return makeoid_raw( oidStr.Access(), oidStr.Length(), type, ordinal ); +} + +// Make an oid for a unique string tuple, per type, per ordinal +uint64_t makeoid3( const char *pszIdentifierA, const char *pszIdentifierB, const char *pszIdentifierC, EOIDType type, int16_t ordinal = 0 ) +{ + CFmtStr oidStr( "oid3.%s.%s.%s", pszIdentifierA, pszIdentifierB, pszIdentifierC ); + return makeoid_raw( oidStr.Access(), oidStr.Length(), type, ordinal ); +} + +static bool IsStaticLibrary( const char *pszFileName ) +{ + const char *pchExtension = V_GetFileExtension( V_UnqualifiedFileName( pszFileName ) ); + if ( !pchExtension ) + return false; + else if ( ! V_stricmp( pchExtension, "a" ) ) + return true; + return false; +} + + +static bool IsDynamicLibrary( const char *pszFileName ) +{ + const char *pchExtension = V_GetFileExtension( V_UnqualifiedFileName( pszFileName ) ); + if ( !pchExtension ) + return false; + else if ( ! V_stricmp( pchExtension, "dylib" ) ) + return true; + return false; +} + +static const char* EscapeQuotes( const char *pStr ) +{ + int len = V_strlen( pStr ); + static char str[4096]; + int i = 0,j = 0; + for ( ;i <= len,j < V_ARRAYSIZE(str); ) + { + if ( pStr[i] == '"' ) + { + str[j++] = '\\'; + str[j++] = '\\'; + } + str[j++] = pStr[i++]; + } + str[j] = '\0'; + + return str; +} + +static void UsePOSIXSlashes( const char *pStr, char *pOut, int nOutSize ) +{ + int len = V_strlen( pStr ) + 2; + char *str = pOut; + AssertFatal( len <= nOutSize ); + + V_strncpy( str, pStr, len ); + for ( int i = 0; i < len; i++ ) + { + if ( str[i] == '\\' ) + { + // allow escaping of bash special characters + if ( i+1 < len && ( str[i+1] != '"' && str[i+1] != '$' && + str[i+1] != '\'' && str[i+1] != '\\' ) ) + { + str[i] = '/'; + } + } + if ( str[i] == '\0' ) + break; + } +} + +// Auto-allocating (not in-place) version. Caller is responsible for free'ing (or leaking) the allocated buffer. Most +// users leak. Is bad. :-/ +static char* UsePOSIXSlashes( const char *pStr ) +{ + int len = V_strlen( pStr ) + 2; + char *str = (char*)malloc(len*sizeof(char)); + UsePOSIXSlashes( pStr, str, len*sizeof(char) ); + return str; +} + +// Finds the file name component of a path, and prepends 'lib' to it if necesssary +// foo/bar/foo.a -> foo/bar/libfoo.a +// foo/bar/libfoo.a -> unchanged +static void EnforceLibPrefix( char *pInOutStr, int nOutSize ) +{ + char *pFile = V_UnqualifiedFileName( pInOutStr ); + if ( pFile && V_strncmp( pFile, "lib", 3 ) != 0 ) + { + char szOriginalName[MAX_PATH] = { 0 }; + V_strncpy( szOriginalName, pFile, sizeof( szOriginalName ) ); + + *pFile = '\0'; + V_strncat( pInOutStr, "lib", nOutSize ); + V_strncat( pInOutStr, szOriginalName, nOutSize ); + } +} + +// Get the output file with the output directory prepended +static CUtlString OutputFileWithDirectoryFromConfig( KeyValues *pConfigKV ) +{ + char szOutputFile[MAX_PATH] = { 0 }; + char szOutputDir[MAX_PATH] = { 0 }; + UsePOSIXSlashes( pConfigKV->GetString( g_pOption_OutputFile, "" ), szOutputFile, sizeof( szOutputFile ) ); + UsePOSIXSlashes( pConfigKV->GetString( g_pOption_OutputDirectory, "" ), szOutputDir, sizeof( szOutputDir ) ); + + // Our output file is relative to BUILT_PRODUCTS_DIR already. This is a workaround for VPC files expecting Makefile + // semantics -- you shouldn't be using $() in VPC strings. + const char szObjDir[] = "$(OBJ_DIR)"; + V_StrSubstInPlace( szOutputDir, sizeof( szOutputDir ), szObjDir, ".", true ); + V_StrSubstInPlace( szOutputFile, sizeof( szOutputFile ), szObjDir, ".", true ); + + // VPC files have snuck in hard-coding of random variables expecting the Makefile backend to expand them. + if ( V_strstr( szOutputDir, "$" ) || V_strstr( szOutputFile, "$" ) ) + { + g_pVPC->VPCWarning( "$OutputDirectory '%s' or $OutputFile directive '%s' contains what looks like a shell variable reference -- " + "this will be treated literally in most circumstances by the Xcode build system and is likely not intended.", + szOutputDir, szOutputFile ); + } + + char szFormat[MAX_PATH] = { 0 }; + V_ComposeFileName( szOutputDir, szOutputFile, szFormat, sizeof( szFormat ) ); + V_RemoveDotSlashes( szFormat ); + + // For the output files, which are in the build/"Products" directory, Xcode expects static libs to be named + // "libfoo.a" so it can generate a "-lfoo" command to link with projects that depend upon them (vs passing just + // ./path/to/foo.a to the linker, which it doesn't want to do for static libraries generated as dependencies, but + // will do for random external static libs... I don't know either) + if ( IsStaticLibrary( szFormat ) ) + { + EnforceLibPrefix( szFormat, sizeof( szFormat ) ); + } + + // Some VPC files are giving output files that are trying to reference a path outside the build directory -- this is + // what GameOutputFile is for. This actually doesn't seem to break xcode, but isn't really proper and might break + // later. + if ( V_IsAbsolutePath( szFormat ) || V_strncmp( szFormat, "../", 3 ) == 0 ) + { + g_pVPC->VPCWarning( "Final output file '%s' (composited from $OutputDirectory '%s' and $OutputFile '%s') escapes the relative " + "BUILT_PRODUCTS_DIR used by Xcode -- this may break things, and should be achieved by using $GameOutputFile " + "to copy built output to the proper tree location", + szFormat, szOutputDir, szOutputFile ); + } + + CUtlString ret( szFormat ); + return ret; +} + +static CUtlString GameOutputFileFromConfig( KeyValues *pConfigKV ) +{ + char szGameOutputFile[MAX_PATH] = { 0 }; + UsePOSIXSlashes( pConfigKV->GetString( g_pOption_GameOutputFile, "" ), szGameOutputFile, sizeof( szGameOutputFile ) ); + V_RemoveDotSlashes( szGameOutputFile ); + + // VPC files have snuck in hard-coding of random variables expecting the Makefile backend to expand them. + if ( V_strstr( szGameOutputFile, "$" ) ) + { + g_pVPC->VPCWarning( "$GameOutputFile '%s' contains what looks like a shell variable reference -- " + "this will be treated literally in most circumstances by the Xcode build system and is likely not intended.", + szGameOutputFile ); + } + + CUtlString ret( szGameOutputFile ); + return ret; +} + +static const char* SkipLeadingWhitespace( const char *pStr ) +{ + if ( !pStr ) + return NULL; + while ( *pStr != '\0' && isspace(*pStr) ) + pStr++; + return pStr; +} + +static bool ProjectProducesBinary( const CBaseProjectDataCollector *pProjectDataCollector ) +{ + return ( pProjectDataCollector->m_BaseConfigData.m_Configurations[0]->GetOption( g_pOption_OutputFile ) || + pProjectDataCollector->m_BaseConfigData.m_Configurations[0]->GetOption( g_pOption_GameOutputFile ) ); +} + + +static bool NeedsBuildFileEntry( const char *pszFileName ) +{ + const char *pchExtension = V_GetFileExtension( V_UnqualifiedFileName( pszFileName ) ); + if ( !pchExtension ) + return false; + else if ( ! V_stricmp( pchExtension, "cpp" ) || ! V_stricmp( pchExtension, "cxx" ) || ! V_stricmp( pchExtension, "cc" ) || ! V_stricmp( pchExtension, "c" ) || ! V_stricmp( pchExtension, "m" ) || ! V_stricmp( pchExtension, "mm" ) || ! V_stricmp( pchExtension, "cc" ) ) + return true; + else if ( ! V_stricmp( pchExtension, "a" ) || ! V_stricmp( pchExtension, "dylib" ) ) + return true; + return false; +} + + +static bool IsSourceFile( const char *pszFileName ) +{ + const char *pchExtension = V_GetFileExtension( V_UnqualifiedFileName( pszFileName ) ); + if ( !pchExtension ) + return false; + else if ( ! V_stricmp( pchExtension, "cpp" ) || ! V_stricmp( pchExtension, "cc" ) || ! V_stricmp( pchExtension, "cxx" ) || ! V_stricmp( pchExtension, "c" ) || ! V_stricmp( pchExtension, "m" ) || ! V_stricmp( pchExtension, "mm" ) || ! V_stricmp( pchExtension, "cc" ) ) + return true; + return false; +} + +static bool FileBuildsWithCustomBuildRule( const CBaseProjectDataCollector *pProjectDataCollector, CFileConfig *pFileConfig ) +{ + if ( !pFileConfig || !pProjectDataCollector ) + return false; + CSpecificConfig *pFileSpecificData = pFileConfig->GetOrCreateConfig( pProjectDataCollector->m_BaseConfigData.m_Configurations[1]->GetConfigName(), + pProjectDataCollector->m_BaseConfigData.m_Configurations[1] ); + return ( pFileSpecificData->GetOption( g_pOption_CustomBuildStepCommandLine ) != NULL && + pFileSpecificData->GetOption( g_pOption_AdditionalDependencies ) == NULL ); + +} + +static bool AppearsInSourcesBuildPhase( const CBaseProjectDataCollector *pProjectDataCollector, CFileConfig *pFileConfig ) +{ + if ( !pFileConfig ) + return false; + return ( IsSourceFile( pFileConfig->m_Filename.String() ) || + ( FileBuildsWithCustomBuildRule( pProjectDataCollector, pFileConfig ) && ProjectProducesBinary( pProjectDataCollector ) ) ); +} + +static bool IsCreatedByCustomBuildStep( const CBaseProjectDataCollector *pProjectDataCollector, CFileConfig *pDynamicFileConfig ) +{ + for ( int i=pProjectDataCollector->m_Files.First(); i != pProjectDataCollector->m_Files.InvalidIndex(); i=pProjectDataCollector->m_Files.Next(i) ) + { + CFileConfig *pFileConfig = pProjectDataCollector->m_Files[i]; + CSpecificConfig *pFileSpecificData = pFileConfig->GetOrCreateConfig( pProjectDataCollector->m_BaseConfigData.m_Configurations[1]->GetConfigName(), + pProjectDataCollector->m_BaseConfigData.m_Configurations[1] ); + + if ( !pFileSpecificData->GetOption( g_pOption_Outputs) ) + continue; + + CUtlString sOutputFiles; + sOutputFiles.SetLength( MAX_PATH ); + CUtlString sInputFile; + sInputFile.SetLength( MAX_PATH ); + V_snprintf( sInputFile.Get(), MAX_PATH, "%s/%s", pProjectDataCollector->m_ProjectName.String(), UsePOSIXSlashes( pDynamicFileConfig->m_Filename.String() ) ); + V_RemoveDotSlashes( sInputFile.Get() ); + + CBaseProjectDataCollector::DoStandardVisualStudioReplacements( pFileSpecificData->GetOption( g_pOption_Outputs), sInputFile, sOutputFiles.Get(), MAX_PATH ); + V_StrSubstInPlace( sOutputFiles.Get(), MAX_PATH, "$(OBJ_DIR)", "${OBJECT_FILE_DIR_normal}", false ); + + if ( V_stristr( sOutputFiles, V_UnqualifiedFileName( pDynamicFileConfig->GetName() ) ) && !pFileSpecificData->GetOption( g_pOption_AdditionalDependencies ) ) + { + g_pVPC->VPCWarning( "Not adding '%s' to the build sources list in project '%s', it's a dyanmic file and seems to be created by building '%s'\n", + pDynamicFileConfig->GetName(), + pProjectDataCollector->m_ProjectName.String(), + pFileConfig->GetName() ); + return true; + } + } + return false; +} + +void ResolveAdditionalProjectDependencies( CDependency_Project *pCurProject, CUtlVector<CDependency_Project*> &projects, CUtlVector<CDependency_Project*> &additionalProjectDependencies ) +{ + for ( int i=0; i < pCurProject->m_AdditionalProjectDependencies.Count(); i++ ) + { + const char *pLookingFor = pCurProject->m_AdditionalProjectDependencies[i].String(); + + int j; + for ( j=0; j < projects.Count(); j++ ) + { + if ( V_stricmp( projects[j]->m_ProjectName.String(), pLookingFor ) == 0 ) + break; + } + + if ( j == projects.Count() ) + g_pVPC->VPCError( "Project %s lists '%s' in its $AdditionalProjectDependencies, but there is no project by that name.", pCurProject->GetName(), pLookingFor ); + + additionalProjectDependencies.AddToTail( projects[j] ); + } +} + + +void CSolutionGenerator_Xcode::WriteFilesFolder( uint64_t oid, const char *pFolderName, const char *pExtensions, CBaseProjectDataCollector *pProject ) +{ + const CUtlDict<CFileConfig *,int> &files = pProject->m_Files; + + CUtlVector<char*> extensions; + V_SplitString( pExtensions, ";", extensions ); + + Write( "%024llX /* %s */ = {\n", oid, pFolderName ); + ++m_nIndent; + Write( "isa = PBXGroup;\n" ); + Write( "children = (\n" ); + ++m_nIndent; + + for ( int i=files.First(); i != files.InvalidIndex(); i=files.Next( i ) ) + { + const char *pFileName = files[i]->GetName(); + + // Check for duplicates -- projects may reference a file twice, and xcode does not enjoy any + // oid being a member of a group twice. + int idxDupe = files.Find( pFileName ); + if ( files.IsValidIndex( idxDupe ) && idxDupe != i ) + { + continue; + } + + // Make sure this file's extension is one of the extensions they're asking for. + bool bValidExt = false; + const char *pFileExtension = V_GetFileExtension( V_UnqualifiedFileName( pFileName ) ); + if ( pFileExtension ) + { + for ( int iExt=0; iExt < extensions.Count(); iExt++ ) + { + const char *pTestExt = extensions[iExt]; + + if ( pTestExt[0] == '*' && pTestExt[1] == '.' && V_stricmp( pTestExt+2, pFileExtension ) == 0 ) + { + bValidExt = true; + break; + } + } + } + + if ( bValidExt ) + { + Write( "%024llX /* %s in %s */,\n", makeoid2( pProject->GetProjectName(), pFileName, EOIDTypeFileReference ), UsePOSIXSlashes( pFileName ), pProject->GetProjectName().String() ); + } + } + + --m_nIndent; + Write( ");\n" ); + Write( "name = \"%s\";\n", pFolderName ); + Write( "sourceTree = \"<group>\";\n" ); + --m_nIndent; + Write( "};\n" ); +} + + +void CSolutionGenerator_Xcode::XcodeFileTypeFromFileName( const char *pszFileName, char *pchOutBuf, int cchOutBuf ) +{ + const char *pchExtension = V_GetFileExtension( V_UnqualifiedFileName( pszFileName ) ); + if ( !pchExtension ) + snprintf( pchOutBuf, cchOutBuf, "compiled.mach-o.executable" ); + else if ( ! V_stricmp( pchExtension, "cpp" ) || ! V_stricmp( pchExtension, "cxx" ) || ! V_stricmp( pchExtension, "cc" ) || ! V_stricmp( pchExtension, "h" ) || ! V_stricmp( pchExtension, "hxx" ) || ! V_stricmp( pchExtension, "cc" ) ) + snprintf( pchOutBuf, cchOutBuf, "sourcecode.cpp.%s", pchExtension ); + else if ( ! V_stricmp( pchExtension, "c" ) ) + snprintf( pchOutBuf, cchOutBuf, "sourcecode.cpp.cpp" ); + else if ( ! V_stricmp( pchExtension, "m" ) || ! V_stricmp( pchExtension, "mm" ) ) + snprintf( pchOutBuf, cchOutBuf, "sourcecode.objc.%s", pchExtension ); + else if ( ! V_stricmp( pchExtension, "a" ) ) + snprintf( pchOutBuf, cchOutBuf, "archive.ar" ); + else if ( ! V_stricmp( pchExtension, "dylib" ) ) + { + const char *pszLibName = V_UnqualifiedFileName( pszFileName ); + if ( pszLibName[0] == 'l' && pszLibName[1] == 'i' && pszLibName[2] == 'b' ) + snprintf( pchOutBuf, cchOutBuf, "compiled.mach-o.dylib" ); + else + snprintf( pchOutBuf, cchOutBuf, "compiled.mach-o.bundle" ); + } + else if ( ! V_stricmp( pchExtension, "pl" ) ) + snprintf( pchOutBuf, cchOutBuf, "text.script.perl" ); + else + snprintf( pchOutBuf, cchOutBuf, "text.plain" ); +} + + +void CSolutionGenerator_Xcode::XcodeProductTypeFromFileName( const char *pszFileName, char *pchOutBuf, int cchOutBuf ) +{ + const char *pchExtension = V_GetFileExtension( V_UnqualifiedFileName( pszFileName ) ); + if ( !pchExtension ) + snprintf( pchOutBuf, cchOutBuf, "com.apple.product-type.tool" ); + else if ( ! V_stricmp( pchExtension, "a" ) ) + snprintf( pchOutBuf, cchOutBuf, "com.apple.product-type.library.static" ); + else if ( ! V_stricmp( pchExtension, "dylib" ) ) + { + snprintf( pchOutBuf, cchOutBuf, "com.apple.product-type.library.dynamic" ); +#if 0 + const char *pszLibName = V_UnqualifiedFileName( pszFileName ); + if ( pszLibName[0] != 'l' || pszLibName[1] != 'i' || pszLibName[2] != 'b' ) + snprintf( pchOutBuf, cchOutBuf, "com.apple.product-type.bundle" ); +#endif + } + else + snprintf( pchOutBuf, cchOutBuf, "com.apple.product-type.unknown" ); +} + +// GetBool only groks 1/0, we want more flexibility +bool IsTrue(const char *str) +{ + if ( V_strlen(str) && ( !V_stricmp( str, "yes" ) || !V_stricmp( str, "true" ) || !V_stricmp( str, "1" ) ) ) + return true; + return false; +} + +void CSolutionGenerator_Xcode::EmitBuildSettings( const char *pszProjectName, const char *pszProjectDir, CUtlDict<CFileConfig *,int> *pDictFiles, KeyValues *pConfigKV, KeyValues *pFirstConfigKV, bool bIsDebug ) +{ + if ( !pConfigKV ) + { + Write( "PRODUCT_NAME = \"%s\";\n", pszProjectName ); + return; + } + + // KeyValuesDumpAsDevMsg( pConfigKV, 0, 0 ); + + // Write( "CC = \"$(SOURCE_ROOT)/devtools/bin/osx32/xcode_ccache_wrapper\";\n" ); + // Write( "LDPLUSPLUS = \"$(DT_TOOLCHAIN_DIR)/usr/bin/clang++\";\n" ); + + Write( "ARCHS = (\n" ); + { + ++m_nIndent; + bool bBuildX64 = IsTrue(pConfigKV->GetString( g_pOption_BuildX64Only, "" )) || IsTrue(pConfigKV->GetString( g_pOption_BuildMultiArch, "" ) ); + bool bBuildi386 = !IsTrue( pConfigKV->GetString( g_pOption_BuildX64Only, "" ) ); + if ( bBuildi386 ) + Write( "i386,\n" ); + if ( bBuildX64 ) + { + Write( "x86_64,\n" ); + } + --m_nIndent; + } + Write( ");\n" ); + + // We do not handle Output file names changing between configurations, and use the first configuration for such + // things all over the generator. I think we would need to duplicate all the targets to be release and debug + // targets. Instead, when generating configurations, just warn that this isn't supported. + CUtlString sBuildOutputFile = OutputFileWithDirectoryFromConfig( pFirstConfigKV ); + CUtlString sGameOutputFile = GameOutputFileFromConfig( pFirstConfigKV ); + for ( int iConfig = 1; iConfig < V_ARRAYSIZE(k_rgchXCConfigFiles); iConfig++ ) + { + CUtlString sConfigOutputFile = OutputFileWithDirectoryFromConfig( pConfigKV ); + CUtlString sConfigGameOutputFile = GameOutputFileFromConfig( pConfigKV ); + if ( sConfigOutputFile != sBuildOutputFile || sConfigGameOutputFile != sGameOutputFile ) + { + g_pVPC->VPCWarning( "Config '%s' for project '%s' has effective output files:\n" + " $OutputDirectory/$OutputFile: %s\n" + " $GameOutputFile: %s\n" + " This differs from the first configuration's output files:\n" + " $OutputDirectory/$OutputFile: %s\n" + " $GameOutputFile: %s\n" + " XCode does not support having differing product names per config,\n" + " the first configuration's names will be used for all configs.", + k_rgchConfigNames[iConfig], pszProjectName, + sConfigOutputFile.String(), sConfigGameOutputFile.String(), + sBuildOutputFile.String(), sGameOutputFile.String() ); + } + } + + if ( sGameOutputFile.Length() ) + { + Write( "PRODUCT_NAME = \"%s\";\n", pszProjectName ); + Write( "EXECUTABLE_NAME = \"%s\";\n", sBuildOutputFile.String() ); + + if ( V_strlen( pConfigKV->GetString( g_pOption_ExtraLinkerFlags, "" ) ) ) + Write( "OTHER_LDFLAGS = \"%s\";\n", pConfigKV->GetString( g_pOption_ExtraLinkerFlags ) ); + + + CUtlString sOtherCompilerCFlags = "OTHER_CFLAGS = \"$(OTHER_CFLAGS) "; + CUtlString sOtherCompilerCPlusFlags = "OTHER_CPLUSPLUSFLAGS = \"$(OTHER_CPLUSPLUSFLAGS) "; + + // Buffer overflow checks default to on so only change things + // if we need to turn them off. + bool bBufferSecurityCheck = Sys_StringToBool( pConfigKV->GetString( g_pOption_BufferSecurityCheck, "Yes" ) ); + if ( !bBufferSecurityCheck ) + { + sOtherCompilerCFlags += "-fno-stack-protector "; + sOtherCompilerCPlusFlags += "-fno-stack-protector "; + } + + if ( V_strlen( pConfigKV->GetString( g_pOption_ExtraCompilerFlags, "" ) ) ) + { + sOtherCompilerCFlags += pConfigKV->GetString( g_pOption_ExtraCompilerFlags ); + sOtherCompilerCPlusFlags += pConfigKV->GetString( g_pOption_ExtraCompilerFlags ); + } + + if ( V_strlen( pConfigKV->GetString( g_pOption_ForceInclude, "" ) ) ) + { + + CSplitString outStrings( pConfigKV->GetString( g_pOption_ForceInclude ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < outStrings.Count(); i++ ) + { + if ( V_strlen( outStrings[i] ) > 2 ) + { + //char sIncludeDir[ MAX_PATH ]; + char szIncludeLine[ MAX_PATH ]; + /*V_snprintf( sIncludeDir, sizeof( sIncludeDir ), "%s/%s", pszProjectDir, outStrings[i] ); + V_FixSlashes( sIncludeDir, '/' ); + V_RemoveDotSlashes( sIncludeDir ); + #ifdef STEAM + V_StripPrecedingAndTrailingWhitespace( sIncludeDir ); + #endif */ + V_snprintf( szIncludeLine, sizeof(szIncludeLine), " -include %s", UsePOSIXSlashes( outStrings[i] ) ); + sOtherCompilerCFlags += szIncludeLine; + sOtherCompilerCPlusFlags += szIncludeLine; + } + } + } + + sOtherCompilerCFlags += "\";\n" ; + sOtherCompilerCPlusFlags += "\";\n" ; + + Write( sOtherCompilerCFlags ); + Write( sOtherCompilerCPlusFlags ); + + if ( IsDynamicLibrary( sGameOutputFile ) ) + { + char szBaseName[MAX_PATH] = { 0 }; + V_StripExtension( V_UnqualifiedFileName( sGameOutputFile ), szBaseName, sizeof( szBaseName ) ); + + if ( Sys_StringToBool( pConfigKV->GetString( g_pOption_LinkAsBundle, "No" ) ) ) + { + Write( "MACH_O_TYPE = mh_bundle;\n" ); + // Bundles can't have versions and they're defaulted to 1 + // so make sure we have our own no-version properties. + Write( "DYLIB_COMPATIBILITY_VERSION = \"\";\n" ); + Write( "DYLIB_CURRENT_VERSION = \"\";\n" ); + } + else if ( szBaseName[0] != 'l' || szBaseName[1] != 'i' || szBaseName[2] == 'b' ) + { + //if ( !pConfigKV->GetString( g_pOption_LocalFrameworks, NULL ) ) + // Write( "OTHER_LDFLAGS = \"-flat_namespace\";\n" ); + // Write( "MACH_O_TYPE = mh_bundle;\n" ); + // Write( "EXECUTABLE_EXTENSION = dylib;\n" ); + // Write( "OTHER_LDFLAGS = \"-flat_namespace -undefined suppress\";\n" ); + } + else + { + Write( "MACH_O_TYPE = mh_dylib;\n" ); + } + + Write( "LD_DYLIB_INSTALL_NAME = \"@loader_path/%s.dylib\";\n", szBaseName ); + } + + if ( IsStaticLibrary( sGameOutputFile ) ) + { + Write( "DEBUG_INFORMATION_FORMAT = dwarf;\n" ); + } + } + else + Write( "PRODUCT_NAME = \"%s\";\n", pszProjectName ); + + // add our header search paths + CSplitString outStrings( pConfigKV->GetString( g_pOption_AdditionalIncludeDirectories ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + if ( outStrings.Count() ) + { + char sIncludeDir[MAX_PATH]; + + // start the iquote list with the project directory + V_snprintf( sIncludeDir, sizeof( sIncludeDir ), "%s", pszProjectDir ); + V_FixSlashes( sIncludeDir, '/' ); + V_RemoveDotSlashes( sIncludeDir ); +#ifdef STEAM + V_StripPrecedingAndTrailingWhitespace( sIncludeDir ); +#endif + + Write( "USER_HEADER_SEARCH_PATHS = (\n" ); + ++m_nIndent; +#ifdef STEAM + Write( "\"%s\",\n", sIncludeDir ); +#endif + for ( int i=0; i < outStrings.Count(); i++ ) + { + char sExpandedOutString[MAX_PATH]; + + CBaseProjectDataCollector::DoStandardVisualStudioReplacements( outStrings[i], CFmtStr( "%s/dummy.txt", pszProjectDir ).Access(), sExpandedOutString, sizeof( sExpandedOutString ) ); + V_StrSubstInPlace( sExpandedOutString, sizeof( sExpandedOutString ), "$(OBJ_DIR)", "\"${OBJECT_FILE_DIR_normal}\"", false ); + V_StrSubstInPlace( sExpandedOutString, sizeof( sExpandedOutString ), "\"", "\\\"", false ); + + if ( V_IsAbsolutePath( sExpandedOutString ) || V_strncmp( sExpandedOutString, "$", 1 ) == 0 ) + V_snprintf( sIncludeDir, sizeof( sExpandedOutString ), "%s", sExpandedOutString ); + else + { + V_snprintf( sIncludeDir, sizeof( sExpandedOutString ), "%s/%s", pszProjectDir, sExpandedOutString ); + V_RemoveDotSlashes( sIncludeDir ); + } +#ifdef STEAM + V_StripPrecedingAndTrailingWhitespace( sIncludeDir ); +#endif + Write( "\"%s\",\n", sIncludeDir ); + } + --m_nIndent; + Write( ");\n" ); + } + + + // add local frameworks we link against to the compiler framework search paths + CSplitString localFrameworks( pConfigKV->GetString( g_pOption_LocalFrameworks ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + if ( localFrameworks.Count() ) + { + Write( "FRAMEWORK_SEARCH_PATHS = (\n" ); + ++m_nIndent; + { + Write( "\"$(inherited)\",\n" ); + for ( int i=0; i < localFrameworks.Count(); i++ ) + { + char rgchFrameworkPath[MAX_PATH]; + V_snprintf( rgchFrameworkPath, sizeof( rgchFrameworkPath ), "%s/%s", pszProjectDir, localFrameworks[i] ); + rgchFrameworkPath[ V_strlen( rgchFrameworkPath ) - V_strlen( V_UnqualifiedFileName( localFrameworks[i] ) ) ] = '\0'; + V_RemoveDotSlashes( rgchFrameworkPath ); + + Write( "\"%s\",\n", rgchFrameworkPath ); + } + } + --m_nIndent; + Write( ");\n" ); + } + + // add our needed preprocessor definitions + CSplitString preprocessorDefines( pConfigKV->GetString( g_pOption_PreprocessorDefinitions ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + CUtlVector< macro_t* > vpcMacroDefines; + g_pVPC->GetMacrosMarkedForCompilerDefines( vpcMacroDefines ); + if ( preprocessorDefines.Count() || vpcMacroDefines.Count() ) + { + Write( "GCC_PREPROCESSOR_DEFINITIONS = (\n" ); + ++m_nIndent; + { + Write( "\"$(GCC_PREPROCESSOR_DEFINITIONS)\",\n" ); + for ( int i=0; i < preprocessorDefines.Count(); i++ ) + { + Write( "\"%s\",\n", preprocessorDefines[i] ); + } + for ( int i=0; i < vpcMacroDefines.Count(); i++ ) + { + Write( "\"%s=%s\",\n", vpcMacroDefines[i]->name.String(), vpcMacroDefines[i]->value.String() ); + } + } + --m_nIndent; + Write( ");\n" ); + } + + bool bTreatWarningsAsErrors = Sys_StringToBool( pConfigKV->GetString( g_pOption_TreatWarningsAsErrors, "false" ) ); + Write( "GCC_TREAT_WARNINGS_AS_ERRORS = %s;\n", bTreatWarningsAsErrors ? "YES" : "NO" ); + + CUtlMap<const char *, bool> librarySearchPaths( StringLessThan ); + if ( pDictFiles ) + { + // libraries we consume (specified in our files list) + for ( int i=pDictFiles->First(); i != pDictFiles->InvalidIndex(); i=pDictFiles->Next(i) ) + { + const char *pFileName = (*pDictFiles)[i]->m_Filename.String(); + if ( IsStaticLibrary( pFileName ) || IsDynamicLibrary( pFileName ) ) + { + char rgchLibPath[MAX_PATH]; + V_snprintf( rgchLibPath, sizeof( rgchLibPath ), "%s/%s", pszProjectDir, pFileName ); + V_RemoveDotSlashes( rgchLibPath ); + V_StripFilename( rgchLibPath ); + int nIndex = librarySearchPaths.Find( rgchLibPath ); + if ( nIndex == librarySearchPaths.InvalidIndex() ) + { + char *pszLibPath = new char[MAX_PATH]; + V_strncpy( pszLibPath, rgchLibPath, MAX_PATH ); + nIndex = librarySearchPaths.Insert( pszLibPath ); + } + } + } + } + + // add additional library search paths + CSplitString additionalLibraryDirectories( pConfigKV->GetString( g_pOption_AdditionalLibraryDirectories ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i = 0; i < additionalLibraryDirectories.Count(); i++ ) + { + int nIndex = librarySearchPaths.Find( additionalLibraryDirectories[i] ); + if ( nIndex == librarySearchPaths.InvalidIndex() ) + { + // we need to dup the string so the map can free it later + char *pszLibPath = new char[MAX_PATH]; + V_strncpy( pszLibPath, additionalLibraryDirectories[i], MAX_PATH ); + nIndex = librarySearchPaths.Insert( pszLibPath ); + } + } + if ( librarySearchPaths.Count() ) + { + char sIncludeDir[MAX_PATH]; + + // add the library path we know we need to reference + Write( "LIBRARY_SEARCH_PATHS = (\n" ); + ++m_nIndent; + { + Write( "\"$(inherited)\",\n" ); + FOR_EACH_MAP_FAST( librarySearchPaths, i ) + { + char sExpandedOutString[MAX_PATH]; + V_strncpy( sExpandedOutString, librarySearchPaths.Key(i), sizeof( sExpandedOutString ) ); + V_StrSubstInPlace( sExpandedOutString, sizeof( sExpandedOutString ), "\"", "\\\"", false ); + + if ( V_IsAbsolutePath( sExpandedOutString ) || V_strncmp( sExpandedOutString, "$", 1 ) == 0 ) + V_snprintf( sIncludeDir, sizeof( sExpandedOutString ), "%s", sExpandedOutString ); + else + { + V_snprintf( sIncludeDir, sizeof( sExpandedOutString ), "%s/%s", pszProjectDir, sExpandedOutString ); + V_RemoveDotSlashes( sIncludeDir ); + } + + Write( "\"%s\",\n", sIncludeDir ); + } + } + --m_nIndent; + Write( ");\n" ); + } + + while ( librarySearchPaths.Count() ) + { + const char *key = librarySearchPaths.Key( librarySearchPaths.FirstInorder() ); + librarySearchPaths.Remove( key ); + delete [] key; + } +} + +class CStringLess +{ +public: + bool Less( const char *lhs, const char *rhs, void *pCtx ) + { + return ( strcmp( lhs, rhs ) < 0 ? true : false ); + } +}; + +void CSolutionGenerator_Xcode::GenerateSolutionFile( const char *pSolutionFilename, CUtlVector<CDependency_Project*> &projects ) +{ + CFmtStr oidStrSolutionRoot( "solutionroot.%s", pSolutionFilename ); + CFmtStr oidStrProjectsRoot( "projectsroot.%s", pSolutionFilename ); + + Assert( projects.Count() == g_vecPGenerators.Count() ); + + char sPbxProjFile[MAX_PATH]; + sprintf( sPbxProjFile, "%s.xcodeproj", pSolutionFilename ); + mkdir( sPbxProjFile, 0777 ); + sprintf( sPbxProjFile, "%s.xcodeproj/project.pbxproj", pSolutionFilename ); + + char sProjProjectListFile[MAX_PATH]; + V_snprintf( sProjProjectListFile, sizeof( sProjProjectListFile ), "%s.projects", sPbxProjFile ); + + bool bUpToDate = !g_pVPC->IsForceGenerate() && Sys_Exists( sPbxProjFile ); + int64 llSize = 0, llModTime = 0, llLastModTime = 0; + + FOR_EACH_VEC( projects, iProject ) + { + AssertFatal( !V_strcmp( projects[iProject]->m_ProjectName, g_vecPGenerators[iProject]->GetProjectName() ) ); + // the solution is up-to-date only if all the projects in it were up to date + // and the solution was built after the mod time on all the project outputs + CProjectGenerator_Xcode *pProjGen = dynamic_cast<CProjectGenerator_Xcode*>(g_vecPGenerators[iProject]); + bUpToDate &= pProjGen->m_bIsCurrent; + if ( bUpToDate && Sys_FileInfo( pProjGen->m_OutputFilename, llSize, llModTime ) && llModTime > llLastModTime ) + { + llLastModTime = llModTime; + } + } + + // regenerate pbxproj if it is older than the latest of the project output files + if ( bUpToDate && ( !Sys_FileInfo( sPbxProjFile, llSize, llModTime ) || llModTime < llLastModTime ) ) + { + bUpToDate = false; + } + + // now go see if our project list agrees with the one on disk + if ( bUpToDate ) + { + FILE *fp = fopen( sProjProjectListFile, "r+t" ); + if ( !fp ) + bUpToDate = false; + + char line[2048]; + char *pLine; + if ( bUpToDate ) + { + pLine = fgets( line, sizeof(line), fp ); + if (!pLine) + bUpToDate = false; + if ( stricmp( line, VPCCRCCHECK_FILE_VERSION_STRING "\n" ) ) + bUpToDate = false; + } + + int cProjectsPreviously = 0; + while (bUpToDate) + { + pLine = fgets( line, sizeof(line), fp ); + if ( !pLine ) + break; + + ++cProjectsPreviously; + + int len = strlen( line ) - 1; + while ( line[len] == '\n' || line[len] == '\r' ) + { + line[len] = '\0'; + len--; + } + + // N^2 sucks, but N is small + bool bProjectFound = false; + FOR_EACH_VEC( g_vecPGenerators, iGenerator ) + { + CProjectGenerator_Xcode *pGenerator = (CProjectGenerator_Xcode*)g_vecPGenerators[iGenerator]; + if ( stricmp( pGenerator->m_ProjectName.String(), pLine ) == 0 ) + { + bProjectFound = true; + break; + } + } + if ( !bProjectFound ) + { + // fprintf( stderr, "%s has vanished from the project, regenerating...\n", pLine ); + bUpToDate = false; + break; + } + } + if ( g_vecPGenerators.Count() != cProjectsPreviously ) + { + // fprintf( stderr, "Project count has changed (%d/%d), regenerating...\n", cProjectsPreviously, g_vecPGenerators.Count() ); + bUpToDate = false; + } + fclose(fp); + } + + if ( bUpToDate ) + { + g_pVPC->VPCStatus( true, "Xcode Project %s.xcodeproj looks up-to-date, not generating", pSolutionFilename ); + return; + } + + m_fp = fopen( sPbxProjFile, "wt" ); + m_nIndent = 0; + + Msg( "\nWriting master Xcode project %s.xcodeproj.\n\n", pSolutionFilename ); + + /** header **/ + Write( "// !$*UTF8*$!\n{\n" ); + ++m_nIndent; + { + /** + ** + ** preamble + ** + **/ + Write( "archiveVersion = 1;\n" ); + Write( "classes = {\n" ); + Write( "};\n" ); + Write( "objectVersion = 44;\n" ); + Write( "objects = {\n" ); + { + /** + ** + ** buildfiles - any file that's involved in, or the output of, a build phase + ** + **/ + Write( "\n/* Begin PBXBuildFile section */" ); + ++m_nIndent; + { + FOR_EACH_VEC( g_vecPGenerators, iGenerator ) + { + // poke into the project we're looking @ in the dependency projects vector to figure out it's location on disk + char rgchProjectDir[MAX_PATH]; rgchProjectDir[0] = '\0'; + V_strncpy( rgchProjectDir, projects[iGenerator]->m_ProjectFilename.String(), sizeof( rgchProjectDir ) ); + V_StripFilename( rgchProjectDir ); + + // the files this project references + for ( int i=g_vecPGenerators[iGenerator]->m_Files.First(); i != g_vecPGenerators[iGenerator]->m_Files.InvalidIndex(); i=g_vecPGenerators[iGenerator]->m_Files.Next(i) ) + { + char rgchFilePath[MAX_PATH]; + V_snprintf( rgchFilePath, sizeof( rgchFilePath ), "%s/%s", rgchProjectDir, g_vecPGenerators[iGenerator]->m_Files[i]->m_Filename.String() ); + V_RemoveDotSlashes( rgchFilePath ); + + CFileConfig *pFileConfig = g_vecPGenerators[iGenerator]->m_Files[i]; + const char *pFileName = pFileConfig->m_Filename.String(); + + bool bExcluded = true; + for ( int iConfig = 0; iConfig < V_ARRAYSIZE(k_rgchConfigNames); iConfig++ ) + { + bExcluded &= ( pFileConfig->IsExcludedFrom( k_rgchConfigNames[iConfig] ) ); + } + + if ( bExcluded ) + { + g_pVPC->VPCStatus( false, "xcode: excluding File %s\n", pFileName ); + continue; + } + + + // dynamic files - generated as part of the build - may be automatically added to the build set by xcode, + // if we add them twice, bad things (duplicate symbols) happen. + bool bIsDynamicFile = pFileConfig->IsDynamicFile( k_rgchConfigNames[1] ); + + // if we have a custom build step, we need to include this file in the build set + if ( ( !bIsDynamicFile || !IsCreatedByCustomBuildStep( g_vecPGenerators[iGenerator], pFileConfig ) ) && AppearsInSourcesBuildPhase( g_vecPGenerators[iGenerator], g_vecPGenerators[iGenerator]->m_Files[i] ) ) + { + Write( "\n" ); + CUtlString sCompilerFlags = NULL; + // on mac we can only globally specify common (debug and release) per-file compiler flags + for ( int i=pFileConfig->m_Configurations.First(); i != pFileConfig->m_Configurations.InvalidIndex(); i=pFileConfig->m_Configurations.Next(i) ) + { + sCompilerFlags += pFileConfig->m_Configurations[i]->m_pKV->GetString( g_pOption_ExtraCompilerFlags ); + } + // File reference OIDs are unique per project per file + Write( "%024llX /* %s in Sources */ = {isa = PBXBuildFile; fileRef = %024llX /* %s */; ", makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pFileName, EOIDTypeBuildFile ), V_UnqualifiedFileName( pFileName ), makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pFileName, EOIDTypeFileReference ), pFileName ); + if ( !sCompilerFlags.IsEmpty() ) + { + Write( "settings = { COMPILER_FLAGS = \"%s\"; };", sCompilerFlags.String() ); + } + Write( " };" ); + } + + if ( IsDynamicLibrary( pFileName ) ) + { + Write( "\n" ); + Write( "%024llX /* %s in Frameworks */ = {isa = PBXBuildFile; fileRef = %024llX /* %s */; };", makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pFileName, EOIDTypeBuildFile ), V_UnqualifiedFileName( pFileName ), makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pFileName, EOIDTypeFileReference ), pFileName ); + } + + if ( IsStaticLibrary( pFileName ) ) + { + Write( "\n" ); + Write( "%024llX /* %s in Frameworks */ = {isa = PBXBuildFile; fileRef = %024llX /* %s */; };", + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pFileName, EOIDTypeBuildFile ), pFileName, + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pFileName, EOIDTypeFileReference ), pFileName ); + } + } + + // system libraries we link against + KeyValues *pKV = g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[0]->m_pKV; + CSplitString libs( pKV->GetString( g_pOption_SystemLibraries ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < libs.Count(); i++ ) + { + Write( "\n" ); + Write( "%024llX /* lib%s.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = %024llX /* lib%s.dylib */; };", + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pKV->GetString( g_pOption_SystemLibraries ), EOIDTypeBuildFile, i ), libs[i], + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pKV->GetString( g_pOption_SystemLibraries ), EOIDTypeFileReference, i ), libs[i] ); + } + + // system frameworks we link against + CSplitString sysFrameworks( pKV->GetString( g_pOption_SystemFrameworks ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < sysFrameworks.Count(); i++ ) + { + Write( "\n" ); + Write( "%024llX /* %s.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = %024llX /* %s.framework */; };", + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pKV->GetString( g_pOption_SystemFrameworks ), EOIDTypeBuildFile, i ), sysFrameworks[i], + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pKV->GetString( g_pOption_SystemFrameworks ), EOIDTypeFileReference, i ), sysFrameworks[i] ); + } + + // local frameworks we link against + CSplitString localFrameworks( pKV->GetString( g_pOption_LocalFrameworks ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < localFrameworks.Count(); i++ ) + { + char rgchFrameworkName[MAX_PATH]; + V_StripExtension( V_UnqualifiedFileName( localFrameworks[i] ), rgchFrameworkName, sizeof( rgchFrameworkName ) ); + + Write( "\n" ); + Write( "%024llX /* %s.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = %024llX /* %s.framework */; };", + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pKV->GetString( g_pOption_LocalFrameworks ), EOIDTypeBuildFile, i ), rgchFrameworkName, + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pKV->GetString( g_pOption_LocalFrameworks ), EOIDTypeFileReference, i ), rgchFrameworkName ); + } + + + // look at everyone who depends on us, and emit a build file pointing at our output file for each of + // them to depend upon. We use the OutputFile (products directory) so XCode's dependency/linking + // logic works right. + // + // The oid has the project in question as the ordinal, so we have a unique build file OID for each + // project that wants to depend on us -- they all point to the same file reference. + CDependency_Project *pCurProject = projects[iGenerator]; + CUtlString sGameOutputFile = GameOutputFileFromConfig( pKV ); + CUtlString sOutputFile = OutputFileWithDirectoryFromConfig( pKV ); + + if ( sOutputFile.Length() && ( IsStaticLibrary( sOutputFile ) || IsDynamicLibrary( sOutputFile ) ) ) + { + for ( int iTestProject=0; iTestProject < projects.Count(); iTestProject++ ) + { + if ( iGenerator == iTestProject ) + continue; + + CDependency_Project *pTestProject = projects[iTestProject]; + + CUtlVector<CDependency_Project*> additionalProjectDependencies; + ResolveAdditionalProjectDependencies( pTestProject, projects, additionalProjectDependencies ); + + int dependsOnFlags = k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse; + if ( pTestProject->DependsOn( pCurProject, dependsOnFlags ) || additionalProjectDependencies.Find( pCurProject ) != additionalProjectDependencies.InvalidIndex() ) + { + Write( "\n" ); + Write( "%024llX /* (lib)%s */ = {isa = PBXBuildFile; fileRef = %024llX /* (lib)%s - depended on by %s */; };", + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), sOutputFile, EOIDTypeBuildFile, iTestProject ), + sOutputFile.String(), + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), sOutputFile, EOIDTypeFileReference ), + sOutputFile.String(), + pTestProject->m_ProjectName.String() ); + } + } + } + + // Add our our output file and game output file -1 OID for ourselves. + if ( sGameOutputFile.Length() ) + { + Write( "\n" ); + Write( "%024llX /* %s */ = {isa = PBXBuildFile; fileRef = %024llX /* %s */; };", + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), sGameOutputFile, EOIDTypeBuildFile, -1 ), + sGameOutputFile.String(), + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), sGameOutputFile, EOIDTypeFileReference ), + sGameOutputFile.String() ); + } + + if ( sOutputFile.Length() ) + { + Write( "\n" ); + Write( "%024llX /* %s in Products */ = {isa = PBXBuildFile; fileRef = %024llX /* %s */; };", + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), sOutputFile, EOIDTypeBuildFile, -1 ), + sOutputFile.String(), + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), sOutputFile, EOIDTypeFileReference ), + sOutputFile.String() ); + } + } + } + --m_nIndent; + Write( "\n/* End PBXBuildFile section */\n" ); + + Write( "\n/*Begin PBXBuildRule section */\n" ); + ++m_nIndent; + { + FOR_EACH_VEC( g_vecPGenerators, iGenerator ) + { + CProjectGenerator_Xcode *pGenerator = (CProjectGenerator_Xcode*)g_vecPGenerators[iGenerator]; + + if ( !ProjectProducesBinary( pGenerator ) ) + continue; + + char rgchProjectDir[MAX_PATH]; rgchProjectDir[0] = '\0'; + V_strncpy( rgchProjectDir, projects[iGenerator]->m_ProjectFilename.String(), sizeof( rgchProjectDir ) ); + V_StripFilename( rgchProjectDir ); + + // we don't have an output file - wander the list of files, looking for custom build steps + // if we find any, magic up shell scripts to run them + for ( int i=g_vecPGenerators[iGenerator]->m_Files.First(); i != g_vecPGenerators[iGenerator]->m_Files.InvalidIndex(); i=g_vecPGenerators[iGenerator]->m_Files.Next(i) ) + { + + CFileConfig *pFileConfig = g_vecPGenerators[iGenerator]->m_Files[i]; + CSpecificConfig *pFileSpecificData = pFileConfig->GetOrCreateConfig( g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[1]->GetConfigName(), + g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[1] ); + + // custom build rules with additional dependencies don't map to pbxbuildrules, we handle them + // as custom script phases + if ( pFileSpecificData->GetOption( g_pOption_AdditionalDependencies ) ) + continue; + + CUtlString sCustomBuildCommandLine = pFileSpecificData->GetOption( g_pOption_CustomBuildStepCommandLine ); + CUtlString sOutputFiles = pFileSpecificData->GetOption( g_pOption_Outputs ); + CUtlString sCommand; + + if ( sOutputFiles.Length() && !sCustomBuildCommandLine.IsEmpty() ) + { + CUtlString sInputFile; + sInputFile.SetLength( MAX_PATH ); + + int cCommand = MAX( sCustomBuildCommandLine.Length() * 2, 8 * 1024 ); + sCommand.SetLength( cCommand ); + + Write( "\n" ); + Write( "%024llX /* PBXbuildRule */ = {\n", makeoid( projects[iGenerator]->m_ProjectName, EOIDTypeCustomBuildRule, pGenerator->m_nCustomBuildRules++ ) ); + ++m_nIndent; + { + Write( "isa = PBXBuildRule;\n" ); + Write( "compilerSpec = com.apple.compilers.proxy.script;\n" ); + + // DoStandardVisualStudioReplacements needs to know where the file is, so make sure it's got a path on it + if ( V_IsAbsolutePath( UsePOSIXSlashes( pFileConfig->m_Filename.String() ) ) ) + V_snprintf( sInputFile.Get(), MAX_PATH, "%s", UsePOSIXSlashes( pFileConfig->m_Filename.String() ) ); + else + { + V_snprintf( sInputFile.Get(), MAX_PATH, "%s/%s", rgchProjectDir, UsePOSIXSlashes( pFileConfig->m_Filename.String() ) ); + V_RemoveDotSlashes( sInputFile.Get() ); + } + Write( "filePatterns = \"%s\";\n", sInputFile.String() ); + Write( "fileType = pattern.proxy;\n" ); + Write( "isEditable = 1;\n" ); + + Write( "outputFiles = (\n" ); + ++m_nIndent; + { + CSplitString outFiles( sOutputFiles, ";" ); + for ( int i = 0; i < outFiles.Count(); i ++ ) + { + CUtlString sOutputFile; + sOutputFile.SetLength( MAX_PATH ); + CBaseProjectDataCollector::DoStandardVisualStudioReplacements( outFiles[i], sInputFile, sOutputFile.Get(), MAX_PATH ); + V_StrSubstInPlace( sOutputFile.Get(), MAX_PATH, "$(OBJ_DIR)", "${OBJECT_FILE_DIR_normal}", false ); + + CUtlString sOutputPath; + sOutputPath.SetLength( MAX_PATH ); + + if ( V_IsAbsolutePath( sOutputFile ) || V_strncmp( outFiles[i], "$", 1 ) == 0 ) + V_snprintf( sOutputPath.Get(), MAX_PATH, "%s", sOutputFile.String() ); + else + { + V_snprintf( sOutputPath.Get(), MAX_PATH, "%s/%s", rgchProjectDir, sOutputFile.String() ); + V_RemoveDotSlashes( sOutputPath.Get() ); + } + Write( "\"%s\",\n", sOutputPath.String() ); + } + } + --m_nIndent; + Write( ");\n"); + CBaseProjectDataCollector::DoStandardVisualStudioReplacements( sCustomBuildCommandLine, sInputFile, sCommand.Get(), cCommand ); + V_StrSubstInPlace( sCommand.Get(), cCommand, "$(OBJ_DIR)", "\"${OBJECT_FILE_DIR_normal}\"", false ); + V_StrSubstInPlace( sCommand.Get(), cCommand, ";", ";\\n", false ); + V_StrSubstInPlace( sCommand.Get(), cCommand, "\"", "\\\"", false ); + + Write( "script = \"#!/bin/bash\\n" + "cd %s\\n" + "%s\\n" + "exit $?\";\n", rgchProjectDir, sCommand.String() ); + } + --m_nIndent; + Write( "};" ); + + } + } + } + } + --m_nIndent; + Write( "\n/*End PBXBuildRule section */\n" ); + + /** + ** + ** file references - any file that appears in the project browser + ** + **/ + Write( "\n/* Begin PBXFileReference section */" ); + ++m_nIndent; + { + // include the xcconfig files + for ( int iConfig = 0; iConfig < V_ARRAYSIZE(k_rgchXCConfigFiles); iConfig++ ) + { + char rgchFilePath[MAX_PATH]; + V_snprintf( rgchFilePath, sizeof( rgchFilePath ), "%s.xcodeproj/../devtools/%s", pSolutionFilename, k_rgchXCConfigFiles[iConfig] ); + V_RemoveDotSlashes( rgchFilePath ); + + Write( "\n" ); + Write( "%024llX /* %s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = \"%s\"; path = \"%s\"; sourceTree = \"<absolute>\"; };", + makeoid2( oidStrSolutionRoot, k_rgchXCConfigFiles[iConfig], EOIDTypeFileReference ), + k_rgchXCConfigFiles[iConfig], + k_rgchXCConfigFiles[iConfig], + rgchFilePath + ); + } + + FOR_EACH_VEC( g_vecPGenerators, iGenerator ) + { + // find the project we're looking @ in the dependency projects vector to figure out it's location on disk + char rgchProjectDir[MAX_PATH]; rgchProjectDir[0] = '\0'; + V_strncpy( rgchProjectDir, projects[iGenerator]->m_ProjectFilename.String(), sizeof( rgchProjectDir ) ); + V_StripFilename( rgchProjectDir ); + + + for ( int i=g_vecPGenerators[iGenerator]->m_Files.First(); i != g_vecPGenerators[iGenerator]->m_Files.InvalidIndex(); i=g_vecPGenerators[iGenerator]->m_Files.Next(i) ) + { + char rgchFilePath[MAX_PATH]; + V_snprintf( rgchFilePath, sizeof( rgchFilePath ), "%s/%s", rgchProjectDir, g_vecPGenerators[iGenerator]->m_Files[i]->m_Filename.String() ); + V_RemoveDotSlashes( rgchFilePath ); + + const char *pFileName = V_UnqualifiedFileName( g_vecPGenerators[iGenerator]->m_Files[i]->m_Filename.String() ); + + char rgchFileType[MAX_PATH]; + + // Can't support compiling as different types in different configurations, but that would be insane anyway, right!? Grab the Release settings. + CSpecificConfig *pFileSpecificData = g_vecPGenerators[iGenerator]->m_Files[i]->GetOrCreateConfig( + g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[1]->GetConfigName(), + g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[1] ); + const char *pCompileAsOption = pFileSpecificData->GetOption( g_pOption_CompileAs ); + if ( pCompileAsOption && strstr( pCompileAsOption, "(/TC)" ) ) // Compile as C Code (/TC) + { + strcpy( rgchFileType, "sourcecode.c.c" ); + } + else + { + XcodeFileTypeFromFileName( pFileName, rgchFileType, sizeof( rgchFileType ) ); + } + + Write( "\n" ); + Write( "%024llX /* %s */ = {isa = PBXFileReference; fileEncoding = 4; explicitFileType = \"%s\"; name = \"%s\"; path = \"%s\"; sourceTree = \"<absolute>\"; };", + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), g_vecPGenerators[iGenerator]->m_Files[i]->m_Filename, EOIDTypeFileReference ), + pFileName, + rgchFileType, + pFileName, + rgchFilePath ); + } + KeyValues *pKV = g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[0]->m_pKV; + + // system libraries we link against + CSplitString libs( pKV->GetString( g_pOption_SystemLibraries ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < libs.Count(); i++ ) + { + Write( "\n" ); + Write( "%024llX /* lib%s.dylib */ = {isa = PBXFileReference; lastKnownFileType = \"compiled.mach-o.dylib\"; name = \"lib%s.dylib\"; path = \"usr/lib/lib%s.dylib\"; sourceTree = SDKROOT; };", + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pKV->GetString( g_pOption_SystemLibraries ), EOIDTypeFileReference, i ), libs[i], libs[i], libs[i] ); + } + + // system frameworks we link against + CSplitString sysFrameworks( pKV->GetString( g_pOption_SystemFrameworks ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < sysFrameworks.Count(); i++ ) + { + Write( "\n" ); + Write( "%024llX /* %s.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = \"%s.framework\"; path = \"System/Library/Frameworks/%s.framework\"; sourceTree = SDKROOT; };", + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pKV->GetString( g_pOption_SystemFrameworks ), EOIDTypeFileReference, i ), sysFrameworks[i], sysFrameworks[i], sysFrameworks[i] ); + } + + // local frameworks we link against + CSplitString localFrameworks( pKV->GetString( g_pOption_LocalFrameworks ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < localFrameworks.Count(); i++ ) + { + char rgchFrameworkName[MAX_PATH]; + V_StripExtension( V_UnqualifiedFileName( localFrameworks[i] ), rgchFrameworkName, sizeof( rgchFrameworkName ) ); + + char rgchFrameworkPath[MAX_PATH]; + V_snprintf( rgchFrameworkPath, sizeof( rgchFrameworkPath ), "%s/%s", rgchProjectDir, localFrameworks[i] ); + V_RemoveDotSlashes( rgchFrameworkPath ); + + Write( "\n" ); + Write( "%024llX /* %s.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = \"%s.framework\"; path = \"%s\"; sourceTree = \"<absolute>\"; };", + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pKV->GetString( g_pOption_LocalFrameworks ), EOIDTypeFileReference, i ), rgchFrameworkName, rgchFrameworkName, rgchFrameworkPath ); + } + + + // include the output files (build products) We don't support these changing between configs -- We + // check for and warn about this in EmitBuildSettings + KeyValues *pConfigKV = g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[0]->m_pKV; + const char *pszConfigName = k_rgchConfigNames[0]; + CUtlString sOutputFile = OutputFileWithDirectoryFromConfig( pConfigKV ); + if ( sOutputFile.Length() ) + { + char rgchFileType[MAX_PATH]; + XcodeFileTypeFromFileName( sOutputFile, rgchFileType, sizeof( rgchFileType ) ); + + Write( "\n" ); + Write( "%024llX /* %s */ = {isa = PBXFileReference; explicitFileType = \"%s\"; includeInIndex = 0; path = \"%s\"; sourceTree = BUILT_PRODUCTS_DIR; };", + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), sOutputFile, EOIDTypeFileReference ), sOutputFile.String(), rgchFileType, sOutputFile.String() ); + } + + // and the gameoutputfile + CUtlString sGameOutputFile = GameOutputFileFromConfig( pKV ); + if ( sGameOutputFile.Length() ) + { + char rgchFilePath[MAX_PATH]; + V_snprintf( rgchFilePath, sizeof( rgchFilePath ), "%s/%s", rgchProjectDir, sGameOutputFile.String() ); + V_RemoveDotSlashes( rgchFilePath ); + + char rgchFileType[MAX_PATH]; + XcodeFileTypeFromFileName( sGameOutputFile, rgchFileType, sizeof( rgchFileType ) ); + + Write( "\n" ); + Write( "%024llX /* %s */ = {isa = PBXFileReference; explicitFileType = \"%s\"; includeInIndex = 0; path = \"%s\"; sourceTree = \"<absolute>\"; };", + makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), sGameOutputFile, EOIDTypeFileReference ), sGameOutputFile.String(), rgchFileType, rgchFilePath ); + } + } + } + --m_nIndent; + Write( "\n/* End PBXFileReference section */\n" ); + + /** + ** + ** groups - the file hierarchy displayed in the project + ** + **/ + Write( "\n/* Begin PBXGroup section */\n" ); + ++m_nIndent; + { + FOR_EACH_VEC( g_vecPGenerators, iGenerator ) + { + CUtlVector<char*> folderNames; + V_SplitString( "Source Files;Header Files;Resources;VPC Files", ";", folderNames ); + + static const char* folderExtensions[] = + { + "*.c;*.C;*.cc;*.cpp;*.cp;*.cxx;*.c++;*.prg;*.pas;*.dpr;*.asm;*.s;*.bas;*.java;*.cs;*.sc;*.e;*.cob;*.html;*.tcl;*.py;*.pl;*.m;*.mm", + "*.h;*.H;*.hh;*.hpp;*.hxx;*.inc;*.sh;*.cpy;*.if", + "*.plist;*.strings;*.xib;*.rc;*.proto;*.nut", + "*.vpc" + }; + + FOR_EACH_VEC( folderNames, iFolder ) + { + WriteFilesFolder( makeoid( g_vecPGenerators[iGenerator]->m_ProjectName, EOIDTypeGroup, iFolder+1 ), folderNames[iFolder], folderExtensions[iFolder], g_vecPGenerators[iGenerator] ); + } + + Write( "%024llX /* %s */ = {\n", makeoid( g_vecPGenerators[iGenerator]->m_ProjectName, EOIDTypeGroup ), g_vecPGenerators[iGenerator]->GetProjectName().String() ); + ++m_nIndent; + { + Write( "isa = PBXGroup;\n" ); + Write( "children = (\n" ); + + ++m_nIndent; + { + FOR_EACH_VEC( folderNames, iFolder ) + { + Write( "%024llX /* %s */,\n", makeoid( g_vecPGenerators[iGenerator]->m_ProjectName, EOIDTypeGroup, iFolder+1 ), folderNames[iFolder] ); + } + + // XCode does not easily support having differing membership/output names per config. We'll + // only output the file names for release, then warn below that they are not shifting. + KeyValues *pKV = g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[0]->m_pKV; + + // system libraries we link against + CSplitString libs( pKV->GetString( g_pOption_SystemLibraries ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < libs.Count(); i++ ) + { + Write( "%024llX /* lib%s.dylib (system library) */,\n", makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pKV->GetString( g_pOption_SystemLibraries ), EOIDTypeFileReference, i ), libs[i] ); + } + + // system frameworks we link against + CSplitString sysFrameworks( pKV->GetString( g_pOption_SystemFrameworks ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < sysFrameworks.Count(); i++ ) + { + Write( "%024llX /* %s.framework (system framework) */,\n", makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pKV->GetString( g_pOption_SystemFrameworks ), EOIDTypeFileReference, i ), sysFrameworks[i] ); + } + + // local frameworks we link against + CSplitString localFrameworks( pKV->GetString( g_pOption_LocalFrameworks ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < localFrameworks.Count(); i++ ) + { + char rgchFrameworkName[MAX_PATH]; + V_StripExtension( V_UnqualifiedFileName( localFrameworks[i] ), rgchFrameworkName, sizeof( rgchFrameworkName ) ); + + Write( "%024llX /* %s.framework (local framework) */,\n", makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), pKV->GetString( g_pOption_LocalFrameworks ), EOIDTypeFileReference, i ), rgchFrameworkName ); + } + + // libraries we consume (specified in our files list) + for ( int i=g_vecPGenerators[iGenerator]->m_Files.First(); i != g_vecPGenerators[iGenerator]->m_Files.InvalidIndex(); i=g_vecPGenerators[iGenerator]->m_Files.Next(i) ) + { + CUtlString sFileName = UsePOSIXSlashes( g_vecPGenerators[iGenerator]->m_Files[i]->m_Filename.String() ); + bool bInclude = IsDynamicLibrary( sFileName ); + if ( IsStaticLibrary( sFileName ) ) + { + char szAbsoluteFileName[MAX_PATH] = { 0 }; + V_MakeAbsolutePath( szAbsoluteFileName, sizeof( szAbsoluteFileName ), + UsePOSIXSlashes( g_vecPGenerators[iGenerator]->m_Files[i]->m_Filename.String() ), + projects[iGenerator]->m_szStoredCurrentDirectory ); + + bInclude = true; + FOR_EACH_VEC( g_vecPGenerators, iGenerator2 ) + { + // don't include static libs generated by other projects - we'll pull them out of the built products tree + KeyValues *pKV = g_vecPGenerators[iGenerator2]->m_BaseConfigData.m_Configurations[0]->m_pKV; + char szAbsoluteGameOutputFile[MAX_PATH] = { 0 }; + V_MakeAbsolutePath( szAbsoluteGameOutputFile, sizeof( szAbsoluteGameOutputFile ), + GameOutputFileFromConfig( pKV ).String(), + projects[iGenerator2]->m_szStoredCurrentDirectory ); + if ( !V_stricmp( szAbsoluteFileName, szAbsoluteGameOutputFile ) ) + { + bInclude = false; + break; + } + } + } + + if ( bInclude ) + { + Write( "%024llX /* %s in Frameworks (explicit) */,\n", makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), g_vecPGenerators[iGenerator]->m_Files[i]->m_Filename, EOIDTypeFileReference ), sFileName.String() ); + } + } + + CUtlString sOutputFile = OutputFileWithDirectoryFromConfig( pKV ); + if ( sOutputFile.Length() ) + Write( "%024llX /* %s */,\n", makeoid2( g_vecPGenerators[iGenerator]->GetProjectName(), sOutputFile.String(), EOIDTypeFileReference ), sOutputFile.String() ); + } + + --m_nIndent; + + Write( ");\n" ); + Write( "name = \"%s\";\n", g_vecPGenerators[iGenerator]->GetProjectName().String() ); + Write( "sourceTree = \"<group>\";\n" ); + } + --m_nIndent; + Write( "};\n" ); + + } + + // root group - the top of the displayed hierarchy + Write( "%024llX = {\n", makeoid( oidStrProjectsRoot, EOIDTypeGroup ) ); + ++m_nIndent; + { + Write( "isa = PBXGroup;\n" ); + Write( "children = (\n" ); + + // sort the projects by name before we emit the list + CUtlSortVector< CUtlString, CStringLess > vecSortedProjectNames; + FOR_EACH_VEC( g_vecPGenerators, iGen ) + { + // fprintf( stderr, "inserting %s (%p)\n", g_vecPGenerators[iGen]->GetProjectName().String(), &g_vecPGenerators[iGen]->GetProjectName() ); + vecSortedProjectNames.Insert( g_vecPGenerators[iGen]->GetProjectName() ); + } + + ++m_nIndent; + { + FOR_EACH_VEC( vecSortedProjectNames, iProjectName ) + { + // fprintf( stderr, "looking for %s\n", vecSortedProjectNames[iProjectName].String() ); + // and each project's group (of groups) + FOR_EACH_VEC( g_vecPGenerators, iGenerator ) + { + if ( strcmp( g_vecPGenerators[iGenerator]->m_ProjectName.String(), vecSortedProjectNames[iProjectName] ) ) + { + // 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 ); + continue; + } + // fprintf( stderr, "emitting %s (%d, %d)\n", g_vecPGenerators[iGenerator]->GetProjectName().String(), iGenerator, iProjectName ); + + Write( "%024llX /* %s */,\n", makeoid( g_vecPGenerators[iGenerator]->m_ProjectName, EOIDTypeGroup ), g_vecPGenerators[iGenerator]->GetProjectName().String() ); + break; + } + } + + // add the build config (.xcconfig) files + for ( int iConfig = 0; iConfig < V_ARRAYSIZE(k_rgchXCConfigFiles); iConfig++ ) + { + Write( "%024llX /* %s */, \n", makeoid2( oidStrSolutionRoot, k_rgchXCConfigFiles[iConfig], EOIDTypeFileReference ), k_rgchXCConfigFiles[iConfig] ); + } + } + --m_nIndent; + Write( ");\n" ); + Write( "sourceTree = \"<group>\";\n" ); + // make the project follow our coding standards, and use tabs. + Write( "usesTabs = 1;\n" ); + } + --m_nIndent; + Write( "};" ); + } + m_nIndent--; + Write( "\n/* End PBXGroup section */\n" ); + + + /** + ** + ** the sources build phases - each target that compiles source references on of these, it in turn references the source files to be compiled + ** + **/ + Write( "\n/* Begin PBXSourcesBuildPhase section */" ); + ++m_nIndent; + FOR_EACH_VEC( projects, iProject ) + { + Write( "\n" ); + Write( "%024llX /* Sources */ = {\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeSourcesBuildPhase ) ); + ++m_nIndent; + { + Write( "isa = PBXSourcesBuildPhase;\n" ); + Write( "buildActionMask = 2147483647;\n" ); + Write( "files = (\n" ); + ++m_nIndent; + { + for ( int i=g_vecPGenerators[iProject]->m_Files.First(); i != g_vecPGenerators[iProject]->m_Files.InvalidIndex(); i=g_vecPGenerators[iProject]->m_Files.Next(i) ) + { + const char *pFileName = g_vecPGenerators[iProject]->m_Files[i]->m_Filename.String(); + CFileConfig *pFileConfig = g_vecPGenerators[iProject]->m_Files[i]; + + if ( AppearsInSourcesBuildPhase( g_vecPGenerators[iProject], pFileConfig ) ) + { + Write( "%024llX /* %s in Sources */,\n", makeoid2( g_vecPGenerators[iProject]->GetProjectName(), pFileName, EOIDTypeBuildFile ), V_UnqualifiedFileName( UsePOSIXSlashes( pFileName ) ) ); + } + } + } + --m_nIndent; + Write( ");\n"); + Write( "runOnlyForDeploymentPostprocessing = 0;\n" ); + } + --m_nIndent; + Write( "};" ); + } + --m_nIndent; + Write( "\n/* End PBXSourcesBuildPhase section */\n" ); + + + /** + ** + ** the frameworks build phases - each target that links libraries (static, dyamic, framework) has one of these, it references the linked thing + ** + **/ + Write( "\n/* Begin PBXFrameworksBuildPhase section */" ); + ++m_nIndent; + FOR_EACH_VEC( projects, iProject ) + { + Write( "\n" ); + Write( "%024llX /* Frameworks */ = {\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeFrameworksBuildPhase ) ); + ++m_nIndent; + { + Write( "isa = PBXFrameworksBuildPhase;\n" ); + Write( "buildActionMask = 2147483647;\n" ); + Write( "files = (\n" ); + ++m_nIndent; + { + // libraries we consume (specified in our files list) + for ( int i=g_vecPGenerators[iProject]->m_Files.First(); i != g_vecPGenerators[iProject]->m_Files.InvalidIndex(); i=g_vecPGenerators[iProject]->m_Files.Next(i) ) + { + const char *pFileName = g_vecPGenerators[iProject]->m_Files[i]->m_Filename.String(); + if ( IsStaticLibrary( UsePOSIXSlashes( pFileName ) ) || IsDynamicLibrary( UsePOSIXSlashes( pFileName ) ) ) + { + char szAbsoluteFileName[MAX_PATH] = { 0 }; + V_MakeAbsolutePath( szAbsoluteFileName, sizeof( szAbsoluteFileName ), + UsePOSIXSlashes( g_vecPGenerators[iProject]->m_Files[i]->m_Filename.String() ), + projects[iProject]->m_szStoredCurrentDirectory ); + bool bInclude = true; + FOR_EACH_VEC( g_vecPGenerators, iGenerator ) + { + // Don't include libs generated by other projects - we'll pull them out of the built + // products tree. Resolve the absolute path of both, since they are relative to + // different projects. + KeyValues *pKV = g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[0]->m_pKV; + char szAbsoluteGameOutputFile[MAX_PATH] = { 0 }; + V_MakeAbsolutePath( szAbsoluteGameOutputFile, sizeof( szAbsoluteGameOutputFile ), + GameOutputFileFromConfig( pKV ).String(), + projects[iGenerator]->m_szStoredCurrentDirectory ); + + if ( !V_stricmp( szAbsoluteFileName, szAbsoluteGameOutputFile ) ) + { + bInclude = false; + break; + } + } + + if ( bInclude ) + { + Write( "%024llX /* %s in Frameworks (explicit) */,\n", makeoid2( g_vecPGenerators[iProject]->GetProjectName(), pFileName, EOIDTypeBuildFile ), pFileName ); + } + + } + } + + // libraries from projects we depend on + CDependency_Project *pCurProject = projects[iProject]; + + CUtlVector<CDependency_Project*> additionalProjectDependencies; + ResolveAdditionalProjectDependencies( pCurProject, projects, additionalProjectDependencies ); + + for ( int iTestProject=projects.Count()-1; iTestProject >= 0; --iTestProject ) + { + if ( iProject == iTestProject ) + continue; + + CDependency_Project *pTestProject = projects[iTestProject]; + int dependsOnFlags = k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse; + if ( pCurProject->DependsOn( pTestProject, dependsOnFlags ) || additionalProjectDependencies.Find( pTestProject ) != additionalProjectDependencies.InvalidIndex() ) + { + // In the PBXBuildFile section each of our dependencies generated an OID pointing to + // their output file with our project index as the ordinal. We use the PRODUCTS + // directory build file as depending on the final GameOutputFile confuses XCode's linker + // logic, and it should not matter (since GameOutputFile is just copying it to a final + // destination, so we can depend/link on the products directory intermediate) + KeyValues *pKV = g_vecPGenerators[iTestProject]->m_BaseConfigData.m_Configurations[0]->m_pKV; + CUtlString sOutputFile = OutputFileWithDirectoryFromConfig( pKV ); + if ( sOutputFile.Length() && ( IsStaticLibrary( sOutputFile ) || IsDynamicLibrary( sOutputFile ) ) ) + { + // The project in question will have generated a BuildFile dependency for us under its name with ordinal set to our index + Write( "%024llX /* (lib)%s (dependency) */,\n", + makeoid2( g_vecPGenerators[iTestProject]->GetProjectName(), sOutputFile, EOIDTypeBuildFile, iProject ), sOutputFile.String() ); + } + } + } + + KeyValues *pKV = g_vecPGenerators[iProject]->m_BaseConfigData.m_Configurations[0]->m_pKV; + + // local frameworks we link against + CSplitString localFrameworks( pKV->GetString( g_pOption_LocalFrameworks ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < localFrameworks.Count(); i++ ) + { + char rgchFrameworkName[MAX_PATH]; + V_StripExtension( V_UnqualifiedFileName( localFrameworks[i] ), rgchFrameworkName, sizeof( rgchFrameworkName ) ); + + Write( "%024llX /* %s in Frameworks (local framework) */,\n", makeoid2( g_vecPGenerators[iProject]->GetProjectName(), pKV->GetString( g_pOption_LocalFrameworks ), EOIDTypeBuildFile, i ), rgchFrameworkName ); + } + + // system frameworks we link against + CSplitString sysFrameworks( pKV->GetString( g_pOption_SystemFrameworks ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < sysFrameworks.Count(); i++ ) + { + Write( "%024llX /* %s in Frameworks (system framework) */,\n", makeoid2( g_vecPGenerators[iProject]->GetProjectName(), pKV->GetString( g_pOption_SystemFrameworks ), EOIDTypeBuildFile, i ), sysFrameworks[i] ); + } + + // system libraries we link against + CSplitString libs( pKV->GetString( g_pOption_SystemLibraries ), (const char**)g_IncludeSeparators, V_ARRAYSIZE(g_IncludeSeparators) ); + for ( int i=0; i < libs.Count(); i++ ) + { + Write( "%024llX /* %s in Frameworks (system library) */,\n", makeoid2( g_vecPGenerators[iProject]->GetProjectName(), pKV->GetString( g_pOption_SystemLibraries ), EOIDTypeBuildFile, i ), libs[i] ); + } + + } + --m_nIndent; + Write( ");\n"); + Write( "runOnlyForDeploymentPostprocessing = 0;\n" ); + } + --m_nIndent; + Write( "};" ); + } + --m_nIndent; + Write( "\n/* End PBXFrameworksBuildPhase section */\n" ); + + + /** + ** + ** the shell script (pre/post build step) build phases - each target that generates a "gameoutputfile" has one of these, + ** to p4 edit the target and copy the build result there. + ** + **/ + Write( "\n/* Begin PBXShellScriptBuildPhase section */" ); + ++m_nIndent; + { + FOR_EACH_VEC( g_vecPGenerators, iGenerator ) + { + CProjectGenerator_Xcode *pGenerator = (CProjectGenerator_Xcode*)g_vecPGenerators[iGenerator]; + char rgchProjectDir[MAX_PATH]; rgchProjectDir[0] = '\0'; + V_strncpy( rgchProjectDir, projects[iGenerator]->m_ProjectFilename.String(), sizeof( rgchProjectDir ) ); + V_StripFilename( rgchProjectDir ); + + CUtlString sPreBuildCommandLine = g_vecPGenerators[iGenerator]->m_Files[0]->GetOrCreateConfig( g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[1]->GetConfigName(), + g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[1] )->GetOption( g_pOption_PreBuildEventCommandLine ); + if ( sPreBuildCommandLine.Length() ) + { + CUtlString sCommand; + int cCommand = MAX( sPreBuildCommandLine.Length() * 2, 8 * 1024 ); + sCommand.SetLength( cCommand ); + + Write( "\n" ); + Write( "%024llX /* ShellScript */ = {\n", makeoid( projects[iGenerator]->m_ProjectName, EOIDTypePreBuildPhase, pGenerator->m_nPreBuildEvents++ ) ); + ++m_nIndent; + { + Write( "isa = PBXShellScriptBuildPhase;\n" ); + Write( "buildActionMask = 2147483647;\n" ); + Write( "files = (\n" ); + Write( ");\n" ); + Write( "inputPaths = (\n);\n" ); + Write( "name = \"%s\";\n", CFmtStr( "PreBuild Event for %s", projects[iGenerator]->m_ProjectName.String() ).Access() ); + Write( "outputPaths = (\n);\n" ); + Write( "runOnlyForDeploymentPostprocessing = 0;\n" ); + Write( "shellPath = /bin/bash;\n" ); + + CBaseProjectDataCollector::DoStandardVisualStudioReplacements( sPreBuildCommandLine, CFmtStr( "%s/dummy.txt", rgchProjectDir ).Access(), sCommand.Get(), cCommand ); + V_StrSubstInPlace( sCommand.Get(), cCommand, "$(OBJ_DIR)", "\"${OBJECT_FILE_DIR_normal}\"", false ); + V_StrSubstInPlace( sCommand.Get(), cCommand, ";", ";\\n", false ); + V_StrSubstInPlace( sCommand.Get(), cCommand, "\"", "\\\"", false ); + + // xcode wants to run your custom shell scripts anytime the pbxproj has changed (which makes some sense - the script might + // be different) - we can't and don't want to early out in this case. + Write( "shellScript = \"cd %s\\n" + "%s\";\n", rgchProjectDir, sCommand.String() ); + } + --m_nIndent; + Write( "};" ); + } + // we don't have an output file - wander the list of files, looking for custom build steps + // if we find any, magic up shell scripts to run them + for ( int i=g_vecPGenerators[iGenerator]->m_Files.First(); i != g_vecPGenerators[iGenerator]->m_Files.InvalidIndex(); i=g_vecPGenerators[iGenerator]->m_Files.Next(i) ) + { + + CFileConfig *pFileConfig = g_vecPGenerators[iGenerator]->m_Files[i]; + CSpecificConfig *pFileSpecificData = pFileConfig->GetOrCreateConfig( g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[1]->GetConfigName(), + g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[1] ); + + CUtlString sCustomBuildCommandLine = pFileSpecificData->GetOption( g_pOption_CustomBuildStepCommandLine ); + CUtlString sOutputFiles = pFileSpecificData->GetOption( g_pOption_Outputs ); + CUtlString sAdditionalDeps = pFileSpecificData->GetOption( g_pOption_AdditionalDependencies ); + CUtlString sCommand; + + // if the project produces a binary, it's a native target and we'll handle this custom build step + // as a build rule unless the custom build has additional dependencies + if ( ProjectProducesBinary( pGenerator ) && !sAdditionalDeps.Length() ) + continue; + + if ( sOutputFiles.Length() && !sCustomBuildCommandLine.IsEmpty() ) + { + CUtlString sInputFile; + sInputFile.SetLength( MAX_PATH ); + + int cCommand = MAX( sCustomBuildCommandLine.Length() * 2, 8 * 1024 ); + sCommand.SetLength( cCommand ); + + Write( "\n" ); + Write( "%024llX /* ShellScript */ = {\n", makeoid( projects[iGenerator]->m_ProjectName, EOIDTypeShellScriptBuildPhase, pGenerator->m_nShellScriptPhases++ ) ); + ++m_nIndent; + { + Write( "isa = PBXShellScriptBuildPhase;\n" ); + Write( "buildActionMask = 2147483647;\n" ); + Write( "files = (\n" ); + Write( ");\n" ); + Write( "inputPaths = (\n" ); + ++m_nIndent; + { + // DoStandardVisualStudioReplacements needs to know where the file is, so make sure it's got a path on it + if ( V_IsAbsolutePath( UsePOSIXSlashes( pFileConfig->m_Filename.String() ) ) ) + V_snprintf( sInputFile.Get(), MAX_PATH, "%s", UsePOSIXSlashes( pFileConfig->m_Filename.String() ) ); + else + { + V_snprintf( sInputFile.Get(), MAX_PATH, "%s/%s", rgchProjectDir, UsePOSIXSlashes( pFileConfig->m_Filename.String() ) ); + V_RemoveDotSlashes( sInputFile.Get() ); + } + Write( "\"%s\",\n", sInputFile.String() ); + + CSplitString additionalDeps( sAdditionalDeps, ";" ); + FOR_EACH_VEC( additionalDeps, i ) + { + const char *pchOneFile = additionalDeps[i]; + if ( *pchOneFile != '\0' ) + { + char szDependency[MAX_PATH]; + // DoStandardVisualStudioReplacements needs to know where the file is, so make sure it's got a path on it + if ( V_IsAbsolutePath( UsePOSIXSlashes( pchOneFile ) ) ) + V_snprintf( szDependency, MAX_PATH, "%s", UsePOSIXSlashes( pchOneFile ) ); + else + { + V_snprintf( szDependency, MAX_PATH, "%s/%s", rgchProjectDir, UsePOSIXSlashes( pchOneFile ) ); + V_RemoveDotSlashes( szDependency ); + } + Write( "\"%s\",\n", szDependency ); + } + } + + } + --m_nIndent; + Write( ");\n" ); + + CUtlString sDescription; + if ( pFileSpecificData->GetOption( g_pOption_Description ) ) + { + int cDescription = V_strlen( pFileSpecificData->GetOption( g_pOption_Description ) ) * 2; + sDescription.SetLength( cDescription ); + CBaseProjectDataCollector::DoStandardVisualStudioReplacements( pFileSpecificData->GetOption( g_pOption_Description ), sInputFile, sDescription.Get(), cDescription ); + } + else + sDescription = CFmtStr( "Custom Build Step for %s", pFileConfig->m_Filename.String() ).Access(); + + Write( "name = \"%s\";\n", sDescription.String() ); + + Write( "outputPaths = (\n" ); +#define TELL_XCODE_ABOUT_OUTPUT_FILES 1 +#ifdef TELL_XCODE_ABOUT_OUTPUT_FILES + // telling xcode about the output files used to cause it's dependency evaluation to + // assume that those files had changed anytime the script had run, even if the script + // doesn't change them, which caused us to rebuild a bunch of stuff we didn't need to rebuild + // but testing with Xcode 6 suggests they fixed that bug, and lying less to the build system is + // generally good. + ++m_nIndent; + { + CSplitString outFiles( sOutputFiles, ";" ); + for ( int i = 0; i < outFiles.Count(); i ++ ) + { + CUtlString sOutputFile; + sOutputFile.SetLength( MAX_PATH ); + CBaseProjectDataCollector::DoStandardVisualStudioReplacements( outFiles[i], sInputFile, sOutputFile.Get(), MAX_PATH ); + V_StrSubstInPlace( sOutputFile.Get(), MAX_PATH, "$(OBJ_DIR)", "${OBJECT_FILE_DIR_normal}", false ); + + CUtlString sOutputPath; + sOutputPath.SetLength( MAX_PATH ); + + if ( V_IsAbsolutePath( sOutputFile ) || V_strncmp( outFiles[i], "$", 1 ) == 0 ) + V_snprintf( sOutputPath.Get(), MAX_PATH, "%s", sOutputFile.String() ); + else + { + V_snprintf( sOutputPath.Get(), MAX_PATH, "%s/%s", rgchProjectDir, sOutputFile.String() ); + V_RemoveDotSlashes( sOutputPath.Get() ); + } + Write( "\"%s\",\n", sOutputPath.String() ); + } + } + --m_nIndent; +#endif + Write( ");\n"); + Write( "runOnlyForDeploymentPostprocessing = 0;\n" ); + Write( "shellPath = /bin/bash;\n" ); + + CBaseProjectDataCollector::DoStandardVisualStudioReplacements( sCustomBuildCommandLine, sInputFile, sCommand.Get(), cCommand ); + V_StrSubstInPlace( sCommand.Get(), cCommand, "$(OBJ_DIR)", "\"${OBJECT_FILE_DIR_normal}\"", false ); + V_StrSubstInPlace( sCommand.Get(), cCommand, ";", ";\\n", false ); + V_StrSubstInPlace( sCommand.Get(), cCommand, "\"", "\\\"", false ); + + // this is something of a dirty ugly hack. it seems that xcode wants to run your custom shell + // scripts anytime the pbxproj has changed (which makes some sense - the script might be different) + // since we generate one big project, any vpc change means we'll run all the custom + // build steps again, which will generate code, and link code, and generally take time + // so if this project was up-to-date (i.e. no vpc changes), add an early out that checks if + // all the output files are newer than the input files and early out if that's the case + CUtlString sConditionalBlock = CFmtStr( "export CANARY_FILE=\\\"%s\\\";\\n", pGenerator->m_OutputFilename.String() ).Access(); + // uncomment this line to debug the embedded shell script + // sConditionalBlock += "set -x\\n"; + sConditionalBlock += "EARLY_OUT=1\\n" + "let LI=$SCRIPT_INPUT_FILE_COUNT-1\\n" + "let LO=$SCRIPT_OUTPUT_FILE_COUNT-1\\n" + "for j in $(seq 0 $LO); do\\n" + " OUTPUT=SCRIPT_OUTPUT_FILE_$j\\n" + " if [ \\\"${CANARY_FILE}\\\" -nt \\\"${!OUTPUT}\\\" ]; then\\n" + " EARLY_OUT=0\\n" + " break\\n" + " fi\\n" + " for i in $(seq 0 $LI); do\\n" + " INPUT=SCRIPT_INPUT_FILE_$i\\n" + " if [ \\\"${!INPUT}\\\" -nt \\\"${!OUTPUT}\\\" ]; then\\n" + " EARLY_OUT=0\\n" + " break 2\\n" + " fi\\n" + " done\\n" + "done\\n"; + + sConditionalBlock += "if [ $EARLY_OUT -eq 1 ]; then\\n" + " echo \\\"outputs are newer than input, skipping execution...\\\"\\n" + " exit 0\\n" + "fi\\n"; + Write( "shellScript = \"cd %s\\n" + "%s" + "%s\";\n", rgchProjectDir, sConditionalBlock.String(), sCommand.String() ); + } + --m_nIndent; + Write( "};" ); + + } + } + + KeyValues *pDebugKV = g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[0]->m_pKV; + CUtlString sDebugGameOutputFile = GameOutputFileFromConfig( pDebugKV ); + + KeyValues *pReleaseKV = g_vecPGenerators[iGenerator]->m_BaseConfigData.m_Configurations[1]->m_pKV; + CUtlString sReleaseGameOutputFile = GameOutputFileFromConfig( pReleaseKV ); + + if ( sDebugGameOutputFile.Length() || sReleaseGameOutputFile.Length() ) + { + char rgchDebugFilePath[MAX_PATH]; + V_snprintf( rgchDebugFilePath, sizeof( rgchDebugFilePath ), "%s/%s", rgchProjectDir, sDebugGameOutputFile.String() ); + V_RemoveDotSlashes( rgchDebugFilePath ); + + char rgchReleaseFilePath[MAX_PATH]; + V_snprintf( rgchReleaseFilePath, sizeof( rgchReleaseFilePath ), "%s/%s", rgchProjectDir, sReleaseGameOutputFile.String() ); + V_RemoveDotSlashes( rgchReleaseFilePath ); + + Write( "\n" ); + Write( "%024llX /* ShellScript */ = {\n", makeoid( projects[iGenerator]->m_ProjectName, EOIDTypePostBuildPhase, 0 ) ); + ++m_nIndent; + { + Write( "isa = PBXShellScriptBuildPhase;\n" ); + Write( "buildActionMask = 2147483647;\n" ); + Write( "files = (\n" ); + Write( ");\n" ); + Write( "inputPaths = (\n" ); + ++m_nIndent; + { + Write( "\"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}\",\n" ); + } + --m_nIndent; + Write( ");\n" ); + Write( "name = \"Post-Build Step\";\n" ); + Write( "outputPaths = (\n" ); + ++m_nIndent; + { + V_StrSubstInPlace( rgchDebugFilePath, sizeof( rgchDebugFilePath ), "/lib/osx32/debug/", "/lib/osx32/${CONFIGURATION}/", false ); + CBaseProjectDataCollector::DoStandardVisualStudioReplacements( rgchDebugFilePath, rgchDebugFilePath, rgchDebugFilePath, sizeof( rgchDebugFilePath ) ); + V_StrSubstInPlace( rgchReleaseFilePath, sizeof( rgchReleaseFilePath ), "/lib/osx32/release/", "/lib/osx32/${CONFIGURATION}/", false ); + CBaseProjectDataCollector::DoStandardVisualStudioReplacements( rgchReleaseFilePath, rgchReleaseFilePath, rgchReleaseFilePath, sizeof( rgchReleaseFilePath ) ); + + Write( "\"%s\",\n", rgchDebugFilePath ); + if ( V_strcmp( rgchDebugFilePath, rgchReleaseFilePath ) ) + Write( "\"%s\",\n", rgchReleaseFilePath ); + } + --m_nIndent; + Write( ");\n"); + Write( "runOnlyForDeploymentPostprocessing = 0;\n" ); + Write( "shellPath = /bin/bash;\n" ); + + CUtlString strScript( CFmtStr( "shellScript = \"cd %s;\\n", rgchProjectDir ) ); + + CUtlString strScriptExtra; + bool bHasReleasePostBuildCmd = V_strlen( SkipLeadingWhitespace( pReleaseKV->GetString( g_pOption_PostBuildEventCommandLine, "" ) ) ) > 0; + bool bHasDebugPostBuildCmd = V_strlen( SkipLeadingWhitespace( pDebugKV->GetString( g_pOption_PostBuildEventCommandLine, "" ) ) ) > 0; + strScriptExtra.Format( + "if [ -z \\\"$CONFIGURATION\\\" -a -n \\\"$BUILD_STYLE\\\" ]; then\\n" + " CONFIGURATION=${BUILD_STYLE}\\n" + "fi\\n" + "if [ -z \\\"$CONFIGURATION\\\" ]; then\\n" + " echo \\\"Could not determine build configuration.\\\";\\n" + " exit 1; \\n" + "fi\\n" + "CONFIGURATION=$(echo $CONFIGURATION | tr [A-Z] [a-z])\\n" + "OUTPUTFILE=\\\"%s\\\"\\n" + "if [ -z \\\"$VALVE_NO_AUTO_P4\\\" ]; then\\n" + " P4_EDIT_CHANGELIST_CMD=\\\"p4 changes -c $(p4 client -o | grep ^Client | cut -f 2) -s pending | fgrep 'POSIX Auto Checkout' | cut -d' ' -f 2 | tail -n 1\\\"\\n" + " P4_EDIT_CHANGELIST=$(eval \\\"$P4_EDIT_CHANGELIST_CMD\\\")\\n" + " if [ -z \\\"$P4_EDIT_CHANGELIST\\\" ]; then\\n" + " P4_EDIT_CHANGELIST=$(echo -e \\\"Change: new\\\\nDescription: POSIX Auto Checkout\\\" | p4 change -i | cut -f 2 -d ' ')\\n" + " fi\\n" + "fi\\n" + "if [ -f \\\"$OUTPUTFILE\\\" -o -d \\\"$OUTPUTFILE.dSYM\\\" ]; then\\n" + " if [ -z \\\"$VALVE_NO_AUTO_P4\\\" ]; then\\n" + " p4 edit -c $P4_EDIT_CHANGELIST \\\"$OUTPUTFILE...\\\" | grep -v \\\"also opened\\\"\\n" + " else\\n" + " if [ -f \\\"$OUTPUTFILE\\\" ]; then\\n" + " chmod -f +w \\\"$OUTPUTFILE\\\"\\n" + " fi\\n" + " if [ -d \\\"$OUTPUTFILE.dSYM\\\" ]; then\\n" + " chmod -R -f +w \\\"$OUTPUTFILE.dSYM\\\"\\n" + " fi\\n" + " fi\\n" + "fi\\n" + "set -eu\\n" + "if [ -d \\\"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}.dSYM\\\" ]; then\\n" + " echo \\\"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}.dSYM -> ${OUTPUTFILE}.dSYM\\\"\\n" + " rm -rf \\\"${OUTPUTFILE}.dSYM\\\"\\n" + " cp -pR \\\"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}.dSYM\\\" \\\"${OUTPUTFILE}.dSYM\\\"\\n" + "fi\\n" + "cp -pv \\\"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}\\\" \\\"$OUTPUTFILE\\\"\\n" + "# POST-BUILD:\\n" + "set -e\\n" + "if [ ${CONFIGURATION} == \\\"release\\\" ]; then\\n" + " %s\\n" + "elif [ ${CONFIGURATION} == \\\"debug\\\" ]; then\\n" + " %s\\n" + "fi\\n" + "\";\n", + rgchReleaseFilePath, + bHasReleasePostBuildCmd ? UsePOSIXSlashes( pReleaseKV->GetString( g_pOption_PostBuildEventCommandLine, "true" ) ) : "true", + bHasDebugPostBuildCmd ? UsePOSIXSlashes( pDebugKV->GetString( g_pOption_PostBuildEventCommandLine, "true" ) ) : "true" ); + + strScript += strScriptExtra; + Write( strScript.Get() ); + } + --m_nIndent; + Write( "};" ); + } + } + } + --m_nIndent; + Write( "\n/* End PBXShellScriptBuildPhase section */\n" ); + + /** + ** + ** nativetargets section - build targets, which ultimately reference build phases + ** + **/ + Write( "\n/* Begin PBXNativeTarget section */" ); + ++m_nIndent; + FOR_EACH_VEC( projects, iProject ) + { + CProjectGenerator_Xcode *pGenerator = (CProjectGenerator_Xcode*)g_vecPGenerators[iProject]; + + KeyValues *pKV = g_vecPGenerators[iProject]->m_BaseConfigData.m_Configurations[0]->m_pKV; + CUtlString sGameOutputFile = GameOutputFileFromConfig( pKV ); + if ( !sGameOutputFile.Length() ) + continue; + + Write( "\n" ); + Write( "%024llX /* %s */ = {\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeNativeTarget ), projects[iProject]->m_ProjectName.String() ); + ++m_nIndent; + { + Write( "isa = PBXNativeTarget;\n" ); + + Write( "buildConfigurationList = %024llX /* Build configuration list for PBXNativeTarget \"%s\" */;\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeConfigurationList ), projects[iProject]->m_ProjectName.String() ); + Write( "buildPhases = (\n" ); + ++m_nIndent; + { + for ( int i = 0; i < pGenerator->m_nPreBuildEvents; i++ ) + Write( "%024llX /* PreBuildEvent */,\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypePreBuildPhase, i ) ); + for ( int i = 0; i < pGenerator->m_nShellScriptPhases; i++ ) + Write( "%024llX /* ShellScript */,\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeShellScriptBuildPhase, i ) ); + Write( "%024llX /* Sources */,\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeSourcesBuildPhase ) ); + Write( "%024llX /* Frameworks */,\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeFrameworksBuildPhase ) ); + Write( "%024llX /* PostBuildPhase */,\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypePostBuildPhase, 0 ) ); + } + --m_nIndent; + Write( ");\n" ); + Write( "buildRules = (\n" ); + ++m_nIndent; + { + for ( int i = 0; i < pGenerator->m_nCustomBuildRules; i++ ) + Write( "%024llX /* PBXBuildRule */,\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeCustomBuildRule, i ) ); + } + --m_nIndent; + Write( ");\n" ); + Write( "dependencies = (\n" ); + ++m_nIndent; + { + // these dependencies point to the dependency objects, which reference other projects through the container item proxy objects + CDependency_Project *pCurProject = projects[iProject]; + + CUtlVector<CDependency_Project*> additionalProjectDependencies; + ResolveAdditionalProjectDependencies( pCurProject, projects, additionalProjectDependencies ); + + for ( int iTestProject=0; iTestProject < projects.Count(); iTestProject++ ) + { + if ( iProject == iTestProject ) + continue; + + CDependency_Project *pTestProject = projects[iTestProject]; + int dependsOnFlags = k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse; + if ( pCurProject->DependsOn( pTestProject, dependsOnFlags ) || additionalProjectDependencies.Find( pTestProject ) != additionalProjectDependencies.InvalidIndex() ) + { + Write( "%024llX /* %s */,\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeTargetDependency, (uint16_t)iTestProject ), pTestProject->GetName() ); + } + } + } + --m_nIndent; + Write( ");\n" ); + Write( "productName = \"%s\";\n", projects[iProject]->m_ProjectName.String() ); + Write( "name = \"%s\";\n", projects[iProject]->m_ProjectName.String() ); + + if ( sGameOutputFile.Length() ) + { + Write( "productReference = %024llX /* %s */;\n", makeoid2( projects[iProject]->m_ProjectName, sGameOutputFile, EOIDTypeFileReference ), sGameOutputFile.String() ); + } + + char rgchProductType[MAX_PATH]; + XcodeProductTypeFromFileName( V_UnqualifiedFileName( sGameOutputFile ), rgchProductType, sizeof( rgchProductType ) ); + Write( "productType = \"%s\";\n", rgchProductType ); + } + --m_nIndent; + Write( "};" ); + } + --m_nIndent; + Write( "\n/* End PBXNativeTarget section */\n" ); + + /** + ** + ** aggregate targets - for targets that have no output files (i.e. are scripts) + ** and the "all" target + ** + **/ + Write( "\n/* Begin PBXAggregateTarget section */\n" ); + ++m_nIndent; + { + Write( "%024llX /* All */ = {\n", makeoid( oidStrSolutionRoot, EOIDTypeAggregateTarget ) ); + ++m_nIndent; + { + Write( "isa = PBXAggregateTarget;\n" ); + Write( "buildConfigurationList = %024llX /* Build configuration list for PBXAggregateTarget \"All\" */;\n", makeoid( oidStrSolutionRoot, EOIDTypeConfigurationList, 1 ) ); + Write( "buildPhases = (\n" ); + Write( ");\n" ); + Write( "dependencies = (\n" ); + ++m_nIndent; + { + FOR_EACH_VEC( projects, iProject ) + { + // 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. + Write( "%024llX /* PBXProjectDependency */,\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeTargetDependency, -1 ) ); + } + } + --m_nIndent; + Write( ");\n" ); + Write( "name = All;\n" ); + Write( "productName = All;\n" ); + } + --m_nIndent; + Write( "};\n" ); + + FOR_EACH_VEC( projects, iProject ) + { + CProjectGenerator_Xcode *pGenerator = (CProjectGenerator_Xcode*)g_vecPGenerators[iProject]; + KeyValues *pKV = g_vecPGenerators[iProject]->m_BaseConfigData.m_Configurations[0]->m_pKV; + CUtlString sOutputFile = OutputFileWithDirectoryFromConfig( pKV ); + if ( sOutputFile.Length() ) + continue; + + // NOTE: the use of EOIDTypeNativeTarget here is intentional - a project will never appear as both, and this makes things link up without + // having to special case in dependencies and aggregate targets + // NOTE: the driving loop is the number of shell script phases we have - aggregate targets with > 1 shell script phase + // get broken into N aggregate targets, each with 1 shell script phase so xcode can execute them in parallel + int cSubAggregateTargets = ( pGenerator->m_nShellScriptPhases / k_nShellScriptPhasesPerAggregateTarget ) + ( pGenerator->m_nShellScriptPhases % k_nShellScriptPhasesPerAggregateTarget ? 1 : 0); + for ( int i = 0; i < cSubAggregateTargets; i++ ) + { + Write( "%024llX /* %s_%d */ = {\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeNativeTarget, i ), projects[iProject]->m_ProjectName.String(), i ); + ++m_nIndent; + { + Write( "isa = PBXAggregateTarget;\n" ); + + Write( "buildConfigurationList = %024llX /* Build configuration list for PBXAggregateTarget \"%s\" */;\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeConfigurationList ), projects[iProject]->m_ProjectName.String() ); + Write( "buildPhases = (\n" ); + ++m_nIndent; + { + for (int j = 0; j < k_nShellScriptPhasesPerAggregateTarget; j++) + Write( "%024llX /* ShellScript %d/%d*/,\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeShellScriptBuildPhase, i*k_nShellScriptPhasesPerAggregateTarget+j ), i*k_nShellScriptPhasesPerAggregateTarget+j+1, pGenerator->m_nShellScriptPhases ); + } + --m_nIndent; + Write( ");\n" ); + + Write( "buildRules = (\n" ); + ++m_nIndent; + { + // Aggregate targets don't get build rules + } + --m_nIndent; + Write( ");\n" ); + Write( "dependencies = (\n" ); + ++m_nIndent; + { + // these dependencies point to the dependency objects, which reference other projects through the container item proxy objects + CDependency_Project *pCurProject = projects[iProject]; + + CUtlVector<CDependency_Project*> additionalProjectDependencies; + ResolveAdditionalProjectDependencies( pCurProject, projects, additionalProjectDependencies ); + + for ( int iTestProject=0; iTestProject < projects.Count(); iTestProject++ ) + { + if ( iProject == iTestProject ) + { + // the "parent" aggregate depends on all the subaggregates, so the vpc dependency structure doesn't need to + // change. + if ( i == 0) + for ( int j = 1; j < cSubAggregateTargets; j++) + // the 0-(j+1) is to avoid colliding with the All aggregate dependency at -1 + Write( "%024llX /* %s_%d (subproject) */,\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeTargetDependency, 0-(j+1) ), pCurProject->m_ProjectName.String(), j ); + continue; + } + + CDependency_Project *pTestProject = projects[iTestProject]; + int dependsOnFlags = k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse; + if ( pCurProject->DependsOn( pTestProject, dependsOnFlags ) || additionalProjectDependencies.Find( pTestProject ) != additionalProjectDependencies.InvalidIndex() ) + { + Write( "%024llX /* %s */,\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeTargetDependency, (uint16_t)iTestProject ), pTestProject->GetName() ); + } + } + } + --m_nIndent; + Write( ");\n" ); + if ( i == 0 ) + { + Write( "name = \"%s\";\n", projects[iProject]->m_ProjectName.String() ); + Write( "productName = \"%s\";\n", projects[iProject]->m_ProjectName.String() ); + } + else + { + Write( "name = \"%s_%d\";\n", projects[iProject]->m_ProjectName.String(), i ); + Write( "productName = \"%s_%d\";\n", projects[iProject]->m_ProjectName.String(), i ); + } + } + --m_nIndent; + Write( "};\n" ); + } + } + } + --m_nIndent; + Write( "\n/* End PBXAggregateTarget section */\n" ); + + /** + ** + ** project section - the top-level object that ties all the bits (targets, groups, ...) together + ** + **/ + Write( "\n/* Begin PBXProject section */\n" ); + ++m_nIndent; + Write( "%024llX /* project object */ = {\n", makeoid( oidStrSolutionRoot, EOIDTypeProject ) ); + ++m_nIndent; + { + Write( "isa = PBXProject;\n" ); + Write( "attributes = {\n" ); + ++m_nIndent; + { + Write( "BuildIndependentTargetsInParallel = YES;\n" ); + } + --m_nIndent; + Write( "};\n" ); + Write( "buildConfigurationList = %024llX /* Build configuration list for PBXProject \"%s\" */;\n", makeoid( oidStrSolutionRoot, EOIDTypeConfigurationList ), V_UnqualifiedFileName( UsePOSIXSlashes( pSolutionFilename ) ) ); + Write( "compatibilityVersion = \"Xcode 3.0\";\n" ); + Write( "hasScannedForEncodings = 0;\n" ); + Write( "mainGroup = %024llX;\n", makeoid( oidStrProjectsRoot, EOIDTypeGroup ) ); + Write( "productRefGroup = %024llX /* Products */;\n", makeoid( oidStrSolutionRoot, EOIDTypeGroup ) ); + Write( "projectDirPath = \"\";\n" ); + Write( "projectRoot = \"\";\n" ); + Write( "targets = (\n" ); + ++m_nIndent; + { + Write( "%024llX /* All */,\n", makeoid( oidStrSolutionRoot, EOIDTypeAggregateTarget ) ); + // sort the projects by name before we emit the list + CUtlSortVector< CUtlString, CStringLess > vecSortedProjectNames; + FOR_EACH_VEC( g_vecPGenerators, iGen ) + { + vecSortedProjectNames.Insert( g_vecPGenerators[iGen]->GetProjectName() ); + } + FOR_EACH_VEC( vecSortedProjectNames, iProjectName ) + { + FOR_EACH_VEC( projects, iProject ) + { + if ( strcmp( projects[iProject]->m_ProjectName.String(), vecSortedProjectNames[iProjectName] ) ) + { + continue; + } + Write( "%024llX /* %s */,\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeNativeTarget ), projects[iProject]->m_ProjectName.String() ); + // if this is an aggregate target with more than one shell script, emit the "child" aggregates + if ( !ProjectProducesBinary( ((CProjectGenerator_Xcode*)g_vecPGenerators[iProject]) ) ) + { + int cSubAggregateTargets = ( ((CProjectGenerator_Xcode*)g_vecPGenerators[iProject])->m_nShellScriptPhases / k_nShellScriptPhasesPerAggregateTarget ) + ( ((CProjectGenerator_Xcode*)g_vecPGenerators[iProject])->m_nShellScriptPhases % k_nShellScriptPhasesPerAggregateTarget ? 1 : 0 ); + for ( int i=1; i < cSubAggregateTargets; i++ ) + Write( "%024llX /* %s_%d */,\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeNativeTarget, i ), projects[iProject]->m_ProjectName.String(), i ); + } + } + } + } + --m_nIndent; + Write( ");\n" ); + } + --m_nIndent; + Write( "};" ); + Write( "\n/* End PBXProject section */\n" ); + + /** + ** + ** container item proxies (no clue, I just work here...) - they sit between projects when expressing dependencies + ** + **/ + Write( "\n/* Begin PBXContainerItemProxy section */" ); + { + FOR_EACH_VEC( projects, iProject ) + { + + // for the aggregate target + Write( "\n" ); + Write( "%024llX /* PBXContainerItemProxy */ = {\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeContainerItemProxy, -1 ) ); + ++m_nIndent; + { + Write( "isa = PBXContainerItemProxy;\n" ); + // it looks like if you cross ref between xcodeprojs, this is the oid for the other xcode proj + Write( "containerPortal = %024llX; /* Project object */\n", makeoid( oidStrSolutionRoot, EOIDTypeProject ) ); + Write( "proxyType = 1;\n" ); + Write( "remoteGlobalIDString = %024llX;\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeNativeTarget ) ); + Write( "remoteInfo = \"%s\";\n", projects[iProject]->m_ProjectName.String() ); + } + --m_nIndent; + Write( "};" ); + + // for each project, figure out what projects it depends on, and spit out a containeritemproxy for that dependency + // of particular note is that there are many item proxies for a given project, so we make their oids with the ordinal + // of the project they depend on - this must be consistent within the generated solution + CDependency_Project *pCurProject = projects[iProject]; + + CUtlVector<CDependency_Project*> additionalProjectDependencies; + ResolveAdditionalProjectDependencies( pCurProject, projects, additionalProjectDependencies ); + + for ( int iTestProject=0; iTestProject < projects.Count(); iTestProject++ ) + { + if ( iProject == iTestProject ) + { + int cSubAggregateTargets = ( ((CProjectGenerator_Xcode*)g_vecPGenerators[iProject])->m_nShellScriptPhases / k_nShellScriptPhasesPerAggregateTarget ) + ( ((CProjectGenerator_Xcode*)g_vecPGenerators[iProject])->m_nShellScriptPhases % k_nShellScriptPhasesPerAggregateTarget ? 1 : 0 ); + for ( int i = 1; i < cSubAggregateTargets; i++ ) + { + Write( "\n" ); + Write( "%024llX /* PBXContainerItemProxy (subproject) */ = {\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeContainerItemProxy, 0-(i+1) ) ); + ++m_nIndent; + { + Write( "isa = PBXContainerItemProxy;\n" ); + // it looks like if you cross ref between xcodeprojs, this is the oid for the other xcode proj + Write( "containerPortal = %024llX; /* Project object */\n", makeoid( oidStrSolutionRoot, EOIDTypeProject ) ); + Write( "proxyType = 1;\n" ); + Write( "remoteGlobalIDString = %024llX;\n", makeoid( projects[iTestProject]->m_ProjectName, EOIDTypeNativeTarget, i ) ); + Write( "remoteInfo = \"%s\";\n", projects[iTestProject]->m_ProjectName.String() ); + } + --m_nIndent; + Write( "};" ); + } + continue; + } + + CDependency_Project *pTestProject = projects[iTestProject]; + int dependsOnFlags = k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse; + if ( pCurProject->DependsOn( pTestProject, dependsOnFlags ) || additionalProjectDependencies.Find( pTestProject ) != additionalProjectDependencies.InvalidIndex() ) + { + Write( "\n" ); + Write( "%024llX /* PBXContainerItemProxy */ = {\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeContainerItemProxy, (uint16_t)iTestProject ) ); + ++m_nIndent; + { + Write( "isa = PBXContainerItemProxy;\n" ); + // it looks like if you cross ref between xcodeprojs, this is the oid for the other xcode proj + Write( "containerPortal = %024llX; /* Project object */\n", makeoid( oidStrSolutionRoot, EOIDTypeProject ) ); + Write( "proxyType = 1;\n" ); + Write( "remoteGlobalIDString = %024llX;\n", makeoid( projects[iTestProject]->m_ProjectName, EOIDTypeNativeTarget ) ); + Write( "remoteInfo = \"%s\";\n", projects[iTestProject]->m_ProjectName.String() ); + } + --m_nIndent; + Write( "};" ); + } + } + } + } + Write( "\n/* End PBXContainerItemProxy section */\n" ); + + /** + ** + ** target dependencies - referenced by each project, in turn references the proxy container objects to express dependencies between targets + ** + **/ + Write( "\n/* Begin PBXTargetDependency section */" ); + FOR_EACH_VEC( projects, iProject ) + { + Write( "\n" ); + Write( "%024llX /* PBXTargetDependency */ = {\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeTargetDependency, -1 ) ); + ++m_nIndent; + { + Write( "isa = PBXTargetDependency;\n" ); + Write( "target = %024llX /* %s */;\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeNativeTarget ), projects[iProject]->m_ProjectName.String() ); + Write( "targetProxy = %024llX /* PBXContainerItemProxy */;\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeContainerItemProxy, -1 ) ); + } + --m_nIndent; + Write( "};" ); + + CDependency_Project *pCurProject = projects[iProject]; + + CUtlVector<CDependency_Project*> additionalProjectDependencies; + ResolveAdditionalProjectDependencies( pCurProject, projects, additionalProjectDependencies ); + + for ( int iTestProject=0; iTestProject < projects.Count(); iTestProject++ ) + { + if ( iProject == iTestProject ) + { + for ( int i = 1; i < ((CProjectGenerator_Xcode*)g_vecPGenerators[iProject])->m_nShellScriptPhases; i++ ) + { + Write( "\n" ); + Write( "%024llX /* PBXTargetDependency */ = {\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeTargetDependency, 0-(i+1) ) ); + ++m_nIndent; + { + Write( "isa = PBXTargetDependency;\n" ); + Write( "target = %024llX /* %s_%d */;\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeNativeTarget, i ), projects[iProject]->m_ProjectName.String(), i ); + Write( "targetProxy = %024llX /* PBXContainerItemProxy */;\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeContainerItemProxy, 0-(i+1) ) ); + } + --m_nIndent; + Write( "};" ); + } + continue; + } + + CDependency_Project *pTestProject = projects[iTestProject]; + int dependsOnFlags = k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse; + if ( pCurProject->DependsOn( pTestProject, dependsOnFlags ) || additionalProjectDependencies.Find( pTestProject ) != additionalProjectDependencies.InvalidIndex() ) + { + // project_t *pTestProjectT = &g_projects[ pTestProject->m_iProjectIndex ]; + Write( "\n" ); + Write( "%024llX /* PBXTargetDependency */ = {\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeTargetDependency, (uint16_t)iTestProject ) ); + ++m_nIndent; + { + Write( "isa = PBXTargetDependency;\n" ); + Write( "target = %024llX /* %s */;\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeNativeTarget ), projects[iProject]->m_ProjectName.String() ); + Write( "targetProxy = %024llX /* PBXContainerItemProxy */;\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeContainerItemProxy, (uint16_t)iTestProject ) ); + } + --m_nIndent; + Write( "};" ); + } + } + } + --m_nIndent; + Write( "\n/* End PBXTargetDependency section */\n" ); + + + /** + ** + ** 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 + ** the "baseConfigurationReference" points back to the appropriate .xcconfig file that gets referenced by the project and has all the non-target specific settings + ** + **/ + + Write( "\n/* Begin XCBuildConfiguration section */" ); + ++m_nIndent; + { + // project and aggregate "all" target + for ( int iConfig = 0; iConfig < V_ARRAYSIZE(k_rgchConfigNames); iConfig++ ) + { + bool bIsDebug = !V_stristr( k_rgchConfigNames[iConfig], "release" ); + + Write( "\n" ); + Write( "%024llX /* %s */ = {\n", makeoid2( oidStrSolutionRoot, k_rgchConfigNames[iConfig], EOIDTypeBuildConfiguration ), k_rgchConfigNames[iConfig] ); + ++m_nIndent; + { + Write( "isa = XCBuildConfiguration;\n" ); + Write( "baseConfigurationReference = %024llX /* %s */;\n", makeoid2( oidStrSolutionRoot, k_rgchXCConfigFiles[iConfig], EOIDTypeFileReference ), k_rgchXCConfigFiles[iConfig] ); + Write( "buildSettings = {\n" ); + ++m_nIndent; + { + EmitBuildSettings( "All", NULL, NULL, NULL, NULL, bIsDebug ); + } + --m_nIndent; + Write( "};\n" ); + Write( "name = \"%s\";\n", k_rgchConfigNames[iConfig] ); + } + --m_nIndent; + Write( "};" ); + + Write( "\n" ); + Write( "%024llX /* %s */ = {\n", makeoid2( oidStrSolutionRoot, k_rgchConfigNames[iConfig], EOIDTypeBuildConfiguration, 1 ), k_rgchConfigNames[iConfig] ); + ++m_nIndent; + { + Write( "isa = XCBuildConfiguration;\n" ); + Write( "baseConfigurationReference = %024llX /* %s */;\n", makeoid2( oidStrSolutionRoot, k_rgchXCConfigFiles[iConfig], EOIDTypeFileReference ), k_rgchXCConfigFiles[iConfig] ); + Write( "buildSettings = {\n" ); + ++m_nIndent; + { + EmitBuildSettings( "All", NULL, NULL, NULL, NULL, bIsDebug ); + } + --m_nIndent; + Write( "};\n" ); + Write( "name = \"%s\";\n", k_rgchConfigNames[iConfig] ); + } + --m_nIndent; + Write( "};" ); + } + + FOR_EACH_VEC( projects, iProject ) + { + KeyValues *pReleaseKV = g_vecPGenerators[iProject]->m_BaseConfigData.m_Configurations[0]->m_pKV; + for ( int iConfig = 0; iConfig < V_ARRAYSIZE(k_rgchConfigNames); iConfig++ ) + { + bool bIsDebug = !V_stristr( k_rgchConfigNames[iConfig], "release" ); + + Write( "\n" ); + Write( "%024llX /* %s */ = {\n", makeoid3( oidStrSolutionRoot, projects[iProject]->m_ProjectName, k_rgchConfigNames[iConfig], EOIDTypeBuildConfiguration ), k_rgchConfigNames[iConfig] ); + ++m_nIndent; + { + Write( "isa = XCBuildConfiguration;\n" ); + Write( "baseConfigurationReference = %024llX /* %s */;\n", makeoid2( oidStrSolutionRoot, k_rgchXCConfigFiles[iConfig], EOIDTypeFileReference ), k_rgchXCConfigFiles[iConfig] ); + Write( "buildSettings = {\n" ); + ++m_nIndent; + { + KeyValues *pConfigKV = g_vecPGenerators[iProject]->m_BaseConfigData.m_Configurations[iConfig]->m_pKV; + char rgchProjectDir[MAX_PATH]; + V_strncpy( rgchProjectDir, projects[iProject]->m_ProjectFilename.String(), sizeof( rgchProjectDir ) ); + V_StripFilename( rgchProjectDir ); + + EmitBuildSettings( projects[iProject]->m_ProjectName, rgchProjectDir, &(g_vecPGenerators[iProject]->m_Files), pConfigKV, pReleaseKV, bIsDebug ); + } + --m_nIndent; + Write( "};\n" ); + Write( "name = \"%s\";\n", k_rgchConfigNames[iConfig] ); + } + --m_nIndent; + Write( "};" ); + } + } + } + --m_nIndent; + Write( "\n/* End XCBuildConfiguration section */\n" ); + + /** + ** + ** configuration lists - aggregates the build configurations above into sets, which are referenced by the individual targets. + ** + **/ + Write( "\n/* Begin XCConfigurationList section */\n" ); + ++m_nIndent; + { + Write( "%024llX /* Build configuration list for PBXProject \"%s\" */ = {\n", makeoid( oidStrSolutionRoot, EOIDTypeConfigurationList ), V_UnqualifiedFileName( UsePOSIXSlashes( pSolutionFilename ) ) ); + ++m_nIndent; + { + Write( "isa = XCConfigurationList;\n" ); + Write( "buildConfigurations = (\n" ); + ++m_nIndent; + for ( int iConfig = 0; iConfig < V_ARRAYSIZE(k_rgchConfigNames); iConfig++ ) + { + Write( "%024llX /* %s */,\n", makeoid2( oidStrSolutionRoot, k_rgchConfigNames[iConfig], EOIDTypeBuildConfiguration ), k_rgchConfigNames[iConfig] ); + } + --m_nIndent; + Write( ");\n" ); + Write( "defaultConfigurationIsVisible = 0;\n" ); + Write( "defaultConfigurationName = \"%s\";\n", k_rgchConfigNames[0] ); + } + --m_nIndent; + Write( "};\n" ); + + Write( "%024llX /* Build configuration list for PBXAggregateTarget \"All\" */ = {\n", makeoid( oidStrSolutionRoot, EOIDTypeConfigurationList, 1 ) ); + ++m_nIndent; + { + Write( "isa = XCConfigurationList;\n" ); + Write( "buildConfigurations = (\n" ); + ++m_nIndent; + for ( int iConfig = 0; iConfig < V_ARRAYSIZE(k_rgchConfigNames); iConfig++ ) + { + Write( "%024llX /* %s */,\n", makeoid2( oidStrSolutionRoot, k_rgchConfigNames[iConfig], EOIDTypeBuildConfiguration, 1 ), k_rgchConfigNames[iConfig] ); + } + --m_nIndent; + Write( ");\n" ); + Write( "defaultConfigurationIsVisible = 0;\n" ); + Write( "defaultConfigurationName = \"%s\";\n", k_rgchConfigNames[0] ); + } + --m_nIndent; + Write( "};" ); + + FOR_EACH_VEC( projects, iProject ) + { + Write( "\n" ); + Write( "%024llX /* Build configuration list for PBXNativeTarget \"%s\" */ = {\n", makeoid( projects[iProject]->m_ProjectName, EOIDTypeConfigurationList ), projects[iProject]->m_ProjectName.String() ); + ++m_nIndent; + { + Write( "isa = XCConfigurationList;\n" ); + Write( "buildConfigurations = (\n" ); + ++m_nIndent; + for ( int iConfig = 0; iConfig < V_ARRAYSIZE(k_rgchConfigNames); iConfig++ ) + { + Write( "%024llX /* %s */,\n", makeoid3( oidStrSolutionRoot, projects[iProject]->m_ProjectName, k_rgchConfigNames[iConfig], EOIDTypeBuildConfiguration ), k_rgchConfigNames[iConfig] ); + } + --m_nIndent; + Write( ");\n" ); + Write( "defaultConfigurationIsVisible = 0;\n" ); + Write( "defaultConfigurationName = \"%s\";\n", k_rgchConfigNames[0] ); + } + --m_nIndent; + Write( "};" ); + } + } + --m_nIndent; + Write( "\n/* End XCConfigurationList section */\n" ); + } + Write( "};\n" ); // objects = { ... + + /** + ** + ** root object in the graph + ** + **/ + Write( "rootObject = %024llX /* Project object */;\n", makeoid( oidStrSolutionRoot, EOIDTypeProject ) ); + } + --m_nIndent; + + Write( "}\n" ); + fclose( m_fp ); + + // and now write a .projects file inside the xcode project so we can detect the list of projects changing + // (specifically a vpc project dissapearing from our target list) + FILE *fp = fopen( sProjProjectListFile, "wt" ); + if ( !fp ) + { + g_pVPC->VPCError( "Unable to open %s to write projects into.", sProjProjectListFile ); + } + // we don't need to be quite as careful as project script, as we're only looking to catch cases where the rest of VPC thinks we're up-to-date + fprintf( fp, "%s\n", VPCCRCCHECK_FILE_VERSION_STRING ); + FOR_EACH_VEC( g_vecPGenerators, iGenerator ) + { + CProjectGenerator_Xcode *pGenerator = (CProjectGenerator_Xcode*)g_vecPGenerators[iGenerator]; + + fprintf( fp, "%s\n", pGenerator->m_ProjectName.String() ); + } + fclose( fp ); +} + +void CSolutionGenerator_Xcode::Write( const char *pMsg, ... ) +{ + for ( int i=0; i < m_nIndent; i++ ) + fprintf( m_fp, "\t" ); + + va_list marker; + va_start( marker, pMsg ); + vfprintf( m_fp, pMsg, marker ); + va_end( marker ); +} + +static CSolutionGenerator_Xcode g_SolutionGenerator_Xcode; +IBaseSolutionGenerator* GetXcodeSolutionGenerator() +{ + return &g_SolutionGenerator_Xcode; +} + +static CProjectGenerator_Xcode g_ProjectGenerator_Xcode; +IBaseProjectGenerator* GetXcodeProjectGenerator() +{ + return &g_ProjectGenerator_Xcode; +} diff --git a/external/vpc/utils/vpc/sys_utils.cpp b/external/vpc/utils/vpc/sys_utils.cpp new file mode 100644 index 0000000..63684d8 --- /dev/null +++ b/external/vpc/utils/vpc/sys_utils.cpp @@ -0,0 +1,781 @@ +//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: VPC +// +//=====================================================================================// + +#include "vpc.h" + +#ifdef STEAM +#include "tier1/utlintrusivelist.h" +#endif + +#ifdef POSIX +#define _O_RDONLY O_RDONLY +#define _open open +#include <sys/errno.h> +#define _lseek lseek +#define _read read +#define _close close +#define _stat stat +#include <glob.h> +#else +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <io.h> +#include <ShellAPI.h> +#endif + +#ifdef OSX +#include <mach-o/dyld.h> +#endif + +CXMLWriter::CXMLWriter() +{ + m_fp = NULL; + m_b2010Format = false; +} + +bool CXMLWriter::Open( const char *pFilename, bool b2010Format ) +{ + m_FilenameString = pFilename; + m_b2010Format = b2010Format; + + m_fp = fopen( pFilename, "wt" ); + if ( !m_fp ) + return false; + + if ( b2010Format ) + { + Write( "\xEF\xBB\xBF<?xml version=\"1.0\" encoding=\"utf-8\"?>" ); + } + else + { + // 2005 format + Write( "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\n" ); + } + + return true; +} + +void CXMLWriter::Close() +{ + if ( !m_fp ) + return; + fclose( m_fp ); + + Sys_CopyToMirror( m_FilenameString.Get() ); + + m_fp = NULL; + m_FilenameString = NULL; +} + +void CXMLWriter::PushNode( const char *pName ) +{ + Indent(); + + char *pNewName = strdup( pName ); + m_Nodes.Push( pNewName ); + + fprintf( m_fp, "<%s%s\n", pName, m_Nodes.Count() == 2 ? ">" : "" ); +} + +void CXMLWriter::PushNode( const char *pName, const char *pString ) +{ + Indent(); + + char *pNewName = strdup( pName ); + m_Nodes.Push( pNewName ); + + fprintf( m_fp, "<%s%s%s>\n", pName, pString ? " " : "", pString ? pString : "" ); +} + +void CXMLWriter::WriteLineNode( const char *pName, const char *pExtra, const char *pString ) +{ + Indent(); + + fprintf( m_fp, "<%s%s>%s</%s>\n", pName, pExtra ? pExtra : "", pString, pName ); +} + +void CXMLWriter::PopNode( bool bEmitLabel ) +{ + char *pName; + m_Nodes.Pop( pName ); + + Indent(); + if ( bEmitLabel ) + { + fprintf( m_fp, "</%s>\n", pName ); + } + else + { + fprintf( m_fp, "/>\n" ); + } + + free( pName ); +} + +void CXMLWriter::Write( const char *p ) +{ + if ( m_fp ) + { + Indent(); + fprintf( m_fp, "%s\n", p ); + } +} + +CUtlString CXMLWriter::FixupXMLString( const char *pInput ) +{ + struct XMLFixup_t + { + const char *m_pFrom; + const char *m_pTo; + bool m_b2010Only; + }; + + // these tokens are not allowed in xml vcproj and be be escaped per msdev docs + XMLFixup_t xmlFixups[] = + { + {"&", "&", false}, + {"\"", """, false}, + {"\'", "'", false}, + {"\n", "
", false}, + {">", ">", false}, + {"<", "<", false}, + {"$(InputFileName)", "%(Filename)%(Extension)", true}, + {"$(InputName)", "%(Filename)", true}, + {"$(InputPath)", "%(FullPath)", true}, + {"$(InputDir)", "%(RootDir)%(Directory)", true}, + }; + + bool bNeedsFixups = false; + CUtlVector< bool > needsFixups; + CUtlString outString; + + needsFixups.SetCount( ARRAYSIZE( xmlFixups ) ); + for ( int i = 0; i < ARRAYSIZE( xmlFixups ); i++ ) + { + needsFixups[i] = false; + + if ( !m_b2010Format && xmlFixups[i].m_b2010Only ) + continue; + + if ( V_stristr( pInput, xmlFixups[i].m_pFrom ) ) + { + needsFixups[i] = true; + bNeedsFixups = true; + } + } + + if ( !bNeedsFixups ) + { + outString = pInput; + } + else + { + int flip = 0; + char bigBuffer[2][8192]; + V_strncpy( bigBuffer[flip], pInput, sizeof( bigBuffer[0] ) ); + + for ( int i = 0; i < ARRAYSIZE( xmlFixups ); i++ ) + { + if ( !needsFixups[i] ) + continue; + + if ( !V_StrSubst( bigBuffer[flip], xmlFixups[i].m_pFrom, xmlFixups[i].m_pTo, bigBuffer[flip ^ 1], sizeof( bigBuffer[0] ), false ) ) + { + g_pVPC->VPCError( "XML overflow - Increase big buffer" ); + } + flip ^= 1; + } + outString = bigBuffer[flip]; + } + + return outString; +} + +void CXMLWriter::Indent() +{ + for ( int i = 0; i < m_Nodes.Count(); i++ ) + { + if ( m_b2010Format ) + { + fprintf( m_fp, " " ); + } + else + { + fprintf( m_fp, "\t" ); + } + } +} + +//----------------------------------------------------------------------------- +// Sys_LoadFile +// +//----------------------------------------------------------------------------- +int Sys_LoadFile( const char* filename, void** bufferptr, bool bText ) +{ + int handle; + long length; + char* buffer; + + *bufferptr = NULL; + + if ( !Sys_Exists( filename ) ) + return ( -1 ); + + int flags = _O_RDONLY; +#if !defined( POSIX ) + flags |= (bText ? _O_TEXT : _O_BINARY); +#endif + handle = _open( filename, flags ); + if ( handle == -1 ) + Sys_Error( "Sys_LoadFile(): Error opening %s: %s", filename, strerror( errno ) ); + + length = _lseek( handle, 0, SEEK_END ); + _lseek( handle, 0, SEEK_SET ); + buffer = ( char* )malloc( length+1 ); + + int bytesRead = _read( handle, buffer, length ); + if ( !bText && ( bytesRead != length ) ) + Sys_Error( "Sys_LoadFile(): read truncated failure" ); + + _close( handle ); + + // text mode is truncated, add null for parsing + buffer[bytesRead] = '\0'; + + *bufferptr = ( void* )buffer; + + return ( length ); +} + +//----------------------------------------------------------------------------- +// Sys_LoadFileIntoBuffer +// +//----------------------------------------------------------------------------- +bool Sys_LoadFileIntoBuffer( const char *pchFileIn, CUtlBuffer &buf, bool bText ) +{ + buf.SetBufferType( bText, bText ); + struct stat statBuf; + if ( stat( pchFileIn, &statBuf ) != 0 ) + return false; + buf.EnsureCapacity( (int)(statBuf.st_size + 1) ); + if ( !buf.IsValid() ) + return false; + + FILE *fp = fopen( pchFileIn, "rb" ); + if ( !fp ) + return false; + + char *pBuffer = (char*)buf.Base(); + int nBytesRead = statBuf.st_size * fread( pBuffer, statBuf.st_size, 1, fp ); + fclose( fp ); + buf.SeekPut( CUtlBuffer::SEEK_HEAD, nBytesRead ); + pBuffer[statBuf.st_size] = 0; // terminate buffer without changing put size + return nBytesRead == statBuf.st_size; +} + + +//----------------------------------------------------------------------------- +// Sys_FileLength +//----------------------------------------------------------------------------- +long Sys_FileLength( const char* filename, bool bText ) +{ + long length; + + if ( filename ) + { + int flags = _O_RDONLY; +#if !defined( POSIX ) + flags |= (bText ? _O_TEXT : _O_BINARY); +#endif + int handle = _open( filename, flags ); + if ( handle == -1 ) + { + // file does not exist + return ( -1 ); + } + + length = _lseek( handle, 0, SEEK_END ); + _close( handle ); + } + else + { + return ( -1 ); + } + + return ( length ); +} + +//----------------------------------------------------------------------------- +// Sys_StripPath +// +// Removes path portion from a fully qualified name, leaving filename and extension. +//----------------------------------------------------------------------------- +void Sys_StripPath( const char* inpath, char* outpath ) +{ + const char* src; + + src = inpath + strlen( inpath ); + while ( ( src != inpath ) && ( *( src-1 ) != '\\' ) && ( *( src-1 ) != '/' ) && ( *( src-1 ) != ':' ) ) + src--; + + strcpy( outpath,src ); +} + +//----------------------------------------------------------------------------- +// Sys_Exists +// +// Returns TRUE if file exists. +//----------------------------------------------------------------------------- +bool Sys_Exists( const char* filename ) +{ + FILE* test; + + if ( ( test = fopen( filename, "rb" ) ) == NULL ) + return ( false ); + + fclose( test ); + + return ( true ); +} + + +//----------------------------------------------------------------------------- +// Sys_Touch +// +// Returns TRUE if the file could be accessed for write +//----------------------------------------------------------------------------- +bool Sys_Touch( const char* filename ) +{ + FILE* test; + + if ( ( test = fopen( filename, "wb" ) ) == NULL ) + return ( false ); + + fclose( test ); + + return ( true ); +} + + +//----------------------------------------------------------------------------- +// Sys_FileInfo +//----------------------------------------------------------------------------- +bool Sys_FileInfo( const char *pFilename, int64 &nFileSize, int64 &nModifyTime ) +{ + struct _stat statData; + int rt = _stat( pFilename, &statData ); + if ( rt != 0 ) + return false; + + nFileSize = statData.st_size; + nModifyTime = statData.st_mtime; + return true; +} + +//----------------------------------------------------------------------------- +// Ignores allowable trailing characters. +//----------------------------------------------------------------------------- +bool Sys_StringToBool( const char *pString ) +{ + if ( !V_strnicmp( pString, "no", 2 ) || + !V_strnicmp( pString, "off", 3 ) || + !V_strnicmp( pString, "false", 5 ) || + !V_strnicmp( pString, "not set", 7 ) || + !V_strnicmp( pString, "disabled", 8 ) || + !V_strnicmp( pString, "0", 1 ) ) + { + // false + return false; + } + else if ( !V_strnicmp( pString, "yes", 3 ) || + !V_strnicmp( pString, "on", 2 ) || + !V_strnicmp( pString, "true", 4 ) || + !V_strnicmp( pString, "set", 3 ) || + !V_strnicmp( pString, "enabled", 7 ) || + !V_strnicmp( pString, "1", 1 ) ) + { + // true + return true; + } + else + { + // unknown boolean expression + g_pVPC->VPCSyntaxError( "Unknown boolean expression '%s'", pString ); + } + + // assume false + return false; +} + +bool Sys_ReplaceString( const char *pStream, const char *pSearch, const char *pReplace, char *pOutBuff, int outBuffSize ) +{ + const char *pFind; + const char *pStart = pStream; + char *pOut = pOutBuff; + int len; + bool bReplaced = false; + + while ( 1 ) + { + // find sub string + pFind = V_stristr( pStart, pSearch ); + if ( !pFind ) + { + /// end of string + len = strlen( pStart ); + pFind = pStart + len; + memcpy( pOut, pStart, len ); + pOut += len; + break; + } + else + { + bReplaced = true; + } + + // copy up to sub string + len = pFind - pStart; + memcpy( pOut, pStart, len ); + pOut += len; + + // substitute new string + len = strlen( pReplace ); + memcpy( pOut, pReplace, len ); + pOut += len; + + // advance past sub string + pStart = pFind + strlen( pSearch ); + } + + *pOut = '\0'; + + return bReplaced; +} + +//-------------------------------------------------------------------------------- +// string match with wildcards. +// '?' = match any char +//-------------------------------------------------------------------------------- +bool Sys_StringPatternMatch( char const *pSrcPattern, char const *pString ) +{ + for (;;) + { + char nPat = *(pSrcPattern++); + char nString= *(pString++); + if ( !( ( nPat == nString ) || ( ( nPat == '?' ) && nString ) ) ) + return false; + if ( !nString ) + return true; // end of string + } +} + +bool Sys_EvaluateEnvironmentExpression( const char *pExpression, const char *pDefault, char *pOutBuff, int nOutBuffSize ) +{ + char *pEnvVarName = (char*)StringAfterPrefix( pExpression, "$env(" ); + if ( !pEnvVarName ) + { + // not an environment specification + return false; + } + + char *pLastChar = &pEnvVarName[ V_strlen( pEnvVarName ) - 1 ]; + if ( !*pEnvVarName || *pLastChar != ')' ) + { + g_pVPC->VPCSyntaxError( "$env() must have a closing ')' in \"%s\"\n", pExpression ); + } + + // get the contents of the $env( blah..blah ) expressions + // handles expresions that could have whitepsaces + g_pVPC->GetScript().PushScript( pExpression, pEnvVarName ); + const char *pToken = g_pVPC->GetScript().GetToken( false ); + g_pVPC->GetScript().PopScript(); + + if ( pToken && pToken[0] ) + { + const char *pResolve = getenv( pToken ); + if ( !pResolve ) + { + // not defined, use default + pResolve = pDefault ? pDefault : ""; + } + + V_strncpy( pOutBuff, pResolve, nOutBuffSize ); + } + + return true; +} + +bool Sys_ExpandFilePattern( const char *pPattern, CUtlVector< CUtlString > &vecResults ) +{ +#if defined( _WIN32 ) + char rgchPathPart[MAX_PATH]; + V_strncpy( rgchPathPart, pPattern, V_ARRAYSIZE( rgchPathPart ) ); + V_StripFilename( rgchPathPart ); + if ( V_strlen( rgchPathPart ) ) + V_strncat( rgchPathPart, "\\", V_ARRAYSIZE( rgchPathPart ) ); + + WIN32_FIND_DATA findData; + HANDLE hFind = FindFirstFile( pPattern, &findData ); + if ( hFind != INVALID_HANDLE_VALUE ) + { + vecResults.AddToTail( CFmtStr( "%s%s", rgchPathPart, findData.cFileName ).Access() ); + BOOL bMore = TRUE; + while ( bMore ) + { + bMore = FindNextFile( hFind, &findData ); + if ( bMore ) + vecResults.AddToTail( CFmtStr( "%s%s", rgchPathPart, findData.cFileName ).Access() ); + } + FindClose( hFind ); + } +#elif defined( POSIX ) + glob_t gr; + if ( glob( pPattern, 0, NULL, &gr ) == 0 ) + { + for ( int i = 0; i < gr.gl_pathc; i++ ) + { + vecResults.AddToTail( gr.gl_pathv[i] ); + } + globfree( &gr ); + } +#else +#error +#endif + return vecResults.Count() > 0; +} + +bool Sys_GetExecutablePath( char *pBuf, int cbBuf ) +{ +#if defined( _WIN32 ) + return ( 0 != GetModuleFileNameA( NULL, pBuf, cbBuf ) ); +#elif defined(OSX) + uint32_t _nBuff = cbBuf; + bool bSuccess = _NSGetExecutablePath(pBuf, &_nBuff) == 0; + pBuf[cbBuf-1] = '\0'; + return bSuccess; +#elif defined LINUX + ssize_t nRead = readlink("/proc/self/exe", pBuf, cbBuf-1 ); + if ( nRead != -1 ) + { + pBuf[ nRead ] = 0; + return true; + } + + pBuf[0] = 0; + return false; +#else +#error Sys_GetExecutablePath +#endif +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void Sys_CreatePath( const char *path ) +{ +#if defined( _WIN32 ) + char pFullPath[MAX_PATH]; + V_MakeAbsolutePath( pFullPath, sizeof(pFullPath), path ); + + // If Sys_CreatePath is called with a filename, all is well. + // If it is called with a folder name, it must have a trailing slash: + if ( !V_GetFileExtension( pFullPath ) ) + V_AppendSlash( pFullPath, sizeof(pFullPath) ); + + char *ptr; + + // skip past the drive path, but don't strip + if ( pFullPath[1] == ':' ) + { + ptr = strchr( pFullPath, '\\' ); + } + else + { + ptr = pFullPath; + } + while ( ptr ) + { + ptr = strchr( ptr+1, '\\' ); + if ( ptr ) + { + *ptr = '\0'; + +#if defined( _WIN32 ) || defined( WIN32 ) + CreateDirectory( pFullPath, NULL ); +#else +#error Sys_CreatePath: this mkdir is probably correct but has not been tested + mkdir( pFullPath, 0777 ); +#endif + *ptr = '\\'; + } + } +#endif +} + +//----------------------------------------------------------------------------- +// Given some arbitrary case filename, provides what the OS thinks it is. +// Windows specific. Returns false if file cannot be resolved (i.e. does not exist). +//----------------------------------------------------------------------------- +bool Sys_GetActualFilenameCase( const char *pFilename, char *pOutputBuffer, int nOutputBufferSize ) +{ +#if defined( _WINDOWS ) + char filenameBuffer[MAX_PATH]; + V_strncpy( filenameBuffer, pFilename, sizeof( filenameBuffer ) ); + V_FixSlashes( filenameBuffer ); + V_RemoveDotSlashes( filenameBuffer ); + + int nFilenameLength = V_strlen( filenameBuffer ); + + CUtlString actualFilename; + + // march along filename, resolving up to next seperator + int nLastComponentStart = 0; + bool bAddSeparator = false; + int i = 0; + while ( i < nFilenameLength ) + { + // cannot resolve these, emit as-is + if ( !V_strnicmp( filenameBuffer + i, ".\\", 2 ) ) + { + i += 2; + actualFilename += CUtlString( ".\\" ); + continue; + } + + // cannot resolve these, emit as-is + if ( !V_strnicmp( filenameBuffer + i, "..\\", 3 ) ) + { + i += 3; + actualFilename += CUtlString( "..\\" ); + continue; + } + + // skip until path separator + while ( i < nFilenameLength && filenameBuffer[i] != '\\' ) + { + ++i; + } + + bool bFoundSeparator = ( i < nFilenameLength ); + + // truncate at separator, windows resolves each component in pieces + filenameBuffer[i] = 0; + + SHFILEINFOA info = {0}; + HRESULT hr = SHGetFileInfoA( filenameBuffer, 0, &info, sizeof( info ), SHGFI_DISPLAYNAME ); + if ( SUCCEEDED( hr ) ) + { + // reassemble based on actual component + if ( bAddSeparator ) + { + actualFilename += CUtlString( "\\" ); + } + actualFilename += CUtlString( info.szDisplayName ); + } + else + { + return false; + } + + // restore path separator + if ( bFoundSeparator ) + { + filenameBuffer[i] = '\\'; + } + + ++i; + nLastComponentStart = i; + bAddSeparator = true; + } + + V_strncpy( pOutputBuffer, actualFilename.Get(), nOutputBufferSize ); + return true; +#else + return false; +#endif +} + +//----------------------------------------------------------------------------- +// Given some arbitrary case filename, determine if OS version matches. +//----------------------------------------------------------------------------- +bool Sys_IsFilenameCaseConsistent( const char *pFilename, char *pOutputBuffer, int nOutputBufferSize ) +{ + V_strncpy( pOutputBuffer, pFilename, nOutputBufferSize ); + + // normalize the provided filename separators + CUtlString filename = pFilename; + V_FixSlashes( filename.Get() ); + V_RemoveDotSlashes( filename.Get() ); + + if ( !Sys_GetActualFilenameCase( filename.Get(), pOutputBuffer, nOutputBufferSize ) ) + return false; + + if ( !V_strcmp( filename.Get(), pOutputBuffer ) ) + return true; + + return false; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool Sys_CopyToMirror( const char *pFilename ) +{ + if ( !pFilename || !pFilename[0] ) + return false; + + const char *pMirrorPath = g_pVPC->GetOutputMirrorPath(); + if ( !pMirrorPath || !pMirrorPath[0] ) + return false; + + char absolutePathToOriginal[MAX_PATH]; + if ( V_IsAbsolutePath( pFilename ) ) + { + V_strncpy( absolutePathToOriginal, pFilename, sizeof( absolutePathToOriginal ) ); + } + else + { + // need to determine where file resides for mirroring + char currentDirectory[MAX_PATH] = { 0 }; + V_GetCurrentDirectory( currentDirectory, sizeof( currentDirectory ) ); + V_ComposeFileName( currentDirectory, pFilename, absolutePathToOriginal, sizeof( absolutePathToOriginal ) ); + } + + if ( !Sys_Exists( absolutePathToOriginal ) ) + { + g_pVPC->VPCWarning( "Cannot mirror '%s', cannot resolve to expected '%s'", pFilename, absolutePathToOriginal ); + return false; + } + + const char *pTargetPath = StringAfterPrefix( absolutePathToOriginal, g_pVPC->GetSourcePath() ); + if ( !pTargetPath || !pTargetPath[0] ) + { + g_pVPC->VPCWarning( "Cannot mirror '%s', missing expected prefix '%s' in '%s'", pFilename, g_pVPC->GetSourcePath(), absolutePathToOriginal ); + return false; + } + + // supply the mirror path head + char absolutePathToMirror[MAX_PATH]; + if ( pTargetPath[0] == '\\' ) + { + pTargetPath++; + } + V_ComposeFileName( pMirrorPath, pTargetPath, absolutePathToMirror, sizeof( absolutePathToMirror ) ); + +#ifdef _WIN32 + Sys_CreatePath( absolutePathToMirror ); + + if ( !CopyFile( absolutePathToOriginal, absolutePathToMirror, FALSE ) ) + { + g_pVPC->VPCWarning( "Cannot mirror '%s' to '%s'", absolutePathToOriginal, absolutePathToMirror ); + return false; + } + else + { + g_pVPC->VPCStatus( true, "Mirror: '%s' to '%s'", absolutePathToOriginal, absolutePathToMirror ); + } +#endif + + return true; +}
\ No newline at end of file diff --git a/external/vpc/utils/vpc/sys_utils.h b/external/vpc/utils/vpc/sys_utils.h new file mode 100644 index 0000000..7cd457f --- /dev/null +++ b/external/vpc/utils/vpc/sys_utils.h @@ -0,0 +1,157 @@ +//======= Copyright 1996-2005, Valve Corporation, All rights reserved. ======// +// +// File Utilities. +// +//===========================================================================// + +#ifdef _WIN32 +#pragma once +#endif + +#define _CRT_SECURE_NO_DEPRECATE 1 + +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <string.h> + +#ifdef POSIX +#include <unistd.h> +#endif + +#if defined( LINUX ) || defined( _LINUX ) + #include <sys/io.h> +#endif + +#include "tier0/platform.h" +#include "../vpccrccheck/crccheck_shared.h" + +template< class T, class NullType, int nMax > +class CSimplePointerStack +{ +public: + inline CSimplePointerStack() + { + m_nCount = 0; + } + + inline void Purge() + { + for ( int i=0; i < m_nCount; i++ ) + m_Values[i] = (NullType)NULL; + m_nCount = 0; + } + + inline int Count() + { + return m_nCount; + } + + inline T& Top() + { + Assert( m_nCount > 0 ); + return m_Values[m_nCount-1]; + } + + inline void Pop( T &val ) + { + Assert( m_nCount > 0 ); + --m_nCount; + val = m_Values[m_nCount]; + m_Values[m_nCount] = (NullType)NULL; + } + + inline void Pop() + { + Assert( m_nCount > 0 ); + --m_nCount; + m_Values[m_nCount] = (NullType)NULL; + } + + inline void Push( T &val ) + { + Assert( m_nCount+1 < nMax ); + m_Values[m_nCount] = val; + ++m_nCount; + } + +public: + T m_Values[nMax]; + int m_nCount; +}; + +class CXMLWriter +{ +public: + CXMLWriter(); + + bool Open( const char *pFilename, bool bIs2010Format = false ); + void Close(); + + void PushNode( const char *pName ); + void PopNode( bool bEmitLabel ); + + void WriteLineNode( const char *pName, const char *pExtra, const char *pString ); + void PushNode( const char *pName, const char *pString ); + + void Write( const char *p ); + CUtlString FixupXMLString( const char *pInput ); + +private: + void Indent(); + + bool m_b2010Format; + FILE *m_fp; + + CUtlString m_FilenameString; + + CSimplePointerStack< char *, char *, 128 > m_Nodes; +}; + +long Sys_FileLength( const char* filename, bool bText = false ); +int Sys_LoadFile( const char *filename, void **bufferptr, bool bText = false ); +bool Sys_LoadFileIntoBuffer( const char *pchFileIn, CUtlBuffer &buf, bool bText ); +void Sys_StripPath( const char *path, char *outpath ); +bool Sys_Exists( const char *filename ); +bool Sys_Touch( const char *filename ); +bool Sys_FileInfo( const char *pFilename, int64 &nFileSize, int64 &nModifyTime ); + +bool Sys_StringToBool( const char *pString ); +bool Sys_ReplaceString( const char *pStream, const char *pSearch, const char *pReplace, char *pOutBuff, int outBuffSize ); +bool Sys_StringPatternMatch( char const *pSrcPattern, char const *pString ); + +bool Sys_EvaluateEnvironmentExpression( const char *pExpression, const char *pDefault, char *pOutBuff, int nOutBuffSize ); + +bool Sys_ExpandFilePattern( const char *pPattern, CUtlVector< CUtlString > &vecResults ); +bool Sys_GetExecutablePath( char *pBuf, int cbBuf ); + +bool Sys_CopyToMirror( const char *pFilename ); +inline bool IsCFileExtension( const char *pExtension ) +{ + if ( !pExtension ) + return false; + + return !V_stricmp( pExtension, "cpp" ) || + !V_stricmp( pExtension, "cxx" ) || + !V_stricmp( pExtension, "cc" ) || + !V_stricmp( pExtension, "c" ); +} + +bool Sys_GetActualFilenameCase( const char *pFilename, char *pOutputBuffer, int nOutputBufferSize ); +bool Sys_IsFilenameCaseConsistent( const char *pFilename, char *pOutputBuffer, int nOutputBufferSize ); +inline bool IsHFileExtension( const char *pExtension ) +{ + if ( !pExtension ) + return false; + + return !V_stricmp( pExtension, "hpp" ) || + !V_stricmp( pExtension, "hxx" ) || + !V_stricmp( pExtension, "hh" ) || + !V_stricmp( pExtension, "h" ); +} + + diff --git a/external/vpc/utils/vpc/vpc.h b/external/vpc/utils/vpc/vpc.h new file mode 100644 index 0000000..4ff493e --- /dev/null +++ b/external/vpc/utils/vpc/vpc.h @@ -0,0 +1,482 @@ +//========= Copyright 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: VPC +// +//=====================================================================================// + +#pragma once + +// Exclude rarely-used stuff from Windows headers +#define WIN32_LEAN_AND_MEAN +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN +#endif + +#include "utlstring.h" +#include "utlrbtree.h" +#include "utlvector.h" +#include "utlbuffer.h" +#include "utlstack.h" +#include "utldict.h" +#include "utlsortvector.h" +#include "checksum_crc.h" +#include "checksum_md5.h" +#include "fmtstr.h" +#include "exprevaluator.h" +#include "tier1/interface.h" +#include "p4lib/ip4.h" +#include "scriptsource.h" +#include "logging.h" +#ifdef STEAM +#include "vstdlib/strtools.h" +#else +#include "tier1/strtools.h" +#endif +#include "sys_utils.h" +#include "keyvalues.h" +#include "generatordefinition.h" + +DECLARE_LOGGING_CHANNEL( LOG_VPC ); + +#if defined( WIN32 ) +#include <atlbase.h> +#include <io.h> +#endif // WIN32 + +struct KeywordName_t +{ + const char *m_pName; + configKeyword_e m_Keyword; +}; + +typedef bool (*procptr_t)( const char *pPropertyName ); +typedef bool (*GetSymbolProc_t)( const char *pKey ); + +#define INVALID_INDEX -1 + +struct property_t +{ + const char *pName; + procptr_t handler; + int platformMask; +}; + +enum conditionalType_e +{ + CONDITIONAL_NULL, + CONDITIONAL_PLATFORM, + CONDITIONAL_GAME, + CONDITIONAL_CUSTOM +}; + +struct conditional_t +{ + conditional_t() + { + type = CONDITIONAL_NULL; + m_bDefined = false; + m_bGameConditionActive = false; + } + + CUtlString name; + CUtlString upperCaseName; + conditionalType_e type; + + // a conditional can be present in the table but not defined + // e.g. default conditionals that get set by command line args + bool m_bDefined; + + // only used during multiple game iterations for game conditionals as each 'defined' game becomes active + bool m_bGameConditionActive; +}; + +struct macro_t +{ + macro_t() + { + m_bSetupDefineInProjectFile = false; + m_bInternalCreatedMacro = false; + } + + CUtlString name; + CUtlString value; + + // If set to true, then VPC will add this as a -Dname=value parameter to the compiler's command line. + bool m_bSetupDefineInProjectFile; + + // VPC created this macro itself rather than the macro being created from a script file. + bool m_bInternalCreatedMacro; +}; + +typedef int scriptIndex_t; +struct script_t +{ + CUtlString name; + CUtlString m_condition; +}; + +typedef int projectIndex_t; +struct project_t +{ + CUtlString name; + CUtlVector< script_t > scripts; +}; + +typedef int groupIndex_t; +struct group_t +{ + CUtlVector< projectIndex_t > projects; +}; + +typedef int groupTagIndex_t; +struct groupTag_t +{ + groupTag_t() + { + bSameAsProject = false; + } + + CUtlString name; + CUtlVector< groupIndex_t > groups; + + // this tag is an implicit definition of the project + bool bSameAsProject; +}; + +struct scriptList_t +{ + scriptList_t() + { + m_crc = 0; + } + + CUtlString m_scriptName; + CRC32_t m_crc; +}; + +class IProjectIterator +{ +public: + // iProject indexes g_projectList. + virtual bool VisitProject( projectIndex_t iProject, const char *szScriptPath ) = 0; +}; + +#include "ibasesolutiongenerator.h" +#include "ibaseprojectgenerator.h" +#if defined( WIN32 ) +#include "baseprojectdatacollector.h" +#include "projectgenerator_vcproj.h" +#include "projectgenerator_win32.h" +#include "projectgenerator_win32_2010.h" +#include "projectgenerator_xbox360.h" +#include "projectgenerator_xbox360_2010.h" +#include "projectgenerator_ps3.h" +#endif + +enum EVSVersion +{ + k_EVSVersion_Invalid, + k_EVSVersion_2005, + k_EVSVersion_2008, + k_EVSVersion_2010, + k_EVSVersion_2012, + k_EVSVersion_2013, + k_EVSVersion_2015, +}; + +class CVPC +{ +public: + CVPC(); + ~CVPC(); + + bool Init( int argc, char **argv ); + void Shutdown( bool bHasError = false ); + + void VPCError( PRINTF_FORMAT_STRING const char *pFormat, ... ); + void VPCWarning( PRINTF_FORMAT_STRING const char *pFormat, ... ); + void VPCStatus( bool bAlwaysSpew, PRINTF_FORMAT_STRING const char *pFormat, ... ); + void VPCSyntaxError( PRINTF_FORMAT_STRING const char *pFormat = NULL, ... ); + + bool IsProjectCurrent( const char *pVCProjFilename, bool bSpewStatus ); + + bool HasCommandLineParameter( const char *pParamName ); + bool HasP4SLNCommand(); + + CScript &GetScript() { return m_Script; } + + bool IsVerbose() { return m_bVerbose; } + bool IsQuiet() { return m_bQuiet; } + bool IsShowDependencies() { return m_bShowDeps; } + bool IsForceGenerate() { return m_bForceGenerate; } + bool IsPosixPCHDisabled() { return m_bNoPosixPCH; } + bool IsForceIterate() { return m_bForceIterate; } + bool IsDecorateProject() { return m_bDecorateProject; } + const char *GetDecorateString() { return m_strDecorate.String(); } + bool IsCheckFiles() { return m_bCheckFiles; } + bool Is2010() { return m_bUseVS2010FileFormat || m_eVSVersion == k_EVSVersion_2010; } + bool Is2012() { return m_eVSVersion == k_EVSVersion_2012; } // When this returns true so does Is2010() because of the file format similarities + bool Is2013() { return m_eVSVersion == k_EVSVersion_2013; } // When this returns true so does Is2010() because of the file format similarities + bool Is2015() { return m_eVSVersion == k_EVSVersion_2015; } // When this returns true so does Is2010() because of the file format similarities + bool BUse2008() { return m_eVSVersion == k_EVSVersion_2008; } + bool IsDedicatedBuild() { return m_bDedicatedBuild; } + bool IsUnity() { return m_bUseUnity; } + bool IsShowCaseIssues() { return m_bShowCaseIssues; } + bool UseValveBinDir() { return m_bUseValveBinDir; } + bool IsVerboseMakefile() { return m_bVerboseMakefile; } + bool BUseP4SCC() { return m_bP4SCC; } + bool BUse32BitTools() { return m_b32BitTools; } + + void DecorateProjectName( char *pchProjectName ); + + int GetMissingFilesCount() const { return m_FilesMissing; } + void IncrementFileMissing() { ++m_FilesMissing; } + void ResetMissingFilesCount() { m_FilesMissing = 0; } + + bool IsIgnoreRedundancyWarning() { return m_bIgnoreRedundancyWarning; } + void SetIgnoreRedundancyWarning( bool bSet ) { m_bIgnoreRedundancyWarning = bSet; } + + const char *GetStartDirectory() { return m_StartDirectory.Get(); } + const char *GetSourcePath() { return m_SourcePath.Get(); } + const char *GetProjectPath() { return m_ProjectPath.Get(); } + const char *GetCRCString() { return m_SupplementalCRCString.Get(); } + const char *GetSolutionItemsFilename() { return m_SolutionItemsFilename.Get(); } + + const char *GetOutputFilename() { return m_OutputFilename.Get(); } + void SetOutputFilename( const char *pOutputFilename ) { m_OutputFilename = pOutputFilename; } + + const char *GetProjectName() { return m_ProjectName.Get(); } + void SetProjectName( const char *pProjectName ) { m_ProjectName = pProjectName; } + + const char *GetLoadAddressName() { return m_LoadAddressName.Get(); } + void SetLoadAddressName( const char *pLoadAddressName ) { m_LoadAddressName = pLoadAddressName; } + + const char *GetOutputMirrorPath() { return m_OutputMirrorString.Get(); } + + int ProcessCommandLine(); + + // Returns the mask identifying what platforms whould be built + bool IsPlatformDefined( const char *pName ); + const char *GetTargetPlatformName(); + + void GetProjectDependencies( CUtlVector<CDependency_Project *> &referencedProjects ); + void SetPhase1Projects( CUtlVector<CDependency_Project *> *pPhase1Projects ) { m_pPhase1Projects = pPhase1Projects; } + + IBaseProjectGenerator *GetProjectGenerator() { return m_pProjectGenerator; } + void SetProjectGenerator( IBaseProjectGenerator *pGenerator ) { m_pProjectGenerator = pGenerator; } + + IBaseSolutionGenerator *GetSolutionGenerator() { return m_pSolutionGenerator; } + + // Conditionals + conditional_t *FindOrCreateConditional( const char *pName, bool bCreate, conditionalType_e type ); + void ResolveMacrosInConditional( char const *pString, char *pOutBuff, int outBuffSize ); + bool ResolveConditionalSymbol( const char *pSymbol ); + bool EvaluateConditionalExpression( const char *pExpression ); + bool ConditionHasDefinedType( const char* pCondition, conditionalType_e type ); + void SetConditional( const char *pName, bool bSet = true ); + + // Macros + macro_t *FindOrCreateMacro( const char *pName, bool bCreate, const char *pValue ); + void ResolveMacrosInString( char const *pString, char *pOutBuff, int outBuffSize ); + int GetMacrosMarkedForCompilerDefines( CUtlVector< macro_t* > ¯oDefines ); + void RemoveScriptCreatedMacros(); + const char *GetMacroValue( const char *pName ); + void SetMacro( const char *pName, const char *pValue, bool bSetupDefineInProjectFile ); + + // Iterates all the projects in the specified list, checks their conditionals, and calls pIterator->VisitProject for + // each one that passes the conditional tests. + // + // If bForce is false, then it does a CRC check before visiting any project to see if the target project file is + // already up-to-date with its .vpc file. + void IterateTargetProjects( CUtlVector<projectIndex_t> &projectList, IProjectIterator *pIterator ); + + bool ParseProjectScript( const char *pScriptName, int depth, bool bQuiet, bool bWriteCRCCheckFile ); + + void AddScriptToCRCCheck( const char *pScriptName, CRC32_t crc ); + + const char *KeywordToName( configKeyword_e keyword ); + configKeyword_e NameToKeyword( const char *pKeywordName ); + + int GetProjectsInGroup( CUtlVector< projectIndex_t > &projectList, const char *pGroupHame ); + +private: + void SpewUsage( void ); + + bool LoadPerforceInterface(); + void UnloadPerforceInterface(); + + void InProcessCRCCheck(); + void CheckForInstalledXDK(); + + void DetermineSourcePath(); + void SetDefaultSourcePath(); + + void SetupGenerators(); + void SetupDefaultConditionals(); + void SetMacrosAndConditionals(); + void ResolveMacrosInStringInternal( char const *pString, char *pOutBuff, int outBuffSize, bool bStringIsConditional ); + + void HandleSingleCommandLineArg( const char *pArg ); + void ParseBuildOptions( int argc, char *argv[] ); + + bool CheckBinPath( char *pOutBinPath, int outBinPathSize ); + bool RestartFromCorrectLocation( bool *pIsChild ); + + void GenerateOptionsCRCString(); + void CreateOutputFilename( project_t *pProject, const char *pchPlatform, const char *pchPhase, const char *pGameName, const char *pchExtension ); + void FindProjectFromVCPROJ( const char *pScriptNameVCProj ); + const char *BuildTempGroupScript( const char *pScriptName ); + + bool HandleP4SLN( IBaseSolutionGenerator *pSolutionGenerator ); + void HandleMKSLN( IBaseSolutionGenerator *pSolutionGenerator ); + + void GenerateBuildSet( CProjectDependencyGraph &dependencyGraph ); + bool BuildTargetProjects(); + bool BuildTargetProject( IProjectIterator *pIterator, projectIndex_t projectIndex, script_t *pProjectScript, const char *pGameName ); + + bool m_bVerbose; + bool m_bQuiet; + bool m_bUsageOnly; + bool m_bHelp; + bool m_bSpewPlatforms; + bool m_bSpewGames; + bool m_bSpewGroups; + bool m_bSpewProjects; + bool m_bIgnoreRedundancyWarning; + bool m_bSpewProperties; + bool m_bTestMode; + bool m_bForceGenerate; + bool m_bNoPosixPCH; + bool m_bForceIterate; + bool m_bEnableVpcGameMacro; + bool m_bCheckFiles; + bool m_bDecorateProject; + bool m_bShowDeps; + bool m_bP4AutoAdd; + bool m_bP4SlnCheckEverything; + bool m_bDedicatedBuild; + bool m_bAppendSrvToDedicated; // concat "_srv" to dedicated server .so's. + bool m_bUseValveBinDir; // On Linux, use gcc toolchain from /valve/bin/ + bool m_bAnyProjectQualified; + EVSVersion m_eVSVersion; + bool m_bUseVS2010FileFormat; + bool m_bUseUnity; + bool m_bShowCaseIssues; + bool m_bVerboseMakefile; + bool m_bP4SCC; // VPC_SCC_INTEGRATION define, or "/srcctl" cmd line option, or env var VPC_SRCCTL=1 + bool m_b32BitTools; // Normally we prefer the 64-bit toolchain when building a 64-bit target. This turns that off. + + // How many of the files listed in the VPC files are missing? + int m_FilesMissing; + + int m_nArgc; + char **m_ppArgv; + + CColorizedLoggingListener m_LoggingListener; + + CSysModule *m_pP4Module; + CSysModule *m_pFilesystemModule; + + CScript m_Script; + + // Path where vpc was started from + CUtlString m_StartDirectory; + + // Root path to the sources (i.e. the directory where the vpc_scripts directory can be found in). + CUtlString m_SourcePath; + + // path to the project being processed (i.e. the directory where this project's .vpc can be found). + CUtlString m_ProjectPath; + + // strings derived from command-line commands which is checked alongside project CRCs: + CUtlString m_SupplementalCRCString; + CUtlString m_ExtraOptionsCRCString; + + CUtlString m_MKSolutionFilename; + + CUtlString m_SolutionItemsFilename; // For /slnitems + + CUtlString m_P4SolutionFilename; // For /p4sln + CUtlVector< int > m_iP4Changelists; + + CUtlString m_OutputFilename; + CUtlString m_ProjectName; + CUtlString m_LoadAddressName; + + CUtlString m_OutputMirrorString; + + CUtlString m_TempGroupScriptFilename; + + CUtlString m_strDecorate; + + // This abstracts the differences between different output methods. + IBaseProjectGenerator *m_pProjectGenerator; + IBaseSolutionGenerator *m_pSolutionGenerator; + + CUtlVector< CUtlString > m_BuildCommands; + + CUtlVector<CDependency_Project *> *m_pPhase1Projects; + +public: + CUtlVector< conditional_t > m_Conditionals; + CUtlVector< macro_t > m_Macros; + + CUtlVector< scriptList_t > m_ScriptList; + + CUtlVector< project_t > m_Projects; + CUtlVector< projectIndex_t > m_TargetProjects; + + CProjectDependencyGraph m_dependencyGraph; + + CUtlVector< group_t > m_Groups; + CUtlVector< groupTag_t > m_GroupTags; + + CUtlVector< CUtlString > m_P4GroupRestrictions; + + CUtlVector< CUtlString > m_SchemaFiles; + + CUtlDict< CUtlString, int > m_CustomBuildSteps; + + bool m_bGeneratedProject; + + CUtlDict< bool > m_UnityFilesSeen; + CUtlStack< CUtlString > m_UnityStack; + CUtlString m_sUnityCurrent; + bool m_bInMkSlnPass; +}; + +extern CVPC *g_pVPC; + +extern const char *g_pOption_ImportLibrary; // "$ImportLibrary"; +extern const char *g_pOption_OutputFile; // "$OutputFile"; +extern const char *g_pOption_GameOutputFile; // "$GameOutputFile"; +extern const char *g_pOption_AdditionalIncludeDirectories; // "$AdditionalIncludeDirectories" +extern const char *g_pOption_AdditionalProjectDependencies; // "$AdditionalProjectDependencies" +extern const char *g_pOption_AdditionalOutputFiles; // "$AdditionalOutputFiles" +extern const char *g_pOption_PreprocessorDefinitions; // "$PreprocessorDefinitions" +extern char *g_IncludeSeparators[2]; + +extern void VPC_ParseGroupScript( const char *pScriptName ); + +extern groupTagIndex_t VPC_Group_FindOrCreateGroupTag( const char *pName, bool bCreate ); + +extern void VPC_Keyword_Configuration(); +extern void VPC_Keyword_FileConfiguration(); + + +struct folderConfig_t +{ + CUtlVector<CUtlString> vecConfigurationNames; + CScriptSource scriptSource; + + bool BHasConfig() { return vecConfigurationNames.Count() > 0; } + void Clear() { vecConfigurationNames.RemoveAll(); } +}; + +void VPC_Keyword_FolderConfiguration( folderConfig_t *pFolderConfig ); +void VPC_ApplyFolderConfigurationToFile( const folderConfig_t &folderConfig ); + +extern void VPC_Config_SpewProperties( configKeyword_e keyword ); +extern bool VPC_Config_IgnoreOption( const char *pPropertyName ); + +extern void VPC_FakeKeyword_SchemaFolder( class CBaseProjectDataCollector *pDataCollector ); diff --git a/external/vpc/utils/vpc/vpc.sln b/external/vpc/utils/vpc/vpc.sln new file mode 100644 index 0000000..9e106f5 --- /dev/null +++ b/external/vpc/utils/vpc/vpc.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vpc", "vpc.vcxproj", "{36C5F545-588F-4091-B480-89E03EDBDA93}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {36C5F545-588F-4091-B480-89E03EDBDA93}.Debug|Win32.ActiveCfg = Debug|Win32 + {36C5F545-588F-4091-B480-89E03EDBDA93}.Debug|Win32.Build.0 = Debug|Win32 + {36C5F545-588F-4091-B480-89E03EDBDA93}.Release|Win32.ActiveCfg = Release|Win32 + {36C5F545-588F-4091-B480-89E03EDBDA93}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/external/vpc/utils/vpc/vpc.vcxproj b/external/vpc/utils/vpc/vpc.vcxproj new file mode 100644 index 0000000..be37d59 --- /dev/null +++ b/external/vpc/utils/vpc/vpc.vcxproj @@ -0,0 +1,237 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{36C5F545-588F-4091-B480-89E03EDBDA93}</ProjectGuid> + <RootNamespace>vpc</RootNamespace> + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <CharacterSet>NotSet</CharacterSet> + <PlatformToolset>v140_xp</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>NotSet</CharacterSet> + <PlatformToolset>v140_xp</PlatformToolset> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup /> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\..\public;..\..\public\tier0;..\..\public\tier1;..\..\public\vstdlib;..\..\common\;..\..\common\p4api</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_WIN32;PLATFORM_WINDOWS;COMPILER_MSVC;COMPILER_MSVC32;_USE_32BIT_TIME_T;STATIC_TIER0;NO_MALLOC_OVERRIDE;STATIC_VSTDLIB;STANDALONE_VPC;_MBCS;_CRT_NO_VA_START_VALIDATION;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType> + <CompileAs>CompileAsCpp</CompileAs> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <ExceptionHandling>Async</ExceptionHandling> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;wsock32.lib;Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <IgnoreSpecificDefaultLibraries>libcmt.lib</IgnoreSpecificDefaultLibraries> + <SubSystem>Console</SubSystem> + </Link> + <PostBuildEvent> + <Command>p4 edit ..\..\..\..\devtools\bin\vpc.exe && copy /y $(TargetPath) ..\..\..\..\devtools\bin\vpc.exe +p4 edit ..\..\..\..\devtools\bin\vpc.pdb && copy /y $(TargetDir)\vpc.pdb ..\..\..\..\devtools\bin\vpc.pdb +</Command> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>..\..\public;..\..\public\tier0;..\..\public\tier1;..\..\public\vstdlib;..\..\common\;..\..\common\p4api</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_WIN32;PLATFORM_WINDOWS;COMPILER_MSVC;COMPILER_MSVC32;_USE_32BIT_TIME_T;STATIC_TIER0;NO_MALLOC_OVERRIDE;STATIC_VSTDLIB;STANDALONE_VPC;_MBCS;_CRT_NO_VA_START_VALIDATION;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType> + <CompileAs>CompileAsCpp</CompileAs> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;wsock32.lib;Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <SubSystem>Console</SubSystem> + </Link> + <PostBuildEvent> + <Command>p4 edit ..\..\..\..\devtools\bin\vpc.exe && copy /y $(TargetPath) ..\..\..\..\devtools\bin\vpc.exe +p4 edit ..\..\..\..\devtools\bin\vpc.pdb && copy /y $(TargetDir)\vpc.pdb ..\..\..\..\devtools\bin\vpc.pdb +</Command> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\..\interfaces\interfaces.cpp" /> + <ClCompile Include="..\..\p4lib\p4.cpp" /> + <ClCompile Include="..\..\tier0\assert_dialog.cpp" /> + <ClCompile Include="..\..\tier0\commandline.cpp" /> + <ClCompile Include="..\..\tier0\cpu.cpp" /> + <ClCompile Include="..\..\tier0\cputopology.cpp" /> + <ClCompile Include="..\..\tier0\dbg.cpp" /> + <ClCompile Include="..\..\tier0\fasttimer.cpp" /> + <ClCompile Include="..\..\tier0\logging.cpp" /> + <ClCompile Include="..\..\tier0\mem.cpp" /> + <ClCompile Include="..\..\tier0\memdbg.cpp" /> + <ClCompile Include="..\..\tier0\memstd.cpp" /> + <ClCompile Include="..\..\tier0\memvalidate.cpp" /> + <ClCompile Include="..\..\tier0\mem_helpers.cpp" /> + <ClCompile Include="..\..\tier0\minidump.cpp" /> + <ClCompile Include="..\..\tier0\pch_tier0.cpp" /> + <ClCompile Include="..\..\tier0\platform.cpp" /> + <ClCompile Include="..\..\tier0\pme.cpp" /> + <ClCompile Include="..\..\tier0\pmelib.cpp" /> + <ClCompile Include="..\..\tier0\stacktools.cpp" /> + <ClCompile Include="..\..\tier0\threadtools.cpp" /> + <ClCompile Include="..\..\tier0\tier0_strtools.cpp" /> + <ClCompile Include="..\..\tier0\valobject.cpp" /> + <ClCompile Include="..\..\tier0\vprof.cpp" /> + <ClCompile Include="..\..\tier0\win32consoleio.cpp" /> + <ClCompile Include="..\..\tier1\characterset.cpp" /> + <ClCompile Include="..\..\tier1\checksum_crc.cpp" /> + <ClCompile Include="..\..\tier1\checksum_md5.cpp" /> + <ClCompile Include="..\..\tier1\convar.cpp" /> + <ClCompile Include="..\..\tier1\exprevaluator.cpp" /> + <ClCompile Include="..\..\tier1\generichash.cpp" /> + <ClCompile Include="..\..\tier1\interface.cpp" /> + <ClCompile Include="..\..\tier1\keyvalues.cpp" /> + <ClCompile Include="..\..\tier1\mempool.cpp" /> + <ClCompile Include="..\..\tier1\memstack.cpp" /> + <ClCompile Include="..\..\tier1\splitstring.cpp" /> + <ClCompile Include="..\..\tier1\stringpool.cpp" /> + <ClCompile Include="..\..\tier1\strtools.cpp" /> + <ClCompile Include="..\..\tier1\tier1.cpp" /> + <ClCompile Include="..\..\tier1\utlbuffer.cpp" /> + <ClCompile Include="..\..\tier1\utlstring.cpp" /> + <ClCompile Include="..\..\tier1\utlsymbol.cpp" /> + <ClCompile Include="..\..\vstdlib\cvar.cpp" /> + <ClCompile Include="..\..\vstdlib\keyvaluessystem.cpp" /> + <ClCompile Include="..\..\vstdlib\random.cpp" /> + <ClCompile Include="..\..\vstdlib\vstrtools.cpp" /> + <ClCompile Include="..\vpccrccheck\crccheck_shared.cpp" /> + <ClCompile Include="baseprojectdatacollector.cpp" /> + <ClCompile Include="conditionals.cpp" /> + <ClCompile Include="configuration.cpp" /> + <ClCompile Include="dependencies.cpp" /> + <ClCompile Include="exprsimplifier.cpp" /> + <ClCompile Include="generatordefinition.cpp" /> + <ClCompile Include="groupscript.cpp" /> + <ClCompile Include="macros.cpp" /> + <ClCompile Include="main.cpp" /> + <ClCompile Include="p4sln.cpp" /> + <ClCompile Include="projectgenerator_codelite.cpp" /> + <ClCompile Include="projectgenerator_makefile.cpp" /> + <ClCompile Include="projectgenerator_ps3.cpp" /> + <ClCompile Include="projectgenerator_vcproj.cpp" /> + <ClCompile Include="projectgenerator_win32.cpp" /> + <ClCompile Include="projectgenerator_win32_2010.cpp" /> + <ClCompile Include="projectgenerator_xbox360.cpp" /> + <ClCompile Include="projectgenerator_xbox360_2010.cpp" /> + <ClCompile Include="projectscript.cpp" /> + <ClCompile Include="scriptsource.cpp" /> + <ClCompile Include="solutiongenerator_codelite.cpp" /> + <ClCompile Include="solutiongenerator_makefile.cpp" /> + <ClCompile Include="solutiongenerator_win32.cpp" /> + <ClCompile Include="solutiongenerator_xcode.cpp" /> + <ClCompile Include="sys_utils.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\..\tier0\cputopology.h" /> + <ClInclude Include="..\..\tier0\memstd.h" /> + <ClInclude Include="..\..\tier0\mem_helpers.h" /> + <ClInclude Include="..\..\tier0\mem_impl_type.h" /> + <ClInclude Include="..\..\tier0\pch_tier0.h" /> + <ClInclude Include="..\..\tier0\resource.h" /> + <ClInclude Include="..\..\tier0\tier0_strtools.h" /> + <ClInclude Include="..\..\vstdlib\concommandhash.h" /> + <ClInclude Include="..\vpccrccheck\crccheck_shared.h" /> + <ClInclude Include="baseprojectdatacollector.h" /> + <ClInclude Include="dependencies.h" /> + <ClInclude Include="generatordefinition.h" /> + <ClInclude Include="ibaseprojectgenerator.h" /> + <ClInclude Include="ibasesolutiongenerator.h" /> + <ClInclude Include="p4sln.h" /> + <ClInclude Include="projectgenerator_codelite.h" /> + <ClInclude Include="projectgenerator_ps3.h" /> + <ClInclude Include="projectgenerator_vcproj.h" /> + <ClInclude Include="projectgenerator_win32.h" /> + <ClInclude Include="projectgenerator_win32_2010.h" /> + <ClInclude Include="projectgenerator_xbox360.h" /> + <ClInclude Include="projectgenerator_xbox360_2010.h" /> + <ClInclude Include="projectgenerator_xcode.h" /> + <ClInclude Include="scriptsource.h" /> + <ClInclude Include="sys_utils.h" /> + <ClInclude Include="vpc.h" /> + </ItemGroup> + <ItemGroup> + <None Include="..\..\vpc_scripts\definitions\ps3.def" /> + <None Include="..\..\vpc_scripts\definitions\win32_2005.def" /> + <None Include="..\..\vpc_scripts\definitions\win32_2010.def" /> + <None Include="..\..\vpc_scripts\definitions\xbox360.def" /> + <None Include="..\..\vpc_scripts\definitions\xbox360_2010.def" /> + <None Include="Makefile" /> + <None Include="projectgenerator_ps3.inc" /> + <None Include="projectgenerator_win32.inc" /> + <None Include="projectgenerator_win32_2010.inc" /> + <None Include="projectgenerator_xbox360.inc" /> + <None Include="projectgenerator_xbox360_2010.inc" /> + <None Include="vpc.opensdf" /> + <None Include="vpc.vpc" /> + </ItemGroup> + <ItemGroup> + <Library Include="..\..\lib\common\debug\libclient.lib"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + </Library> + <Library Include="..\..\lib\common\debug\libp4sslstub.lib"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + </Library> + <Library Include="..\..\lib\common\debug\librpc.lib"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + </Library> + <Library Include="..\..\lib\common\debug\libsupp.lib"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + </Library> + <Library Include="..\..\lib\common\libclient.lib"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> + </Library> + <Library Include="..\..\lib\common\libp4sslstub.lib"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> + </Library> + <Library Include="..\..\lib\common\librpc.lib"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> + </Library> + <Library Include="..\..\lib\common\libsupp.lib"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> + </Library> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/external/vpc/utils/vpc/vpc.vcxproj.filters b/external/vpc/utils/vpc/vpc.vcxproj.filters new file mode 100644 index 0000000..be39a00 --- /dev/null +++ b/external/vpc/utils/vpc/vpc.vcxproj.filters @@ -0,0 +1,393 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="VPC"> + <UniqueIdentifier>{46bac1ee-3374-43a2-9761-f79ee2691007}</UniqueIdentifier> + </Filter> + <Filter Include="VPC\Header Files"> + <UniqueIdentifier>{38599379-561b-43c5-bdc9-e84eee3ab186}</UniqueIdentifier> + </Filter> + <Filter Include="VPC\Source Files"> + <UniqueIdentifier>{13ae58f1-21cb-4159-82ae-3d2dbd5238a7}</UniqueIdentifier> + </Filter> + <Filter Include="Dependencies"> + <UniqueIdentifier>{e86543a4-b232-42c1-91e4-ddd9dd9c36a8}</UniqueIdentifier> + </Filter> + <Filter Include="Dependencies\Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Dependencies\Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="VPC\definitions"> + <UniqueIdentifier>{f5d738f6-132d-42e7-9f03-05388b11b408}</UniqueIdentifier> + </Filter> + <Filter Include="VPC\VPCCRCCheck"> + <UniqueIdentifier>{90afaed2-cb09-4747-bb13-2186c417c0f2}</UniqueIdentifier> + </Filter> + <Filter Include="P4 Libs"> + <UniqueIdentifier>{7bc720f7-b058-4998-9fa5-03df7999beef}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\..\interfaces\interfaces.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\assert_dialog.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\commandline.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\cpu.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\dbg.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\fasttimer.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\logging.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\mem.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\mem_helpers.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\memdbg.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\memstd.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\memvalidate.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\minidump.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\pch_tier0.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\threadtools.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\tier0_strtools.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\valobject.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\vprof.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\win32consoleio.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\characterset.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\checksum_crc.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\checksum_md5.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\convar.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\exprevaluator.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\generichash.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\interface.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\keyvalues.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\mempool.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\memstack.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\splitstring.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\stringpool.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\strtools.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\tier1.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\utlbuffer.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\utlstring.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier1\utlsymbol.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\vstdlib\cvar.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\vstdlib\keyvaluessystem.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\vstdlib\random.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\vstdlib\vstrtools.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\platform.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\cputopology.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\stacktools.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\pme.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\tier0\pmelib.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + <ClCompile Include="baseprojectdatacollector.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="conditionals.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="configuration.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="dependencies.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="exprsimplifier.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="generatordefinition.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="groupscript.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="macros.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="main.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="p4sln.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="projectgenerator_makefile.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="projectgenerator_ps3.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="projectgenerator_vcproj.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="projectgenerator_win32.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="projectgenerator_win32_2010.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="projectgenerator_xbox360.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="projectgenerator_xbox360_2010.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="projectscript.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="scriptsource.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="solutiongenerator_makefile.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="solutiongenerator_win32.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="solutiongenerator_xcode.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="sys_utils.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\vpccrccheck\crccheck_shared.cpp"> + <Filter>VPC\VPCCRCCheck</Filter> + </ClCompile> + <ClCompile Include="projectgenerator_codelite.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="solutiongenerator_codelite.cpp"> + <Filter>VPC\Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\p4lib\p4.cpp"> + <Filter>Dependencies\Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\..\tier0\mem_helpers.h"> + <Filter>Dependencies\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\tier0\mem_impl_type.h"> + <Filter>Dependencies\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\tier0\memstd.h"> + <Filter>Dependencies\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\tier0\pch_tier0.h"> + <Filter>Dependencies\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\tier0\resource.h"> + <Filter>Dependencies\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\tier0\tier0_strtools.h"> + <Filter>Dependencies\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\vstdlib\concommandhash.h"> + <Filter>Dependencies\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\tier0\cputopology.h"> + <Filter>Dependencies\Header Files</Filter> + </ClInclude> + <ClInclude Include="baseprojectdatacollector.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + <ClInclude Include="dependencies.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + <ClInclude Include="generatordefinition.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + <ClInclude Include="ibaseprojectgenerator.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + <ClInclude Include="ibasesolutiongenerator.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + <ClInclude Include="p4sln.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + <ClInclude Include="projectgenerator_ps3.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + <ClInclude Include="projectgenerator_vcproj.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + <ClInclude Include="projectgenerator_win32.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + <ClInclude Include="projectgenerator_win32_2010.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + <ClInclude Include="projectgenerator_xbox360.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + <ClInclude Include="projectgenerator_xbox360_2010.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + <ClInclude Include="projectgenerator_xcode.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + <ClInclude Include="scriptsource.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + <ClInclude Include="sys_utils.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + <ClInclude Include="vpc.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + <ClInclude Include="..\vpccrccheck\crccheck_shared.h"> + <Filter>VPC\VPCCRCCheck</Filter> + </ClInclude> + <ClInclude Include="projectgenerator_codelite.h"> + <Filter>VPC\Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <None Include="Makefile" /> + <None Include="vpc.opensdf" /> + <None Include="vpc.vpc" /> + <None Include="projectgenerator_ps3.inc"> + <Filter>VPC\Header Files</Filter> + </None> + <None Include="projectgenerator_win32.inc"> + <Filter>VPC\Header Files</Filter> + </None> + <None Include="projectgenerator_win32_2010.inc"> + <Filter>VPC\Header Files</Filter> + </None> + <None Include="projectgenerator_xbox360.inc"> + <Filter>VPC\Header Files</Filter> + </None> + <None Include="projectgenerator_xbox360_2010.inc"> + <Filter>VPC\Header Files</Filter> + </None> + <None Include="..\..\vpc_scripts\definitions\ps3.def"> + <Filter>VPC\definitions</Filter> + </None> + <None Include="..\..\vpc_scripts\definitions\win32_2005.def"> + <Filter>VPC\definitions</Filter> + </None> + <None Include="..\..\vpc_scripts\definitions\win32_2010.def"> + <Filter>VPC\definitions</Filter> + </None> + <None Include="..\..\vpc_scripts\definitions\xbox360.def"> + <Filter>VPC\definitions</Filter> + </None> + <None Include="..\..\vpc_scripts\definitions\xbox360_2010.def"> + <Filter>VPC\definitions</Filter> + </None> + </ItemGroup> + <ItemGroup> + <Library Include="..\..\lib\common\libsupp.lib"> + <Filter>P4 Libs</Filter> + </Library> + <Library Include="..\..\lib\common\libclient.lib"> + <Filter>P4 Libs</Filter> + </Library> + <Library Include="..\..\lib\common\librpc.lib"> + <Filter>P4 Libs</Filter> + </Library> + <Library Include="..\..\lib\common\libp4sslstub.lib"> + <Filter>P4 Libs</Filter> + </Library> + <Library Include="..\..\lib\common\debug\libclient.lib"> + <Filter>P4 Libs</Filter> + </Library> + <Library Include="..\..\lib\common\debug\libp4sslstub.lib"> + <Filter>P4 Libs</Filter> + </Library> + <Library Include="..\..\lib\common\debug\librpc.lib"> + <Filter>P4 Libs</Filter> + </Library> + <Library Include="..\..\lib\common\debug\libsupp.lib"> + <Filter>P4 Libs</Filter> + </Library> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/external/vpc/utils/vpc/vpc.xcodeproj/project.pbxproj b/external/vpc/utils/vpc/vpc.xcodeproj/project.pbxproj new file mode 100644 index 0000000..e468cfd --- /dev/null +++ b/external/vpc/utils/vpc/vpc.xcodeproj/project.pbxproj @@ -0,0 +1,529 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 976DE7B71239412500E8D60A /* crccheck_shared.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 976DE7B51239412500E8D60A /* crccheck_shared.cpp */; }; + 976DE7BA1239423E00E8D60A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 976DE7B91239423E00E8D60A /* Foundation.framework */; }; + 976DE7BC1239424500E8D60A /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 976DE7BB1239424500E8D60A /* CoreServices.framework */; }; + 976DE7BE1239424E00E8D60A /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 976DE7BD1239424E00E8D60A /* libiconv.dylib */; }; + 977F706212393A2A008D8433 /* baseprojectdatacollector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F705012393A2A008D8433 /* baseprojectdatacollector.cpp */; }; + 977F706312393A2A008D8433 /* configuration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F705212393A2A008D8433 /* configuration.cpp */; }; + 977F706412393A2A008D8433 /* dependencies.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F705312393A2A008D8433 /* dependencies.cpp */; }; + 977F706512393A2A008D8433 /* ExprSimplifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F705512393A2A008D8433 /* ExprSimplifier.cpp */; }; + 977F706612393A2A008D8433 /* GroupScript.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F705612393A2A008D8433 /* GroupScript.cpp */; }; + 977F706712393A2A008D8433 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F705912393A2A008D8433 /* main.cpp */; }; + 977F706812393A2A008D8433 /* projectgenerator_makefile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F705A12393A2A008D8433 /* projectgenerator_makefile.cpp */; }; + 977F706912393A2A008D8433 /* projectgenerator_xcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F705B12393A2A008D8433 /* projectgenerator_xcode.cpp */; }; + 977F706A12393A2A008D8433 /* ProjectScript.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F705D12393A2A008D8433 /* ProjectScript.cpp */; }; + 977F706B12393A2A008D8433 /* solutiongenerator_makefile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F705E12393A2A008D8433 /* solutiongenerator_makefile.cpp */; }; + 977F706C12393A2A008D8433 /* solutiongenerator_xcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F705F12393A2A008D8433 /* solutiongenerator_xcode.cpp */; }; + 977F706D12393A2A008D8433 /* sys_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F706012393A2A008D8433 /* sys_utils.cpp */; }; + 977F708912393ADD008D8433 /* assert_dialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F707212393ADD008D8433 /* assert_dialog.cpp */; }; + 977F708A12393ADD008D8433 /* cpu_posix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F707312393ADD008D8433 /* cpu_posix.cpp */; }; + 977F708B12393ADD008D8433 /* cpu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F707412393ADD008D8433 /* cpu.cpp */; }; + 977F708C12393ADD008D8433 /* dbg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F707512393ADD008D8433 /* dbg.cpp */; }; + 977F708D12393ADD008D8433 /* fasttimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F707612393ADD008D8433 /* fasttimer.cpp */; }; + 977F708E12393ADD008D8433 /* mem_helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F707712393ADD008D8433 /* mem_helpers.cpp */; }; + 977F708F12393ADD008D8433 /* memblockhdr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F707812393ADD008D8433 /* memblockhdr.cpp */; }; + 977F709012393ADD008D8433 /* memdbg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F707912393ADD008D8433 /* memdbg.cpp */; }; + 977F709112393ADD008D8433 /* memstd.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F707A12393ADD008D8433 /* memstd.cpp */; }; + 977F709212393ADD008D8433 /* memvalidate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F707B12393ADD008D8433 /* memvalidate.cpp */; }; + 977F709312393ADD008D8433 /* minidump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F707C12393ADD008D8433 /* minidump.cpp */; }; + 977F709412393ADD008D8433 /* pch_tier0.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F707D12393ADD008D8433 /* pch_tier0.cpp */; }; + 977F709512393ADD008D8433 /* platform_posix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F707E12393ADD008D8433 /* platform_posix.cpp */; }; + 977F709612393ADD008D8433 /* pme_posix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F707F12393ADD008D8433 /* pme_posix.cpp */; }; + 977F709712393ADD008D8433 /* pmelib.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F708012393ADD008D8433 /* pmelib.cpp */; }; + 977F709812393ADD008D8433 /* testthread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F708112393ADD008D8433 /* testthread.cpp */; }; + 977F709912393ADD008D8433 /* thread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F708212393ADD008D8433 /* thread.cpp */; }; + 977F709A12393ADD008D8433 /* threadtools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F708312393ADD008D8433 /* threadtools.cpp */; }; + 977F709B12393ADD008D8433 /* tier0.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F708412393ADD008D8433 /* tier0.cpp */; }; + 977F709C12393ADD008D8433 /* validator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F708512393ADD008D8433 /* validator.cpp */; }; + 977F709D12393ADD008D8433 /* valobject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F708612393ADD008D8433 /* valobject.cpp */; }; + 977F709E12393ADD008D8433 /* vcrmode_posix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F708712393ADD008D8433 /* vcrmode_posix.cpp */; }; + 977F709F12393ADD008D8433 /* vprof.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F708812393ADD008D8433 /* vprof.cpp */; }; + 977F70AB12393B10008D8433 /* checksum_crc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70A012393B10008D8433 /* checksum_crc.cpp */; }; + 977F70AC12393B10008D8433 /* checksum_md5.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70A112393B10008D8433 /* checksum_md5.cpp */; }; + 977F70AD12393B10008D8433 /* convar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70A212393B10008D8433 /* convar.cpp */; }; + 977F70AE12393B10008D8433 /* generichash.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70A312393B10008D8433 /* generichash.cpp */; }; + 977F70AF12393B10008D8433 /* interface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70A412393B10008D8433 /* interface.cpp */; }; + 977F70B012393B10008D8433 /* KeyValues.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70A512393B10008D8433 /* KeyValues.cpp */; }; + 977F70B112393B10008D8433 /* mempool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70A612393B10008D8433 /* mempool.cpp */; }; + 977F70B212393B10008D8433 /* memstack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70A712393B10008D8433 /* memstack.cpp */; }; + 977F70B312393B10008D8433 /* stringpool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70A812393B10008D8433 /* stringpool.cpp */; }; + 977F70B412393B10008D8433 /* utlbuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70A912393B10008D8433 /* utlbuffer.cpp */; }; + 977F70B512393B10008D8433 /* utlsymbol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70AA12393B10008D8433 /* utlsymbol.cpp */; }; + 977F70BF12393B49008D8433 /* commandline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70B612393B49008D8433 /* commandline.cpp */; }; + 977F70C012393B49008D8433 /* cvar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70B712393B49008D8433 /* cvar.cpp */; }; + 977F70C112393B49008D8433 /* keyvaluessystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70B812393B49008D8433 /* keyvaluessystem.cpp */; }; + 977F70C212393B49008D8433 /* osversion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70B912393B49008D8433 /* osversion.cpp */; }; + 977F70C312393B49008D8433 /* qsort_s.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70BA12393B49008D8433 /* qsort_s.cpp */; }; + 977F70C412393B49008D8433 /* random.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70BB12393B49008D8433 /* random.cpp */; }; + 977F70C512393B49008D8433 /* splitstring.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70BC12393B49008D8433 /* splitstring.cpp */; }; + 977F70C612393B49008D8433 /* stringnormalize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70BD12393B49008D8433 /* stringnormalize.cpp */; }; + 977F70C712393B49008D8433 /* strtools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 977F70BE12393B49008D8433 /* strtools.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 977F703E12393174008D8433 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 976DE7B51239412500E8D60A /* crccheck_shared.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = crccheck_shared.cpp; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpccrccheck/crccheck_shared.cpp; sourceTree = "<absolute>"; }; + 976DE7B61239412500E8D60A /* crccheck_shared.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crccheck_shared.h; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpccrccheck/crccheck_shared.h; sourceTree = "<absolute>"; }; + 976DE7B91239423E00E8D60A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Xcode4/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 976DE7BB1239424500E8D60A /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = Xcode4/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; + 976DE7BD1239424E00E8D60A /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = Xcode4/SDKs/MacOSX10.5.sdk/usr/lib/libiconv.dylib; sourceTree = SDKROOT; }; + 977F704012393174008D8433 /* vpc_osx */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = vpc_osx; sourceTree = BUILT_PRODUCTS_DIR; }; + 977F705012393A2A008D8433 /* baseprojectdatacollector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = baseprojectdatacollector.cpp; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/baseprojectdatacollector.cpp; sourceTree = "<absolute>"; }; + 977F705112393A2A008D8433 /* baseprojectdatacollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = baseprojectdatacollector.h; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/baseprojectdatacollector.h; sourceTree = "<absolute>"; }; + 977F705212393A2A008D8433 /* configuration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = configuration.cpp; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/configuration.cpp; sourceTree = "<absolute>"; }; + 977F705312393A2A008D8433 /* dependencies.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dependencies.cpp; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/dependencies.cpp; sourceTree = "<absolute>"; }; + 977F705412393A2A008D8433 /* dependencies.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dependencies.h; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/dependencies.h; sourceTree = "<absolute>"; }; + 977F705512393A2A008D8433 /* ExprSimplifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExprSimplifier.cpp; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/ExprSimplifier.cpp; sourceTree = "<absolute>"; }; + 977F705612393A2A008D8433 /* GroupScript.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GroupScript.cpp; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/GroupScript.cpp; sourceTree = "<absolute>"; }; + 977F705712393A2A008D8433 /* ibaseprojectgenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ibaseprojectgenerator.h; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/ibaseprojectgenerator.h; sourceTree = "<absolute>"; }; + 977F705812393A2A008D8433 /* ibasesolutiongenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ibasesolutiongenerator.h; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/ibasesolutiongenerator.h; sourceTree = "<absolute>"; }; + 977F705912393A2A008D8433 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/main.cpp; sourceTree = "<absolute>"; }; + 977F705A12393A2A008D8433 /* projectgenerator_makefile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = projectgenerator_makefile.cpp; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/projectgenerator_makefile.cpp; sourceTree = "<absolute>"; }; + 977F705B12393A2A008D8433 /* projectgenerator_xcode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = projectgenerator_xcode.cpp; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/projectgenerator_xcode.cpp; sourceTree = "<absolute>"; }; + 977F705C12393A2A008D8433 /* projectgenerator_xcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = projectgenerator_xcode.h; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/projectgenerator_xcode.h; sourceTree = "<absolute>"; }; + 977F705D12393A2A008D8433 /* ProjectScript.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProjectScript.cpp; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/ProjectScript.cpp; sourceTree = "<absolute>"; }; + 977F705E12393A2A008D8433 /* solutiongenerator_makefile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = solutiongenerator_makefile.cpp; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/solutiongenerator_makefile.cpp; sourceTree = "<absolute>"; }; + 977F705F12393A2A008D8433 /* solutiongenerator_xcode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = solutiongenerator_xcode.cpp; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/solutiongenerator_xcode.cpp; sourceTree = "<absolute>"; }; + 977F706012393A2A008D8433 /* sys_utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = sys_utils.cpp; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/sys_utils.cpp; sourceTree = "<absolute>"; }; + 977F706112393A2A008D8433 /* sys_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sys_utils.h; path = /Users/dberger/P4Clients/steam3_main/src/utils/vpc/sys_utils.h; sourceTree = "<absolute>"; }; + 977F707212393ADD008D8433 /* assert_dialog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = assert_dialog.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/assert_dialog.cpp; sourceTree = "<absolute>"; }; + 977F707312393ADD008D8433 /* cpu_posix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cpu_posix.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/cpu_posix.cpp; sourceTree = "<absolute>"; }; + 977F707412393ADD008D8433 /* cpu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cpu.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/cpu.cpp; sourceTree = "<absolute>"; }; + 977F707512393ADD008D8433 /* dbg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dbg.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/dbg.cpp; sourceTree = "<absolute>"; }; + 977F707612393ADD008D8433 /* fasttimer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = fasttimer.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/fasttimer.cpp; sourceTree = "<absolute>"; }; + 977F707712393ADD008D8433 /* mem_helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mem_helpers.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/mem_helpers.cpp; sourceTree = "<absolute>"; }; + 977F707812393ADD008D8433 /* memblockhdr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = memblockhdr.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/memblockhdr.cpp; sourceTree = "<absolute>"; }; + 977F707912393ADD008D8433 /* memdbg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = memdbg.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/memdbg.cpp; sourceTree = "<absolute>"; }; + 977F707A12393ADD008D8433 /* memstd.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = memstd.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/memstd.cpp; sourceTree = "<absolute>"; }; + 977F707B12393ADD008D8433 /* memvalidate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = memvalidate.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/memvalidate.cpp; sourceTree = "<absolute>"; }; + 977F707C12393ADD008D8433 /* minidump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = minidump.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/minidump.cpp; sourceTree = "<absolute>"; }; + 977F707D12393ADD008D8433 /* pch_tier0.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = pch_tier0.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/pch_tier0.cpp; sourceTree = "<absolute>"; }; + 977F707E12393ADD008D8433 /* platform_posix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = platform_posix.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/platform_posix.cpp; sourceTree = "<absolute>"; }; + 977F707F12393ADD008D8433 /* pme_posix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = pme_posix.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/pme_posix.cpp; sourceTree = "<absolute>"; }; + 977F708012393ADD008D8433 /* pmelib.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = pmelib.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/pmelib.cpp; sourceTree = "<absolute>"; }; + 977F708112393ADD008D8433 /* testthread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = testthread.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/testthread.cpp; sourceTree = "<absolute>"; }; + 977F708212393ADD008D8433 /* thread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = thread.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/thread.cpp; sourceTree = "<absolute>"; }; + 977F708312393ADD008D8433 /* threadtools.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = threadtools.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/threadtools.cpp; sourceTree = "<absolute>"; }; + 977F708412393ADD008D8433 /* tier0.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = tier0.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/tier0.cpp; sourceTree = "<absolute>"; }; + 977F708512393ADD008D8433 /* validator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = validator.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/validator.cpp; sourceTree = "<absolute>"; }; + 977F708612393ADD008D8433 /* valobject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = valobject.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/valobject.cpp; sourceTree = "<absolute>"; }; + 977F708712393ADD008D8433 /* vcrmode_posix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = vcrmode_posix.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/vcrmode_posix.cpp; sourceTree = "<absolute>"; }; + 977F708812393ADD008D8433 /* vprof.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = vprof.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier0/vprof.cpp; sourceTree = "<absolute>"; }; + 977F70A012393B10008D8433 /* checksum_crc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = checksum_crc.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier1/checksum_crc.cpp; sourceTree = "<absolute>"; }; + 977F70A112393B10008D8433 /* checksum_md5.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = checksum_md5.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier1/checksum_md5.cpp; sourceTree = "<absolute>"; }; + 977F70A212393B10008D8433 /* convar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = convar.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier1/convar.cpp; sourceTree = "<absolute>"; }; + 977F70A312393B10008D8433 /* generichash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = generichash.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier1/generichash.cpp; sourceTree = "<absolute>"; }; + 977F70A412393B10008D8433 /* interface.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = interface.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier1/interface.cpp; sourceTree = "<absolute>"; }; + 977F70A512393B10008D8433 /* KeyValues.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = KeyValues.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier1/KeyValues.cpp; sourceTree = "<absolute>"; }; + 977F70A612393B10008D8433 /* mempool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mempool.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier1/mempool.cpp; sourceTree = "<absolute>"; }; + 977F70A712393B10008D8433 /* memstack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = memstack.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier1/memstack.cpp; sourceTree = "<absolute>"; }; + 977F70A812393B10008D8433 /* stringpool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stringpool.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier1/stringpool.cpp; sourceTree = "<absolute>"; }; + 977F70A912393B10008D8433 /* utlbuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = utlbuffer.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier1/utlbuffer.cpp; sourceTree = "<absolute>"; }; + 977F70AA12393B10008D8433 /* utlsymbol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = utlsymbol.cpp; path = /Users/dberger/P4Clients/steam3_main/src/tier1/utlsymbol.cpp; sourceTree = "<absolute>"; }; + 977F70B612393B49008D8433 /* commandline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = commandline.cpp; path = /Users/dberger/P4Clients/steam3_main/src/vstdlib/commandline.cpp; sourceTree = "<absolute>"; }; + 977F70B712393B49008D8433 /* cvar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cvar.cpp; path = /Users/dberger/P4Clients/steam3_main/src/vstdlib/cvar.cpp; sourceTree = "<absolute>"; }; + 977F70B812393B49008D8433 /* keyvaluessystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = keyvaluessystem.cpp; path = /Users/dberger/P4Clients/steam3_main/src/vstdlib/keyvaluessystem.cpp; sourceTree = "<absolute>"; }; + 977F70B912393B49008D8433 /* osversion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = osversion.cpp; path = /Users/dberger/P4Clients/steam3_main/src/vstdlib/osversion.cpp; sourceTree = "<absolute>"; }; + 977F70BA12393B49008D8433 /* qsort_s.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = qsort_s.cpp; path = /Users/dberger/P4Clients/steam3_main/src/vstdlib/qsort_s.cpp; sourceTree = "<absolute>"; }; + 977F70BB12393B49008D8433 /* random.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = random.cpp; path = /Users/dberger/P4Clients/steam3_main/src/vstdlib/random.cpp; sourceTree = "<absolute>"; }; + 977F70BC12393B49008D8433 /* splitstring.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = splitstring.cpp; path = /Users/dberger/P4Clients/steam3_main/src/vstdlib/splitstring.cpp; sourceTree = "<absolute>"; }; + 977F70BD12393B49008D8433 /* stringnormalize.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stringnormalize.cpp; path = /Users/dberger/P4Clients/steam3_main/src/vstdlib/stringnormalize.cpp; sourceTree = "<absolute>"; }; + 977F70BE12393B49008D8433 /* strtools.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = strtools.cpp; path = /Users/dberger/P4Clients/steam3_main/src/vstdlib/strtools.cpp; sourceTree = "<absolute>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 977F703D12393174008D8433 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 976DE7BE1239424E00E8D60A /* libiconv.dylib in Frameworks */, + 976DE7BC1239424500E8D60A /* CoreServices.framework in Frameworks */, + 976DE7BA1239423E00E8D60A /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 976DE7B41239411300E8D60A /* crccheck_shared */ = { + isa = PBXGroup; + children = ( + 976DE7B51239412500E8D60A /* crccheck_shared.cpp */, + 976DE7B61239412500E8D60A /* crccheck_shared.h */, + ); + name = crccheck_shared; + sourceTree = "<group>"; + }; + 976DE7BF1239425600E8D60A /* Libs */ = { + isa = PBXGroup; + children = ( + 976DE7BD1239424E00E8D60A /* libiconv.dylib */, + 976DE7BB1239424500E8D60A /* CoreServices.framework */, + 976DE7B91239423E00E8D60A /* Foundation.framework */, + ); + name = Libs; + sourceTree = "<group>"; + }; + 977F703312393173008D8433 = { + isa = PBXGroup; + children = ( + 977F703A12393174008D8433 /* Source */, + 976DE7BF1239425600E8D60A /* Libs */, + 977F704112393174008D8433 /* Products */, + ); + sourceTree = "<group>"; + }; + 977F703A12393174008D8433 /* Source */ = { + isa = PBXGroup; + children = ( + 977F706F12393A45008D8433 /* tier0 */, + 977F707012393A4D008D8433 /* tier1 */, + 977F707112393A56008D8433 /* vstdlib */, + 976DE7B41239411300E8D60A /* crccheck_shared */, + 977F706E12393A3D008D8433 /* vpc */, + ); + path = Source; + sourceTree = "<group>"; + }; + 977F704112393174008D8433 /* Products */ = { + isa = PBXGroup; + children = ( + 977F704012393174008D8433 /* vpc_osx */, + ); + name = Products; + sourceTree = "<group>"; + }; + 977F706E12393A3D008D8433 /* vpc */ = { + isa = PBXGroup; + children = ( + 977F705012393A2A008D8433 /* baseprojectdatacollector.cpp */, + 977F705112393A2A008D8433 /* baseprojectdatacollector.h */, + 977F705212393A2A008D8433 /* configuration.cpp */, + 977F705312393A2A008D8433 /* dependencies.cpp */, + 977F705412393A2A008D8433 /* dependencies.h */, + 977F705512393A2A008D8433 /* ExprSimplifier.cpp */, + 977F705612393A2A008D8433 /* GroupScript.cpp */, + 977F705712393A2A008D8433 /* ibaseprojectgenerator.h */, + 977F705812393A2A008D8433 /* ibasesolutiongenerator.h */, + 977F705912393A2A008D8433 /* main.cpp */, + 977F705A12393A2A008D8433 /* projectgenerator_makefile.cpp */, + 977F705B12393A2A008D8433 /* projectgenerator_xcode.cpp */, + 977F705C12393A2A008D8433 /* projectgenerator_xcode.h */, + 977F705D12393A2A008D8433 /* ProjectScript.cpp */, + 977F705E12393A2A008D8433 /* solutiongenerator_makefile.cpp */, + 977F705F12393A2A008D8433 /* solutiongenerator_xcode.cpp */, + 977F706012393A2A008D8433 /* sys_utils.cpp */, + 977F706112393A2A008D8433 /* sys_utils.h */, + ); + name = vpc; + sourceTree = "<group>"; + }; + 977F706F12393A45008D8433 /* tier0 */ = { + isa = PBXGroup; + children = ( + 977F707212393ADD008D8433 /* assert_dialog.cpp */, + 977F707312393ADD008D8433 /* cpu_posix.cpp */, + 977F707412393ADD008D8433 /* cpu.cpp */, + 977F707512393ADD008D8433 /* dbg.cpp */, + 977F707612393ADD008D8433 /* fasttimer.cpp */, + 977F707712393ADD008D8433 /* mem_helpers.cpp */, + 977F707812393ADD008D8433 /* memblockhdr.cpp */, + 977F707912393ADD008D8433 /* memdbg.cpp */, + 977F707A12393ADD008D8433 /* memstd.cpp */, + 977F707B12393ADD008D8433 /* memvalidate.cpp */, + 977F707C12393ADD008D8433 /* minidump.cpp */, + 977F707D12393ADD008D8433 /* pch_tier0.cpp */, + 977F707E12393ADD008D8433 /* platform_posix.cpp */, + 977F707F12393ADD008D8433 /* pme_posix.cpp */, + 977F708012393ADD008D8433 /* pmelib.cpp */, + 977F708112393ADD008D8433 /* testthread.cpp */, + 977F708212393ADD008D8433 /* thread.cpp */, + 977F708312393ADD008D8433 /* threadtools.cpp */, + 977F708412393ADD008D8433 /* tier0.cpp */, + 977F708512393ADD008D8433 /* validator.cpp */, + 977F708612393ADD008D8433 /* valobject.cpp */, + 977F708712393ADD008D8433 /* vcrmode_posix.cpp */, + 977F708812393ADD008D8433 /* vprof.cpp */, + ); + name = tier0; + sourceTree = "<group>"; + }; + 977F707012393A4D008D8433 /* tier1 */ = { + isa = PBXGroup; + children = ( + 977F70A012393B10008D8433 /* checksum_crc.cpp */, + 977F70A112393B10008D8433 /* checksum_md5.cpp */, + 977F70A212393B10008D8433 /* convar.cpp */, + 977F70A312393B10008D8433 /* generichash.cpp */, + 977F70A412393B10008D8433 /* interface.cpp */, + 977F70A512393B10008D8433 /* KeyValues.cpp */, + 977F70A612393B10008D8433 /* mempool.cpp */, + 977F70A712393B10008D8433 /* memstack.cpp */, + 977F70A812393B10008D8433 /* stringpool.cpp */, + 977F70A912393B10008D8433 /* utlbuffer.cpp */, + 977F70AA12393B10008D8433 /* utlsymbol.cpp */, + ); + name = tier1; + sourceTree = "<group>"; + }; + 977F707112393A56008D8433 /* vstdlib */ = { + isa = PBXGroup; + children = ( + 977F70B612393B49008D8433 /* commandline.cpp */, + 977F70B712393B49008D8433 /* cvar.cpp */, + 977F70B812393B49008D8433 /* keyvaluessystem.cpp */, + 977F70B912393B49008D8433 /* osversion.cpp */, + 977F70BA12393B49008D8433 /* qsort_s.cpp */, + 977F70BB12393B49008D8433 /* random.cpp */, + 977F70BC12393B49008D8433 /* splitstring.cpp */, + 977F70BD12393B49008D8433 /* stringnormalize.cpp */, + 977F70BE12393B49008D8433 /* strtools.cpp */, + ); + name = vstdlib; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 977F703F12393174008D8433 /* vpc */ = { + isa = PBXNativeTarget; + buildConfigurationList = 977F704812393174008D8433 /* Build configuration list for PBXNativeTarget "vpc" */; + buildPhases = ( + 977F703C12393174008D8433 /* Sources */, + 977F703D12393174008D8433 /* Frameworks */, + 977F703E12393174008D8433 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = vpc; + productName = vpc; + productReference = 977F704012393174008D8433 /* vpc_osx */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 977F703512393173008D8433 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 977F703812393173008D8433 /* Build configuration list for PBXProject "vpc" */; + compatibilityVersion = "Xcode 3.2"; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 977F703312393173008D8433; + productRefGroup = 977F704112393174008D8433 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 977F703F12393174008D8433 /* vpc */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 977F703C12393174008D8433 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 977F706212393A2A008D8433 /* baseprojectdatacollector.cpp in Sources */, + 977F706312393A2A008D8433 /* configuration.cpp in Sources */, + 977F706412393A2A008D8433 /* dependencies.cpp in Sources */, + 977F706512393A2A008D8433 /* ExprSimplifier.cpp in Sources */, + 977F706612393A2A008D8433 /* GroupScript.cpp in Sources */, + 977F706712393A2A008D8433 /* main.cpp in Sources */, + 977F706812393A2A008D8433 /* projectgenerator_makefile.cpp in Sources */, + 977F706912393A2A008D8433 /* projectgenerator_xcode.cpp in Sources */, + 977F706A12393A2A008D8433 /* ProjectScript.cpp in Sources */, + 977F706B12393A2A008D8433 /* solutiongenerator_makefile.cpp in Sources */, + 977F706C12393A2A008D8433 /* solutiongenerator_xcode.cpp in Sources */, + 977F706D12393A2A008D8433 /* sys_utils.cpp in Sources */, + 977F708912393ADD008D8433 /* assert_dialog.cpp in Sources */, + 977F708A12393ADD008D8433 /* cpu_posix.cpp in Sources */, + 977F708B12393ADD008D8433 /* cpu.cpp in Sources */, + 977F708C12393ADD008D8433 /* dbg.cpp in Sources */, + 977F708D12393ADD008D8433 /* fasttimer.cpp in Sources */, + 977F708E12393ADD008D8433 /* mem_helpers.cpp in Sources */, + 977F708F12393ADD008D8433 /* memblockhdr.cpp in Sources */, + 977F709012393ADD008D8433 /* memdbg.cpp in Sources */, + 977F709112393ADD008D8433 /* memstd.cpp in Sources */, + 977F709212393ADD008D8433 /* memvalidate.cpp in Sources */, + 977F709312393ADD008D8433 /* minidump.cpp in Sources */, + 977F709412393ADD008D8433 /* pch_tier0.cpp in Sources */, + 977F709512393ADD008D8433 /* platform_posix.cpp in Sources */, + 977F709612393ADD008D8433 /* pme_posix.cpp in Sources */, + 977F709712393ADD008D8433 /* pmelib.cpp in Sources */, + 977F709812393ADD008D8433 /* testthread.cpp in Sources */, + 977F709912393ADD008D8433 /* thread.cpp in Sources */, + 977F709A12393ADD008D8433 /* threadtools.cpp in Sources */, + 977F709B12393ADD008D8433 /* tier0.cpp in Sources */, + 977F709C12393ADD008D8433 /* validator.cpp in Sources */, + 977F709D12393ADD008D8433 /* valobject.cpp in Sources */, + 977F709E12393ADD008D8433 /* vcrmode_posix.cpp in Sources */, + 977F709F12393ADD008D8433 /* vprof.cpp in Sources */, + 977F70AB12393B10008D8433 /* checksum_crc.cpp in Sources */, + 977F70AC12393B10008D8433 /* checksum_md5.cpp in Sources */, + 977F70AD12393B10008D8433 /* convar.cpp in Sources */, + 977F70AE12393B10008D8433 /* generichash.cpp in Sources */, + 977F70AF12393B10008D8433 /* interface.cpp in Sources */, + 977F70B012393B10008D8433 /* KeyValues.cpp in Sources */, + 977F70B112393B10008D8433 /* mempool.cpp in Sources */, + 977F70B212393B10008D8433 /* memstack.cpp in Sources */, + 977F70B312393B10008D8433 /* stringpool.cpp in Sources */, + 977F70B412393B10008D8433 /* utlbuffer.cpp in Sources */, + 977F70B512393B10008D8433 /* utlsymbol.cpp in Sources */, + 977F70BF12393B49008D8433 /* commandline.cpp in Sources */, + 977F70C012393B49008D8433 /* cvar.cpp in Sources */, + 977F70C112393B49008D8433 /* keyvaluessystem.cpp in Sources */, + 977F70C212393B49008D8433 /* osversion.cpp in Sources */, + 977F70C312393B49008D8433 /* qsort_s.cpp in Sources */, + 977F70C412393B49008D8433 /* random.cpp in Sources */, + 977F70C512393B49008D8433 /* splitstring.cpp in Sources */, + 977F70C612393B49008D8433 /* stringnormalize.cpp in Sources */, + 977F70C712393B49008D8433 /* strtools.cpp in Sources */, + 976DE7B71239412500E8D60A /* crccheck_shared.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 977F704612393174008D8433 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = DEBUG; + GCC_VERSION = com.apple.compilers.llvmgcc42; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.5; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + SDKROOT = macosx10.5; + STRIP_INSTALLED_PRODUCT = NO; + }; + name = Debug; + }; + 977F704712393174008D8433 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_VERSION = com.apple.compilers.llvmgcc42; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.5; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + SDKROOT = macosx10.5; + STRIP_INSTALLED_PRODUCT = NO; + }; + name = Release; + }; + 977F704912393174008D8433 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = YES; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_MODEL_TUNING = G5; + "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = ( + _POSIX, + TIER0_DLL_EXPORT, + GNUC, + POSIX, + OSX, + _OSX, + COMPILER_GCC, + STEAM, + ); + GCC_VERSION = com.apple.compilers.llvmgcc42; + INSTALL_PATH = ../../devtools/bin/; + OTHER_CFLAGS = "-fpermissive"; + PRODUCT_NAME = vpc_osx; + SDKROOT = macosx10.5; + USER_HEADER_SEARCH_PATHS = "../../public ../../common ../../public/tier0 ../../public/tier1 ../../public/vstdlib"; + }; + name = Debug; + }; + 977F704A12393174008D8433 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_MODEL_TUNING = G5; + "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = ( + _POSIX, + TIER0_DLL_EXPORT, + GNUC, + POSIX, + OSX, + _OSX, + COMPILER_GCC, + STEAM, + ); + GCC_VERSION = com.apple.compilers.llvmgcc42; + INSTALL_PATH = ../../devtools/bin/; + ONLY_ACTIVE_ARCH = YES; + OTHER_CFLAGS = "-fpermissive"; + PRODUCT_NAME = vpc_osx; + SDKROOT = macosx10.5; + USER_HEADER_SEARCH_PATHS = "../../public ../../common ../../public/tier0 ../../public/tier1 ../../public/vstdlib"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 977F703812393173008D8433 /* Build configuration list for PBXProject "vpc" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 977F704612393174008D8433 /* Debug */, + 977F704712393174008D8433 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 977F704812393174008D8433 /* Build configuration list for PBXNativeTarget "vpc" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 977F704912393174008D8433 /* Debug */, + 977F704A12393174008D8433 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 977F703512393173008D8433 /* Project object */; +} diff --git a/external/vpc/utils/vpccrccheck/crccheck_shared.cpp b/external/vpc/utils/vpccrccheck/crccheck_shared.cpp new file mode 100644 index 0000000..7ca8cb3 --- /dev/null +++ b/external/vpc/utils/vpccrccheck/crccheck_shared.cpp @@ -0,0 +1,590 @@ + +#include "../vpc/vpc.h" +#include "crccheck_shared.h" +#include "tier1/checksum_crc.h" +#include "tier1/strtools.h" +#include <string.h> +#include <stdio.h> +#include <stdarg.h> +#ifdef _WIN32 +#include <process.h> +#else +#include <stdlib.h> +#define stricmp strcasecmp +#endif + +#pragma warning( disable : 4996 ) +#pragma warning( disable : 4127 ) + +#define MAX_INCLUDE_STACK_DEPTH 10 + + +static bool IsValidPathChar( char token ) +{ + // does it look like a file? If this ends up too tight, can probably just check that it's not '[' or '{' + // cause conditional blocks are what we really want to avoid. + return isalpha(token) || isdigit(token) || (token == '.') || (token == '\\') || (token == '/'); +} + +extern const char *g_szArrPlatforms[]; +static void BuildReplacements( const char *token, char *szReplacements ) +{ + // Now go pickup the any files that exist, but were non-matches + *szReplacements = '\0'; + for ( int i = 0; g_szArrPlatforms[i] != NULL; i++ ) + { + char szPath[MAX_PATH]; + char szPathExpanded[MAX_PATH]; + + V_strncpy( szPath, token, sizeof(szPath) ); + Sys_ReplaceString( szPath, "$os", g_szArrPlatforms[i], szPathExpanded, sizeof(szPathExpanded) ); + V_FixSlashes( szPathExpanded ); + V_RemoveDotSlashes( szPathExpanded ); + V_FixDoubleSlashes( szPathExpanded ); + + // this fopen is probably using a relative path, but that's ok, as everything in + // the crc code is opening relative paths and assuming the cwd is set ok. + FILE *f = fopen( szPathExpanded, "rb" ); + if ( f ) + { + fclose(f); + // strcat - blech + strcat( szReplacements, g_szArrPlatforms[i] ); // really just need to stick the existing platforms seen in + strcat( szReplacements, ";" ); + } + + } +} + +static const char * GetToken( const char *ln, char *token ) +{ + *token = '\0'; + + while ( *ln && isspace(*ln) ) + ln++; + + if (!ln[0]) + return NULL; + + if ( ln[0] == '"' ) + { // does vpc allow \" inside the filename string - shouldn't matter, but we're going to assume no. + ln++; + while (*ln) + { + if ( ln[0] == '"' ) + break; + *token++ = *ln++; + } + *token = '\0'; + } + else if ( IsValidPathChar( *ln ) ) + { + while (*ln) + { + if ( isspace(*ln) ) + break; + *token++ = *ln++; + } + *token = '\0'; + } + else + { + token[0] = ln[0]; + token[1] = '\0'; + } + + return ln; +} + +static void PerformFileSubstitions( char * line, int linelen ) +{ + static bool bFindFilePending = false; + const char *ln = line; + + if ( !bFindFilePending ) + { + ln = V_stristr( ln, "$file " ); + if ( ln ) + bFindFilePending = true; + } + + if ( bFindFilePending ) + { + char token[1024]; + ln = GetToken( ln, token ); + if ( !ln ) + return; // no more tokens on line, we should try the next line + + bFindFilePending = false; + + + if ( V_stristr(token, "$os") ) + { + if ( !IsValidPathChar( *token ) ) + fprintf( stderr, "Warning: can't expand %s for crc calculation. Changes to this file set won't trigger automatic rebuild\n", token ); + char szReplacements[2048]; + char buffer[4096]; + BuildReplacements( token, szReplacements ); + Sys_ReplaceString( line, "$os", szReplacements, buffer, sizeof(buffer) ); + V_strncpy( line, buffer, linelen ); + } + } + + static bool bFindFilePatternPending = false; + ln = line; + + if ( !bFindFilePatternPending ) + { + ln = V_stristr( ln, "$filepattern" ); + while ( ln ) + { + ln += 13; + if ( isspace( ln[-1] ) ) + { + bFindFilePatternPending = true; + break; + } + } + } + + if ( bFindFilePatternPending ) + { + char token[1024]; + ln = GetToken( ln, token ); + if ( !ln ) + return; // no more tokens on line, we should try the next line + + bFindFilePatternPending = false; + + char szReplacements[2048]; szReplacements[0] = '\0'; + char buffer[4096]; + CUtlVector< CUtlString > vecResults; + Sys_ExpandFilePattern( token, vecResults ); + if ( vecResults.Count() ) + { + for ( int i= 0; i < vecResults.Count(); i++ ) + { + V_strncat( szReplacements, CFmtStr( "%s;", vecResults[i].String() ).Access(), V_ARRAYSIZE( szReplacements ) ); + } + + CRC32_t nCRC = CRC32_ProcessSingleBuffer( szReplacements, V_strlen( szReplacements ) ); + + Sys_ReplaceString( line, token, CFmtStr( "%s:%u", token, nCRC ).Access(), buffer, sizeof(buffer) ); + V_strncpy( line, buffer, linelen ); + } + else + { + if ( !IsValidPathChar( *token ) ) + fprintf( stderr, "Warning: %s couldn't be expanded during crc calculation. Changes to this file set won't trigger automatic project rebuild\n", token ); + } + } + +} + + +//----------------------------------------------------------------------------- +// Sys_Error +// +//----------------------------------------------------------------------------- +void Sys_Error( const char* format, ... ) +{ + va_list argptr; + + va_start( argptr,format ); + vfprintf( stderr, format, argptr ); + va_end( argptr ); + + exit( 1 ); +} + + +void SafeSnprintf( char *pOut, int nOutLen, const char *pFormat, ... ) +{ + va_list marker; + va_start( marker, pFormat ); + V_vsnprintf( pOut, nOutLen, pFormat, marker ); + va_end( marker ); + + pOut[nOutLen-1] = 0; +} + + +// for linked lists of strings +struct StringNode_t +{ + StringNode_t *m_pNext; + char m_Text[1]; // the string data +}; + + +static StringNode_t *MakeStrNode( char const *pStr ) +{ + size_t nLen = strlen( pStr ); + StringNode_t *nRet = ( StringNode_t * ) new unsigned char[sizeof( StringNode_t ) + nLen ]; + strcpy( nRet->m_Text, pStr ); + return nRet; +} + +//----------------------------------------------------------------------------- +// Sys_LoadTextFileWithIncludes +//----------------------------------------------------------------------------- +int Sys_LoadTextFileWithIncludes( const char* filename, char** bufferptr, bool bInsertFileMacroExpansion ) +{ + FILE *pFileStack[MAX_INCLUDE_STACK_DEPTH]; + int nSP = MAX_INCLUDE_STACK_DEPTH; + + StringNode_t *pFileLines = NULL; // tail ptr for fast adds + + size_t nTotalFileBytes = 0; + FILE *handle = fopen( filename, "r" ); + if ( !handle ) + return -1; + + pFileStack[--nSP] = handle; // push + while ( nSP < MAX_INCLUDE_STACK_DEPTH ) + { + // read lines + for (;;) + { + char lineBuffer[4096]; + char *ln = fgets( lineBuffer, sizeof( lineBuffer ), pFileStack[nSP] ); + if ( !ln ) + break; // out of text + + ln += strspn( ln, "\t " ); // skip white space + + // Need to insert actual files to make sure crc changes if disk-matched files match + if ( bInsertFileMacroExpansion ) + PerformFileSubstitions( ln, sizeof(lineBuffer) - (ln-lineBuffer) ); + + if ( memcmp( ln, "#include", 8 ) == 0 ) + { + // omg, an include + ln += 8; + ln += strspn( ln, " \t\"<" ); // skip whitespace, ", and < + + size_t nPathNameLength = strcspn( ln, " \t\">\n" ); + if ( !nPathNameLength ) + { + Sys_Error( "bad include %s via %s\n", lineBuffer, filename ); + } + ln[nPathNameLength] = 0; // kill everything after end of filename + + FILE *inchandle = fopen( ln, "r" ); + if ( !inchandle ) + { + Sys_Error( "can't open #include of %s\n", ln ); + } + if ( !nSP ) + { + Sys_Error( "include nesting too deep via %s", filename ); + } + pFileStack[--nSP] = inchandle; + } + else + { + size_t nLen = strlen( ln ); + nTotalFileBytes += nLen; + StringNode_t *pNewLine = MakeStrNode( ln ); + + pNewLine->m_pNext = pFileLines; + pFileLines = pNewLine; + } + } + fclose( pFileStack[nSP] ); + nSP++; // pop stack + } + + + // Reverse the pFileLines list so it goes the right way. + StringNode_t *pPrev = NULL; + StringNode_t *pCur; + for( pCur = pFileLines; pCur; ) + { + StringNode_t *pNext = pCur->m_pNext; + pCur->m_pNext = pPrev; + pPrev = pCur; + pCur = pNext; + } + pFileLines = pPrev; + + + // Now dump all the lines out into a single buffer. + char *buffer = new char[nTotalFileBytes + 1]; // and null + *bufferptr = buffer; // tell caller + + // copy all strings and null terminate + int nLine = 0; + StringNode_t *pNext; + for( pCur=pFileLines; pCur; pCur=pNext ) + { + pNext = pCur->m_pNext; + size_t nLen = strlen( pCur->m_Text ); + memcpy( buffer, pCur->m_Text, nLen ); + buffer += nLen; + nLine++; + + // Cleanup the line.. + //delete [] (unsigned char*)pCur; + } + *( buffer++ ) = 0; // null + + return (int)nTotalFileBytes; +} + + +// Just like fgets() but it removes trailing newlines. +char* ChompLineFromFile( char *pOut, int nOutBytes, FILE *fp ) +{ + char *pReturn = fgets( pOut, nOutBytes, fp ); + if ( pReturn ) + { + int len = (int)strlen( pReturn ); + if ( len > 0 && pReturn[len-1] == '\n' ) + { + pReturn[len-1] = 0; + if ( len > 1 && pReturn[len-2] == '\r' ) + pReturn[len-2] = 0; + } + } + + return pReturn; +} + + +bool CheckSupplementalString( const char *pSupplementalString, const char *pReferenceSupplementalString ) +{ + // The supplemental string is only checked while VPC is determining if a project file is stale or not. + // It's not used by the pre-build event's CRC check. + // The supplemental string contains various options that tell how the project was built. It's generated in VPC_GenerateCRCOptionString. + // + // If there's no reference supplemental string (which is the case if we're running vpccrccheck.exe), then we ignore it and continue. + if ( !pReferenceSupplementalString ) + return true; + + return ( pSupplementalString && pReferenceSupplementalString && stricmp( pSupplementalString, pReferenceSupplementalString ) == 0 ); +} + +bool CheckVPCExeCRC( char *pVPCCRCCheckString, const char *szFilename, char *pErrorString, int nErrorStringLength ) +{ + if ( pVPCCRCCheckString == NULL ) + { + SafeSnprintf( pErrorString, nErrorStringLength, "Unexpected end-of-file in %s", szFilename ); + return false; + } + + char *pSpace = strchr( pVPCCRCCheckString, ' ' ); + if ( !pSpace ) + { + SafeSnprintf( pErrorString, nErrorStringLength, "Invalid line ('%s') in %s", pVPCCRCCheckString, szFilename ); + return false; + } + + // Null-terminate it so we have the CRC by itself and the filename follows the space. + *pSpace = 0; + const char *pVPCFilename = pSpace + 1; + + // Parse the CRC out. + unsigned int nReferenceCRC; + sscanf( pVPCCRCCheckString, "%x", &nReferenceCRC ); + + char *pBuffer; + int cbVPCExe = Sys_LoadFile( pVPCFilename, (void**)&pBuffer ); + if ( !pBuffer ) + { + SafeSnprintf( pErrorString, nErrorStringLength, "Unable to load %s for comparison.", pVPCFilename ); + return false; + } + + if ( cbVPCExe < 0 ) + { + SafeSnprintf( pErrorString, nErrorStringLength, "Could not load file '%s' to check CRC", pVPCFilename ); + return false; + } + + // Calculate the CRC from the contents of the file. + CRC32_t nCRCFromFileContents = CRC32_ProcessSingleBuffer( pBuffer, cbVPCExe ); + delete [] pBuffer; + + // Compare them. + if ( nCRCFromFileContents != nReferenceCRC ) + { + SafeSnprintf( pErrorString, nErrorStringLength, "VPC executable has changed since the project was generated." ); + return false; + } + return true; +} + + +bool VPC_CheckProjectDependencyCRCs( const char *pProjectFilename, const char *pReferenceSupplementalString, char *pErrorString, int nErrorStringLength ) +{ + // Build the xxxxx.vcproj.vpc_crc filename + char szFilename[512]; + SafeSnprintf( szFilename, sizeof( szFilename ), "%s.%s", pProjectFilename, VPCCRCCHECK_FILE_EXTENSION ); + + // Open it up. + FILE *fp = fopen( szFilename, "rt" ); + if ( !fp ) + { + SafeSnprintf( pErrorString, nErrorStringLength, "Unable to load %s to check CRC strings", szFilename ); + return false; + } + + bool bReturnValue = false; + char lineBuffer[2048]; + + // Check the version of the CRC file. + const char *pVersionString = ChompLineFromFile( lineBuffer, sizeof( lineBuffer ), fp ); + if ( pVersionString && stricmp( pVersionString, VPCCRCCHECK_FILE_VERSION_STRING ) == 0 ) + { + char *pVPCExeCRCString = ChompLineFromFile( lineBuffer, sizeof( lineBuffer ), fp ); + if ( CheckVPCExeCRC( pVPCExeCRCString, szFilename, pErrorString, nErrorStringLength ) ) + { + // Check the supplemental CRC string. + const char *pSupplementalString = ChompLineFromFile( lineBuffer, sizeof( lineBuffer ), fp ); + if ( CheckSupplementalString( pSupplementalString, pReferenceSupplementalString ) ) + { + // Now read each line. Each line has a CRC and a filename on it. + while ( 1 ) + { + char *pLine = ChompLineFromFile( lineBuffer, sizeof( lineBuffer ), fp ); + if ( !pLine ) + { + // We got all the way through the file without a CRC error, so all's well. + bReturnValue = true; + break; + } + + char *pSpace = strchr( pLine, ' ' ); + if ( !pSpace ) + { + SafeSnprintf( pErrorString, nErrorStringLength, "Invalid line ('%s') in %s", pLine, szFilename ); + break; + } + + // Null-terminate it so we have the CRC by itself and the filename follows the space. + *pSpace = 0; + const char *pVPCFilename = pSpace + 1; + + // Parse the CRC out. + unsigned int nReferenceCRC; + sscanf( pLine, "%x", &nReferenceCRC ); + + + // Calculate the CRC from the contents of the file. + char *pBuffer; + int nTotalFileBytes = Sys_LoadTextFileWithIncludes( pVPCFilename, &pBuffer, true ); + if ( nTotalFileBytes == -1 ) + { + SafeSnprintf( pErrorString, nErrorStringLength, "Unable to load %s for CRC comparison.", pVPCFilename ); + break; + } + + CRC32_t nCRCFromTextContents = CRC32_ProcessSingleBuffer( pBuffer, nTotalFileBytes ); + delete [] pBuffer; + + // Compare them. + if ( nCRCFromTextContents != nReferenceCRC ) + { + SafeSnprintf( pErrorString, nErrorStringLength, "This VCPROJ is out of sync with its VPC scripts.\n %s mismatches (0x%x vs 0x%x).\n Please use VPC to re-generate!\n \n", pVPCFilename, nReferenceCRC, nCRCFromTextContents ); + break; + } + } + } + else + { + SafeSnprintf( pErrorString, nErrorStringLength, "Supplemental string mismatch." ); + } + } + } + else + { + SafeSnprintf( pErrorString, nErrorStringLength, "CRC file %s has an invalid version string ('%s')", szFilename, pVersionString ? pVersionString : "[null]" ); + } + + fclose( fp ); + return bReturnValue; +} + + +int VPC_OldeStyleCRCChecks( int argc, char **argv ) +{ + for ( int i=1; (i+2) < argc; ) + { + const char *pTestArg = argv[i]; + if ( stricmp( pTestArg, "-crc" ) != 0 ) + { + ++i; + continue; + } + + const char *pVPCFilename = argv[i+1]; + + // Get the CRC value on the command line. + const char *pTestCRC = argv[i+2]; + unsigned int nCRCFromCommandLine; + sscanf( pTestCRC, "%x", &nCRCFromCommandLine ); + + // Calculate the CRC from the contents of the file. + char *pBuffer; + int nTotalFileBytes = Sys_LoadTextFileWithIncludes( pVPCFilename, &pBuffer, true ); + if ( nTotalFileBytes == -1 ) + { + Sys_Error( "Unable to load %s for CRC comparison.", pVPCFilename ); + } + + CRC32_t nCRCFromTextContents = CRC32_ProcessSingleBuffer( pBuffer, nTotalFileBytes ); + delete [] pBuffer; + + // Compare them. + if ( nCRCFromTextContents != nCRCFromCommandLine ) + { + Sys_Error( " \n This VCPROJ is out of sync with its VPC scripts.\n %s mismatches (0x%x vs 0x%x).\n Please use VPC to re-generate!\n \n", pVPCFilename, nCRCFromCommandLine, nCRCFromTextContents ); + } + + i += 2; + } + + return 0; +} + + +int VPC_CommandLineCRCChecks( int argc, char **argv ) +{ + if ( argc < 2 ) + { + fprintf( stderr, "Invalid arguments to " VPCCRCCHECK_EXE_FILENAME ". Format: " VPCCRCCHECK_EXE_FILENAME " [project filename]\n" ); + return 1; + } + + const char *pFirstCRC = argv[1]; + + // If the first argument starts with -crc but is not -crc2, then this is an old CRC check command line with all the CRCs and filenames + // directly on the command line. The new format puts all that in a separate file. + if ( pFirstCRC[0] == '-' && pFirstCRC[1] == 'c' && pFirstCRC[2] == 'r' && pFirstCRC[3] == 'c' && pFirstCRC[4] != '2' ) + { + return VPC_OldeStyleCRCChecks( argc, argv ); + } + + if ( stricmp( pFirstCRC, "-crc2" ) != 0 ) + { + fprintf( stderr, "Missing -crc2 parameter on vpc CRC check command line." ); + return 1; + } + + const char *pProjectFilename = argv[2]; + + char errorString[1024]; + bool bCRCsValid = VPC_CheckProjectDependencyCRCs( pProjectFilename, NULL, errorString, sizeof( errorString ) ); + + if ( bCRCsValid ) + { + return 0; + } + else + { + fprintf( stderr, "%s", errorString ); + return 1; + } +} + diff --git a/external/vpc/utils/vpccrccheck/crccheck_shared.h b/external/vpc/utils/vpccrccheck/crccheck_shared.h new file mode 100644 index 0000000..ce177d0 --- /dev/null +++ b/external/vpc/utils/vpccrccheck/crccheck_shared.h @@ -0,0 +1,34 @@ +//===================== Copyright (c) Valve Corporation. All Rights Reserved. ====================== +// +// +// +//================================================================================================== + +#ifndef CRCCHECK_SHARED_H +#define CRCCHECK_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + + +#ifdef STANDALONE_VPC +#define VPCCRCCHECK_EXE_FILENAME "vpc.exe" +#else +#define VPCCRCCHECK_EXE_FILENAME "vpccrccheck.exe" +#endif + +// The file extension for the file that contains the CRCs that a vcproj depends on. +#define VPCCRCCHECK_FILE_EXTENSION "vpc_crc" +#define VPCCRCCHECK_FILE_VERSION_STRING "[vpc crc file version 2]" + + +void Sys_Error( const char *format, ... ); +int Sys_LoadTextFileWithIncludes( const char* filename, char** bufferptr, bool bInsertFileMacroExpansion ); + +bool VPC_CheckProjectDependencyCRCs( const char *pProjectFilename, const char *pReferenceSupplementalString, char *pErrorString, int nErrorStringLength ); + +// Used by vpccrccheck.exe or by vpc.exe to do the CRC check that's initiated in the pre-build steps. +int VPC_CommandLineCRCChecks( int argc, char **argv ); + + +#endif // CRCCHECK_SHARED_H diff --git a/external/vpc/utils/vpccrccheck/vpccrccheck.cpp b/external/vpc/utils/vpccrccheck/vpccrccheck.cpp new file mode 100644 index 0000000..28b5667 --- /dev/null +++ b/external/vpc/utils/vpccrccheck/vpccrccheck.cpp @@ -0,0 +1,16 @@ + +#include "tier1/checksum_crc.h" +#include "crccheck_shared.h" +#include <stdio.h> +#include <string.h> + + + +int main( int argc, char **argv ) +{ + return VPC_CommandLineCRCChecks( argc, argv ); +} + + + + diff --git a/external/vpc/utils/vpccrccheck/vpccrccheck.vpc b/external/vpc/utils/vpccrccheck/vpccrccheck.vpc new file mode 100644 index 0000000..6cdfced --- /dev/null +++ b/external/vpc/utils/vpccrccheck/vpccrccheck.vpc @@ -0,0 +1,33 @@ + //----------------------------------------------------------------------------- +// VPCCRCCHECK.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\devtools\bin" + +$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc" + +$Configuration +{ + $Compiler + { + } +} + +$Project "vpccrccheck" +{ + $Folder "Source Files" + { + -$File "$SRCDIR\public\tier0\memoverride.cpp" + $File "vpccrccheck.cpp" + $File "crccheck_shared.cpp" + $File "$SRCDIR/tier1/checksum_crc.cpp" + } + + $Folder "Link Libraries" + { + -$Implib "$LIBPUBLIC\vstdlib" + } +} |