Let dependencies control 'make install'
[reactos.git] / reactos / tools / rbuild / backend / mingw / mingw.cpp
index 56b43f0..b8d43ce 100644 (file)
 #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
-#ifdef WIN32\r
-#define EXEPOSTFIX ".exe"\r
-#define SEP "\\"\r
-string FixSep ( const string& s )\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
-       string s2(s);\r
-       char* p = strchr ( &s2[0], '/' );\r
-       while ( p )\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
-               *p++ = '\\';\r
-               p = strchr ( p, '/' );\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 s2;\r
+       return s;\r
 }\r
-#else\r
-#define EXEPOSTFIX\r
-#define SEP "/"\r
-string FixSep ( const string& s )\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
-       string s2(s);\r
-       char* p = strchr ( &s2[0], '\\' );\r
-       while ( p )\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
-               *p++ = '/';\r
-               p = strchr ( p, '\\' );\r
+               throw InvalidOperationException ( __FILE__,\r
+                                                 __LINE__,\r
+                                                 "No environment variables can be used here. Path was %s",\r
+                                                 subdir );\r
        }\r
-       return s2;\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
-#endif\r
 \r
-MingwBackend::MingwBackend ( Project& project )\r
-       : Backend ( project )\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
-void MingwBackend::Process ()\r
+bool\r
+Directory::CreateDirectory ( string path )\r
 {\r
-       CreateMakefile ();\r
-       GenerateHeader ();\r
-       GenerateAllTarget ();\r
-       for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )\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
-               ProcessModule ( module );\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 MingwBackend::CreateMakefile ()\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 MingwBackend::CloseMakefile ()\r
+void\r
+MingwBackend::CloseMakefile () const\r
 {\r
        if (fMakefile)\r
                fclose ( fMakefile );\r
 }\r
 \r
-void MingwBackend::GenerateHeader ()\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 MingwBackend::GenerateAllTarget ()\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
-       fprintf ( fMakefile, "all: " );\r
+       string dependencies;\r
        for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )\r
        {\r
                Module& module = *ProjectNode.modules[i];\r
-               fprintf ( fMakefile,\r
-                         " %s" SEP "%s" EXEPOSTFIX,\r
-                         FixSep(module.path).c_str (),\r
-                         module.name.c_str () );\r
+               if ( module.type == BuildTool )\r
+               {\r
+                       if ( dependencies.length () > 0 )\r
+                               dependencies += " ";\r
+                       dependencies += module.GetDependencyPath ();\r
+               }\r
        }\r
-       fprintf ( fMakefile, "\n\n" );\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 MingwBackend::ProcessModule ( Module& module )\r
+void\r
+MingwBackend::GenerateXmlBuildFilesMacro() const\r
 {\r
-       MingwModuleHandlerList moduleHandlers;\r
-       GetModuleHandlers ( moduleHandlers );\r
-       for (size_t i = 0; i < moduleHandlers.size (); i++)\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
-               MingwModuleHandler& moduleHandler = *moduleHandlers[i];\r
-               if (moduleHandler.CanHandleModule ( module ) )\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
-                       moduleHandler.Process ( module );\r
-                       return;\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
+string\r
+MingwBackend::GetNonModuleInstallDirectories ( const string& installDirectory )\r
+{\r
+       string directories;\r
+       for ( size_t i = 0; i < ProjectNode.installfiles.size (); i++ )\r
+       {\r
+               const InstallFile& installfile = *ProjectNode.installfiles[i];\r
+               string targetDirectory ( installDirectory + SSEP + installfile.base );\r
+               if ( directories.size () > 0 )\r
+                       directories += " ";\r
+               directories += MingwModuleHandler::PassThruCacheDirectory (\r
+                       FixupTargetFilename ( targetDirectory ),\r
+                       true );\r
+       }\r
+       return directories;\r
+}\r
+\r
+string\r
+MingwBackend::GetInstallDirectories ( const string& installDirectory )\r
+{\r
+       return GetNonModuleInstallDirectories ( installDirectory );\r
+}\r
+\r
+void\r
+MingwBackend::GetNonModuleInstallFiles (\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
+               out.push_back ( NormalizeFilename ( installfile.GetPath () ) );\r
+       }\r
+}\r
+\r
+void\r
+MingwBackend::GetInstallFiles (\r
+       vector<string>& out ) const\r
+{\r
+       GetNonModuleInstallFiles ( out );\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
+                       FixupTargetFilename ( targetFilenameNoFixup ),\r
+                       true );\r
+               out.push_back ( targetFilename );\r
        }\r
 }\r
 \r
-void MingwBackend::GetModuleHandlers ( MingwModuleHandlerList& moduleHandlers )\r
+void\r
+MingwBackend::GetInstallTargetFiles (\r
+       string installDirectory,\r
+       vector<string>& out ) const\r
 {\r
-       moduleHandlers.push_back ( new MingwKernelModuleHandler ( fMakefile ) );\r
+       GetNonModuleInstallTargetFiles ( installDirectory,\r
+                                        out );\r
+}\r
+\r
+void\r
+MingwBackend::OutputInstallfileTargets ( const string& installDirectory )\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
+                       FixupTargetFilename ( targetFilenameNoFixup ),\r
+                       true );\r
+               string targetDirectory = MingwModuleHandler::PassThruCacheDirectory (\r
+                       FixupTargetFilename ( installDirectory + SSEP + installfile.base ),\r
+                       true );\r
+               fprintf ( fMakefile,\r
+                         "%s: %s %s\n",\r
+                         targetFilename.c_str (),\r
+                         installfile.GetPath ().c_str (),\r
+                         targetDirectory.c_str () );\r
+               fprintf ( fMakefile,\r
+                         "\t$(ECHO_CP)\n" );\r
+               fprintf ( fMakefile,\r
+                         "\t${cp} %s %s\n",\r
+                         installfile.GetPath ().c_str (),\r
+                         targetFilename.c_str () );\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
+       OutputInstallfileTargets ( installDirectoryNoFixup );\r
+       fprintf ( fMakefile,\r
+                 "\n" );\r
 }\r