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