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::GetEnvironmentVariable ( const string
& name
)
125 char* value
= getenv ( name
.c_str () );
126 if ( value
!= NULL
&& strlen ( value
) > 0 )
127 return ssprintf ( "%s",
134 Directory::GetEnvironmentVariablePathOrDefault ( const string
& name
,
135 const string
& defaultValue
)
137 const string
& environmentVariableValue
= GetEnvironmentVariable ( name
);
138 if ( environmentVariableValue
.length () > 0 )
139 return NormalizeFilename ( environmentVariableValue
);
145 Directory::GetIntermediatePath ()
151 Directory::GetOutputPath ()
153 return "output-i386";
157 Directory::GetInstallPath ()
159 return GetEnvironmentVariablePathOrDefault ( "ROS_INSTALL",
164 Directory::ResolveVariablesInPath ( char* buf
,
167 string s
= ReplaceVariable ( "$(INTERMEDIATE)", GetIntermediatePath (), path
);
168 s
= ReplaceVariable ( "$(OUTPUT)", GetOutputPath (), s
);
169 s
= ReplaceVariable ( "$(INSTALL)", GetInstallPath (), s
);
170 strcpy ( buf
, s
.c_str () );
174 Directory::GenerateTree ( const string
& parent
,
183 path
= parent
+ SSEP
+ name
;
184 ResolveVariablesInPath ( buf
, path
);
185 if ( CreateDirectory ( buf
) && verbose
)
186 printf ( "Created %s\n", buf
);
191 for ( directory_map::iterator i
= subdirs
.begin();
195 i
->second
->GenerateTree ( path
, verbose
);
200 static class MingwFactory
: public Backend::Factory
203 MingwFactory() : Factory ( "mingw" ) {}
204 Backend
* operator() ( Project
& project
, bool verbose
)
206 return new MingwBackend ( project
, verbose
);
211 MingwBackend::MingwBackend ( Project
& project
, bool verbose
)
212 : Backend ( project
, verbose
),
213 intermediateDirectory ( new Directory ("$(INTERMEDIATE)" ) ),
214 outputDirectory ( new Directory ( "$(OUTPUT)" ) ),
215 installDirectory ( new Directory ( "$(INSTALL)" ) )
219 MingwBackend::~MingwBackend()
221 delete intermediateDirectory
;
222 delete outputDirectory
;
223 delete installDirectory
;
227 MingwBackend::AddDirectoryTarget ( const string
& directory
,
228 Directory
* directoryTree
)
230 directoryTree
->Add ( directory
.c_str() );
231 return directoryTree
->name
;
235 MingwBackend::ProcessModules ()
237 printf ( "Processing modules..." );
239 vector
<MingwModuleHandler
*> v
;
241 for ( i
= 0; i
< ProjectNode
.modules
.size (); i
++ )
243 Module
& module
= *ProjectNode
.modules
[i
];
244 MingwModuleHandler
* h
= MingwModuleHandler::InstanciateHandler (
247 if ( module
.host
== HostDefault
)
249 module
.host
= h
->DefaultHost();
250 assert ( module
.host
!= HostDefault
);
255 size_t iend
= v
.size ();
257 for ( i
= 0; i
< iend
; i
++ )
258 v
[i
]->GenerateObjectMacro();
259 fprintf ( fMakefile
, "\n" );
260 for ( i
= 0; i
< iend
; i
++ )
261 v
[i
]->GenerateTargetMacro();
262 fprintf ( fMakefile
, "\n" );
264 GenerateAllTarget ( v
);
265 GenerateInitTarget ();
267 for ( i
= 0; i
< iend
; i
++ )
268 v
[i
]->GenerateOtherMacros();
270 for ( i
= 0; i
< iend
; i
++ )
272 MingwModuleHandler
& h
= *v
[i
];
273 h
.GeneratePreconditionDependencies ();
275 h
.GenerateInvocations ();
276 h
.GenerateCleanTarget ();
284 MingwBackend::Process ()
286 DetectPipeSupport ();
290 GenerateGlobalVariables ();
291 GenerateXmlBuildFilesMacro ();
293 GenerateInstallTarget ();
294 GenerateDirectories ();
295 CheckAutomaticDependencies ();
300 MingwBackend::CreateMakefile ()
302 fMakefile
= fopen ( ProjectNode
.makefile
.c_str (), "w" );
304 throw AccessDeniedException ( ProjectNode
.makefile
);
305 MingwModuleHandler::SetBackend ( this );
306 MingwModuleHandler::SetMakefile ( fMakefile
);
307 MingwModuleHandler::SetUsePch ( use_pch
);
311 MingwBackend::CloseMakefile () const
314 fclose ( fMakefile
);
318 MingwBackend::GenerateHeader () const
320 fprintf ( fMakefile
, "# THIS FILE IS AUTOMATICALLY GENERATED, EDIT 'ReactOS.xml' INSTEAD\n\n" );
324 MingwBackend::GenerateProjectCFlagsMacro ( const char* assignmentOperation
,
325 IfableData
& data
) const
332 assignmentOperation
);
333 for ( i
= 0; i
< data
.includes
.size(); i
++ )
338 data
.includes
[i
]->directory
.c_str() );
341 for ( i
= 0; i
< data
.defines
.size(); i
++ )
343 Define
& d
= *data
.defines
[i
];
348 if ( d
.value
.size() )
354 fprintf ( fMakefile
, "\n" );
358 MingwBackend::GenerateGlobalCFlagsAndProperties (
359 const char* assignmentOperation
,
360 IfableData
& data
) const
364 for ( i
= 0; i
< data
.properties
.size(); i
++ )
366 Property
& prop
= *data
.properties
[i
];
367 fprintf ( fMakefile
, "%s := %s\n",
369 prop
.value
.c_str() );
372 if ( data
.includes
.size() || data
.defines
.size() )
374 GenerateProjectCFlagsMacro ( assignmentOperation
,
378 for ( i
= 0; i
< data
.ifs
.size(); i
++ )
380 If
& rIf
= *data
.ifs
[i
];
381 if ( rIf
.data
.defines
.size()
382 || rIf
.data
.includes
.size()
383 || rIf
.data
.ifs
.size() )
387 "ifeq (\"$(%s)\",\"%s\")\n",
388 rIf
.property
.c_str(),
390 GenerateGlobalCFlagsAndProperties (
401 MingwBackend::GenerateProjectLFLAGS () const
404 for ( size_t i
= 0; i
< ProjectNode
.linkerFlags
.size (); i
++ )
406 LinkerFlag
& linkerFlag
= *ProjectNode
.linkerFlags
[i
];
407 if ( lflags
.length () > 0 )
409 lflags
+= linkerFlag
.flag
;
415 MingwBackend::GenerateGlobalVariables () const
417 GenerateGlobalCFlagsAndProperties (
419 ProjectNode
.non_if_data
);
420 fprintf ( fMakefile
, "PROJECT_RCFLAGS := $(PROJECT_CFLAGS)\n" );
421 fprintf ( fMakefile
, "PROJECT_WIDLFLAGS := $(PROJECT_CFLAGS)\n" );
422 fprintf ( fMakefile
, "PROJECT_LFLAGS := %s\n",
423 GenerateProjectLFLAGS ().c_str () );
424 fprintf ( fMakefile
, "PROJECT_CFLAGS += -Wall\n" );
425 fprintf ( fMakefile
, "\n" );
429 MingwBackend::IncludeInAllTarget ( const Module
& module
) const
431 if ( MingwModuleHandler::ReferenceObjects ( module
) )
433 if ( module
.type
== BootSector
)
435 if ( module
.type
== Iso
)
437 if ( module
.type
== Test
)
443 MingwBackend::GenerateAllTarget ( const vector
<MingwModuleHandler
*>& handlers
) const
445 fprintf ( fMakefile
, "all:" );
447 size_t iend
= handlers
.size ();
448 for ( size_t i
= 0; i
< iend
; i
++ )
450 const Module
& module
= handlers
[i
]->module
;
451 if ( IncludeInAllTarget ( module
) )
453 if ( wrap_count
++ == 5 )
454 fprintf ( fMakefile
, " \\\n\t\t" ), wrap_count
= 0;
457 GetTargetMacro(module
).c_str () );
460 fprintf ( fMakefile
, "\n\t\n\n" );
464 MingwBackend::GetBuildToolDependencies () const
467 for ( size_t i
= 0; i
< ProjectNode
.modules
.size (); i
++ )
469 Module
& module
= *ProjectNode
.modules
[i
];
470 if ( module
.type
== BuildTool
)
472 if ( dependencies
.length () > 0 )
474 dependencies
+= module
.GetDependencyPath ();
481 MingwBackend::GenerateInitTarget () const
485 GetBuildToolDependencies ().c_str () );
486 fprintf ( fMakefile
, "\n" );
490 MingwBackend::GenerateXmlBuildFilesMacro() const
493 "XMLBUILDFILES = %s \\\n",
494 ProjectNode
.GetProjectFilename ().c_str () );
495 string xmlbuildFilenames
;
496 int numberOfExistingFiles
= 0;
497 for ( size_t i
= 0; i
< ProjectNode
.xmlbuildfiles
.size (); i
++ )
499 XMLInclude
& xmlbuildfile
= *ProjectNode
.xmlbuildfiles
[i
];
500 if ( !xmlbuildfile
.fileExists
)
502 numberOfExistingFiles
++;
503 if ( xmlbuildFilenames
.length () > 0 )
504 xmlbuildFilenames
+= " ";
505 xmlbuildFilenames
+= NormalizeFilename ( xmlbuildfile
.topIncludeFilename
);
506 if ( numberOfExistingFiles
% 5 == 4 || i
== ProjectNode
.xmlbuildfiles
.size () - 1 )
510 xmlbuildFilenames
.c_str ());
511 if ( i
== ProjectNode
.xmlbuildfiles
.size () - 1 )
513 fprintf ( fMakefile
, "\n" );
519 xmlbuildFilenames
.c_str () );
521 xmlbuildFilenames
.resize ( 0 );
523 numberOfExistingFiles
++;
525 fprintf ( fMakefile
, "\n" );
529 MingwBackend::CheckAutomaticDependencies ()
531 printf ( "Checking automatic dependencies..." );
532 AutomaticDependency
automaticDependency ( ProjectNode
);
533 automaticDependency
.Process ();
534 automaticDependency
.CheckAutomaticDependencies ( verbose
);
539 MingwBackend::IncludeDirectoryTarget ( const string
& directory
) const
541 if ( directory
== "$(INTERMEDIATE)" SSEP
"tools")
548 MingwBackend::GenerateDirectories ()
550 printf ( "Creating directories..." );
551 intermediateDirectory
->GenerateTree ( "", verbose
);
552 outputDirectory
->GenerateTree ( "", verbose
);
553 installDirectory
->GenerateTree ( "", verbose
);
558 MingwBackend::DetectPipeSupport ()
560 printf ( "Detecting compiler -pipe support..." );
562 string pipe_detection
= "tools" SSEP
"rbuild" SSEP
"backend" SSEP
"mingw" SSEP
"pipe_detection.c";
563 string pipe_detectionObjectFilename
= ReplaceExtension ( pipe_detection
,
565 string command
= ssprintf (
566 "gcc -pipe -c %s -o %s 2>%s",
567 pipe_detection
.c_str (),
568 pipe_detectionObjectFilename
.c_str (),
570 int exitcode
= system ( command
.c_str () );
571 FILE* f
= fopen ( pipe_detectionObjectFilename
.c_str (), "rb" );
574 usePipe
= (exitcode
== 0);
576 unlink ( pipe_detectionObjectFilename
.c_str () );
582 printf ( "detected\n" );
584 printf ( "not detected\n" );
588 MingwBackend::DetectPCHSupport ()
590 printf ( "Detecting compiler pre-compiled header support..." );
592 string path
= "tools" SSEP
"rbuild" SSEP
"backend" SSEP
"mingw" SSEP
"pch_detection.h";
593 string cmd
= ssprintf (
597 system ( cmd
.c_str () );
600 FILE* f
= fopen ( path
.c_str (), "rb" );
605 unlink ( path
.c_str () );
611 printf ( "detected\n" );
613 printf ( "not detected\n" );
617 MingwBackend::GetNonModuleInstallTargetFiles (
618 vector
<string
>& out
) const
620 for ( size_t i
= 0; i
< ProjectNode
.installfiles
.size (); i
++ )
622 const InstallFile
& installfile
= *ProjectNode
.installfiles
[i
];
623 string targetFilenameNoFixup
= installfile
.base
+ SSEP
+ installfile
.newname
;
624 string targetFilename
= MingwModuleHandler::PassThruCacheDirectory (
625 NormalizeFilename ( targetFilenameNoFixup
),
627 out
.push_back ( targetFilename
);
632 MingwBackend::GetModuleInstallTargetFiles (
633 vector
<string
>& out
) const
635 for ( size_t i
= 0; i
< ProjectNode
.modules
.size (); i
++ )
637 const Module
& module
= *ProjectNode
.modules
[i
];
638 if ( module
.installName
.length () > 0 )
640 string targetFilenameNoFixup
= module
.installBase
+ SSEP
+ module
.installName
;
641 string targetFilename
= MingwModuleHandler::PassThruCacheDirectory (
642 NormalizeFilename ( targetFilenameNoFixup
),
644 out
.push_back ( targetFilename
);
650 MingwBackend::GetInstallTargetFiles (
651 vector
<string
>& out
) const
653 GetNonModuleInstallTargetFiles ( out
);
654 GetModuleInstallTargetFiles ( out
);
658 MingwBackend::OutputInstallTarget ( const string
& sourceFilename
,
659 const string
& targetFilename
,
660 const string
& targetDirectory
)
662 string normalizedTargetFilename
= MingwModuleHandler::PassThruCacheDirectory (
663 NormalizeFilename ( targetDirectory
+ SSEP
+ targetFilename
),
665 string normalizedTargetDirectory
= MingwModuleHandler::PassThruCacheDirectory (
666 NormalizeFilename ( targetDirectory
),
670 normalizedTargetFilename
.c_str (),
671 sourceFilename
.c_str (),
672 normalizedTargetDirectory
.c_str () );
676 "\t${cp} %s %s 1>$(NUL)\n",
677 sourceFilename
.c_str (),
678 normalizedTargetFilename
.c_str () );
682 MingwBackend::OutputNonModuleInstallTargets ()
684 for ( size_t i
= 0; i
< ProjectNode
.installfiles
.size (); i
++ )
686 const InstallFile
& installfile
= *ProjectNode
.installfiles
[i
];
687 OutputInstallTarget ( installfile
.GetPath (),
694 MingwBackend::OutputModuleInstallTargets ()
696 for ( size_t i
= 0; i
< ProjectNode
.modules
.size (); i
++ )
698 const Module
& module
= *ProjectNode
.modules
[i
];
699 if ( module
.installName
.length () > 0 )
701 string sourceFilename
= MingwModuleHandler::PassThruCacheDirectory (
702 NormalizeFilename ( module
.GetPath () ),
704 OutputInstallTarget ( sourceFilename
,
706 module
.installBase
);
712 MingwBackend::GetRegistrySourceFiles ()
714 return "bootdata" SSEP
"hivecls.inf "
715 "bootdata" SSEP
"hivedef.inf "
716 "bootdata" SSEP
"hiveinst.inf "
717 "bootdata" SSEP
"hivesft.inf "
718 "bootdata" SSEP
"hivesys.inf";
722 MingwBackend::GetRegistryTargetFiles ()
724 string system32ConfigDirectory
= NormalizeFilename (
725 MingwModuleHandler::PassThruCacheDirectory (
726 "system32" SSEP
"config" SSEP
,
727 installDirectory
) );
728 return system32ConfigDirectory
+ SSEP
"default " +
729 system32ConfigDirectory
+ SSEP
"sam " +
730 system32ConfigDirectory
+ SSEP
"security " +
731 system32ConfigDirectory
+ SSEP
"software " +
732 system32ConfigDirectory
+ SSEP
"system";
736 MingwBackend::OutputRegistryInstallTarget ()
738 string system32ConfigDirectory
= NormalizeFilename (
739 MingwModuleHandler::PassThruCacheDirectory (
740 "system32" SSEP
"config" SSEP
,
741 installDirectory
) );
743 string registrySourceFiles
= GetRegistrySourceFiles ();
744 string registryTargetFiles
= GetRegistryTargetFiles ();
746 "install_registry: %s\n",
747 registryTargetFiles
.c_str () );
749 "%s: %s %s $(MKHIVE_TARGET)\n",
750 registryTargetFiles
.c_str (),
751 registrySourceFiles
.c_str (),
752 system32ConfigDirectory
.c_str () );
754 "\t$(ECHO_MKHIVE)\n" );
756 "\t$(MKHIVE_TARGET) bootdata %s bootdata" SSEP
"hiveinst.inf\n",
757 system32ConfigDirectory
.c_str () );
763 MingwBackend::GenerateInstallTarget ()
765 vector
<string
> vInstallTargetFiles
;
766 GetInstallTargetFiles ( vInstallTargetFiles
);
767 string installTargetFiles
= v2s ( vInstallTargetFiles
, 5 );
770 "install: %s install_registry\n",
771 installTargetFiles
.c_str () );
772 OutputNonModuleInstallTargets ();
773 OutputModuleInstallTargets ();
774 OutputRegistryInstallTarget ();