Example #1
0
// DoDynamicDependencies
//------------------------------------------------------------------------------
/*virtual*/ bool CSNode::DoDynamicDependencies( bool UNUSED( forceClean ) )
{
	ASSERT( m_DynamicDependencies.GetSize() == 0 );

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

	// preallocate a reasonable amount of space
	m_DynamicDependencies.SetCapacity( m_StaticDependencies.GetSize() );

	// convert static deps to dynamic deps
	// (ignore the extra refs here)
	size_t numDeps = m_StaticDependencies.GetSize() - m_ExtraRefs.GetSize();
	for ( size_t i=0; i<numDeps; ++i ) 
	{
		Node * n = m_StaticDependencies[ i ].GetNode();

		if ( n->IsAFile() )
		{
			m_DynamicDependencies.Append( Dependency( n ) );
			continue;
		}

		if ( n->GetType() == Node::DIRECTORY_LIST_NODE )
		{
			// get the list of files
			DirectoryListNode * dln = n->CastTo< DirectoryListNode >();
			const Array< FileIO::FileInfo > & files = dln->GetFiles();
			m_DynamicDependencies.SetCapacity( m_DynamicDependencies.GetSize() + files.GetSize() );
			for ( Array< FileIO::FileInfo >::Iter fIt = files.Begin();
					fIt != files.End();
					fIt++ )
			{
				// Create the file node (or find an existing one)
				Node * sn = ng.FindNode( fIt->m_Name );
				if ( sn == nullptr )
				{
					sn = ng.CreateFileNode( fIt->m_Name );
				}
				else if ( sn->IsAFile() == false )
				{
					FLOG_ERROR( "CSAssembly() .CompilerInputFile '%s' is not a FileNode (type: %s)", n->GetName().Get(), n->GetTypeName() );
					return false;
				}

				m_DynamicDependencies.Append( Dependency( sn ) );
			}
			continue;
		}

		FLOG_ERROR( "'%s' is not a supported node type (type: %s)", n->GetName().Get(), n->GetTypeName() );
		return false;
	}

	return true;
}
Example #2
0
// GetOtherLibrary
//------------------------------------------------------------------------------
bool LinkerNode::GetOtherLibrary( NodeGraph & nodeGraph,
                                  const BFFIterator & iter,
                                  const Function * function,
                                  Dependencies & libs,
                                  const AString & path,
                                  const AString & lib,
                                  bool & found ) const
{
    found = false;

    AStackString<> potentialNodeName( path );
    if ( !potentialNodeName.IsEmpty() )
    {
        PathUtils::EnsureTrailingSlash( potentialNodeName );
    }
    potentialNodeName += lib;
    AStackString<> potentialNodeNameClean;
    NodeGraph::CleanPath( potentialNodeName, potentialNodeNameClean );

    // see if a node already exists
    Node * node = nodeGraph.FindNode( potentialNodeNameClean );
    if ( node )
    {
        // aliases not supported - must point to something that provides a file
        if ( node->IsAFile() == false )
        {
            Error::Error_1103_NotAFile( iter, function, ".LinkerOptions", potentialNodeNameClean, node->GetType() );
            return false;
        }

        // found existing node
        libs.Append( Dependency( node ) );
        found = true;
        return true; // no error
    }

    // see if the file exists on disk at this location
    if ( FileIO::FileExists( potentialNodeNameClean.Get() ) )
    {
        node = nodeGraph.CreateFileNode( potentialNodeNameClean );
        libs.Append( Dependency( node ) );
        found = true;
        FLOG_INFO( "Additional library '%s' assumed to be '%s'\n", lib.Get(), potentialNodeNameClean.Get() );
        return true; // no error
    }

    return true; // no error
}
Example #3
0
REGISTER_TESTS_END

// CreateNode
//------------------------------------------------------------------------------
void TestExe::CreateNode() const
{
    FBuild fb;
    NodeGraph & ng = fb.GetDependencyGraph();

    Dependencies inputLibraries( 1, false );
    inputLibraries.Append( Dependency( ng.CreateFileNode( AStackString<>( "dummy.lib" ) ) ) );

    ExeNode * exeNode = ng.CreateExeNode( AStackString<>( "exe.exe" ),
                                          inputLibraries,
                                          Dependencies(),
                                          AString::GetEmpty(),
                                          AStackString<>( "linker.exe" ),
                                          AString::GetEmpty(), // args
                                          0, // flags
                                          Dependencies(),
                                          AStackString<>(),
                                          nullptr,
                                          AString::GetEmpty() ); // assembly resources

    TEST_ASSERT( exeNode->GetType() == Node::EXE_NODE );
    TEST_ASSERT( ExeNode::GetTypeS() == Node::EXE_NODE );
    TEST_ASSERT( AStackString<>( "Exe" ) == exeNode->GetTypeName() );
}
Example #4
0
// DependOnNode
//------------------------------------------------------------------------------
/*static*/ bool LinkerNode::DependOnNode( NodeGraph & nodeGraph,
                                          const BFFIterator & iter,
                                          const Function * function,
                                          const AString & nodeName,
                                          Dependencies & nodes )
{
    // silently ignore empty nodes
    if ( nodeName.IsEmpty() )
    {
        return true;
    }

    Node * node = nodeGraph.FindNode( nodeName );

    // does it exist?
    if ( node != nullptr )
    {
        // process it
        return DependOnNode( iter, function, node, nodes );
    }

    // node not found - create a new FileNode, assuming we are
    // linking against an externally built library
    node = nodeGraph.CreateFileNode( nodeName );
    nodes.Append( Dependency( node ) );
    return true;
}
Example #5
0
// GetObjectListNodes
//------------------------------------------------------------------------------
bool Function::GetObjectListNodes( const BFFIterator & iter,
                                   const Array< AString > & objectLists,
                                   const char * inputVarName,
                                   Dependencies & nodes ) const
{
    NodeGraph & ng = FBuild::Get().GetDependencyGraph();

	const AString * const  end = objectLists.End();
	for ( const AString * it = objectLists.Begin(); it != end; ++it )
	{
		const AString & objectList = *it;

		// get node for the dir we depend on
		Node * node = ng.FindNode( objectList );
		if ( node == nullptr )
		{
            Error::Error_1104_TargetNotDefined( iter, this, inputVarName, objectList );
            return false;
        }
		else if ( node->GetType() != Node::OBJECT_LIST_NODE )
		{
			Error::Error_1102_UnexpectedType( iter, this, inputVarName, node->GetName(), node->GetType(), Node::OBJECT_LIST_NODE );
			return false;
		}

		nodes.Append( Dependency( node ) );
	}
	return true;
}
Example #6
0
void PluginManifest::Load(pugi::xml_document* doc)
{
    pugi::xml_node manifest = doc->child("PluginManifest");
    
    version = manifest.attribute("Version").as_int();
    name = manifest.attribute("Name").as_string();
    icon_url = manifest.attribute("IconUrl").as_string();
    screenshot_url = manifest.attribute("ScreenshotUrl").as_string();
    homepage_url = manifest.attribute("HomepageUrl").as_string();
    author = manifest.attribute("Author").as_string();
    release_date = manifest.attribute("ReleaseDate").as_string();
    version_major = manifest.attribute("VersionMajor").as_int();
    version_minor = manifest.attribute("VersionMinor").as_int();
    api_level_major = manifest.attribute("APILevelMajor").as_int();
    api_level_minor = manifest.attribute("APILevelMinor").as_int();
    
    plugin_name = manifest.child("PluginName").text().as_string();
    plugin_description = manifest.child("Description").text().as_string();
    
    for (pugi::xml_node node = manifest.child("CommonData"); node; node = node.next_sibling("CommonData"))
    {
        common_data.push_back(CommonData(&node));
    }
    
    for (pugi::xml_node node = manifest.child("PlatformData"); node; node = node.next_sibling("PlatformData"))
    {
        platform_data.push_back(PlatformData(&node));
    }
    
    for (pugi::xml_node node = manifest.child("Dependency"); node; node = node.next_sibling("Dependency"))
    {
        dependencies.push_back(Dependency(&node));
    }
}
Example #7
0
			Dependency& targetSet(Target& target,Target& target_from)
				{
				r_target=&target;
				nameFree();
				target.dependencyInverseAdd(Dependency(target_from,m_rel));
				return *this;
				}
Example #8
0
// GetDirectoryNodeList
//------------------------------------------------------------------------------
bool Function::GetDirectoryListNodeList( const BFFIterator & iter,
										 const Array< AString > & paths,
										 const Array< AString > & excludePaths,
                                         const Array< AString > & filesToExclude,
										 bool recurse,
										 const Array< AString > * patterns,
										 const char * inputVarName,
										 Dependencies & nodes ) const
{
	NodeGraph & ng = FBuild::Get().GetDependencyGraph();

	// Handle special case of excluded files beginning with ../
	// Since they can be used seinsibly by matching just the end
	// of a path, assume they are relative to the working dir.
	// TODO:C Move this during bff parsing when everything is using reflection
	Array< AString > filesToExcludeCleaned( filesToExclude.GetSize(), true );
	for ( const AString& file : filesToExclude )
	{
		if ( file.BeginsWith( ".." ) )
		{
			AStackString<> fullPath;
			NodeGraph::CleanPath( file, fullPath );
			filesToExcludeCleaned.Append( fullPath );
		}
		else
		{
			filesToExcludeCleaned.Append( file );
		}
	}

	const AString * const  end = paths.End();
	for ( const AString * it = paths.Begin(); it != end; ++it )
	{
		const AString & path = *it;

		// get node for the dir we depend on
		AStackString<> name;
		DirectoryListNode::FormatName( path, patterns, recurse, excludePaths, filesToExcludeCleaned, name );
		Node * node = ng.FindNode( name );
		if ( node == nullptr )
		{
			node = ng.CreateDirectoryListNode( name,
											   path,
											   patterns,
											   recurse,
											   excludePaths, 
                                               filesToExcludeCleaned );
		}
		else if ( node->GetType() != Node::DIRECTORY_LIST_NODE )
		{
			Error::Error_1102_UnexpectedType( iter, this, inputVarName, node->GetName(), node->GetType(), Node::DIRECTORY_LIST_NODE );
			return false;
		}

		nodes.Append( Dependency( node ) );
	}
	return true;
}
Example #9
0
// CONSTRUCTOR
//------------------------------------------------------------------------------
ExecNode::ExecNode( const AString & dstFileName,
                    FileNode * sourceFile,
                    FileNode * executable,
                    const AString & arguments,
                    const AString & workingDir,
                    int32_t expectedReturnCode,
                    const Dependencies & preBuildDependencies )
    : FileNode( dstFileName, Node::FLAG_NONE )
    , m_SourceFile( sourceFile )
    , m_Executable( executable )
    , m_Arguments( arguments )
    , m_WorkingDir( workingDir )
    , m_ExpectedReturnCode( expectedReturnCode )
{
    ASSERT( sourceFile );
    ASSERT( executable );
    m_StaticDependencies.SetCapacity( 2 );
    m_StaticDependencies.Append( Dependency( sourceFile ) );
    m_StaticDependencies.Append( Dependency( executable ) );
    m_Type = EXEC_NODE;

    m_PreBuildDependencies = preBuildDependencies;
}
Example #10
0
// Save
//------------------------------------------------------------------------------
/*virtual*/ void CSNode::Save( IOStream & stream ) const
{
	NODE_SAVE( m_Name );

	// Only save the original static deps here (remove the extra refs)
	size_t numBaseDeps = m_StaticDependencies.GetSize() - m_ExtraRefs.GetSize();
	Dependencies staticDeps( numBaseDeps, false );
	for ( size_t i=0; i<numBaseDeps; ++i )
	{
		staticDeps.Append( Dependency( m_StaticDependencies[ i ].GetNode() ) );
	}
	NODE_SAVE_DEPS( staticDeps );

	NODE_SAVE( m_CompilerPath );
	NODE_SAVE( m_CompilerArgs );
	NODE_SAVE_DEPS( m_ExtraRefs );
}
Example #11
0
// CONSTRUCTOR
//------------------------------------------------------------------------------
LinkerNode::LinkerNode( const AString & linkerOutputName,
                         const Dependencies & inputLibraries,
                         const Dependencies & otherLibraries,
                         const AString & linkerType,
                         const AString & linker,
                         const AString & linkerArgs,
                         uint32_t flags,
                         const Dependencies & assemblyResources,
                         const AString & importLibName,
                         Node * linkerStampExe,
                         const AString & linkerStampExeArgs )
: FileNode( linkerOutputName, Node::FLAG_NONE )
, m_Flags( flags )
, m_AssemblyResources( assemblyResources )
, m_OtherLibraries( otherLibraries )
, m_ImportLibName( importLibName )
, m_LinkerStampExe( linkerStampExe )
, m_LinkerStampExeArgs( linkerStampExeArgs )
{
    m_LastBuildTimeMs = 20000;

    // presize vector
    size_t numStaticDeps = inputLibraries.GetSize() + assemblyResources.GetSize() + otherLibraries.GetSize();
    if ( linkerStampExe )
    {
        numStaticDeps++;
    }
    m_StaticDependencies.SetCapacity( numStaticDeps );

    // depend on everything we'll link together
    m_StaticDependencies.Append( inputLibraries );
    m_StaticDependencies.Append( assemblyResources );
    m_StaticDependencies.Append( otherLibraries );

    // manage optional LinkerStampExe
    if ( linkerStampExe )
    {
        m_StaticDependencies.Append( Dependency( linkerStampExe ) );
    }

    // store options we'll need to use dynamically
    m_LinkerType = linkerType;
    m_Linker = linker; // TODO:C This should be a node
    m_LinkerArgs = linkerArgs;
}
Example #12
0
// GetFileNode
//------------------------------------------------------------------------------
bool Function::GetFileNode( NodeGraph & nodeGraph,
							const BFFIterator & iter,
                            const AString & file,
                            const char * inputVarName,
                            Dependencies & nodes ) const
{
	// get node for the dir we depend on
	Node * node = nodeGraph.FindNode( file );
	if ( node == nullptr )
	{
		node = nodeGraph.CreateFileNode( file );
    }
	else if ( node->IsAFile() == false )
	{
		Error::Error_1005_UnsupportedNodeType( iter, this, inputVarName, node->GetName(), node->GetType() );
		return false;
	}

	nodes.Append( Dependency( node ) );
	return true;
}
Example #13
0
// GetDirectoryNodeList
//------------------------------------------------------------------------------
bool Function::GetDirectoryListNodeList( const BFFIterator & iter,
										 const Array< AString > & paths,
										 const Array< AString > & excludePaths,
                                         const Array< AString > & filesToExclude,
										 bool recurse,
										 const AString & pattern,
										 const char * inputVarName,
										 Dependencies & nodes ) const
{
	NodeGraph & ng = FBuild::Get().GetDependencyGraph();

	const AString * const  end = paths.End();
	for ( const AString * it = paths.Begin(); it != end; ++it )
	{
		const AString & path = *it;

		// get node for the dir we depend on
		AStackString<> name;
		DirectoryListNode::FormatName( path, pattern, recurse, excludePaths, filesToExclude, name );
		Node * node = ng.FindNode( name );
		if ( node == nullptr )
		{
			node = ng.CreateDirectoryListNode( name,
											   path,
											   pattern,
											   recurse,
											   excludePaths, 
                                               filesToExclude );
		}
		else if ( node->GetType() != Node::DIRECTORY_LIST_NODE )
		{
			Error::Error_1102_UnexpectedType( iter, this, inputVarName, node->GetName(), node->GetType(), Node::DIRECTORY_LIST_NODE );
			return false;
		}

		nodes.Append( Dependency( node ) );
	}
	return true;
}
Example #14
0
// Load
//------------------------------------------------------------------------------
bool Dependencies::Load( NodeGraph & nodeGraph, IOStream & stream )
{
	uint32_t numDeps;
	if ( stream.Read( numDeps ) == false )
	{
		return false;
	}
	if ( GetCapacity() < GetSize() + numDeps )
	{
		SetCapacity( GetSize() + numDeps );
	}
	for ( uint32_t i=0; i<numDeps; ++i )
	{
		// Read node index
		uint32_t index( INVALID_NODE_INDEX );
		if ( stream.Read( index ) == false )
		{
			return false;
		}

		// Convert to Node *
		Node * node = nodeGraph.GetNodeByIndex( index );
		ASSERT( node );

		// Read weak flag
		bool isWeak( false );
		if ( stream.Read( isWeak ) == false )
		{
			return false;
		}

		// Recombine dependency info
		Append( Dependency( node, isWeak ) );
	}
	return true;
}
Example #15
0
// CONSTRUCTOR
//------------------------------------------------------------------------------
SLNNode::SLNNode(   const AString & solutionOuput,
                    const AString & solutionBuildProject,
                    const AString & solutionVisualStudioVersion,
                    const AString & solutionMinimumVisualStudioVersion,
                    const Array< VSProjectConfig > & configs,
                    const Array< VCXProjectNode * > & projects,
                    const Array< SLNSolutionFolder > & folders )
: FileNode( solutionOuput, Node::FLAG_NONE )
, m_SolutionBuildProject( solutionBuildProject )
, m_SolutionVisualStudioVersion( solutionVisualStudioVersion )
, m_SolutionMinimumVisualStudioVersion( solutionMinimumVisualStudioVersion )
, m_Configs( configs )
, m_Folders( folders )
{
    m_LastBuildTimeMs = 100; // higher default than a file node
    m_Type = Node::SLN_NODE;

    // depend on the input nodes
    VCXProjectNode * const * projectsEnd = projects.End();
    for( VCXProjectNode ** it = projects.Begin() ; it != projectsEnd ; ++it )
    {
        m_StaticDependencies.Append( Dependency( *it ) );
    }
}
Example #16
0
// GetInputs
//------------------------------------------------------------------------------
bool FunctionObjectList::GetInputs( const BFFIterator & iter, Dependencies & inputs ) const
{
	NodeGraph & ng = FBuild::Get().GetDependencyGraph();

	// do we want to build files via a unity blob?
    Array< AString > inputUnities;
    if ( !GetStrings( iter, inputUnities, ".CompilerInputUnity", false ) ) // not required
	{
		return false;
	}
    for ( const auto& unity : inputUnities )
    {
        Node * n = ng.FindNode( unity );
		if ( n == nullptr )
		{
			Error::Error_1104_TargetNotDefined( iter, this, "CompilerInputUnity", unity );
			return false;
		}
		if ( n->GetType() != Node::UNITY_NODE )
		{
			Error::Error_1102_UnexpectedType( iter, this, "CompilerInputUnity", unity, n->GetType(), Node::UNITY_NODE );
			return false;
		}
		inputs.Append( Dependency( n ) );
    }

	// do we want to build a files in a directory?
	const BFFVariable * inputPath = BFFStackFrame::GetVar( ".CompilerInputPath" );
	if ( inputPath )
	{
		// get the optional pattern and recurse options related to InputPath
		Array< AString > patterns;
		if ( !GetStrings( iter, patterns, ".CompilerInputPattern", false ) )
		{
			return false; // GetString will have emitted an error
		}
		if ( patterns.IsEmpty() )
		{
			patterns.Append( AStackString<>( "*.cpp" ) );
		}

		// recursive?  default to true
		bool recurse = true;
		if ( !GetBool( iter, recurse, ".CompilerInputPathRecurse", true, false ) )
		{
			return false; // GetBool will have emitted an error
		}

		// Support an exclusion path
		Array< AString > excludePaths;
		if ( !GetFolderPaths( iter, excludePaths, ".CompilerInputExcludePath", false ) )
		{
			return false; // GetFolderPaths will have emitted an error
		}

        Array< AString > filesToExclude;
        if ( !GetStrings( iter, filesToExclude, ".CompilerInputExcludedFiles", false ) ) // not required
        {
            return false; // GetStrings will have emitted an error
        }
	    CleanFileNames( filesToExclude );

		// Input paths
		Array< AString > inputPaths;
		if ( !GetFolderPaths( iter, inputPaths, ".CompilerInputPath", false ) )
		{
			return false; // GetFolderPaths will have emitted an error
		}

		Dependencies dirNodes( inputPaths.GetSize() );
		if ( !GetDirectoryListNodeList( iter, inputPaths, excludePaths, filesToExclude, recurse, &patterns, "CompilerInputPath", dirNodes ) )
		{
			return false; // GetDirectoryListNodeList will have emitted an error
		}
		inputs.Append( dirNodes );
	}

	// do we want to build a specific list of files?
	if ( !GetNodeList( iter, ".CompilerInputFiles", inputs, false ) )
	{
		// helper will emit error
		return false;
	}

	return true;
}
Example #17
0
// DoDynamicDependencies
//------------------------------------------------------------------------------
/*virtual*/ bool CopyDirNode::DoDynamicDependencies( NodeGraph & nodeGraph, bool forceClean )
{
    (void)forceClean; // dynamic deps are always re-added here, so this is meaningless

    ASSERT( !m_StaticDependencies.IsEmpty() );

    Array< AString > preBuildDependencyNames( m_PreBuildDependencies.GetSize(), false );
    for ( const auto & dep : m_PreBuildDependencies )
    {
        preBuildDependencyNames.Append( dep.GetNode()->GetName() );
    }

    // Iterate all the DirectoryListNodes
    const Dependency * const depEnd = m_StaticDependencies.End();
    for ( const Dependency * dep = m_StaticDependencies.Begin();
          dep != depEnd;
          ++dep )
    {
        // Grab the files
        DirectoryListNode * dln = dep->GetNode()->CastTo< DirectoryListNode >();
        const Array< FileIO::FileInfo > & files = dln->GetFiles();
        const FileIO::FileInfo * const fEnd = files.End();
        for ( const FileIO::FileInfo * fIt = files.Begin();
              fIt != fEnd;
              ++fIt )
        {
            // Create a CopyFileNode for each dynamically discovered file

            // source file (full path)
            const AString & srcFile = fIt->m_Name;

            // source file (relative to base path)
            const AStackString<> srcFileRel( srcFile.Get() + dln->GetPath().GetLength() );

            // source file (as a node)
            Node * srcFileNode = nodeGraph.FindNode( srcFile );
            if ( srcFileNode == nullptr )
            {
                srcFileNode = nodeGraph.CreateFileNode( srcFile );
            }
            else if ( srcFileNode->IsAFile() == false )
            {
                FLOG_ERROR( "CopyDir() Node '%s' is not a FileNode (type: %s)", srcFile.Get(), srcFileNode->GetTypeName() );
                return false;
            }

            // generate dest file name
            const AStackString<> dstFile( m_DestPath );
            (AString &)dstFile += (AString &)srcFileRel;

            // make sure dest doesn't already exist
            Node * n = nodeGraph.FindNode( dstFile );
            if ( n == nullptr )
            {
                CopyFileNode * copyFileNode = nodeGraph.CreateCopyFileNode( dstFile );
                copyFileNode->m_Source = srcFileNode->GetName();
                copyFileNode->m_PreBuildDependencyNames = preBuildDependencyNames; // inherit PreBuildDependencies
                BFFIterator iter;
                if ( !copyFileNode->Initialize( nodeGraph, iter, nullptr ) )
                {
                    return false; // Initialize will have emitted an error
                }
                n = copyFileNode;
            }
            else if ( n->GetType() != Node::COPY_FILE_NODE )
            {
                FLOG_ERROR( "Node '%s' is not a CopyFileNode (type: %s)", n->GetName().Get(), n->GetTypeName() );
                return false;
            }
            else
            {
                CopyFileNode * cn = n->CastTo< CopyFileNode >();
                if ( srcFileNode != cn->GetSourceNode() )
                {
                    FLOG_ERROR( "Conflicting objects found during CopyDir:\n"
                                " File A: %s\n"
                                " File B: %s\n"
                                " Both copy to: %s\n",
                                srcFile.Get(),
                                cn->GetSourceNode()->GetName().Get(),
                                dstFile.Get() );
                    return false;
                }
            }

            m_DynamicDependencies.Append( Dependency( n ) );
        }
    }
    return true;
}
Example #18
0
// GatherDynamicDependencies
//------------------------------------------------------------------------------
/*virtual*/ bool ObjectListNode::GatherDynamicDependencies( NodeGraph & nodeGraph, bool forceClean )
{
    (void)forceClean; // dynamic deps are always re-added here, so this is meaningless

    // clear dynamic deps from previous passes
    m_DynamicDependencies.Clear();

#if defined( __WINDOWS__ )
    // On Windows, with MSVC we compile a cpp file to generate the PCH
    // Filter here to ensure that doesn't get compiled twice
    Node * pchCPP = nullptr;
    if ( m_PrecompiledHeader && m_PrecompiledHeader->IsMSVC() )
    {
        pchCPP = m_PrecompiledHeader->GetPrecompiledHeaderCPPFile();
    }
#endif

    // if we depend on any directory lists, we need to use them to get our files
    for ( Dependencies::Iter i = m_StaticDependencies.Begin();
            i != m_StaticDependencies.End();
            i++ )
    {
        // is this a dir list?
        if ( i->GetNode()->GetType() == Node::DIRECTORY_LIST_NODE )
        {
            // get the list of files
            DirectoryListNode * dln = i->GetNode()->CastTo< DirectoryListNode >();
            const Array< FileIO::FileInfo > & files = dln->GetFiles();
            m_DynamicDependencies.SetCapacity( m_DynamicDependencies.GetSize() + files.GetSize() );
            for ( Array< FileIO::FileInfo >::Iter fIt = files.Begin();
                    fIt != files.End();
                    fIt++ )
            {
                // Create the file node (or find an existing one)
                Node * n = nodeGraph.FindNode( fIt->m_Name );
                if ( n == nullptr )
                {
                    n = nodeGraph.CreateFileNode( fIt->m_Name );
                }
                else if ( n->IsAFile() == false )
                {
                    FLOG_ERROR( "Library() .CompilerInputFile '%s' is not a FileNode (type: %s)", n->GetName().Get(), n->GetTypeName() );
                    return false;
                }

                // ignore the precompiled header as a convenience for the user
                // so they don't have to exclude it explicitly
#if defined( __WINDOWS__ )
                if ( n == pchCPP )
                {
                    continue;
                }
#endif

                // create the object that will compile the above file
                if ( CreateDynamicObjectNode( nodeGraph, n, dln->GetPath() ) == false )
                {
                    return false; // CreateDynamicObjectNode will have emitted error
                }
            }
        }
        else if ( i->GetNode()->GetType() == Node::UNITY_NODE )
        {
            // get the dir list from the unity node
            UnityNode * un = i->GetNode()->CastTo< UnityNode >();

            // unity files
            const Array< AString > & unityFiles = un->GetUnityFileNames();
            for ( Array< AString >::Iter it = unityFiles.Begin();
                    it != unityFiles.End();
                    it++ )
            {
                Node * n = nodeGraph.FindNode( *it );
                if ( n == nullptr )
                {
                    n = nodeGraph.CreateFileNode( *it );
                }
                else if ( n->IsAFile() == false )
                {
                    FLOG_ERROR( "Library() .CompilerInputUnity '%s' is not a FileNode (type: %s)", n->GetName().Get(), n->GetTypeName() );
                    return false;
                }

                // create the object that will compile the above file
                if ( CreateDynamicObjectNode( nodeGraph, n, AString::GetEmpty(), true ) == false )
                {
                    return false; // CreateDynamicObjectNode will have emitted error
                }
            }

            // files from unity to build individually
            const Array< UnityNode::FileAndOrigin > & isolatedFiles = un->GetIsolatedFileNames();
            for ( Array< UnityNode::FileAndOrigin >::Iter it = isolatedFiles.Begin();
                    it != isolatedFiles.End();
                    it++ )
            {
                Node * n = nodeGraph.FindNode( it->GetName() );
                if ( n == nullptr )
                {
                    n = nodeGraph.CreateFileNode( it->GetName() );
                }
                else if ( n->IsAFile() == false )
                {
                    FLOG_ERROR( "Library() Isolated '%s' is not a FileNode (type: %s)", n->GetName().Get(), n->GetTypeName() );
                    return false;
                }

                // create the object that will compile the above file
                const AString & baseDir = it->GetDirListOrigin() ? it->GetDirListOrigin()->GetPath() : AString::GetEmpty();
                if ( CreateDynamicObjectNode( nodeGraph, n, baseDir, false, true ) == false )
                {
                    return false; // CreateDynamicObjectNode will have emitted error
                }
            }
        }
        else if ( i->GetNode()->IsAFile() )
        {
            // a single file, create the object that will compile it
            if ( CreateDynamicObjectNode( nodeGraph, i->GetNode(), AString::GetEmpty() ) == false )
            {
                return false; // CreateDynamicObjectNode will have emitted error
            }
        }
        else
        {
            ASSERT( false ); // unexpected node type
        }
    }

    // If we have a precompiled header, add that to our dynamic deps so that
    // any symbols in the PCH's .obj are also linked, when either:
    // a) we are a static library
    // b) a DLL or executable links our .obj files
    if ( m_PrecompiledHeader )
    {
        m_DynamicDependencies.Append( Dependency( m_PrecompiledHeader ) );
    }

    return true;
}
Example #19
0
// CreateDynamicObjectNode
//------------------------------------------------------------------------------
bool ObjectListNode::CreateDynamicObjectNode( NodeGraph & nodeGraph, Node * inputFile, const AString & baseDir, bool isUnityNode, bool isIsolatedFromUnityNode )
{
    const AString & fileName = inputFile->GetName();

    // Transform src file to dst object path
    // get file name only (no path, no ext)
    const char * lastSlash = fileName.FindLast( NATIVE_SLASH );
    lastSlash = lastSlash ? ( lastSlash + 1 ) : fileName.Get();
    const char * lastDot = fileName.FindLast( '.' );
    lastDot = lastDot && ( lastDot > lastSlash ) ? lastDot : fileName.GetEnd();

    // if source comes from a directory listing, use path relative to dirlist base
    // to replicate the folder hierearchy in the output
    AStackString<> subPath;
    if ( baseDir.IsEmpty() == false )
    {
        ASSERT( NodeGraph::IsCleanPath( baseDir ) );
        if ( PathUtils::PathBeginsWith( fileName, baseDir ) )
        {
            // ... use everything after that
            subPath.Assign( fileName.Get() + baseDir.GetLength(), lastSlash ); // includes last slash
        }
    }
    else
    {
        if ( !m_BaseDirectory.IsEmpty() && PathUtils::PathBeginsWith( fileName, m_BaseDirectory ) )
        {
            // ... use everything after that
            subPath.Assign( fileName.Get() + m_BaseDirectory.GetLength(), lastSlash ); // includes last slash
        }
    }

    AStackString<> fileNameOnly( lastSlash, lastDot );
    AStackString<> objFile( m_CompilerOutputPath );
    objFile += subPath;
    objFile += m_CompilerOutputPrefix;
    objFile += fileNameOnly;
    objFile += GetObjExtension();

    // Create an ObjectNode to compile the above file
    // and depend on that
    Node * on = nodeGraph.FindNode( objFile );
    if ( on == nullptr )
    {
        // determine flags - TODO:B Move DetermineFlags call out of build-time
        const bool usingPCH = ( m_PrecompiledHeader != nullptr );
        uint32_t flags = ObjectNode::DetermineFlags( m_Compiler, m_CompilerArgs, false, usingPCH );
        if ( isUnityNode )
        {
            flags |= ObjectNode::FLAG_UNITY;
        }
        if ( isIsolatedFromUnityNode )
        {
            flags |= ObjectNode::FLAG_ISOLATED_FROM_UNITY;
        }
        uint32_t preprocessorFlags = 0;
        if ( m_Preprocessor )
        {
            // determine flags - TODO:B Move DetermineFlags call out of build-time
            preprocessorFlags = ObjectNode::DetermineFlags( m_Preprocessor, m_PreprocessorArgs, false, usingPCH );
        }

        on = nodeGraph.CreateObjectNode( objFile, inputFile, m_Compiler, m_CompilerArgs, m_CompilerArgsDeoptimized, m_PrecompiledHeader, flags, m_CompilerForceUsing, m_DeoptimizeWritableFiles, m_DeoptimizeWritableFilesWithToken, m_AllowDistribution, m_AllowCaching, m_Preprocessor, m_PreprocessorArgs, preprocessorFlags );
    }
    else if ( on->GetType() != Node::OBJECT_NODE )
    {
        FLOG_ERROR( "Node '%s' is not an ObjectNode (type: %s)", on->GetName().Get(), on->GetTypeName() );
        return false;
    }
    else
    {
        ObjectNode * other = on->CastTo< ObjectNode >();
        if ( inputFile != other->GetSourceFile() )
        {
            FLOG_ERROR( "Conflicting objects found:\n"
                        " File A: %s\n"
                        " File B: %s\n"
                        " Both compile to: %s\n",
                        inputFile->GetName().Get(),
                        other->GetSourceFile()->GetName().Get(),
                        objFile.Get() );
            return false;
        }
    }
    m_DynamicDependencies.Append( Dependency( on ) );
    return true;
}
Example #20
0
// ProcessAlias
//------------------------------------------------------------------------------
bool Function::ProcessAlias( const BFFIterator & iter, Node * nodeToAlias ) const
{
	Dependencies nodesToAlias( 1, false );
	nodesToAlias.Append( Dependency( nodeToAlias ) );
	return ProcessAlias( iter, nodesToAlias );
}
Example #21
0
// GetNodeListRecurse
//------------------------------------------------------------------------------
bool Function::GetNodeListRecurse( const BFFIterator & iter, const char * name, Dependencies & nodes, const AString & nodeName,
								   bool allowCopyDirNodes, bool allowUnityNodes, bool allowRemoveDirNodes ) const
{
	NodeGraph & ng = FBuild::Get().GetDependencyGraph();

	// get node
	Node * n = ng.FindNode( nodeName );
	if ( n == nullptr )
	{
		// not found - create a new file node
		n = ng.CreateFileNode( nodeName );
		nodes.Append( Dependency( n ) );
		return true;
	}

	// found - is it a file?
	if ( n->IsAFile() )
	{
		// found file - just use as is
		nodes.Append( Dependency( n ) );
		return true;
	}

	// found - is it an ObjectList?
	if ( n->GetType() == Node::OBJECT_LIST_NODE )
	{
		// use as-is
		nodes.Append( Dependency( n ) );
		return true;
	}

	// extra types
	if ( allowCopyDirNodes )
	{
		// found - is it an ObjectList?
		if ( n->GetType() == Node::COPY_DIR_NODE )
		{
			// use as-is
			nodes.Append( Dependency( n ) );
			return true;
		}
	}
	if ( allowRemoveDirNodes )
	{
		// found - is it a RemoveDirNode?
		if ( n->GetType() == Node::REMOVE_DIR_NODE )
		{
			// use as-is
			nodes.Append( Dependency( n ) );
			return true;
		}
	}
	if ( allowUnityNodes )
	{
		// found - is it an ObjectList?
		if ( n->GetType() == Node::UNITY_NODE )
		{
			// use as-is
			nodes.Append( Dependency( n ) );
			return true;
		}
	}

	// found - is it a group?
	if ( n->GetType() == Node::ALIAS_NODE )
	{
		AliasNode * an = n->CastTo< AliasNode >();
		const Dependencies & aNodes = an->GetAliasedNodes();
		for ( const Dependency * it = aNodes.Begin(); it != aNodes.End(); ++it )
		{
			// TODO:C by passing as string we'll be looking up again for no reason
			const AString & subName = it->GetNode()->GetName();

			if ( !GetNodeListRecurse( iter, name, nodes, subName, allowCopyDirNodes, allowUnityNodes, allowRemoveDirNodes ) )
			{
				return false;
			}
		}
		return true;
	}

	// don't know how to handle this type of node
	Error::Error_1005_UnsupportedNodeType( iter, this, name, n->GetName(), n->GetType() );
	return false;
}
Example #22
0
// DependOnNode
//------------------------------------------------------------------------------
/*static*/ bool LinkerNode::DependOnNode( const BFFIterator & iter,
                                          const Function * function,
                                          Node * node,
                                          Dependencies & nodes )
{
    ASSERT( node );

    // a previously declared library?
    if ( node->GetType() == Node::LIBRARY_NODE )
    {
        // can link directly to it
        nodes.Append( Dependency( node ) );
        return true;
    }

    // a previously declared object list?
    if ( node->GetType() == Node::OBJECT_LIST_NODE )
    {
        // can link directly to it
        nodes.Append( Dependency( node ) );
        return true;
    }

    // a dll?
    if ( node->GetType() == Node::DLL_NODE )
    {
        // TODO:B Depend on import lib
        nodes.Append( Dependency( node, true ) ); // NOTE: Weak dependency
        return true;
    }

    // a previously declared external file?
    if ( node->GetType() == Node::FILE_NODE )
    {
        // can link directy against it
        nodes.Append( Dependency( node ) );
        return true;
    }

    // a file copy?
    if ( node->GetType() == Node::COPY_FILE_NODE )
    {
        // depend on copy - will use input at build time
        nodes.Append( Dependency( node ) );
        return true;
    }

    // an external executable?
    if ( node->GetType() == Node::EXEC_NODE )
    {
        // depend on ndoe - will use exe output at build time
        nodes.Append( Dependency( node ) );
        return true;
    }

    // a group (alias)?
    if ( node->GetType() == Node::ALIAS_NODE )
    {
        // handle all targets in alias
        AliasNode * an = node->CastTo< AliasNode >();
        const Dependencies & aliasNodeList = an->GetAliasedNodes();
        const Dependencies::Iter end = aliasNodeList.End();
        for ( Dependencies::Iter it = aliasNodeList.Begin();
              it != end;
              ++it )
        {
            if ( DependOnNode( iter, function, it->GetNode(), nodes ) == false )
            {
                return false; // something went wrong lower down
            }
        }
        return true; // all nodes in group handled ok
    }

    // don't know how to handle this type of node
    Error::Error_1005_UnsupportedNodeType( iter, function, "Libraries", node->GetName(), node->GetType() );
    return false;
}
Example #23
0
// Commit
//------------------------------------------------------------------------------
/*virtual*/ bool FunctionCopy::Commit( NodeGraph & nodeGraph, const BFFIterator & funcStartIter ) const
{
    // make sure all required variables are defined
    Array< AString > sources( 16, true );
    const BFFVariable * dstFileV;
    if ( !GetStrings( funcStartIter, sources, ".Source", true ) ||
         !GetString( funcStartIter, dstFileV, ".Dest", true ) )
    {
        return false; // GetString will have emitted errors
    }

    // Optional
    AStackString<> sourceBasePath;
    if ( !GetString( funcStartIter, sourceBasePath, ".SourceBasePath", false ) )
    {
        return false; // GetString will have emitted errors
    }

    // Canonicalize the SourceBasePath
    if ( !sourceBasePath.IsEmpty() )
    {
        AStackString<> cleanValue;
        NodeGraph::CleanPath( sourceBasePath, cleanValue );
        PathUtils::EnsureTrailingSlash( cleanValue );
        sourceBasePath = cleanValue;
    }

    // check sources are not paths
    {
        const AString * const end = sources.End();
        for ( const AString * it = sources.Begin(); it != end; ++it )
        {
            const AString & srcFile( *it );

            // source must be a file, not a  path
            if ( PathUtils::IsFolderPath( srcFile ) )
            {
                Error::Error_1105_PathNotAllowed( funcStartIter, this, ".Source", srcFile );
                return false;
            }
        }
    }

    // Pre-build dependencies
    Dependencies preBuildDependencies;
    if ( !GetNodeList( nodeGraph, funcStartIter, ".PreBuildDependencies", preBuildDependencies, false ) )
    {
        return false; // GetNodeList will have emitted an error
    }
    Array< AString > preBuildDependencyNames( preBuildDependencies.GetSize(), false );
    for ( const auto & dep : preBuildDependencies )
    {
        preBuildDependencyNames.Append( dep.GetNode()->GetName() );
    }

    // get source node
    Array< Node * > srcNodes;
    {
        const AString * const end = sources.End();
        for ( const AString * it = sources.Begin(); it != end; ++it )
        {

            Node * srcNode = nodeGraph.FindNode( *it );
            if ( srcNode )
            {
                if ( GetSourceNodes( funcStartIter, srcNode, srcNodes ) == false )
                {
                    return false;
                }
            }
            else
            {
                // source file not defined by use - assume an external file
                srcNodes.Append( nodeGraph.CreateFileNode( *it ) );
            }
        }
    }

    AStackString<> dstFile;
    NodeGraph::CleanPath( dstFileV->GetString(), dstFile );
    const bool dstIsFolderPath = PathUtils::IsFolderPath( dstFile );

    // make all the nodes for copies
    Dependencies copyNodes( srcNodes.GetSize(), false );
    for ( const Node * srcNode : srcNodes )
    {
        AStackString<> dst( dstFile );

        // dest can be a file OR a path.  If it's a path, use the source filename part
        if ( dstIsFolderPath )
        {
            // find filename part of source
            const AString & srcName = srcNode->GetName();

            // If the sourceBasePath is specified (and valid) use the name relative to that
            if ( !sourceBasePath.IsEmpty() && PathUtils::PathBeginsWith( srcName, sourceBasePath ) )
            {
                // Use everything relative to the SourceBasePath
                dst += srcName.Get() + sourceBasePath.GetLength();
            }
            else
            {
                // Use just the file name
                const char * lastSlash = srcName.FindLast( NATIVE_SLASH );
                dst += lastSlash ? ( lastSlash + 1 )    // append filename part if found
                                     : srcName.Get();   // otherwise append whole thing
            }
        }

        // check node doesn't already exist
        if ( nodeGraph.FindNode( dst ) )
        {
            // TODO:C could have a specific error for multiple sources with only 1 output
            // to differentiate from two rules creating the same dst target
            Error::Error_1100_AlreadyDefined( funcStartIter, this, dst );
            return false;
        }

        // create our node
        CopyFileNode * copyFileNode = nodeGraph.CreateCopyFileNode( dst );
        copyFileNode->m_Source = srcNode->GetName();
        copyFileNode->m_PreBuildDependencyNames = preBuildDependencyNames;
        if ( !copyFileNode->Initialize( nodeGraph, funcStartIter, this ) )
        {
            return false; // Initialize will have emitted an error
        }

        copyNodes.Append( Dependency( copyFileNode ) );
    }

    // handle alias creation
    return ProcessAlias( nodeGraph, funcStartIter, copyNodes );
}
Example #24
0
// Initialize
//------------------------------------------------------------------------------
bool LinkerNode::Initialize( NodeGraph & nodeGraph, const BFFIterator & iter, const Function * function )
{
    // .PreBuildDependencies
    if ( !InitializePreBuildDependencies( nodeGraph, iter, function, m_PreBuildDependencyNames ) )
    {
        return false; // InitializePreBuildDependencies will have emitted an error
    }

    // Get linker exe
    Node * linkerExeNode = nullptr;
    if ( !function->GetFileNode( nodeGraph, iter, linkerExeNode, ".Linker" ) ) // TODO:B Use m_Linker property
    {
        return false; // GetFileNode will have emitted an error
    }

    m_Flags = DetermineFlags( m_LinkerType, m_Linker, m_LinkerOptions );

    // Check for Import Library override
    if ( ( m_Flags & LinkerNode::LINK_FLAG_MSVC ) != 0 )
    {
        GetImportLibName( m_LinkerOptions, m_ImportLibName );
    }

    // Check input/output args for Linker
    {
        bool hasInputToken = ( m_LinkerOptions.Find( "%1" ) || m_LinkerOptions.Find( "\"%1\"" ) );
        if ( hasInputToken == false )
        {
            Error::Error_1106_MissingRequiredToken( iter, function, ".LinkerOptions", "%1" );
            return false;
        }
        bool hasOutputToken = ( m_LinkerOptions.Find( "%2" ) || m_LinkerOptions.Find( "\"%2\"" ) );
        if ( hasOutputToken == false )
        {
            Error::Error_1106_MissingRequiredToken( iter, function, ".LinkerOptions", "%2" );
            return false;
        }
    }

    // Standard library dependencies
    Dependencies libraries( 64, true );
    for ( const AString & library : m_Libraries )
    {
        if ( DependOnNode( nodeGraph, iter, function, library, libraries ) == false )
        {
            return false; // DependOnNode will have emitted an error
        }
    }

    // Assembly Resources
    Dependencies assemblyResources( 32, true );
    if ( !function->GetNodeList( nodeGraph, iter, ".LinkerAssemblyResources", assemblyResources, false ) ) // TODO:B Use m_LinkerAssemblyResources directly
    {
        return false; // GetNodeList will have emitted error
    }

    // get inputs not passed through 'LibraryNodes' (i.e. directly specified on the cmd line)
    Dependencies otherLibraryNodes( 64, true );
    if ( ( m_Flags & ( LinkerNode::LINK_FLAG_MSVC | LinkerNode::LINK_FLAG_GCC | LinkerNode::LINK_FLAG_SNC | LinkerNode::LINK_FLAG_ORBIS_LD | LinkerNode::LINK_FLAG_GREENHILLS_ELXR | LinkerNode::LINK_FLAG_CODEWARRIOR_LD ) ) != 0 )
    {
        const bool msvcStyle = ( ( m_Flags & LinkerNode::LINK_FLAG_MSVC ) == LinkerNode::LINK_FLAG_MSVC );
        if ( !GetOtherLibraries( nodeGraph, iter, function, m_LinkerOptions, otherLibraryNodes, msvcStyle ) )
        {
            return false; // will have emitted error
        }
    }

    // Handle LinkerStampExe
    Node * linkerStampExeNode = nullptr;
    if ( m_LinkerStampExe.IsEmpty() == false )
    {
        if ( !function->GetFileNode( nodeGraph, iter, linkerStampExeNode, ".LinkerStampExe" ) ) // TODO: Use m_LinkerStampExe property
        {
            return false; // GetFileNode will have emitted an error
        }
    }

    // Store all dependencies
    m_StaticDependencies.SetCapacity( 1 + // for .Linker
                                      libraries.GetSize() +
                                      assemblyResources.GetSize() +
                                      otherLibraryNodes.GetSize() +
                                      ( linkerStampExeNode ? 1 : 0 ) );
    m_StaticDependencies.Append( Dependency( linkerExeNode ) );
    m_StaticDependencies.Append( libraries );
    m_AssemblyResourcesStartIndex = (uint32_t)m_StaticDependencies.GetSize();
    m_StaticDependencies.Append( assemblyResources );
    m_AssemblyResourcesNum = (uint32_t)assemblyResources.GetSize();
    m_StaticDependencies.Append( otherLibraryNodes );
    if ( linkerStampExeNode )
    {
        m_StaticDependencies.Append( Dependency( linkerStampExeNode ) );
    }

    return true;
}