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