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