// ExtractIntellisenseOptions //------------------------------------------------------------------------------ /*static*/ void ProjectGeneratorBase::ExtractIntellisenseOptions( const AString & compilerArgs, const char * option, const char * alternateOption, Array< AString > & outOptions, bool escapeQuotes ) { ASSERT( option ); Array< AString > tokens; compilerArgs.Tokenize( tokens ); const size_t optionLen = AString::StrLen( option ); const size_t alternateOptionLen = alternateOption ? AString::StrLen( alternateOption ) : 0; for ( size_t i=0; i<tokens.GetSize(); ++i ) { AString & token = tokens[ i ]; // strip quotes around token, e.g: "-IFolder/Folder" if ( token.BeginsWith( '"' ) && token.EndsWith( '"' ) ) { token.Assign( token.Get() + 1, token.GetEnd() - 1 ); } AStackString<> optionBody; // Handle space between option and payload if ( ( token == option ) || ( token == alternateOption ) ) { // Handle an incomplete token at the end of list if ( i == ( tokens.GetSize() - 1 ) ) { break; } // Use next token optionBody = tokens[ i + 1 ]; } else if ( token.BeginsWith( option ) ) { // use everything after token optionBody.Assign( token.Get() + optionLen ); } else if ( alternateOption && token.BeginsWith( alternateOption ) ) { // use everything after token optionBody.Assign( token.Get() + alternateOptionLen ); } // Strip quotes around body (e.g. -I"Folder/Folder") if ( optionBody.BeginsWith( '"' ) && optionBody.EndsWith( '"' ) ) { optionBody.Trim( 1, 1 ); } // Did we find something? if ( optionBody.IsEmpty() == false ) { if ( escapeQuotes ) { optionBody.Replace( "\"", "\\\"" ); } outOptions.Append( optionBody ); } } }
// GetPrecompiledHeaderNode //------------------------------------------------------------------------------ bool FunctionObjectList::GetPrecompiledHeaderNode( NodeGraph & nodeGraph, const BFFIterator & iter, CompilerNode * compilerNode, const BFFVariable * compilerOptions, const Dependencies & compilerForceUsing, ObjectNode * & precompiledHeaderNode, bool deoptimizeWritableFiles, bool deoptimizeWritableFilesWithToken, bool allowDistribution, bool allowCaching, const AString& compilerOutputExtension ) const { const BFFVariable * pchInputFile = nullptr; const BFFVariable * pchOutputFile = nullptr; const BFFVariable * pchOptions = nullptr; if ( !GetString( iter, pchInputFile, ".PCHInputFile" ) || !GetString( iter, pchOutputFile, ".PCHOutputFile" ) || !GetString( iter, pchOptions, ".PCHOptions" ) ) { return false; } precompiledHeaderNode = nullptr; AStackString<> pchObjectName; if ( pchInputFile ) { if ( !pchOutputFile || !pchOptions ) { Error::Error_1300_MissingPCHArgs( iter, this ); return false; } Node * pchInputNode = nodeGraph.FindNode( pchInputFile->GetString() ); if ( pchInputNode ) { // is it a file? if ( pchInputNode->IsAFile() == false ) { Error::Error_1103_NotAFile( iter, this, "PCHInputFile", pchInputNode->GetName(), pchInputNode->GetType() ); return false; } } else { // Create input node pchInputNode = nodeGraph.CreateFileNode( pchInputFile->GetString() ); } if ( nodeGraph.FindNode( pchOutputFile->GetString() ) ) { Error::Error_1301_AlreadyDefinedPCH( iter, this, pchOutputFile->GetString().Get() ); return false; } uint32_t pchFlags = ObjectNode::DetermineFlags( compilerNode, pchOptions->GetString(), true, false ); if ( pchFlags & ObjectNode::FLAG_MSVC ) { // sanity check arguments bool foundYcInPCHOptions = false; bool foundFpInPCHOptions = false; // Find /Fo option to obtain pch object file name Array< AString > pchTokens; pchOptions->GetString().Tokenize( pchTokens ); for ( const AString & token : pchTokens ) { if ( ObjectNode::IsStartOfCompilerArg_MSVC( token, "Fo" ) ) { // Extract filename (and remove quotes if found) pchObjectName = token.Get() + 3; pchObjectName.Trim( pchObjectName.BeginsWith( '"' ) ? 1 : 0, pchObjectName.EndsWith( '"' ) ? 1 : 0 ); // Auto-generate name? if ( pchObjectName == "%3" ) { // example 'PrecompiledHeader.pch' to 'PrecompiledHeader.pch.obj' pchObjectName = pchOutputFile->GetString(); pchObjectName += compilerOutputExtension; } } else if ( ObjectNode::IsStartOfCompilerArg_MSVC( token, "Yc" ) ) { foundYcInPCHOptions = true; } else if ( ObjectNode::IsStartOfCompilerArg_MSVC( token, "Fp" ) ) { foundFpInPCHOptions = true; } } // PCH must have "Create PCH" (e.g. /Yc"PrecompiledHeader.h") if ( foundYcInPCHOptions == false ) { Error::Error_1302_MissingPCHCompilerOption( iter, this, "Yc", "PCHOptions" ); return false; } // PCH must have "Precompiled Header to Use" (e.g. /Fp"PrecompiledHeader.pch") if ( foundFpInPCHOptions == false ) { Error::Error_1302_MissingPCHCompilerOption( iter, this, "Fp", "PCHOptions" ); return false; } // PCH must have object output option (e.g. /Fo"PrecompiledHeader.obj") if ( pchObjectName.IsEmpty() ) { Error::Error_1302_MissingPCHCompilerOption( iter, this, "Fo", "PCHOptions" ); return false; } // Check Compiler Options bool foundYuInCompilerOptions = false; bool foundFpInCompilerOptions = false; Array< AString > compilerTokens; compilerOptions->GetString().Tokenize( compilerTokens ); for ( const AString & token : compilerTokens ) { if ( ObjectNode::IsStartOfCompilerArg_MSVC( token, "Yu" ) ) { foundYuInCompilerOptions = true; } else if ( ObjectNode::IsStartOfCompilerArg_MSVC( token, "Fp" ) ) { foundFpInCompilerOptions = true; } } // Object using the PCH must have "Use PCH" option (e.g. /Yu"PrecompiledHeader.h") if ( foundYuInCompilerOptions == false ) { Error::Error_1302_MissingPCHCompilerOption( iter, this, "Yu", "CompilerOptions" ); return false; } // Object using the PCH must have "Precompiled header to use" (e.g. /Fp"PrecompiledHeader.pch") if ( foundFpInCompilerOptions == false ) { Error::Error_1302_MissingPCHCompilerOption( iter, this, "Fp", "CompilerOptions" ); return false; } } precompiledHeaderNode = nodeGraph.CreateObjectNode( pchOutputFile->GetString(), pchInputNode, compilerNode, pchOptions->GetString(), AString::GetEmpty(), nullptr, pchFlags, compilerForceUsing, deoptimizeWritableFiles, deoptimizeWritableFilesWithToken, allowDistribution, allowCaching, nullptr, AString::GetEmpty(), 0 ); // preprocessor args not supported precompiledHeaderNode->m_PCHObjectFileName = pchObjectName; } return true; }