// GetImportLibName //------------------------------------------------------------------------------ void LinkerNode::GetImportLibName( const AString & args, AString & importLibName ) const { // split to individual tokens Array< AString > tokens; args.Tokenize( tokens ); const AString * const end = tokens.End(); for ( const AString * it = tokens.Begin(); it != end; ++it ) { if ( LinkerNode::IsStartOfLinkerArg_MSVC( *it, "IMPLIB:" ) ) { const char * impStart = it->Get() + 8; const char * impEnd = it->GetEnd(); // if token is exactly /IMPLIB: then value is next token if ( impStart == impEnd ) { ++it; // handle missing next value if ( it == end ) { return; // we just pretend it doesn't exist and let the linker complain } impStart = it->Get(); impEnd = it->GetEnd(); } Args::StripQuotes( impStart, impEnd, importLibName ); } } }
// GetExtraOutputPaths //------------------------------------------------------------------------------ void FunctionObjectList::GetExtraOutputPaths( const AString & args, AString & pdbPath, AString & asmPath ) const { // split to individual tokens Array< AString > tokens; args.Tokenize( tokens ); const AString * const end = tokens.End(); for ( const AString * it = tokens.Begin(); it != end; ++it ) { if ( ObjectNode::IsStartOfCompilerArg_MSVC( *it, "Fd" ) ) { GetExtraOutputPath( it, end, "Fd", pdbPath ); continue; } if ( ObjectNode::IsStartOfCompilerArg_MSVC( *it, "Fa" ) ) { GetExtraOutputPath( it, end, "Fa", asmPath ); continue; } } }
// 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 ); } } }
// GetOtherLibraries //------------------------------------------------------------------------------ bool LinkerNode::GetOtherLibraries( NodeGraph & nodeGraph, const BFFIterator & iter, const Function * function, const AString & args, Dependencies & otherLibraries, bool msvc ) const { // split to individual tokens Array< AString > tokens; args.Tokenize( tokens ); bool ignoreAllDefaultLibs = false; Array< AString > defaultLibsToIgnore( 8, true ); Array< AString > defaultLibs( 16, true ); Array< AString > libs( 16, true ); Array< AString > dashlLibs( 16, true ); Array< AString > libPaths( 16, true ); Array< AString > envLibPaths( 32, true ); // extract lib path from system if present AStackString< 1024 > libVar; if ( Env::GetEnvVariable( "LIB", libVar ) ) { libVar.Tokenize( envLibPaths, ';' ); } const AString * const end = tokens.End(); for ( const AString * it = tokens.Begin(); it != end; ++it ) { const AString & token = *it; // MSVC style if ( msvc ) { // /NODEFAULTLIB if ( LinkerNode::IsLinkerArg_MSVC( token, "NODEFAULTLIB" ) ) { ignoreAllDefaultLibs = true; continue; } // /NODEFAULTLIB: if ( GetOtherLibsArg( "NODEFAULTLIB:", defaultLibsToIgnore, it, end, false, msvc ) ) { continue; } // /DEFAULTLIB: if ( GetOtherLibsArg( "DEFAULTLIB:", defaultLibs, it, end, false, msvc ) ) { continue; } // /LIBPATH: if ( GetOtherLibsArg( "LIBPATH:", libPaths, it, end, true, msvc ) ) // true = canonicalize path { continue; } // some other linker argument? if ( token.BeginsWith( '/' ) || token.BeginsWith( '-' ) ) { continue; } } // GCC/SNC style if ( !msvc ) { // We don't need to check for this, as there is no default lib passing on // the cmd line. // -nodefaultlibs //if ( token == "-nodefaultlibs" ) //{ // ignoreAllDefaultLibs = true; // continue; //} // -L (lib path) if ( GetOtherLibsArg( "L", libPaths, it, end, false, msvc ) ) { continue; } // -l (lib) if ( GetOtherLibsArg( "l", dashlLibs, it, end, false, msvc ) ) { continue; } // some other linker argument? if ( token.BeginsWith( '-' ) ) { continue; } } // build time substitution? if ( token.BeginsWith( '%' ) || // %1 token.BeginsWith( "'%" ) || // '%1' token.BeginsWith( "\"%" ) ) // "%1" { continue; } // anything left is an input to the linker AStackString<> libName; Args::StripQuotes( token.Get(), token.GetEnd(), libName ); if ( token.IsEmpty() == false ) { libs.Append( libName ); } } // filter default libs if ( ignoreAllDefaultLibs ) { // filter all default libs defaultLibs.Clear(); } else { // filter specifically listed default libs const AString * const endI = defaultLibsToIgnore.End(); for ( const AString * itI = defaultLibsToIgnore.Begin(); itI != endI; ++itI ) { const AString * const endD = defaultLibs.End(); for ( AString * itD = defaultLibs.Begin(); itD != endD; ++itD ) { if ( itI->CompareI( *itD ) == 0 ) { defaultLibs.Erase( itD ); break; } } } } if ( !msvc ) { // convert -l<name> style libs to lib<name>.a const AString * const endDL = dashlLibs.End(); for ( const AString * itDL = dashlLibs.Begin(); itDL != endDL; ++itDL ) { AStackString<> libName; libName += "lib"; libName += *itDL; libName += ".a"; libs.Append( libName ); } } // any remaining default libs are treated the same as libs libs.Append( defaultLibs ); // use Environment libpaths if found (but used after LIBPATH provided ones) libPaths.Append( envLibPaths ); // convert libs to nodes const AString * const endL = libs.End(); for ( const AString * itL = libs.Begin(); itL != endL; ++itL ) { bool found = false; // is the file a full path? if ( ( itL->GetLength() > 2 ) && ( (*itL)[ 1 ] == ':' ) ) { // check file exists in current location if ( !GetOtherLibrary( nodeGraph, iter, function, otherLibraries, AString::GetEmpty(), *itL, found ) ) { return false; // GetOtherLibrary will have emitted error } } else { // check each libpath const AString * const endP = libPaths.End(); for ( const AString * itP = libPaths.Begin(); itP != endP; ++itP ) { if ( !GetOtherLibrary( nodeGraph, iter, function, otherLibraries, *itP, *itL, found ) ) { return false; // GetOtherLibrary will have emitted error } if ( found ) { break; } // keep searching lib paths... } } // file does not exist on disk, and there is no rule to build it // Don't complain about this, because: // a) We may be parsing rules on another OS (i.e. parsing Linux rules on Windows) // b) User may have filtered some libs for platforms they don't care about (i.e. libs // for PS4 on a PC developer's machine on a cross-platform team) // If the file is actually needed, the linker will emit an error during link-time. } return true; }
// DetermineFlags //------------------------------------------------------------------------------ /*static*/ uint32_t LinkerNode::DetermineFlags( const AString & linkerType, const AString & linkerName, const AString & args ) { uint32_t flags = DetermineLinkerTypeFlags( linkerType, linkerName ); if ( flags & LINK_FLAG_MSVC ) { // Parse args for some other flags Array< AString > tokens; args.Tokenize( tokens ); bool debugFlag = false; bool incrementalFlag = false; bool incrementalNoFlag = false; bool optREFFlag = false; bool optICFFlag = false; bool optLBRFlag = false; bool orderFlag = false; const AString * const end = tokens.End(); for ( const AString * it=tokens.Begin(); it!=end; ++it ) { const AString & token = *it; if ( IsLinkerArg_MSVC( token, "DLL" ) ) { flags |= LinkerNode::LINK_FLAG_DLL; continue; } if ( IsLinkerArg_MSVC( token, "DEBUG" ) ) { debugFlag = true; continue; } if ( IsLinkerArg_MSVC( token, "INCREMENTAL" ) ) { incrementalFlag = true; continue; } if ( IsLinkerArg_MSVC( token, "INCREMENTAL:NO" ) ) { incrementalNoFlag = true; continue; } if ( IsLinkerArg_MSVC( token, "WX" ) ) { flags |= LinkerNode::LINK_FLAG_WARNINGS_AS_ERRORS_MSVC; continue; } if ( IsStartOfLinkerArg_MSVC( token, "OPT" ) ) { if ( token.FindI( "REF" ) ) { optREFFlag = true; } if ( token.FindI( "ICF" ) ) { optICFFlag = true; } if ( token.FindI( "LBR" ) ) { optLBRFlag = true; } continue; } if ( IsStartOfLinkerArg_MSVC( token, "ORDER" ) ) { orderFlag = true; continue; } } // Determine incremental linking status bool usingIncrementalLinking = false; // false by default // these options enable incremental linking if ( debugFlag || incrementalFlag ) { usingIncrementalLinking = true; } // these options disable incremental linking if ( incrementalNoFlag || optREFFlag || optICFFlag || optLBRFlag || orderFlag ) { usingIncrementalLinking = false; } if ( usingIncrementalLinking ) { flags |= LINK_FLAG_INCREMENTAL; } } else { // Parse args for some other flags Array< AString > tokens; args.Tokenize( tokens ); const AString * const end = tokens.End(); for ( const AString * it=tokens.Begin(); it!=end; ++it ) { const AString & token = *it; if ( ( token == "-shared" ) || ( token == "-dynamiclib" ) || ( token == "--oformat=prx" ) ) { flags |= LinkerNode::LINK_FLAG_DLL; continue; } } } return flags; }