Example #1
0
// EmitCompilationMessage
//------------------------------------------------------------------------------
void TestNode::EmitCompilationMessage( const char * workingDir ) const
{
	AStackString<> output;
	output += "Running Test: ";
	output += GetName();
	output += '\n';
	if ( FLog::ShowInfo() || FBuild::Get().GetOptions().m_ShowCommandLines )
	{
		output += GetTestExecutable()->GetName();
		output += ' ';
		output += m_TestArguments;
		output += '\n';
		if ( workingDir )
		{
			output += "Working Dir: ";
			output += workingDir;
			output += '\n';
		}
	}
    FLOG_BUILD_DIRECT( output.Get() );
}
Example #2
0
REGISTER_TESTS_END

// FileExists
//------------------------------------------------------------------------------
void TestFileIO::FileExists() const
{
	// generate a process unique file path
	AStackString<> path;
	GenerateTempFileName( path );

	// ensure doesn't exist
	FileIO::FileDelete( path.Get() ); // delete in case left over from previous test run
	TEST_ASSERT( FileIO::FileExists( path.Get() ) == false );

	// create it
	FileStream f;
	TEST_ASSERT( f.Open( path.Get(), FileStream::WRITE_ONLY ) == true );
	f.Close();

	// ensure exists
	TEST_ASSERT( FileIO::FileExists( path.Get() ) == true );

	// clean up
	TEST_ASSERT( FileIO::FileDelete( path.Get() ) == true );
	TEST_ASSERT( FileIO::FileExists( path.Get() ) == false );
}
Example #3
0
// TracingOutputCallback
//------------------------------------------------------------------------------
/*static*/ bool FLog::TracingOutputCallback( const char * message )
{
    uint32_t threadIndex = WorkerThread::GetThreadIndex();

    AStackString< 2048 > tmp;

    if ( s_ShowProgress )
    {
        // clear previous progress message
        tmp += g_ClearLineString;
    }

    // print output and then progress
    if ( threadIndex > 0 )
    {
        char buffer[ 8 ];
        _itoa_s( threadIndex, buffer, 8, 10 );
        tmp += buffer;
        tmp += '>';
        if ( threadIndex < 10 )
        {
            tmp += ' '; // keep output aligned when there are > 9 threads
        }
    }

    tmp += message;

    // output to debugger if present
    #ifdef DEBUG
        #ifdef __WINDOWS__
            OutputDebugStringA( message );
        #endif
    #endif

    tmp += m_ProgressText;

    fwrite( tmp.Get(), 1, tmp.GetLength(), stdout );

    return false; // tell tracing not to output it again
}
Example #4
0
// ReadOnly
//------------------------------------------------------------------------------
void TestFileIO::ReadOnly() const
{
	// generate a process unique file path
	AStackString<> path;
	GenerateTempFileName( path );

	// create it
	FileStream f;
	TEST_ASSERT( f.Open( path.Get(), FileStream::WRITE_ONLY ) == true );
	f.Close();

	// should not be read only
	TEST_ASSERT( FileIO::GetReadOnly( path ) == false );

	// set readonly
	TEST_ASSERT( FileIO::SetReadOnly( path.Get(), true ) == true );

	// should be read only
	TEST_ASSERT( FileIO::GetReadOnly( path ) == true );

	// delete should fail
	TEST_ASSERT( FileIO::FileDelete( path.Get() ) == false );

	// clean up
	TEST_ASSERT( FileIO::SetReadOnly( path.Get(), false ) == true );
    TEST_ASSERT( FileIO::GetReadOnly( path ) == false );
	TEST_ASSERT( FileIO::FileDelete( path.Get() ) == true );
}
Example #5
0
// FileTime
//------------------------------------------------------------------------------
void TestFileIO::FileTime() const
{
	// generate a process unique file path
	AStackString<> path;
	GenerateTempFileName( path );

	// create it
	FileStream f;
	TEST_ASSERT( f.Open( path.Get(), FileStream::WRITE_ONLY ) == true );
	f.Close();

	// get last write time
	const uint64_t oldTime = FileIO::GetFileLastWriteTime( path );
	TEST_ASSERT( oldTime != 0 );

	// wait for some time that is bigger than filesystem time granularity
    #if defined( __OSX__ )
        // HFS+ has surprisingly poor time resolution (1 second)
        Thread::Sleep( 1100 );
    #else
        Thread::Sleep( 500 );
    #endif
    
	// modify file
	FileStream f2;
	TEST_ASSERT( f.Open( path.Get(), FileStream::WRITE_ONLY ) == true );
	f.Write( (uint32_t)0 );
	f.Close();

	// get new last write time
	const uint64_t newTime = FileIO::GetFileLastWriteTime( path );
	TEST_ASSERT( newTime > oldTime );

	// manually set time back
	TEST_ASSERT( FileIO::SetFileLastWriteTime( path, oldTime ) == true );
	uint64_t timeNow = FileIO::GetFileLastWriteTime( path );
    TEST_ASSERT( timeNow == oldTime );
}
Example #6
0
// ReadWeakRef
//------------------------------------------------------------------------------
bool TextReader::ReadWeakRef()
{
    // Name
    AStackString<> name;
    if ( !GetToken( name ) )
    {
        Error( "Missing weakref name" );
        return false;
    }

    AStackString<> value;
    if ( !GetString( value ) )
    {
        Error( "Missing weakref value" );
        return false;
    }

    const StackFrame & sf = m_DeserializationStack.Top();

    // null weak refs can be taken care of right now
    if ( value == "null" )
    {
        WeakRef< Object > nullWR;
        sf.m_Reflection->SetProperty( sf.m_Base, name.Get(), nullWR );
        return true;
    }

    // non-null WeakRefs must be deferred
    // (since we might not have created the child object yet)
    UnresolvedWeakRef u;
    u.m_Base = sf.m_Base;
    u.m_Reflection = sf.m_Reflection;
    u.m_WeakRefName = name;
    u.m_WeakRefValue = value;
    m_UnresolvedWeakRefs.Append( u );

    return true;
}
Example #7
0
// AStackStringOverflow
//------------------------------------------------------------------------------
void TestAString::AStackStringOverflow() const
{
    {
        // constructor with string longer than buffer
        AStackString< 8 > string( "01234567890123456789" );
        TEST_ASSERT( string.GetLength() == 20 );
        TEST_ASSERT( string.GetLength() == AString::StrLen( string.Get() ) );
    }
    {
        // assigned of string longer than buffer
        AStackString< 8 > string;
        string = "01234567890123456789";
        TEST_ASSERT( string.GetLength() == 20 );
        TEST_ASSERT( string.GetLength() == AString::StrLen( string.Get() ) );
    }
    {
        // concetentation of string longer than buffer
        AStackString< 8 > string;
        string += "01234567890123456789";
        TEST_ASSERT( string.GetLength() == 20 );
        TEST_ASSERT( string.GetLength() == AString::StrLen( string.Get() ) );
    }
}
Example #8
0
// EmitCompilationMessage
//------------------------------------------------------------------------------
void ExecNode::EmitCompilationMessage( const AString & args ) const
{
    // basic info
    AStackString< 2048 > output;
    output += "Run: ";
    output += GetName();
    output += '\n';

    // verbose mode
    if ( FLog::ShowInfo() || FBuild::Get().GetOptions().m_ShowCommandLines )
    {
        AStackString< 1024 > verboseOutput;
        verboseOutput.Format( "%s %s\nWorkingDir: %s\nExpectedReturnCode: %i\n",
                              m_Executable->GetName().Get(),
                              args.Get(),
                              m_WorkingDir.Get(),
                              m_ExpectedReturnCode );
        output += verboseOutput;
    }

    // output all at once for contiguousness
    FLOG_BUILD_DIRECT( output.Get() );
}
Example #9
0
// Retrieve
//------------------------------------------------------------------------------
/*virtual*/ bool Cache::Retrieve( const AString & cacheId, void * & data, size_t & dataSize )
{
    data = nullptr;
    dataSize = 0;

    AStackString<> cacheFileName;
    GetCacheFileName( cacheId, cacheFileName );

    FileStream cacheFile;
    if ( cacheFile.Open( cacheFileName.Get(), FileStream::READ_ONLY ) )
    {
        const size_t cacheFileSize = (size_t)cacheFile.GetFileSize();
        AutoPtr< char > mem( (char *)ALLOC( cacheFileSize ) );
        if ( cacheFile.Read( mem.Get(), cacheFileSize ) == cacheFileSize )
        {
            dataSize = cacheFileSize;
            data = mem.Release();
            return true;
        }
    }

    return false;
}
Example #10
0
// ProcessEnvironment
//------------------------------------------------------------------------------
void FunctionSettings::ProcessEnvironment( const Array< AString > & envStrings ) const
{
    // the environment string is used in windows as a double-null terminated string
    // so convert our array to a single buffer

    // work out space required
    uint32_t size = 0;
    for ( uint32_t i=0; i<envStrings.GetSize(); ++i )
    {
        size += envStrings[ i ].GetLength() + 1; // string len inc null
    }

    // allocate space
    AutoPtr< char > envString( (char *)ALLOC( size + 1 ) ); // +1 for extra double-null

    // while iterating, extract the LIB environment variable (if there is one)
    AStackString<> libEnvVar;

    // copy strings end to end
    char * dst = envString.Get();
    for ( uint32_t i=0; i<envStrings.GetSize(); ++i )
    {
        if ( envStrings[ i ].BeginsWith( "LIB=" ) )
        {
            libEnvVar.Assign( envStrings[ i ].Get() + 4, envStrings[ i ].GetEnd() );
        }

        const uint32_t thisStringLen = envStrings[ i ].GetLength();
        AString::Copy( envStrings[ i ].Get(), dst, thisStringLen );
        dst += ( thisStringLen + 1 );
    }

    // final double-null
    *dst = '\000';

    FBuild::Get().SetEnvironmentString( envString.Get(), size, libEnvVar );
}
Example #11
0
// Save
//------------------------------------------------------------------------------
void WorkerSettings::Save()
{
    AStackString<> settingsPath;
    Env::GetExePath( settingsPath );
    settingsPath += ".settings";

    FileStream f;
    if ( f.Open( settingsPath.Get(), FileStream::WRITE_ONLY ) )
    {
        bool ok = true;

        // header
        ok &= ( f.Write( "FWS", 3 ) == 3 );
        ok &= ( f.Write( uint8_t( FBUILDWORKER_SETTINGS_CURRENT_VERSION ) ) == 1 );

        // settings
        ok &= f.Write( (uint32_t)m_Mode );
        ok &= f.Write( m_NumCPUsToUse );
        ok &= f.Write( m_StartMinimized );

        if ( ok )
        {
            return;
        }
    }

    #if defined( __WINDOWS__ )
        MessageBox( nullptr, "Failed to save settings.", "FBuildWorker", MB_OK );
    #elif defined( __APPLE__ )
        // TODO:MAC Implement ShowMessageBox
    #elif defined( __LINUX__ )
        // TODO:LINUX Implement ShowMessageBox
    #else
        #error Unknown Platform
    #endif
}
Example #12
0
// WriteNestedProjects
//------------------------------------------------------------------------------
void SLNGenerator::WriteNestedProjects( const Array< AString > & solutionProjectsToFolder,
                                        const Array< AString > & solutionFolderPaths )
{
    if ( solutionProjectsToFolder.GetSize() == 0 &&
            solutionFolderPaths.GetSize() == 0 )
    {
        return; // skip global section
    }

    Write( "\tGlobalSection(NestedProjects) = preSolution\r\n" );

    // Write every project to solution folder relationships
    const AString * const solutionProjectsToFolderEnd = solutionProjectsToFolder.End();
    for( const AString * it = solutionProjectsToFolder.Begin() ; it != solutionProjectsToFolderEnd ; ++it )
    {
        Write( it->Get() );
    }

    // Write every intermediate path
    const AString * const solutionFolderPathsEnd = solutionFolderPaths.End();
    for( const AString * it = solutionFolderPaths.Begin() ; it != solutionFolderPathsEnd ; ++it )
    {
        // parse solution folder parent path
        AStackString<> solutionFolderParentGuid;
        const char * lastSlash = it->FindLast( NATIVE_SLASH );
        if ( lastSlash )
        {
            AStackString<> solutionFolderParentPath( it->Get(), lastSlash );
            VSProjectGenerator::FormatDeterministicProjectGUID( solutionFolderParentGuid, solutionFolderParentPath );
        }

        if ( solutionFolderParentGuid.GetLength() > 0 )
        {
            // generate a guid for the solution folder
            AStackString<> solutionFolderGuid;
            VSProjectGenerator::FormatDeterministicProjectGUID( solutionFolderGuid, *it );

            solutionFolderGuid.ToUpper();
            solutionFolderParentGuid.ToUpper();

            // write parent solution folder relationship
            Write( "\t\t%s = %s\r\n", solutionFolderGuid.Get(), solutionFolderParentGuid.Get() );
        }
    }

    Write( "\tEndGlobalSection\r\n" );
}
Example #13
0
// StopBuild
//------------------------------------------------------------------------------
/*static*/ void FLog::StopBuild()
{
    if ( g_MonitorFileStream )
    {
        MutexHolder lock( g_MonitorMutex );
        Monitor( "STOP_BUILD\n" );
        g_MonitorFileStream->Close();

        delete g_MonitorFileStream;
        g_MonitorFileStream = nullptr;
    }

    Tracing::RemoveCallbackOutput( &TracingOutputCallback );

    if ( s_ShowProgress )
    {
        fputs( g_ClearLineString.Get(), stdout );
        m_ProgressText.Clear();
    }
}
Example #14
0
// DoToggleSection
//------------------------------------------------------------------------------
void Report::DoToggleSection( size_t numMore )
{
	static int tableId = 0;
	++tableId;
	AStackString<> tableIdStr;
	tableIdStr.Format( "table%u", tableId );

	DoTableStop();
	AStackString<> more;
	if ( numMore )
	{
		more.Format( "%u ", (uint32_t)numMore );
	}
	Write( "<a href='javascript:toggleTable(\"%s\");'>%sMore...</a>\n", tableIdStr.Get(), more.Get() );
	DoTableStart( DEFAULT_TABLE_WIDTH, tableIdStr.Get(), true ); // hide table
}
Example #15
0
// Format
//------------------------------------------------------------------------------
void TestAString::Format() const
{
    // Create a really long input string
    AStackString<> longInput;
    const size_t longStringLen( 1024 * 1024 );
    for ( size_t i=0; i<longStringLen; ++i )
    {
        longInput += 'A';
    }

    // Make sure we correctly handle formatting large strings
    AStackString<> buffer;
    buffer.Format( "%s", longInput.Get() );
    TEST_ASSERT( buffer.GetLength() == longStringLen );
    TEST_ASSERT( AString::StrLen( buffer.Get() ) == longStringLen );
}
Example #16
0
// Monitor
//------------------------------------------------------------------------------
/*static*/ void FLog::Monitor( const char * formatString, ... )
{
    // Is monitoring enabled?
    if ( g_MonitorFileStream == nullptr )
    {
        return; // No - nothing to do
    }

    PROFILE_SECTION( "FLog::Monitor" )

    AStackString< 1024 > buffer;
    va_list args;
    va_start( args, formatString );
    buffer.VFormat( formatString, args );
    va_end( args );

    AStackString< 1024 > finalBuffer;
    finalBuffer.Format( "%llu %s", Time::GetCurrentFileTime(), buffer.Get() );

    MutexHolder lock( g_MonitorMutex );
    g_MonitorFileStream->WriteBuffer( finalBuffer.Get(), finalBuffer.GetLength() );
}
Example #17
0
// FormatError
//------------------------------------------------------------------------------
void Error::FormatError( const BFFIterator & iter,
                         uint32_t errNum,
                         const Function * function,
                         const char * message, ... )
{
    ASSERT( message );
    AStackString< 4096 > buffer;

    va_list args;
    va_start(args, message);
    buffer.VFormat( message, args );
    va_end( args );

    // get human readable info about the position of the error
    uint32_t line = 0;
    uint32_t column = 0;
    const char * lineStart = nullptr;
    iter.GetPosInfo( line, column, lineStart );

    // convert to full path and '/'->'\' cleanup
    const AStackString<> fileName( iter.GetFileName() );
    AStackString<> fullPath;
    NodeGraph::CleanPath( fileName, fullPath );

    // deliberately using OUTPUT here to avoid "Error:" in front
    OUTPUT( "%s(%u,%u): FASTBuild Error #%04u - %s%s%s\n",
            fullPath.Get(),
            line,
            column,
            errNum,
            function ? function->GetName().Get() : "",
            function ? "() - " : "",
            buffer.Get() );

    // find the line end
    BFFIterator lineEnd( iter );
    while ( !lineEnd.IsAtEnd() )
    {
        if (( *lineEnd != '\r' ) && ( *lineEnd != '\n' ))
        {
            lineEnd++;
            continue;
        }
        break;
    }

    // if line is too crazy to be useful, don't print anything more
    size_t lineLength = lineEnd.GetCurrent() - lineStart;
    if ( lineLength >= 256 )
    {
        return;
    }

    // print the problematic line
    AString::Copy( lineStart, buffer.Get(), lineLength );
    FLOG_ERROR( "%s", buffer.Get() );

    // point to the specific pos where parsing broke
    // (taking into account tabs)
    char * c = buffer.Get();
    const char * end = c + column - 1;
    for ( ; c < end; ++c )
    {
        if ( *c != '\t' )
        {
            *c = ' ';
        }
    }

    AString::Copy( "^", c, 1 );
    FLOG_ERROR( buffer.Get() );
    AString::Copy( "\\--here", c, 8 );
    FLOG_ERROR( buffer.Get() );
}
Example #18
0
// GenerateVCXProjFilters
//------------------------------------------------------------------------------
const AString & VSProjectGenerator::GenerateVCXProjFilters( const AString & projectFile )
{
    // preallocate to avoid re-allocations
    m_Tmp.SetReserved( MEGABYTE );
    m_Tmp.SetLength( 0 );

    // determine folder for project
    const char * lastProjSlash = projectFile.FindLast( NATIVE_SLASH );
    AStackString<> projectBasePath( projectFile.Get(), lastProjSlash ? lastProjSlash + 1 : projectFile.Get() );

    // header
    Write( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" );
    Write( "<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n" );

    // list of all folders
    Array< AString > folders( 1024, true );

    // files
    {
        Write( "  <ItemGroup>\n" );
        const AString * const fEnd = m_Files.End();
        for ( const AString * fIt = m_Files.Begin(); fIt!=fEnd; ++fIt )
        {
            // get folder part, relative to base dir
            AStackString<> folder;
            GetFolderPath( *fIt, folder );
            const char * fileName = fIt->BeginsWithI( projectBasePath ) ? fIt->Get() + projectBasePath.GetLength() : fIt->Get();
            Write( "    <CustomBuild Include=\"%s\">\n", fileName );
            if ( !folder.IsEmpty() )
            {
                Write( "      <Filter>%s</Filter>\n", folder.Get() );
            }
            Write( "    </CustomBuild>\n" );

            // add new folders
            if ( !folder.IsEmpty() )
            {
                for (;;)
                {
                    // add this folder if unique
                    bool found = false;
                    for ( const AString * it=folders.Begin(); it!=folders.End(); ++it )
                    {
                        if ( it->CompareI( folder ) == 0 )
                        {
                            found = true;
                            break;
                        }
                    }
                    if ( !found )
                    {
                        folders.Append( folder );
                    }

                    // handle intermediate folders
                    const char * lastSlash = folder.FindLast( BACK_SLASH );
                    if ( lastSlash == nullptr )
                    {
                        break;
                    }
                    folder.SetLength( (uint32_t)( lastSlash - folder.Get() ) );
                }
            }
        }
        Write( "  </ItemGroup>\n" );
    }

    // folders
    {
        const AString * const fEnd = folders.End();
        for ( const AString * fIt = folders.Begin(); fIt!=fEnd; ++fIt )
        {
            Write( "  <ItemGroup>\n" );
            Write( "    <Filter Include=\"%s\">\n", fIt->Get() );
            Write( "      <UniqueIdentifier>{%08x-6c94-4f93-bc2a-7f5284b7d434}</UniqueIdentifier>\n", CRC32::Calc( *fIt ) );
            Write( "    </Filter>\n" );
            Write( "  </ItemGroup>\n" );
        }
    }

    // footer
    Write( "</Project>" ); // no carriage return

    m_OutputVCXProjFilters = m_Tmp;
    return m_OutputVCXProjFilters;
}
Example #19
0
// PrintVarRecurse
//------------------------------------------------------------------------------
/*static*/ void FunctionPrint::PrintVarRecurse( const BFFVariable & var, uint32_t indent )
{
    AStackString<> indentStr;
    for ( uint32_t i=0; i<indent; ++i )
    {
        indentStr += "    ";
    }
    ++indent;
    FLOG_BUILD( indentStr.Get() );

    switch ( var.GetType() )
    {
    case BFFVariable::VAR_ANY:
        ASSERT( false );
        break; // Something is terribly wrong
    case BFFVariable::VAR_STRING:
    {
        AStackString<> value( var.GetString() );
        value.Replace( "'", "^'" ); // escape single quotes
        FLOG_BUILD( "%s = '%s'\n", var.GetName().Get(), value.Get() );
        break;
    }
    case BFFVariable::VAR_BOOL:
    {
        FLOG_BUILD( "%s = %s\n", var.GetName().Get(), var.GetBool() ? "true" : "false" );
        break;
    }
    case BFFVariable::VAR_ARRAY_OF_STRINGS:
    {
        const auto & strings = var.GetArrayOfStrings();
        FLOG_BUILD( "%s = // ArrayOfStrings, size: %u\n%s{\n", var.GetName().Get(), (uint32_t)strings.GetSize(), indentStr.Get() );
        for ( const AString & string : strings )
        {
            AStackString<> value( string );
            value.Replace( "'", "^'" ); // escape single quotes
            FLOG_BUILD( "%s    '%s'\n", indentStr.Get(), value.Get() );
        }
        FLOG_BUILD( "%s}\n", indentStr.Get() );
        break;
    }
    case BFFVariable::VAR_INT:
    {
        FLOG_BUILD( "%s = %i\n", var.GetName().Get(), var.GetInt() );
        break;
    }
    case BFFVariable::VAR_STRUCT:
    {
        FLOG_BUILD( "%s = // Struct\n%s[\n", var.GetName().Get(), indentStr.Get() );
        for ( const BFFVariable * subVar : var.GetStructMembers() )
        {
            PrintVarRecurse( *subVar, indent );
        }
        FLOG_BUILD( "%s]\n", indentStr.Get() );
        break;
    }
    case BFFVariable::VAR_ARRAY_OF_STRUCTS:
    {
        const auto & structs = var.GetArrayOfStructs();
        FLOG_BUILD( "%s = // ArrayOfStructs, size: %u\n%s{\n", var.GetName().Get(), (uint32_t)structs.GetSize(), indentStr.Get() );
        for ( const BFFVariable * subVar : structs )
        {
            PrintVarRecurse( *subVar, indent );
        }
        FLOG_BUILD( "%s}\n", indentStr.Get() );
        break;
    }
    case BFFVariable::MAX_VAR_TYPES:
        ASSERT( false );
        break; // Something is terribly wrong
    }
}
Example #20
0
// Commit
//------------------------------------------------------------------------------
/*virtual*/ bool FunctionObjectList::Commit( const BFFIterator & funcStartIter ) const
{
	// make sure all required variables are defined
	const BFFVariable * compiler;
	const BFFVariable * compilerOptions;
	AStackString<> compilerOptionsDeoptimized;
	AStackString<> compilerOutputPath;
    AStackString<> compilerOutputPrefix;
	const BFFVariable * compilerOutputExtension;
	if ( !GetString( funcStartIter, compiler, ".Compiler", true ) ||
		 !GetString( funcStartIter, compilerOptions, ".CompilerOptions", true ) ||
		 !GetString( funcStartIter, compilerOptionsDeoptimized, ".CompilerOptionsDeoptimized", false ) ||
		 !GetString( funcStartIter, compilerOutputPath, ".CompilerOutputPath", true ) ||
		 !GetString( funcStartIter, compilerOutputPrefix, ".CompilerOutputPrefix", false ) ||
		 !GetString( funcStartIter, compilerOutputExtension, ".CompilerOutputExtension", false ) )
	{
		return false;
	}

    PathUtils::FixupFolderPath( compilerOutputPath );

	NodeGraph & ng = FBuild::Get().GetDependencyGraph();

	// find or create the compiler node
	CompilerNode * compilerNode = nullptr;
	if ( !FunctionObjectList::GetCompilerNode( funcStartIter, compiler->GetString(), compilerNode ) )
	{
		return false; // GetCompilerNode will have emitted error
	}

	// Sanity check compile flags
	uint32_t objFlags = ObjectNode::DetermineFlags( compilerNode, compilerOptions->GetString() );
	if ( ( objFlags & ObjectNode::FLAG_MSVC ) && ( objFlags & ObjectNode::FLAG_CREATING_PCH ) )
	{
		// must not specify use of precompiled header (must use the PCH specific options)
		Error::Error_1303_PCHCreateOptionOnlyAllowedOnPCH( funcStartIter, this, "/Yc", "CompilerOptions" );
		return false;
	}

	// Check input/output for Compiler
	{
		const AString & args = compilerOptions->GetString();
		bool hasInputToken = ( args.Find( "%1" ) || args.Find( "\"%1\"" ) );
		if ( hasInputToken == false )
		{
			Error::Error_1106_MissingRequiredToken( funcStartIter, this, ".CompilerOptions", "%1" );
			return false;
		}
		bool hasOutputToken = ( args.Find( "%2" ) || args.Find( "\"%2\"" ) );
		if ( hasOutputToken == false )
		{
			Error::Error_1106_MissingRequiredToken( funcStartIter, this, ".CompilerOptions", "%2" );
			return false;
		}

        // check /c or -c
        if ( objFlags & ObjectNode::FLAG_MSVC )
        {
            if ( args.Find( "/c" ) == nullptr &&
				args.Find( "-c" ) == nullptr)
            {
		        Error::Error_1106_MissingRequiredToken( funcStartIter, this, ".CompilerOptions", "/c or -c" );
			    return false;
		    }
        }
        else if ( objFlags & ( ObjectNode::FLAG_SNC | ObjectNode::FLAG_GCC | ObjectNode::FLAG_CLANG ) )
        {
            if ( args.Find( "-c" ) == nullptr )
            {
		        Error::Error_1106_MissingRequiredToken( funcStartIter, this, ".CompilerOptions", "-c" );
			    return false;
		    }
        }
	}

	// Compiler Force Using
	Dependencies compilerForceUsing;
	if ( !GetNodeList( funcStartIter, ".CompilerForceUsing", compilerForceUsing, false ) )
	{
		return false; // GetNodeList will have emitted an error
	}

	// Get the (optional) Preprocessor & PreprocessorOptions
	const BFFVariable * preprocessor = nullptr;
	const BFFVariable * preprocessorOptions = nullptr;
    CompilerNode * preprocessorNode = nullptr;
	if ( !GetString( funcStartIter, preprocessor, ".Preprocessor", false ) )
	{
		return false; // GetString will have emitted an error
	}
	if ( preprocessor )
    {
		// get the preprocessor executable
        if ( !FunctionObjectList::GetCompilerNode( funcStartIter, preprocessor->GetString(), preprocessorNode ) )
        {
            return false; // GetCompilerNode will have emitted an error
        }

		// get the command line args for the preprocessor
        if ( !GetString( funcStartIter, preprocessorOptions, ".PreprocessorOptions", true ) ) // required
		{
			return false; // GetString will have emitted an error
		}
    }

	// Pre-build dependencies
	Dependencies preBuildDependencies;
	if ( !GetNodeList( funcStartIter, ".PreBuildDependencies", preBuildDependencies, false ) )
	{
		return false; // GetNodeList will have emitted an error
	}

	// de-optimization setting
	bool deoptimizeWritableFiles = false;
	bool deoptimizeWritableFilesWithToken = false;
	if ( !GetBool( funcStartIter, deoptimizeWritableFiles, ".DeoptimizeWritableFiles", false, false ) )
	{
		return false; // GetBool will have emitted error
	}
	if ( !GetBool( funcStartIter, deoptimizeWritableFilesWithToken, ".DeoptimizeWritableFilesWithToken", false, false ) )
	{
		return false; // GetBool will have emitted error
	}
	if ( ( deoptimizeWritableFiles || deoptimizeWritableFilesWithToken ) && compilerOptionsDeoptimized.IsEmpty() )
	{
		Error::Error_1101_MissingProperty( funcStartIter, this, AStackString<>( ".CompilerOptionsDeoptimized" ) );
		return false;
	}

	// Precompiled Header support
	ObjectNode * precompiledHeaderNode = nullptr;
	if ( !GetPrecompiledHeaderNode( funcStartIter, compilerNode, objFlags, compilerOptions, compilerForceUsing, precompiledHeaderNode, deoptimizeWritableFiles, deoptimizeWritableFilesWithToken ) )
	{
		return false; // GetPrecompiledHeaderNode will have emitted error
	}

	Dependencies staticDeps( 32, true );
	if ( !GetInputs( funcStartIter, staticDeps ) )
	{
		return false; // GetStaticDeps will gave emitted error
	}

	if ( staticDeps.IsEmpty() )
	{
		Error::Error_1006_NothingToBuild( funcStartIter, this );
		return false;
	}

	// parsing logic should guarantee we have a string for our name
	ASSERT( m_AliasForFunction.IsEmpty() == false );

	// Check for existing node
	if ( ng.FindNode( m_AliasForFunction ) )
	{
		Error::Error_1100_AlreadyDefined( funcStartIter, this, m_AliasForFunction );
		return false;
	}

	// Create library node which depends on the single file or list
	ObjectListNode * o = ng.CreateObjectListNode( m_AliasForFunction,
												  staticDeps,
												  compilerNode,
												  compilerOptions->GetString(),
												  compilerOptionsDeoptimized,
												  compilerOutputPath,
												  precompiledHeaderNode,
												  compilerForceUsing,
												  preBuildDependencies,
												  deoptimizeWritableFiles,
												  deoptimizeWritableFilesWithToken,
                                                  preprocessorNode,
                                                  preprocessorOptions ? preprocessorOptions->GetString() : AString::GetEmpty() );
	if ( compilerOutputExtension )
	{
		o->m_ObjExtensionOverride = compilerOutputExtension->GetString();
	}
    o->m_CompilerOutputPrefix = compilerOutputPrefix;

	return true;
}
// Commit
//------------------------------------------------------------------------------
/*virtual*/ bool FunctionVCXProject::Commit( const BFFIterator & funcStartIter ) const
{
	// required
	AStackString<> projectOutput;
	AStackString<> rootNamespace;
	AStackString<> projectGuid;
	AStackString<> defaultLanguage;
	AStackString<> applicationEnvironment;
	if ( !GetString( funcStartIter, projectOutput,		".ProjectOutput", true ) ||
		 !GetString( funcStartIter, rootNamespace,		".RootNamespace", false ) ||
		 !GetString( funcStartIter, projectGuid,		".ProjectGuid", false ) ||
		 !GetString( funcStartIter, defaultLanguage,	".DefaultLanguage", false ) ||
		 !GetString( funcStartIter, applicationEnvironment,	".ApplicationEnvironment", false ) )
	{
		return false;
	}

	// optional inputs
	Array< AString > inputPaths;
	Array< AString > inputPathsExclude;
	if ( !GetStrings( funcStartIter, inputPaths,		".ProjectInputPaths", false ) ||
		 !GetStrings( funcStartIter, inputPathsExclude,	".ProjectInputPathsExclude", false ) )
	{
		return false;
	}

	// project base
	Array< AString > basePaths;
	if ( !GetStrings( funcStartIter, basePaths,	".ProjectBasePath", false ) )
	{
		return false;
	}
	CleanFolderPaths( basePaths );

	// references
	Array< AString > references;
	Array< AString > projectReferences;
	if ( !GetStrings( funcStartIter, references,		".ProjectReferences", false ) ||
		 !GetStrings( funcStartIter, projectReferences,	".ProjectProjectReferences", false ) )
	{
		return false;
	}

	// permitted file extensions
	Array< AString > allowedFileExtensions( 8, true );
	if ( !GetStrings( funcStartIter, allowedFileExtensions, ".ProjectAllowedFileExtensions", false ) )
	{
		return true;
	}
	if ( allowedFileExtensions.IsEmpty() )
	{
		const char * extensions[] = { ".cpp", ".hpp", ".cxx",".hxx",".c",".h",".cc",".hh",
									  ".cp",".hp",".cs",".inl",".bff",".rc",".resx",".m",".mm",
									  ".cu",
									  nullptr };
		AStackString<> tmp;
		const char ** item = extensions;
		while ( *item )
		{
			tmp.Assign( *item );
			allowedFileExtensions.Append( tmp );
			++item;
		}
	}

	// files and filesToExclude
	Array< AString > files( 8, true );
	Array< AString > filesToExclude( 8, true );	
	if ( !GetStrings( funcStartIter, files,				".ProjectFiles", false ) ||
 		 !GetStrings( funcStartIter, filesToExclude,	".ProjectFilesToExclude", false ) )
	{
		return false;
	}

	// filetypes
	Array< VSProjectFileType > fileTypes;
	const BFFVariable * projectFileTypes = BFFStackFrame::GetVar( ".ProjectFileTypes" );
	if ( projectFileTypes )
	{
		if ( projectFileTypes->IsArrayOfStructs() == false )
		{
			Error::Error_1050_PropertyMustBeOfType( funcStartIter, this, ".ProjectFileTypes", projectFileTypes->GetType(), BFFVariable::VAR_ARRAY_OF_STRUCTS );
			return false;
		}

		const Array< const BFFVariable * > & structs = projectFileTypes->GetArrayOfStructs();
		const BFFVariable * const * end = structs.End();
		for ( const BFFVariable ** it = structs.Begin(); it != end; ++it )
		{
			const BFFVariable * s = *it;

			VSProjectFileType ft;

			// .FileType must be provided
			if ( !GetStringFromStruct( s, ".FileType",	ft.m_FileType ) )
			{
				// TODO:B custom error
				Error::Error_1101_MissingProperty( funcStartIter, this, AStackString<>( ".FileType" ) );
				return false;
			}

			// .Pattern must be provided
			if ( !GetStringFromStruct( s, ".Pattern",	ft.m_Pattern ) )
			{
				// TODO:B custom error
				Error::Error_1101_MissingProperty( funcStartIter, this, AStackString<>( ".Pattern" ) );
				return false;
			}

			fileTypes.Append( ft );
		}
	}

	// path cleaning
	CleanFolderPaths( inputPaths );			// input paths
	CleanFolderPaths( inputPathsExclude );	// exclude paths
	CleanFilePaths( files );				// explicit files

	// per-config options
	VSProjectConfig baseConfig;

	// various options
	if ( !GetString( funcStartIter, baseConfig.m_BuildCommand,	".ProjectBuildCommand", false ) ||
		 !GetString( funcStartIter, baseConfig.m_RebuildCommand,".ProjectRebuildCommand", false ) ||
		 !GetString( funcStartIter, baseConfig.m_CleanCommand,	".ProjectCleanCommand", false ) ||
		 !GetString( funcStartIter, baseConfig.m_Output,		".Output", false ) ||
		 !GetString( funcStartIter, baseConfig.m_PreprocessorDefinitions,	".PreprocessorDefinitions", false ) ||
		 !GetString( funcStartIter, baseConfig.m_IncludeSearchPath,		".IncludeSearchPath", false ) ||
		 !GetString( funcStartIter, baseConfig.m_ForcedIncludes,		".ForcedIncludes", false ) ||
		 !GetString( funcStartIter, baseConfig.m_AssemblySearchPath,	".AssemblySearchPath", false ) ||
		 !GetString( funcStartIter, baseConfig.m_ForcedUsingAssemblies,	".ForcedUsingAssemblies", false ) ||
		 !GetString( funcStartIter, baseConfig.m_AdditionalOptions,		".AdditionalOptions", false ) ||
		 !GetString( funcStartIter, baseConfig.m_OutputDirectory,		".OutputDirectory", false ) ||
		 !GetString( funcStartIter, baseConfig.m_IntermediateDirectory,	".IntermediateDirectory", false ) ||
		 !GetString( funcStartIter, baseConfig.m_Xbox360DebuggerCommand,".Xbox360DebuggerCommand", false ) ||
		 !GetString( funcStartIter, baseConfig.m_LayoutDir,				".LayoutDir", false ) ||
		 !GetString( funcStartIter, baseConfig.m_LayoutExtensionFilter,	".LayoutExtensionFilter", false ) ||
		 !GetString( funcStartIter, baseConfig.m_DebuggerFlavor,		".DebuggerFlavor", false ) ||
		 !GetString( funcStartIter, baseConfig.m_AumidOverride,			".AumidOverride", false ) ||
		 !GetString( funcStartIter, baseConfig.m_PlatformToolset,		".PlatformToolset", false ) ||
		 !GetString( funcStartIter, baseConfig.m_DeploymentType,		".DeploymentType", false ) ||
		 !GetString( funcStartIter, baseConfig.m_DeploymentFiles,		".DeploymentFiles", false ) ||
		 !GetString( funcStartIter, baseConfig.m_LocalDebuggerCommandArguments,	".LocalDebuggerCommandArguments", false ) ||
		 !GetString( funcStartIter, baseConfig.m_LocalDebuggerWorkingDirectory,	".LocalDebuggerWorkingDirectory", false ) ||
		 !GetString( funcStartIter, baseConfig.m_LocalDebuggerCommand,			".LocalDebuggerCommand", false ) ||
		 !GetString( funcStartIter, baseConfig.m_LocalDebuggerEnvironment,		".LocalDebuggerEnvironment", false ) )
	{
		return false;
	}

	// create configs
	Array< VSProjectConfig > configs( 16, true );

	const BFFVariable * projectConfigs = BFFStackFrame::GetVar( ".ProjectConfigs" );
	if ( projectConfigs )
	{
		if ( projectConfigs->IsArrayOfStructs() == false )
		{
			Error::Error_1050_PropertyMustBeOfType( funcStartIter, this, ".ProjectConfigs", projectConfigs->GetType(), BFFVariable::VAR_ARRAY_OF_STRUCTS );
			return false;
		}

		const Array< const BFFVariable * > & structs = projectConfigs->GetArrayOfStructs();
		const BFFVariable * const * end = structs.End();
		for ( const BFFVariable ** it = structs.Begin(); it != end; ++it )
		{
			const BFFVariable * s = *it;

			// start with the base configuration
			VSProjectConfig newConfig( baseConfig );

			// .Platform must be provided
			if ( !GetStringFromStruct( s, ".Platform",	newConfig.m_Platform ) )
			{
				// TODO:B custom error
				Error::Error_1101_MissingProperty( funcStartIter, this, AStackString<>( ".Platform" ) );
				return false;
			}

			// .Config must be provided
			if ( !GetStringFromStruct( s, ".Config",	newConfig.m_Config ) )
			{
				// TODO:B custom error
				Error::Error_1101_MissingProperty( funcStartIter, this, AStackString<>( ".Config" ) );
				return false;
			}

			GetStringFromStruct( s, ".ProjectBuildCommand",		newConfig.m_BuildCommand );
			GetStringFromStruct( s, ".ProjectRebuildCommand",	newConfig.m_RebuildCommand );
			GetStringFromStruct( s, ".ProjectCleanCommand",		newConfig.m_CleanCommand );
			GetStringFromStruct( s, ".Output",					newConfig.m_Output );
			GetStringFromStruct( s, ".PreprocessorDefinitions",	newConfig.m_PreprocessorDefinitions );
			GetStringFromStruct( s, ".IncludeSearchPath",		newConfig.m_IncludeSearchPath );
			GetStringFromStruct( s, ".ForcedIncludes",			newConfig.m_ForcedIncludes );
			GetStringFromStruct( s, ".AssemblySearchPath",		newConfig.m_AssemblySearchPath );
			GetStringFromStruct( s, ".ForcedUsingAssemblies",	newConfig.m_ForcedUsingAssemblies );
			GetStringFromStruct( s, ".AdditionalOptions",		newConfig.m_AdditionalOptions );
			GetStringFromStruct( s, ".OutputDirectory",			newConfig.m_OutputDirectory );
			GetStringFromStruct( s, ".IntermediateDirectory",	newConfig.m_IntermediateDirectory );
		 	GetStringFromStruct( s, ".LayoutDir",				newConfig.m_LayoutDir );
			GetStringFromStruct( s, ".LayoutExtensionFilter",	newConfig.m_LayoutExtensionFilter );
			GetStringFromStruct( s, ".Xbox360DebuggerCommand",	newConfig.m_Xbox360DebuggerCommand );
			GetStringFromStruct( s, ".DebuggerFlavor",			newConfig.m_DebuggerFlavor );
			GetStringFromStruct( s, ".AumidOverride",			newConfig.m_AumidOverride );
			GetStringFromStruct( s, ".PlatformToolset",			newConfig.m_PlatformToolset );
			GetStringFromStruct( s, ".DeploymentType",			newConfig.m_DeploymentType );
			GetStringFromStruct( s, ".DeploymentFiles",			newConfig.m_DeploymentFiles );
			GetStringFromStruct( s, ".LocalDebuggerCommandArguments",	newConfig.m_LocalDebuggerCommandArguments );
			GetStringFromStruct( s, ".LocalDebuggerWorkingDirectory",	newConfig.m_LocalDebuggerWorkingDirectory );
			GetStringFromStruct( s, ".LocalDebuggerCommand",			newConfig.m_LocalDebuggerCommand );
			GetStringFromStruct( s, ".LocalDebuggerEnvironment",		newConfig.m_LocalDebuggerEnvironment );

			configs.Append( newConfig );
		}
	}
	else
	{
		// no user specified configs, make some defaults

		// start from the default
		VSProjectConfig config( baseConfig );

		// make the configs
		config.m_Platform	= "Win32";
		config.m_Config		= "Debug";
		configs.Append( config );
		config.m_Config		= "Release";
		configs.Append( config );
		config.m_Platform	= "x64";
		configs.Append( config );
		config.m_Config		= "Debug";
		configs.Append( config );
	}

	NodeGraph & ng = FBuild::Get().GetDependencyGraph();

	// create all of the DirectoryListNodes we need
	Dependencies dirNodes( inputPaths.GetSize() );
	if ( !GetDirectoryListNodeList( funcStartIter, inputPaths, Array< AString >(), Array< AString >(), true, nullptr, "ProjectInputPaths", dirNodes ) )
	{
		return false; // GetDirectoryListNodeList will have emitted an error
	}

	// Check for existing node
	if ( ng.FindNode( projectOutput ) )
	{
		Error::Error_1100_AlreadyDefined( funcStartIter, this, projectOutput );
		return false;
	}

	VCXProjectNode * pn = ng.CreateVCXProjectNode( projectOutput,
												   basePaths,
												   dirNodes,
												   inputPathsExclude, // TODO:B Remove this (handled by DirectoryListNode now)
												   allowedFileExtensions, // TODO:B Remove this (handled by DirectoryListNode now)
												   files,
												   filesToExclude,
												   rootNamespace,
												   projectGuid,
												   defaultLanguage,
												   applicationEnvironment,
												   configs,
												   fileTypes,
												   references,
												   projectReferences );

	ASSERT( pn );

	return ProcessAlias( funcStartIter, pn );
}
Example #22
0
// WriteProjectListings
//------------------------------------------------------------------------------
void SLNGenerator::WriteProjectListings(    const AString& solutionBasePath,
        const AString& solutionBuildProject,
        const Array< VCXProjectNode * > & projects,
        const Array< SLNSolutionFolder > & folders,
        const Array< SLNDependency > & slnDeps,
        AString & solutionBuildProjectGuid,
        Array< AString > & projectGuids,
        Array< AString > & solutionProjectsToFolder )
{
    // Project Listings

    VCXProjectNode ** const projectsEnd = projects.End();
    for( VCXProjectNode ** it = projects.Begin() ; it != projectsEnd ; ++it )
    {
        // check if this project is the master project
        const bool projectIsActive = ( solutionBuildProject.CompareI( (*it)->GetName() ) == 0 );

        AStackString<> projectPath( (*it)->GetName() );

        // get project base name only
        const char * lastSlash  = projectPath.FindLast( NATIVE_SLASH );
        const char * lastPeriod = projectPath.FindLast( '.' );
        AStackString<> projectName( lastSlash  ? lastSlash + 1  : projectPath.Get(),
                                    lastPeriod ? lastPeriod		: projectPath.GetEnd() );

        // retrieve projectGuid
        AStackString<> projectGuid;
        if ( (*it)->GetProjectGuid().GetLength() == 0 )
        {
            // For backward compatibility, keep the preceding slash and .vcxproj extension for GUID generation
            AStackString<> projectNameForGuid( lastSlash ? lastSlash : projectPath.Get() );
            VSProjectGenerator::FormatDeterministicProjectGUID( projectGuid, projectNameForGuid );
        }
        else
        {
            projectGuid = (*it)->GetProjectGuid();
        }

        // make project path relative
        projectPath.Replace( solutionBasePath.Get(), "" );

        // projectGuid must be uppercase (visual does that, it changes the .sln otherwise)
        projectGuid.ToUpper();

        if ( projectIsActive )
        {
            ASSERT( solutionBuildProjectGuid.GetLength() == 0 );
            solutionBuildProjectGuid = projectGuid;
        }

        Write( "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"%s\", \"%s\", \"%s\"\r\n",
               projectName.Get(), projectPath.Get(), projectGuid.Get() );

        // Manage dependencies
        Array< AString > dependencyGUIDs( 64, true );
        const AString & fullProjectPath = (*it)->GetName();
        for ( const SLNDependency & deps : slnDeps )
        {
            // is the set of deps relevant to this project?
            if ( deps.m_Projects.Find( fullProjectPath ) )
            {
                // get all the projects this project depends on
                for ( const AString & dependency : deps.m_Dependencies )
                {
                    // For backward compatibility, keep the preceding slash and .vcxproj extension for GUID generation
                    const char * projNameFromSlash = dependency.FindLast( NATIVE_SLASH );
                    AStackString<> projectNameForGuid( projNameFromSlash ? projNameFromSlash : dependency.Get() );

                    AStackString<> newGUID;
                    VSProjectGenerator::FormatDeterministicProjectGUID( newGUID, projectNameForGuid );
                    dependencyGUIDs.Append( newGUID );
                }
            }
        }
        if ( !dependencyGUIDs.IsEmpty() )
        {
            Write( "\tProjectSection(ProjectDependencies) = postProject\r\n" );
            for ( const AString & guid : dependencyGUIDs )
            {
                Write( "\t\t%s = %s\r\n", guid.Get(), guid.Get() );
            }
            Write( "\tEndProjectSection\r\n" );
        }

        Write( "EndProject\r\n" );

        projectGuids.Append( projectGuid );

        // check if this project is in a solution folder
        const SLNSolutionFolder * const foldersEnd = folders.End();
        for ( const SLNSolutionFolder * it2 = folders.Begin() ; it2 != foldersEnd ; ++it2 )
        {
            // this has to be done here to have the same order of declaration (like visual)
            if ( it2->m_ProjectNames.Find( (*it)->GetName() ) )
            {
                // generate a guid for the solution folder
                AStackString<> solutionFolderGuid;
                VSProjectGenerator::FormatDeterministicProjectGUID( solutionFolderGuid, it2->m_Path );

                solutionFolderGuid.ToUpper();

                AStackString<> projectToFolder;
                projectToFolder.Format( "\t\t%s = %s\r\n", projectGuid.Get(), solutionFolderGuid.Get() );

                solutionProjectsToFolder.Append( projectToFolder );
            }
        }
    }
}
Example #23
0
// CreateOverview
//------------------------------------------------------------------------------
void Report::CreateOverview( const FBuildStats & stats )
{
	DoSectionTitle( "Overview", "overview" );

	AStackString<> buffer;

	DoTableStart();

	// Headings
	Write( "<tr><th width=150>Item</th><th>Details</th></tr>\n" );

	// Full command line
    AStackString<> commandLineBuffer;
    Env::GetCmdLine( commandLineBuffer );
    #if defined( __WINDOWS__ )
        const char * exeExtension = strstr( commandLineBuffer.Get(), ".exe\"" );
        const char * commandLine = exeExtension ? ( exeExtension + 5 ) : commandLineBuffer.Get(); // skip .exe + closing quote
    #else
        const char * commandLine = commandLineBuffer.Get();
    #endif
	Write( "<tr><td width=80>Cmd Line Options</td><td>%s</td></tr>", commandLine );

	// Target
	AStackString<> targets;
	const Node * rootNode = stats.GetRootNode();
	if (rootNode->GetType() != Node::PROXY_NODE)
	{
		targets = rootNode->GetName();
	}
	else
	{
		const Dependencies & childNodes = rootNode->GetStaticDependencies();
		size_t num = childNodes.GetSize();
		for ( size_t i=0; i<num; ++i )
		{
			if ( i != 0 )
			{
				targets += ", ";
			}
			const Node * child = childNodes[ i ].GetNode();
			targets += child->GetName();
		}
	}
	Write( "<tr><td>Target(s)</td><td>%s</td></tr>\n", targets.Get() );

	// Result
	const bool buildOK = ( stats.GetRootNode()->GetState() == Node::UP_TO_DATE );
	Write( "<tr><td>Result</td><td>%s</td></tr>\n", buildOK ? "OK" : "FAILED" );

	// Real Time
	float totalBuildTime = stats.m_TotalBuildTime;
	stats.FormatTime( totalBuildTime, buffer );
	Write( "<tr><td>Time</td><td>%s</td></tr>\n", buffer.Get() );

	// Local CPU Time 
	float totalLocalCPUInSeconds = (float)( (double)stats.m_TotalLocalCPUTimeMS / (double)1000 );
	stats.FormatTime( totalLocalCPUInSeconds, buffer );
	float localRatio = ( totalLocalCPUInSeconds / totalBuildTime );
	Write( "<tr><td>CPU Time</td><td>%s (%2.1f:1)</td></tr>\n", buffer.Get(), localRatio );

	// version info
	Write( "<tr><td>Version</td><td>%s %s</td></tr>\n", FBUILD_VERSION_STRING, FBUILD_VERSION_PLATFORM );

	// report time
	char timeBuffer[ 256 ];
	#if defined( __WINDOWS__ )
		VERIFY( ::GetTimeFormat( LOCALE_NAME_USER_DEFAULT,		// LCID Locale
								 TIME_FORCE24HOURFORMAT,		// DWORD dwFlags
								 nullptr,						// SYSTEMTIME *lpTime
								 nullptr,						// LPCTSTR lpFormat,
								 timeBuffer,					// LPTSTR lpTimeStr,
								 256 ) );						// int cchTime
	#elif defined( __APPLE__ )
		timeBuffer[ 0 ] = '\000'; // TODO:MAC Implement GetTimeFormat in Report
	#elif defined( __LINUX__ )
		timeBuffer[ 0 ] = '\000'; // TODO:LINUX Implement GetTimeFormat in Report
	#else
		#error Unknown platform
	#endif

	char dateBuffer[ 256 ];
	#if defined( __WINDOWS__ )
		VERIFY( ::GetDateFormat( LOCALE_NAME_USER_DEFAULT,		// LCID Locale
								 DATE_LONGDATE,					// DWORD dwFlags
								 nullptr,						// SYSTEMTIME *lpTime
								 nullptr,						// LPCTSTR lpFormat,
								 dateBuffer,					// LPTSTR lpTimeStr,
								 256 ) );						// int cchTime
	#elif defined( __APPLE__ )
		dateBuffer[ 0 ] = '\000'; // TODO:MAC Implement GetDateFormat in Report
	#elif defined( __LINUX__ )
		dateBuffer[ 0 ] = '\000'; // TODO:LINUX Implement GetDateFormat in Report
	#else
		#error Unknown platform
	#endif

	// NOTE: leave space to patch in time taken later "^^^^                          "
	Write( "<tr><td>Report Generated</td><td>^^^^                         - %s %s</td></tr>\n", dateBuffer, timeBuffer );

	DoTableStop();
}
Example #24
0
// Commit
//------------------------------------------------------------------------------
/*virtual*/ bool FunctionLibrary::Commit( NodeGraph & nodeGraph, const BFFIterator & funcStartIter ) const
{
    // make sure all required variables are defined
    const BFFVariable * outputLib;
    const BFFVariable * compiler;
    const BFFVariable * compilerOptions;
    AStackString<> compilerOptionsDeoptimized;
    AStackString<> compilerOutputPath;
    AStackString<> compilerOutputPrefix;
    const BFFVariable * compilerOutputExtension;
    const BFFVariable * librarian;
    const BFFVariable * librarianOptions;
    if ( !GetString( funcStartIter, outputLib, ".LibrarianOutput", true ) ||
         !GetString( funcStartIter, compiler, ".Compiler", true ) ||
         !GetString( funcStartIter, compilerOptions, ".CompilerOptions", true ) ||
         !GetString( funcStartIter, compilerOptionsDeoptimized, ".CompilerOptionsDeoptimized", false ) ||
         !GetString( funcStartIter, compilerOutputPath, ".CompilerOutputPath", true ) ||
         !GetString( funcStartIter, compilerOutputPrefix, ".CompilerOutputPrefix", false ) ||
         !GetString( funcStartIter, compilerOutputExtension, ".CompilerOutputExtension", false ) ||
         !GetString( funcStartIter, librarian, ".Librarian", true ) ||
         !GetString( funcStartIter, librarianOptions, ".LibrarianOptions", true ) )
    {
        return false;
    }

    PathUtils::FixupFolderPath( compilerOutputPath );

    // find or create the compiler node
    CompilerNode * compilerNode = nullptr;
    if ( !FunctionObjectList::GetCompilerNode( nodeGraph, funcStartIter, compiler->GetString(), compilerNode ) )
    {
        return false; // GetCompilerNode will have emitted error
    }

    // Compiler Force Using
    Dependencies compilerForceUsing;
    if ( !GetNodeList( nodeGraph, funcStartIter, ".CompilerForceUsing", compilerForceUsing, false ) )
    {
        return false; // GetNodeList will have emitted an error
    }

    // de-optimization setting
    bool deoptimizeWritableFiles = false;
    bool deoptimizeWritableFilesWithToken = false;
    if ( !GetBool( funcStartIter, deoptimizeWritableFiles, ".DeoptimizeWritableFiles", false, false ) )
    {
        return false; // GetBool will have emitted error
    }
    if ( !GetBool( funcStartIter, deoptimizeWritableFilesWithToken, ".DeoptimizeWritableFilesWithToken", false, false ) )
    {
        return false; // GetBool will have emitted error
    }
    if ( ( deoptimizeWritableFiles || deoptimizeWritableFilesWithToken ) && compilerOptionsDeoptimized.IsEmpty() )
    {
        Error::Error_1101_MissingProperty( funcStartIter, this, AStackString<>( ".CompilerOptionsDeoptimized" ) );
        return false;
    }

    // cache & distribution control
    bool allowDistribution( true );
    bool allowCaching( true );
    if ( !GetBool( funcStartIter, allowDistribution, ".AllowDistribution", true ) ||
         !GetBool( funcStartIter, allowCaching, ".AllowCaching", true ) )
    {
        return false; // GetBool will have emitted error
    }

    // Precompiled Header support
    ObjectNode * precompiledHeaderNode = nullptr;
    AStackString<> compilerOutputExtensionStr( compilerOutputExtension ? compilerOutputExtension->GetString().Get() : ".obj" );
    if ( !GetPrecompiledHeaderNode( nodeGraph, funcStartIter, compilerNode, compilerOptions, compilerForceUsing, precompiledHeaderNode, deoptimizeWritableFiles, deoptimizeWritableFilesWithToken, allowDistribution, allowCaching, compilerOutputExtensionStr ) )
    {
        return false; // GetPrecompiledHeaderNode will have emitted error
    }

    // Sanity check compile flags
    const bool usingPCH = ( precompiledHeaderNode != nullptr );
    uint32_t objFlags = ObjectNode::DetermineFlags( compilerNode, compilerOptions->GetString(), false, usingPCH );
    if ( ( objFlags & ObjectNode::FLAG_MSVC ) && ( objFlags & ObjectNode::FLAG_CREATING_PCH ) )
    {
        // must not specify use of precompiled header (must use the PCH specific options)
        Error::Error_1303_PCHCreateOptionOnlyAllowedOnPCH( funcStartIter, this, "Yc", "CompilerOptions" );
        return false;
    }

    // Check input/output for Compiler
    {
        bool hasInputToken = false;
        bool hasOutputToken = false;
        bool hasCompileToken = false;

        const AString & args = compilerOptions->GetString();
        Array< AString > tokens;
        args.Tokenize( tokens );
        for ( const AString & token : tokens )
        {
            if ( token.Find( "%1" ) )
            {
                hasInputToken = true;
            }
            else if ( token.Find( "%2" ) )
            {
                hasOutputToken = true;
            }
            else
            {
                if ( objFlags & ObjectNode::FLAG_MSVC )
                {
                    if ( ( token == "/c" ) || ( token == "-c" ) )
                    {
                        hasCompileToken = true;
                    }
                }
                else
                {
                    if ( token == "-c" )
                    {
                        hasCompileToken = true;
                    }
                }
            }
        }

        if ( hasInputToken == false )
        {
            Error::Error_1106_MissingRequiredToken( funcStartIter, this, ".CompilerOptions", "%1" );
            return false;
        }
        if ( hasOutputToken == false )
        {
            Error::Error_1106_MissingRequiredToken( funcStartIter, this, ".CompilerOptions", "%2" );
            return false;
        }

        // check /c or -c
        if ( objFlags & ObjectNode::FLAG_MSVC )
        {
            if ( hasCompileToken == false )
            {
                Error::Error_1106_MissingRequiredToken( funcStartIter, this, ".CompilerOptions", "/c or -c" );
                return false;
            }
        }
        else if ( objFlags & ( ObjectNode::FLAG_SNC | ObjectNode::FLAG_GCC | ObjectNode::FLAG_CLANG ) )
        {
            if ( hasCompileToken == false )
            {
                Error::Error_1106_MissingRequiredToken( funcStartIter, this, ".CompilerOptions", "-c" );
                return false;
            }
        }
    }

    // Check input/output for Librarian
    {
        const AString & args = librarianOptions->GetString();
        bool hasInputToken = ( args.Find( "%1" ) || args.Find( "\"%1\"" ) );
        if ( hasInputToken == false )
        {
            Error::Error_1106_MissingRequiredToken( funcStartIter, this, ".LibrarianOptions", "%1" );
            return false;
        }
        bool hasOutputToken = ( args.Find( "%2" ) || args.Find( "\"%2\"" ) );
        if ( hasOutputToken == false )
        {
            Error::Error_1106_MissingRequiredToken( funcStartIter, this, ".LibrarianOptions", "%2" );
            return false;
        }
    }

    // Get the (optional) Preprocessor & PreprocessorOptions
    const BFFVariable * preprocessor = nullptr;
    const BFFVariable * preprocessorOptions = nullptr;
    CompilerNode * preprocessorNode = nullptr;
    if ( !GetString( funcStartIter, preprocessor, ".Preprocessor", false ) )
    {
        return false; // GetString will have emitted an error
    }
    if ( preprocessor )
    {
        // get the preprocessor executable
        if ( !FunctionObjectList::GetCompilerNode( nodeGraph, funcStartIter, preprocessor->GetString(), preprocessorNode ) )
        {
            return false; // GetCompilerNode will have emitted an error
        }

        // get the command line args for the preprocessor
        if ( !GetString( funcStartIter, preprocessorOptions, ".PreprocessorOptions", true ) ) // required
        {
            return false; // GetString will have emitted an error
        }
    }

    // Pre-build dependencies
    Dependencies preBuildDependencies;
    if ( !GetNodeList( nodeGraph, funcStartIter, ".PreBuildDependencies", preBuildDependencies, false ) )
    {
        return false; // GetNodeList will have emitted an error
    }

    Dependencies staticDeps( 32, true );
    if ( !GetInputs( nodeGraph, funcStartIter, staticDeps ) )
    {
        return false; // GetStaticDeps will gave emitted error
    }

    // are the additional inputs to merge into the libaray?
    Dependencies additionalInputs;
    if ( !GetNodeList( nodeGraph, funcStartIter, ".LibrarianAdditionalInputs", additionalInputs, false ) )
    {
        return false;// helper will emit error
    }

    if ( staticDeps.IsEmpty() && additionalInputs.IsEmpty() )
    {
        Error::Error_1006_NothingToBuild( funcStartIter, this );
        return false;
    }

    uint32_t flags = LibraryNode::DetermineFlags( librarian->GetString() );

    // Create library node which depends on the single file or list
    if ( nodeGraph.FindNode( outputLib->GetString() ) )
    {
        Error::Error_1100_AlreadyDefined( funcStartIter, this, outputLib->GetString() );
        return false;
    }

    AStackString<> baseDirectory;
    if ( !GetBaseDirectory( funcStartIter, baseDirectory ) )
    {
        return false; // GetBaseDirectory will have emitted error
    }

    AStackString<> extraPDBPath, extraASMPath;
    GetExtraOutputPaths( compilerOptions->GetString(), extraPDBPath, extraASMPath );

    LibraryNode * libNode = nodeGraph.CreateLibraryNode( outputLib->GetString(),
                          staticDeps,
                          compilerNode,
                          compilerOptions->GetString(),
                          compilerOptionsDeoptimized,
                          compilerOutputPath,
                          librarian->GetString(),
                          librarianOptions->GetString(),
                          flags,
                          precompiledHeaderNode,
                          compilerForceUsing,
                          preBuildDependencies,
                          additionalInputs,
                          deoptimizeWritableFiles,
                          deoptimizeWritableFilesWithToken,
                          allowDistribution,
                          allowCaching,
                          preprocessorNode,
                          preprocessorOptions ? preprocessorOptions->GetString() : AString::GetEmpty(),
                          baseDirectory );
    if ( compilerOutputExtension )
    {
        libNode->m_ObjExtensionOverride = compilerOutputExtension->GetString();
    }
    libNode->m_CompilerOutputPrefix = compilerOutputPrefix;
    libNode->m_ExtraPDBPath = extraPDBPath;
    libNode->m_ExtraASMPath = extraASMPath;

    return ProcessAlias( nodeGraph, funcStartIter, libNode );
}
Example #25
0
	/*static*/ bool ReflectionInfo::WriteDefinitions()
	{
		uint32_t numProblems = 0;

		const ReflectionInfo * ri = s_FirstReflectionInfo;
		for ( ; ri != nullptr; ri = ri->m_Next )
		{
			// ignore abstract classes
			if ( ri->IsAbstract() )
			{
				continue;
			}

			// Serialize a default instance to a MemoryStream 
			MemoryStream ms;
			{
				// Create and serialize default instance
				if ( ri->IsObject() )
				{
					RefObject * object = ri->CreateObject();
					{
						TextWriter tw( ms );
						tw.Write( object );
					}
					FDELETE( object );
				}
				else
				{
					ASSERT( ri->IsStruct() )
					Struct * str = ri->CreateStruct();
					{
						TextWriter tw( ms );
						tw.Write( str, ri );
					}
					FDELETE( str );
				}
			}

			AStackString<> fileName; 
			fileName.Format( "..\\Data\\Reflection\\.Definitions\\%s.definition", ri->GetTypeName() );

			// avoid writing file if not changed

			// Try to open existing file
			FileStream f;
			if ( f.Open( fileName.Get(), FileStream::READ_ONLY ) )
			{
				// read content
				const uint64_t fileSize = f.GetFileSize();
				if ( fileSize == ms.GetSize() )
				{
					AutoPtr< char > mem( (char *)Alloc( (size_t)fileSize ) );
					if ( f.Read( mem.Get(), (size_t)fileSize ) == fileSize )
					{
						if ( memcmp( mem.Get(), ms.GetData(), (size_t)fileSize ) == 0 )
						{
							continue; // definition has not changed
						}
					}
				}
				f.Close();
			}

			// Definition changed - try to save it

			int result = 0;
			AutoPtr< char > memOut;
			AutoPtr< char > memErr;
			uint32_t memOutSize;
			uint32_t memErrSize;

			// existing definition?
			if ( FileIO::FileExists( fileName.Get() ) )
			{
				// existing - need to open for edit?
				if ( FileIO::GetReadOnly( fileName ) )
				{
					AStackString<> args( "edit " );
					args += fileName;
					Process p;
					if ( p.Spawn( "p4", args.Get(), nullptr, nullptr ) )
					{
						p.ReadAllData( memOut, &memOutSize, memErr, &memErrSize );
						result = p.WaitForExit();
					}
				}
			}
			else
			{
				// new - open for add
				AStackString<> args( "add " );
				args += fileName;
				Process p;
				if ( p.Spawn( "p4", args.Get(), nullptr, nullptr ) )
				{
					p.ReadAllData( memOut, &memOutSize, memErr, &memErrSize );
					result = p.WaitForExit();
				}
			}

			if ( result == 0 )
			{ 
				if ( f.Open( fileName.Get(), FileStream::WRITE_ONLY ) )
				{
					if ( f.Write( ms.GetData(), ms.GetSize() ) == ms.GetSize() )
					{
						continue; // all ok!
					}
				}
			}

			// PROBLEM!
			OUTPUT( "Error writing definition '%s'\n", fileName.Get() );
			if ( result != 0 )
			{
				OUTPUT( "Perforce error: %s\n", memErr.Get() );
			}
			++numProblems;
		}
		if ( numProblems > 0 )
		{
			FATALERROR( "Problem writing %u definition(s).\n", numProblems );
		}
		return ( numProblems == 0 );
	}
Example #26
0
// Deserialize
//------------------------------------------------------------------------------
void ToolManifest::Deserialize( IOStream & ms )
{
	ms.Read( m_ToolId );

	ASSERT( m_Files.IsEmpty() );

	uint32_t numFiles( 0 );
	ms.Read( numFiles );
	m_Files.SetCapacity( numFiles );

	for ( size_t i=0; i<(size_t)numFiles; ++i )
	{		
		AStackString<> name;
		uint64_t timeStamp( 0 );
		uint32_t hash( 0 );
		uint32_t contentSize( 0 );
		ms.Read( name );
		ms.Read( timeStamp );
		ms.Read( hash );
		ms.Read( contentSize );
		m_Files.Append( File( name, timeStamp, hash, nullptr, contentSize ) );
	}

	// determine if any files are remaining from a previous run
	size_t numFilesAlreadySynchronized = 0;
	for ( size_t i=0; i<(size_t)numFiles; ++i )
	{
		AStackString<> localFile;
		GetRemoteFilePath( (uint32_t)i, localFile );

		// is this file already present?
		AutoPtr< FileStream > fileStream( FNEW( FileStream ) );
		FileStream & f = *( fileStream.Get() );
		if ( f.Open( localFile.Get() ) == false )
		{
			continue; // file not found
		}
		if ( f.GetFileSize() != m_Files[ i ].m_ContentSize )
		{
			continue; // file is not complete
		}
		AutoPtr< char > mem( (char *)ALLOC( (size_t)f.GetFileSize() ) );
		if ( f.Read( mem.Get(), (size_t)f.GetFileSize() ) != f.GetFileSize() )
		{
			continue; // problem reading file
		}
		if( Murmur3::Calc32( mem.Get(), (size_t)f.GetFileSize() ) != m_Files[ i ].m_Hash )
		{
			continue; // file contents unexpected
		}

		// file present and ok
		m_Files[ i ].m_FileLock = fileStream.Release(); // NOTE: keep file open to prevent deletions
		m_Files[ i ].m_SyncState = File::SYNCHRONIZED;
		numFilesAlreadySynchronized++;
	}

	// Generate Environment
	ASSERT( m_RemoteEnvironmentString == nullptr );

	// PATH=
	AStackString<> basePath;
	GetRemotePath( basePath );
	AStackString<> paths;
	paths.Format( "PATH=%s", basePath.Get() );

	// TMP=
	AStackString<> normalTmp;
	Env::GetEnvVariable( "TMP", normalTmp );
	AStackString<> tmp;
	tmp.Format( "TMP=%s", normalTmp.Get() );

	// SystemRoot=
	AStackString<> sysRoot( "SystemRoot=C:\\Windows" );

	char * mem = (char *)ALLOC( paths.GetLength() + 1 +
								  tmp.GetLength() + 1 +
								  sysRoot.GetLength() + 1 +
								  1 );
	m_RemoteEnvironmentString = mem;

	AString::Copy( paths.Get(), mem, paths.GetLength() + 1 ); // including null
	mem += ( paths.GetLength() + 1 ); // including null

	AString::Copy( tmp.Get(), mem, tmp.GetLength() + 1 ); // including null
	mem += ( tmp.GetLength() + 1 ); // including null

	AString::Copy( sysRoot.Get(), mem, sysRoot.GetLength() + 1 ); // including null
	mem += ( sysRoot.GetLength() + 1 ); // including null

	*mem = 0; ++mem; // double null

	// are all files already present?
	if ( numFilesAlreadySynchronized == m_Files.GetSize() )
	{
		m_Synchronized = true;		
	}
}
Example #27
0
//------------------------------------------------------------------------------
/*virtual*/ bool FunctionPrint::ParseFunction( const BFFIterator & functionNameStart,
        const BFFIterator * functionBodyStartToken,
        const BFFIterator * functionBodyStopToken,
        const BFFIterator * functionHeaderStartToken,
        const BFFIterator * functionHeaderStopToken ) const
{
    (void)functionNameStart;
    (void)functionBodyStartToken;
    (void)functionBodyStopToken;

    if ( functionHeaderStartToken && functionHeaderStopToken &&
            ( functionHeaderStartToken->GetDistTo( *functionHeaderStopToken ) >= 1 ) )
    {
        BFFIterator start( *functionHeaderStartToken );
        ASSERT( *start == BFFParser::BFF_FUNCTION_ARGS_OPEN );
        start++;
        start.SkipWhiteSpace();

        // a quoted string?
        const char c = *start;
        if ( ( c == '"' ) || ( c == '\'' ) )
        {
            // find end of string
            BFFIterator stop( start );
            stop.SkipString( c );
            ASSERT( stop.GetCurrent() <= functionHeaderStopToken->GetCurrent() ); // should not be in this function if strings are not validly terminated

            // perform variable substitutions
            AStackString< 1024 > tmp;

            start++; // skip past opening quote
            if ( BFFParser::PerformVariableSubstitutions( start, stop, tmp ) == false )
            {
                return false; // substitution will have emitted an error
            }
            tmp += '\n';

            FLOG_BUILD_DIRECT( tmp.Get() );
        }
        else if ( c == BFFParser::BFF_DECLARE_VAR_INTERNAL ||
                  c == BFFParser::BFF_DECLARE_VAR_PARENT )
        {
            // find end of var name
            BFFIterator stop( start );
            AStackString< BFFParser::MAX_VARIABLE_NAME_LENGTH > varName;
            bool parentScope = false;
            if ( BFFParser::ParseVariableName( stop, varName, parentScope ) == false )
            {
                return false;
            }

            ASSERT( stop.GetCurrent() <= functionHeaderStopToken->GetCurrent() ); // should not be in this function if strings are not validly terminated

            const BFFVariable * var = nullptr;
            BFFStackFrame * const varFrame = ( parentScope )
                                             ? BFFStackFrame::GetParentDeclaration( varName, BFFStackFrame::GetCurrent()->GetParent(), var )
                                             : nullptr;

            if ( false == parentScope )
            {
                var = BFFStackFrame::GetVar( varName, nullptr );
            }

            if ( ( parentScope && ( nullptr == varFrame ) ) || ( nullptr == var ) )
            {
                Error::Error_1009_UnknownVariable( start, this );
                return false;
            }

            // dump the contents
            PrintVarRecurse( *var, 0 );
        }
        else
        {
            Error::Error_1001_MissingStringStartToken( start, this );
            return false;
        }
    }

    return true;
}
Example #28
0
// ReceiveFileData
//------------------------------------------------------------------------------
bool ToolManifest::ReceiveFileData( uint32_t fileId, const void * data, size_t & dataSize )
{
	MutexHolder mh( m_Mutex );

	File & f = m_Files[ fileId ];

	// gracefully handle multiple receipts of the same data
	if ( f.m_Content )
	{
		ASSERT( f.m_SyncState == File::SYNCHRONIZED );
		return true;
	}

	ASSERT( f.m_SyncState == File::SYNCHRONIZING );

	// prepare name for this file
	AStackString<> fileName;
	GetRemoteFilePath( fileId, fileName );

	// prepare destination
	AStackString<> pathOnly( fileName.Get(), fileName.FindLast( NATIVE_SLASH ) );
	if ( !FileIO::EnsurePathExists( pathOnly ) )
	{
		return false; // FAILED
	}

	// write to disk
	FileStream fs;
	if ( !fs.Open( fileName.Get(), FileStream::WRITE_ONLY ) )
	{
		return false; // FAILED
	}
	if ( fs.Write( data, dataSize ) != dataSize )
	{
		return false; // FAILED
	}
	fs.Close();

	// open read-only 
	AutoPtr< FileStream > fileStream( FNEW( FileStream ) );
	if ( fileStream.Get()->Open( fileName.Get(), FileStream::READ_ONLY ) == false )
	{
		return false; // FAILED
	}

	// This file is now synchronized
	f.m_FileLock = fileStream.Release(); // NOTE: Keep file open to prevent deletion
	f.m_SyncState = File::SYNCHRONIZED;

	// is completely synchronized?
	const File * const end = m_Files.End();
	for ( const File * it = m_Files.Begin(); it != end; ++it )
	{
		if ( it->m_SyncState != File::SYNCHRONIZED )
		{
			// still some files to be received
			return true; // file stored ok
		}
	}

	// all files received
	m_Synchronized = true;
	return true; // file stored ok
}
Example #29
0
// CompareHashTimes_Small
//------------------------------------------------------------------------------
void TestHash::CompareHashTimes_Small() const
{
	// some different strings to hash
	Array< AString > strings( 32, true );
	strings.Append( AString( " " ) );
	strings.Append( AString( "short" ) );
	strings.Append( AString( "mediumstringmediumstring123456789" ) );
	strings.Append( AString( "longstring_98274ncoif834jodhiorhmwe8r8wy48on87h8mhwejrijrdierwurd9j,8chm8hiuorciwriowjri" ) );
	strings.Append( AString( "c:\\files\\subdir\\project\\thing\\stuff.cpp" ) );
	const size_t numStrings = strings.GetSize();
	const size_t numIterations = 102400;

	// calc datasize
	size_t dataSize( 0 );
	for ( size_t i=0; i<numStrings; ++i )
	{
		dataSize += strings[ i ].GetLength();
	}
	dataSize *= numIterations;

	// xxHash - 32
	{
		Timer t;
		uint32_t crc( 0 );
		for ( size_t j=0; j<numIterations; ++j )
		{
			for ( size_t i=0; i<numStrings; ++i )
			{
				crc += xxHash::Calc32( strings[ i ].Get(), strings[ i ].GetLength() );
			}
		}
		float time = t.GetElapsed();
		float speed = ( (float)dataSize / (float)( 1024 * 1024 * 1024 ) ) / time;
		OUTPUT( "xxHash-32       : %2.3fs @ %6.3f GiB/s (hash: 0x%x)\n", time, speed, crc );
    }

	// xxHash - 64
	{
		Timer t;
		uint64_t crc( 0 );
		for ( size_t j=0; j<numIterations; ++j )
		{
			for ( size_t i=0; i<numStrings; ++i )
			{
				crc += xxHash::Calc64( strings[ i ].Get(), strings[ i ].GetLength() );
			}
		}
		float time = t.GetElapsed();
		float speed = ( (float)dataSize / (float)( 1024 * 1024 * 1024 ) ) / time;
		OUTPUT( "xxHash-64       : %2.3fs @ %6.3f GiB/s (hash: %016llx)\n", time, speed, crc );
    }

	// Murmur3 - 32
	{
		Timer t;
		uint32_t crc( 0 );
		for ( size_t j=0; j<numIterations; ++j )
		{
			for ( size_t i=0; i<numStrings; ++i )
			{
				crc += Murmur3::Calc32( strings[ i ].Get(), strings[ i ].GetLength() );
			}
		}
		float time = t.GetElapsed();
		float speed = ( (float)dataSize / (float)( 1024 * 1024 * 1024 ) ) / time;
		OUTPUT( "Murmur3-32      : %2.3fs @ %6.3f GiB/s (hash: 0x%x)\n", time, speed, crc );
	}

	// Murmur3 - 128
	{
		Timer t;
		uint64_t hashB( 0 );
		uint64_t hashA( 0 );
		for ( size_t j=0; j<numIterations; ++j )
		{
			for ( size_t i=0; i<numStrings; ++i )
			{
				hashA += Murmur3::Calc128( strings[ i ].Get(), strings[ i ].GetLength(), hashB );
			}
		}
		float time = t.GetElapsed();
		float speed = ( (float)dataSize / (float)( 1024 * 1024 * 1024 ) ) / time;
		OUTPUT( "Murmur3-128     : %2.3fs @ %6.3f GiB/s (%016llx, %016llx)\n", time, speed, hashA, hashB );
	}

	// CRC32 - 8x8 slicing
	{
		Timer t;
		uint32_t crc( 0 );
		for ( size_t j=0; j<numIterations; ++j )
		{
			for ( size_t i=0; i<numStrings; ++i )
			{
				crc += CRC32::Calc( strings[ i ].Get(), strings[ i ].GetLength() );
			}
		}
		float time = t.GetElapsed();
		float speed = ( (float)dataSize / (float)( 1024 * 1024 * 1024 ) ) / time;
		OUTPUT( "CRC32 8x8       : %2.3fs @ %6.3f GiB/s (hash: 0x%x)\n", time, speed, crc );
	}

	// CRC32 - "standard" algorithm
	{
		Timer t;
	    uint32_t crc( 0 );
		for ( size_t j=0; j<numIterations; ++j )
		{
			for ( size_t i=0; i<numStrings; ++i )
			{
				crc += CRC32::Start();
				crc += CRC32::Update( crc, strings[ i ].Get(), strings[ i ].GetLength() );
				crc += CRC32::Stop( crc );
			}
		}
		float time = t.GetElapsed();
		float speed = ( (float)dataSize / (float)( 1024 * 1024 * 1024 ) ) / time;
		OUTPUT( "CRC32           : %2.3fs @ %6.3f GiB/s (hash: 0x%x)\n", time, speed, crc );
	}

	// CRC32Lower
	{
		Timer t;
		uint32_t crc( 0 );
		for ( size_t j=0; j<numIterations; ++j )
		{
			for ( size_t i=0; i<numStrings; ++i )
			{
				crc += CRC32::CalcLower( strings[ i ].Get(), strings[ i ].GetLength() );
			}
		}
		float time = t.GetElapsed();
		float speed = ( (float)dataSize / (float)( 1024 * 1024 * 1024 ) ) / time;
		OUTPUT( "CRC32Lower      : %2.3fs @ %6.3f GiB/s (hash: 0x%x)\n", time, speed, crc );
	}

	// Murmur3 - 32 Lower
	{
		Timer t;

		// lower-case and hash it
		uint32_t crc( 0 );
		for ( size_t j=0; j<numIterations; ++j )
		{
			for ( size_t i=0; i<numStrings; ++i )
			{
				const AString & str( strings[ i ] );
				AStackString<> tmp;
				const size_t strLen( str.GetLength() );
				tmp.SetLength( (uint32_t)strLen );
				for ( size_t k=0; k<strLen; ++k )
				{
					char c = str[ (uint32_t)k ];
					tmp[ (uint32_t)k ] = ( ( c >= 'A' ) && ( c <= 'Z' ) ) ? 'a' + ( c - 'A' ) : c;
				}
				crc += Murmur3::Calc32( tmp.Get(), tmp.GetLength() );
			}
		}
		float time = t.GetElapsed();
		float speed = ( (float)dataSize / (float)( 1024 * 1024 * 1024 ) ) / time;
		OUTPUT( "Murmur3-32-Lower: %2.3fs @ %6.3f GiB/s (hash: 0x%x)\n", time, speed, crc );
	}
}
Example #30
0
// Spawn
//------------------------------------------------------------------------------
bool Process::Spawn( const char * executable,
					 const char * args,
					 const char * workingDir,
					 const char * environment,
					 bool shareHandles )
{
	ASSERT( !m_Started );
	ASSERT( executable );

    #if defined( __WINDOWS__ )
        // Set up the start up info struct.
        STARTUPINFO si;
        ZeroMemory( &si, sizeof(STARTUPINFO) );
		si.cb = sizeof( STARTUPINFO );
        si.dwFlags |= STARTF_USESHOWWINDOW;
        si.wShowWindow = SW_HIDE;
        
        SECURITY_ATTRIBUTES sa;
        ZeroMemory( &sa, sizeof( SECURITY_ATTRIBUTES ) );
        sa.nLength = sizeof(SECURITY_ATTRIBUTES);
        sa.bInheritHandle = TRUE;
        sa.lpSecurityDescriptor = nullptr;

		m_SharingHandles = shareHandles;

		if ( m_RedirectHandles )
		{
			// create the pipes
			if ( shareHandles )
			{
				si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
				si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
				si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
			}
			else
			{
				if ( ! CreatePipe( &m_StdOutRead, &m_StdOutWrite, &sa, MEGABYTE ) )
				{
					return false;
				}
				SetHandleInformation( m_StdOutRead, HANDLE_FLAG_INHERIT, 0 );

				if ( ! CreatePipe( &m_StdErrRead, &m_StdErrWrite, &sa, MEGABYTE ) )
				{
					VERIFY( CloseHandle( m_StdOutRead ) );
					VERIFY( CloseHandle( m_StdOutWrite ) );
					return false;
				}
				SetHandleInformation( m_StdErrRead, HANDLE_FLAG_INHERIT, 0 );

				si.hStdOutput = m_StdOutWrite;
				si.hStdError = m_StdErrWrite;
				si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); // m_StdInRead;
			}
			si.dwFlags |= STARTF_USESTDHANDLES;
		}
        
        // Make sure the first arg is the executable
        // We also need to make a copy, as CreateProcess can write back to this string
        AStackString< 1024 > fullArgs;
        fullArgs += '\"';
        fullArgs += executable;
        fullArgs += '\"';
		if ( args )
		{
	        fullArgs += ' ';
	        fullArgs += args;
		}
        //fullArgs.Format( "\"%s\" %s", executable, args );

        // create the child
        if ( !CreateProcess( nullptr, //executable,
                              fullArgs.Get(),
                              nullptr,
                              nullptr,
                              (BOOL)m_RedirectHandles, // inherit handles
                              0,
                              (void *)environment,
                              workingDir,
                              &si,
                              (LPPROCESS_INFORMATION)&m_ProcessInfo ) )
        {
            return false;
        }

        m_Started = true;
        return true;
	#elif defined( __LINUX__ ) || defined( __APPLE__ )
        // create StdOut and StdErr pipes to capture output of spawned process
        int stdOutPipeFDs[ 2 ]; 
        int stdErrPipeFDs[ 2 ];
        VERIFY( pipe( stdOutPipeFDs ) == 0 );
        VERIFY( pipe( stdErrPipeFDs ) == 0 );     
            
        // fork the process
        const pid_t childProcessPid = fork();
        if ( childProcessPid == -1 )
        {
            // cleanup pipes
            VERIFY( close( stdOutPipeFDs[ 0 ] ) == 0 );
            VERIFY( close( stdOutPipeFDs[ 1 ] ) == 0 );
            VERIFY( close( stdErrPipeFDs[ 0 ] ) == 0 );
            VERIFY( close( stdErrPipeFDs[ 1 ] ) == 0 );
            
            ASSERT( false ); // fork failed - should not happen in normal operation
            return false;
        }
       
        const bool isChild = ( childProcessPid == 0 );        
        if ( isChild )
        {
            VERIFY( dup2( stdOutPipeFDs[ 1 ], STDOUT_FILENO ) != -1 );
            VERIFY( dup2( stdErrPipeFDs[ 1 ], STDERR_FILENO ) != -1 );

            VERIFY( close( stdOutPipeFDs[ 0 ] ) == 0 );
            VERIFY( close( stdOutPipeFDs[ 1 ] ) == 0 );
            VERIFY( close( stdErrPipeFDs[ 0 ] ) == 0 );
            VERIFY( close( stdErrPipeFDs[ 1 ] ) == 0 );

            if ( workingDir )
            {
                FileIO::SetCurrentDir( AStackString<>( workingDir ) );
            }

            // split args
            AString fullArgs( args );
            Array< AString > splitArgs( 64, true );
            fullArgs.Tokenize( splitArgs );

            // prepare args
            const size_t numArgs = splitArgs.GetSize();
            char ** argv = FNEW( char *[ numArgs + 2 ] );
            argv[ 0 ] = const_cast< char * >( executable );
            for ( size_t i=0; i<numArgs; ++i )
            {
                AString & thisArg = splitArgs[ i ];
				if ( thisArg.BeginsWith( '"' ) && thisArg.EndsWith( '"' ) )
				{
					// strip quotes
					thisArg.SetLength( thisArg.GetLength() - 1 ); // trim end quote
	                argv[ i + 1 ] = thisArg.Get() + 1; // skip start quote
					continue;
				}
                argv[ i + 1 ] = thisArg.Get(); // leave arg as-is
            }
            argv[ numArgs + 1 ] = nullptr;                      
                                    
            // transfer execution to new executable
            execv( executable, argv );
            
            exit( -1 ); // only get here if execv fails
        }
        else
        {