Show execution time of tests
[reactos.git] / reactos / tools / rbuild / backend / mingw / mingw.cpp
index bd50e02..aeeadd9 100644 (file)
-\r
-#include "../../pch.h"\r
-\r
-#include "mingw.h"\r
-#include <assert.h>\r
-#include <dirent.h>\r
-#include "modulehandler.h"\r
-\r
-#ifdef WIN32\r
-#define MKDIR(s) mkdir(s)\r
-#else\r
-#define MKDIR(s) mkdir(s, 0755)\r
-#endif\r
-\r
-using std::string;\r
-using std::vector;\r
-using std::set;\r
-using std::map;\r
-\r
-typedef set<string> set_string;\r
-typedef map<string,Directory*> directory_map;\r
-\r
-\r
-string\r
-v2s ( const string_list& v, int wrap_at )\r
-{\r
-       if ( !v.size() )\r
-               return "";\r
-       string s;\r
-       int wrap_count = 0;\r
-       for ( size_t i = 0; i < v.size(); i++ )\r
-       {\r
-               if ( !v[i].size() )\r
-                       continue;\r
-               if ( wrap_at > 0 && wrap_count++ == wrap_at )\r
-                       s += " \\\n\t\t";\r
-               else if ( s.size() )\r
-                       s += " ";\r
-               s += v[i];\r
-       }\r
-       return s;\r
-}\r
-\r
-\r
-class Directory\r
-{\r
-public:\r
-       string name;\r
-       directory_map subdirs;\r
-       Directory ( const string& name );\r
-       void Add ( const char* subdir );\r
-       void GenerateTree ( const string& parent,\r
-                           bool verbose );\r
-private:\r
-       bool mkdir_p ( const char* path );\r
-       string ReplaceVariable ( string name,\r
-                                string value,\r
-                                string path );\r
-       string GetIntermediatePath ();\r
-       string GetOutputPath ();\r
-       void ResolveVariablesInPath ( char* buf,\r
-                                     string path );\r
-       bool CreateDirectory ( string path );\r
-};\r
-\r
-Directory::Directory ( const string& name_ )\r
-       : name(name_)\r
-{\r
-}\r
-\r
-void Directory::Add ( const char* subdir )\r
-{\r
-       size_t i;\r
-       string s1 = string ( subdir );\r
-       if ( ( i = s1.find ( '$' ) ) != string::npos )\r
-       {\r
-               throw InvalidOperationException ( __FILE__,\r
-                                                 __LINE__,\r
-                                                 "No environment variables can be used here. Path was %s",\r
-                                                 subdir );\r
-       }\r
-\r
-       const char* p = strpbrk ( subdir, "/\\" );\r
-       if ( !p )\r
-               p = subdir + strlen(subdir);\r
-       string s ( subdir, p-subdir );\r
-       if ( subdirs.find(s) == subdirs.end() )\r
-               subdirs[s] = new Directory(s);\r
-       if ( *p && *++p )\r
-               subdirs[s]->Add ( p );\r
-}\r
-\r
-bool\r
-Directory::mkdir_p ( const char* path )\r
-{\r
-       DIR *directory;\r
-       directory = opendir ( path );\r
-       if ( directory != NULL )\r
-       {\r
-               closedir ( directory );\r
-               return false;\r
-       }\r
-\r
-       if ( MKDIR ( path ) != 0 )\r
-               throw AccessDeniedException ( string ( path ) );\r
-       return true;\r
-}\r
-\r
-bool\r
-Directory::CreateDirectory ( string path )\r
-{\r
-       size_t index = 0;\r
-       size_t nextIndex;\r
-       if ( isalpha ( path[0] ) && path[1] == ':' && path[2] == CSEP )\r
-       {\r
-               nextIndex = path.find ( CSEP, 3);\r
-       }\r
-       else\r
-               nextIndex = path.find ( CSEP );\r
-\r
-       bool directoryWasCreated = false;\r
-       while ( nextIndex != string::npos )\r
-       {\r
-               nextIndex = path.find ( CSEP, index + 1 );\r
-               directoryWasCreated = mkdir_p ( path.substr ( 0, nextIndex ).c_str () );\r
-               index = nextIndex;\r
-       }\r
-       return directoryWasCreated;\r
-}\r
-\r
-string\r
-Directory::ReplaceVariable ( string name,\r
-                                string value,\r
-                                string path )\r
-{\r
-       size_t i = path.find ( name );\r
-       if ( i != string::npos )\r
-               return path.replace ( i, name.length (), value );\r
-       else\r
-               return path;\r
-}\r
-\r
-string\r
-Directory::GetIntermediatePath ()\r
-{\r
-       return "obj-i386";\r
-}\r
-\r
-string\r
-Directory::GetOutputPath ()\r
-{\r
-       return "output-i386";\r
-}\r
-\r
-void\r
-Directory::ResolveVariablesInPath ( char* buf,\r
-                                       string path )\r
-{\r
-       string s = ReplaceVariable ( "$(INTERMEDIATE)", GetIntermediatePath (), path );\r
-       s = ReplaceVariable ( "$(OUTPUT)", GetOutputPath (), s );\r
-       strcpy ( buf, s.c_str () );\r
-}\r
-\r
-void\r
-Directory::GenerateTree ( const string& parent,\r
-                             bool verbose )\r
-{\r
-       string path;\r
-\r
-       if ( parent.size() )\r
-       {\r
-               char buf[256];\r
-               \r
-               path = parent + SSEP + name;\r
-               ResolveVariablesInPath ( buf, path );\r
-               if ( CreateDirectory ( buf ) && verbose )\r
-                       printf ( "Created %s\n", buf );\r
-       }\r
-       else\r
-               path = name;\r
-\r
-       for ( directory_map::iterator i = subdirs.begin();\r
-               i != subdirs.end();\r
-               ++i )\r
-       {\r
-               i->second->GenerateTree ( path, verbose );\r
-       }\r
-}\r
-\r
-static class MingwFactory : public Backend::Factory\r
-{\r
-public:\r
-       MingwFactory() : Factory ( "mingw" ) {}\r
-       Backend* operator() ( Project& project, bool verbose )\r
-       {\r
-               return new MingwBackend ( project, verbose );\r
-       }\r
-} factory;\r
-\r
-\r
-MingwBackend::MingwBackend ( Project& project, bool verbose )\r
-       : Backend ( project, verbose ),\r
-         int_directories ( new Directory("$(INTERMEDIATE)") ),\r
-         out_directories ( new Directory("$(OUTPUT)") )\r
-{\r
-}\r
-\r
-MingwBackend::~MingwBackend()\r
-{\r
-       delete int_directories;\r
-       delete out_directories;\r
-}\r
-\r
-string\r
-MingwBackend::AddDirectoryTarget ( const string& directory, bool out )\r
-{\r
-       const char* dir_name = "$(INTERMEDIATE)";\r
-       Directory* dir = int_directories;\r
-       if ( out )\r
-       {\r
-               dir_name = "$(OUTPUT)";\r
-               dir = out_directories;\r
-       }\r
-       dir->Add ( directory.c_str() );\r
-       return dir_name;\r
-}\r
-\r
-void\r
-MingwBackend::ProcessModules ()\r
-{\r
-       printf ( "Processing modules..." );\r
-\r
-       vector<MingwModuleHandler*> v;\r
-       size_t i;\r
-       for ( i = 0; i < ProjectNode.modules.size (); i++ )\r
-       {\r
-               Module& module = *ProjectNode.modules[i];\r
-               MingwModuleHandler* h = MingwModuleHandler::InstanciateHandler (\r
-                       module,\r
-                       this );\r
-               if ( module.host == HostDefault )\r
-               {\r
-                       module.host = h->DefaultHost();\r
-                       assert ( module.host != HostDefault );\r
-               }\r
-               v.push_back ( h );\r
-       }\r
-\r
-       size_t iend = v.size ();\r
-\r
-       for ( i = 0; i < iend; i++ )\r
-               v[i]->GenerateObjectMacro();\r
-       fprintf ( fMakefile, "\n" );\r
-       for ( i = 0; i < iend; i++ )\r
-               v[i]->GenerateTargetMacro();\r
-       fprintf ( fMakefile, "\n" );\r
-\r
-       GenerateAllTarget ( v );\r
-       GenerateInitTarget ();\r
-\r
-       for ( i = 0; i < iend; i++ )\r
-               v[i]->GenerateOtherMacros();\r
-\r
-       for ( i = 0; i < iend; i++ )\r
-       {\r
-               MingwModuleHandler& h = *v[i];\r
-               h.GeneratePreconditionDependencies ();\r
-               h.Process ();\r
-               h.GenerateInvocations ();\r
-               h.GenerateCleanTarget ();\r
-               delete v[i];\r
-       }\r
-\r
-       printf ( "done\n" );\r
-}\r
-       \r
-void\r
-MingwBackend::Process ()\r
-{\r
-       DetectPipeSupport ();\r
-       DetectPCHSupport ();\r
-       CreateMakefile ();\r
-       GenerateHeader ();\r
-       GenerateGlobalVariables ();\r
-       GenerateXmlBuildFilesMacro ();\r
-       ProcessModules ();\r
-       GenerateInstallTarget ();\r
-       GenerateDirectories ();\r
-       CheckAutomaticDependencies ();\r
-       CloseMakefile ();\r
-}\r
-\r
-void\r
-MingwBackend::CreateMakefile ()\r
-{\r
-       fMakefile = fopen ( ProjectNode.makefile.c_str (), "w" );\r
-       if ( !fMakefile )\r
-               throw AccessDeniedException ( ProjectNode.makefile );\r
-       MingwModuleHandler::SetBackend ( this );\r
-       MingwModuleHandler::SetMakefile ( fMakefile );\r
-       MingwModuleHandler::SetUsePch ( use_pch );\r
-}\r
-\r
-void\r
-MingwBackend::CloseMakefile () const\r
-{\r
-       if (fMakefile)\r
-               fclose ( fMakefile );\r
-}\r
-\r
-void\r
-MingwBackend::GenerateHeader () const\r
-{\r
-       fprintf ( fMakefile, "# THIS FILE IS AUTOMATICALLY GENERATED, EDIT 'ReactOS.xml' INSTEAD\n\n" );\r
-}\r
-\r
-void\r
-MingwBackend::GenerateProjectCFlagsMacro ( const char* assignmentOperation,\r
-                                           IfableData& data ) const\r
-{\r
-       size_t i;\r
-\r
-       fprintf (\r
-               fMakefile,\r
-               "PROJECT_CFLAGS %s",\r
-               assignmentOperation );\r
-       for ( i = 0; i < data.includes.size(); i++ )\r
-       {\r
-               fprintf (\r
-                       fMakefile,\r
-                       " -I%s",\r
-                       data.includes[i]->directory.c_str() );\r
-       }\r
-\r
-       for ( i = 0; i < data.defines.size(); i++ )\r
-       {\r
-               Define& d = *data.defines[i];\r
-               fprintf (\r
-                       fMakefile,\r
-                       " -D%s",\r
-                       d.name.c_str() );\r
-               if ( d.value.size() )\r
-                       fprintf (\r
-                               fMakefile,\r
-                               "=%s",\r
-                               d.value.c_str() );\r
-       }\r
-       fprintf ( fMakefile, "\n" );\r
-}\r
-\r
-void\r
-MingwBackend::GenerateGlobalCFlagsAndProperties (\r
-       const char* assignmentOperation,\r
-       IfableData& data ) const\r
-{\r
-       size_t i;\r
-\r
-       for ( i = 0; i < data.properties.size(); i++ )\r
-       {\r
-               Property& prop = *data.properties[i];\r
-               fprintf ( fMakefile, "%s := %s\n",\r
-                       prop.name.c_str(),\r
-                       prop.value.c_str() );\r
-       }\r
-\r
-       if ( data.includes.size() || data.defines.size() )\r
-       {\r
-               GenerateProjectCFlagsMacro ( assignmentOperation,\r
-                                            data );\r
-       }\r
-\r
-       for ( i = 0; i < data.ifs.size(); i++ )\r
-       {\r
-               If& rIf = *data.ifs[i];\r
-               if ( rIf.data.defines.size()\r
-                       || rIf.data.includes.size()\r
-                       || rIf.data.ifs.size() )\r
-               {\r
-                       fprintf (\r
-                               fMakefile,\r
-                               "ifeq (\"$(%s)\",\"%s\")\n",\r
-                               rIf.property.c_str(),\r
-                               rIf.value.c_str() );\r
-                       GenerateGlobalCFlagsAndProperties (\r
-                               "+=",\r
-                               rIf.data );\r
-                       fprintf (\r
-                               fMakefile,\r
-                               "endif\n\n" );\r
-               }\r
-       }\r
-}\r
-\r
-string\r
-MingwBackend::GenerateProjectLFLAGS () const\r
-{\r
-       string lflags;\r
-       for ( size_t i = 0; i < ProjectNode.linkerFlags.size (); i++ )\r
-       {\r
-               LinkerFlag& linkerFlag = *ProjectNode.linkerFlags[i];\r
-               if ( lflags.length () > 0 )\r
-                       lflags += " ";\r
-               lflags += linkerFlag.flag;\r
-       }\r
-       return lflags;\r
-}\r
-\r
-void\r
-MingwBackend::GenerateGlobalVariables () const\r
-{\r
-       GenerateGlobalCFlagsAndProperties (\r
-               "=",\r
-               ProjectNode.non_if_data );\r
-       fprintf ( fMakefile, "PROJECT_RCFLAGS = $(PROJECT_CFLAGS)\n" );\r
-       fprintf ( fMakefile, "PROJECT_LFLAGS = %s\n",\r
-                 GenerateProjectLFLAGS ().c_str () );\r
-       fprintf ( fMakefile, "\n" );\r
-}\r
-\r
-bool\r
-MingwBackend::IncludeInAllTarget ( const Module& module ) const\r
-{\r
-       if ( module.type == ObjectLibrary )\r
-               return false;\r
-       if ( module.type == BootSector )\r
-               return false;\r
-       if ( module.type == Iso )\r
-               return false;\r
-       return true;\r
-}\r
-\r
-void\r
-MingwBackend::GenerateAllTarget ( const vector<MingwModuleHandler*>& handlers ) const\r
-{\r
-       fprintf ( fMakefile, "all:" );\r
-       int wrap_count = 0;\r
-       size_t iend = handlers.size ();\r
-       for ( size_t i = 0; i < iend; i++ )\r
-       {\r
-               const Module& module = handlers[i]->module;\r
-               if ( IncludeInAllTarget ( module ) )\r
-               {\r
-                       if ( wrap_count++ == 5 )\r
-                               fprintf ( fMakefile, " \\\n\t\t" ), wrap_count = 0;\r
-                       fprintf ( fMakefile,\r
-                                 " %s",\r
-                                 GetTargetMacro(module).c_str () );\r
-               }\r
-       }\r
-       fprintf ( fMakefile, "\n\t\n\n" );\r
-}\r
-\r
-string\r
-MingwBackend::GetBuildToolDependencies () const\r
-{\r
-       string dependencies;\r
-       for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )\r
-       {\r
-               Module& module = *ProjectNode.modules[i];\r
-               if ( module.type == BuildTool )\r
-               {\r
-                       if ( dependencies.length () > 0 )\r
-                               dependencies += " ";\r
-                       dependencies += module.GetDependencyPath ();\r
-               }\r
-       }\r
-       return dependencies;\r
-}\r
-\r
-void\r
-MingwBackend::GenerateInitTarget () const\r
-{\r
-       fprintf ( fMakefile,\r
-                 "INIT = %s\n",\r
-                 GetBuildToolDependencies ().c_str () );\r
-       fprintf ( fMakefile, "\n" );\r
-}\r
-\r
-void\r
-MingwBackend::GenerateXmlBuildFilesMacro() const\r
-{\r
-       fprintf ( fMakefile,\r
-                 "XMLBUILDFILES = %s \\\n",\r
-                 ProjectNode.GetProjectFilename ().c_str () );\r
-       string xmlbuildFilenames;\r
-       int numberOfExistingFiles = 0;\r
-       for ( size_t i = 0; i < ProjectNode.xmlbuildfiles.size (); i++ )\r
-       {\r
-               XMLInclude& xmlbuildfile = *ProjectNode.xmlbuildfiles[i];\r
-               if ( !xmlbuildfile.fileExists )\r
-                       continue;\r
-               numberOfExistingFiles++;\r
-               if ( xmlbuildFilenames.length () > 0 )\r
-                       xmlbuildFilenames += " ";\r
-               xmlbuildFilenames += NormalizeFilename ( xmlbuildfile.topIncludeFilename );\r
-               if ( numberOfExistingFiles % 5 == 4 || i == ProjectNode.xmlbuildfiles.size () - 1 )\r
-               {\r
-                       fprintf ( fMakefile,\r
-                                 "\t%s",\r
-                                 xmlbuildFilenames.c_str ());\r
-                       if ( i == ProjectNode.xmlbuildfiles.size () - 1 )\r
-                       {\r
-                               fprintf ( fMakefile, "\n" );\r
-                       }\r
-                       else\r
-                       {\r
-                               fprintf ( fMakefile,\r
-                                         " \\\n",\r
-                                         xmlbuildFilenames.c_str () );\r
-                       }\r
-                       xmlbuildFilenames.resize ( 0 );\r
-               }\r
-               numberOfExistingFiles++;\r
-       }\r
-       fprintf ( fMakefile, "\n" );\r
-}\r
-\r
-void\r
-MingwBackend::CheckAutomaticDependencies ()\r
-{\r
-       printf ( "Checking automatic dependencies..." );\r
-       AutomaticDependency automaticDependency ( ProjectNode );\r
-       automaticDependency.Process ();\r
-       automaticDependency.CheckAutomaticDependencies ( verbose );\r
-       printf ( "done\n" );\r
-}\r
-\r
-bool\r
-MingwBackend::IncludeDirectoryTarget ( const string& directory ) const\r
-{\r
-       if ( directory == "$(INTERMEDIATE)" SSEP "tools")\r
-               return false;\r
-       else\r
-               return true;\r
-}\r
-\r
-void\r
-MingwBackend::GenerateDirectories ()\r
-{\r
-       printf ( "Creating directories..." );\r
-       int_directories->GenerateTree ( "", verbose );\r
-       out_directories->GenerateTree ( "", verbose );\r
-       printf ( "done\n" );\r
-}\r
-\r
-string\r
-FixupTargetFilename ( const string& targetFilename )\r
-{\r
-       return NormalizeFilename ( targetFilename );\r
-}\r
-\r
-void\r
-MingwBackend::DetectPipeSupport ()\r
-{\r
-       printf ( "Detecting compiler -pipe support..." );\r
-\r
-       string pipe_detection = "tools" SSEP "rbuild" SSEP "backend" SSEP "mingw" SSEP "pipe_detection.c";\r
-       string pipe_detectionObjectFilename = ReplaceExtension ( pipe_detection,\r
-                                                                ".o" );\r
-       string command = ssprintf (\r
-               "gcc -pipe -c %s -o %s 2>%s",\r
-               pipe_detection.c_str (),\r
-               pipe_detectionObjectFilename.c_str (),\r
-               NUL );\r
-       int exitcode = system ( command.c_str () );\r
-       FILE* f = fopen ( pipe_detectionObjectFilename.c_str (), "rb" );\r
-       if ( f )\r
-       {\r
-               usePipe = (exitcode == 0);\r
-               fclose ( f );\r
-               unlink ( pipe_detectionObjectFilename.c_str () );\r
-       }\r
-       else\r
-               usePipe = false;\r
-\r
-       if ( usePipe )\r
-               printf ( "detected\n" );\r
-       else\r
-               printf ( "not detected\n" );\r
-\r
-       // TODO FIXME - eventually check for ROS_USE_PCH env var and\r
-       // allow that to override use_pch if true\r
-}\r
-\r
-void\r
-MingwBackend::DetectPCHSupport ()\r
-{\r
-       printf ( "Detecting compiler pre-compiled header support..." );\r
-\r
-       string path = "tools" SSEP "rbuild" SSEP "backend" SSEP "mingw" SSEP "pch_detection.h";\r
-       string cmd = ssprintf (\r
-               "gcc -c %s 2>%s",\r
-               path.c_str (),\r
-               NUL );\r
-       system ( cmd.c_str () );\r
-       path += ".gch";\r
-\r
-       FILE* f = fopen ( path.c_str (), "rb" );\r
-       if ( f )\r
-       {\r
-               use_pch = true;\r
-               fclose ( f );\r
-               unlink ( path.c_str () );\r
-       }\r
-       else\r
-               use_pch = false;\r
-\r
-       if ( use_pch )\r
-               printf ( "detected\n" );\r
-       else\r
-               printf ( "not detected\n" );\r
-\r
-       // TODO FIXME - eventually check for ROS_USE_PCH env var and\r
-       // allow that to override use_pch if true\r
-}\r
-\r
-void\r
-MingwBackend::GetNonModuleInstallTargetFiles (\r
-       string installDirectory,\r
-       vector<string>& out ) const\r
-{\r
-       for ( size_t i = 0; i < ProjectNode.installfiles.size (); i++ )\r
-       {\r
-               const InstallFile& installfile = *ProjectNode.installfiles[i];\r
-               string targetFilenameNoFixup = installDirectory + SSEP + installfile.base + SSEP + installfile.newname;\r
-               string targetFilename = MingwModuleHandler::PassThruCacheDirectory (\r
-                       NormalizeFilename ( targetFilenameNoFixup ),\r
-                       true );\r
-               out.push_back ( targetFilename );\r
-       }\r
-}\r
-\r
-void\r
-MingwBackend::GetModuleInstallTargetFiles (\r
-       string installDirectory,\r
-       vector<string>& out ) const\r
-{\r
-       for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )\r
-       {\r
-               const Module& module = *ProjectNode.modules[i];\r
-               if ( module.installName.length () > 0 )\r
-               {\r
-                       string targetFilenameNoFixup = installDirectory + SSEP + module.installBase + SSEP + module.installName;\r
-                       string targetFilename = MingwModuleHandler::PassThruCacheDirectory (\r
-                               NormalizeFilename ( targetFilenameNoFixup ),\r
-                               true );\r
-                       out.push_back ( targetFilename );\r
-               }\r
-       }\r
-}\r
-\r
-void\r
-MingwBackend::GetInstallTargetFiles (\r
-       string installDirectory,\r
-       vector<string>& out ) const\r
-{\r
-       GetNonModuleInstallTargetFiles ( installDirectory,\r
-                                        out );\r
-       GetModuleInstallTargetFiles ( installDirectory,\r
-                                     out );\r
-}\r
-\r
-void\r
-MingwBackend::OutputInstallTarget ( const string& installDirectory,\r
-                                       const string& sourceFilename,\r
-                                       const string& targetFilename,\r
-                                       const string& targetDirectory )\r
-{\r
-       string normalizedTargetFilename = MingwModuleHandler::PassThruCacheDirectory (\r
-               NormalizeFilename ( installDirectory + SSEP + targetDirectory + SSEP + targetFilename ),\r
-               true );\r
-       string normalizedTargetDirectory = MingwModuleHandler::PassThruCacheDirectory (\r
-               NormalizeFilename ( installDirectory + SSEP + targetDirectory ),\r
-               true );\r
-       fprintf ( fMakefile,\r
-                 "%s: %s %s\n",\r
-                 normalizedTargetFilename.c_str (),\r
-                 sourceFilename.c_str (),\r
-                 normalizedTargetDirectory.c_str () );\r
-       fprintf ( fMakefile,\r
-                 "\t$(ECHO_CP)\n" );\r
-       fprintf ( fMakefile,\r
-                 "\t${cp} %s %s\n",\r
-                 sourceFilename.c_str (),\r
-                 normalizedTargetFilename.c_str () );\r
-}\r
-\r
-void\r
-MingwBackend::OutputNonModuleInstallTargets ( const string& installDirectory )\r
-{\r
-       for ( size_t i = 0; i < ProjectNode.installfiles.size (); i++ )\r
-       {\r
-               const InstallFile& installfile = *ProjectNode.installfiles[i];\r
-               OutputInstallTarget ( installDirectory,\r
-                                 installfile.GetPath (),\r
-                                 installfile.newname,\r
-                                 installfile.base );\r
-       }\r
-}\r
-\r
-void\r
-MingwBackend::OutputModuleInstallTargets ( const string& installDirectory )\r
-{\r
-       for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )\r
-       {\r
-               const Module& module = *ProjectNode.modules[i];\r
-               if ( module.installName.length () > 0 )\r
-               {\r
-                       string sourceFilename = MingwModuleHandler::PassThruCacheDirectory (\r
-                               NormalizeFilename ( module.GetPath () ),\r
-                               true );\r
-                       OutputInstallTarget ( installDirectory,\r
-                                         sourceFilename,\r
-                                         module.installName,\r
-                                         module.installBase );\r
-               }\r
-       }\r
-}\r
-\r
-void\r
-MingwBackend::GenerateInstallTarget ()\r
-{\r
-       string installDirectoryNoFixup = "reactos";\r
-       string installDirectory = MingwModuleHandler::PassThruCacheDirectory (\r
-               NormalizeFilename ( installDirectoryNoFixup ),\r
-               true );\r
-       vector<string> vInstallTargetFiles;\r
-       GetInstallTargetFiles ( installDirectoryNoFixup,\r
-                               vInstallTargetFiles );\r
-       string installTargetFiles = v2s ( vInstallTargetFiles, 5 );\r
-\r
-       fprintf ( fMakefile,\r
-                 "install: %s %s\n",\r
-                 installDirectory.c_str (),\r
-                 installTargetFiles.c_str () );\r
-       OutputNonModuleInstallTargets ( installDirectoryNoFixup );\r
-       OutputModuleInstallTargets ( installDirectoryNoFixup );\r
-       fprintf ( fMakefile,\r
-                 "\n" );\r
-}\r
+
+#include "../../pch.h"
+
+#include "mingw.h"
+#include <assert.h>
+#include <dirent.h>
+#include "modulehandler.h"
+
+#ifdef WIN32
+#define MKDIR(s) mkdir(s)
+#else
+#define MKDIR(s) mkdir(s, 0755)
+#endif
+
+using std::string;
+using std::vector;
+using std::set;
+using std::map;
+
+typedef set<string> set_string;
+
+
+string
+v2s ( const string_list& v, int wrap_at )
+{
+       if ( !v.size() )
+               return "";
+       string s;
+       int wrap_count = 0;
+       for ( size_t i = 0; i < v.size(); i++ )
+       {
+               if ( !v[i].size() )
+                       continue;
+               if ( wrap_at > 0 && wrap_count++ == wrap_at )
+                       s += " \\\n\t\t";
+               else if ( s.size() )
+                       s += " ";
+               s += v[i];
+       }
+       return s;
+}
+
+
+Directory::Directory ( const string& name_ )
+       : name(name_)
+{
+}
+
+void
+Directory::Add ( const char* subdir )
+{
+       size_t i;
+       string s1 = string ( subdir );
+       if ( ( i = s1.find ( '$' ) ) != string::npos )
+       {
+               throw InvalidOperationException ( __FILE__,
+                                                 __LINE__,
+                                                 "No environment variables can be used here. Path was %s",
+                                                 subdir );
+       }
+
+       const char* p = strpbrk ( subdir, "/\\" );
+       if ( !p )
+               p = subdir + strlen(subdir);
+       string s ( subdir, p-subdir );
+       if ( subdirs.find(s) == subdirs.end() )
+               subdirs[s] = new Directory(s);
+       if ( *p && *++p )
+               subdirs[s]->Add ( p );
+}
+
+bool
+Directory::mkdir_p ( const char* path )
+{
+       DIR *directory;
+       directory = opendir ( path );
+       if ( directory != NULL )
+       {
+               closedir ( directory );
+               return false;
+       }
+
+       if ( MKDIR ( path ) != 0 )
+               throw AccessDeniedException ( string ( path ) );
+       return true;
+}
+
+bool
+Directory::CreateDirectory ( string path )
+{
+       size_t index = 0;
+       size_t nextIndex;
+       if ( isalpha ( path[0] ) && path[1] == ':' && path[2] == CSEP )
+       {
+               nextIndex = path.find ( CSEP, 3);
+       }
+       else
+               nextIndex = path.find ( CSEP );
+
+       bool directoryWasCreated = false;
+       while ( nextIndex != string::npos )
+       {
+               nextIndex = path.find ( CSEP, index + 1 );
+               directoryWasCreated = mkdir_p ( path.substr ( 0, nextIndex ).c_str () );
+               index = nextIndex;
+       }
+       return directoryWasCreated;
+}
+
+string
+Directory::ReplaceVariable ( string name,
+                             string value,
+                             string path )
+{
+       size_t i = path.find ( name );
+       if ( i != string::npos )
+               return path.replace ( i, name.length (), value );
+       else
+               return path;
+}
+
+void
+Directory::ResolveVariablesInPath ( char* buf,
+                                    string path )
+{
+       string s = ReplaceVariable ( "$(INTERMEDIATE)", Environment::GetIntermediatePath (), path );
+       s = ReplaceVariable ( "$(OUTPUT)", Environment::GetOutputPath (), s );
+       s = ReplaceVariable ( "$(INSTALL)", Environment::GetInstallPath (), s );
+       strcpy ( buf, s.c_str () );
+}
+
+void
+Directory::GenerateTree ( const string& parent,
+                          bool verbose )
+{
+       string path;
+
+       if ( parent.size () > 0 )
+       {
+               char buf[256];
+               
+               path = parent + SSEP + name;
+               ResolveVariablesInPath ( buf, path );
+               if ( CreateDirectory ( buf ) && verbose )
+                       printf ( "Created %s\n", buf );
+       }
+       else
+               path = name;
+
+       for ( directory_map::iterator i = subdirs.begin ();
+               i != subdirs.end ();
+               ++i )
+       {
+               i->second->GenerateTree ( path, verbose );
+       }
+}
+
+string
+Directory::EscapeSpaces ( string path )
+{
+       string newpath;
+       char* p = &path[0];
+       while ( *p != 0 )
+       {
+               if ( *p == ' ' )
+                       newpath = newpath + "\\ ";
+               else
+                       newpath = newpath + *p;
+               *p++;
+       }
+       return newpath;
+}
+
+void
+Directory::CreateRule ( FILE* f,
+                        const string& parent )
+{
+       string path;
+
+       if ( parent.size() > 0 )
+       {
+               string escapedParent = EscapeSpaces ( parent );
+               fprintf ( f,
+                       "%s%c%s: | %s\n",
+                       escapedParent.c_str (),
+                       CSEP,
+                       EscapeSpaces ( name ).c_str (),
+                       escapedParent.c_str () );
+
+               fprintf ( f,
+                       "\t$(ECHO_MKDIR)\n" );
+
+               fprintf ( f,
+                       "\t${mkdir} $@\n" );
+
+               path = parent + SSEP + name;
+       }
+       else
+               path = name;
+
+       for ( directory_map::iterator i = subdirs.begin();
+               i != subdirs.end();
+               ++i )
+       {
+               i->second->CreateRule ( f, path );
+       }
+}
+
+
+static class MingwFactory : public Backend::Factory
+{
+public:
+       MingwFactory() : Factory ( "mingw" ) {}
+       Backend* operator() ( Project& project,
+                             Configuration& configuration )
+       {
+               return new MingwBackend ( project,
+                                         configuration );
+       }
+} factory;
+
+
+MingwBackend::MingwBackend ( Project& project,
+                             Configuration& configuration )
+       : Backend ( project, configuration ),
+         intermediateDirectory ( new Directory ("$(INTERMEDIATE)" ) ),
+         outputDirectory ( new Directory ( "$(OUTPUT)" ) ),
+         installDirectory ( new Directory ( "$(INSTALL)" ) )
+{
+       compilerPrefix = "";
+}
+
+MingwBackend::~MingwBackend()
+{
+       delete intermediateDirectory;
+       delete outputDirectory;
+       delete installDirectory;
+}
+
+string
+MingwBackend::AddDirectoryTarget ( const string& directory,
+                                   Directory* directoryTree )
+{
+       if ( directory.length () > 0)
+               directoryTree->Add ( directory.c_str() );
+       return directoryTree->name;
+}
+
+void
+MingwBackend::ProcessModules ()
+{
+       printf ( "Processing modules..." );
+
+       vector<MingwModuleHandler*> v;
+       size_t i;
+       for ( i = 0; i < ProjectNode.modules.size (); i++ )
+       {
+               Module& module = *ProjectNode.modules[i];
+               if ( !module.enabled )
+                       continue;
+               MingwModuleHandler* h = MingwModuleHandler::InstanciateHandler (
+                       module,
+                       this );
+               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]->GenerateObjectMacro();
+       fprintf ( fMakefile, "\n" );
+       for ( i = 0; i < iend; i++ )
+               v[i]->GenerateTargetMacro();
+       fprintf ( fMakefile, "\n" );
+
+       GenerateAllTarget ( v );
+       GenerateInitTarget ();
+       GenerateRegTestsRunTarget ();
+
+       for ( i = 0; i < iend; i++ )
+               v[i]->GenerateOtherMacros();
+
+       for ( i = 0; i < iend; i++ )
+       {
+               MingwModuleHandler& h = *v[i];
+               h.GeneratePreconditionDependencies ();
+               h.Process ();
+               h.GenerateInvocations ();
+               h.GenerateCleanTarget ();
+               h.GenerateInstallTarget ();
+               h.GenerateDependsTarget ();
+               delete v[i];
+       }
+
+       printf ( "done\n" );
+}
+
+void
+MingwBackend::Process ()
+{
+       if ( configuration.CheckDependenciesForModuleOnly )
+               CheckAutomaticDependenciesForModuleOnly ();
+       else
+               ProcessNormal ();
+}
+
+void
+MingwBackend::CheckAutomaticDependenciesForModuleOnly ()
+{
+       if ( configuration.AutomaticDependencies )
+       {
+               Module* module = ProjectNode.LocateModule ( configuration.CheckDependenciesForModuleOnlyModule );
+               if ( module == NULL )
+               {
+                       printf ( "Module '%s' does not exist\n",
+                               configuration.CheckDependenciesForModuleOnlyModule.c_str () );
+                       return;
+               }
+               
+               printf ( "Checking automatic dependencies for module '%s'...",
+                        module->name.c_str () );
+               AutomaticDependency automaticDependency ( ProjectNode );
+               automaticDependency.CheckAutomaticDependencies ( *module,
+                                                                configuration.Verbose );
+               printf ( "done\n" );
+       }
+}
+
+void
+MingwBackend::ProcessNormal ()
+{
+       DetectCompiler ();
+       DetectNetwideAssembler ();
+       DetectPipeSupport ();
+       DetectPCHSupport ();
+       CreateMakefile ();
+       GenerateHeader ();
+       GenerateGlobalVariables ();
+       GenerateXmlBuildFilesMacro ();
+       ProcessModules ();
+       GenerateInstallTarget ();
+       GenerateTestTarget ();
+       GenerateDirectoryTargets ();
+       GenerateDirectories ();
+       UnpackWineResources ();
+       GenerateTestSupportCode ();
+       GenerateProxyMakefiles ();
+       CheckAutomaticDependencies ();
+       CloseMakefile ();
+}
+
+void
+MingwBackend::CreateMakefile ()
+{
+       fMakefile = fopen ( ProjectNode.makefile.c_str (), "w" );
+       if ( !fMakefile )
+               throw AccessDeniedException ( ProjectNode.makefile );
+       MingwModuleHandler::SetBackend ( this );
+       MingwModuleHandler::SetMakefile ( fMakefile );
+       MingwModuleHandler::SetUsePch ( use_pch );
+}
+
+void
+MingwBackend::CloseMakefile () const
+{
+       if (fMakefile)
+               fclose ( fMakefile );
+}
+
+void
+MingwBackend::GenerateHeader () const
+{
+       fprintf ( fMakefile, "# THIS FILE IS AUTOMATICALLY GENERATED, EDIT 'ReactOS.xml' INSTEAD\n\n" );
+}
+
+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 (
+       const char* assignmentOperation,
+       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() )
+       {
+               GenerateProjectCFlagsMacro ( assignmentOperation,
+                                            data );
+       }
+
+       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() )
+               {
+                       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" );
+               }
+       }
+}
+
+string
+MingwBackend::GenerateProjectLFLAGS () const
+{
+       string lflags;
+       for ( size_t i = 0; i < ProjectNode.linkerFlags.size (); i++ )
+       {
+               LinkerFlag& linkerFlag = *ProjectNode.linkerFlags[i];
+               if ( lflags.length () > 0 )
+                       lflags += " ";
+               lflags += linkerFlag.flag;
+       }
+       return lflags;
+}
+
+void
+MingwBackend::GenerateGlobalVariables () const
+{
+       fprintf ( fMakefile,
+                 "PREFIX := %s\n",
+                 compilerPrefix.c_str () );
+       fprintf ( fMakefile,
+                 "nasm := %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, "PROJECT_CFLAGS += $(PROJECT_GCCOPTIONS)\n" );
+       fprintf ( fMakefile, "\n" );
+}
+
+bool
+MingwBackend::IncludeInAllTarget ( const Module& module ) const
+{
+       if ( MingwModuleHandler::ReferenceObjects ( module ) )
+               return false;
+       if ( module.type == BootSector )
+               return false;
+       if ( module.type == Iso )
+               return false;
+       if ( module.type == LiveIso )
+               return false;
+       if ( module.type == Test )
+               return false;
+       return true;
+}
+
+void
+MingwBackend::GenerateAllTarget ( const vector<MingwModuleHandler*>& handlers ) const
+{
+       fprintf ( fMakefile, "all:" );
+       int wrap_count = 0;
+       size_t iend = handlers.size ();
+       for ( size_t i = 0; i < iend; i++ )
+       {
+               const Module& module = handlers[i]->module;
+               if ( IncludeInAllTarget ( module ) )
+               {
+                       if ( wrap_count++ == 5 )
+                               fprintf ( fMakefile, " \\\n\t\t" ), wrap_count = 0;
+                       fprintf ( fMakefile,
+                                 " %s",
+                                 GetTargetMacro(module).c_str () );
+               }
+       }
+       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
+{
+       fprintf ( fMakefile,
+                 "REGTESTS_RUN_TARGET = regtests.dll\n" );
+       fprintf ( fMakefile,
+                 "$(REGTESTS_RUN_TARGET): $(REGTESTS_TARGET)\n" );
+       fprintf ( fMakefile,
+                 "\t$(cp) $(REGTESTS_TARGET) $(REGTESTS_RUN_TARGET)\n" );
+       fprintf ( fMakefile, "\n" );
+}
+
+void
+MingwBackend::GenerateXmlBuildFilesMacro() const
+{
+       fprintf ( fMakefile,
+                 "XMLBUILDFILES = %s \\\n",
+                 ProjectNode.GetProjectFilename ().c_str () );
+       string xmlbuildFilenames;
+       int numberOfExistingFiles = 0;
+       for ( size_t i = 0; i < ProjectNode.xmlbuildfiles.size (); i++ )
+       {
+               XMLInclude& xmlbuildfile = *ProjectNode.xmlbuildfiles[i];
+               if ( !xmlbuildfile.fileExists )
+                       continue;
+               numberOfExistingFiles++;
+               if ( xmlbuildFilenames.length () > 0 )
+                       xmlbuildFilenames += " ";
+               xmlbuildFilenames += NormalizeFilename ( xmlbuildfile.topIncludeFilename );
+               if ( numberOfExistingFiles % 5 == 4 || i == ProjectNode.xmlbuildfiles.size () - 1 )
+               {
+                       fprintf ( fMakefile,
+                                 "\t%s",
+                                 xmlbuildFilenames.c_str ());
+                       if ( i == ProjectNode.xmlbuildfiles.size () - 1 )
+                       {
+                               fprintf ( fMakefile, "\n" );
+                       }
+                       else
+                       {
+                               fprintf ( fMakefile,
+                                         " \\\n" );
+                       }
+                       xmlbuildFilenames.resize ( 0 );
+               }
+               numberOfExistingFiles++;
+       }
+       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 ()
+{
+       printf ( "Generating test support code..." );
+       TestSupportCode testSupportCode ( ProjectNode );
+       testSupportCode.GenerateTestSupportCode ( configuration.Verbose );
+       printf ( "done\n" );
+}
+
+string
+MingwBackend::GetProxyMakefileTree () const
+{
+       if ( configuration.GenerateProxyMakefilesInSourceTree )
+               return "";
+       else
+               return Environment::GetOutputPath ();
+}
+
+void
+MingwBackend::GenerateProxyMakefiles ()
+{
+       printf ( "Generating proxy makefiles..." );
+       ProxyMakefile proxyMakefile ( ProjectNode );
+       proxyMakefile.GenerateProxyMakefiles ( configuration.Verbose,
+                                              GetProxyMakefileTree () );
+       printf ( "done\n" );
+}
+
+void
+MingwBackend::CheckAutomaticDependencies ()
+{
+       if ( configuration.AutomaticDependencies )
+       {
+               printf ( "Checking automatic dependencies..." );
+               AutomaticDependency automaticDependency ( ProjectNode );
+               automaticDependency.CheckAutomaticDependencies ( configuration.Verbose );
+               printf ( "done\n" );
+       }
+}
+
+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 );
+       if ( !configuration.MakeHandlesInstallDirectories )
+               installDirectory->GenerateTree ( "", configuration.Verbose );
+       printf ( "done\n" );
+}
+
+bool
+MingwBackend::TryToDetectThisCompiler ( const string& compiler )
+{
+       string command = ssprintf (
+               "%s -v 1>%s 2>%s",
+               compiler.c_str (),
+               NUL,
+               NUL );
+       int exitcode = system ( command.c_str () );
+       return (exitcode == 0);
+}
+
+void
+MingwBackend::DetectCompiler ()
+{
+       printf ( "Detecting compiler..." );
+
+       bool detectedCompiler = false;
+       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 );
+       }
+#endif
+       if ( !detectedCompiler )
+       {
+               compilerPrefix = "mingw32";
+               compilerCommand = compilerPrefix + "-gcc";
+               detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
+       }
+       if ( detectedCompiler )
+               printf ( "detected (%s)\n", compilerCommand.c_str () );
+       else
+               printf ( "not detected\n" );
+}
+
+bool
+MingwBackend::TryToDetectThisNetwideAssembler ( const string& assembler )
+{
+       string command = ssprintf (
+               "%s -h 1>%s 2>%s",
+               assembler.c_str (),
+               NUL,
+               NUL );
+       int exitcode = system ( command.c_str () );
+       return (exitcode == 0);
+}
+
+void
+MingwBackend::DetectNetwideAssembler ()
+{
+       printf ( "Detecting netwide assembler..." );
+
+       nasmCommand = "nasm";
+       bool detectedNasm = TryToDetectThisNetwideAssembler ( nasmCommand );
+#if defined(WIN32)
+       if ( !detectedNasm )
+       {
+               nasmCommand = "nasmw";
+               detectedNasm = TryToDetectThisNetwideAssembler ( nasmCommand );
+       }
+#endif
+       if ( detectedNasm )
+               printf ( "detected (%s)\n", nasmCommand.c_str () );
+       else
+               printf ( "not detected\n" );
+}
+
+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",
+               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" );
+}
+
+void
+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",
+               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" );
+}
+
+void
+MingwBackend::GetNonModuleInstallTargetFiles (
+       vector<string>& out ) const
+{
+       for ( size_t i = 0; i < ProjectNode.installfiles.size (); i++ )
+       {
+               const InstallFile& installfile = *ProjectNode.installfiles[i];
+               string targetFilenameNoFixup = installfile.base + SSEP + installfile.newname;
+               string targetFilename = MingwModuleHandler::PassThruCacheDirectory (
+                       NormalizeFilename ( targetFilenameNoFixup ),
+                       installDirectory );
+               out.push_back ( targetFilename );
+       }
+}
+
+void
+MingwBackend::GetModuleInstallTargetFiles (
+       vector<string>& out ) const
+{
+       for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
+       {
+               const Module& module = *ProjectNode.modules[i];
+               if ( !module.enabled )
+                       continue;
+               if ( module.installName.length () > 0 )
+               {
+                       string targetFilenameNoFixup;
+                       if ( module.installBase.length () > 0 )
+                               targetFilenameNoFixup = module.installBase + SSEP + module.installName;
+                       else
+                               targetFilenameNoFixup = module.installName;
+                       string targetFilename = MingwModuleHandler::PassThruCacheDirectory (
+                               NormalizeFilename ( targetFilenameNoFixup ),
+                               installDirectory );
+                       out.push_back ( targetFilename );
+               }
+       }
+}
+
+void
+MingwBackend::GetInstallTargetFiles (
+       vector<string>& out ) const
+{
+       GetNonModuleInstallTargetFiles ( out );
+       GetModuleInstallTargetFiles ( out );
+}
+
+void
+MingwBackend::OutputInstallTarget ( const string& sourceFilename,
+                                   const string& targetFilename,
+                                   const string& targetDirectory )
+{
+       string fullTargetFilename;
+       if ( targetDirectory.length () > 0)
+               fullTargetFilename = targetDirectory + SSEP + targetFilename;
+       else
+               fullTargetFilename = targetFilename;
+       string normalizedTargetFilename = MingwModuleHandler::PassThruCacheDirectory (
+               NormalizeFilename ( fullTargetFilename ),
+               installDirectory );
+       string normalizedTargetDirectory = MingwModuleHandler::PassThruCacheDirectory (
+               NormalizeFilename ( targetDirectory ),
+               installDirectory );
+       fprintf ( fMakefile,
+                 "%s: %s | %s\n",
+                 normalizedTargetFilename.c_str (),
+                 sourceFilename.c_str (),
+                 normalizedTargetDirectory.c_str () );
+       fprintf ( fMakefile,
+                 "\t$(ECHO_CP)\n" );
+       fprintf ( fMakefile,
+                 "\t${cp} %s %s 1>$(NUL)\n",
+                 sourceFilename.c_str (),
+                 normalizedTargetFilename.c_str () );
+}
+
+void
+MingwBackend::OutputNonModuleInstallTargets ()
+{
+       for ( size_t i = 0; i < ProjectNode.installfiles.size (); i++ )
+       {
+               const InstallFile& installfile = *ProjectNode.installfiles[i];
+               OutputInstallTarget ( installfile.GetPath (),
+                                     installfile.newname,
+                                     installfile.base );
+       }
+}
+
+void
+MingwBackend::OutputModuleInstallTargets ()
+{
+       for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
+       {
+               const Module& module = *ProjectNode.modules[i];
+               if ( !module.enabled )
+                       continue;
+               if ( module.installName.length () > 0 )
+               {
+                       string sourceFilename = MingwModuleHandler::PassThruCacheDirectory (
+                               NormalizeFilename ( module.GetPath () ),
+                               outputDirectory );
+                       OutputInstallTarget ( sourceFilename,
+                                             module.installName,
+                                             module.installBase );
+               }
+       }
+}
+
+string
+MingwBackend::GetRegistrySourceFiles ()
+{
+       return "bootdata" SSEP "hivecls.inf "
+               "bootdata" SSEP "hivedef.inf "
+               "bootdata" SSEP "hiveinst.inf "
+               "bootdata" SSEP "hivesft.inf "
+               "bootdata" SSEP "hivesys.inf";
+}
+
+string
+MingwBackend::GetRegistryTargetFiles ()
+{
+       string system32ConfigDirectory = NormalizeFilename (
+               MingwModuleHandler::PassThruCacheDirectory (
+               "system32" SSEP "config" SSEP,
+               installDirectory ) );
+       return system32ConfigDirectory + SSEP "default " +
+               system32ConfigDirectory + SSEP "sam " +
+               system32ConfigDirectory + SSEP "security " +
+               system32ConfigDirectory + SSEP "software " +
+               system32ConfigDirectory + SSEP "system";
+}
+
+void
+MingwBackend::OutputRegistryInstallTarget ()
+{
+       string system32ConfigDirectory = NormalizeFilename (
+               MingwModuleHandler::PassThruCacheDirectory (
+               "system32" SSEP "config" SSEP,
+               installDirectory ) );
+
+       string registrySourceFiles = GetRegistrySourceFiles ();
+       string registryTargetFiles = GetRegistryTargetFiles ();
+       fprintf ( fMakefile,
+                 "install_registry: %s\n",
+                 registryTargetFiles.c_str () );
+       fprintf ( fMakefile,
+                 "%s: %s %s $(MKHIVE_TARGET)\n",
+                 registryTargetFiles.c_str (),
+                 registrySourceFiles.c_str (),
+                 system32ConfigDirectory.c_str () );
+       fprintf ( fMakefile,
+                 "\t$(ECHO_MKHIVE)\n" );
+       fprintf ( fMakefile,
+                 "\t$(MKHIVE_TARGET) bootdata %s bootdata" SSEP "hiveinst.inf\n",
+                 system32ConfigDirectory.c_str () );
+       fprintf ( fMakefile,
+                 "\n" );
+}
+
+void
+MingwBackend::GenerateInstallTarget ()
+{
+       vector<string> vInstallTargetFiles;
+       GetInstallTargetFiles ( vInstallTargetFiles );
+       string installTargetFiles = v2s ( vInstallTargetFiles, 5 );
+       string registryTargetFiles = GetRegistryTargetFiles ();
+
+       fprintf ( fMakefile,
+                 "install: %s %s\n",
+                 installTargetFiles.c_str (),
+                 registryTargetFiles.c_str () );
+       OutputNonModuleInstallTargets ();
+       OutputModuleInstallTargets ();
+       OutputRegistryInstallTarget ();
+       fprintf ( fMakefile,
+                 "\n" );
+}
+
+void
+MingwBackend::GetModuleTestTargets (
+       vector<string>& out ) const
+{
+       for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
+       {
+               const Module& module = *ProjectNode.modules[i];
+               if ( !module.enabled )
+                       continue;
+               if ( module.type == Test )
+                       out.push_back ( module.name );
+       }
+}
+
+void
+MingwBackend::GenerateTestTarget ()
+{
+       vector<string> vTestTargets;
+       GetModuleTestTargets ( vTestTargets );
+       string testTargets = v2s ( vTestTargets, 5 );
+
+       fprintf ( fMakefile,
+                 "test: %s\n",
+                 testTargets.c_str () );
+       fprintf ( fMakefile,
+                 "\n" );
+}
+
+void
+MingwBackend::GenerateDirectoryTargets ()
+{
+       intermediateDirectory->CreateRule ( fMakefile, "" );
+       outputDirectory->CreateRule ( fMakefile, "" );
+       installDirectory->CreateRule ( fMakefile, "" );
+}