Support for non-standard module base addresses
[reactos.git] / reactos / tools / rbuild / module.cpp
index e1a883d..47157e4 100644 (file)
@@ -1,5 +1,3 @@
-// module.cpp\r
-\r
 #include "pch.h"\r
 #include <assert.h>\r
 \r
@@ -21,6 +19,37 @@ FixSeparator ( const string& s )
        return s2;\r
 }\r
 \r
+string\r
+GetExtension ( const string& filename )\r
+{\r
+       size_t index = filename.find_last_of ( '/' );\r
+       if (index == string::npos) index = 0;\r
+       string tmp = filename.substr( index, filename.size() - index );\r
+       size_t ext_index = tmp.find_last_of( '.' );\r
+       if (ext_index != string::npos) \r
+               return filename.substr ( index + ext_index, filename.size() );\r
+       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
+       Path path;\r
+       string normalizedPath = path.Fixup ( filename, true );\r
+       string relativeNormalizedPath = path.RelativeFromWorkingDirectory ( normalizedPath );\r
+       return FixSeparator ( relativeNormalizedPath );\r
+}\r
+\r
 Module::Module ( const Project& project,\r
                  const XMLElement& moduleNode,\r
                  const string& modulePath )\r
@@ -42,10 +71,28 @@ Module::Module ( const Project& project,
        type = GetModuleType ( node.location, *att );\r
 \r
        att = moduleNode.GetAttribute ( "extension", false );\r
-       if (att != NULL)\r
+       if ( att != NULL )\r
                extension = att->value;\r
        else\r
                extension = GetDefaultModuleExtension ();\r
+\r
+       att = moduleNode.GetAttribute ( "entrypoint", false );\r
+       if ( att != NULL )\r
+               entrypoint = att->value;\r
+       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
+       else\r
+               mangledSymbols = false;\r
 }\r
 \r
 Module::~Module ()\r
@@ -65,6 +112,10 @@ Module::~Module ()
                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
 }\r
 \r
 void\r
@@ -87,6 +138,10 @@ Module::ProcessXML()
                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
 }\r
 \r
 void\r
@@ -98,7 +153,18 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
        string subpath ( path );\r
        if ( e.name == "file" && e.value.size () > 0 )\r
        {\r
-               File* pFile = new File ( FixSeparator ( path + CSEP + e.value ) );\r
+               bool first = false;\r
+               const XMLAttribute* att = e.GetAttribute ( "first", false );\r
+               if ( att )\r
+               {\r
+                       if ( !stricmp ( att->value.c_str(), "true" ) )\r
+                               first = true;\r
+                       else if ( stricmp ( att->value.c_str(), "false" ) )\r
+                               throw InvalidBuildFileException (\r
+                                       e.location,\r
+                                       "attribute 'first' of <file> element can only be 'true' or 'false'" );\r
+               }\r
+               File* pFile = new File ( FixSeparator ( path + CSEP + e.value ), first );\r
                if ( pIf )\r
                        pIf->files.push_back ( pFile );\r
                else\r
@@ -179,6 +245,16 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                        ifs.push_back ( pIf );\r
                subs_invalid = false;\r
        }\r
+       else if ( e.name == "compilerflag" )\r
+       {\r
+               compilerFlags.push_back ( new CompilerFlag ( project, this, e ) );\r
+               subs_invalid = true;\r
+       }\r
+       else if ( e.name == "linkerflag" )\r
+       {\r
+               linkerFlags.push_back ( new LinkerFlag ( project, this, e ) );\r
+               subs_invalid = true;\r
+       }\r
        else if ( e.name == "property" )\r
        {\r
                throw InvalidBuildFileException (\r
@@ -201,14 +277,30 @@ Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
                return BuildTool;\r
        if ( attribute.value == "staticlibrary" )\r
                return StaticLibrary;\r
+       if ( attribute.value == "objectlibrary" )\r
+               return ObjectLibrary;\r
        if ( attribute.value == "kernel" )\r
                return Kernel;\r
        if ( attribute.value == "kernelmodedll" )\r
                return KernelModeDLL;\r
+       if ( attribute.value == "kernelmodedriver" )\r
+               return KernelModeDriver;\r
        if ( attribute.value == "nativedll" )\r
                return NativeDLL;\r
+       if ( attribute.value == "nativecui" )\r
+               return NativeCUI;\r
        if ( attribute.value == "win32dll" )\r
                return Win32DLL;\r
+       if ( attribute.value == "win32cui" )\r
+               return Win32CUI;\r
+       if ( attribute.value == "win32gui" )\r
+               return Win32GUI;\r
+       if ( attribute.value == "bootloader" )\r
+               return BootLoader;\r
+       if ( attribute.value == "bootsector" )\r
+               return BootSector;\r
+       if ( attribute.value == "iso" )\r
+               return Iso;\r
        throw InvalidAttributeValueException ( location,\r
                                               attribute.name,\r
                                               attribute.value );\r
@@ -223,12 +315,90 @@ Module::GetDefaultModuleExtension () const
                        return EXEPOSTFIX;\r
                case StaticLibrary:\r
                        return ".a";\r
+               case ObjectLibrary:\r
+                       return ".o";\r
                case Kernel:\r
+               case NativeCUI:\r
+               case Win32CUI:\r
+               case Win32GUI:\r
                        return ".exe";\r
                case KernelModeDLL:\r
                case NativeDLL:\r
                case Win32DLL:\r
                        return ".dll";\r
+               case KernelModeDriver:\r
+               case BootLoader:\r
+                       return ".sys";\r
+               case BootSector:\r
+                       return ".o";\r
+               case Iso:\r
+                       return ".iso";\r
+       }\r
+       throw InvalidOperationException ( __FILE__,\r
+                                         __LINE__ );\r
+}\r
+\r
+string\r
+Module::GetDefaultModuleEntrypoint () const\r
+{\r
+       switch (type)\r
+       {\r
+               case Kernel:\r
+                       return "_NtProcessStartup";\r
+               case KernelModeDLL:\r
+                       return "_DriverEntry@8";\r
+               case NativeDLL:\r
+                       return "_DllMainCRTStartup@12";\r
+               case NativeCUI:\r
+                       return "_NtProcessStartup@4";\r
+               case Win32DLL:\r
+                       return "_DllMain@12";\r
+               case Win32CUI:\r
+                       return "_mainCRTStartup";\r
+               case Win32GUI:\r
+                       return "_WinMainCRTStartup";\r
+               case KernelModeDriver:\r
+                       return "_DriverEntry@8";\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
+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
@@ -306,9 +476,38 @@ Module::GetInvocationTarget ( const int index ) const
                          index );\r
 }\r
 \r
+bool\r
+Module::HasFileWithExtensions ( const std::string& extension1,\r
+                                   const std::string& extension2 ) const\r
+{\r
+       for ( size_t i = 0; i < files.size (); i++ )\r
+       {\r
+               File& file = *files[i];\r
+               string extension = GetExtension ( file.name );\r
+               if ( extension == extension1 || extension == extension2 )\r
+                       return true;\r
+       }\r
+       return false;\r
+}\r
 \r
-File::File ( const string& _name )\r
-       : name(_name)\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
 {\r
 }\r
 \r
@@ -431,11 +630,45 @@ Invoke::GetTargets () const
                InvokeFile& file = *output[i];\r
                if ( targets.length () > 0 )\r
                        targets += " ";\r
-               targets += file.name;\r
+               targets += NormalizeFilename ( file.name );\r
        }\r
        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