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