// GetAssemblyResourceFiles //------------------------------------------------------------------------------ void LinkerNode::GetAssemblyResourceFiles( Args & fullArgs, const AString & pre, const AString & post ) const { const Dependency * const end = m_AssemblyResources.End(); for ( Dependencies::Iter i = m_AssemblyResources.Begin(); i != end; i++ ) { Node * n( i->GetNode() ); if ( n->GetType() == Node::OBJECT_LIST_NODE ) { ObjectListNode * oln = n->CastTo< ObjectListNode >(); oln->GetInputFiles( fullArgs, pre, post ); continue; } if ( n->GetType() == Node::LIBRARY_NODE ) { LibraryNode * ln = n->CastTo< LibraryNode >(); ln->GetInputFiles( fullArgs, pre, post ); continue; } fullArgs += pre; fullArgs += n->GetName(); fullArgs += post; fullArgs.AddDelimiter(); } }
// GetInputFiles //------------------------------------------------------------------------------ void ObjectListNode::GetInputFiles( Array< AString > & files ) const { // only valid to call on ObjectListNode (not LibraryNode) ASSERT( GetType() == Node::OBJECT_LIST_NODE ); files.SetCapacity( files.GetCapacity() + m_DynamicDependencies.GetSize() ); for ( Dependencies::Iter i = m_DynamicDependencies.Begin(); i != m_DynamicDependencies.End(); i++ ) { const Node * n = i->GetNode(); files.Append( n->GetName() ); } }
// GetInputFiles //------------------------------------------------------------------------------ void ObjectListNode::GetInputFiles( Args & fullArgs, const AString & pre, const AString & post ) const { for ( Dependencies::Iter i = m_DynamicDependencies.Begin(); i != m_DynamicDependencies.End(); i++ ) { const Node * n = i->GetNode(); // handle pch files - get path to object if ( n->GetType() == Node::OBJECT_NODE ) { // handle pch files - get path to matching object const ObjectNode * on = n->CastTo< ObjectNode >(); if ( on->IsCreatingPCH() ) { if ( on->IsMSVC() ) { fullArgs += pre; fullArgs += on->GetName(); fullArgs += on->GetObjExtension(); fullArgs += post; fullArgs.AddDelimiter(); continue; } else { // Clang/GCC/SNC don't have an object to link for a pch continue; } } } // extract objects from additional lists if ( n->GetType() == Node::OBJECT_LIST_NODE ) { ASSERT( GetType() == Node::LIBRARY_NODE ); // should only be possible for a LibraryNode // insert all the objects in the object list ObjectListNode * oln = n->CastTo< ObjectListNode >(); oln->GetInputFiles( fullArgs, pre, post ); continue; } // normal object fullArgs += pre; fullArgs += n->GetName(); fullArgs += post; fullArgs.AddDelimiter(); } }
// GetInputFiles //------------------------------------------------------------------------------ void LinkerNode::GetInputFiles( Args & fullArgs, const AString & pre, const AString & post ) const { // (exlude assembly resources from inputs) const Dependency * end = m_StaticDependencies.End() - ( m_AssemblyResources.GetSize() + m_OtherLibraries.GetSize() ); if ( m_LinkerStampExe ) { --end; // LinkerStampExe is not an input used for linking } for ( Dependencies::Iter i = m_StaticDependencies.Begin(); i != end; i++ ) { Node * n( i->GetNode() ); GetInputFiles( n, fullArgs, pre, post ); } }
// DoBuild //------------------------------------------------------------------------------ /*virtual*/ Node::BuildResult AliasNode::DoBuild( Job * UNUSED( job ) ) { const Dependencies::Iter end = m_StaticDependencies.End(); for ( Dependencies::Iter it = m_StaticDependencies.Begin(); it != end; ++it ) { // If any nodes are file nodes ... const Node * n = it->GetNode(); if ( n->GetType() == Node::FILE_NODE ) { // ... and the file is missing ... if ( n->GetStamp() == 0 ) { // ... the build should fail FLOG_ERROR( "Alias: %s\nFailed due to missing file: %s\n", GetName().Get(), n->GetName().Get() ); return Node::NODE_RESULT_FAILED; } } } return NODE_RESULT_OK; }
// 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; }
// 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; }