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