// 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 }
// 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; }
// 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; }
// 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; }
// 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; }
// 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; }
// 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; }
// 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; }
// 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; }