sync with trunk head (34904)
[reactos.git] / reactos / tools / rbuild / module.cpp
index 1073fb1..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
@@ -118,53 +119,41 @@ ReplaceExtension (
 
 string
 GetSubPath (
+       const Project& project,
        const string& location,
        const string& path,
        const string& att_value )
 {
        if ( !att_value.size() )
-               throw InvalidBuildFileException (
+               throw XMLInvalidBuildFileException (
                        location,
                        "<directory> tag has empty 'name' attribute" );
        if ( strpbrk ( att_value.c_str (), "/\\?*:<>|" ) )
-               throw InvalidBuildFileException (
+               throw XMLInvalidBuildFileException (
                        location,
                        "<directory> tag has invalid characters in 'name' attribute" );
        if ( !path.size() )
                return att_value;
+
        return FixSeparator(path + cSep + att_value);
 }
 
-string
+static string
 GetExtension ( const string& filename )
 {
        size_t index = filename.find_last_of ( '/' );
        if (index == string::npos) index = 0;
        string tmp = filename.substr( index, filename.size() - index );
        size_t ext_index = tmp.find_last_of( '.' );
-       if (ext_index != string::npos) 
+       if (ext_index != string::npos)
                return filename.substr ( index + ext_index, filename.size() );
        return "";
 }
 
 string
-GetDirectory ( const string& filename )
+GetExtension ( const FileLocation& file )
 {
-       size_t index = filename.find_last_of ( cSep );
-       if ( index == string::npos )
-               return "";
-       else
-               return filename.substr ( 0, index );
-}
-
-string
-GetFilename ( const string& filename )
-{
-       size_t index = filename.find_last_of ( cSep );
-       if ( index == string::npos )
-               return filename;
-       else
-               return filename.substr ( index + 1, filename.length () - index );
+       return GetExtension ( file.name );
 }
 
 string
@@ -187,6 +176,26 @@ GetBooleanValue ( const string& value )
                return false;
 }
 
+string
+ToLower ( string filename )
+{
+       for ( size_t i = 1; i < filename.length (); i++ )
+               filename[i] = tolower ( filename[i] );
+       return filename;
+}
+
+IfableData::IfableData( )
+       : asmFiles ( 0 )
+{
+}
+
+void IfableData::ExtractModules( std::vector<Module*> &modules )
+{
+       size_t i;
+       for ( i = 0; i < this->modules.size (); i++ )
+               modules.push_back(this->modules[i]);
+}
+
 IfableData::~IfableData()
 {
        size_t i;
@@ -200,8 +209,8 @@ IfableData::~IfableData()
                delete properties[i];
        for ( i = 0; i < compilerFlags.size (); i++ )
                delete compilerFlags[i];
-       for ( i = 0; i < ifs.size (); i++ )
-               delete ifs[i];
+       for ( i = 0; i < modules.size(); i++ )
+               delete modules[i];
        for ( i = 0; i < compilationUnits.size (); i++ )
                delete compilationUnits[i];
 }
@@ -219,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 ();
 }
@@ -231,24 +238,31 @@ Module::Module ( const Project& project,
        : 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__,
                                                  __LINE__,
                                                  "Module created with non-<module> node" );
 
-       xmlbuildFile = Path::RelativeFromWorkingDirectory ( moduleNode.xmlFile->filename () );
+       xmlbuildFile = FixSeparator ( Path::RelativeFromWorkingDirectory ( moduleNode.xmlFile->filename () ) );
 
-       path = FixSeparator ( modulePath );
+       const XMLAttribute* att = moduleNode.GetAttribute ( "name", true );
+       assert(att);
+       name = att->value;
 
        enabled = true;
 
-       const XMLAttribute* att = moduleNode.GetAttribute ( "if", false );
+       att = moduleNode.GetAttribute ( "if", false );
        if ( att != NULL )
                enabled = GetBooleanValue ( project.ResolveProperties ( att->value ) );
 
@@ -256,9 +270,8 @@ Module::Module ( const Project& project,
        if ( att != NULL )
                enabled = !GetBooleanValue ( project.ResolveProperties ( att->value ) );
 
-       att = moduleNode.GetAttribute ( "name", true );
-       assert(att);
-       name = att->value;
+       if ( !enabled && project.configuration.Verbose )
+               printf("Module '%s' has been disabled.\n", name.c_str () );
 
        att = moduleNode.GetAttribute ( "type", true );
        assert(att);
@@ -289,11 +302,35 @@ Module::Module ( const Project& project,
        else
                isUnicode = false;
 
+       if (isUnicode)
+       {
+               // Always define UNICODE and _UNICODE
+               Define* pDefine = new Define ( project, this, "UNICODE" );
+               non_if_data.defines.push_back ( pDefine );
+
+               pDefine = new Define ( project, this, "_UNICODE" );
+               non_if_data.defines.push_back ( pDefine );
+       }
+
        att = moduleNode.GetAttribute ( "entrypoint", false );
        if ( att != NULL )
+       {
+               if ( att->value == "" )
+               {
+                       throw InvalidAttributeValueException (
+                               moduleNode.location,
+                               "entrypoint",
+                               att->value );
+               }
+
                entrypoint = att->value;
+               isDefaultEntryPoint = false;
+       }
        else
+       {
                entrypoint = GetDefaultModuleEntrypoint ();
+               isDefaultEntryPoint = true;
+       }
 
        att = moduleNode.GetAttribute ( "baseaddress", false );
        if ( att != NULL )
@@ -320,6 +357,12 @@ Module::Module ( const Project& project,
        else
                mangledSymbols = false;
 
+       att = moduleNode.GetAttribute ( "underscoresymbols", false );
+       if ( att != NULL )
+               underscoreSymbols = att->value == "true";
+       else
+               underscoreSymbols = false;
+
        att = moduleNode.GetAttribute ( "host", false );
        if ( att != NULL )
        {
@@ -337,27 +380,69 @@ Module::Module ( const Project& project,
                }
        }
 
-       att = moduleNode.GetAttribute ( "prefix", false );
+       att = moduleNode.GetAttribute ( "isstartuplib", false );
        if ( att != NULL )
-               prefix = att->value;
+       {
+               const char* p = att->value.c_str();
+               if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
+                       isStartupLib = true;
+               else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
+                       isStartupLib = false;
+               else
+               {
+                       throw InvalidAttributeValueException (
+                               moduleNode.location,
+                               "host",
+                               att->value );
+               }
+       }
+       else
+               isStartupLib = false;
 
-       att = moduleNode.GetAttribute ( "installbase", false );
+       att = moduleNode.GetAttribute ( "prefix", false );
        if ( att != NULL )
-               installBase = att->value;
-       else
-               installBase = "";
+               prefix = att->value;
 
        att = moduleNode.GetAttribute ( "installname", false );
        if ( att != NULL )
-               installName = att->value;
-       else
-               installName = "";
-       
-       att = moduleNode.GetAttribute ( "usewrc", false );
+       {
+               const XMLAttribute* installbase = moduleNode.GetAttribute ( "installbase", false );
+               install = new FileLocation ( InstallDirectory,
+                                            installbase ? installbase->value : "",
+                                            att->value,
+                                            &moduleNode );
+
+               output = new FileLocation ( GetTargetDirectoryTree (),
+                                           modulePath,
+                                           att->value,
+                                           &moduleNode );
+       }
+
+       att = moduleNode.GetAttribute ( "output", false );
        if ( att != NULL )
-               useWRC = att->value == "true";
-       else
-               useWRC = true;
+       {
+               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)
+       {
+               output = new FileLocation ( GetTargetDirectoryTree (),
+                                                                       modulePath,
+                                                                       name + extension,
+                                                                       &moduleNode );
+       }
 
        att = moduleNode.GetAttribute ( "allowwarnings", false );
        if ( att == NULL )
@@ -379,6 +464,53 @@ Module::Module ( const Project& project,
                aliasedModuleName = att->value;
        else
                aliasedModuleName = "";
+
+       if ( type == BootProgram )
+       {
+               att = moduleNode.GetAttribute ( "payload", true );
+               payload = att->value;
+       }
+
+       if ( type == BootProgram || type == ElfExecutable )
+       {
+               att = moduleNode.GetAttribute ( "buildtype", false );
+               if ( att != NULL )
+               {
+                       buildtype = att->value;
+               }
+               else
+               {
+                       buildtype = "BOOTPROG";
+               }
+       }
+
+       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 );
 }
 
 Module::~Module ()
@@ -398,6 +530,22 @@ Module::~Module ()
                delete linkerScript;
        if ( pch )
                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;          
 }
 
 void
@@ -405,25 +553,30 @@ Module::ProcessXML()
 {
        if ( type == Alias )
        {
+               aliasedModuleName = project.ResolveProperties ( aliasedModuleName );
                if ( aliasedModuleName == name )
-                       throw InvalidBuildFileException (
+               {
+                       throw XMLInvalidBuildFileException (
                                node.location,
                                "module '%s' cannot link against itself",
                                name.c_str() );
-               const Module* m = project.LocateModule ( aliasedModuleName );
-               if ( !m )
-                       throw InvalidBuildFileException (
+               }
+               const Module* m = project.LocateModule ( aliasedModuleName );
+               if ( !m && enabled )
+               {
+                       throw XMLInvalidBuildFileException (
                                node.location,
                                "module '%s' trying to alias non-existant module '%s'",
                                name.c_str(),
                                aliasedModuleName.c_str() );
+               }
        }
 
        size_t i;
        for ( i = 0; i < node.subElements.size(); i++ )
        {
                ParseContext parseContext;
-               ProcessXMLSubElement ( *node.subElements[i], path, parseContext );
+               ProcessXMLSubElement ( *node.subElements[i], SourceDirectory, output->relative_path, parseContext );
        }
        for ( i = 0; i < invocations.size(); i++ )
                invocations[i]->ProcessXML ();
@@ -440,17 +593,20 @@ Module::ProcessXML()
                linkerScript->ProcessXML();
        if ( pch )
                pch->ProcessXML();
+       if ( autoRegister )
+               autoRegister->ProcessXML();
 }
 
 void
 Module::ProcessXMLSubElement ( const XMLElement& e,
-                               const string& path,
+                               DirectoryLocation directory,
+                                  const string& relative_path,
                                ParseContext& parseContext )
 {
-       If* pOldIf = parseContext.ifData;
        CompilationUnit* pOldCompilationUnit = parseContext.compilationUnit;
        bool subs_invalid = false;
-       string subpath ( path );
+       string subpath ( relative_path );
+       DirectoryLocation subdirectory = SourceDirectory;
        if ( e.name == "file" && e.value.size () > 0 )
        {
                bool first = false;
@@ -460,9 +616,11 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                        if ( !stricmp ( att->value.c_str(), "true" ) )
                                first = true;
                        else if ( stricmp ( att->value.c_str(), "false" ) )
-                               throw InvalidBuildFileException (
+                       {
+                               throw XMLInvalidBuildFileException (
                                        e.location,
                                        "attribute 'first' of <file> element can only be 'true' or 'false'" );
+                       }
                }
                string switches = "";
                att = e.GetAttribute ( "switches", false );
@@ -479,115 +637,146 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                        else if ( !stricmp ( ext.c_str(), ".cxx" ) )
                                cplusplus = true;
                }
-               File* pFile = new File ( FixSeparator ( path + cSep + e.value ),
+               File* pFile = new File ( directory,
+                                        relative_path,
+                                        e.value,
                                         first,
                                         switches,
                                         false );
                if ( parseContext.compilationUnit )
-                       parseContext.compilationUnit->files.push_back ( pFile );
+                       parseContext.compilationUnit->AddFile ( pFile );
                else
                {
                        CompilationUnit* pCompilationUnit = new CompilationUnit ( pFile );
-                       if ( parseContext.ifData )
-                               parseContext.ifData->data.compilationUnits.push_back ( pCompilationUnit );
-                       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 );
+                       }
                }
-               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" )
        {
                const XMLAttribute* att = e.GetAttribute ( "name", true );
+               const XMLAttribute* root = e.GetAttribute ( "root", false );
                assert(att);
-               subpath = GetSubPath ( e.location, path, att->value );
+               if ( root )
+               {
+                       if ( root->value == "intermediate" )
+                               subdirectory = IntermediateDirectory;
+                       else if ( root->value == "output" )
+                               subdirectory = OutputDirectory;
+                       else
+                       {
+                               throw InvalidAttributeValueException (
+                                       e.location,
+                                       "root",
+                                       root->value );
+                       }
+               }
+               subpath = GetSubPath ( this->project, e.location, relative_path, att->value );
        }
        else if ( e.name == "include" )
        {
-               Include* include = new Include ( project, this, &e );
-               if ( parseContext.ifData )
-                       parseContext.ifData->data.includes.push_back ( include );
-               else
-                       non_if_data.includes.push_back ( include );
+               Include* include = new Include ( project, &e, this );
+               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" )
+       {
+               metadata = new Metadata ( e, *this );
+               subs_invalid = false;
+       }
        else if ( e.name == "invoke" )
        {
-               if ( parseContext.ifData )
-                       throw InvalidBuildFileException (
-                               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 InvalidBuildFileException (
-                               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 InvalidBuildFileException (
-                               e.location,
-                               "<importlibrary> is not a valid sub-element of <if>" );
                if ( importLibrary )
-                       throw InvalidBuildFileException (
+               {
+                       throw XMLInvalidBuildFileException (
                                e.location,
                                "Only one <importlibrary> is valid per module" );
-               importLibrary = new ImportLibrary ( 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" )
@@ -598,10 +787,24 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
        else if ( e.name == "linkerscript" )
        {
                if ( linkerScript )
-                       throw InvalidBuildFileException (
+               {
+                       throw XMLInvalidBuildFileException (
                                e.location,
                                "Only one <linkerscript> is valid per module" );
-               linkerScript = new LinkerScript ( project, this, e );
+               }
+               size_t pos = e.value.find_last_of ( "/\\" );
+               if ( pos == string::npos )
+               {
+                       linkerScript = new LinkerScript (
+                               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, new FileLocation ( SourceDirectory, relative_path + sSep + dir, name, &e ) );
+               }
                subs_invalid = true;
        }
        else if ( e.name == "component" )
@@ -611,7 +814,7 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
        }
        else if ( e.name == "property" )
        {
-               throw InvalidBuildFileException (
+               throw XMLInvalidBuildFileException (
                        e.location,
                        "<property> is not a valid sub-element of <module>" );
        }
@@ -622,16 +825,25 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
        }
        else if ( e.name == "pch" )
        {
-               if ( parseContext.ifData )
-                       throw InvalidBuildFileException (
-                               e.location,
-                               "<pch> is not a valid sub-element of <if>" );
                if ( pch )
-                       throw InvalidBuildFileException (
+               {
+                       throw XMLInvalidBuildFileException (
                                e.location,
                                "Only one <pch> is valid per module" );
-               pch = new PchFile (
-                       e, *this, File ( FixSeparator ( path + cSep + e.value ), false, "", true ) );
+               }
+               size_t pos = e.value.find_last_of ( "/\\" );
+               if ( pos == string::npos )
+               {
+                       pch = new PchFile (
+                               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, new FileLocation ( SourceDirectory, relative_path + sSep + dir, name, &e ) );
+               }
                subs_invalid = true;
        }
        else if ( e.name == "compilationunit" )
@@ -639,22 +851,32 @@ 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;
        }
+       else if ( e.name == "autoregister" )
+       {
+               if ( autoRegister != NULL)
+               {
+                       throw XMLInvalidBuildFileException (
+                               e.location,
+                               "there can be only one <%s> element for a module",
+                               e.name.c_str() );
+               }
+               autoRegister = new AutoRegister ( project, this, e );
+               subs_invalid = true;
+       }
        if ( subs_invalid && e.subElements.size() > 0 )
-               throw InvalidBuildFileException (
+       {
+               throw XMLInvalidBuildFileException (
                        e.location,
                        "<%s> cannot have sub-elements",
                        e.name.c_str() );
+       }
        for ( size_t i = 0; i < e.subElements.size (); i++ )
-               ProcessXMLSubElement ( *e.subElements[i], subpath, parseContext );
-       parseContext.ifData = pOldIf;
+               ProcessXMLSubElement ( *e.subElements[i], subdirectory, subpath, parseContext );
        parseContext.compilationUnit = pOldCompilationUnit;
 }
 
@@ -665,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" )
@@ -677,33 +901,105 @@ 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" )
+               return Win32OCX;
        if ( attribute.value == "win32cui" )
                return Win32CUI;
        if ( attribute.value == "win32gui" )
                return Win32GUI;
+       if ( attribute.value == "win32scr" )
+               return Win32SCR;
        if ( attribute.value == "bootloader" )
                return BootLoader;
        if ( attribute.value == "bootsector" )
                return BootSector;
+       if ( attribute.value == "bootprogram" )
+               return BootProgram;
        if ( attribute.value == "iso" )
                return Iso;
        if ( attribute.value == "liveiso" )
                return LiveIso;
+       if ( attribute.value == "isoregtest" )
+               return IsoRegTest;
+       if ( attribute.value == "liveisoregtest" )
+               return LiveIsoRegTest;
        if ( attribute.value == "test" )
                return Test;
        if ( attribute.value == "rpcserver" )
                return RpcServer;
        if ( attribute.value == "rpcclient" )
                return RpcClient;
+       if ( attribute.value == "rpcproxy" )
+               return RpcProxy;
        if ( attribute.value == "alias" )
                return Alias;
+       if ( attribute.value == "idlheader" )
+               return IdlHeader;
+       if ( attribute.value == "embeddedtypelib" )
+               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 );
 }
 
+DirectoryLocation
+Module::GetTargetDirectoryTree () const
+{
+       switch ( type )
+       {
+               case Kernel:
+               case KernelModeDLL:
+               case KeyboardLayout:
+               case NativeDLL:
+               case Win32DLL:
+               case Win32OCX:
+               case KernelModeDriver:
+               case NativeCUI:
+               case Win32CUI:
+               case Test:
+               case Win32SCR:
+               case Win32GUI:
+               case BuildTool:
+               case BootLoader:
+               case BootSector:
+               case BootProgram:
+               case Iso:
+               case LiveIso:
+               case IsoRegTest:
+               case LiveIsoRegTest:
+               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;
+       }
+       throw InvalidOperationException ( __FILE__,
+                                         __LINE__,
+                                         "Invalid module type %d.",
+                                         type );
+}
+
 string
 Module::GetDefaultModuleExtension () const
 {
@@ -711,7 +1007,9 @@ Module::GetDefaultModuleExtension () const
        {
                case BuildTool:
                        return ExePostfix;
+               case BootProgram:
                case StaticLibrary:
+               case HostStaticLibrary:
                        return ".a";
                case ObjectLibrary:
                        return ".o";
@@ -720,26 +1018,43 @@ Module::GetDefaultModuleExtension () const
                case Win32CUI:
                case Win32GUI:
                        return ".exe";
+               case Win32SCR:
+                       return ".scr";
+
                case KernelModeDLL:
                case NativeDLL:
+               case KeyboardLayout:
                case Win32DLL:
                        return ".dll";
+               case Win32OCX:
+                       return ".ocx";
                case KernelModeDriver:
                case BootLoader:
                        return ".sys";
+               case Cabinet:
+                       return ".cab";
                case BootSector:
                        return ".o";
                case Iso:
                case LiveIso:
+               case IsoRegTest:
+               case LiveIsoRegTest:
                        return ".iso";
                case Test:
                        return ".exe";
                case RpcServer:
-                       return ".o";
                case RpcClient:
+               case RpcProxy:
                        return ".o";
                case Alias:
+               case ElfExecutable:
+               case IdlHeader:
+               case MessageHeader:
                        return "";
+               case EmbeddedTypeLib:
+                       return ".tlb";
+               case TypeDontCare:
+                       break;
        }
        throw InvalidOperationException ( __FILE__,
                                          __LINE__ );
@@ -751,39 +1066,57 @@ Module::GetDefaultModuleEntrypoint () const
        switch ( type )
        {
                case Kernel:
-                       return "_NtProcessStartup";
+                       return "KiSystemStartup";
+               case KeyboardLayout:
                case KernelModeDLL:
-                       return "_DriverEntry@8";
+               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:
-                       return "_DllMain@12";
+               case Win32OCX:
+            if (Environment::GetArch() == "arm") return "DllMain";
+                       return "DllMain@12";
                case Win32CUI:
                case Test:
                        if ( isUnicode )
-                               return "_wmainCRTStartup";
+                               return "wmainCRTStartup";
                        else
-                               return "_mainCRTStartup";
+                               return "mainCRTStartup";
+               case Win32SCR:
                case Win32GUI:
                        if ( isUnicode )
-                               return "_wWinMainCRTStartup";
+                               return "wWinMainCRTStartup";
                        else
-                               return "_WinMainCRTStartup";
-               case KernelModeDriver:
-                       return "_DriverEntry@8";
+                               return "WinMainCRTStartup";
                case BuildTool:
                case StaticLibrary:
+               case HostStaticLibrary:
                case ObjectLibrary:
                case BootLoader:
                case BootSector:
                case Iso:
                case LiveIso:
+               case IsoRegTest:
+               case LiveIsoRegTest:
                case RpcServer:
                case RpcClient:
+               case RpcProxy:
                case Alias:
+               case BootProgram:
+               case IdlHeader:
+               case MessageHeader:
+               case ElfExecutable:
+               case EmbeddedTypeLib:
+               case Cabinet:
                        return "";
+               case TypeDontCare:
+                       break;
        }
        throw InvalidOperationException ( __FILE__,
                                          __LINE__ );
@@ -795,30 +1128,46 @@ Module::GetDefaultModuleBaseaddress () const
        switch ( type )
        {
                case Kernel:
-                       return "0x80000000";
+                       return "0x80800000";
                case Win32DLL:
+               case Win32OCX:
                        return "0x10000000";
                case NativeDLL:
                case NativeCUI:
                case Win32CUI:
                case Test:
                        return "0x00400000";
+               case Win32SCR:
                case Win32GUI:
                        return "0x00400000";
+               case KeyboardLayout:
                case KernelModeDLL:
                case KernelModeDriver:
                        return "0x00010000";
+               case ElfExecutable:
+                       return "0xe00000";
                case BuildTool:
                case StaticLibrary:
+               case HostStaticLibrary:
                case ObjectLibrary:
                case BootLoader:
                case BootSector:
                case Iso:
                case LiveIso:
+               case IsoRegTest:
+               case LiveIsoRegTest:
                case RpcServer:
                case RpcClient:
+               case RpcProxy:
                case Alias:
+               case BootProgram:
+               case IdlHeader:
+               case MessageHeader:
+               case EmbeddedTypeLib:
+               case Cabinet:
                        return "";
+               case TypeDontCare:
+                       break;
        }
        throw InvalidOperationException ( __FILE__,
                                          __LINE__ );
@@ -827,7 +1176,7 @@ Module::GetDefaultModuleBaseaddress () const
 bool
 Module::HasImportLibrary () const
 {
-       return importLibrary != NULL;
+       return importLibrary != NULL && type != StaticLibrary && type != HostStaticLibrary;
 }
 
 bool
@@ -838,102 +1187,90 @@ Module::IsDLL () const
                case Kernel:
                case KernelModeDLL:
                case NativeDLL:
+               case KeyboardLayout:
                case Win32DLL:
+               case Win32OCX:
                case KernelModeDriver:
                        return true;
                case NativeCUI:
                case Win32CUI:
                case Test:
+               case Win32SCR:
                case Win32GUI:
                case BuildTool:
                case StaticLibrary:
+               case HostStaticLibrary:
                case ObjectLibrary:
                case BootLoader:
                case BootSector:
+               case BootProgram:
                case Iso:
                case LiveIso:
+               case IsoRegTest:
+               case LiveIsoRegTest:
                case RpcServer:
                case RpcClient:
+               case RpcProxy:
                case Alias:
+               case IdlHeader:
+               case MessageHeader:
+               case EmbeddedTypeLib:
+               case ElfExecutable:
+               case Cabinet:
                        return false;
-       }
-       throw InvalidOperationException ( __FILE__,
-                                         __LINE__ );
-}
-
-bool
-Module::GenerateInOutputTree () const
-{
-       switch ( type )
-       {
-               case Kernel:
-               case KernelModeDLL:
-               case NativeDLL:
-               case Win32DLL:
-               case KernelModeDriver:
-               case NativeCUI:
-               case Win32CUI:
-               case Test:
-               case Win32GUI:
-               case BuildTool:
-               case BootLoader:
-               case BootSector:
-               case Iso:
-               case LiveIso:
-                       return true;
-               case StaticLibrary:
-               case ObjectLibrary:
-               case RpcServer:
-               case RpcClient:
-               case Alias:
-                       return false;
+               case TypeDontCare:
+                       break;
        }
        throw InvalidOperationException ( __FILE__,
                                          __LINE__ );
 }
 
 string
-Module::GetTargetName () const
+Module::GetPathWithPrefix ( const string& prefix ) const
 {
-       return name + extension;
+       return output->relative_path + cSep + prefix + output->name;
 }
 
 string
-Module::GetDependencyPath () const
+Module::GetPathToBaseDir () const
 {
-       if ( HasImportLibrary () )
-               return ReplaceExtension ( GetPathWithPrefix ( "lib" ), ".a" );
-       else
-               return GetPath();
+       string temp_path = output->relative_path;
+       string result = "..\\";
+       while(temp_path.find ('\\') != string::npos)
+       {
+               temp_path.erase (0, temp_path.find('\\')+1);
+               result += "..\\";
+       }
+       return result;
 }
 
 string
-Module::GetBasePath () const
+Module::GetInvocationTarget ( const int index ) const
 {
-       return path;
+       return ssprintf ( "%s_invoke_%d",
+                         name.c_str (),
+                         index );
 }
 
 string
-Module::GetPath () const
+Module::GetEntryPoint(bool leadingUnderscore) const
 {
-       if ( path.length() > 0 )
-               return path + cSep + GetTargetName ();
-       else
-               return GetTargetName ();
-}
+       string result = "";
+       if (entrypoint == "0" || entrypoint == "0x0")
+               return "0";
+       if (leadingUnderscore)
+               result = "_";
 
-string
-Module::GetPathWithPrefix ( const string& prefix ) const
-{
-       return path + cSep + prefix + GetTargetName ();
-}
+       result += entrypoint;
 
-string
-Module::GetInvocationTarget ( const int index ) const
-{
-       return ssprintf ( "%s_invoke_%d",
-                         name.c_str (),
-                         index );
+       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;
 }
 
 bool
@@ -948,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;
 }
 
@@ -962,7 +1294,7 @@ Module::InvokeModule () const
        for ( size_t i = 0; i < invocations.size (); i++ )
        {
                Invoke& invoke = *invocations[i];
-               string command = FixSeparatorForSystemCommand(invoke.invokeModule->GetPath ()) + " " + invoke.GetParameters ();
+               string command = FixSeparatorForSystemCommand(invoke.invokeModule->output->relative_path + "/" + invoke.invokeModule->output->name ) + " " + invoke.GetParameters ();
                printf ( "Executing '%s'\n\n", command.c_str () );
                int exitcode = system ( command.c_str () );
                if ( exitcode != 0 )
@@ -972,52 +1304,106 @@ Module::InvokeModule () const
 }
 
 
-File::File ( const string& _name, bool _first,
-             std::string _switches,
+void
+Module::SetImportLibrary ( ImportLibrary* importLibrary )
+{
+       this->importLibrary = importLibrary;
+       dependency = new FileLocation ( HasImportLibrary () ? IntermediateDirectory : output->directory,
+                                       output->relative_path,
+                                       HasImportLibrary () ? "lib" + name + ".a" : output->name );
+}
+
+
+File::File ( DirectoryLocation directory,
+             const string& relative_path,
+             const string& name,
+             bool _first,
+             const string& _switches,
              bool _isPreCompiledHeader )
-       : name(_name),
+       : file ( directory, relative_path, name ),
          first(_first),
          switches(_switches),
          isPreCompiledHeader(_isPreCompiledHeader)
 {
 }
 
+
 void
 File::ProcessXML()
 {
 }
 
 
+std::string File::GetFullPath () const
+{
+       string directory ( "" );
+       switch ( file.directory )
+       {
+               case SourceDirectory:
+                       break;
+               case IntermediateDirectory:
+                       directory = Environment::GetIntermediatePath () + sSep;
+                       break;
+               default:
+                       throw InvalidOperationException ( __FILE__,
+                                                         __LINE__,
+                                                         "Invalid directory %d.",
+                                                         file.directory );
+       }
+
+       if ( file.relative_path.length () > 0 )
+               directory += file.relative_path + sSep;
+
+
+       return directory + file.name;
+}
+
+
 Library::Library ( const XMLElement& _node,
                    const Module& _module,
                    const string& _name )
-       : node(_node),
+       : node(&_node),
          module(_module),
          name(_name),
          importedModule(_module.project.LocateModule(_name))
 {
        if ( module.name == name )
-               throw InvalidBuildFileException (
-                       node.location,
+       {
+               throw XMLInvalidBuildFileException (
+                       node->location,
                        "module '%s' cannot link against itself",
                        name.c_str() );
+       }
        if ( !importedModule )
-               throw InvalidBuildFileException (
-                       node.location,
+       {
+               throw XMLInvalidBuildFileException (
+                       node->location,
                        "module '%s' trying to import non-existant module '%s'",
                        module.name.c_str(),
                        name.c_str() );
+       }
+}
+
+Library::Library ( const Module& _module,
+                   const string& _name )
+       : node(NULL),
+         module(_module),
+         name(_name),
+         importedModule(_module.project.LocateModule(_name))
+{
 }
 
 void
 Library::ProcessXML()
 {
-       if ( !module.project.LocateModule ( name ) )
-               throw InvalidBuildFileException (
-                       node.location,
+       if ( node && !module.project.LocateModule ( name ) )
+       {
+               throw XMLInvalidBuildFileException (
+                       node->location,
                        "module '%s' is trying to link against non-existant module '%s'",
                        module.name.c_str(),
                        name.c_str() );
+       }
 }
 
 
@@ -1038,11 +1424,13 @@ Invoke::ProcessXML()
        {
                invokeModule = module.project.LocateModule ( att->value );
                if ( invokeModule == NULL )
-                       throw InvalidBuildFileException (
+               {
+                       throw XMLInvalidBuildFileException (
                                node.location,
                                "module '%s' is trying to invoke non-existant module '%s'",
                                module.name.c_str(),
                                att->value.c_str() );
+               }
        }
 
        for ( size_t i = 0; i < node.subElements.size (); i++ )
@@ -1064,9 +1452,12 @@ Invoke::ProcessXMLSubElement ( const XMLElement& e )
                        ProcessXMLSubElementOutput ( *e.subElements[i] );
        }
        if ( subs_invalid && e.subElements.size() > 0 )
-               throw InvalidBuildFileException ( e.location,
-                                                 "<%s> cannot have sub-elements",
-                                                 e.name.c_str() );
+       {
+               throw XMLInvalidBuildFileException (
+                       e.location,
+                       "<%s> cannot have sub-elements",
+                       e.name.c_str() );
+       }
 }
 
 void
@@ -1075,13 +1466,17 @@ Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
        bool subs_invalid = false;
        if ( e.name == "inputfile" && e.value.size () > 0 )
        {
-               input.push_back ( new InvokeFile ( e, FixSeparator ( module.path + cSep + e.value ) ) );
+               input.push_back ( new InvokeFile (
+                       e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
                subs_invalid = true;
        }
        if ( subs_invalid && e.subElements.size() > 0 )
-               throw InvalidBuildFileException ( e.location,
-                                                 "<%s> cannot have sub-elements",
-                                                 e.name.c_str() );
+       {
+               throw XMLInvalidBuildFileException (
+                       e.location,
+                       "<%s> cannot have sub-elements",
+                       e.name.c_str() );
+       }
 }
 
 void
@@ -1090,14 +1485,17 @@ Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
        bool subs_invalid = false;
        if ( e.name == "outputfile" && e.value.size () > 0 )
        {
-               output.push_back ( new InvokeFile ( e, FixSeparator ( module.path + cSep + e.value ) ) );
+               output.push_back ( new InvokeFile (
+                       e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
                subs_invalid = true;
        }
        if ( subs_invalid && e.subElements.size() > 0 )
-               throw InvalidBuildFileException (
+       {
+               throw XMLInvalidBuildFileException (
                        e.location,
                        "<%s> cannot have sub-elements",
                        e.name.c_str() );
+       }
 }
 
 void
@@ -1175,71 +1573,247 @@ Dependency::ProcessXML()
 {
        dependencyModule = module.project.LocateModule ( node.value );
        if ( dependencyModule == NULL )
-               throw InvalidBuildFileException ( node.location,
-                                                 "module '%s' depend on non-existant module '%s'",
-                                                 module.name.c_str(),
-                                                 node.value.c_str() );
+       {
+               throw XMLInvalidBuildFileException (
+                       node.location,
+                       "module '%s' depend on non-existant module '%s'",
+                       module.name.c_str(),
+                       node.value.c_str() );
+       }
+}
+
+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;
+       }
 
-ImportLibrary::ImportLibrary ( const XMLElement& _node,
-                               const Module& _module )
+       return false;
+}
+
+Metadata::Metadata ( const XMLElement& _node,
+                     const Module& _module )
        : node (_node),
          module (_module)
 {
-       const XMLAttribute* att = _node.GetAttribute ( "basename", false );
+       /* The module name */
+       const XMLAttribute* att = _node.GetAttribute ( "name", false );
        if (att != NULL)
-               basename = att->value;
+               name = att->value;
        else
-               basename = module.name;
+               name = module.name;
 
-       att = _node.GetAttribute ( "definition", true );
-       assert (att);
-       definition = FixSeparator(att->value);
-}
+       /* The module description */
+       att = _node.GetAttribute ( "description", false );
+       if (att != NULL)
+               description = att->value;
+       else
+               description = "";
 
+       /* The module version */
+       att = _node.GetAttribute ( "version", false );
+       if (att != NULL)
+               version = att->value;
+       else
+               version = "";
 
-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;
+       /* The module copyright */
+       att = _node.GetAttribute ( "copyright", false );
+       if (att != NULL)
+               copyright = att->value;
+       else
+               copyright = "";
 
-       att = node.GetAttribute ( "property", true );
-       assert(att);
-       property = att->value;
+       att = _node.GetAttribute ( "url", false );
+       if (att != NULL)
+               url = att->value;
+       else
+               url = "";
 
-       att = node.GetAttribute ( "value", true );
-       assert(att);
-       value = att->value;
+       /* When was this module updated */
+       att = _node.GetAttribute ( "date", false );
+       if (att != NULL)
+               date = att->value;
+       else
+               date = "?";
+
+       /* When was this module updated */
+       att = _node.GetAttribute ( "owner", false );
+       if (att != NULL)
+               owner = att->value;
+       else
+               owner = "ReactOS";
 }
 
-If::~If ()
+
+ImportLibrary::~ImportLibrary ()
 {
+       delete source;
 }
 
-void
-If::ProcessXML()
+
+ImportLibrary::ImportLibrary ( const Project& project,
+                               const XMLElement& node,
+                               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 || module->type == HostStaticLibrary )
+               throw XMLInvalidBuildFileException (
+                   node.location,
+                   "<importlibrary> dllname attribute required." );
+
+       size_t index = definition->value.find_last_of ( "/\\" );
+       if ( index == string::npos )
+       {
+               source = new FileLocation ( directory,
+                                           base->output->relative_path,
+                                           definition->value,
+                                           &node );
+       }
+       else
+       {
+               string dir = definition->value.substr ( 0, index );
+               string name = definition->value.substr ( index + 1);
+               source = new FileLocation ( directory,
+                                           NormalizeFilename ( base->output->relative_path + sSep + dir ),
+                                           name,
+                                           &node );
+       }
 }
 
 
 Property::Property ( const XMLElement& node_,
                      const Project& project_,
                      const Module* module_ )
-       : node(node_), project(project_), module(module_)
+       : project(project_), module(module_)
 {
        const XMLAttribute* att;
 
-       att = node.GetAttribute ( "name", true );
+       att = node_.GetAttribute ( "name", true );
        assert(att);
-       name = att->value;
+       name = project.ResolveProperties ( att->value );
 
-       att = node.GetAttribute ( "value", true );
+       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_,
+                     const Module* module_,
+                     const std::string& name_,
+                     const std::string& value_ )
+       : project(project_), module(module_), name(name_), value(value_)
+{
 }
 
 void
@@ -1251,11 +1825,16 @@ Property::ProcessXML()
 PchFile::PchFile (
        const XMLElement& node_,
        const Module& module_,
-       const File file_ )
+       const FileLocation *file_ )
        : node(node_), module(module_), file(file_)
 {
 }
 
+PchFile::~PchFile()
+{
+       delete file;
+}
+
 void
 PchFile::ProcessXML()
 {