7 #include "modulehandler.h"
10 #define MKDIR(s) mkdir(s)
12 #define MKDIR(s) mkdir(s, 0755)
20 typedef set
<string
> set_string
;
21 typedef map
<string
,Directory
*> directory_map
;
27 directory_map subdirs
;
28 Directory ( const string
& name
);
29 void Add ( const char* subdir
);
30 void GenerateTree ( const string
& parent
,
33 bool mkdir_p ( const char* path
);
34 string
ReplaceVariable ( string name
,
37 string
GetIntermediatePath ();
38 string
GetOutputPath ();
39 void ResolveVariablesInPath ( char* buf
,
41 bool CreateDirectory ( string path
);
44 Directory::Directory ( const string
& name_
)
49 void Directory::Add ( const char* subdir
)
52 string s1
= string ( subdir
);
53 if ( ( i
= s1
.find ( '$' ) ) != string::npos
)
55 throw InvalidOperationException ( __FILE__
,
57 "No environment variables can be used here. Path was %s",
61 const char* p
= strpbrk ( subdir
, "/\\" );
63 p
= subdir
+ strlen(subdir
);
64 string
s ( subdir
, p
-subdir
);
65 if ( subdirs
.find(s
) == subdirs
.end() )
66 subdirs
[s
] = new Directory(s
);
68 subdirs
[s
]->Add ( p
);
72 Directory::mkdir_p ( const char* path
)
75 directory
= opendir ( path
);
76 if ( directory
!= NULL
)
78 closedir ( directory
);
82 if ( MKDIR ( path
) != 0 )
83 throw AccessDeniedException ( string ( path
) );
88 Directory::CreateDirectory ( string path
)
92 if ( isalpha ( path
[0] ) && path
[1] == ':' && path
[2] == CSEP
)
94 nextIndex
= path
.find ( CSEP
, 3);
97 nextIndex
= path
.find ( CSEP
);
99 bool directoryWasCreated
= false;
100 while ( nextIndex
!= string::npos
)
102 nextIndex
= path
.find ( CSEP
, index
+ 1 );
103 directoryWasCreated
= mkdir_p ( path
.substr ( 0, nextIndex
).c_str () );
106 return directoryWasCreated
;
110 Directory::ReplaceVariable ( string name
,
114 size_t i
= path
.find ( name
);
115 if ( i
!= string::npos
)
116 return path
.replace ( i
, name
.length (), value
);
122 Directory::GetIntermediatePath ()
128 Directory::GetOutputPath ()
130 return "output-i386";
134 Directory::ResolveVariablesInPath ( char* buf
,
137 string s
= ReplaceVariable ( "$(INTERMEDIATE)", GetIntermediatePath (), path
);
138 s
= ReplaceVariable ( "$(OUTPUT)", GetOutputPath (), s
);
139 strcpy ( buf
, s
.c_str () );
143 Directory::GenerateTree ( const string
& parent
,
152 path
= parent
+ SSEP
+ name
;
153 ResolveVariablesInPath ( buf
, path
);
154 if ( CreateDirectory ( buf
) && verbose
)
155 printf ( "Created %s\n", buf
);
160 for ( directory_map::iterator i
= subdirs
.begin();
164 i
->second
->GenerateTree ( path
, verbose
);
168 static class MingwFactory
: public Backend::Factory
171 MingwFactory() : Factory ( "mingw" ) {}
172 Backend
* operator() ( Project
& project
, bool verbose
)
174 return new MingwBackend ( project
, verbose
);
179 MingwBackend::MingwBackend ( Project
& project
, bool verbose
)
180 : Backend ( project
, verbose
),
181 int_directories ( new Directory("$(INTERMEDIATE)") ),
182 out_directories ( new Directory("$(OUTPUT)") )
186 MingwBackend::~MingwBackend()
188 delete int_directories
;
189 delete out_directories
;
193 MingwBackend::AddDirectoryTarget ( const string
& directory
, bool out
)
195 const char* dir_name
= "$(INTERMEDIATE)";
196 Directory
* dir
= int_directories
;
199 dir_name
= "$(OUTPUT)";
200 dir
= out_directories
;
202 dir
->Add ( directory
.c_str() );
207 MingwBackend::ProcessModules ()
209 printf ( "Processing modules..." );
211 vector
<MingwModuleHandler
*> v
;
213 for ( i
= 0; i
< ProjectNode
.modules
.size (); i
++ )
215 Module
& module
= *ProjectNode
.modules
[i
];
216 MingwModuleHandler
* h
= MingwModuleHandler::InstanciateHandler (
219 if ( module
.host
== HostDefault
)
221 module
.host
= h
->DefaultHost();
222 assert ( module
.host
!= HostDefault
);
227 size_t iend
= v
.size ();
229 for ( i
= 0; i
< iend
; i
++ )
230 v
[i
]->GenerateObjectMacro();
231 fprintf ( fMakefile
, "\n" );
232 for ( i
= 0; i
< iend
; i
++ )
233 v
[i
]->GenerateTargetMacro();
234 fprintf ( fMakefile
, "\n" );
236 GenerateAllTarget ( v
);
237 GenerateInitTarget ();
239 for ( i
= 0; i
< iend
; i
++ )
240 v
[i
]->GenerateOtherMacros();
242 for ( i
= 0; i
< iend
; i
++ )
244 MingwModuleHandler
& h
= *v
[i
];
245 h
.GeneratePreconditionDependencies ();
247 h
.GenerateInvocations ();
248 h
.GenerateCleanTarget ();
256 MingwBackend::Process ()
258 DetectPipeSupport ();
262 GenerateGlobalVariables ();
263 GenerateXmlBuildFilesMacro ();
265 GenerateDirectories ();
266 CheckAutomaticDependencies ();
271 MingwBackend::CreateMakefile ()
273 fMakefile
= fopen ( ProjectNode
.makefile
.c_str (), "w" );
275 throw AccessDeniedException ( ProjectNode
.makefile
);
276 MingwModuleHandler::SetBackend ( this );
277 MingwModuleHandler::SetMakefile ( fMakefile
);
278 MingwModuleHandler::SetUsePch ( use_pch
);
282 MingwBackend::CloseMakefile () const
285 fclose ( fMakefile
);
289 MingwBackend::GenerateHeader () const
291 fprintf ( fMakefile
, "# THIS FILE IS AUTOMATICALLY GENERATED, EDIT 'ReactOS.xml' INSTEAD\n\n" );
295 MingwBackend::GenerateProjectCFlagsMacro ( const char* assignmentOperation
,
296 IfableData
& data
) const
303 assignmentOperation
);
304 for ( i
= 0; i
< data
.includes
.size(); i
++ )
309 data
.includes
[i
]->directory
.c_str() );
312 for ( i
= 0; i
< data
.defines
.size(); i
++ )
314 Define
& d
= *data
.defines
[i
];
319 if ( d
.value
.size() )
325 fprintf ( fMakefile
, "\n" );
329 MingwBackend::GenerateGlobalCFlagsAndProperties (
330 const char* assignmentOperation
,
331 IfableData
& data
) const
335 for ( i
= 0; i
< data
.properties
.size(); i
++ )
337 Property
& prop
= *data
.properties
[i
];
338 fprintf ( fMakefile
, "%s := %s\n",
340 prop
.value
.c_str() );
343 if ( data
.includes
.size() || data
.defines
.size() )
345 GenerateProjectCFlagsMacro ( assignmentOperation
,
349 for ( i
= 0; i
< data
.ifs
.size(); i
++ )
351 If
& rIf
= *data
.ifs
[i
];
352 if ( rIf
.data
.defines
.size()
353 || rIf
.data
.includes
.size()
354 || rIf
.data
.ifs
.size() )
358 "ifeq (\"$(%s)\",\"%s\")\n",
359 rIf
.property
.c_str(),
361 GenerateGlobalCFlagsAndProperties (
372 MingwBackend::GenerateProjectLFLAGS () const
375 for ( size_t i
= 0; i
< ProjectNode
.linkerFlags
.size (); i
++ )
377 LinkerFlag
& linkerFlag
= *ProjectNode
.linkerFlags
[i
];
378 if ( lflags
.length () > 0 )
380 lflags
+= linkerFlag
.flag
;
386 MingwBackend::GenerateGlobalVariables () const
388 GenerateGlobalCFlagsAndProperties (
390 ProjectNode
.non_if_data
);
391 fprintf ( fMakefile
, "PROJECT_RCFLAGS = $(PROJECT_CFLAGS)\n" );
392 fprintf ( fMakefile
, "PROJECT_LFLAGS = %s\n",
393 GenerateProjectLFLAGS ().c_str () );
394 fprintf ( fMakefile
, "\n" );
398 MingwBackend::IncludeInAllTarget ( const Module
& module
) const
400 if ( module
.type
== ObjectLibrary
)
402 if ( module
.type
== BootSector
)
404 if ( module
.type
== Iso
)
410 MingwBackend::GenerateAllTarget ( const vector
<MingwModuleHandler
*>& handlers
) const
412 fprintf ( fMakefile
, "all:" );
414 size_t iend
= handlers
.size ();
415 for ( size_t i
= 0; i
< iend
; i
++ )
417 const Module
& module
= handlers
[i
]->module
;
418 if ( IncludeInAllTarget ( module
) )
420 if ( wrap_count
++ == 5 )
421 fprintf ( fMakefile
, " \\\n\t\t" ), wrap_count
= 0;
424 GetTargetMacro(module
).c_str () );
427 fprintf ( fMakefile
, "\n\t\n\n" );
431 MingwBackend::GetBuildToolDependencies () const
434 for ( size_t i
= 0; i
< ProjectNode
.modules
.size (); i
++ )
436 Module
& module
= *ProjectNode
.modules
[i
];
437 if ( module
.type
== BuildTool
)
439 if ( dependencies
.length () > 0 )
441 dependencies
+= module
.GetDependencyPath ();
448 MingwBackend::GenerateInitTarget () const
452 GetBuildToolDependencies ().c_str () );
453 fprintf ( fMakefile
, "\n" );
457 MingwBackend::GenerateXmlBuildFilesMacro() const
460 "XMLBUILDFILES = %s \\\n",
461 ProjectNode
.GetProjectFilename ().c_str () );
462 string xmlbuildFilenames
;
463 int numberOfExistingFiles
= 0;
464 for ( size_t i
= 0; i
< ProjectNode
.xmlbuildfiles
.size (); i
++ )
466 XMLInclude
& xmlbuildfile
= *ProjectNode
.xmlbuildfiles
[i
];
467 if ( !xmlbuildfile
.fileExists
)
469 numberOfExistingFiles
++;
470 if ( xmlbuildFilenames
.length () > 0 )
471 xmlbuildFilenames
+= " ";
472 xmlbuildFilenames
+= NormalizeFilename ( xmlbuildfile
.topIncludeFilename
);
473 if ( numberOfExistingFiles
% 5 == 4 || i
== ProjectNode
.xmlbuildfiles
.size () - 1 )
477 xmlbuildFilenames
.c_str ());
478 if ( i
== ProjectNode
.xmlbuildfiles
.size () - 1 )
480 fprintf ( fMakefile
, "\n" );
486 xmlbuildFilenames
.c_str () );
488 xmlbuildFilenames
.resize ( 0 );
490 numberOfExistingFiles
++;
492 fprintf ( fMakefile
, "\n" );
496 MingwBackend::CheckAutomaticDependencies ()
498 printf ( "Checking automatic dependencies..." );
499 AutomaticDependency
automaticDependency ( ProjectNode
);
500 automaticDependency
.Process ();
501 automaticDependency
.CheckAutomaticDependencies ( verbose
);
506 MingwBackend::IncludeDirectoryTarget ( const string
& directory
) const
508 if ( directory
== "$(INTERMEDIATE)" SSEP
"tools")
515 MingwBackend::GenerateDirectories ()
517 printf ( "Creating directories..." );
518 int_directories
->GenerateTree ( "", verbose
);
519 out_directories
->GenerateTree ( "", verbose
);
524 FixupTargetFilename ( const string
& targetFilename
)
526 return NormalizeFilename ( targetFilename
);
530 MingwBackend::DetectPipeSupport ()
532 printf ( "Detecting compiler -pipe support..." );
534 string pipe_detection
= "tools" SSEP
"rbuild" SSEP
"backend" SSEP
"mingw" SSEP
"pipe_detection.c";
535 string pipe_detectionObjectFilename
= ReplaceExtension ( pipe_detection
,
537 string command
= ssprintf (
538 "gcc -pipe -c %s -o %s 2>%s",
539 pipe_detection
.c_str (),
540 pipe_detectionObjectFilename
.c_str (),
542 int exitcode
= system ( command
.c_str () );
543 FILE* f
= fopen ( pipe_detectionObjectFilename
.c_str (), "rb" );
546 usePipe
= (exitcode
== 0);
548 unlink ( pipe_detectionObjectFilename
.c_str () );
554 printf ( "detected\n" );
556 printf ( "not detected\n" );
558 // TODO FIXME - eventually check for ROS_USE_PCH env var and
559 // allow that to override use_pch if true
563 MingwBackend::DetectPCHSupport ()
565 printf ( "Detecting compiler pre-compiled header support..." );
567 string path
= "tools" SSEP
"rbuild" SSEP
"backend" SSEP
"mingw" SSEP
"pch_detection.h";
568 string cmd
= ssprintf (
572 system ( cmd
.c_str () );
575 FILE* f
= fopen ( path
.c_str (), "rb" );
580 unlink ( path
.c_str () );
586 printf ( "detected\n" );
588 printf ( "not detected\n" );
590 // TODO FIXME - eventually check for ROS_USE_PCH env var and
591 // allow that to override use_pch if true