-\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
-\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
-/* static */ string\r
-Environment::GetVariable ( const string& name )\r
-{\r
- char* value = getenv ( name.c_str () );\r
- if ( value != NULL && strlen ( value ) > 0 )\r
- return ssprintf ( "%s",\r
- value );\r
- else\r
- return "";\r
-}\r
-\r
-\r
-Directory::Directory ( const string& name_ )\r
- : name(name_)\r
-{\r
-}\r
-\r
-void\r
-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::GetEnvironmentVariablePathOrDefault ( const string& name,\r
- const string& defaultValue )\r
-{\r
- const string& environmentVariableValue = Environment::GetVariable ( name );\r
- if ( environmentVariableValue.length () > 0 )\r
- return NormalizeFilename ( environmentVariableValue );\r
- else\r
- return defaultValue;\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
-string\r
-Directory::GetInstallPath ()\r
-{\r
- return GetEnvironmentVariablePathOrDefault ( "ROS_INSTALL",\r
- "reactos" );\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
- s = ReplaceVariable ( "$(INSTALL)", GetInstallPath (), 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
-\r
-static class MingwFactory : public Backend::Factory\r
-{\r
-public:\r
- MingwFactory() : Factory ( "mingw" ) {}\r
- Backend* operator() ( Project& project,\r
- bool verbose,\r
- bool cleanAsYouGo )\r
- {\r
- return new MingwBackend ( project,\r
- verbose,\r
- cleanAsYouGo );\r
- }\r
-} factory;\r
-\r
-\r
-MingwBackend::MingwBackend ( Project& project,\r
- bool verbose,\r
- bool cleanAsYouGo )\r
- : Backend ( project, verbose, cleanAsYouGo ),\r
- intermediateDirectory ( new Directory ("$(INTERMEDIATE)" ) ),\r
- outputDirectory ( new Directory ( "$(OUTPUT)" ) ),\r
- installDirectory ( new Directory ( "$(INSTALL)" ) )\r
-{\r
-}\r
-\r
-MingwBackend::~MingwBackend()\r
-{\r
- delete intermediateDirectory;\r
- delete outputDirectory;\r
- delete installDirectory;\r
-}\r
-\r
-string\r
-MingwBackend::AddDirectoryTarget ( const string& directory,\r
- Directory* directoryTree )\r
-{\r
- directoryTree->Add ( directory.c_str() );\r
- return directoryTree->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
- DetectCompiler ();\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_WIDLFLAGS := $(PROJECT_CFLAGS)\n" );\r
- fprintf ( fMakefile, "PROJECT_LFLAGS := %s\n",\r
- GenerateProjectLFLAGS ().c_str () );\r
- fprintf ( fMakefile, "PROJECT_CFLAGS += -Wall\n" );\r
- fprintf ( fMakefile, "\n" );\r
-}\r
-\r
-bool\r
-MingwBackend::IncludeInAllTarget ( const Module& module ) const\r
-{\r
- if ( MingwModuleHandler::ReferenceObjects ( module ) )\r
- return false;\r
- if ( module.type == BootSector )\r
- return false;\r
- if ( module.type == Iso )\r
- return false;\r
- if ( module.type == LiveIso )\r
- return false;\r
- if ( module.type == Test )\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
- intermediateDirectory->GenerateTree ( "", verbose );\r
- outputDirectory->GenerateTree ( "", verbose );\r
- installDirectory->GenerateTree ( "", verbose );\r
- printf ( "done\n" );\r
-}\r
-\r
-bool\r
-MingwBackend::TryToDetectThisCompiler ( const string& compiler )\r
-{\r
- string command = ssprintf (\r
- "%s -v 2>%s",\r
- compiler.c_str (),\r
- NUL );\r
- int exitcode = system ( command.c_str () );\r
- return (exitcode == 0);\r
-}\r
-\r
-void\r
-MingwBackend::DetectCompiler ()\r
-{\r
- printf ( "Detecting compiler..." );\r
-\r
- bool detectedCompiler = false;\r
- const string& ROS_PREFIXValue = Environment::GetVariable ( "ROS_PREFIX" );\r
- if ( ROS_PREFIXValue.length () > 0 )\r
- {\r
- compilerCommand = ROS_PREFIXValue + "-gcc";\r
- detectedCompiler = TryToDetectThisCompiler ( compilerCommand );\r
- }\r
- if ( !detectedCompiler )\r
- {\r
- compilerCommand = "gcc";\r
- detectedCompiler = TryToDetectThisCompiler ( compilerCommand );\r
- }\r
- if ( !detectedCompiler )\r
- {\r
- compilerCommand = "mingw32-gcc";\r
- detectedCompiler = TryToDetectThisCompiler ( compilerCommand );\r
- }\r
- if ( detectedCompiler )\r
- printf ( "detected (%s)\n", compilerCommand.c_str () );\r
- else\r
- printf ( "not detected\n" );\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
- "%s -pipe -c %s -o %s 2>%s",\r
- compilerCommand.c_str (),\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
-\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
- "%s -c %s 2>%s",\r
- compilerCommand.c_str (),\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
-\r
-void\r
-MingwBackend::GetNonModuleInstallTargetFiles (\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 = installfile.base + SSEP + installfile.newname;\r
- string targetFilename = MingwModuleHandler::PassThruCacheDirectory (\r
- NormalizeFilename ( targetFilenameNoFixup ),\r
- installDirectory );\r
- out.push_back ( targetFilename );\r
- }\r
-}\r
-\r
-void\r
-MingwBackend::GetModuleInstallTargetFiles (\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 = module.installBase + SSEP + module.installName;\r
- string targetFilename = MingwModuleHandler::PassThruCacheDirectory (\r
- NormalizeFilename ( targetFilenameNoFixup ),\r
- installDirectory );\r
- out.push_back ( targetFilename );\r
- }\r
- }\r
-}\r
-\r
-void\r
-MingwBackend::GetInstallTargetFiles (\r
- vector<string>& out ) const\r
-{\r
- GetNonModuleInstallTargetFiles ( out );\r
- GetModuleInstallTargetFiles ( out );\r
-}\r
-\r
-void\r
-MingwBackend::OutputInstallTarget ( const string& sourceFilename,\r
- const string& targetFilename,\r
- const string& targetDirectory )\r
-{\r
- string normalizedTargetFilename = MingwModuleHandler::PassThruCacheDirectory (\r
- NormalizeFilename ( targetDirectory + SSEP + targetFilename ),\r
- installDirectory );\r
- string normalizedTargetDirectory = MingwModuleHandler::PassThruCacheDirectory (\r
- NormalizeFilename ( targetDirectory ),\r
- installDirectory );\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 1>$(NUL)\n",\r
- sourceFilename.c_str (),\r
- normalizedTargetFilename.c_str () );\r
-}\r
-\r
-void\r
-MingwBackend::OutputNonModuleInstallTargets ()\r
-{\r
- for ( size_t i = 0; i < ProjectNode.installfiles.size (); i++ )\r
- {\r
- const InstallFile& installfile = *ProjectNode.installfiles[i];\r
- OutputInstallTarget ( installfile.GetPath (),\r
- installfile.newname,\r
- installfile.base );\r
- }\r
-}\r
-\r
-void\r
-MingwBackend::OutputModuleInstallTargets ()\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
- outputDirectory );\r
- OutputInstallTarget ( sourceFilename,\r
- module.installName,\r
- module.installBase );\r
- }\r
- }\r
-}\r
-\r
-string\r
-MingwBackend::GetRegistrySourceFiles ()\r
-{\r
- return "bootdata" SSEP "hivecls.inf "\r
- "bootdata" SSEP "hivedef.inf "\r
- "bootdata" SSEP "hiveinst.inf "\r
- "bootdata" SSEP "hivesft.inf "\r
- "bootdata" SSEP "hivesys.inf";\r
-}\r
-\r
-string\r
-MingwBackend::GetRegistryTargetFiles ()\r
-{\r
- string system32ConfigDirectory = NormalizeFilename (\r
- MingwModuleHandler::PassThruCacheDirectory (\r
- "system32" SSEP "config" SSEP,\r
- installDirectory ) );\r
- return system32ConfigDirectory + SSEP "default " +\r
- system32ConfigDirectory + SSEP "sam " +\r
- system32ConfigDirectory + SSEP "security " +\r
- system32ConfigDirectory + SSEP "software " +\r
- system32ConfigDirectory + SSEP "system";\r
-}\r
-\r
-void\r
-MingwBackend::OutputRegistryInstallTarget ()\r
-{\r
- string system32ConfigDirectory = NormalizeFilename (\r
- MingwModuleHandler::PassThruCacheDirectory (\r
- "system32" SSEP "config" SSEP,\r
- installDirectory ) );\r
-\r
- string registrySourceFiles = GetRegistrySourceFiles ();\r
- string registryTargetFiles = GetRegistryTargetFiles ();\r
- fprintf ( fMakefile,\r
- "install_registry: %s\n",\r
- registryTargetFiles.c_str () );\r
- fprintf ( fMakefile,\r
- "%s: %s %s $(MKHIVE_TARGET)\n",\r
- registryTargetFiles.c_str (),\r
- registrySourceFiles.c_str (),\r
- system32ConfigDirectory.c_str () );\r
- fprintf ( fMakefile,\r
- "\t$(ECHO_MKHIVE)\n" );\r
- fprintf ( fMakefile,\r
- "\t$(MKHIVE_TARGET) bootdata %s bootdata" SSEP "hiveinst.inf\n",\r
- system32ConfigDirectory.c_str () );\r
- fprintf ( fMakefile,\r
- "\n" );\r
-}\r
-\r
-void\r
-MingwBackend::GenerateInstallTarget ()\r
-{\r
- vector<string> vInstallTargetFiles;\r
- GetInstallTargetFiles ( vInstallTargetFiles );\r
- string installTargetFiles = v2s ( vInstallTargetFiles, 5 );\r
-\r
- fprintf ( fMakefile,\r
- "install: %s install_registry\n",\r
- installTargetFiles.c_str () );\r
- OutputNonModuleInstallTargets ();\r
- OutputModuleInstallTargets ();\r
- OutputRegistryInstallTarget ();\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, "" );
+}