more efficient detection of C++ modules, fixed bug in C++ pch support, always clean...
[reactos.git] / reactos / tools / rbuild / module.cpp
index d2f07cb..0ffae73 100644 (file)
@@ -31,6 +31,16 @@ GetExtension ( const string& filename )
        return "";\r
 }\r
 \r
+string\r
+GetDirectory ( const string& filename )\r
+{\r
+       size_t index = filename.find_last_of ( CSEP );\r
+       if ( index == string::npos )\r
+               return filename;\r
+       else\r
+               return filename.substr ( 0, index );\r
+}\r
+\r
 string\r
 NormalizeFilename ( const string& filename )\r
 {\r
@@ -40,12 +50,49 @@ NormalizeFilename ( const string& filename )
        return FixSeparator ( relativeNormalizedPath );\r
 }\r
 \r
+IfableData::~IfableData()\r
+{\r
+       size_t i;\r
+       for ( i = 0; i < files.size(); i++ )\r
+               delete files[i];\r
+       for ( i = 0; i < includes.size(); i++ )\r
+               delete includes[i];\r
+       for ( i = 0; i < defines.size(); i++ )\r
+               delete defines[i];\r
+       for ( i = 0; i < libraries.size(); i++ )\r
+               delete libraries[i];\r
+       for ( i = 0; i < properties.size(); i++ )\r
+               delete properties[i];\r
+       for ( i = 0; i < ifs.size(); i++ )\r
+               delete ifs[i];\r
+}\r
+\r
+void IfableData::ProcessXML ()\r
+{\r
+       size_t i;\r
+       for ( i = 0; i < files.size (); i++ )\r
+               files[i]->ProcessXML ();\r
+       for ( i = 0; i < includes.size (); i++ )\r
+               includes[i]->ProcessXML ();\r
+       for ( i = 0; i < defines.size (); i++ )\r
+               defines[i]->ProcessXML ();\r
+       for ( i = 0; i < libraries.size (); i++ )\r
+               libraries[i]->ProcessXML ();\r
+       for ( i = 0; i < properties.size(); i++ )\r
+               properties[i]->ProcessXML ();\r
+       for ( i = 0; i < ifs.size (); i++ )\r
+               ifs[i]->ProcessXML ();\r
+}\r
+\r
 Module::Module ( const Project& project,\r
                  const XMLElement& moduleNode,\r
                  const string& modulePath )\r
        : project (project),\r
          node (moduleNode),\r
-         importLibrary (NULL)\r
+         importLibrary (NULL),\r
+         bootstrap (NULL),\r
+         pch (NULL),\r
+         cplusplus (false)\r
 {\r
        if ( node.name != "module" )\r
                throw Exception ( "internal tool error: Module created with non-<module> node" );\r
@@ -72,6 +119,12 @@ Module::Module ( const Project& project,
        else\r
                entrypoint = GetDefaultModuleEntrypoint ();\r
 \r
+       att = moduleNode.GetAttribute ( "baseaddress", false );\r
+       if ( att != NULL )\r
+               baseaddress = att->value;\r
+       else\r
+               baseaddress = GetDefaultModuleBaseaddress ();\r
+\r
        att = moduleNode.GetAttribute ( "mangledsymbols", false );\r
        if ( att != NULL )\r
                mangledSymbols = att->value != "false";\r
@@ -82,24 +135,16 @@ Module::Module ( const Project& project,
 Module::~Module ()\r
 {\r
        size_t i;\r
-       for ( i = 0; i < files.size(); i++ )\r
-               delete files[i];\r
-       for ( i = 0; i < libraries.size(); i++ )\r
-               delete libraries[i];\r
-       for ( i = 0; i < includes.size(); i++ )\r
-               delete includes[i];\r
-       for ( i = 0; i < defines.size(); i++ )\r
-               delete defines[i];\r
        for ( i = 0; i < invocations.size(); i++ )\r
                delete invocations[i];\r
        for ( i = 0; i < dependencies.size(); i++ )\r
                delete dependencies[i];\r
-       for ( i = 0; i < ifs.size(); i++ )\r
-               delete ifs[i];\r
        for ( i = 0; i < compilerFlags.size(); i++ )\r
                delete compilerFlags[i];\r
        for ( i = 0; i < linkerFlags.size(); i++ )\r
                delete linkerFlags[i];\r
+       if ( pch )\r
+               delete pch;\r
 }\r
 \r
 void\r
@@ -108,24 +153,17 @@ Module::ProcessXML()
        size_t i;\r
        for ( i = 0; i < node.subElements.size(); i++ )\r
                ProcessXMLSubElement ( *node.subElements[i], path );\r
-       for ( i = 0; i < files.size (); i++ )\r
-               files[i]->ProcessXML ();\r
-       for ( i = 0; i < libraries.size(); i++ )\r
-               libraries[i]->ProcessXML ();\r
-       for ( i = 0; i < includes.size(); i++ )\r
-               includes[i]->ProcessXML ();\r
-       for ( i = 0; i < defines.size(); i++ )\r
-               defines[i]->ProcessXML ();\r
        for ( i = 0; i < invocations.size(); i++ )\r
                invocations[i]->ProcessXML ();\r
        for ( i = 0; i < dependencies.size(); i++ )\r
                dependencies[i]->ProcessXML ();\r
-       for ( i = 0; i < ifs.size(); i++ )\r
-               ifs[i]->ProcessXML();\r
        for ( i = 0; i < compilerFlags.size(); i++ )\r
                compilerFlags[i]->ProcessXML();\r
        for ( i = 0; i < linkerFlags.size(); i++ )\r
                linkerFlags[i]->ProcessXML();\r
+       non_if_data.ProcessXML();\r
+       if ( pch )\r
+               pch->ProcessXML();\r
 }\r
 \r
 void\r
@@ -148,20 +186,31 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                                        e.location,\r
                                        "attribute 'first' of <file> element can only be 'true' or 'false'" );\r
                }\r
+               if ( !cplusplus )\r
+               {\r
+                       // check for c++ file\r
+                       string ext = GetExtension ( e.value );\r
+                       if ( !stricmp ( ext.c_str(), ".cpp" ) )\r
+                               cplusplus = true;\r
+                       else if ( !stricmp ( ext.c_str(), ".cc" ) )\r
+                               cplusplus = true;\r
+                       else if ( !stricmp ( ext.c_str(), ".cxx" ) )\r
+                               cplusplus = true;\r
+               }\r
                File* pFile = new File ( FixSeparator ( path + CSEP + e.value ), first );\r
                if ( pIf )\r
-                       pIf->files.push_back ( pFile );\r
+                       pIf->data.files.push_back ( pFile );\r
                else\r
-                       files.push_back ( pFile );\r
+                       non_if_data.files.push_back ( pFile );\r
                subs_invalid = true;\r
        }\r
        else if ( e.name == "library" && e.value.size () )\r
        {\r
+               Library* pLibrary = new Library ( e, *this, e.value );\r
                if ( pIf )\r
-                       throw InvalidBuildFileException (\r
-                               e.location,\r
-                               "<library> is not a valid sub-element of <if>" );\r
-               libraries.push_back ( new Library ( e, *this, e.value ) );\r
+                       pIf->data.libraries.push_back ( pLibrary );\r
+               else\r
+                       non_if_data.libraries.push_back ( pLibrary );\r
                subs_invalid = true;\r
        }\r
        else if ( e.name == "directory" )\r
@@ -174,18 +223,18 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
        {\r
                Include* include = new Include ( project, this, e );\r
                if ( pIf )\r
-                       pIf->includes.push_back ( include );\r
+                       pIf->data.includes.push_back ( include );\r
                else\r
-                       includes.push_back ( include );\r
+                       non_if_data.includes.push_back ( include );\r
                subs_invalid = true;\r
        }\r
        else if ( e.name == "define" )\r
        {\r
                Define* pDefine = new Define ( project, this, e );\r
                if ( pIf )\r
-                       pIf->defines.push_back ( pDefine );\r
+                       pIf->data.defines.push_back ( pDefine );\r
                else\r
-                       defines.push_back ( pDefine );\r
+                       non_if_data.defines.push_back ( pDefine );\r
                subs_invalid = true;\r
        }\r
        else if ( e.name == "invoke" )\r
@@ -224,9 +273,9 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                If* pOldIf = pIf;\r
                pIf = new If ( e, project, this );\r
                if ( pOldIf )\r
-                       pOldIf->ifs.push_back ( pIf );\r
+                       pOldIf->data.ifs.push_back ( pIf );\r
                else\r
-                       ifs.push_back ( pIf );\r
+                       non_if_data.ifs.push_back ( pIf );\r
                subs_invalid = false;\r
        }\r
        else if ( e.name == "compilerflag" )\r
@@ -245,6 +294,25 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                        e.location,\r
                        "<property> is not a valid sub-element of <module>" );\r
        }\r
+       else if ( e.name == "bootstrap" )\r
+       {\r
+               bootstrap = new Bootstrap ( project, this, e );\r
+               subs_invalid = true;\r
+       }\r
+       else if ( e.name == "pch" )\r
+       {\r
+               if ( pIf )\r
+                       throw InvalidBuildFileException (\r
+                               e.location,\r
+                               "<pch> is not a valid sub-element of <if>" );\r
+               if ( pch )\r
+                       throw InvalidBuildFileException (\r
+                               e.location,\r
+                               "Only one <pch> is valid per module" );\r
+               pch = new PchFile (\r
+                       e, *this, FixSeparator ( path + CSEP + e.value ) );\r
+               subs_invalid = true;\r
+       }\r
        if ( subs_invalid && e.subElements.size() > 0 )\r
                throw InvalidBuildFileException (\r
                        e.location,\r
@@ -355,6 +423,39 @@ Module::GetDefaultModuleEntrypoint () const
                                          __LINE__ );\r
 }\r
 \r
+string\r
+Module::GetDefaultModuleBaseaddress () const\r
+{\r
+       switch (type)\r
+       {\r
+               case Kernel:\r
+                       return "0xc0000000";\r
+               case KernelModeDLL:\r
+                       return "0x10000";\r
+               case NativeDLL:\r
+                       return "0x10000";\r
+               case NativeCUI:\r
+                       return "0x10000";\r
+               case Win32DLL:\r
+                       return "0x10000";\r
+               case Win32CUI:\r
+                       return "0x00400000";\r
+               case Win32GUI:\r
+                       return "0x00400000";\r
+               case KernelModeDriver:\r
+                       return "0x10000";\r
+               case BuildTool:\r
+               case StaticLibrary:\r
+               case ObjectLibrary:\r
+               case BootLoader:\r
+               case BootSector:\r
+               case Iso:\r
+                       return "";\r
+       }\r
+       throw InvalidOperationException ( __FILE__,\r
+                                         __LINE__ );\r
+}\r
+\r
 bool\r
 Module::HasImportLibrary () const\r
 {\r
@@ -428,19 +529,41 @@ Module::GetInvocationTarget ( const int index ) const
 }\r
 \r
 bool\r
-Module::HasFileWithExtensions ( const std::string& extension1,\r
-                                   const std::string& extension2 ) const\r
+Module::HasFileWithExtension (\r
+       const IfableData& data,\r
+       const std::string& extension ) const\r
 {\r
-       for ( size_t i = 0; i < files.size (); i++ )\r
+       size_t i;\r
+       for ( i = 0; i < data.files.size (); i++ )\r
+       {\r
+               File& file = *data.files[i];\r
+               string file_ext = GetExtension ( file.name );\r
+               if ( !stricmp ( file_ext.c_str (), extension.c_str () ) )\r
+                       return true;\r
+       }\r
+       for ( i = 0; i < data.ifs.size (); i++ )\r
        {\r
-               File& file = *files[i];\r
-               string extension = GetExtension ( file.name );\r
-               if ( extension == extension1 || extension == extension2 )\r
+               if ( HasFileWithExtension ( data.ifs[i]->data, extension ) )\r
                        return true;\r
        }\r
        return false;\r
 }\r
 \r
+void\r
+Module::InvokeModule () const\r
+{\r
+       for ( size_t i = 0; i < invocations.size (); i++ )\r
+       {\r
+               Invoke& invoke = *invocations[i];\r
+               string command = invoke.invokeModule->GetPath () + " " + invoke.GetParameters ();\r
+               printf ( "Executing '%s'\n\n", command.c_str () );\r
+               int exitcode = system ( command.c_str () );\r
+               if ( exitcode != 0 )\r
+                       throw InvocationFailedException ( command,\r
+                                                         exitcode );\r
+       }\r
+}\r
+\r
 \r
 File::File ( const string& _name, bool _first )\r
        : name(_name), first(_first)\r
@@ -458,13 +581,20 @@ Library::Library ( const XMLElement& _node,
                    const string& _name )\r
        : node(_node),\r
          module(_module),\r
-         name(_name)\r
+         name(_name),\r
+         imported_module(_module.project.LocateModule(_name))\r
 {\r
        if ( module.name == name )\r
                throw InvalidBuildFileException (\r
                        node.location,\r
                        "module '%s' cannot link against itself",\r
                        name.c_str() );\r
+       if ( !imported_module )\r
+               throw InvalidBuildFileException (\r
+                       node.location,\r
+                       "module '%s' trying to import non-existant module '%s'",\r
+                       module.name.c_str(),\r
+                       name.c_str() );\r
 }\r
 \r
 void\r
@@ -571,6 +701,40 @@ Invoke::GetTargets () const
        return targets;\r
 }\r
 \r
+string\r
+Invoke::GetParameters () const\r
+{\r
+       string parameters ( "" );\r
+       size_t i;\r
+       for ( i = 0; i < output.size (); i++ )\r
+       {\r
+               if ( parameters.length () > 0)\r
+                       parameters += " ";\r
+               InvokeFile& invokeFile = *output[i];\r
+               if ( invokeFile.switches.length () > 0 )\r
+               {\r
+                       parameters += invokeFile.switches;\r
+                       parameters += " ";\r
+               }\r
+               parameters += invokeFile.name;\r
+       }\r
+\r
+       for ( i = 0; i < input.size (); i++ )\r
+       {\r
+               if ( parameters.length () > 0 )\r
+                       parameters += " ";\r
+               InvokeFile& invokeFile = *input[i];\r
+               if ( invokeFile.switches.length () > 0 )\r
+               {\r
+                       parameters += invokeFile.switches;\r
+                       parameters += " ";\r
+               }\r
+               parameters += invokeFile.name ;\r
+       }\r
+\r
+       return parameters;\r
+}\r
+\r
 \r
 InvokeFile::InvokeFile ( const XMLElement& _node,\r
                          const string& _name )\r
@@ -645,15 +809,6 @@ If::If ( const XMLElement& node_,
 \r
 If::~If ()\r
 {\r
-       size_t i;\r
-       for ( i = 0; i < files.size(); i++ )\r
-               delete files[i];\r
-       for ( i = 0; i < includes.size(); i++ )\r
-               delete includes[i];\r
-       for ( i = 0; i < defines.size(); i++ )\r
-               delete defines[i];\r
-       for ( i = 0; i < ifs.size(); i++ )\r
-               delete ifs[i];\r
 }\r
 \r
 void\r
@@ -682,3 +837,17 @@ void
 Property::ProcessXML()\r
 {\r
 }\r
+\r
+\r
+PchFile::PchFile (\r
+       const XMLElement& node_,\r
+       const Module& module_,\r
+       const string& header_ )\r
+       : node(node_), module(module_), header(header_)\r
+{\r
+}\r
+\r
+void\r
+PchFile::ProcessXML()\r
+{\r
+}\r