9b8a970c5b95efff3653cca5513e2bfe8ae6248c
[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 delete v[i];
297 }
298
299 printf ( "done\n" );
300 }
301
302 void
303 MingwBackend::Process ()
304 {
305 DetectCompiler ();
306 DetectNetwideAssembler ();
307 DetectPipeSupport ();
308 DetectPCHSupport ();
309 CreateMakefile ();
310 GenerateHeader ();
311 GenerateGlobalVariables ();
312 GenerateXmlBuildFilesMacro ();
313 ProcessModules ();
314 GenerateInstallTarget ();
315 GenerateTestTarget ();
316 GenerateDirectoryTargets ();
317 GenerateDirectories ();
318 UnpackWineResources ();
319 GenerateTestSupportCode ();
320 GenerateProxyMakefiles ();
321 CheckAutomaticDependencies ();
322 CloseMakefile ();
323 }
324
325 void
326 MingwBackend::CreateMakefile ()
327 {
328 fMakefile = fopen ( ProjectNode.makefile.c_str (), "w" );
329 if ( !fMakefile )
330 throw AccessDeniedException ( ProjectNode.makefile );
331 MingwModuleHandler::SetBackend ( this );
332 MingwModuleHandler::SetMakefile ( fMakefile );
333 MingwModuleHandler::SetUsePch ( use_pch );
334 }
335
336 void
337 MingwBackend::CloseMakefile () const
338 {
339 if (fMakefile)
340 fclose ( fMakefile );
341 }
342
343 void
344 MingwBackend::GenerateHeader () const
345 {
346 fprintf ( fMakefile, "# THIS FILE IS AUTOMATICALLY GENERATED, EDIT 'ReactOS.xml' INSTEAD\n\n" );
347 }
348
349 string
350 MingwBackend::GenerateIncludesAndDefines ( IfableData& data ) const
351 {
352 string includeParameters = MingwModuleHandler::GenerateGccIncludeParametersFromVector ( data.includes );
353 string defineParameters = MingwModuleHandler::GenerateGccDefineParametersFromVector ( data.defines );
354 return includeParameters + " " + defineParameters;
355 }
356
357 void
358 MingwBackend::GenerateProjectCFlagsMacro ( const char* assignmentOperation,
359 IfableData& data ) const
360 {
361 fprintf (
362 fMakefile,
363 "PROJECT_CFLAGS %s",
364 assignmentOperation );
365
366 fprintf ( fMakefile,
367 " %s",
368 GenerateIncludesAndDefines ( data ).c_str() );
369
370 fprintf ( fMakefile, "\n" );
371 }
372
373 void
374 MingwBackend::GenerateGlobalCFlagsAndProperties (
375 const char* assignmentOperation,
376 IfableData& data ) const
377 {
378 size_t i;
379
380 for ( i = 0; i < data.properties.size(); i++ )
381 {
382 Property& prop = *data.properties[i];
383 fprintf ( fMakefile, "%s := %s\n",
384 prop.name.c_str(),
385 prop.value.c_str() );
386 }
387
388 if ( data.includes.size() || data.defines.size() )
389 {
390 GenerateProjectCFlagsMacro ( assignmentOperation,
391 data );
392 }
393
394 for ( i = 0; i < data.ifs.size(); i++ )
395 {
396 If& rIf = *data.ifs[i];
397 if ( rIf.data.defines.size()
398 || rIf.data.includes.size()
399 || rIf.data.ifs.size() )
400 {
401 fprintf (
402 fMakefile,
403 "ifeq (\"$(%s)\",\"%s\")\n",
404 rIf.property.c_str(),
405 rIf.value.c_str() );
406 GenerateGlobalCFlagsAndProperties (
407 "+=",
408 rIf.data );
409 fprintf (
410 fMakefile,
411 "endif\n\n" );
412 }
413 }
414 }
415
416 void
417 MingwBackend::GenerateProjectGccOptionsMacro ( const char* assignmentOperation,
418 IfableData& data ) const
419 {
420 size_t i;
421
422 fprintf (
423 fMakefile,
424 "PROJECT_GCCOPTIONS %s",
425 assignmentOperation );
426
427 for ( i = 0; i < data.compilerFlags.size(); i++ )
428 {
429 fprintf (
430 fMakefile,
431 " %s",
432 data.compilerFlags[i]->flag.c_str() );
433 }
434
435 fprintf ( fMakefile, "\n" );
436 }
437
438 void
439 MingwBackend::GenerateProjectGccOptions (
440 const char* assignmentOperation,
441 IfableData& data ) const
442 {
443 size_t i;
444
445 if ( data.compilerFlags.size() )
446 {
447 GenerateProjectGccOptionsMacro ( assignmentOperation,
448 data );
449 }
450
451 for ( i = 0; i < data.ifs.size(); i++ )
452 {
453 If& rIf = *data.ifs[i];
454 if ( rIf.data.compilerFlags.size()
455 || rIf.data.ifs.size() )
456 {
457 fprintf (
458 fMakefile,
459 "ifeq (\"$(%s)\",\"%s\")\n",
460 rIf.property.c_str(),
461 rIf.value.c_str() );
462 GenerateProjectGccOptions (
463 "+=",
464 rIf.data );
465 fprintf (
466 fMakefile,
467 "endif\n\n" );
468 }
469 }
470 }
471
472 string
473 MingwBackend::GenerateProjectLFLAGS () const
474 {
475 string lflags;
476 for ( size_t i = 0; i < ProjectNode.linkerFlags.size (); i++ )
477 {
478 LinkerFlag& linkerFlag = *ProjectNode.linkerFlags[i];
479 if ( lflags.length () > 0 )
480 lflags += " ";
481 lflags += linkerFlag.flag;
482 }
483 return lflags;
484 }
485
486 void
487 MingwBackend::GenerateGlobalVariables () const
488 {
489 fprintf ( fMakefile,
490 "PREFIX := %s\n",
491 compilerPrefix.c_str () );
492 fprintf ( fMakefile,
493 "nasm := %s\n",
494 nasmCommand.c_str () );
495
496 GenerateGlobalCFlagsAndProperties ( "=", ProjectNode.non_if_data );
497 GenerateProjectGccOptions ( "=", ProjectNode.non_if_data );
498
499 fprintf ( fMakefile, "PROJECT_RCFLAGS := $(PROJECT_CFLAGS)\n" );
500 fprintf ( fMakefile, "PROJECT_WIDLFLAGS := $(PROJECT_CFLAGS)\n" );
501 fprintf ( fMakefile, "PROJECT_LFLAGS := %s\n",
502 GenerateProjectLFLAGS ().c_str () );
503 fprintf ( fMakefile, "PROJECT_CFLAGS += -Wall\n" );
504 fprintf ( fMakefile, "PROJECT_CFLAGS += $(PROJECT_GCCOPTIONS)\n" );
505 fprintf ( fMakefile, "\n" );
506 }
507
508 bool
509 MingwBackend::IncludeInAllTarget ( const Module& module ) const
510 {
511 if ( MingwModuleHandler::ReferenceObjects ( module ) )
512 return false;
513 if ( module.type == BootSector )
514 return false;
515 if ( module.type == Iso )
516 return false;
517 if ( module.type == LiveIso )
518 return false;
519 if ( module.type == Test )
520 return false;
521 return true;
522 }
523
524 void
525 MingwBackend::GenerateAllTarget ( const vector<MingwModuleHandler*>& handlers ) const
526 {
527 fprintf ( fMakefile, "all:" );
528 int wrap_count = 0;
529 size_t iend = handlers.size ();
530 for ( size_t i = 0; i < iend; i++ )
531 {
532 const Module& module = handlers[i]->module;
533 if ( IncludeInAllTarget ( module ) )
534 {
535 if ( wrap_count++ == 5 )
536 fprintf ( fMakefile, " \\\n\t\t" ), wrap_count = 0;
537 fprintf ( fMakefile,
538 " %s",
539 GetTargetMacro(module).c_str () );
540 }
541 }
542 fprintf ( fMakefile, "\n\t\n\n" );
543 }
544
545 string
546 MingwBackend::GetBuildToolDependencies () const
547 {
548 string dependencies;
549 for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
550 {
551 Module& module = *ProjectNode.modules[i];
552 if ( !module.enabled )
553 continue;
554 if ( module.type == BuildTool )
555 {
556 if ( dependencies.length () > 0 )
557 dependencies += " ";
558 dependencies += module.GetDependencyPath ();
559 }
560 }
561 return dependencies;
562 }
563
564 void
565 MingwBackend::GenerateInitTarget () const
566 {
567 fprintf ( fMakefile,
568 "INIT = %s\n",
569 GetBuildToolDependencies ().c_str () );
570 fprintf ( fMakefile, "\n" );
571 }
572
573 void
574 MingwBackend::GenerateRegTestsRunTarget () const
575 {
576 fprintf ( fMakefile,
577 "REGTESTS_RUN_TARGET = regtests.dll\n" );
578 fprintf ( fMakefile,
579 "$(REGTESTS_RUN_TARGET):\n" );
580 fprintf ( fMakefile,
581 "\t$(cp) $(REGTESTS_TARGET) $(REGTESTS_RUN_TARGET)\n" );
582 fprintf ( fMakefile, "\n" );
583 }
584
585 void
586 MingwBackend::GenerateXmlBuildFilesMacro() const
587 {
588 fprintf ( fMakefile,
589 "XMLBUILDFILES = %s \\\n",
590 ProjectNode.GetProjectFilename ().c_str () );
591 string xmlbuildFilenames;
592 int numberOfExistingFiles = 0;
593 for ( size_t i = 0; i < ProjectNode.xmlbuildfiles.size (); i++ )
594 {
595 XMLInclude& xmlbuildfile = *ProjectNode.xmlbuildfiles[i];
596 if ( !xmlbuildfile.fileExists )
597 continue;
598 numberOfExistingFiles++;
599 if ( xmlbuildFilenames.length () > 0 )
600 xmlbuildFilenames += " ";
601 xmlbuildFilenames += NormalizeFilename ( xmlbuildfile.topIncludeFilename );
602 if ( numberOfExistingFiles % 5 == 4 || i == ProjectNode.xmlbuildfiles.size () - 1 )
603 {
604 fprintf ( fMakefile,
605 "\t%s",
606 xmlbuildFilenames.c_str ());
607 if ( i == ProjectNode.xmlbuildfiles.size () - 1 )
608 {
609 fprintf ( fMakefile, "\n" );
610 }
611 else
612 {
613 fprintf ( fMakefile,
614 " \\\n" );
615 }
616 xmlbuildFilenames.resize ( 0 );
617 }
618 numberOfExistingFiles++;
619 }
620 fprintf ( fMakefile, "\n" );
621 }
622
623 string
624 MingwBackend::GetBin2ResExecutable ()
625 {
626 return NormalizeFilename ( Environment::GetOutputPath () + SSEP + "tools/bin2res/bin2res" + EXEPOSTFIX );
627 }
628
629 void
630 MingwBackend::UnpackWineResources ()
631 {
632 printf ( "Unpacking WINE resources..." );
633 WineResource wineResource ( ProjectNode,
634 GetBin2ResExecutable () );
635 wineResource.UnpackResources ( configuration.Verbose );
636 printf ( "done\n" );
637 }
638
639 void
640 MingwBackend::GenerateTestSupportCode ()
641 {
642 printf ( "Generating test support code..." );
643 TestSupportCode testSupportCode ( ProjectNode );
644 testSupportCode.GenerateTestSupportCode ( configuration.Verbose );
645 printf ( "done\n" );
646 }
647
648 string
649 MingwBackend::GetProxyMakefileTree () const
650 {
651 if ( configuration.GenerateProxyMakefilesInSourceTree )
652 return "";
653 else
654 return Environment::GetOutputPath ();
655 }
656
657 void
658 MingwBackend::GenerateProxyMakefiles ()
659 {
660 printf ( "Generating proxy makefiles..." );
661 ProxyMakefile proxyMakefile ( ProjectNode );
662 proxyMakefile.GenerateProxyMakefiles ( configuration.Verbose,
663 GetProxyMakefileTree () );
664 printf ( "done\n" );
665 }
666
667 void
668 MingwBackend::CheckAutomaticDependencies ()
669 {
670 if ( configuration.AutomaticDependencies )
671 {
672 printf ( "Checking automatic dependencies..." );
673 AutomaticDependency automaticDependency ( ProjectNode );
674 automaticDependency.Process ();
675 automaticDependency.CheckAutomaticDependencies ( configuration.Verbose );
676 printf ( "done\n" );
677 }
678 }
679
680 bool
681 MingwBackend::IncludeDirectoryTarget ( const string& directory ) const
682 {
683 if ( directory == "$(INTERMEDIATE)" SSEP "tools")
684 return false;
685 else
686 return true;
687 }
688
689 void
690 MingwBackend::GenerateDirectories ()
691 {
692 printf ( "Creating directories..." );
693 intermediateDirectory->GenerateTree ( "", configuration.Verbose );
694 outputDirectory->GenerateTree ( "", configuration.Verbose );
695 if ( !configuration.MakeHandlesInstallDirectories )
696 installDirectory->GenerateTree ( "", configuration.Verbose );
697 printf ( "done\n" );
698 }
699
700 bool
701 MingwBackend::TryToDetectThisCompiler ( const string& compiler )
702 {
703 string command = ssprintf (
704 "%s -v 1>%s 2>%s",
705 compiler.c_str (),
706 NUL,
707 NUL );
708 int exitcode = system ( command.c_str () );
709 return (exitcode == 0);
710 }
711
712 void
713 MingwBackend::DetectCompiler ()
714 {
715 printf ( "Detecting compiler..." );
716
717 bool detectedCompiler = false;
718 const string& ROS_PREFIXValue = Environment::GetVariable ( "ROS_PREFIX" );
719 if ( ROS_PREFIXValue.length () > 0 )
720 {
721 compilerPrefix = ROS_PREFIXValue;
722 compilerCommand = compilerPrefix + "-gcc";
723 detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
724 }
725 #if defined(WIN32)
726 if ( !detectedCompiler )
727 {
728 compilerPrefix = "";
729 compilerCommand = "gcc";
730 detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
731 }
732 #endif
733 if ( !detectedCompiler )
734 {
735 compilerPrefix = "mingw32";
736 compilerCommand = compilerPrefix + "-gcc";
737 detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
738 }
739 if ( detectedCompiler )
740 printf ( "detected (%s)\n", compilerCommand.c_str () );
741 else
742 printf ( "not detected\n" );
743 }
744
745 bool
746 MingwBackend::TryToDetectThisNetwideAssembler ( const string& assembler )
747 {
748 string command = ssprintf (
749 "%s -h 1>%s 2>%s",
750 assembler.c_str (),
751 NUL,
752 NUL );
753 int exitcode = system ( command.c_str () );
754 return (exitcode == 0);
755 }
756
757 void
758 MingwBackend::DetectNetwideAssembler ()
759 {
760 printf ( "Detecting netwide assembler..." );
761
762 nasmCommand = "nasm";
763 bool detectedNasm = TryToDetectThisNetwideAssembler ( nasmCommand );
764 #if defined(WIN32)
765 if ( !detectedNasm )
766 {
767 nasmCommand = "nasmw";
768 detectedNasm = TryToDetectThisNetwideAssembler ( nasmCommand );
769 }
770 #endif
771 if ( detectedNasm )
772 printf ( "detected (%s)\n", nasmCommand.c_str () );
773 else
774 printf ( "not detected\n" );
775 }
776
777 void
778 MingwBackend::DetectPipeSupport ()
779 {
780 printf ( "Detecting compiler -pipe support..." );
781
782 string pipe_detection = "tools" SSEP "rbuild" SSEP "backend" SSEP "mingw" SSEP "pipe_detection.c";
783 string pipe_detectionObjectFilename = ReplaceExtension ( pipe_detection,
784 ".o" );
785 string command = ssprintf (
786 "%s -pipe -c %s -o %s 1>%s 2>%s",
787 compilerCommand.c_str (),
788 pipe_detection.c_str (),
789 pipe_detectionObjectFilename.c_str (),
790 NUL,
791 NUL );
792 int exitcode = system ( command.c_str () );
793 FILE* f = fopen ( pipe_detectionObjectFilename.c_str (), "rb" );
794 if ( f )
795 {
796 usePipe = (exitcode == 0);
797 fclose ( f );
798 unlink ( pipe_detectionObjectFilename.c_str () );
799 }
800 else
801 usePipe = false;
802
803 if ( usePipe )
804 printf ( "detected\n" );
805 else
806 printf ( "not detected\n" );
807 }
808
809 void
810 MingwBackend::DetectPCHSupport ()
811 {
812 printf ( "Detecting compiler pre-compiled header support..." );
813
814 string path = "tools" SSEP "rbuild" SSEP "backend" SSEP "mingw" SSEP "pch_detection.h";
815 string cmd = ssprintf (
816 "%s -c %s 1>%s 2>%s",
817 compilerCommand.c_str (),
818 path.c_str (),
819 NUL,
820 NUL );
821 system ( cmd.c_str () );
822 path += ".gch";
823
824 FILE* f = fopen ( path.c_str (), "rb" );
825 if ( f )
826 {
827 use_pch = true;
828 fclose ( f );
829 unlink ( path.c_str () );
830 }
831 else
832 use_pch = false;
833
834 if ( use_pch )
835 printf ( "detected\n" );
836 else
837 printf ( "not detected\n" );
838 }
839
840 void
841 MingwBackend::GetNonModuleInstallTargetFiles (
842 vector<string>& out ) const
843 {
844 for ( size_t i = 0; i < ProjectNode.installfiles.size (); i++ )
845 {
846 const InstallFile& installfile = *ProjectNode.installfiles[i];
847 string targetFilenameNoFixup = installfile.base + SSEP + installfile.newname;
848 string targetFilename = MingwModuleHandler::PassThruCacheDirectory (
849 NormalizeFilename ( targetFilenameNoFixup ),
850 installDirectory );
851 out.push_back ( targetFilename );
852 }
853 }
854
855 void
856 MingwBackend::GetModuleInstallTargetFiles (
857 vector<string>& out ) const
858 {
859 for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
860 {
861 const Module& module = *ProjectNode.modules[i];
862 if ( !module.enabled )
863 continue;
864 if ( module.installName.length () > 0 )
865 {
866 string targetFilenameNoFixup;
867 if ( module.installBase.length () > 0 )
868 targetFilenameNoFixup = module.installBase + SSEP + module.installName;
869 else
870 targetFilenameNoFixup = module.installName;
871 string targetFilename = MingwModuleHandler::PassThruCacheDirectory (
872 NormalizeFilename ( targetFilenameNoFixup ),
873 installDirectory );
874 out.push_back ( targetFilename );
875 }
876 }
877 }
878
879 void
880 MingwBackend::GetInstallTargetFiles (
881 vector<string>& out ) const
882 {
883 GetNonModuleInstallTargetFiles ( out );
884 GetModuleInstallTargetFiles ( out );
885 }
886
887 void
888 MingwBackend::OutputInstallTarget ( const string& sourceFilename,
889 const string& targetFilename,
890 const string& targetDirectory )
891 {
892 string fullTargetFilename;
893 if ( targetDirectory.length () > 0)
894 fullTargetFilename = targetDirectory + SSEP + targetFilename;
895 else
896 fullTargetFilename = targetFilename;
897 string normalizedTargetFilename = MingwModuleHandler::PassThruCacheDirectory (
898 NormalizeFilename ( fullTargetFilename ),
899 installDirectory );
900 string normalizedTargetDirectory = MingwModuleHandler::PassThruCacheDirectory (
901 NormalizeFilename ( targetDirectory ),
902 installDirectory );
903 fprintf ( fMakefile,
904 "%s: %s | %s\n",
905 normalizedTargetFilename.c_str (),
906 sourceFilename.c_str (),
907 normalizedTargetDirectory.c_str () );
908 fprintf ( fMakefile,
909 "\t$(ECHO_CP)\n" );
910 fprintf ( fMakefile,
911 "\t${cp} %s %s 1>$(NUL)\n",
912 sourceFilename.c_str (),
913 normalizedTargetFilename.c_str () );
914 }
915
916 void
917 MingwBackend::OutputNonModuleInstallTargets ()
918 {
919 for ( size_t i = 0; i < ProjectNode.installfiles.size (); i++ )
920 {
921 const InstallFile& installfile = *ProjectNode.installfiles[i];
922 OutputInstallTarget ( installfile.GetPath (),
923 installfile.newname,
924 installfile.base );
925 }
926 }
927
928 void
929 MingwBackend::OutputModuleInstallTargets ()
930 {
931 for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
932 {
933 const Module& module = *ProjectNode.modules[i];
934 if ( !module.enabled )
935 continue;
936 if ( module.installName.length () > 0 )
937 {
938 string sourceFilename = MingwModuleHandler::PassThruCacheDirectory (
939 NormalizeFilename ( module.GetPath () ),
940 outputDirectory );
941 OutputInstallTarget ( sourceFilename,
942 module.installName,
943 module.installBase );
944 }
945 }
946 }
947
948 string
949 MingwBackend::GetRegistrySourceFiles ()
950 {
951 return "bootdata" SSEP "hivecls.inf "
952 "bootdata" SSEP "hivedef.inf "
953 "bootdata" SSEP "hiveinst.inf "
954 "bootdata" SSEP "hivesft.inf "
955 "bootdata" SSEP "hivesys.inf";
956 }
957
958 string
959 MingwBackend::GetRegistryTargetFiles ()
960 {
961 string system32ConfigDirectory = NormalizeFilename (
962 MingwModuleHandler::PassThruCacheDirectory (
963 "system32" SSEP "config" SSEP,
964 installDirectory ) );
965 return system32ConfigDirectory + SSEP "default " +
966 system32ConfigDirectory + SSEP "sam " +
967 system32ConfigDirectory + SSEP "security " +
968 system32ConfigDirectory + SSEP "software " +
969 system32ConfigDirectory + SSEP "system";
970 }
971
972 void
973 MingwBackend::OutputRegistryInstallTarget ()
974 {
975 string system32ConfigDirectory = NormalizeFilename (
976 MingwModuleHandler::PassThruCacheDirectory (
977 "system32" SSEP "config" SSEP,
978 installDirectory ) );
979
980 string registrySourceFiles = GetRegistrySourceFiles ();
981 string registryTargetFiles = GetRegistryTargetFiles ();
982 fprintf ( fMakefile,
983 "install_registry: %s\n",
984 registryTargetFiles.c_str () );
985 fprintf ( fMakefile,
986 "%s: %s %s $(MKHIVE_TARGET)\n",
987 registryTargetFiles.c_str (),
988 registrySourceFiles.c_str (),
989 system32ConfigDirectory.c_str () );
990 fprintf ( fMakefile,
991 "\t$(ECHO_MKHIVE)\n" );
992 fprintf ( fMakefile,
993 "\t$(MKHIVE_TARGET) bootdata %s bootdata" SSEP "hiveinst.inf\n",
994 system32ConfigDirectory.c_str () );
995 fprintf ( fMakefile,
996 "\n" );
997 }
998
999 void
1000 MingwBackend::GenerateInstallTarget ()
1001 {
1002 vector<string> vInstallTargetFiles;
1003 GetInstallTargetFiles ( vInstallTargetFiles );
1004 string installTargetFiles = v2s ( vInstallTargetFiles, 5 );
1005 string registryTargetFiles = GetRegistryTargetFiles ();
1006
1007 fprintf ( fMakefile,
1008 "install: %s %s\n",
1009 installTargetFiles.c_str (),
1010 registryTargetFiles.c_str () );
1011 OutputNonModuleInstallTargets ();
1012 OutputModuleInstallTargets ();
1013 OutputRegistryInstallTarget ();
1014 fprintf ( fMakefile,
1015 "\n" );
1016 }
1017
1018 void
1019 MingwBackend::GetModuleTestTargets (
1020 vector<string>& out ) const
1021 {
1022 for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
1023 {
1024 const Module& module = *ProjectNode.modules[i];
1025 if ( !module.enabled )
1026 continue;
1027 if ( module.type == Test )
1028 out.push_back ( module.name );
1029 }
1030 }
1031
1032 void
1033 MingwBackend::GenerateTestTarget ()
1034 {
1035 vector<string> vTestTargets;
1036 GetModuleTestTargets ( vTestTargets );
1037 string testTargets = v2s ( vTestTargets, 5 );
1038
1039 fprintf ( fMakefile,
1040 "test: %s\n",
1041 testTargets.c_str () );
1042 fprintf ( fMakefile,
1043 "\n" );
1044 }
1045
1046 void
1047 MingwBackend::GenerateDirectoryTargets ()
1048 {
1049 intermediateDirectory->CreateRule ( fMakefile, "" );
1050 outputDirectory->CreateRule ( fMakefile, "" );
1051 installDirectory->CreateRule ( fMakefile, "" );
1052 }