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