adjust newlines around rsym command
[reactos.git] / reactos / tools / rbuild / backend / mingw / mingw.cpp
index 83d999e..27d0245 100644 (file)
 #include "../../pch.h"\r
 \r
 #include "mingw.h"\r
+#include <assert.h>\r
 \r
 using std::string;\r
 using std::vector;\r
 \r
-#ifdef WIN32\r
-#define EXEPOSTFIX ".exe"\r
-#define SEP "\\"\r
-string FixSep ( const string& s )\r
+static class MingwFactory : public Backend::Factory\r
 {\r
-       string s2(s);\r
-       char* p = strchr ( &s2[0], '/' );\r
-       while ( p )\r
+public:\r
+       MingwFactory() : Factory ( "mingw" ) {}\r
+       Backend* operator() ( Project& project )\r
        {\r
-               *p++ = '\\';\r
-               p = strchr ( p, '/' );\r
+               return new MingwBackend ( project );\r
        }\r
-       return s2;\r
-}\r
-#else\r
-#define EXEPOSTFIX\r
-#define SEP "/"\r
-string FixSep ( const string& s )\r
-{\r
-       string s2(s);\r
-       char* p = strchr ( &s2[0], '\\' );\r
-       while ( p )\r
-       {\r
-               *p++ = '/';\r
-               p = strchr ( p, '\\' );\r
-       }\r
-       return s2;\r
-}\r
-#endif\r
+} factory;\r
+\r
 \r
 MingwBackend::MingwBackend ( Project& project )\r
        : Backend ( project )\r
 {\r
 }\r
 \r
-void MingwBackend::Process ()\r
+void\r
+MingwBackend::Process ()\r
 {\r
+       DetectPCHSupport();\r
+\r
        CreateMakefile ();\r
        GenerateHeader ();\r
+       GenerateGlobalVariables ();\r
        GenerateAllTarget ();\r
+       GenerateInitTarget ();\r
+       GenerateXmlBuildFilesMacro();\r
        for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )\r
        {\r
                Module& module = *ProjectNode.modules[i];\r
                ProcessModule ( module );\r
        }\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::SetMakefile ( fMakefile );\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
+                                           const vector<Include*>& includes,\r
+                                           const vector<Define*>& defines ) const\r
+{\r
+       size_t i;\r
+\r
+       fprintf (\r
+               fMakefile,\r
+               "PROJECT_CFLAGS %s",\r
+               assignmentOperation );\r
+       for ( i = 0; i < includes.size(); i++ )\r
+       {\r
+               fprintf (\r
+                       fMakefile,\r
+                       " -I%s",\r
+                       includes[i]->directory.c_str() );\r
+       }\r
+\r
+       for ( i = 0; i < defines.size(); i++ )\r
+       {\r
+               Define& d = *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
+       const vector<Property*>& properties,\r
+       const vector<Include*>& includes,\r
+       const vector<Define*>& defines,\r
+       const vector<If*>& ifs ) const\r
+{\r
+       size_t i;\r
+\r
+       for ( i = 0; i < properties.size(); i++ )\r
+       {\r
+               Property& prop = *properties[i];\r
+               fprintf ( fMakefile, "%s := %s\n",\r
+                       prop.name.c_str(),\r
+                       prop.value.c_str() );\r
+       }\r
+\r
+       if ( includes.size() || defines.size() )\r
+       {\r
+               GenerateProjectCFlagsMacro ( assignmentOperation,\r
+                                     includes,\r
+                                     defines );\r
+       }\r
+\r
+       for ( i = 0; i < ifs.size(); i++ )\r
+       {\r
+               If& rIf = *ifs[i];\r
+               if ( rIf.defines.size() || rIf.includes.size() || rIf.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.properties,\r
+                               rIf.includes,\r
+                               rIf.defines,\r
+                               rIf.ifs );\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
-       fprintf ( fMakefile, "all: " );\r
+       fprintf ( fMakefile, "mkdir = tools" SSEP "rmkdir" EXEPOSTFIX "\n" );\r
+       fprintf ( fMakefile, "winebuild = tools" SSEP "winebuild" SSEP "winebuild" EXEPOSTFIX "\n" );\r
+       fprintf ( fMakefile, "bin2res = tools" SSEP "bin2res" SSEP "bin2res" EXEPOSTFIX "\n" );\r
+       fprintf ( fMakefile, "cabman = tools" SSEP "cabman" SSEP "cabman" EXEPOSTFIX "\n" );\r
+       fprintf ( fMakefile, "cdmake = tools" SSEP "cdmake" SSEP "cdmake" EXEPOSTFIX "\n" );\r
+       fprintf ( fMakefile, "rsym = tools" SSEP "rsym" EXEPOSTFIX "\n" );\r
+       fprintf ( fMakefile, "wrc = tools" SSEP "wrc" SSEP "wrc" EXEPOSTFIX "\n" );\r
+       fprintf ( fMakefile, "\n" );\r
+       GenerateGlobalCFlagsAndProperties (\r
+               "=",\r
+               ProjectNode.properties,\r
+               ProjectNode.includes,\r
+               ProjectNode.defines,\r
+               ProjectNode.ifs );\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\r
+{\r
+       fprintf ( fMakefile, "all:" );\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 ( IncludeInAllTarget ( module ) )\r
+               {\r
+                       fprintf ( fMakefile,\r
+                                 " %s",\r
+                                 FixupTargetFilename ( module.GetPath () ).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
-       fprintf ( fMakefile, "\n\n" );\r
+       return dependencies;\r
 }\r
 \r
-void MingwBackend::ProcessModule ( Module& module )\r
+void\r
+MingwBackend::GenerateInitTarget () const\r
 {\r
-       MingwModuleHandlerList moduleHandlers;\r
-       GetModuleHandlers ( moduleHandlers );\r
-       for (size_t i = 0; i < moduleHandlers.size (); i++)\r
+       fprintf ( fMakefile,\r
+                 "init:");\r
+       fprintf ( fMakefile,\r
+                 " $(ROS_INTERMEDIATE)." SSEP "tools" );\r
+       fprintf ( fMakefile,\r
+                 " %s",\r
+                 GetBuildToolDependencies ().c_str () );\r
+       fprintf ( fMakefile,\r
+                 " %s",\r
+                 "include" SSEP "reactos" SSEP "buildno.h" );\r
+       fprintf ( fMakefile,\r
+                 "\n\t\n\n" );\r
+\r
+       fprintf ( fMakefile,\r
+                 "$(ROS_INTERMEDIATE)." SSEP "tools:\n" );\r
+       fprintf ( fMakefile,\r
+                 "ifneq ($(ROS_INTERMEDIATE),)\n" );\r
+       fprintf ( fMakefile,\r
+                 "\t${nmkdir} $(ROS_INTERMEDIATE)\n" );\r
+       fprintf ( fMakefile,\r
+                 "endif\n" );\r
+       fprintf ( fMakefile,\r
+                 "\t${nmkdir} $(ROS_INTERMEDIATE)." SSEP "tools\n" );\r
+       fprintf ( fMakefile,\r
+                 "\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
-               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,\r
+                                         "\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,\r
+                 "\n" );\r
 }\r
 \r
-void MingwBackend::GetModuleHandlers ( MingwModuleHandlerList& moduleHandlers )\r
+void\r
+MingwBackend::CheckAutomaticDependencies ()\r
 {\r
-       moduleHandlers.push_back ( new MingwKernelModuleHandler () );\r
+       AutomaticDependency automaticDependency ( ProjectNode );\r
+       automaticDependency.Process ();\r
+       automaticDependency.CheckAutomaticDependencies ();\r
+}\r
+\r
+void\r
+MingwBackend::ProcessModule ( Module& module ) const\r
+{\r
+       MingwModuleHandler* h = MingwModuleHandler::LookupHandler (\r
+               module.node.location,\r
+               module.type );\r
+       h->Process ( module );\r
+       h->GenerateDirectoryTargets ();\r
+}\r
+\r
+string\r
+FixupTargetFilename ( const string& targetFilename )\r
+{\r
+       return string("$(ROS_INTERMEDIATE)") + NormalizeFilename ( targetFilename );\r
+}\r
+\r
+void\r
+MingwBackend::DetectPCHSupport()\r
+{\r
+       string path = "tools" SSEP "rbuild" SSEP "backend" SSEP "mingw" SSEP "pch_detection.h";\r
+       system ( ssprintf("gcc -c %s", path.c_str()).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
+       // TODO FIXME - eventually check for ROS_USE_PCH env var and\r
+       // allow that to override use_pch if true\r
 }\r