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