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
)
45 Environment::GetVariable ( const string
& name
)
47 char* value
= getenv ( name
.c_str () );
48 if ( value
!= NULL
&& strlen ( value
) > 0 )
49 return ssprintf ( "%s",
56 Directory::Directory ( const string
& name_
)
62 Directory::Add ( const char* subdir
)
65 string s1
= string ( subdir
);
66 if ( ( i
= s1
.find ( '$' ) ) != string::npos
)
68 throw InvalidOperationException ( __FILE__
,
70 "No environment variables can be used here. Path was %s",
74 const char* p
= strpbrk ( subdir
, "/\\" );
76 p
= subdir
+ strlen(subdir
);
77 string
s ( subdir
, p
-subdir
);
78 if ( subdirs
.find(s
) == subdirs
.end() )
79 subdirs
[s
] = new Directory(s
);
81 subdirs
[s
]->Add ( p
);
85 Directory::mkdir_p ( const char* path
)
88 directory
= opendir ( path
);
89 if ( directory
!= NULL
)
91 closedir ( directory
);
95 if ( MKDIR ( path
) != 0 )
96 throw AccessDeniedException ( string ( path
) );
101 Directory::CreateDirectory ( string path
)
105 if ( isalpha ( path
[0] ) && path
[1] == ':' && path
[2] == CSEP
)
107 nextIndex
= path
.find ( CSEP
, 3);
110 nextIndex
= path
.find ( CSEP
);
112 bool directoryWasCreated
= false;
113 while ( nextIndex
!= string::npos
)
115 nextIndex
= path
.find ( CSEP
, index
+ 1 );
116 directoryWasCreated
= mkdir_p ( path
.substr ( 0, nextIndex
).c_str () );
119 return directoryWasCreated
;
123 Directory::ReplaceVariable ( string name
,
127 size_t i
= path
.find ( name
);
128 if ( i
!= string::npos
)
129 return path
.replace ( i
, name
.length (), value
);
135 Directory::GetEnvironmentVariablePathOrDefault ( const string
& name
,
136 const string
& defaultValue
)
138 const string
& environmentVariableValue
= Environment::GetVariable ( name
);
139 if ( environmentVariableValue
.length () > 0 )
140 return NormalizeFilename ( environmentVariableValue
);
146 Directory::GetIntermediatePath ()
148 return GetEnvironmentVariablePathOrDefault ( "ROS_INTERMEDIATE",
153 Directory::GetOutputPath ()
155 return GetEnvironmentVariablePathOrDefault ( "ROS_OUTPUT",
160 Directory::GetInstallPath ()
162 return GetEnvironmentVariablePathOrDefault ( "ROS_INSTALL",
167 Directory::ResolveVariablesInPath ( char* buf
,
170 string s
= ReplaceVariable ( "$(INTERMEDIATE)", GetIntermediatePath (), path
);
171 s
= ReplaceVariable ( "$(OUTPUT)", GetOutputPath (), s
);
172 s
= ReplaceVariable ( "$(INSTALL)", GetInstallPath (), s
);
173 strcpy ( buf
, s
.c_str () );
177 Directory::GenerateTree ( const string
& parent
,
186 path
= parent
+ SSEP
+ name
;
187 ResolveVariablesInPath ( buf
, path
);
188 if ( CreateDirectory ( buf
) && verbose
)
189 printf ( "Created %s\n", buf
);
194 for ( directory_map::iterator i
= subdirs
.begin();
198 i
->second
->GenerateTree ( path
, verbose
);
203 static class MingwFactory
: public Backend::Factory
206 MingwFactory() : Factory ( "mingw" ) {}
207 Backend
* operator() ( Project
& project
,
211 return new MingwBackend ( project
,
218 MingwBackend::MingwBackend ( Project
& project
,
221 : Backend ( project
, verbose
, cleanAsYouGo
),
222 intermediateDirectory ( new Directory ("$(INTERMEDIATE)" ) ),
223 outputDirectory ( new Directory ( "$(OUTPUT)" ) ),
224 installDirectory ( new Directory ( "$(INSTALL)" ) )
228 MingwBackend::~MingwBackend()
230 delete intermediateDirectory
;
231 delete outputDirectory
;
232 delete installDirectory
;
236 MingwBackend::AddDirectoryTarget ( const string
& directory
,
237 Directory
* directoryTree
)
239 directoryTree
->Add ( directory
.c_str() );
240 return directoryTree
->name
;
244 MingwBackend::ProcessModules ()
246 printf ( "Processing modules..." );
248 vector
<MingwModuleHandler
*> v
;
250 for ( i
= 0; i
< ProjectNode
.modules
.size (); i
++ )
252 Module
& module
= *ProjectNode
.modules
[i
];
253 MingwModuleHandler
* h
= MingwModuleHandler::InstanciateHandler (
256 if ( module
.host
== HostDefault
)
258 module
.host
= h
->DefaultHost();
259 assert ( module
.host
!= HostDefault
);
264 size_t iend
= v
.size ();
266 for ( i
= 0; i
< iend
; i
++ )
267 v
[i
]->GenerateObjectMacro();
268 fprintf ( fMakefile
, "\n" );
269 for ( i
= 0; i
< iend
; i
++ )
270 v
[i
]->GenerateTargetMacro();
271 fprintf ( fMakefile
, "\n" );
273 GenerateAllTarget ( v
);
274 GenerateInitTarget ();
276 for ( i
= 0; i
< iend
; i
++ )
277 v
[i
]->GenerateOtherMacros();
279 for ( i
= 0; i
< iend
; i
++ )
281 MingwModuleHandler
& h
= *v
[i
];
282 h
.GeneratePreconditionDependencies ();
284 h
.GenerateInvocations ();
285 h
.GenerateCleanTarget ();
293 MingwBackend::Process ()
296 DetectPipeSupport ();
300 GenerateGlobalVariables ();
301 GenerateXmlBuildFilesMacro ();
303 GenerateInstallTarget ();
304 GenerateDirectories ();
305 CheckAutomaticDependencies ();
310 MingwBackend::CreateMakefile ()
312 fMakefile
= fopen ( ProjectNode
.makefile
.c_str (), "w" );
314 throw AccessDeniedException ( ProjectNode
.makefile
);
315 MingwModuleHandler::SetBackend ( this );
316 MingwModuleHandler::SetMakefile ( fMakefile
);
317 MingwModuleHandler::SetUsePch ( use_pch
);
321 MingwBackend::CloseMakefile () const
324 fclose ( fMakefile
);
328 MingwBackend::GenerateHeader () const
330 fprintf ( fMakefile
, "# THIS FILE IS AUTOMATICALLY GENERATED, EDIT 'ReactOS.xml' INSTEAD\n\n" );
334 MingwBackend::GenerateProjectCFlagsMacro ( const char* assignmentOperation
,
335 IfableData
& data
) const
342 assignmentOperation
);
343 for ( i
= 0; i
< data
.includes
.size(); i
++ )
348 data
.includes
[i
]->directory
.c_str() );
351 for ( i
= 0; i
< data
.defines
.size(); i
++ )
353 Define
& d
= *data
.defines
[i
];
358 if ( d
.value
.size() )
364 fprintf ( fMakefile
, "\n" );
368 MingwBackend::GenerateGlobalCFlagsAndProperties (
369 const char* assignmentOperation
,
370 IfableData
& data
) const
374 for ( i
= 0; i
< data
.properties
.size(); i
++ )
376 Property
& prop
= *data
.properties
[i
];
377 fprintf ( fMakefile
, "%s := %s\n",
379 prop
.value
.c_str() );
382 if ( data
.includes
.size() || data
.defines
.size() )
384 GenerateProjectCFlagsMacro ( assignmentOperation
,
388 for ( i
= 0; i
< data
.ifs
.size(); i
++ )
390 If
& rIf
= *data
.ifs
[i
];
391 if ( rIf
.data
.defines
.size()
392 || rIf
.data
.includes
.size()
393 || rIf
.data
.ifs
.size() )
397 "ifeq (\"$(%s)\",\"%s\")\n",
398 rIf
.property
.c_str(),
400 GenerateGlobalCFlagsAndProperties (
411 MingwBackend::GenerateProjectLFLAGS () const
414 for ( size_t i
= 0; i
< ProjectNode
.linkerFlags
.size (); i
++ )
416 LinkerFlag
& linkerFlag
= *ProjectNode
.linkerFlags
[i
];
417 if ( lflags
.length () > 0 )
419 lflags
+= linkerFlag
.flag
;
425 MingwBackend::GenerateGlobalVariables () const
427 GenerateGlobalCFlagsAndProperties (
429 ProjectNode
.non_if_data
);
431 fprintf ( fMakefile
, "PROJECT_RCFLAGS := $(PROJECT_CFLAGS)\n" );
432 fprintf ( fMakefile
, "PROJECT_WIDLFLAGS := $(PROJECT_CFLAGS)\n" );
433 fprintf ( fMakefile
, "PROJECT_LFLAGS := %s\n",
434 GenerateProjectLFLAGS ().c_str () );
435 fprintf ( fMakefile
, "PROJECT_CFLAGS += -Wall\n" );
436 fprintf ( fMakefile
, "\n" );
440 MingwBackend::IncludeInAllTarget ( const Module
& module
) const
442 if ( MingwModuleHandler::ReferenceObjects ( module
) )
444 if ( module
.type
== BootSector
)
446 if ( module
.type
== Iso
)
448 if ( module
.type
== LiveIso
)
450 if ( module
.type
== Test
)
456 MingwBackend::GenerateAllTarget ( const vector
<MingwModuleHandler
*>& handlers
) const
458 fprintf ( fMakefile
, "all:" );
460 size_t iend
= handlers
.size ();
461 for ( size_t i
= 0; i
< iend
; i
++ )
463 const Module
& module
= handlers
[i
]->module
;
464 if ( IncludeInAllTarget ( module
) )
466 if ( wrap_count
++ == 5 )
467 fprintf ( fMakefile
, " \\\n\t\t" ), wrap_count
= 0;
470 GetTargetMacro(module
).c_str () );
473 fprintf ( fMakefile
, "\n\t\n\n" );
477 MingwBackend::GetBuildToolDependencies () const
480 for ( size_t i
= 0; i
< ProjectNode
.modules
.size (); i
++ )
482 Module
& module
= *ProjectNode
.modules
[i
];
483 if ( module
.type
== BuildTool
)
485 if ( dependencies
.length () > 0 )
487 dependencies
+= module
.GetDependencyPath ();
494 MingwBackend::GenerateInitTarget () const
498 GetBuildToolDependencies ().c_str () );
499 fprintf ( fMakefile
, "\n" );
503 MingwBackend::GenerateXmlBuildFilesMacro() const
506 "XMLBUILDFILES = %s \\\n",
507 ProjectNode
.GetProjectFilename ().c_str () );
508 string xmlbuildFilenames
;
509 int numberOfExistingFiles
= 0;
510 for ( size_t i
= 0; i
< ProjectNode
.xmlbuildfiles
.size (); i
++ )
512 XMLInclude
& xmlbuildfile
= *ProjectNode
.xmlbuildfiles
[i
];
513 if ( !xmlbuildfile
.fileExists
)
515 numberOfExistingFiles
++;
516 if ( xmlbuildFilenames
.length () > 0 )
517 xmlbuildFilenames
+= " ";
518 xmlbuildFilenames
+= NormalizeFilename ( xmlbuildfile
.topIncludeFilename
);
519 if ( numberOfExistingFiles
% 5 == 4 || i
== ProjectNode
.xmlbuildfiles
.size () - 1 )
523 xmlbuildFilenames
.c_str ());
524 if ( i
== ProjectNode
.xmlbuildfiles
.size () - 1 )
526 fprintf ( fMakefile
, "\n" );
532 xmlbuildFilenames
.c_str () );
534 xmlbuildFilenames
.resize ( 0 );
536 numberOfExistingFiles
++;
538 fprintf ( fMakefile
, "\n" );
542 MingwBackend::CheckAutomaticDependencies ()
544 printf ( "Checking automatic dependencies..." );
545 AutomaticDependency
automaticDependency ( ProjectNode
);
546 automaticDependency
.Process ();
547 automaticDependency
.CheckAutomaticDependencies ( verbose
);
552 MingwBackend::IncludeDirectoryTarget ( const string
& directory
) const
554 if ( directory
== "$(INTERMEDIATE)" SSEP
"tools")
561 MingwBackend::GenerateDirectories ()
563 printf ( "Creating directories..." );
564 intermediateDirectory
->GenerateTree ( "", verbose
);
565 outputDirectory
->GenerateTree ( "", verbose
);
566 installDirectory
->GenerateTree ( "", verbose
);
571 MingwBackend::TryToDetectThisCompiler ( const string
& compiler
)
573 string command
= ssprintf (
577 int exitcode
= system ( command
.c_str () );
578 return (exitcode
== 0);
582 MingwBackend::DetectCompiler ()
584 printf ( "Detecting compiler..." );
586 bool detectedCompiler
= false;
587 const string
& ROS_PREFIXValue
= Environment::GetVariable ( "ROS_PREFIX" );
588 if ( ROS_PREFIXValue
.length () > 0 )
590 compilerCommand
= ROS_PREFIXValue
+ "-gcc";
591 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
593 if ( !detectedCompiler
)
595 compilerCommand
= "gcc";
596 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
598 if ( !detectedCompiler
)
600 compilerCommand
= "mingw32-gcc";
601 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
603 if ( detectedCompiler
)
604 printf ( "detected (%s)\n", compilerCommand
.c_str () );
606 printf ( "not detected\n" );
610 MingwBackend::DetectPipeSupport ()
612 printf ( "Detecting compiler -pipe support..." );
614 string pipe_detection
= "tools" SSEP
"rbuild" SSEP
"backend" SSEP
"mingw" SSEP
"pipe_detection.c";
615 string pipe_detectionObjectFilename
= ReplaceExtension ( pipe_detection
,
617 string command
= ssprintf (
618 "%s -pipe -c %s -o %s 2>%s",
619 compilerCommand
.c_str (),
620 pipe_detection
.c_str (),
621 pipe_detectionObjectFilename
.c_str (),
623 int exitcode
= system ( command
.c_str () );
624 FILE* f
= fopen ( pipe_detectionObjectFilename
.c_str (), "rb" );
627 usePipe
= (exitcode
== 0);
629 unlink ( pipe_detectionObjectFilename
.c_str () );
635 printf ( "detected\n" );
637 printf ( "not detected\n" );
641 MingwBackend::DetectPCHSupport ()
643 printf ( "Detecting compiler pre-compiled header support..." );
645 string path
= "tools" SSEP
"rbuild" SSEP
"backend" SSEP
"mingw" SSEP
"pch_detection.h";
646 string cmd
= ssprintf (
648 compilerCommand
.c_str (),
651 system ( cmd
.c_str () );
654 FILE* f
= fopen ( path
.c_str (), "rb" );
659 unlink ( path
.c_str () );
665 printf ( "detected\n" );
667 printf ( "not detected\n" );
671 MingwBackend::GetNonModuleInstallTargetFiles (
672 vector
<string
>& out
) const
674 for ( size_t i
= 0; i
< ProjectNode
.installfiles
.size (); i
++ )
676 const InstallFile
& installfile
= *ProjectNode
.installfiles
[i
];
677 string targetFilenameNoFixup
= installfile
.base
+ SSEP
+ installfile
.newname
;
678 string targetFilename
= MingwModuleHandler::PassThruCacheDirectory (
679 NormalizeFilename ( targetFilenameNoFixup
),
681 out
.push_back ( targetFilename
);
686 MingwBackend::GetModuleInstallTargetFiles (
687 vector
<string
>& out
) const
689 for ( size_t i
= 0; i
< ProjectNode
.modules
.size (); i
++ )
691 const Module
& module
= *ProjectNode
.modules
[i
];
692 if ( module
.installName
.length () > 0 )
694 string targetFilenameNoFixup
= module
.installBase
+ SSEP
+ module
.installName
;
695 string targetFilename
= MingwModuleHandler::PassThruCacheDirectory (
696 NormalizeFilename ( targetFilenameNoFixup
),
698 out
.push_back ( targetFilename
);
704 MingwBackend::GetInstallTargetFiles (
705 vector
<string
>& out
) const
707 GetNonModuleInstallTargetFiles ( out
);
708 GetModuleInstallTargetFiles ( out
);
712 MingwBackend::OutputInstallTarget ( const string
& sourceFilename
,
713 const string
& targetFilename
,
714 const string
& targetDirectory
)
716 string normalizedTargetFilename
= MingwModuleHandler::PassThruCacheDirectory (
717 NormalizeFilename ( targetDirectory
+ SSEP
+ targetFilename
),
719 string normalizedTargetDirectory
= MingwModuleHandler::PassThruCacheDirectory (
720 NormalizeFilename ( targetDirectory
),
724 normalizedTargetFilename
.c_str (),
725 sourceFilename
.c_str (),
726 normalizedTargetDirectory
.c_str () );
730 "\t${cp} %s %s 1>$(NUL)\n",
731 sourceFilename
.c_str (),
732 normalizedTargetFilename
.c_str () );
736 MingwBackend::OutputNonModuleInstallTargets ()
738 for ( size_t i
= 0; i
< ProjectNode
.installfiles
.size (); i
++ )
740 const InstallFile
& installfile
= *ProjectNode
.installfiles
[i
];
741 OutputInstallTarget ( installfile
.GetPath (),
748 MingwBackend::OutputModuleInstallTargets ()
750 for ( size_t i
= 0; i
< ProjectNode
.modules
.size (); i
++ )
752 const Module
& module
= *ProjectNode
.modules
[i
];
753 if ( module
.installName
.length () > 0 )
755 string sourceFilename
= MingwModuleHandler::PassThruCacheDirectory (
756 NormalizeFilename ( module
.GetPath () ),
758 OutputInstallTarget ( sourceFilename
,
760 module
.installBase
);
766 MingwBackend::GetRegistrySourceFiles ()
768 return "bootdata" SSEP
"hivecls.inf "
769 "bootdata" SSEP
"hivedef.inf "
770 "bootdata" SSEP
"hiveinst.inf "
771 "bootdata" SSEP
"hivesft.inf "
772 "bootdata" SSEP
"hivesys.inf";
776 MingwBackend::GetRegistryTargetFiles ()
778 string system32ConfigDirectory
= NormalizeFilename (
779 MingwModuleHandler::PassThruCacheDirectory (
780 "system32" SSEP
"config" SSEP
,
781 installDirectory
) );
782 return system32ConfigDirectory
+ SSEP
"default " +
783 system32ConfigDirectory
+ SSEP
"sam " +
784 system32ConfigDirectory
+ SSEP
"security " +
785 system32ConfigDirectory
+ SSEP
"software " +
786 system32ConfigDirectory
+ SSEP
"system";
790 MingwBackend::OutputRegistryInstallTarget ()
792 string system32ConfigDirectory
= NormalizeFilename (
793 MingwModuleHandler::PassThruCacheDirectory (
794 "system32" SSEP
"config" SSEP
,
795 installDirectory
) );
797 string registrySourceFiles
= GetRegistrySourceFiles ();
798 string registryTargetFiles
= GetRegistryTargetFiles ();
800 "install_registry: %s\n",
801 registryTargetFiles
.c_str () );
803 "%s: %s %s $(MKHIVE_TARGET)\n",
804 registryTargetFiles
.c_str (),
805 registrySourceFiles
.c_str (),
806 system32ConfigDirectory
.c_str () );
808 "\t$(ECHO_MKHIVE)\n" );
810 "\t$(MKHIVE_TARGET) bootdata %s bootdata" SSEP
"hiveinst.inf\n",
811 system32ConfigDirectory
.c_str () );
817 MingwBackend::GenerateInstallTarget ()
819 vector
<string
> vInstallTargetFiles
;
820 GetInstallTargetFiles ( vInstallTargetFiles
);
821 string installTargetFiles
= v2s ( vInstallTargetFiles
, 5 );
824 "install: %s install_registry\n",
825 installTargetFiles
.c_str () );
826 OutputNonModuleInstallTargets ();
827 OutputModuleInstallTargets ();
828 OutputRegistryInstallTarget ();