sync with trunk head (34904)
[reactos.git] / reactos / tools / rbuild / module.cpp
index 20912ce..688a934 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2005 Casper S. Hornstrup
+ * Copyright (C) 2008 HervĂ© Poussineau
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -210,8 +211,6 @@ IfableData::~IfableData()
                delete compilerFlags[i];
        for ( i = 0; i < modules.size(); i++ )
                delete modules[i];
-       for ( i = 0; i < ifs.size (); i++ )
-               delete ifs[i];
        for ( i = 0; i < compilationUnits.size (); i++ )
                delete compilationUnits[i];
 }
@@ -229,8 +228,6 @@ void IfableData::ProcessXML ()
                properties[i]->ProcessXML ();
        for ( i = 0; i < compilerFlags.size(); i++ )
                compilerFlags[i]->ProcessXML ();
-       for ( i = 0; i < ifs.size (); i++ )
-               ifs[i]->ProcessXML ();
        for ( i = 0; i < compilationUnits.size (); i++ )
                compilationUnits[i]->ProcessXML ();
 }
@@ -242,12 +239,15 @@ Module::Module ( const Project& project,
          node (moduleNode),
          importLibrary (NULL),
          metadata (NULL),
+         bootSector (NULL),
          bootstrap (NULL),
          autoRegister(NULL),
          linkerScript (NULL),
          pch (NULL),
          cplusplus (false),
-         host (HostDefault)
+         host (HostDefault),
+         output (NULL),
+         install (NULL)
 {
        if ( node.name != "module" )
                throw InvalidOperationException ( __FILE__,
@@ -417,13 +417,31 @@ Module::Module ( const Project& project,
                                            att->value,
                                            &moduleNode );
        }
-       else
+
+       att = moduleNode.GetAttribute ( "output", false );
+       if ( att != NULL )
+       {
+               if (output != NULL)
+               {
+                       printf ( "%s: WARNING: 'installname' overrides 'output' also defined for this module.\n",
+                               moduleNode.location.c_str() );
+               }
+               else
+               {
+                       output = new FileLocation ( GetTargetDirectoryTree (),
+                                                                               modulePath,
+                                                                               att->value,
+                                                                               &moduleNode );
+               }
+       }
+
+       /* If no one has set the output file for this module set it automatically */
+       if (output == NULL)
        {
-               install = NULL;
                output = new FileLocation ( GetTargetDirectoryTree (),
-                                           modulePath,
-                                           name + extension,
-                                           &moduleNode );
+                                                                       modulePath,
+                                                                       name + extension,
+                                                                       &moduleNode );
        }
 
        att = moduleNode.GetAttribute ( "allowwarnings", false );
@@ -466,6 +484,32 @@ Module::Module ( const Project& project,
                }
        }
 
+       att = moduleNode.GetAttribute ( "description", false );
+       if (att != NULL )
+       {
+               description = project.ResolveProperties(att->value);
+       }
+       else
+               description = "";
+
+       att = moduleNode.GetAttribute ( "lcid", false );
+       if (type == KeyboardLayout && att != NULL )
+               lcid = att->value;
+       else
+               lcid = "";
+
+       att = moduleNode.GetAttribute ( "layoutid", false );
+       if (type == KeyboardLayout && att != NULL )
+               layoutId = att->value;
+       else
+               layoutId = "";
+
+       att = moduleNode.GetAttribute ( "layoutnameresid", false );
+       if (type == KeyboardLayout && att != NULL )
+               layoutNameResId = att->value;
+       else
+               layoutNameResId = "";
+
        SetImportLibrary ( NULL );
 }
 
@@ -488,8 +532,20 @@ Module::~Module ()
                delete pch;
        if ( install )
                delete install;
+       if ( metadata )
+               delete metadata;
+       if ( bootstrap )
+               delete bootstrap;
+       if ( importLibrary )
+               delete importLibrary;
+       if ( bootSector )
+               delete  bootSector;
+       if ( dependency )
+               delete  dependency;
+       if ( autoRegister )
+               delete autoRegister;
        if ( output )
-               delete output;
+               delete output;          
 }
 
 void
@@ -547,7 +603,6 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                                   const string& relative_path,
                                ParseContext& parseContext )
 {
-       If* pOldIf = parseContext.ifData;
        CompilationUnit* pOldCompilationUnit = parseContext.compilationUnit;
        bool subs_invalid = false;
        string subpath ( relative_path );
@@ -593,46 +648,35 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                else
                {
                        CompilationUnit* pCompilationUnit = new CompilationUnit ( pFile );
-                       if ( parseContext.ifData )
-                               parseContext.ifData->data.compilationUnits.push_back ( pCompilationUnit );
+                       string ext = ToLower ( GetExtension ( e.value ) );
+                       if ( ext == ".idl" )
+                       {
+                               // put .idl files at the start of the module
+                               non_if_data.compilationUnits.insert (
+                                       non_if_data.compilationUnits.begin(),
+                                       pCompilationUnit );
+                       }
+                       else if ( ext == ".asm" || ext == ".s" )
+                       {
+                               // put .asm files at the end of the module
+                               non_if_data.compilationUnits.push_back ( pCompilationUnit );
+                               non_if_data.asmFiles++;
+                       }
                        else
                        {
-                               string ext = ToLower ( GetExtension ( e.value ) );
-                               if ( ext == ".idl" )
-                               {
-                                       // put .idl files at the start of the module
-                                       non_if_data.compilationUnits.insert (
-                                               non_if_data.compilationUnits.begin(),
-                                               pCompilationUnit );
-                               }
-                               else if ( ext == ".asm" || ext == ".s" )
-                               {
-                                       // put .asm files at the end of the module
-                                       non_if_data.compilationUnits.push_back ( pCompilationUnit );
-                                       non_if_data.asmFiles++;
-                               }
-                               else
-                               {
-                                       // put other files in the middle
-                                       non_if_data.compilationUnits.insert (
-                                               non_if_data.compilationUnits.end() - non_if_data.asmFiles,
-                                               pCompilationUnit );
-                               }
+                               // put other files in the middle
+                               non_if_data.compilationUnits.insert (
+                                       non_if_data.compilationUnits.end() - non_if_data.asmFiles,
+                                       pCompilationUnit );
                        }
                }
-               if ( parseContext.ifData )
-                       parseContext.ifData->data.files.push_back ( pFile );
-               else
-                       non_if_data.files.push_back ( pFile );
+               non_if_data.files.push_back ( pFile );
                subs_invalid = true;
        }
        else if ( e.name == "library" && e.value.size () )
        {
                Library* pLibrary = new Library ( e, *this, e.value );
-               if ( parseContext.ifData )
-                       parseContext.ifData->data.libraries.push_back ( pLibrary );
-               else
-                       non_if_data.libraries.push_back ( pLibrary );
+               non_if_data.libraries.push_back ( pLibrary );
                subs_invalid = true;
        }
        else if ( e.name == "directory" )
@@ -659,96 +703,80 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
        else if ( e.name == "include" )
        {
                Include* include = new Include ( project, &e, this );
-               if ( parseContext.ifData )
-                       parseContext.ifData->data.includes.push_back ( include );
-               else
-                       non_if_data.includes.push_back ( include );
+               non_if_data.includes.push_back ( include );
                subs_invalid = true;
        }
        else if ( e.name == "define" )
        {
                Define* pDefine = new Define ( project, this, e );
-               if ( parseContext.ifData )
-                       parseContext.ifData->data.defines.push_back ( pDefine );
-               else
-                       non_if_data.defines.push_back ( pDefine );
+               non_if_data.defines.push_back ( pDefine );
                subs_invalid = true;
        }
        else if ( e.name == "metadata" )
        {
-               if ( parseContext.ifData )
-               {
-                       throw XMLInvalidBuildFileException (
-                               e.location,
-                               "<metadata> is not a valid sub-element of <if>" );
-               }
                metadata = new Metadata ( e, *this );
                subs_invalid = false;
        }
        else if ( e.name == "invoke" )
        {
-               if ( parseContext.ifData )
-               {
-                       throw XMLInvalidBuildFileException (
-                               e.location,
-                               "<invoke> is not a valid sub-element of <if>" );
-               }
                invocations.push_back ( new Invoke ( e, *this ) );
                subs_invalid = false;
        }
        else if ( e.name == "dependency" )
        {
-               if ( parseContext.ifData )
-               {
-                       throw XMLInvalidBuildFileException (
-                               e.location,
-                               "<dependency> is not a valid sub-element of <if>" );
-               }
                dependencies.push_back ( new Dependency ( e, *this ) );
                subs_invalid = true;
        }
+       else if ( e.name == "bootsector" )
+       {
+               bootSector = new Bootsector ( e, this );
+               subs_invalid = true;
+       }
        else if ( e.name == "importlibrary" )
        {
-               if ( parseContext.ifData )
-               {
-                       throw XMLInvalidBuildFileException (
-                               e.location,
-                               "<importlibrary> is not a valid sub-element of <if>" );
-               }
                if ( importLibrary )
                {
                        throw XMLInvalidBuildFileException (
                                e.location,
                                "Only one <importlibrary> is valid per module" );
                }
-               SetImportLibrary ( new ImportLibrary ( project, e, *this ) );
+               SetImportLibrary ( new ImportLibrary ( project, e, this ) );
                subs_invalid = true;
        }
-       else if ( e.name == "if" )
+       else if ( e.name == "if" || e.name == "ifnot" )
        {
-               parseContext.ifData = new If ( e, project, this );
-               if ( pOldIf )
-                       pOldIf->data.ifs.push_back ( parseContext.ifData );
-               else
-                       non_if_data.ifs.push_back ( parseContext.ifData );
-               subs_invalid = false;
-       }
-       else if ( e.name == "ifnot" )
-       {
-               parseContext.ifData = new If ( e, project, this, true );
-               if ( pOldIf )
-                       pOldIf->data.ifs.push_back ( parseContext.ifData );
-               else
-                       non_if_data.ifs.push_back ( parseContext.ifData );
+               const XMLAttribute* name;
+               name = e.GetAttribute ( "property", true );
+               assert( name );
+               const Property *property = project.LookupProperty( name->value );
+               if ( !property )
+               {
+                       // Property not found
+                       throw InvalidOperationException ( __FILE__,
+                                                         __LINE__,
+                                                         "Test on unknown property '%s' at %s",
+                                                         name->value.c_str (), e.location.c_str () );
+               }
+
+               const XMLAttribute* value;
+               value = e.GetAttribute ( "value", true );
+               assert( value );
+
+               bool negate = ( e.name == "ifnot" );
+               bool equality = ( property->value == value->value );
+               if ( equality == negate )
+               {
+                       // Failed, skip this element
+                       if ( project.configuration.Verbose )
+                               printf("Skipping 'If' at %s\n", e.location.c_str () );
+                       return;
+               }
                subs_invalid = false;
        }
        else if ( e.name == "compilerflag" )
        {
                CompilerFlag* pCompilerFlag = new CompilerFlag ( project, this, e );
-               if ( parseContext.ifData )
-                       parseContext.ifData->data.compilerFlags.push_back ( pCompilerFlag );
-               else
-                       non_if_data.compilerFlags.push_back ( pCompilerFlag );
+               non_if_data.compilerFlags.push_back ( pCompilerFlag );
                subs_invalid = true;
        }
        else if ( e.name == "linkerflag" )
@@ -758,12 +786,6 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
        }
        else if ( e.name == "linkerscript" )
        {
-               if ( parseContext.ifData )
-               {
-                       throw XMLInvalidBuildFileException (
-                               e.location,
-                               "<linkerscript> is not a valid sub-element of <if>" );
-               }
                if ( linkerScript )
                {
                        throw XMLInvalidBuildFileException (
@@ -774,14 +796,14 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                if ( pos == string::npos )
                {
                        linkerScript = new LinkerScript (
-                               e, *this, FileLocation ( SourceDirectory, relative_path, e.value, &e ) );
+                               e, *this, new FileLocation ( SourceDirectory, relative_path, e.value, &e ) );
                }
                else
                {
                        string dir = e.value.substr ( 0, pos );
                        string name = e.value.substr ( pos + 1);
                        linkerScript = new LinkerScript (
-                               e, *this, FileLocation ( SourceDirectory, relative_path + sSep + dir, name, &e ) );
+                               e, *this, new FileLocation ( SourceDirectory, relative_path + sSep + dir, name, &e ) );
                }
                subs_invalid = true;
        }
@@ -803,12 +825,6 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
        }
        else if ( e.name == "pch" )
        {
-               if ( parseContext.ifData )
-               {
-                       throw XMLInvalidBuildFileException (
-                               e.location,
-                               "<pch> is not a valid sub-element of <if>" );
-               }
                if ( pch )
                {
                        throw XMLInvalidBuildFileException (
@@ -819,14 +835,14 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                if ( pos == string::npos )
                {
                        pch = new PchFile (
-                               e, *this, FileLocation ( SourceDirectory, relative_path, e.value, &e ) );
+                               e, *this, new FileLocation ( SourceDirectory, relative_path, e.value, &e ) );
                }
                else
                {
                        string dir = e.value.substr ( 0, pos );
                        string name = e.value.substr ( pos + 1);
                        pch = new PchFile (
-                               e, *this, FileLocation ( SourceDirectory, relative_path + sSep + dir, name, &e ) );
+                               e, *this, new FileLocation ( SourceDirectory, relative_path + sSep + dir, name, &e ) );
                }
                subs_invalid = true;
        }
@@ -835,10 +851,7 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                if ( project.configuration.CompilationUnitsEnabled )
                {
                        CompilationUnit* pCompilationUnit = new CompilationUnit ( &project, this, &e );
-                       if ( parseContext.ifData )
-                               parseContext.ifData->data.compilationUnits.push_back ( pCompilationUnit );
-                       else
-                               non_if_data.compilationUnits.push_back ( pCompilationUnit );
+                       non_if_data.compilationUnits.push_back ( pCompilationUnit );
                        parseContext.compilationUnit = pCompilationUnit;
                }
                subs_invalid = false;
@@ -864,7 +877,6 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
        }
        for ( size_t i = 0; i < e.subElements.size (); i++ )
                ProcessXMLSubElement ( *e.subElements[i], subdirectory, subpath, parseContext );
-       parseContext.ifData = pOldIf;
        parseContext.compilationUnit = pOldCompilationUnit;
 }
 
@@ -875,6 +887,8 @@ Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
                return BuildTool;
        if ( attribute.value == "staticlibrary" )
                return StaticLibrary;
+       if ( attribute.value == "hoststaticlibrary" )
+               return HostStaticLibrary;
        if ( attribute.value == "objectlibrary" )
                return ObjectLibrary;
        if ( attribute.value == "kernel" )
@@ -887,6 +901,8 @@ Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
                return NativeDLL;
        if ( attribute.value == "nativecui" )
                return NativeCUI;
+       if ( attribute.value == "keyboardlayout" )
+               return KeyboardLayout;
        if ( attribute.value == "win32dll" )
                return Win32DLL;
        if ( attribute.value == "win32ocx" )
@@ -927,6 +943,10 @@ Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
                return EmbeddedTypeLib;
        if ( attribute.value == "elfexecutable" )
                return ElfExecutable;
+       if ( attribute.value == "cabinet" )
+               return Cabinet;
+       if ( attribute.value == "messageheader" )
+               return MessageHeader;
        throw InvalidAttributeValueException ( location,
                                               attribute.name,
                                               attribute.value );
@@ -939,6 +959,7 @@ Module::GetTargetDirectoryTree () const
        {
                case Kernel:
                case KernelModeDLL:
+               case KeyboardLayout:
                case NativeDLL:
                case Win32DLL:
                case Win32OCX:
@@ -956,16 +977,19 @@ Module::GetTargetDirectoryTree () const
                case LiveIso:
                case IsoRegTest:
                case LiveIsoRegTest:
-               case EmbeddedTypeLib:
                case ElfExecutable:
+               case Cabinet:
                        return OutputDirectory;
+               case EmbeddedTypeLib:
                case StaticLibrary:
+               case HostStaticLibrary:
                case ObjectLibrary:
                case RpcServer:
                case RpcClient:
                case RpcProxy:
                case Alias:
                case IdlHeader:
+               case MessageHeader:
                        return IntermediateDirectory;
                case TypeDontCare:
                        break;
@@ -985,6 +1009,7 @@ Module::GetDefaultModuleExtension () const
                        return ExePostfix;
                case BootProgram:
                case StaticLibrary:
+               case HostStaticLibrary:
                        return ".a";
                case ObjectLibrary:
                        return ".o";
@@ -998,6 +1023,7 @@ Module::GetDefaultModuleExtension () const
 
                case KernelModeDLL:
                case NativeDLL:
+               case KeyboardLayout:
                case Win32DLL:
                        return ".dll";
                case Win32OCX:
@@ -1005,6 +1031,8 @@ Module::GetDefaultModuleExtension () const
                case KernelModeDriver:
                case BootLoader:
                        return ".sys";
+               case Cabinet:
+                       return ".cab";
                case BootSector:
                        return ".o";
                case Iso:
@@ -1021,6 +1049,7 @@ Module::GetDefaultModuleExtension () const
                case Alias:
                case ElfExecutable:
                case IdlHeader:
+               case MessageHeader:
                        return "";
                case EmbeddedTypeLib:
                        return ".tlb";
@@ -1038,15 +1067,20 @@ Module::GetDefaultModuleEntrypoint () const
        {
                case Kernel:
                        return "KiSystemStartup";
+               case KeyboardLayout:
                case KernelModeDLL:
                case KernelModeDriver:
+            if (Environment::GetArch() == "arm") return "DriverEntry";
                        return "DriverEntry@8";
                case NativeDLL:
-                       return "DllMainCRTStartup@12";
+            if (Environment::GetArch() == "arm") return "DllMainCRTStartup";
+            return "DllMainCRTStartup@12";
                case NativeCUI:
-                       return "NtProcessStartup@4";
+            if (Environment::GetArch() == "arm") return "NtProcessStartup";
+            return "NtProcessStartup@4";            
                case Win32DLL:
                case Win32OCX:
+            if (Environment::GetArch() == "arm") return "DllMain";
                        return "DllMain@12";
                case Win32CUI:
                case Test:
@@ -1062,6 +1096,7 @@ Module::GetDefaultModuleEntrypoint () const
                                return "WinMainCRTStartup";
                case BuildTool:
                case StaticLibrary:
+               case HostStaticLibrary:
                case ObjectLibrary:
                case BootLoader:
                case BootSector:
@@ -1075,8 +1110,10 @@ Module::GetDefaultModuleEntrypoint () const
                case Alias:
                case BootProgram:
                case IdlHeader:
+               case MessageHeader:
                case ElfExecutable:
                case EmbeddedTypeLib:
+               case Cabinet:
                        return "";
                case TypeDontCare:
                        break;
@@ -1103,6 +1140,7 @@ Module::GetDefaultModuleBaseaddress () const
                case Win32SCR:
                case Win32GUI:
                        return "0x00400000";
+               case KeyboardLayout:
                case KernelModeDLL:
                case KernelModeDriver:
                        return "0x00010000";
@@ -1110,6 +1148,7 @@ Module::GetDefaultModuleBaseaddress () const
                        return "0xe00000";
                case BuildTool:
                case StaticLibrary:
+               case HostStaticLibrary:
                case ObjectLibrary:
                case BootLoader:
                case BootSector:
@@ -1123,7 +1162,9 @@ Module::GetDefaultModuleBaseaddress () const
                case Alias:
                case BootProgram:
                case IdlHeader:
+               case MessageHeader:
                case EmbeddedTypeLib:
+               case Cabinet:
                        return "";
                case TypeDontCare:
                        break;
@@ -1135,7 +1176,7 @@ Module::GetDefaultModuleBaseaddress () const
 bool
 Module::HasImportLibrary () const
 {
-       return importLibrary != NULL && type != StaticLibrary;
+       return importLibrary != NULL && type != StaticLibrary && type != HostStaticLibrary;
 }
 
 bool
@@ -1146,6 +1187,7 @@ Module::IsDLL () const
                case Kernel:
                case KernelModeDLL:
                case NativeDLL:
+               case KeyboardLayout:
                case Win32DLL:
                case Win32OCX:
                case KernelModeDriver:
@@ -1157,6 +1199,7 @@ Module::IsDLL () const
                case Win32GUI:
                case BuildTool:
                case StaticLibrary:
+               case HostStaticLibrary:
                case ObjectLibrary:
                case BootLoader:
                case BootSector:
@@ -1170,8 +1213,10 @@ Module::IsDLL () const
                case RpcProxy:
                case Alias:
                case IdlHeader:
+               case MessageHeader:
                case EmbeddedTypeLib:
                case ElfExecutable:
+               case Cabinet:
                        return false;
                case TypeDontCare:
                        break;
@@ -1217,6 +1262,14 @@ Module::GetEntryPoint(bool leadingUnderscore) const
                result = "_";
 
        result += entrypoint;
+
+       if (Environment::GetArch() == "amd64")
+       {
+               size_t at_index = result.find_last_of( '@' );
+               if ( at_index != result.npos )
+                       return result.substr (0, at_index );
+       }
+
        return result;
 }
 
@@ -1232,11 +1285,6 @@ Module::HasFileWithExtension (
                if ( compilationUnit->HasFileWithExtension ( extension ) )
                        return true;
        }
-       for ( i = 0; i < data.ifs.size (); i++ )
-       {
-               if ( HasFileWithExtension ( data.ifs[i]->data, extension ) )
-                       return true;
-       }
        return false;
 }
 
@@ -1534,6 +1582,57 @@ Dependency::ProcessXML()
        }
 }
 
+Bootsector::Bootsector ( const XMLElement& _node,
+                         const Module* _module )
+       : node (_node),
+         module (_module),
+         bootSectorModule (NULL)
+{
+       if ( !IsSupportedModuleType ( module->type ) )
+       {
+               throw XMLInvalidBuildFileException (
+                       node.location,
+                       "<bootsector> is not applicable for this module type." );
+       }
+
+       bootSectorModule = module->project.LocateModule ( node.value );
+       if ( bootSectorModule == NULL )
+       {
+               throw XMLInvalidBuildFileException (
+                       node.location,
+                       "module '%s' depend on non-existant module '%s'",
+                       module->name.c_str(),
+                       node.value.c_str() );
+       }
+
+       if (bootSectorModule->type != BootSector)
+       {
+               throw XMLInvalidBuildFileException (
+                       node.location,
+                       "module '%s' is referencing non BootSector module '%s'",
+                       module->name.c_str(),
+                       node.value.c_str() );
+       }
+}
+
+void
+Bootsector::ProcessXML()
+{
+}
+
+bool
+Bootsector::IsSupportedModuleType ( ModuleType type )
+{
+       if ( type == Iso ||
+            type == LiveIso ||
+            type == IsoRegTest ||
+                type == LiveIsoRegTest )
+       {
+               return true;
+       }
+
+       return false;
+}
 
 Metadata::Metadata ( const XMLElement& _node,
                      const Module& _module )
@@ -1590,33 +1689,75 @@ Metadata::Metadata ( const XMLElement& _node,
 }
 
 
+ImportLibrary::~ImportLibrary ()
+{
+       delete source;
+}
+
+
 ImportLibrary::ImportLibrary ( const Project& project,
                                const XMLElement& node,
-                               const Module& module )
+                               const Module* module )
        : XmlNode ( project, node ),
          module (module)
 {
+       DirectoryLocation directory = SourceDirectory;
+       const Module* base = module;
        const XMLAttribute* dllname = node.GetAttribute ( "dllname", false );
        const XMLAttribute* definition = node.GetAttribute ( "definition", true );
        assert ( definition );
 
+       string relative_path;
+       const XMLAttribute* att = node.GetAttribute ( "base", false );
+       if ( att )
+       {
+                       base = project.LocateModule ( att->value );
+                       if ( !base )
+                               throw XMLInvalidBuildFileException (
+                                       node.location,
+                                       "<importlibrary> attribute 'base' references non-existant module '%s'",
+                                       att->value.c_str() );
+
+       }
+
+       if ( base )
+       {
+               relative_path = base->output->relative_path;
+               if ( node.value.length () > 0 && node.value != "." )
+                       relative_path += sSep + node.value;
+       }
+       else
+               relative_path = node.value;
+
+       att = node.GetAttribute ( "root", false );
+       if ( att )
+       {
+               if ( att->value == "intermediate" )
+                       directory = IntermediateDirectory;
+               else
+                       throw InvalidAttributeValueException ( node.location,
+                                                              "root",
+                                                              att->value );
+       }
+       else
+       {
+               size_t index = definition->value.rfind ( ".spec.def" );
+               if ( index != string::npos )
+                       directory = IntermediateDirectory;
+       }
+
        if ( dllname )
                this->dllname = dllname->value;
-       else if ( module.type == StaticLibrary )
+       else if ( module->type == StaticLibrary || module->type == HostStaticLibrary )
                throw XMLInvalidBuildFileException (
                    node.location,
                    "<importlibrary> dllname attribute required." );
 
-       DirectoryLocation directory = SourceDirectory;
-       size_t index = definition->value.rfind ( ".spec.def" );
-       if ( index != string::npos )
-               directory = IntermediateDirectory;
-
-       index = definition->value.find_last_of ( "/\\" );
+       size_t index = definition->value.find_last_of ( "/\\" );
        if ( index == string::npos )
        {
                source = new FileLocation ( directory,
-                                           module.output->relative_path,
+                                           base->output->relative_path,
                                            definition->value,
                                            &node );
        }
@@ -1625,41 +1766,13 @@ ImportLibrary::ImportLibrary ( const Project& project,
                string dir = definition->value.substr ( 0, index );
                string name = definition->value.substr ( index + 1);
                source = new FileLocation ( directory,
-                                           NormalizeFilename ( module.output->relative_path + sSep + dir ),
+                                           NormalizeFilename ( base->output->relative_path + sSep + dir ),
                                            name,
                                            &node );
        }
 }
 
 
-If::If ( const XMLElement& node_,
-         const Project& project_,
-         const Module* module_,
-         const bool negated_ )
-       : node(node_), project(project_), module(module_), negated(negated_)
-{
-       const XMLAttribute* att;
-
-       att = node.GetAttribute ( "property", true );
-       assert(att);
-       property = att->value;
-
-       att = node.GetAttribute ( "value", true );
-       assert(att);
-       value = att->value;
-}
-
-If::~If ()
-{
-}
-
-void
-If::ProcessXML()
-{
-
-}
-
-
 Property::Property ( const XMLElement& node_,
                      const Project& project_,
                      const Module* module_ )
@@ -1674,6 +1787,25 @@ Property::Property ( const XMLElement& node_,
        att = node_.GetAttribute ( "value", true );
        assert(att);
        value = att->value;
+
+       att = node_.GetAttribute ( "internal", false );
+       if ( att != NULL )
+       {
+               const char* p = att->value.c_str();
+               if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
+                       isInternal = true;
+               else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
+                       isInternal = false;
+               else
+               {
+                       throw InvalidAttributeValueException (
+                               node_.location,
+                               "internal",
+                               att->value );
+               }
+       }
+       else
+               isInternal = false;
 }
 
 Property::Property ( const Project& project_,
@@ -1693,11 +1825,16 @@ Property::ProcessXML()
 PchFile::PchFile (
        const XMLElement& node_,
        const Module& module_,
-       const FileLocationfile_ )
+       const FileLocation *file_ )
        : node(node_), module(module_), file(file_)
 {
 }
 
+PchFile::~PchFile()
+{
+       delete file;
+}
+
 void
 PchFile::ProcessXML()
 {