aeeadd935cea2b37b2034919a22a33354cc00285
[reactos.git] / reactos / tools / rbuild / backend / mingw / mingw.cpp
1
2 #include "../../pch.h"
3
4 #include "mingw.h"
5 #include <assert.h>
6 #include <dirent.h>
7 #include "modulehandler.h"
8
9 #ifdef WIN32
10 #define MKDIR(s) mkdir(s)
11 #else
12 #define MKDIR(s) mkdir(s, 0755)
13 #endif
14
15 using std::string;
16 using std::vector;
17 using std::set;
18 using std::map;
19
20 typedef set<string> set_string;
21
22
23 string
24 v2s ( const string_list& v, int wrap_at )
25 {
26 if ( !v.size() )
27 return "";
28 string s;
29 int wrap_count = 0;
30 for ( size_t i = 0; i < v.size(); i++ )
31 {
32 if ( !v[i].size() )
33 continue;
34 if ( wrap_at > 0 && wrap_count++ == wrap_at )
35 s += " \\\n\t\t";
36 else if ( s.size() )
37 s += " ";
38 s += v[i];
39 }
40 return s;
41 }
42
43
44 Directory::Directory ( const string& name_ )
45 : name(name_)
46 {
47 }
48
49 void
50 Directory::Add ( const char* subdir )
51 {
52 size_t i;
53 string s1 = string ( subdir );
54 if ( ( i = s1.find ( '$' ) ) != string::npos )
55 {
56 throw InvalidOperationException ( __FILE__,
57 __LINE__,
58 "No environment variables can be used here. Path was %s",
59 subdir );
60 }
61
62 const char* p = strpbrk ( subdir, "/\\" );
63 if ( !p )
64 p = subdir + strlen(subdir);
65 string s ( subdir, p-subdir );
66 if ( subdirs.find(s) == subdirs.end() )
67 subdirs[s] = new Directory(s);
68 if ( *p && *++p )
69 subdirs[s]->Add ( p );
70 }
71
72 bool
73 Directory::mkdir_p ( const char* path )
74 {
75 DIR *directory;
76 directory = opendir ( path );
77 if ( directory != NULL )
78 {
79 closedir ( directory );
80 return false;
81 }
82
83 if ( MKDIR ( path ) != 0 )
84 throw AccessDeniedException ( string ( path ) );
85 return true;
86 }
87
88 bool
89 Directory::CreateDirectory ( string path )
90 {
91 size_t index = 0;
92 size_t nextIndex;
93 if ( isalpha ( path[0] ) && path[1] == ':' && path[2] == CSEP )
94 {
95 nextIndex = path.find ( CSEP, 3);
96 }
97 else
98 nextIndex = path.find ( CSEP );
99
100 bool directoryWasCreated = false;
101 while ( nextIndex != string::npos )
102 {
103 nextIndex = path.find ( CSEP, index + 1 );
104 directoryWasCreated = mkdir_p ( path.substr ( 0, nextIndex ).c_str () );
105 index = nextIndex;
106 }
107 return directoryWasCreated;
108 }
109
110 string
111 Directory::ReplaceVariable ( string name,
112 string value,
113 string path )
114 {
115 size_t i = path.find ( name );
116 if ( i != string::npos )
117 return path.replace ( i, name.length (), value );
118 else
119 return path;
120 }
121
122 void
123 Directory::ResolveVariablesInPath ( char* buf,
124 string path )
125 {
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 () );
130 }
131
132 void
133 Directory::GenerateTree ( const string& parent,
134 bool verbose )
135 {
136 string path;
137
138 if ( parent.size () > 0 )
139 {
140 char buf[256];
141
142 path = parent + SSEP + name;
143 ResolveVariablesInPath ( buf, path );
144 if ( CreateDirectory ( buf ) && verbose )
145 printf ( "Created %s\n", buf );
146 }
147 else
148 path = name;
149
150 for ( directory_map::iterator i = subdirs.begin ();
151 i != subdirs.end ();
152 ++i )
153 {
154 i->second->GenerateTree ( path, verbose );
155 }
156 }
157
158 string
159 Directory::EscapeSpaces ( string path )
160 {
161 string newpath;
162 char* p = &path[0];
163 while ( *p != 0 )
164 {
165 if ( *p == ' ' )
166 newpath = newpath + "\\ ";
167 else
168 newpath = newpath + *p;
169 *p++;
170 }
171 return newpath;
172 }
173
174 void
175 Directory::CreateRule ( FILE* f,
176 const string& parent )
177 {
178 string path;
179
180 if ( parent.size() > 0 )
181 {
182 string escapedParent = EscapeSpaces ( parent );
183 fprintf ( f,
184 "%s%c%s: | %s\n",
185 escapedParent.c_str (),
186 CSEP,
187 EscapeSpaces ( name ).c_str (),
188 escapedParent.c_str () );
189
190 fprintf ( f,
191 "\t$(ECHO_MKDIR)\n" );
192
193 fprintf ( f,
194 "\t${mkdir} $@\n" );
195
196 path = parent + SSEP + name;
197 }
198 else
199 path = name;
200
201 for ( directory_map::iterator i = subdirs.begin();
202 i != subdirs.end();
203 ++i )
204 {
205 i->second->CreateRule ( f, path );
206 }
207 }
208
209
210 static class MingwFactory : public Backend::Factory
211 {
212 public:
213 MingwFactory() : Factory ( "mingw" ) {}
214 Backend* operator() ( Project& project,
215 Configuration& configuration )
216 {
217 return new MingwBackend ( project,
218 configuration );
219 }
220 } factory;
221
222
223 MingwBackend::MingwBackend ( Project& project,
224 Configuration& configuration )
225 : Backend ( project, configuration ),
226 intermediateDirectory ( new Directory ("$(INTERMEDIATE)" ) ),
227 outputDirectory ( new Directory ( "$(OUTPUT)" ) ),
228 installDirectory ( new Directory ( "$(INSTALL)" ) )
229 {
230 compilerPrefix = "";
231 }
232
233 MingwBackend::~MingwBackend()
234 {
235 delete intermediateDirectory;
236 delete outputDirectory;
237 delete installDirectory;
238 }
239
240 string
241 MingwBackend::AddDirectoryTarget ( const string& directory,
242 Directory* directoryTree )
243 {
244 if ( directory.length () > 0)
245 directoryTree->Add ( directory.c_str() );
246 return directoryTree->name;
247 }
248
249 void
250 MingwBackend::ProcessModules ()
251 {
252 printf ( "Processing modules..." );
253
254 vector<MingwModuleHandler*> v;
255 size_t i;
256 for ( i = 0; i < ProjectNode.modules.size (); i++ )
257 {
258 Module& module = *ProjectNode.modules[i];
259 if ( !module.enabled )
260 continue;
261 MingwModuleHandler* h = MingwModuleHandler::InstanciateHandler (
262 module,
263 this );
264 if ( module.host == HostDefault )
265 {
266 module.host = h->DefaultHost();
267 assert ( module.host != HostDefault );
268 }
269 v.push_back ( h );
270 }
271
272 size_t iend = v.size ();
273
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" );
280
281 GenerateAllTarget ( v );
282 GenerateInitTarget ();
283 GenerateRegTestsRunTarget ();
284
285 for ( i = 0; i < iend; i++ )
286 v[i]->GenerateOtherMacros();
287
288 for ( i = 0; i < iend; i++ )
289 {
290 MingwModuleHandler& h = *v[i];
291 h.GeneratePreconditionDependencies ();
292 h.Process ();
293 h.GenerateInvocations ();
294 h.GenerateCleanTarget ();
295 h.GenerateInstallTarget ();
296 h.GenerateDependsTarget ();
297 delete v[i];
298 }
299
300 printf ( "done\n" );
301 }
302
303 void
304 MingwBackend::Process ()
305 {
306 if ( configuration.CheckDependenciesForModuleOnly )
307 CheckAutomaticDependenciesForModuleOnly ();
308 else
309 ProcessNormal ();
310 }
311
312 void
313 MingwBackend::CheckAutomaticDependenciesForModuleOnly ()
314 {
315 if ( configuration.AutomaticDependencies )
316 {
317 Module* module = ProjectNode.LocateModule ( configuration.CheckDependenciesForModuleOnlyModule );
318 if ( module == NULL )
319 {
320 printf ( "Module '%s' does not exist\n",
321 configuration.CheckDependenciesForModuleOnlyModule.c_str () );
322 return;
323 }
324
325 printf ( "Checking automatic dependencies for module '%s'...",
326 module->name.c_str () );
327 AutomaticDependency automaticDependency ( ProjectNode );
328 automaticDependency.CheckAutomaticDependencies ( *module,
329 configuration.Verbose );
330 printf ( "done\n" );
331 }
332 }
333
334 void
335 MingwBackend::ProcessNormal ()
336 {
337 DetectCompiler ();
338 DetectNetwideAssembler ();
339 DetectPipeSupport ();
340 DetectPCHSupport ();
341 CreateMakefile ();
342 GenerateHeader ();
343 GenerateGlobalVariables ();
344 GenerateXmlBuildFilesMacro ();
345 ProcessModules ();
346 GenerateInstallTarget ();
347 GenerateTestTarget ();
348 GenerateDirectoryTargets ();
349 GenerateDirectories ();
350 UnpackWineResources ();
351 GenerateTestSupportCode ();
352 GenerateProxyMakefiles ();
353 CheckAutomaticDependencies ();
354 CloseMakefile ();
355 }
356
357 void
358 MingwBackend::CreateMakefile ()
359 {
360 fMakefile = fopen ( ProjectNode.makefile.c_str (), "w" );
361 if ( !fMakefile )
362 throw AccessDeniedException ( ProjectNode.makefile );
363 MingwModuleHandler::SetBackend ( this );
364 MingwModuleHandler::SetMakefile ( fMakefile );
365 MingwModuleHandler::SetUsePch ( use_pch );
366 }
367
368 void
369 MingwBackend::CloseMakefile () const
370 {
371 if (fMakefile)
372 fclose ( fMakefile );
373 }
374
375 void
376 MingwBackend::GenerateHeader () const
377 {
378 fprintf ( fMakefile, "# THIS FILE IS AUTOMATICALLY GENERATED, EDIT 'ReactOS.xml' INSTEAD\n\n" );
379 }
380
381 string
382 MingwBackend::GenerateIncludesAndDefines ( IfableData& data ) const
383 {
384 string includeParameters = MingwModuleHandler::GenerateGccIncludeParametersFromVector ( data.includes );
385 string defineParameters = MingwModuleHandler::GenerateGccDefineParametersFromVector ( data.defines );
386 return includeParameters + " " + defineParameters;
387 }
388
389 void
390 MingwBackend::GenerateProjectCFlagsMacro ( const char* assignmentOperation,
391 IfableData& data ) const
392 {
393 fprintf (
394 fMakefile,
395 "PROJECT_CFLAGS %s",
396 assignmentOperation );
397
398 fprintf ( fMakefile,
399 " %s",
400 GenerateIncludesAndDefines ( data ).c_str() );
401
402 fprintf ( fMakefile, "\n" );
403 }
404
405 void
406 MingwBackend::GenerateGlobalCFlagsAndProperties (
407 const char* assignmentOperation,
408 IfableData& data ) const
409 {
410 size_t i;
411
412 for ( i = 0; i < data.properties.size(); i++ )
413 {
414 Property& prop = *data.properties[i];
415 fprintf ( fMakefile, "%s := %s\n",
416 prop.name.c_str(),
417 prop.value.c_str() );
418 }
419
420 if ( data.includes.size() || data.defines.size() )
421 {
422 GenerateProjectCFlagsMacro ( assignmentOperation,
423 data );
424 }
425
426 for ( i = 0; i < data.ifs.size(); i++ )
427 {
428 If& rIf = *data.ifs[i];
429 if ( rIf.data.defines.size()
430 || rIf.data.includes.size()
431 || rIf.data.ifs.size() )
432 {
433 fprintf (
434 fMakefile,
435 "ifeq (\"$(%s)\",\"%s\")\n",
436 rIf.property.c_str(),
437 rIf.value.c_str() );
438 GenerateGlobalCFlagsAndProperties (
439 "+=",
440 rIf.data );
441 fprintf (
442 fMakefile,
443 "endif\n\n" );
444 }
445 }
446 }
447
448 void
449 MingwBackend::GenerateProjectGccOptionsMacro ( const char* assignmentOperation,
450 IfableData& data ) const
451 {
452 size_t i;
453
454 fprintf (
455 fMakefile,
456 "PROJECT_GCCOPTIONS %s",
457 assignmentOperation );
458
459 for ( i = 0; i < data.compilerFlags.size(); i++ )
460 {
461 fprintf (
462 fMakefile,
463 " %s",
464 data.compilerFlags[i]->flag.c_str() );
465 }
466
467 fprintf ( fMakefile, "\n" );
468 }
469
470 void
471 MingwBackend::GenerateProjectGccOptions (
472 const char* assignmentOperation,
473 IfableData& data ) const
474 {
475 size_t i;
476
477 if ( data.compilerFlags.size() )
478 {
479 GenerateProjectGccOptionsMacro ( assignmentOperation,
480 data );
481 }
482
483 for ( i = 0; i < data.ifs.size(); i++ )
484 {
485 If& rIf = *data.ifs[i];
486 if ( rIf.data.compilerFlags.size()
487 || rIf.data.ifs.size() )
488 {
489 fprintf (
490 fMakefile,
491 "ifeq (\"$(%s)\",\"%s\")\n",
492 rIf.property.c_str(),
493 rIf.value.c_str() );
494 GenerateProjectGccOptions (
495 "+=",
496 rIf.data );
497 fprintf (
498 fMakefile,
499 "endif\n\n" );
500 }
501 }
502 }
503
504 string
505 MingwBackend::GenerateProjectLFLAGS () const
506 {
507 string lflags;
508 for ( size_t i = 0; i < ProjectNode.linkerFlags.size (); i++ )
509 {
510 LinkerFlag& linkerFlag = *ProjectNode.linkerFlags[i];
511 if ( lflags.length () > 0 )
512 lflags += " ";
513 lflags += linkerFlag.flag;
514 }
515 return lflags;
516 }
517
518 void
519 MingwBackend::GenerateGlobalVariables () const
520 {
521 fprintf ( fMakefile,
522 "PREFIX := %s\n",
523 compilerPrefix.c_str () );
524 fprintf ( fMakefile,
525 "nasm := %s\n",
526 nasmCommand.c_str () );
527
528 GenerateGlobalCFlagsAndProperties ( "=", ProjectNode.non_if_data );
529 GenerateProjectGccOptions ( "=", ProjectNode.non_if_data );
530
531 fprintf ( fMakefile, "PROJECT_RCFLAGS := $(PROJECT_CFLAGS)\n" );
532 fprintf ( fMakefile, "PROJECT_WIDLFLAGS := $(PROJECT_CFLAGS)\n" );
533 fprintf ( fMakefile, "PROJECT_LFLAGS := %s\n",
534 GenerateProjectLFLAGS ().c_str () );
535 fprintf ( fMakefile, "PROJECT_CFLAGS += -Wall\n" );
536 fprintf ( fMakefile, "PROJECT_CFLAGS += $(PROJECT_GCCOPTIONS)\n" );
537 fprintf ( fMakefile, "\n" );
538 }
539
540 bool
541 MingwBackend::IncludeInAllTarget ( const Module& module ) const
542 {
543 if ( MingwModuleHandler::ReferenceObjects ( module ) )
544 return false;
545 if ( module.type == BootSector )
546 return false;
547 if ( module.type == Iso )
548 return false;
549 if ( module.type == LiveIso )
550 return false;
551 if ( module.type == Test )
552 return false;
553 return true;
554 }
555
556 void
557 MingwBackend::GenerateAllTarget ( const vector<MingwModuleHandler*>& handlers ) const
558 {
559 fprintf ( fMakefile, "all:" );
560 int wrap_count = 0;
561 size_t iend = handlers.size ();
562 for ( size_t i = 0; i < iend; i++ )
563 {
564 const Module& module = handlers[i]->module;
565 if ( IncludeInAllTarget ( module ) )
566 {
567 if ( wrap_count++ == 5 )
568 fprintf ( fMakefile, " \\\n\t\t" ), wrap_count = 0;
569 fprintf ( fMakefile,
570 " %s",
571 GetTargetMacro(module).c_str () );
572 }
573 }
574 fprintf ( fMakefile, "\n\t\n\n" );
575 }
576
577 string
578 MingwBackend::GetBuildToolDependencies () const
579 {
580 string dependencies;
581 for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
582 {
583 Module& module = *ProjectNode.modules[i];
584 if ( !module.enabled )
585 continue;
586 if ( module.type == BuildTool )
587 {
588 if ( dependencies.length () > 0 )
589 dependencies += " ";
590 dependencies += module.GetDependencyPath ();
591 }
592 }
593 return dependencies;
594 }
595
596 void
597 MingwBackend::GenerateInitTarget () const
598 {
599 fprintf ( fMakefile,
600 "INIT = %s\n",
601 GetBuildToolDependencies ().c_str () );
602 fprintf ( fMakefile, "\n" );
603 }
604
605 void
606 MingwBackend::GenerateRegTestsRunTarget () const
607 {
608 fprintf ( fMakefile,
609 "REGTESTS_RUN_TARGET = regtests.dll\n" );
610 fprintf ( fMakefile,
611 "$(REGTESTS_RUN_TARGET): $(REGTESTS_TARGET)\n" );
612 fprintf ( fMakefile,
613 "\t$(cp) $(REGTESTS_TARGET) $(REGTESTS_RUN_TARGET)\n" );
614 fprintf ( fMakefile, "\n" );
615 }
616
617 void
618 MingwBackend::GenerateXmlBuildFilesMacro() const
619 {
620 fprintf ( fMakefile,
621 "XMLBUILDFILES = %s \\\n",
622 ProjectNode.GetProjectFilename ().c_str () );
623 string xmlbuildFilenames;
624 int numberOfExistingFiles = 0;
625 for ( size_t i = 0; i < ProjectNode.xmlbuildfiles.size (); i++ )
626 {
627 XMLInclude& xmlbuildfile = *ProjectNode.xmlbuildfiles[i];
628 if ( !xmlbuildfile.fileExists )
629 continue;
630 numberOfExistingFiles++;
631 if ( xmlbuildFilenames.length () > 0 )
632 xmlbuildFilenames += " ";
633 xmlbuildFilenames += NormalizeFilename ( xmlbuildfile.topIncludeFilename );
634 if ( numberOfExistingFiles % 5 == 4 || i == ProjectNode.xmlbuildfiles.size () - 1 )
635 {
636 fprintf ( fMakefile,
637 "\t%s",
638 xmlbuildFilenames.c_str ());
639 if ( i == ProjectNode.xmlbuildfiles.size () - 1 )
640 {
641 fprintf ( fMakefile, "\n" );
642 }
643 else
644 {
645 fprintf ( fMakefile,
646 " \\\n" );
647 }
648 xmlbuildFilenames.resize ( 0 );
649 }
650 numberOfExistingFiles++;
651 }
652 fprintf ( fMakefile, "\n" );
653 }
654
655 string
656 MingwBackend::GetBin2ResExecutable ()
657 {
658 return NormalizeFilename ( Environment::GetOutputPath () + SSEP + "tools/bin2res/bin2res" + EXEPOSTFIX );
659 }
660
661 void
662 MingwBackend::UnpackWineResources ()
663 {
664 printf ( "Unpacking WINE resources..." );
665 WineResource wineResource ( ProjectNode,
666 GetBin2ResExecutable () );
667 wineResource.UnpackResources ( configuration.Verbose );
668 printf ( "done\n" );
669 }
670
671 void
672 MingwBackend::GenerateTestSupportCode ()
673 {
674 printf ( "Generating test support code..." );
675 TestSupportCode testSupportCode ( ProjectNode );
676 testSupportCode.GenerateTestSupportCode ( configuration.Verbose );
677 printf ( "done\n" );
678 }
679
680 string
681 MingwBackend::GetProxyMakefileTree () const
682 {
683 if ( configuration.GenerateProxyMakefilesInSourceTree )
684 return "";
685 else
686 return Environment::GetOutputPath ();
687 }
688
689 void
690 MingwBackend::GenerateProxyMakefiles ()
691 {
692 printf ( "Generating proxy makefiles..." );
693 ProxyMakefile proxyMakefile ( ProjectNode );
694 proxyMakefile.GenerateProxyMakefiles ( configuration.Verbose,
695 GetProxyMakefileTree () );
696 printf ( "done\n" );
697 }
698
699 void
700 MingwBackend::CheckAutomaticDependencies ()
701 {
702 if ( configuration.AutomaticDependencies )
703 {
704 printf ( "Checking automatic dependencies..." );
705 AutomaticDependency automaticDependency ( ProjectNode );
706 automaticDependency.CheckAutomaticDependencies ( configuration.Verbose );
707 printf ( "done\n" );
708 }
709 }
710
711 bool
712 MingwBackend::IncludeDirectoryTarget ( const string& directory ) const
713 {
714 if ( directory == "$(INTERMEDIATE)" SSEP "tools")
715 return false;
716 else
717 return true;
718 }
719
720 void
721 MingwBackend::GenerateDirectories ()
722 {
723 printf ( "Creating directories..." );
724 intermediateDirectory->GenerateTree ( "", configuration.Verbose );
725 outputDirectory->GenerateTree ( "", configuration.Verbose );
726 if ( !configuration.MakeHandlesInstallDirectories )
727 installDirectory->GenerateTree ( "", configuration.Verbose );
728 printf ( "done\n" );
729 }
730
731 bool
732 MingwBackend::TryToDetectThisCompiler ( const string& compiler )
733 {
734 string command = ssprintf (
735 "%s -v 1>%s 2>%s",
736 compiler.c_str (),
737 NUL,
738 NUL );
739 int exitcode = system ( command.c_str () );
740 return (exitcode == 0);
741 }
742
743 void
744 MingwBackend::DetectCompiler ()
745 {
746 printf ( "Detecting compiler..." );
747
748 bool detectedCompiler = false;
749 const string& ROS_PREFIXValue = Environment::GetVariable ( "ROS_PREFIX" );
750 if ( ROS_PREFIXValue.length () > 0 )
751 {
752 compilerPrefix = ROS_PREFIXValue;
753 compilerCommand = compilerPrefix + "-gcc";
754 detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
755 }
756 #if defined(WIN32)
757 if ( !detectedCompiler )
758 {
759 compilerPrefix = "";
760 compilerCommand = "gcc";
761 detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
762 }
763 #endif
764 if ( !detectedCompiler )
765 {
766 compilerPrefix = "mingw32";
767 compilerCommand = compilerPrefix + "-gcc";
768 detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
769 }
770 if ( detectedCompiler )
771 printf ( "detected (%s)\n", compilerCommand.c_str () );
772 else
773 printf ( "not detected\n" );
774 }
775
776 bool
777 MingwBackend::TryToDetectThisNetwideAssembler ( const string& assembler )
778 {
779 string command = ssprintf (
780 "%s -h 1>%s 2>%s",
781 assembler.c_str (),
782 NUL,
783 NUL );
784 int exitcode = system ( command.c_str () );
785 return (exitcode == 0);
786 }
787
788 void
789 MingwBackend::DetectNetwideAssembler ()
790 {
791 printf ( "Detecting netwide assembler..." );
792
793 nasmCommand = "nasm";
794 bool detectedNasm = TryToDetectThisNetwideAssembler ( nasmCommand );
795 #if defined(WIN32)
796 if ( !detectedNasm )
797 {
798 nasmCommand = "nasmw";
799 detectedNasm = TryToDetectThisNetwideAssembler ( nasmCommand );
800 }
801 #endif
802 if ( detectedNasm )
803 printf ( "detected (%s)\n", nasmCommand.c_str () );
804 else
805 printf ( "not detected\n" );
806 }
807
808 void
809 MingwBackend::DetectPipeSupport ()
810 {
811 printf ( "Detecting compiler -pipe support..." );
812
813 string pipe_detection = "tools" SSEP "rbuild" SSEP "backend" SSEP "mingw" SSEP "pipe_detection.c";
814 string pipe_detectionObjectFilename = ReplaceExtension ( pipe_detection,
815 ".o" );
816 string command = ssprintf (
817 "%s -pipe -c %s -o %s 1>%s 2>%s",
818 compilerCommand.c_str (),
819 pipe_detection.c_str (),
820 pipe_detectionObjectFilename.c_str (),
821 NUL,
822 NUL );
823 int exitcode = system ( command.c_str () );
824 FILE* f = fopen ( pipe_detectionObjectFilename.c_str (), "rb" );
825 if ( f )
826 {
827 usePipe = (exitcode == 0);
828 fclose ( f );
829 unlink ( pipe_detectionObjectFilename.c_str () );
830 }
831 else
832 usePipe = false;
833
834 if ( usePipe )
835 printf ( "detected\n" );
836 else
837 printf ( "not detected\n" );
838 }
839
840 void
841 MingwBackend::DetectPCHSupport ()
842 {
843 printf ( "Detecting compiler pre-compiled header support..." );
844
845 string path = "tools" SSEP "rbuild" SSEP "backend" SSEP "mingw" SSEP "pch_detection.h";
846 string cmd = ssprintf (
847 "%s -c %s 1>%s 2>%s",
848 compilerCommand.c_str (),
849 path.c_str (),
850 NUL,
851 NUL );
852 system ( cmd.c_str () );
853 path += ".gch";
854
855 FILE* f = fopen ( path.c_str (), "rb" );
856 if ( f )
857 {
858 use_pch = true;
859 fclose ( f );
860 unlink ( path.c_str () );
861 }
862 else
863 use_pch = false;
864
865 if ( use_pch )
866 printf ( "detected\n" );
867 else
868 printf ( "not detected\n" );
869 }
870
871 void
872 MingwBackend::GetNonModuleInstallTargetFiles (
873 vector<string>& out ) const
874 {
875 for ( size_t i = 0; i < ProjectNode.installfiles.size (); i++ )
876 {
877 const InstallFile& installfile = *ProjectNode.installfiles[i];
878 string targetFilenameNoFixup = installfile.base + SSEP + installfile.newname;
879 string targetFilename = MingwModuleHandler::PassThruCacheDirectory (
880 NormalizeFilename ( targetFilenameNoFixup ),
881 installDirectory );
882 out.push_back ( targetFilename );
883 }
884 }
885
886 void
887 MingwBackend::GetModuleInstallTargetFiles (
888 vector<string>& out ) const
889 {
890 for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
891 {
892 const Module& module = *ProjectNode.modules[i];
893 if ( !module.enabled )
894 continue;
895 if ( module.installName.length () > 0 )
896 {
897 string targetFilenameNoFixup;
898 if ( module.installBase.length () > 0 )
899 targetFilenameNoFixup = module.installBase + SSEP + module.installName;
900 else
901 targetFilenameNoFixup = module.installName;
902 string targetFilename = MingwModuleHandler::PassThruCacheDirectory (
903 NormalizeFilename ( targetFilenameNoFixup ),
904 installDirectory );
905 out.push_back ( targetFilename );
906 }
907 }
908 }
909
910 void
911 MingwBackend::GetInstallTargetFiles (
912 vector<string>& out ) const
913 {
914 GetNonModuleInstallTargetFiles ( out );
915 GetModuleInstallTargetFiles ( out );
916 }
917
918 void
919 MingwBackend::OutputInstallTarget ( const string& sourceFilename,
920 const string& targetFilename,
921 const string& targetDirectory )
922 {
923 string fullTargetFilename;
924 if ( targetDirectory.length () > 0)
925 fullTargetFilename = targetDirectory + SSEP + targetFilename;
926 else
927 fullTargetFilename = targetFilename;
928 string normalizedTargetFilename = MingwModuleHandler::PassThruCacheDirectory (
929 NormalizeFilename ( fullTargetFilename ),
930 installDirectory );
931 string normalizedTargetDirectory = MingwModuleHandler::PassThruCacheDirectory (
932 NormalizeFilename ( targetDirectory ),
933 installDirectory );
934 fprintf ( fMakefile,
935 "%s: %s | %s\n",
936 normalizedTargetFilename.c_str (),
937 sourceFilename.c_str (),
938 normalizedTargetDirectory.c_str () );
939 fprintf ( fMakefile,
940 "\t$(ECHO_CP)\n" );
941 fprintf ( fMakefile,
942 "\t${cp} %s %s 1>$(NUL)\n",
943 sourceFilename.c_str (),
944 normalizedTargetFilename.c_str () );
945 }
946
947 void
948 MingwBackend::OutputNonModuleInstallTargets ()
949 {
950 for ( size_t i = 0; i < ProjectNode.installfiles.size (); i++ )
951 {
952 const InstallFile& installfile = *ProjectNode.installfiles[i];
953 OutputInstallTarget ( installfile.GetPath (),
954 installfile.newname,
955 installfile.base );
956 }
957 }
958
959 void
960 MingwBackend::OutputModuleInstallTargets ()
961 {
962 for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
963 {
964 const Module& module = *ProjectNode.modules[i];
965 if ( !module.enabled )
966 continue;
967 if ( module.installName.length () > 0 )
968 {
969 string sourceFilename = MingwModuleHandler::PassThruCacheDirectory (
970 NormalizeFilename ( module.GetPath () ),
971 outputDirectory );
972 OutputInstallTarget ( sourceFilename,
973 module.installName,
974 module.installBase );
975 }
976 }
977 }
978
979 string
980 MingwBackend::GetRegistrySourceFiles ()
981 {
982 return "bootdata" SSEP "hivecls.inf "
983 "bootdata" SSEP "hivedef.inf "
984 "bootdata" SSEP "hiveinst.inf "
985 "bootdata" SSEP "hivesft.inf "
986 "bootdata" SSEP "hivesys.inf";
987 }
988
989 string
990 MingwBackend::GetRegistryTargetFiles ()
991 {
992 string system32ConfigDirectory = NormalizeFilename (
993 MingwModuleHandler::PassThruCacheDirectory (
994 "system32" SSEP "config" SSEP,
995 installDirectory ) );
996 return system32ConfigDirectory + SSEP "default " +
997 system32ConfigDirectory + SSEP "sam " +
998 system32ConfigDirectory + SSEP "security " +
999 system32ConfigDirectory + SSEP "software " +
1000 system32ConfigDirectory + SSEP "system";
1001 }
1002
1003 void
1004 MingwBackend::OutputRegistryInstallTarget ()
1005 {
1006 string system32ConfigDirectory = NormalizeFilename (
1007 MingwModuleHandler::PassThruCacheDirectory (
1008 "system32" SSEP "config" SSEP,
1009 installDirectory ) );
1010
1011 string registrySourceFiles = GetRegistrySourceFiles ();
1012 string registryTargetFiles = GetRegistryTargetFiles ();
1013 fprintf ( fMakefile,
1014 "install_registry: %s\n",
1015 registryTargetFiles.c_str () );
1016 fprintf ( fMakefile,
1017 "%s: %s %s $(MKHIVE_TARGET)\n",
1018 registryTargetFiles.c_str (),
1019 registrySourceFiles.c_str (),
1020 system32ConfigDirectory.c_str () );
1021 fprintf ( fMakefile,
1022 "\t$(ECHO_MKHIVE)\n" );
1023 fprintf ( fMakefile,
1024 "\t$(MKHIVE_TARGET) bootdata %s bootdata" SSEP "hiveinst.inf\n",
1025 system32ConfigDirectory.c_str () );
1026 fprintf ( fMakefile,
1027 "\n" );
1028 }
1029
1030 void
1031 MingwBackend::GenerateInstallTarget ()
1032 {
1033 vector<string> vInstallTargetFiles;
1034 GetInstallTargetFiles ( vInstallTargetFiles );
1035 string installTargetFiles = v2s ( vInstallTargetFiles, 5 );
1036 string registryTargetFiles = GetRegistryTargetFiles ();
1037
1038 fprintf ( fMakefile,
1039 "install: %s %s\n",
1040 installTargetFiles.c_str (),
1041 registryTargetFiles.c_str () );
1042 OutputNonModuleInstallTargets ();
1043 OutputModuleInstallTargets ();
1044 OutputRegistryInstallTarget ();
1045 fprintf ( fMakefile,
1046 "\n" );
1047 }
1048
1049 void
1050 MingwBackend::GetModuleTestTargets (
1051 vector<string>& out ) const
1052 {
1053 for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
1054 {
1055 const Module& module = *ProjectNode.modules[i];
1056 if ( !module.enabled )
1057 continue;
1058 if ( module.type == Test )
1059 out.push_back ( module.name );
1060 }
1061 }
1062
1063 void
1064 MingwBackend::GenerateTestTarget ()
1065 {
1066 vector<string> vTestTargets;
1067 GetModuleTestTargets ( vTestTargets );
1068 string testTargets = v2s ( vTestTargets, 5 );
1069
1070 fprintf ( fMakefile,
1071 "test: %s\n",
1072 testTargets.c_str () );
1073 fprintf ( fMakefile,
1074 "\n" );
1075 }
1076
1077 void
1078 MingwBackend::GenerateDirectoryTargets ()
1079 {
1080 intermediateDirectory->CreateRule ( fMakefile, "" );
1081 outputDirectory->CreateRule ( fMakefile, "" );
1082 installDirectory->CreateRule ( fMakefile, "" );
1083 }