Let dependencies control 'make install'
[reactos.git] / reactos / tools / rbuild / backend / mingw / mingw.cpp
index b16197a..b8d43ce 100644 (file)
@@ -20,6 +20,28 @@ using std::map;
 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
@@ -27,7 +49,8 @@ public:
        directory_map subdirs;\r
        Directory ( const string& name );\r
        void Add ( const char* subdir );\r
-       void GenerateTree ( const string& parent );\r
+       void GenerateTree ( const string& parent,\r
+                           bool verbose );\r
 private:\r
        bool mkdir_p ( const char* path );\r
        string ReplaceVariable ( string name,\r
@@ -139,7 +162,8 @@ Directory::ResolveVariablesInPath ( char* buf,
 }\r
 \r
 void\r
-Directory::GenerateTree ( const string& parent )\r
+Directory::GenerateTree ( const string& parent,\r
+                             bool verbose )\r
 {\r
        string path;\r
 \r
@@ -149,7 +173,7 @@ Directory::GenerateTree ( const string& parent )
                \r
                path = parent + SSEP + name;\r
                ResolveVariablesInPath ( buf, path );\r
-               if ( CreateDirectory ( buf ) )\r
+               if ( CreateDirectory ( buf ) && verbose )\r
                        printf ( "Created %s\n", buf );\r
        }\r
        else\r
@@ -159,7 +183,7 @@ Directory::GenerateTree ( const string& parent )
                i != subdirs.end();\r
                ++i )\r
        {\r
-               i->second->GenerateTree ( path );\r
+               i->second->GenerateTree ( path, verbose );\r
        }\r
 }\r
 \r
@@ -167,15 +191,15 @@ static class MingwFactory : public Backend::Factory
 {\r
 public:\r
        MingwFactory() : Factory ( "mingw" ) {}\r
-       Backend* operator() ( Project& project )\r
+       Backend* operator() ( Project& project, bool verbose )\r
        {\r
-               return new MingwBackend ( project );\r
+               return new MingwBackend ( project, verbose );\r
        }\r
 } factory;\r
 \r
 \r
-MingwBackend::MingwBackend ( Project& project )\r
-       : Backend ( project ),\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
@@ -202,19 +226,12 @@ MingwBackend::AddDirectoryTarget ( const string& directory, bool out )
 }\r
 \r
 void\r
-MingwBackend::Process ()\r
+MingwBackend::ProcessModules ()\r
 {\r
-       size_t i;\r
-\r
-       DetectPCHSupport();\r
-\r
-       CreateMakefile ();\r
-       GenerateHeader ();\r
-       GenerateGlobalVariables ();\r
-       GenerateXmlBuildFilesMacro();\r
+       printf ( "Processing modules..." );\r
 \r
        vector<MingwModuleHandler*> v;\r
-\r
+       size_t i;\r
        for ( i = 0; i < ProjectNode.modules.size (); i++ )\r
        {\r
                Module& module = *ProjectNode.modules[i];\r
@@ -254,6 +271,20 @@ MingwBackend::Process ()
                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
@@ -487,9 +518,11 @@ MingwBackend::GenerateXmlBuildFilesMacro() const
 void\r
 MingwBackend::CheckAutomaticDependencies ()\r
 {\r
+       printf ( "Checking automatic dependencies..." );\r
        AutomaticDependency automaticDependency ( ProjectNode );\r
        automaticDependency.Process ();\r
-       automaticDependency.CheckAutomaticDependencies ();\r
+       automaticDependency.CheckAutomaticDependencies ( verbose );\r
+       printf ( "done\n" );\r
 }\r
 \r
 bool\r
@@ -504,8 +537,10 @@ MingwBackend::IncludeDirectoryTarget ( const string& directory ) const
 void\r
 MingwBackend::GenerateDirectories ()\r
 {\r
-       int_directories->GenerateTree ( "" );\r
-       out_directories->GenerateTree ( "" );\r
+       printf ( "Creating directories..." );\r
+       int_directories->GenerateTree ( "", verbose );\r
+       out_directories->GenerateTree ( "", verbose );\r
+       printf ( "done\n" );\r
 }\r
 \r
 string\r
@@ -515,31 +550,180 @@ FixupTargetFilename ( const string& targetFilename )
 }\r
 \r
 void\r
-MingwBackend::DetectPCHSupport()\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
-#ifdef WIN32\r
-       string sNUL = "NUL";\r
-#else\r
-       string sNUL = "/dev/null";\r
-#endif\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
+       string cmd = ssprintf (\r
                "gcc -c %s 2>%s",\r
                path.c_str (),\r
-               sNUL.c_str () );\r
-       system ( cmd.c_str() );\r
+               NUL );\r
+       system ( cmd.c_str () );\r
        path += ".gch";\r
 \r
-       FILE* f = fopen ( path.c_str(), "rb" );\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
+               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\r
+MingwBackend::GetInstallTargetFiles (\r
+       string installDirectory,\r
+       vector<string>& out ) const\r
+{\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