7 #include "modulehandler.h"
10 #define MKDIR(s) mkdir(s)
12 #define MKDIR(s) mkdir(s, 0755)
20 typedef set
<string
> set_string
;
24 v2s ( const string_list
& v
, int wrap_at
)
30 for ( size_t i
= 0; i
< v
.size(); i
++ )
34 if ( wrap_at
> 0 && wrap_count
++ == wrap_at
)
44 Directory::Directory ( const string
& name_
)
50 Directory::Add ( const char* subdir
)
53 string s1
= string ( subdir
);
54 if ( ( i
= s1
.find ( '$' ) ) != string::npos
)
56 throw InvalidOperationException ( __FILE__
,
58 "No environment variables can be used here. Path was %s",
62 const char* p
= strpbrk ( subdir
, "/\\" );
64 p
= subdir
+ strlen(subdir
);
65 string
s ( subdir
, p
-subdir
);
66 if ( subdirs
.find(s
) == subdirs
.end() )
67 subdirs
[s
] = new Directory(s
);
69 subdirs
[s
]->Add ( p
);
73 Directory::mkdir_p ( const char* path
)
76 directory
= opendir ( path
);
77 if ( directory
!= NULL
)
79 closedir ( directory
);
83 if ( MKDIR ( path
) != 0 )
84 throw AccessDeniedException ( string ( path
) );
89 Directory::CreateDirectory ( string path
)
93 if ( isalpha ( path
[0] ) && path
[1] == ':' && path
[2] == CSEP
)
95 nextIndex
= path
.find ( CSEP
, 3);
98 nextIndex
= path
.find ( CSEP
);
100 bool directoryWasCreated
= false;
101 while ( nextIndex
!= string::npos
)
103 nextIndex
= path
.find ( CSEP
, index
+ 1 );
104 directoryWasCreated
= mkdir_p ( path
.substr ( 0, nextIndex
).c_str () );
107 return directoryWasCreated
;
111 Directory::ReplaceVariable ( string name
,
115 size_t i
= path
.find ( name
);
116 if ( i
!= string::npos
)
117 return path
.replace ( i
, name
.length (), value
);
123 Directory::ResolveVariablesInPath ( char* buf
,
126 string s
= ReplaceVariable ( "$(INTERMEDIATE)", Environment::GetIntermediatePath (), path
);
127 s
= ReplaceVariable ( "$(OUTPUT)", Environment::GetOutputPath (), s
);
128 s
= ReplaceVariable ( "$(INSTALL)", Environment::GetInstallPath (), s
);
129 strcpy ( buf
, s
.c_str () );
133 Directory::GenerateTree ( const string
& parent
,
138 if ( parent
.size () > 0 )
142 path
= parent
+ SSEP
+ name
;
143 ResolveVariablesInPath ( buf
, path
);
144 if ( CreateDirectory ( buf
) && verbose
)
145 printf ( "Created %s\n", buf
);
150 for ( directory_map::iterator i
= subdirs
.begin ();
154 i
->second
->GenerateTree ( path
, verbose
);
159 Directory::EscapeSpaces ( string path
)
166 newpath
= newpath
+ "\\ ";
168 newpath
= newpath
+ *p
;
175 Directory::CreateRule ( FILE* f
,
176 const string
& parent
)
180 if ( parent
.size() > 0 )
182 string escapedParent
= EscapeSpaces ( parent
);
185 escapedParent
.c_str (),
187 EscapeSpaces ( name
).c_str (),
188 escapedParent
.c_str () );
191 "\t$(ECHO_MKDIR)\n" );
196 path
= parent
+ SSEP
+ name
;
201 for ( directory_map::iterator i
= subdirs
.begin();
205 i
->second
->CreateRule ( f
, path
);
210 static class MingwFactory
: public Backend::Factory
213 MingwFactory() : Factory ( "mingw" ) {}
214 Backend
* operator() ( Project
& project
,
218 return new MingwBackend ( project
,
225 MingwBackend::MingwBackend ( Project
& project
,
228 : Backend ( project
, verbose
, cleanAsYouGo
),
229 intermediateDirectory ( new Directory ("$(INTERMEDIATE)" ) ),
230 outputDirectory ( new Directory ( "$(OUTPUT)" ) ),
231 installDirectory ( new Directory ( "$(INSTALL)" ) )
235 MingwBackend::~MingwBackend()
237 delete intermediateDirectory
;
238 delete outputDirectory
;
239 delete installDirectory
;
243 MingwBackend::AddDirectoryTarget ( const string
& directory
,
244 Directory
* directoryTree
)
246 if ( directory
.length () > 0)
247 directoryTree
->Add ( directory
.c_str() );
248 return directoryTree
->name
;
252 MingwBackend::ProcessModules ()
254 printf ( "Processing modules..." );
256 vector
<MingwModuleHandler
*> v
;
258 for ( i
= 0; i
< ProjectNode
.modules
.size (); i
++ )
260 Module
& module
= *ProjectNode
.modules
[i
];
261 MingwModuleHandler
* h
= MingwModuleHandler::InstanciateHandler (
264 if ( module
.host
== HostDefault
)
266 module
.host
= h
->DefaultHost();
267 assert ( module
.host
!= HostDefault
);
272 size_t iend
= v
.size ();
274 for ( i
= 0; i
< iend
; i
++ )
275 v
[i
]->GenerateObjectMacro();
276 fprintf ( fMakefile
, "\n" );
277 for ( i
= 0; i
< iend
; i
++ )
278 v
[i
]->GenerateTargetMacro();
279 fprintf ( fMakefile
, "\n" );
281 GenerateAllTarget ( v
);
282 GenerateInitTarget ();
284 for ( i
= 0; i
< iend
; i
++ )
285 v
[i
]->GenerateOtherMacros();
287 for ( i
= 0; i
< iend
; i
++ )
289 MingwModuleHandler
& h
= *v
[i
];
290 h
.GeneratePreconditionDependencies ();
292 h
.GenerateInvocations ();
293 h
.GenerateCleanTarget ();
294 h
.GenerateInstallTarget ();
302 MingwBackend::Process ()
305 DetectPipeSupport ();
309 GenerateGlobalVariables ();
310 GenerateXmlBuildFilesMacro ();
312 GenerateInstallTarget ();
313 GenerateDirectoryTargets ();
314 GenerateDirectories ();
315 UnpackWineResources ();
316 GenerateTestSupportCode ();
317 GenerateProxyMakefiles ();
318 CheckAutomaticDependencies ();
323 MingwBackend::CreateMakefile ()
325 fMakefile
= fopen ( ProjectNode
.makefile
.c_str (), "w" );
327 throw AccessDeniedException ( ProjectNode
.makefile
);
328 MingwModuleHandler::SetBackend ( this );
329 MingwModuleHandler::SetMakefile ( fMakefile
);
330 MingwModuleHandler::SetUsePch ( use_pch
);
334 MingwBackend::CloseMakefile () const
337 fclose ( fMakefile
);
341 MingwBackend::GenerateHeader () const
343 fprintf ( fMakefile
, "# THIS FILE IS AUTOMATICALLY GENERATED, EDIT 'ReactOS.xml' INSTEAD\n\n" );
347 MingwBackend::GenerateIncludesAndDefines ( IfableData
& data
) const
349 string includeParameters
= MingwModuleHandler::GenerateGccIncludeParametersFromVector ( data
.includes
);
350 string defineParameters
= MingwModuleHandler::GenerateGccDefineParametersFromVector ( data
.defines
);
351 return includeParameters
+ " " + defineParameters
;
355 MingwBackend::GenerateProjectCFlagsMacro ( const char* assignmentOperation
,
356 IfableData
& data
) const
361 assignmentOperation
);
365 GenerateIncludesAndDefines ( data
).c_str() );
367 fprintf ( fMakefile
, "\n" );
371 MingwBackend::GenerateGlobalCFlagsAndProperties (
372 const char* assignmentOperation
,
373 IfableData
& data
) const
377 for ( i
= 0; i
< data
.properties
.size(); i
++ )
379 Property
& prop
= *data
.properties
[i
];
380 fprintf ( fMakefile
, "%s := %s\n",
382 prop
.value
.c_str() );
385 if ( data
.includes
.size() || data
.defines
.size() )
387 GenerateProjectCFlagsMacro ( assignmentOperation
,
391 for ( i
= 0; i
< data
.ifs
.size(); i
++ )
393 If
& rIf
= *data
.ifs
[i
];
394 if ( rIf
.data
.defines
.size()
395 || rIf
.data
.includes
.size()
396 || rIf
.data
.ifs
.size() )
400 "ifeq (\"$(%s)\",\"%s\")\n",
401 rIf
.property
.c_str(),
403 GenerateGlobalCFlagsAndProperties (
414 MingwBackend::GenerateProjectGccOptionsMacro ( const char* assignmentOperation
,
415 IfableData
& data
) const
421 "PROJECT_GCCOPTIONS %s",
422 assignmentOperation
);
424 for ( i
= 0; i
< data
.compilerFlags
.size(); i
++ )
429 data
.compilerFlags
[i
]->flag
.c_str() );
432 fprintf ( fMakefile
, "\n" );
436 MingwBackend::GenerateProjectGccOptions (
437 const char* assignmentOperation
,
438 IfableData
& data
) const
442 if ( data
.compilerFlags
.size() )
444 GenerateProjectGccOptionsMacro ( assignmentOperation
,
448 for ( i
= 0; i
< data
.ifs
.size(); i
++ )
450 If
& rIf
= *data
.ifs
[i
];
451 if ( rIf
.data
.compilerFlags
.size()
452 || rIf
.data
.ifs
.size() )
456 "ifeq (\"$(%s)\",\"%s\")\n",
457 rIf
.property
.c_str(),
459 GenerateProjectGccOptions (
470 MingwBackend::GenerateProjectLFLAGS () const
473 for ( size_t i
= 0; i
< ProjectNode
.linkerFlags
.size (); i
++ )
475 LinkerFlag
& linkerFlag
= *ProjectNode
.linkerFlags
[i
];
476 if ( lflags
.length () > 0 )
478 lflags
+= linkerFlag
.flag
;
484 MingwBackend::GenerateGlobalVariables () const
486 GenerateGlobalCFlagsAndProperties ( "=", ProjectNode
.non_if_data
);
487 GenerateProjectGccOptions ( "=", ProjectNode
.non_if_data
);
489 fprintf ( fMakefile
, "PROJECT_RCFLAGS := $(PROJECT_CFLAGS)\n" );
490 fprintf ( fMakefile
, "PROJECT_WIDLFLAGS := $(PROJECT_CFLAGS)\n" );
491 fprintf ( fMakefile
, "PROJECT_LFLAGS := %s\n",
492 GenerateProjectLFLAGS ().c_str () );
493 fprintf ( fMakefile
, "PROJECT_CFLAGS += $(PROJECT_GCCOPTIONS)\n" );
494 fprintf ( fMakefile
, "PROJECT_CFLAGS += -Wall\n" );
495 fprintf ( fMakefile
, "\n" );
499 MingwBackend::IncludeInAllTarget ( const Module
& module
) const
501 if ( MingwModuleHandler::ReferenceObjects ( module
) )
503 if ( module
.type
== BootSector
)
505 if ( module
.type
== Iso
)
507 if ( module
.type
== LiveIso
)
509 if ( module
.type
== Test
)
515 MingwBackend::GenerateAllTarget ( const vector
<MingwModuleHandler
*>& handlers
) const
517 fprintf ( fMakefile
, "all:" );
519 size_t iend
= handlers
.size ();
520 for ( size_t i
= 0; i
< iend
; i
++ )
522 const Module
& module
= handlers
[i
]->module
;
523 if ( IncludeInAllTarget ( module
) )
525 if ( wrap_count
++ == 5 )
526 fprintf ( fMakefile
, " \\\n\t\t" ), wrap_count
= 0;
529 GetTargetMacro(module
).c_str () );
532 fprintf ( fMakefile
, "\n\t\n\n" );
536 MingwBackend::GetBuildToolDependencies () const
539 for ( size_t i
= 0; i
< ProjectNode
.modules
.size (); i
++ )
541 Module
& module
= *ProjectNode
.modules
[i
];
542 if ( module
.type
== BuildTool
)
544 if ( dependencies
.length () > 0 )
546 dependencies
+= module
.GetDependencyPath ();
553 MingwBackend::GenerateInitTarget () const
557 GetBuildToolDependencies ().c_str () );
558 fprintf ( fMakefile
, "\n" );
562 MingwBackend::GenerateXmlBuildFilesMacro() const
565 "XMLBUILDFILES = %s \\\n",
566 ProjectNode
.GetProjectFilename ().c_str () );
567 string xmlbuildFilenames
;
568 int numberOfExistingFiles
= 0;
569 for ( size_t i
= 0; i
< ProjectNode
.xmlbuildfiles
.size (); i
++ )
571 XMLInclude
& xmlbuildfile
= *ProjectNode
.xmlbuildfiles
[i
];
572 if ( !xmlbuildfile
.fileExists
)
574 numberOfExistingFiles
++;
575 if ( xmlbuildFilenames
.length () > 0 )
576 xmlbuildFilenames
+= " ";
577 xmlbuildFilenames
+= NormalizeFilename ( xmlbuildfile
.topIncludeFilename
);
578 if ( numberOfExistingFiles
% 5 == 4 || i
== ProjectNode
.xmlbuildfiles
.size () - 1 )
582 xmlbuildFilenames
.c_str ());
583 if ( i
== ProjectNode
.xmlbuildfiles
.size () - 1 )
585 fprintf ( fMakefile
, "\n" );
591 xmlbuildFilenames
.c_str () );
593 xmlbuildFilenames
.resize ( 0 );
595 numberOfExistingFiles
++;
597 fprintf ( fMakefile
, "\n" );
601 MingwBackend::GetBin2ResExecutable ()
603 return NormalizeFilename ( Environment::GetOutputPath () + SSEP
+ "tools/bin2res/bin2res" + EXEPOSTFIX
);
607 MingwBackend::UnpackWineResources ()
609 printf ( "Unpacking WINE resources..." );
610 WineResource
wineResource ( ProjectNode
,
611 GetBin2ResExecutable () );
612 wineResource
.UnpackResources ( verbose
);
617 MingwBackend::GenerateTestSupportCode ()
619 printf ( "Generating test support code..." );
620 TestSupportCode
testSupportCode ( ProjectNode
);
621 testSupportCode
.GenerateTestSupportCode ( verbose
);
626 MingwBackend::GenerateProxyMakefiles ()
628 printf ( "Generating proxy makefiles..." );
629 ProxyMakefile
proxyMakefile ( ProjectNode
);
630 proxyMakefile
.GenerateProxyMakefiles ( verbose
);
635 MingwBackend::CheckAutomaticDependencies ()
637 printf ( "Checking automatic dependencies..." );
638 AutomaticDependency
automaticDependency ( ProjectNode
);
639 automaticDependency
.Process ();
640 automaticDependency
.CheckAutomaticDependencies ( verbose
);
645 MingwBackend::IncludeDirectoryTarget ( const string
& directory
) const
647 if ( directory
== "$(INTERMEDIATE)" SSEP
"tools")
654 MingwBackend::GenerateDirectories ()
656 printf ( "Creating directories..." );
657 intermediateDirectory
->GenerateTree ( "", verbose
);
658 outputDirectory
->GenerateTree ( "", verbose
);
659 installDirectory
->GenerateTree ( "", verbose
);
664 MingwBackend::TryToDetectThisCompiler ( const string
& compiler
)
666 string command
= ssprintf (
670 int exitcode
= system ( command
.c_str () );
671 return (exitcode
== 0);
675 MingwBackend::DetectCompiler ()
677 printf ( "Detecting compiler..." );
679 bool detectedCompiler
= false;
680 const string
& ROS_PREFIXValue
= Environment::GetVariable ( "ROS_PREFIX" );
681 if ( ROS_PREFIXValue
.length () > 0 )
683 compilerCommand
= ROS_PREFIXValue
+ "-gcc";
684 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
687 if ( !detectedCompiler
)
689 compilerCommand
= "gcc";
690 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
693 if ( !detectedCompiler
)
695 compilerCommand
= "mingw32-gcc";
696 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
698 if ( detectedCompiler
)
699 printf ( "detected (%s)\n", compilerCommand
.c_str () );
701 printf ( "not detected\n" );
705 MingwBackend::DetectPipeSupport ()
707 printf ( "Detecting compiler -pipe support..." );
709 string pipe_detection
= "tools" SSEP
"rbuild" SSEP
"backend" SSEP
"mingw" SSEP
"pipe_detection.c";
710 string pipe_detectionObjectFilename
= ReplaceExtension ( pipe_detection
,
712 string command
= ssprintf (
713 "%s -pipe -c %s -o %s 2>%s",
714 compilerCommand
.c_str (),
715 pipe_detection
.c_str (),
716 pipe_detectionObjectFilename
.c_str (),
718 int exitcode
= system ( command
.c_str () );
719 FILE* f
= fopen ( pipe_detectionObjectFilename
.c_str (), "rb" );
722 usePipe
= (exitcode
== 0);
724 unlink ( pipe_detectionObjectFilename
.c_str () );
730 printf ( "detected\n" );
732 printf ( "not detected\n" );
736 MingwBackend::DetectPCHSupport ()
738 printf ( "Detecting compiler pre-compiled header support..." );
740 string path
= "tools" SSEP
"rbuild" SSEP
"backend" SSEP
"mingw" SSEP
"pch_detection.h";
741 string cmd
= ssprintf (
743 compilerCommand
.c_str (),
746 system ( cmd
.c_str () );
749 FILE* f
= fopen ( path
.c_str (), "rb" );
754 unlink ( path
.c_str () );
760 printf ( "detected\n" );
762 printf ( "not detected\n" );
766 MingwBackend::GetNonModuleInstallTargetFiles (
767 vector
<string
>& out
) const
769 for ( size_t i
= 0; i
< ProjectNode
.installfiles
.size (); i
++ )
771 const InstallFile
& installfile
= *ProjectNode
.installfiles
[i
];
772 string targetFilenameNoFixup
= installfile
.base
+ SSEP
+ installfile
.newname
;
773 string targetFilename
= MingwModuleHandler::PassThruCacheDirectory (
774 NormalizeFilename ( targetFilenameNoFixup
),
776 out
.push_back ( targetFilename
);
781 MingwBackend::GetModuleInstallTargetFiles (
782 vector
<string
>& out
) const
784 for ( size_t i
= 0; i
< ProjectNode
.modules
.size (); i
++ )
786 const Module
& module
= *ProjectNode
.modules
[i
];
787 if ( module
.installName
.length () > 0 )
789 string targetFilenameNoFixup
;
790 if ( module
.installBase
.length () > 0 )
791 targetFilenameNoFixup
= module
.installBase
+ SSEP
+ module
.installName
;
793 targetFilenameNoFixup
= module
.installName
;
794 string targetFilename
= MingwModuleHandler::PassThruCacheDirectory (
795 NormalizeFilename ( targetFilenameNoFixup
),
797 out
.push_back ( targetFilename
);
803 MingwBackend::GetInstallTargetFiles (
804 vector
<string
>& out
) const
806 GetNonModuleInstallTargetFiles ( out
);
807 GetModuleInstallTargetFiles ( out
);
811 MingwBackend::OutputInstallTarget ( const string
& sourceFilename
,
812 const string
& targetFilename
,
813 const string
& targetDirectory
)
815 string fullTargetFilename
;
816 if ( targetDirectory
.length () > 0)
817 fullTargetFilename
= targetDirectory
+ SSEP
+ targetFilename
;
819 fullTargetFilename
= targetFilename
;
820 string normalizedTargetFilename
= MingwModuleHandler::PassThruCacheDirectory (
821 NormalizeFilename ( fullTargetFilename
),
823 string normalizedTargetDirectory
= MingwModuleHandler::PassThruCacheDirectory (
824 NormalizeFilename ( targetDirectory
),
828 normalizedTargetFilename
.c_str (),
829 sourceFilename
.c_str (),
830 normalizedTargetDirectory
.c_str () );
834 "\t${cp} %s %s 1>$(NUL)\n",
835 sourceFilename
.c_str (),
836 normalizedTargetFilename
.c_str () );
840 MingwBackend::OutputNonModuleInstallTargets ()
842 for ( size_t i
= 0; i
< ProjectNode
.installfiles
.size (); i
++ )
844 const InstallFile
& installfile
= *ProjectNode
.installfiles
[i
];
845 OutputInstallTarget ( installfile
.GetPath (),
852 MingwBackend::OutputModuleInstallTargets ()
854 for ( size_t i
= 0; i
< ProjectNode
.modules
.size (); i
++ )
856 const Module
& module
= *ProjectNode
.modules
[i
];
857 if ( module
.installName
.length () > 0 )
859 string sourceFilename
= MingwModuleHandler::PassThruCacheDirectory (
860 NormalizeFilename ( module
.GetPath () ),
862 OutputInstallTarget ( sourceFilename
,
864 module
.installBase
);
870 MingwBackend::GetRegistrySourceFiles ()
872 return "bootdata" SSEP
"hivecls.inf "
873 "bootdata" SSEP
"hivedef.inf "
874 "bootdata" SSEP
"hiveinst.inf "
875 "bootdata" SSEP
"hivesft.inf "
876 "bootdata" SSEP
"hivesys.inf";
880 MingwBackend::GetRegistryTargetFiles ()
882 string system32ConfigDirectory
= NormalizeFilename (
883 MingwModuleHandler::PassThruCacheDirectory (
884 "system32" SSEP
"config" SSEP
,
885 installDirectory
) );
886 return system32ConfigDirectory
+ SSEP
"default " +
887 system32ConfigDirectory
+ SSEP
"sam " +
888 system32ConfigDirectory
+ SSEP
"security " +
889 system32ConfigDirectory
+ SSEP
"software " +
890 system32ConfigDirectory
+ SSEP
"system";
894 MingwBackend::OutputRegistryInstallTarget ()
896 string system32ConfigDirectory
= NormalizeFilename (
897 MingwModuleHandler::PassThruCacheDirectory (
898 "system32" SSEP
"config" SSEP
,
899 installDirectory
) );
901 string registrySourceFiles
= GetRegistrySourceFiles ();
902 string registryTargetFiles
= GetRegistryTargetFiles ();
904 "install_registry: %s\n",
905 registryTargetFiles
.c_str () );
907 "%s: %s %s $(MKHIVE_TARGET)\n",
908 registryTargetFiles
.c_str (),
909 registrySourceFiles
.c_str (),
910 system32ConfigDirectory
.c_str () );
912 "\t$(ECHO_MKHIVE)\n" );
914 "\t$(MKHIVE_TARGET) bootdata %s bootdata" SSEP
"hiveinst.inf\n",
915 system32ConfigDirectory
.c_str () );
921 MingwBackend::GenerateInstallTarget ()
923 vector
<string
> vInstallTargetFiles
;
924 GetInstallTargetFiles ( vInstallTargetFiles
);
925 string installTargetFiles
= v2s ( vInstallTargetFiles
, 5 );
926 string registryTargetFiles
= GetRegistryTargetFiles ();
930 installTargetFiles
.c_str (),
931 registryTargetFiles
.c_str () );
932 OutputNonModuleInstallTargets ();
933 OutputModuleInstallTargets ();
934 OutputRegistryInstallTarget ();
940 MingwBackend::GenerateDirectoryTargets ()
942 intermediateDirectory
->CreateRule ( fMakefile
, "" );
943 outputDirectory
->CreateRule ( fMakefile
, "" );
944 installDirectory
->CreateRule ( fMakefile
, "" );