Sync to trunk head (r42241)
[reactos.git] / reactos / tools / rbuild / backend / mingw / mingw.cpp
index eff8f3e..afef39a 100644 (file)
@@ -34,13 +34,52 @@ using std::map;
 
 typedef set<string> set_string;
 
+const struct ModuleHandlerInformations ModuleHandlerInformations[] = {
+       { HostTrue, "", "", "" }, // BuildTool
+       { HostFalse, "", "", "" }, // StaticLibrary
+       { HostFalse, "", "", "" }, // ObjectLibrary
+       { HostFalse, "", "", "" }, // Kernel
+       { HostFalse, "", "", "" }, // KernelModeDLL
+       { HostFalse, "-D__NTDRIVER__", "", "" }, // KernelModeDriver
+       { HostFalse, "", "", "" }, // NativeDLL
+       { HostFalse, "-D__NTAPP__", "", "" }, // NativeCUI
+       { HostFalse, "", "", "" }, // Win32DLL
+       { HostFalse, "", "", "" }, // Win32OCX
+       { HostFalse, "", "", "" }, // Win32CUI
+       { HostFalse, "", "", "" }, // Win32GUI
+       { HostFalse, "", "", "-nostartfiles -nostdlib" }, // BootLoader
+       { HostFalse, "", "-f bin", "" }, // BootSector
+       { HostFalse, "", "", "" }, // Iso
+       { HostFalse, "", "", "" }, // LiveIso
+       { HostFalse, "", "", "" }, // Test
+       { HostFalse, "", "", "" }, // RpcServer
+       { HostFalse, "", "", "" }, // RpcClient
+       { HostFalse, "", "", "" }, // Alias
+       { HostFalse, "", "", "-nostartfiles -nostdlib" }, // BootProgram
+       { HostFalse, "", "", "" }, // Win32SCR
+       { HostFalse, "", "", "" }, // IdlHeader
+       { HostFalse, "", "", "" }, // IdlInterface
+       { HostFalse, "", "", "" }, // IsoRegTest
+       { HostFalse, "", "", "" }, // LiveIsoRegTest
+       { HostFalse, "", "", "" }, // EmbeddedTypeLib
+       { HostFalse, "", "", "" }, // ElfExecutable
+       { HostFalse, "", "", "" }, // RpcProxy
+       { HostTrue, "", "", "" }, // HostStaticLibrary
+       { HostFalse, "", "", "" }, // Cabinet
+       { HostFalse, "", "", "" }, // KeyboardLayout
+       { HostFalse, "", "", "" }, // MessageHeader
+};
+
+static std::string mscPath;
+static std::string mslinkPath;
+
 string
-strDirectory ( const FileLocation *file )
+MingwBackend::GetFullPath ( const FileLocation& file ) const
 {
-       MingwModuleHandler::PassThruCacheDirectory ( file );
+       MingwModuleHandler::PassThruCacheDirectory ( &file );
 
        string directory;
-       switch ( file->directory )
+       switch ( file.directory )
        {
                case SourceDirectory:
                        directory = "";
@@ -60,23 +99,24 @@ strDirectory ( const FileLocation *file )
                default:
                        throw InvalidOperationException ( __FILE__,
                                                          __LINE__,
-                                                         "Invalid directory." );
+                                                         "Invalid directory %d.",
+                                                         file.directory );
        }
 
-       if ( file->relative_path.length () > 0 )
+       if ( file.relative_path.length () > 0 )
        {
                if ( directory.length () > 0 )
                        directory += sSep;
-               directory += file->relative_path;
+               directory += file.relative_path;
        }
        return directory;
 }
 
 string
-strFile ( const FileLocation *file )
+MingwBackend::GetFullName ( const FileLocation& file ) const
 {
        string directory;
-       switch ( file->directory )
+       switch ( file.directory )
        {
                case SourceDirectory:
                        directory = "";
@@ -96,25 +136,25 @@ strFile ( const FileLocation *file )
                default:
                        throw InvalidOperationException ( __FILE__,
                                                          __LINE__,
-                                                         "Invalid directory." );
+                                                         "Invalid directory %d.",
+                                                         file.directory );
        }
 
-       if ( file->relative_path.length () > 0 )
+       if ( file.relative_path.length () > 0 )
        {
                if ( directory.length () > 0 )
                        directory += sSep;
-               directory += file->relative_path;
+               directory += file.relative_path;
        }
 
        if ( directory.length () > 0 )
                directory += sSep;
 
-       return directory + file->name;
+       return directory + file.name;
 }
 
-
 string
-v2s ( const vector<FileLocation>& files, int wrap_at )
+v2s ( const Backend* backend, const vector<FileLocation>& files, int wrap_at )
 {
        if ( !files.size() )
                return "";
@@ -127,7 +167,7 @@ v2s ( const vector<FileLocation>& files, int wrap_at )
                        s += " \\\n\t\t";
                else if ( s.size() )
                        s += " ";
-               s += strFile ( &file );
+               s += backend->GetFullName ( file );
        }
        return s;
 }
@@ -171,9 +211,9 @@ MingwBackend::MingwBackend ( Project& project,
                              Configuration& configuration )
        : Backend ( project, configuration ),
          manualBinutilsSetting( false ),
-         intermediateDirectory ( new Directory ("$(INTERMEDIATE)" ) ),
-         outputDirectory ( new Directory ( "$(OUTPUT)" ) ),
-         installDirectory ( new Directory ( "$(INSTALL)" ) )
+         intermediateDirectory ( new Directory ( "" ) ),
+         outputDirectory ( new Directory ( "" ) ),
+         installDirectory ( new Directory ( "" ) )
 {
        compilerPrefix = "";
 }
@@ -205,28 +245,9 @@ MingwBackend::CanEnablePreCompiledHeaderSupportForModule ( const Module& module
        for ( i = 0; i < compilationUnits.size (); i++ )
        {
                CompilationUnit& compilationUnit = *compilationUnits[i];
-               if ( compilationUnit.files.size () != 1 )
+               if ( compilationUnit.GetFiles ().size () != 1 )
                        return false;
        }
-       // intentionally make a copy so that we can append more work in
-       // the middle of processing without having to go recursive
-       vector<If*> v = module.non_if_data.ifs;
-       for ( i = 0; i < v.size (); i++ )
-       {
-               size_t j;
-               If& rIf = *v[i];
-               // check for sub-ifs to add to list
-               const vector<If*>& ifs = rIf.data.ifs;
-               for ( j = 0; j < ifs.size (); j++ )
-                       v.push_back ( ifs[j] );
-               const vector<CompilationUnit*>& compilationUnits = rIf.data.compilationUnits;
-               for ( j = 0; j < compilationUnits.size (); j++ )
-               {
-                       CompilationUnit& compilationUnit = *compilationUnits[j];
-                       if ( compilationUnit.files.size () != 1 )
-                               return false;
-               }
-       }
        return true;
 }
 
@@ -238,9 +259,12 @@ MingwBackend::ProcessModules ()
        vector<MingwModuleHandler*> v;
        size_t i;
 
-       for ( i = 0; i < ProjectNode.modules.size (); i++ )
+       for ( std::map<std::string, Module*>::iterator p = ProjectNode.modules.begin (); p != ProjectNode.modules.end (); ++ p )
+               fprintf ( fMakefile, "%s_TYPE:=%u\n", p->second->name.c_str(), p->second->type );
+
+       for ( std::map<std::string, Module*>::iterator p = ProjectNode.modules.begin (); p != ProjectNode.modules.end (); ++ p )
        {
-               Module& module = *ProjectNode.modules[i];
+               Module& module = *p->second;
                if ( !module.enabled )
                        continue;
                MingwModuleHandler* h = MingwModuleHandler::InstanciateHandler (
@@ -249,16 +273,13 @@ MingwBackend::ProcessModules ()
                h->AddImplicitLibraries ( module );
                if ( use_pch && CanEnablePreCompiledHeaderSupportForModule ( module ) )
                        h->EnablePreCompiledHeaderSupport ();
-               if ( module.host == HostDefault )
-               {
-                       module.host = h->DefaultHost();
-                       assert ( module.host != HostDefault );
-               }
                v.push_back ( h );
        }
 
        size_t iend = v.size ();
 
+       for ( i = 0; i < iend; i++ )
+               v[i]->GenerateSourceMacro();
        for ( i = 0; i < iend; i++ )
                v[i]->GenerateObjectMacro();
        fprintf ( fMakefile, "\n" );
@@ -267,7 +288,6 @@ MingwBackend::ProcessModules ()
        fprintf ( fMakefile, "\n" );
 
        GenerateAllTarget ( v );
-       GenerateInitTarget ();
        GenerateRegTestsRunTarget ();
 
        for ( i = 0; i < iend; i++ )
@@ -300,7 +320,7 @@ MingwBackend::Process ()
 void
 MingwBackend::CheckAutomaticDependenciesForModuleOnly ()
 {
-       if ( configuration.AutomaticDependencies )
+       if ( configuration.Dependencies == AutomaticDependencies )
        {
                Module* module = ProjectNode.LocateModule ( configuration.CheckDependenciesForModuleOnlyModule );
                if ( module == NULL )
@@ -309,7 +329,7 @@ MingwBackend::CheckAutomaticDependenciesForModuleOnly ()
                                configuration.CheckDependenciesForModuleOnlyModule.c_str () );
                        return;
                }
-               
+
                printf ( "Checking automatic dependencies for module '%s'...",
                         module->name.c_str () );
                AutomaticDependency automaticDependency ( ProjectNode );
@@ -322,6 +342,8 @@ MingwBackend::CheckAutomaticDependenciesForModuleOnly ()
 void
 MingwBackend::ProcessNormal ()
 {
+       assert(sizeof(ModuleHandlerInformations)/sizeof(ModuleHandlerInformations[0]) == TypeDontCare);
+
        DetectCompiler ();
        DetectBinutils ();
        DetectNetwideAssembler ();
@@ -331,7 +353,6 @@ MingwBackend::ProcessNormal ()
        GenerateHeader ();
        GenerateGlobalVariables ();
        GenerateXmlBuildFilesMacro ();
-       UnpackWineResources ();
        ProcessModules ();
        GenerateInstallTarget ();
        GenerateTestTarget ();
@@ -369,125 +390,20 @@ MingwBackend::GenerateHeader () const
                ProjectNode.GetProjectFilename ().c_str () );
 }
 
-string
-MingwBackend::GenerateIncludesAndDefines ( IfableData& data ) const
-{
-       string includeParameters = MingwModuleHandler::GenerateGccIncludeParametersFromVector ( data.includes );
-       string defineParameters = MingwModuleHandler::GenerateGccDefineParametersFromVector ( data.defines );
-       return includeParameters + " " + defineParameters;
-}
-
-void
-MingwBackend::GenerateProjectCFlagsMacro ( const char* assignmentOperation,
-                                           IfableData& data ) const
-{
-       fprintf (
-               fMakefile,
-               "PROJECT_CFLAGS %s",
-               assignmentOperation );
-       
-       fprintf ( fMakefile,
-                 " %s",
-                 GenerateIncludesAndDefines ( data ).c_str() );
-
-       fprintf ( fMakefile, "\n" );
-}
-
 void
-MingwBackend::GenerateGlobalCFlagsAndProperties (
+MingwBackend::GenerateGlobalProperties (
        const char* assignmentOperation,
-       IfableData& data ) const
+       const IfableData& data ) const
 {
-       size_t i;
-
-       for ( i = 0; i < data.properties.size(); i++ )
-       {
-               Property& prop = *data.properties[i];
-               fprintf ( fMakefile, "%s := %s\n",
-                       prop.name.c_str(),
-                       prop.value.c_str() );
-       }
-
-       if ( data.includes.size() || data.defines.size() )
+       for ( std::map<std::string, Property*>::const_iterator p = data.properties.begin(); p != data.properties.end(); ++ p )
        {
-               GenerateProjectCFlagsMacro ( assignmentOperation,
-                                            data );
-       }
+               Property& prop = *p->second;
 
-       for ( i = 0; i < data.ifs.size(); i++ )
-       {
-               If& rIf = *data.ifs[i];
-               if ( rIf.data.defines.size()
-                       || rIf.data.includes.size()
-                       || rIf.data.ifs.size() )
+               if (!prop.isInternal)
                {
-                       fprintf (
-                               fMakefile,
-                               "ifeq (\"$(%s)\",\"%s\")\n",
-                               rIf.property.c_str(),
-                               rIf.value.c_str() );
-                       GenerateGlobalCFlagsAndProperties (
-                               "+=",
-                               rIf.data );
-                       fprintf (
-                               fMakefile,
-                               "endif\n\n" );
-               }
-       }
-}
-
-void
-MingwBackend::GenerateProjectGccOptionsMacro ( const char* assignmentOperation,
-                                               IfableData& data ) const
-{
-       size_t i;
-
-       fprintf (
-               fMakefile,
-               "PROJECT_GCCOPTIONS %s",
-               assignmentOperation );
-       
-       for ( i = 0; i < data.compilerFlags.size(); i++ )
-       {
-               fprintf (
-                       fMakefile,
-                       " %s",
-                       data.compilerFlags[i]->flag.c_str() );
-       }
-
-       fprintf ( fMakefile, "\n" );
-}
-
-void
-MingwBackend::GenerateProjectGccOptions (
-       const char* assignmentOperation,
-       IfableData& data ) const
-{
-       size_t i;
-
-       if ( data.compilerFlags.size() )
-       {
-               GenerateProjectGccOptionsMacro ( assignmentOperation,
-                                                data );
-       }
-
-       for ( i = 0; i < data.ifs.size(); i++ )
-       {
-               If& rIf = *data.ifs[i];
-               if ( rIf.data.compilerFlags.size()
-                    || rIf.data.ifs.size() )
-               {
-                       fprintf (
-                               fMakefile,
-                               "ifeq (\"$(%s)\",\"%s\")\n",
-                               rIf.property.c_str(),
-                               rIf.value.c_str() );
-                       GenerateProjectGccOptions (
-                               "+=",
-                               rIf.data );
-                       fprintf (
-                               fMakefile,
-                               "endif\n\n" );
+                       fprintf ( fMakefile, "%s := %s\n",
+                               prop.name.c_str(),
+                               prop.value.c_str() );
                }
        }
 }
@@ -509,25 +425,105 @@ MingwBackend::GenerateProjectLFLAGS () const
 void
 MingwBackend::GenerateGlobalVariables () const
 {
+       fputs ( "include tools$(SEP)rbuild$(SEP)backend$(SEP)mingw$(SEP)rules.mak\n", fMakefile );
+       fprintf ( fMakefile, "include tools$(SEP)rbuild$(SEP)backend$(SEP)mingw$(SEP)linkers$(SEP)%s.mak\n", ProjectNode.GetLinkerSet ().c_str () );
+       fprintf ( fMakefile, "include tools$(SEP)rbuild$(SEP)backend$(SEP)mingw$(SEP)compilers$(SEP)%s.mak\n", ProjectNode.GetCompilerSet ().c_str () );
+
+       if ( mscPath.length() )
+               fprintf ( fMakefile, "export RBUILD_CL_PATH=%s\n", mscPath.c_str () );
+
+       if ( mslinkPath.length() )
+               fprintf ( fMakefile, "export RBUILD_LINK_PATH=%s\n", mslinkPath.c_str () );
+
+       if ( configuration.Dependencies == FullDependencies )
+       {
+               fprintf ( fMakefile,
+                                 "ifeq ($(ROS_BUILDDEPS),)\n"
+                                 "ROS_BUILDDEPS:=%s\n"
+                                 "endif\n",
+                                 "full" );
+       }
+
        fprintf ( fMakefile,
                  "PREFIX := %s\n",
                  compilerPrefix.c_str () );
        fprintf ( fMakefile,
-                 "nasm := %s\n",
+                 "nasm := $(Q)%s\n",
                  nasmCommand.c_str () );
 
-       GenerateGlobalCFlagsAndProperties ( "=", ProjectNode.non_if_data );
-       GenerateProjectGccOptions ( "=", ProjectNode.non_if_data );
-
-       fprintf ( fMakefile, "PROJECT_RCFLAGS := $(PROJECT_CFLAGS)\n" );
-       fprintf ( fMakefile, "PROJECT_WIDLFLAGS := $(PROJECT_CFLAGS)\n" );
-       fprintf ( fMakefile, "PROJECT_LFLAGS := %s\n",
-                 GenerateProjectLFLAGS ().c_str () );
-       fprintf ( fMakefile, "PROJECT_CFLAGS += -Wall\n" );
-       fprintf ( fMakefile, "ifneq ($(OARCH),)\n" );
-       fprintf ( fMakefile, "PROJECT_CFLAGS += -march=$(OARCH)\n" );
-       fprintf ( fMakefile, "endif\n" );
-       fprintf ( fMakefile, "PROJECT_CFLAGS += $(PROJECT_GCCOPTIONS)\n" );
+       GenerateGlobalProperties ( "=", ProjectNode.non_if_data );
+
+       if ( ProjectNode.configuration.Compiler == GnuGcc )
+       {
+               fprintf ( fMakefile, "ifneq ($(OARCH),)\n" );
+               fprintf ( fMakefile, "PROJECT_ASFLAGS += -march=$(OARCH)\n" );
+               fprintf ( fMakefile, "PROJECT_CFLAGS += -march=$(OARCH)\n" );
+               fprintf ( fMakefile, "PROJECT_CXXFLAGS += -march=$(OARCH)\n" );
+               fprintf ( fMakefile, "endif\n" );
+               fprintf ( fMakefile, "ifneq ($(TUNE),)\n" );
+               fprintf ( fMakefile, "PROJECT_CFLAGS += -mtune=$(TUNE)\n" );
+               fprintf ( fMakefile, "PROJECT_CXXFLAGS += -mtune=$(TUNE)\n" );
+               fprintf ( fMakefile, "endif\n" );
+
+               if ( usePipe )
+               {
+                       fprintf ( fMakefile, "PROJECT_CFLAGS += -pipe\n" );
+                       fprintf ( fMakefile, "PROJECT_CXXFLAGS += -pipe\n" );
+                       fprintf ( fMakefile, "PROJECT_ASFLAGS += -pipe\n" );
+               }
+
+               // Would be nice to have our own C++ runtime
+               fputs ( "BUILTIN_CXXINCLUDES+= $(TARGET_CPPFLAGS)\n", fMakefile );
+       }
+
+       // Because RosBE gcc is built to suck
+       fputs ( "BUILTIN_HOST_CINCLUDES+= $(HOST_CFLAGS)\n", fMakefile );
+       fputs ( "BUILTIN_HOST_CPPINCLUDES+= $(HOST_CFLAGS)\n", fMakefile );
+       fputs ( "BUILTIN_HOST_CXXINCLUDES+= $(HOST_CPPFLAGS)\n", fMakefile );
+
+       MingwModuleHandler::GenerateParameters ( "PROJECT", "+=", ProjectNode.non_if_data );
+       MingwModuleHandler::GenerateParameters ( "PROJECT_HOST", "+=", ProjectNode.host_non_if_data );
+
+       // TODO: linker flags
+       fprintf ( fMakefile, "PROJECT_LFLAGS := '$(shell ${TARGET_CC} -print-libgcc-file-name)' %s\n", GenerateProjectLFLAGS ().c_str () );
+       fprintf ( fMakefile, "PROJECT_LPPFLAGS := '$(shell ${TARGET_CPP} -print-file-name=libstdc++.a)' '$(shell ${TARGET_CPP} -print-file-name=libgcc.a)' '$(shell ${TARGET_CPP} -print-file-name=libmingw32.a)' '$(shell ${TARGET_CPP} -print-file-name=libmingwex.a)'\n" );
+       /* hack to get libgcc_eh.a, should check mingw version or something */
+       if (Environment::GetArch() == "amd64")
+       {
+           fprintf ( fMakefile, "PROJECT_LPPFLAGS += '$(shell ${TARGET_CPP} -print-file-name=libgcc_eh.a)'\n" );
+       }
+
+       // TODO: use symbolic names for module types
+       for ( size_t i = 0; i < sizeof(ModuleHandlerInformations) / sizeof(ModuleHandlerInformations[0]); ++ i )
+       {
+               if ( ModuleHandlerInformations[i].cflags && ModuleHandlerInformations[i].cflags[0] )
+               {
+                               fprintf ( fMakefile,
+                                                 "MODULETYPE%d_%sFLAGS:=%s\n",
+                                                 (int)i,
+                                                 "C",
+                                                 ModuleHandlerInformations[i].cflags );
+               }
+
+               if ( ModuleHandlerInformations[i].cflags && ModuleHandlerInformations[i].cflags[0] )
+               {
+                               fprintf ( fMakefile,
+                                                 "MODULETYPE%d_%sFLAGS:=%s\n",
+                                                 (int)i,
+                                                 "CXX",
+                                                 ModuleHandlerInformations[i].cflags );
+               }
+
+               if ( ModuleHandlerInformations[i].nasmflags && ModuleHandlerInformations[i].nasmflags[0] )
+               {
+                               fprintf ( fMakefile,
+                                                 "MODULETYPE%d_%sFLAGS:=%s\n",
+                                                 (int)i,
+                                                 "NASM",
+                                                 ModuleHandlerInformations[i].nasmflags );
+               }
+       }
+
        fprintf ( fMakefile, "\n" );
 }
 
@@ -574,34 +570,6 @@ MingwBackend::GenerateAllTarget ( const vector<MingwModuleHandler*>& handlers )
        fprintf ( fMakefile, "\n\t\n\n" );
 }
 
-string
-MingwBackend::GetBuildToolDependencies () const
-{
-       string dependencies;
-       for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
-       {
-               Module& module = *ProjectNode.modules[i];
-               if ( !module.enabled )
-                       continue;
-               if ( module.type == BuildTool )
-               {
-                       if ( dependencies.length () > 0 )
-                               dependencies += " ";
-                       dependencies += module.GetDependencyPath ();
-               }
-       }
-       return dependencies;
-}
-
-void
-MingwBackend::GenerateInitTarget () const
-{
-       fprintf ( fMakefile,
-                 "INIT = %s\n",
-                 GetBuildToolDependencies ().c_str () );
-       fprintf ( fMakefile, "\n" );
-}
-
 void
 MingwBackend::GenerateRegTestsRunTarget () const
 {
@@ -654,7 +622,7 @@ MingwBackend::GenerateXmlBuildFilesMacro() const
                }
 
                fclose ( f );
-               
+
                xmlbuildFilenames += NormalizeFilename ( xmlbuildfile.topIncludeFilename );
                if ( numberOfExistingFiles % 5 == 4 || i == ProjectNode.xmlbuildfiles.size () - 1 )
                {
@@ -677,22 +645,6 @@ MingwBackend::GenerateXmlBuildFilesMacro() const
        fprintf ( fMakefile, "\n" );
 }
 
-string
-MingwBackend::GetBin2ResExecutable ()
-{
-       return NormalizeFilename ( Environment::GetOutputPath () + sSep + "tools/bin2res/bin2res" + ExePostfix );
-}
-
-void
-MingwBackend::UnpackWineResources ()
-{
-       printf ( "Unpacking WINE resources..." );
-       WineResource wineResource ( ProjectNode,
-                                   GetBin2ResExecutable () );
-       wineResource.UnpackResources ( configuration.Verbose );
-       printf ( "done\n" );
-}
-
 void
 MingwBackend::GenerateTestSupportCode ()
 {
@@ -745,7 +697,7 @@ MingwBackend::GenerateProxyMakefiles ()
 void
 MingwBackend::CheckAutomaticDependencies ()
 {
-       if ( configuration.AutomaticDependencies )
+       if ( configuration.Dependencies == AutomaticDependencies )
        {
                printf ( "Checking automatic dependencies..." );
                AutomaticDependency automaticDependency ( ProjectNode );
@@ -754,23 +706,14 @@ MingwBackend::CheckAutomaticDependencies ()
        }
 }
 
-bool
-MingwBackend::IncludeDirectoryTarget ( const string& directory ) const
-{
-       if ( directory == "$(INTERMEDIATE)" + sSep + "tools")
-               return false;
-       else
-               return true;
-}
-
 void
 MingwBackend::GenerateDirectories ()
 {
        printf ( "Creating directories..." );
-       intermediateDirectory->GenerateTree ( "", configuration.Verbose );
-       outputDirectory->GenerateTree ( "", configuration.Verbose );
+       intermediateDirectory->GenerateTree ( IntermediateDirectory, configuration.Verbose );
+       outputDirectory->GenerateTree ( OutputDirectory, configuration.Verbose );
        if ( !configuration.MakeHandlesInstallDirectories )
-               installDirectory->GenerateTree ( "", configuration.Verbose );
+               installDirectory->GenerateTree ( InstallDirectory, configuration.Verbose );
        printf ( "done\n" );
 }
 
@@ -792,32 +735,48 @@ MingwBackend::DetectCompiler ()
        printf ( "Detecting compiler..." );
 
        bool detectedCompiler = false;
-       const string& ROS_PREFIXValue = Environment::GetVariable ( "ROS_PREFIX" );
-       if ( ROS_PREFIXValue.length () > 0 )
+       bool supportedCompiler = false;
+       string compilerVersion;
+
+       if ( ProjectNode.configuration.Compiler == GnuGcc )
        {
-               compilerPrefix = ROS_PREFIXValue;
-               compilerCommand = compilerPrefix + "-gcc";
-               detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
-       }
+               const string& ROS_PREFIXValue = Environment::GetVariable ( "ROS_PREFIX" );
+               if ( ROS_PREFIXValue.length () > 0 )
+               {
+                       compilerPrefix = ROS_PREFIXValue;
+                       compilerCommand = compilerPrefix + "-gcc";
+                       detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
+               }
 #if defined(WIN32)
-       if ( !detectedCompiler )
-       {
-               compilerPrefix = "";
-               compilerCommand = "gcc";
-               detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
-       }
+               if ( !detectedCompiler )
+               {
+                       compilerPrefix = "";
+                       compilerCommand = "gcc";
+                       detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
+               }
 #endif
-       if ( !detectedCompiler )
+               if ( !detectedCompiler )
+               {
+                       compilerPrefix = "mingw32";
+                       compilerCommand = compilerPrefix + "-gcc";
+                       detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
+               }
+
+               if ( detectedCompiler )
+                       compilerVersion = GetCompilerVersion ( compilerCommand );
+
+               supportedCompiler = IsSupportedCompilerVersion ( compilerVersion );
+       }
+       else if ( ProjectNode.configuration.Compiler == MicrosoftC )
        {
-               compilerPrefix = "mingw32";
-               compilerCommand = compilerPrefix + "-gcc";
-               detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
+               compilerCommand = "cl";
+               detectedCompiler = DetectMicrosoftCompiler ( compilerVersion, mscPath );
+               supportedCompiler = true; // TODO
        }
 
        if ( detectedCompiler )
        {
-               string compilerVersion = GetCompilerVersion ( compilerCommand );
-               if ( IsSupportedCompilerVersion ( compilerVersion ) )
+               if ( supportedCompiler )
                        printf ( "detected (%s %s)\n", compilerCommand.c_str (), compilerVersion.c_str() );
                else
                {
@@ -849,21 +808,22 @@ MingwBackend::GetVersionString ( const string& versionCommand )
 {
        FILE *fp;
        int ch, i;
+       size_t newline;
        char buffer[81];
 
        fp = popen ( versionCommand.c_str () , "r" );
-       for( i = 0; 
-             ( i < 80 ) && 
-                 ( feof ( fp ) == 0 && 
-                   ( ( ch = fgetc( fp ) ) != -1 ) ); 
-             i++ )
+       for( i = 0;
+            ( i < 80 ) &&
+              ( feof ( fp ) == 0 &&
+                ( ( ch = fgetc( fp ) ) != -1 ) );
+            i++ )
        {
                buffer[i] = (char) ch;
        }
        buffer[i] = '\0';
        pclose ( fp );
 
-       char separators[] = " ";
+       char separators[] = " ()";
        char *token;
        char *prevtoken = NULL;
 
@@ -874,6 +834,8 @@ MingwBackend::GetVersionString ( const string& versionCommand )
        {
                prevtoken = token;
                version = string( prevtoken );
+               if ( (newline = version.find('\n')) != std::string::npos )
+                       version.erase(newline, 1);
                if ( version.find('.') != std::string::npos )
                        break;
                token = strtok ( NULL, separators );
@@ -935,7 +897,7 @@ bool
 MingwBackend::TryToDetectThisBinutils ( const string& binutils )
 {
        string command = ssprintf (
-               "%s -v 1>%s",
+               "%s -v 1>%s 2>%s",
                FixSeparatorForSystemCommand(binutils).c_str (),
                NUL,
                NUL );
@@ -955,11 +917,11 @@ MingwBackend::GetBinutilsVersionDate ( const string& binutilsCommand )
                                           NUL,
                                           NUL );
        fp = popen ( versionCommand.c_str () , "r" );
-       for( i = 0; 
-             ( i < 80 ) && 
-                 ( feof ( fp ) == 0 && 
-                   ( ( ch = fgetc( fp ) ) != -1 ) ); 
-             i++ )
+       for( i = 0;
+            ( i < 80 ) &&
+                ( feof ( fp ) == 0 &&
+                  ( ( ch = fgetc( fp ) ) != -1 ) );
+            i++ )
        {
                buffer[i] = (char) ch;
        }
@@ -1016,34 +978,51 @@ MingwBackend::DetectBinutils ()
        printf ( "Detecting binutils..." );
 
        bool detectedBinutils = false;
-       const string& ROS_PREFIXValue = Environment::GetVariable ( "ROS_PREFIX" );
+       bool supportedBinutils = false;
+       string binutilsVersion;
 
-       if ( ROS_PREFIXValue.length () > 0 )
+       if ( ProjectNode.configuration.Linker == GnuLd )
        {
-               binutilsPrefix = ROS_PREFIXValue;
-               binutilsCommand = binutilsPrefix + "-ld";
-               manualBinutilsSetting = true;
-               detectedBinutils = true;
-       }
+               const string& ROS_PREFIXValue = Environment::GetVariable ( "ROS_PREFIX" );
+
+               if ( ROS_PREFIXValue.length () > 0 )
+               {
+                       binutilsPrefix = ROS_PREFIXValue;
+                       binutilsCommand = binutilsPrefix + "-ld";
+                       manualBinutilsSetting = true;
+                       detectedBinutils = true;
+               }
 #if defined(WIN32)
-       if ( !detectedBinutils )
-       {
-               binutilsPrefix = "";
-               binutilsCommand = "ld";
-               detectedBinutils = TryToDetectThisBinutils ( binutilsCommand );
-       }
+               if ( !detectedBinutils )
+               {
+                       binutilsPrefix = "";
+                       binutilsCommand = "ld";
+                       detectedBinutils = TryToDetectThisBinutils ( binutilsCommand );
+               }
 #endif
-       if ( !detectedBinutils )
+               if ( !detectedBinutils )
+               {
+                       binutilsPrefix = "mingw32";
+                       binutilsCommand = binutilsPrefix + "-ld";
+                       detectedBinutils = TryToDetectThisBinutils ( binutilsCommand );
+               }
+               if ( detectedBinutils )
+               {
+                       binutilsVersion = GetBinutilsVersionDate ( binutilsCommand );
+                       supportedBinutils = IsSupportedBinutilsVersion ( binutilsVersion );
+               }
+       }
+       else if ( ProjectNode.configuration.Linker == MicrosoftLink )
        {
-               binutilsPrefix = "mingw32";
-               binutilsCommand = binutilsPrefix + "-ld";
-               detectedBinutils = TryToDetectThisBinutils ( binutilsCommand );
+               compilerCommand = "link";
+               detectedBinutils = DetectMicrosoftLinker ( binutilsVersion, mslinkPath );
+               supportedBinutils = true; // TODO
        }
+
        if ( detectedBinutils )
        {
-               string binutilsVersion = GetBinutilsVersionDate ( binutilsCommand );
-               if ( IsSupportedBinutilsVersion ( binutilsVersion ) )
-                       printf ( "detected (%s %s)\n", binutilsCommand.c_str (), GetBinutilsVersion( binutilsCommand ).c_str() );
+               if ( supportedBinutils )
+                       printf ( "detected (%s %s)\n", binutilsCommand.c_str (), binutilsVersion.c_str() );
                else
                {
                        printf ( "detected (%s), but with unsupported version (%s)\n",
@@ -1085,33 +1064,38 @@ MingwBackend::DetectNetwideAssembler ()
 void
 MingwBackend::DetectPipeSupport ()
 {
-       printf ( "Detecting compiler -pipe support..." );
-
-       string pipe_detection = "tools" + sSep + "rbuild" + sSep + "backend" + sSep + "mingw" + sSep + "pipe_detection.c";
-       string pipe_detectionObjectFilename = ReplaceExtension ( pipe_detection,
-                                                                ".o" );
-       string command = ssprintf (
-               "%s -pipe -c %s -o %s 1>%s 2>%s",
-               FixSeparatorForSystemCommand(compilerCommand).c_str (),
-               pipe_detection.c_str (),
-               pipe_detectionObjectFilename.c_str (),
-               NUL,
-               NUL );
-       int exitcode = system ( command.c_str () );
-       FILE* f = fopen ( pipe_detectionObjectFilename.c_str (), "rb" );
-       if ( f )
+       if ( ProjectNode.configuration.Compiler == GnuGcc )
        {
-               usePipe = (exitcode == 0);
-               fclose ( f );
-               unlink ( pipe_detectionObjectFilename.c_str () );
+               printf ( "Detecting compiler -pipe support..." );
+
+               string pipe_detection = "tools" + sSep + "rbuild" + sSep + "backend" + sSep + "mingw" + sSep + "pipe_detection.c";
+               string pipe_detectionObjectFilename = ReplaceExtension ( pipe_detection,
+                                                                                                                                ".o" );
+               string command = ssprintf (
+                       "%s -pipe -c %s -o %s 1>%s 2>%s",
+                       FixSeparatorForSystemCommand(compilerCommand).c_str (),
+                       pipe_detection.c_str (),
+                       pipe_detectionObjectFilename.c_str (),
+                       NUL,
+                       NUL );
+               int exitcode = system ( command.c_str () );
+               FILE* f = fopen ( pipe_detectionObjectFilename.c_str (), "rb" );
+               if ( f )
+               {
+                       usePipe = (exitcode == 0);
+                       fclose ( f );
+                       unlink ( pipe_detectionObjectFilename.c_str () );
+               }
+               else
+                       usePipe = false;
+
+               if ( usePipe )
+                       printf ( "detected\n" );
+               else
+                       printf ( "not detected\n" );
        }
        else
                usePipe = false;
-
-       if ( usePipe )
-               printf ( "detected\n" );
-       else
-               printf ( "not detected\n" );
 }
 
 void
@@ -1119,30 +1103,38 @@ MingwBackend::DetectPCHSupport ()
 {
        printf ( "Detecting compiler pre-compiled header support..." );
 
-       string path = "tools" + sSep + "rbuild" + sSep + "backend" + sSep + "mingw" + sSep + "pch_detection.h";
-       string cmd = ssprintf (
-               "%s -c %s 1>%s 2>%s",
-               FixSeparatorForSystemCommand(compilerCommand).c_str (),
-               path.c_str (),
-               NUL,
-               NUL );
-       system ( cmd.c_str () );
-       path += ".gch";
-
-       FILE* f = fopen ( path.c_str (), "rb" );
-       if ( f )
+       if ( configuration.PrecompiledHeadersEnabled && ProjectNode.configuration.Compiler == GnuGcc )
        {
-               use_pch = true;
-               fclose ( f );
-               unlink ( path.c_str () );
+               string path = "tools" + sSep + "rbuild" + sSep + "backend" + sSep + "mingw" + sSep + "pch_detection.h";
+               string cmd = ssprintf (
+                       "%s -c %s 1>%s 2>%s",
+                       FixSeparatorForSystemCommand(compilerCommand).c_str (),
+                       path.c_str (),
+                       NUL,
+                       NUL );
+               system ( cmd.c_str () );
+               path += ".gch";
+
+               FILE* f = fopen ( path.c_str (), "rb" );
+               if ( f )
+               {
+                       use_pch = true;
+                       fclose ( f );
+                       unlink ( path.c_str () );
+               }
+               else
+                       use_pch = false;
+
+               if ( use_pch )
+                       printf ( "detected\n" );
+               else
+                       printf ( "not detected\n" );
        }
        else
+       {
                use_pch = false;
-
-       if ( use_pch )
-               printf ( "detected\n" );
-       else
-               printf ( "not detected\n" );
+               printf ( "disabled\n" );
+       }
 }
 
 void
@@ -1160,17 +1152,13 @@ void
 MingwBackend::GetModuleInstallTargetFiles (
        vector<FileLocation>& out ) const
 {
-       for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
+       for ( std::map<std::string, Module*>::const_iterator p = ProjectNode.modules.begin (); p != ProjectNode.modules.end (); ++ p )
        {
-               const Module& module = *ProjectNode.modules[i];
+               const Module& module = *p->second;
                if ( !module.enabled )
                        continue;
-               if ( module.installName.length () > 0 )
-               {
-                       out.push_back ( FileLocation ( InstallDirectory,
-                                                      module.installBase,
-                                                      module.installName ) );
-               }
+               if ( module.install )
+                       out.push_back ( *module.install );
        }
 }
 
@@ -1188,15 +1176,15 @@ MingwBackend::OutputInstallTarget ( const FileLocation& source,
 {
        fprintf ( fMakefile,
                  "%s: %s | %s\n",
-                 strFile( &target ).c_str (),
-                 strFile( &source ).c_str (),
-                 strDirectory( &target ).c_str () );
+                 GetFullName ( target ).c_str (),
+                 GetFullName ( source ).c_str (),
+                 GetFullPath ( target ).c_str () );
        fprintf ( fMakefile,
                  "\t$(ECHO_CP)\n" );
        fprintf ( fMakefile,
                  "\t${cp} %s %s 1>$(NUL)\n",
-                 strFile( &source ).c_str (),
-                 strFile( &target ).c_str () );
+                 GetFullName ( source ).c_str (),
+                 GetFullName ( target ).c_str () );
 }
 
 void
@@ -1225,18 +1213,15 @@ MingwBackend::GetAliasedModuleOrModule ( const Module& module ) const
 void
 MingwBackend::OutputModuleInstallTargets ()
 {
-       for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
+       for ( std::map<std::string, Module*>::const_iterator p = ProjectNode.modules.begin (); p != ProjectNode.modules.end (); ++ p )
        {
-               const Module& module = *ProjectNode.modules[i];
+               const Module& module = *p->second;
                if ( !module.enabled )
                        continue;
-               if ( module.installName.length () > 0 )
+               if ( module.install )
                {
                        const Module& aliasedModule = GetAliasedModuleOrModule ( module );
-
-                       FileLocation source ( OutputDirectory, aliasedModule.GetBasePath (), aliasedModule.GetTargetName () );
-                       FileLocation target ( InstallDirectory, module.installBase, module.installName );
-                       OutputInstallTarget ( source, target );
+                       OutputInstallTarget ( *aliasedModule.output, *module.install );
                }
        }
 }
@@ -1244,11 +1229,11 @@ MingwBackend::OutputModuleInstallTargets ()
 string
 MingwBackend::GetRegistrySourceFiles ()
 {
-       return "boot" + sSep + "bootdata" + sSep + "hivecls.inf "
-               "boot" + sSep + "bootdata" + sSep + "hivedef.inf "
-               "boot" + sSep + "bootdata" + sSep + "hiveinst.inf "
-               "boot" + sSep + "bootdata" + sSep + "hivesft.inf "
-               "boot" + sSep + "bootdata" + sSep + "hivesys.inf";
+       return "boot" + sSep + "bootdata" + sSep + "hivecls_" + Environment::GetArch() + ".inf "
+               "boot" + sSep + "bootdata" + sSep + "hivedef_" + Environment::GetArch() + ".inf "
+               "boot" + sSep + "bootdata" + sSep + "hiveinst_" + Environment::GetArch() + ".inf "
+               "boot" + sSep + "bootdata" + sSep + "hivesft_" + Environment::GetArch() + ".inf "
+               "boot" + sSep + "bootdata" + sSep + "hivesys_" + Environment::GetArch() + ".inf ";
 }
 
 string
@@ -1264,7 +1249,7 @@ MingwBackend::GetRegistryTargetFiles ()
        registry_files.push_back ( FileLocation ( InstallDirectory, system32ConfigDirectory, "software" ) );
        registry_files.push_back ( FileLocation ( InstallDirectory, system32ConfigDirectory, "system" ) );
 
-       return v2s( registry_files, 6 );
+       return v2s( this, registry_files, 6 );
 }
 
 void
@@ -1281,12 +1266,12 @@ MingwBackend::OutputRegistryInstallTarget ()
                  "%s: %s %s $(MKHIVE_TARGET)\n",
                  registryTargetFiles.c_str (),
                  registrySourceFiles.c_str (),
-                 strDirectory ( &system32 ).c_str () );
+                 GetFullPath ( system32 ).c_str () );
        fprintf ( fMakefile,
                  "\t$(ECHO_MKHIVE)\n" );
        fprintf ( fMakefile,
-                 "\t$(MKHIVE_TARGET) boot%cbootdata %s boot%cbootdata%chiveinst.inf\n",
-                 cSep, strDirectory ( &system32 ).c_str (),
+                 "\t$(MKHIVE_TARGET) boot%cbootdata %s $(ARCH) boot%cbootdata%chiveinst_$(ARCH).inf\n",
+                 cSep, GetFullPath ( system32 ).c_str (),
                  cSep, cSep );
        fprintf ( fMakefile,
                  "\n" );
@@ -1297,7 +1282,7 @@ MingwBackend::GenerateInstallTarget ()
 {
        vector<FileLocation> vInstallTargetFiles;
        GetInstallTargetFiles ( vInstallTargetFiles );
-       string installTargetFiles = v2s ( vInstallTargetFiles, 5 );
+       string installTargetFiles = v2s ( this, vInstallTargetFiles, 5 );
        string registryTargetFiles = GetRegistryTargetFiles ();
 
        fprintf ( fMakefile,
@@ -1315,9 +1300,9 @@ void
 MingwBackend::GetModuleTestTargets (
        vector<string>& out ) const
 {
-       for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
+       for ( std::map<std::string, Module*>::const_iterator p = ProjectNode.modules.begin (); p != ProjectNode.modules.end (); ++ p )
        {
-               const Module& module = *ProjectNode.modules[i];
+               const Module& module = *p->second;
                if ( !module.enabled )
                        continue;
                if ( module.type == Test )
@@ -1342,7 +1327,7 @@ MingwBackend::GenerateTestTarget ()
 void
 MingwBackend::GenerateDirectoryTargets ()
 {
-       intermediateDirectory->CreateRule ( fMakefile, "" );
-       outputDirectory->CreateRule ( fMakefile, "" );
-       installDirectory->CreateRule ( fMakefile, "" );
+       intermediateDirectory->CreateRule ( fMakefile, "$(INTERMEDIATE)" );
+       outputDirectory->CreateRule ( fMakefile, "$(OUTPUT)" );
+       installDirectory->CreateRule ( fMakefile, "$(INSTALL)" );
 }