Undo r37623 until cross compilation is fixed
[reactos.git] / reactos / tools / rbuild / backend / mingw / mingw.cpp
1 /*
2 * Copyright (C) 2005 Casper S. Hornstrup
3 * 2006 Christoph von Wittich
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 #include "../../pch.h"
20
21 #include "mingw.h"
22 #include <assert.h>
23 #include "modulehandler.h"
24
25 #ifdef _MSC_VER
26 #define popen _popen
27 #define pclose _pclose
28 #endif//_MSC_VER
29
30 using std::string;
31 using std::vector;
32 using std::set;
33 using std::map;
34
35 typedef set<string> set_string;
36
37 const struct ModuleHandlerInformations ModuleHandlerInformations[] = {
38 { HostTrue, "", "", "" }, // BuildTool
39 { HostFalse, "", "", "" }, // StaticLibrary
40 { HostFalse, "", "", "" }, // ObjectLibrary
41 { HostFalse, "", "", "" }, // Kernel
42 { HostFalse, "", "", "" }, // KernelModeDLL
43 { HostFalse, "-D__NTDRIVER__", "", "" }, // KernelModeDriver
44 { HostFalse, "", "", "" }, // NativeDLL
45 { HostFalse, "-D__NTAPP__", "", "" }, // NativeCUI
46 { HostFalse, "", "", "" }, // Win32DLL
47 { HostFalse, "", "", "" }, // Win32OCX
48 { HostFalse, "", "", "" }, // Win32CUI
49 { HostFalse, "", "", "" }, // Win32GUI
50 { HostFalse, "", "", "-nostartfiles -nostdlib" }, // BootLoader
51 { HostFalse, "", "-f bin", "" }, // BootSector
52 { HostFalse, "", "", "" }, // Iso
53 { HostFalse, "", "", "" }, // LiveIso
54 { HostFalse, "", "", "" }, // Test
55 { HostFalse, "", "", "" }, // RpcServer
56 { HostFalse, "", "", "" }, // RpcClient
57 { HostFalse, "", "", "" }, // Alias
58 { HostFalse, "", "", "-nostartfiles -nostdlib" }, // BootProgram
59 { HostFalse, "", "", "" }, // Win32SCR
60 { HostFalse, "", "", "" }, // IdlHeader
61 { HostFalse, "", "", "" }, // IsoRegTest
62 { HostFalse, "", "", "" }, // LiveIsoRegTest
63 { HostFalse, "", "", "" }, // EmbeddedTypeLib
64 { HostFalse, "", "", "" }, // ElfExecutable
65 { HostFalse, "", "", "" }, // RpcProxy
66 { HostTrue, "", "", "" }, // HostStaticLibrary
67 { HostFalse, "", "", "" }, // Cabinet
68 { HostFalse, "", "", "" }, // KeyboardLayout
69 { HostFalse, "", "", "" }, // MessageHeader
70 };
71
72 string
73 MingwBackend::GetFullPath ( const FileLocation& file ) const
74 {
75 MingwModuleHandler::PassThruCacheDirectory ( &file );
76
77 string directory;
78 switch ( file.directory )
79 {
80 case SourceDirectory:
81 directory = "";
82 break;
83 case IntermediateDirectory:
84 directory = "$(INTERMEDIATE)";
85 break;
86 case OutputDirectory:
87 directory = "$(OUTPUT)";
88 break;
89 case InstallDirectory:
90 directory = "$(INSTALL)";
91 break;
92 case TemporaryDirectory:
93 directory = "$(TEMPORARY)";
94 break;
95 default:
96 throw InvalidOperationException ( __FILE__,
97 __LINE__,
98 "Invalid directory %d.",
99 file.directory );
100 }
101
102 if ( file.relative_path.length () > 0 )
103 {
104 if ( directory.length () > 0 )
105 directory += sSep;
106 directory += file.relative_path;
107 }
108 return directory;
109 }
110
111 string
112 MingwBackend::GetFullName ( const FileLocation& file ) const
113 {
114 string directory;
115 switch ( file.directory )
116 {
117 case SourceDirectory:
118 directory = "";
119 break;
120 case IntermediateDirectory:
121 directory = "$(INTERMEDIATE)";
122 break;
123 case OutputDirectory:
124 directory = "$(OUTPUT)";
125 break;
126 case InstallDirectory:
127 directory = "$(INSTALL)";
128 break;
129 case TemporaryDirectory:
130 directory = "$(TEMPORARY)";
131 break;
132 default:
133 throw InvalidOperationException ( __FILE__,
134 __LINE__,
135 "Invalid directory %d.",
136 file.directory );
137 }
138
139 if ( file.relative_path.length () > 0 )
140 {
141 if ( directory.length () > 0 )
142 directory += sSep;
143 directory += file.relative_path;
144 }
145
146 if ( directory.length () > 0 )
147 directory += sSep;
148
149 return directory + file.name;
150 }
151
152 string
153 v2s ( const Backend* backend, const vector<FileLocation>& files, int wrap_at )
154 {
155 if ( !files.size() )
156 return "";
157 string s;
158 int wrap_count = 0;
159 for ( size_t i = 0; i < files.size(); i++ )
160 {
161 const FileLocation& file = files[i];
162 if ( wrap_at > 0 && wrap_count++ == wrap_at )
163 s += " \\\n\t\t";
164 else if ( s.size() )
165 s += " ";
166 s += backend->GetFullName ( file );
167 }
168 return s;
169 }
170
171
172 string
173 v2s ( const string_list& v, int wrap_at )
174 {
175 if ( !v.size() )
176 return "";
177 string s;
178 int wrap_count = 0;
179 for ( size_t i = 0; i < v.size(); i++ )
180 {
181 if ( !v[i].size() )
182 continue;
183 if ( wrap_at > 0 && wrap_count++ == wrap_at )
184 s += " \\\n\t\t";
185 else if ( s.size() )
186 s += " ";
187 s += v[i];
188 }
189 return s;
190 }
191
192
193 static class MingwFactory : public Backend::Factory
194 {
195 public:
196 MingwFactory() : Factory ( "mingw", "Minimalist GNU Win32" ) {}
197 Backend* operator() ( Project& project,
198 Configuration& configuration )
199 {
200 return new MingwBackend ( project,
201 configuration );
202 }
203 } factory;
204
205
206 MingwBackend::MingwBackend ( Project& project,
207 Configuration& configuration )
208 : Backend ( project, configuration ),
209 manualBinutilsSetting( false ),
210 intermediateDirectory ( new Directory ( "" ) ),
211 outputDirectory ( new Directory ( "" ) ),
212 installDirectory ( new Directory ( "" ) )
213 {
214 compilerPrefix = "";
215 }
216
217 MingwBackend::~MingwBackend()
218 {
219 delete intermediateDirectory;
220 delete outputDirectory;
221 delete installDirectory;
222 }
223
224 string
225 MingwBackend::AddDirectoryTarget ( const string& directory,
226 Directory* directoryTree )
227 {
228 if ( directory.length () > 0)
229 directoryTree->Add ( directory.c_str() );
230 return directoryTree->name;
231 }
232
233 bool
234 MingwBackend::CanEnablePreCompiledHeaderSupportForModule ( const Module& module )
235 {
236 if ( !configuration.CompilationUnitsEnabled )
237 return true;
238
239 const vector<CompilationUnit*>& compilationUnits = module.non_if_data.compilationUnits;
240 size_t i;
241 for ( i = 0; i < compilationUnits.size (); i++ )
242 {
243 CompilationUnit& compilationUnit = *compilationUnits[i];
244 if ( compilationUnit.GetFiles ().size () != 1 )
245 return false;
246 }
247 return true;
248 }
249
250 void
251 MingwBackend::ProcessModules ()
252 {
253 printf ( "Processing modules..." );
254
255 vector<MingwModuleHandler*> v;
256 size_t i;
257
258 for ( std::map<std::string, Module*>::iterator p = ProjectNode.modules.begin (); p != ProjectNode.modules.end (); ++ p )
259 {
260 Module& module = *p->second;
261 if ( !module.enabled )
262 continue;
263 MingwModuleHandler* h = MingwModuleHandler::InstanciateHandler (
264 module,
265 this );
266 h->AddImplicitLibraries ( module );
267 if ( use_pch && CanEnablePreCompiledHeaderSupportForModule ( module ) )
268 h->EnablePreCompiledHeaderSupport ();
269 v.push_back ( h );
270 }
271
272 size_t iend = v.size ();
273
274 for ( i = 0; i < iend; i++ )
275 v[i]->GenerateSourceMacro();
276 for ( i = 0; i < iend; i++ )
277 v[i]->GenerateObjectMacro();
278 fprintf ( fMakefile, "\n" );
279 for ( i = 0; i < iend; i++ )
280 v[i]->GenerateTargetMacro();
281 fprintf ( fMakefile, "\n" );
282
283 GenerateAllTarget ( v );
284 GenerateRegTestsRunTarget ();
285
286 for ( i = 0; i < iend; i++ )
287 v[i]->GenerateOtherMacros();
288
289 for ( i = 0; i < iend; i++ )
290 {
291 MingwModuleHandler& h = *v[i];
292 h.GeneratePreconditionDependencies ();
293 h.Process ();
294 h.GenerateInvocations ();
295 h.GenerateCleanTarget ();
296 h.GenerateInstallTarget ();
297 h.GenerateDependsTarget ();
298 delete v[i];
299 }
300
301 printf ( "done\n" );
302 }
303
304 void
305 MingwBackend::Process ()
306 {
307 if ( configuration.CheckDependenciesForModuleOnly )
308 CheckAutomaticDependenciesForModuleOnly ();
309 else
310 ProcessNormal ();
311 }
312
313 void
314 MingwBackend::CheckAutomaticDependenciesForModuleOnly ()
315 {
316 if ( configuration.AutomaticDependencies )
317 {
318 Module* module = ProjectNode.LocateModule ( configuration.CheckDependenciesForModuleOnlyModule );
319 if ( module == NULL )
320 {
321 printf ( "Module '%s' does not exist\n",
322 configuration.CheckDependenciesForModuleOnlyModule.c_str () );
323 return;
324 }
325
326 printf ( "Checking automatic dependencies for module '%s'...",
327 module->name.c_str () );
328 AutomaticDependency automaticDependency ( ProjectNode );
329 automaticDependency.CheckAutomaticDependenciesForModule ( *module,
330 configuration.Verbose );
331 printf ( "done\n" );
332 }
333 }
334
335 void
336 MingwBackend::ProcessNormal ()
337 {
338 assert(sizeof(ModuleHandlerInformations)/sizeof(ModuleHandlerInformations[0]) == TypeDontCare);
339
340 DetectCompiler ();
341 DetectBinutils ();
342 DetectNetwideAssembler ();
343 DetectPipeSupport ();
344 DetectPCHSupport ();
345 CreateMakefile ();
346 GenerateHeader ();
347 GenerateGlobalVariables ();
348 GenerateXmlBuildFilesMacro ();
349 ProcessModules ();
350 GenerateInstallTarget ();
351 GenerateTestTarget ();
352 GenerateDirectoryTargets ();
353 GenerateDirectories ();
354 GenerateTestSupportCode ();
355 GenerateCompilationUnitSupportCode ();
356 GenerateSysSetup ();
357 GenerateProxyMakefiles ();
358 CheckAutomaticDependencies ();
359 CloseMakefile ();
360 }
361
362 void
363 MingwBackend::CreateMakefile ()
364 {
365 fMakefile = fopen ( ProjectNode.makefile.c_str (), "w" );
366 if ( !fMakefile )
367 throw AccessDeniedException ( ProjectNode.makefile );
368 MingwModuleHandler::SetBackend ( this );
369 MingwModuleHandler::SetMakefile ( fMakefile );
370 }
371
372 void
373 MingwBackend::CloseMakefile () const
374 {
375 if (fMakefile)
376 fclose ( fMakefile );
377 }
378
379 void
380 MingwBackend::GenerateHeader () const
381 {
382 fprintf ( fMakefile, "# THIS FILE IS AUTOMATICALLY GENERATED, EDIT '%s' INSTEAD\n\n",
383 ProjectNode.GetProjectFilename ().c_str () );
384 }
385
386 void
387 MingwBackend::GenerateProjectCFlagsMacro ( const char* assignmentOperation,
388 const IfableData& data ) const
389 {
390 set<string> used_defs;
391
392 if ( data.includes.size () > 0 )
393 fprintf (
394 fMakefile,
395 "PROJECT_CFLAGS %s %s\n",
396 assignmentOperation,
397 MingwModuleHandler::GenerateGccIncludeParametersFromVector ( data.includes ).c_str ());
398
399 if ( data.defines.size () > 0 )
400 fprintf (
401 fMakefile,
402 "PROJECT_CDEFINES %s %s\n",
403 assignmentOperation,
404 MingwModuleHandler::GenerateGccDefineParametersFromVector ( data.defines, used_defs ).c_str ());
405 }
406
407 void
408 MingwBackend::GenerateGlobalCFlagsAndProperties (
409 const char* assignmentOperation,
410 const IfableData& data ) const
411 {
412 for ( std::map<std::string, Property*>::const_iterator p = data.properties.begin(); p != data.properties.end(); ++ p )
413 {
414 Property& prop = *p->second;
415
416 if (!prop.isInternal)
417 {
418 fprintf ( fMakefile, "%s := %s\n",
419 prop.name.c_str(),
420 prop.value.c_str() );
421 }
422 }
423
424 if ( data.includes.size() || data.defines.size() )
425 {
426 GenerateProjectCFlagsMacro ( assignmentOperation,
427 data );
428 }
429 }
430
431 void
432 MingwBackend::GenerateProjectGccOptionsMacro ( const char* assignmentOperation,
433 IfableData& data ) const
434 {
435 size_t i;
436
437 fprintf (
438 fMakefile,
439 "PROJECT_GCCOPTIONS %s",
440 assignmentOperation );
441
442 for ( i = 0; i < data.compilerFlags.size(); i++ )
443 {
444 if ( data.compilerFlags[i]->compiler == CompilerTypeDontCare )
445 {
446 fprintf (
447 fMakefile,
448 " %s",
449 data.compilerFlags[i]->flag.c_str() );
450 }
451 }
452
453 fputs ( "\n", fMakefile );
454
455 // TODO: reference these from somewhere
456 fprintf (
457 fMakefile,
458 "PROJECT_GCC_CFLAGS %s",
459 assignmentOperation );
460
461 for ( i = 0; i < data.compilerFlags.size(); i++ )
462 {
463 if ( data.compilerFlags[i]->compiler == CompilerTypeCC )
464 {
465 fprintf (
466 fMakefile,
467 " %s",
468 data.compilerFlags[i]->flag.c_str() );
469 }
470 }
471
472 fputs ( "\n", fMakefile );
473
474 fprintf (
475 fMakefile,
476 "PROJECT_GCC_CXXFLAGS %s",
477 assignmentOperation );
478
479 for ( i = 0; i < data.compilerFlags.size(); i++ )
480 {
481 if ( data.compilerFlags[i]->compiler == CompilerTypeCPP )
482 {
483 fprintf (
484 fMakefile,
485 " %s",
486 data.compilerFlags[i]->flag.c_str() );
487 }
488 }
489
490 fputs ( "\n", fMakefile );
491 }
492
493 void
494 MingwBackend::GenerateProjectGccOptions (
495 const char* assignmentOperation,
496 IfableData& data ) const
497 {
498 if ( data.compilerFlags.size() )
499 {
500 GenerateProjectGccOptionsMacro ( assignmentOperation,
501 data );
502 }
503 }
504
505 string
506 MingwBackend::GenerateProjectLFLAGS () const
507 {
508 string lflags;
509 for ( size_t i = 0; i < ProjectNode.linkerFlags.size (); i++ )
510 {
511 LinkerFlag& linkerFlag = *ProjectNode.linkerFlags[i];
512 if ( lflags.length () > 0 )
513 lflags += " ";
514 lflags += linkerFlag.flag;
515 }
516 return lflags;
517 }
518
519 void
520 MingwBackend::GenerateGlobalVariables () const
521 {
522 fprintf ( fMakefile,
523 "PREFIX := %s\n",
524 compilerPrefix.c_str () );
525 fprintf ( fMakefile,
526 "nasm := %s\n",
527 nasmCommand.c_str () );
528
529 GenerateGlobalCFlagsAndProperties ( "=", ProjectNode.non_if_data );
530 GenerateProjectGccOptions ( "=", ProjectNode.non_if_data );
531
532 fprintf ( fMakefile, "PROJECT_RCFLAGS := $(PROJECT_CFLAGS) $(PROJECT_CDEFINES)\n" );
533 fprintf ( fMakefile, "PROJECT_WIDLFLAGS := $(PROJECT_CFLAGS) $(PROJECT_CDEFINES)\n" );
534 fprintf ( fMakefile, "PROJECT_LFLAGS := '$(shell ${TARGET_CC} -print-libgcc-file-name)' %s\n", GenerateProjectLFLAGS ().c_str () );
535 fprintf ( fMakefile, "PROJECT_LPPFLAGS := '$(shell ${TARGET_CPP} -print-file-name=libstdc++.a)' '$(shell ${TARGET_CPP} -print-file-name=libgcc.a)' '$(shell ${TARGET_CPP} -print-file-name=libmingw32.a)' '$(shell ${TARGET_CPP} -print-file-name=libmingwex.a)'\n" );
536 fprintf ( fMakefile, "PROJECT_CFLAGS += -Wall\n" );
537 fprintf ( fMakefile, "ifneq ($(OARCH),)\n" );
538 fprintf ( fMakefile, "PROJECT_CFLAGS += -march=$(OARCH)\n" );
539 fprintf ( fMakefile, "endif\n" );
540 fprintf ( fMakefile, "PROJECT_CFLAGS += $(PROJECT_GCCOPTIONS)\n" );
541 fprintf ( fMakefile, "\n" );
542 }
543
544 bool
545 MingwBackend::IncludeInAllTarget ( const Module& module ) const
546 {
547 if ( MingwModuleHandler::ReferenceObjects ( module ) )
548 return false;
549 if ( module.type == BootSector )
550 return false;
551 if ( module.type == Iso )
552 return false;
553 if ( module.type == LiveIso )
554 return false;
555 if ( module.type == IsoRegTest )
556 return false;
557 if ( module.type == LiveIsoRegTest )
558 return false;
559 if ( module.type == Test )
560 return false;
561 if ( module.type == Alias )
562 return false;
563 return true;
564 }
565
566 void
567 MingwBackend::GenerateAllTarget ( const vector<MingwModuleHandler*>& handlers ) const
568 {
569 fprintf ( fMakefile, "all:" );
570 int wrap_count = 0;
571 size_t iend = handlers.size ();
572 for ( size_t i = 0; i < iend; i++ )
573 {
574 const Module& module = handlers[i]->module;
575 if ( IncludeInAllTarget ( module ) )
576 {
577 if ( wrap_count++ == 5 )
578 fprintf ( fMakefile, " \\\n\t\t" ), wrap_count = 0;
579 fprintf ( fMakefile,
580 " %s",
581 GetTargetMacro(module).c_str () );
582 }
583 }
584 fprintf ( fMakefile, "\n\t\n\n" );
585 }
586
587 void
588 MingwBackend::GenerateRegTestsRunTarget () const
589 {
590 fprintf ( fMakefile,
591 "REGTESTS_RUN_TARGET = regtests.dll\n" );
592 fprintf ( fMakefile,
593 "$(REGTESTS_RUN_TARGET): $(REGTESTS_TARGET)\n" );
594 fprintf ( fMakefile,
595 "\t$(cp) $(REGTESTS_TARGET) $(REGTESTS_RUN_TARGET)\n" );
596 fprintf ( fMakefile, "\n" );
597 }
598
599 void
600 MingwBackend::GenerateXmlBuildFilesMacro() const
601 {
602 fprintf ( fMakefile,
603 "XMLBUILDFILES = %s \\\n",
604 ProjectNode.GetProjectFilename ().c_str () );
605 string xmlbuildFilenames;
606 int numberOfExistingFiles = 0;
607 struct stat statbuf;
608 time_t SystemTime, lastWriteTime;
609
610 for ( size_t i = 0; i < ProjectNode.xmlbuildfiles.size (); i++ )
611 {
612 XMLInclude& xmlbuildfile = *ProjectNode.xmlbuildfiles[i];
613 if ( !xmlbuildfile.fileExists )
614 continue;
615 numberOfExistingFiles++;
616 if ( xmlbuildFilenames.length () > 0 )
617 xmlbuildFilenames += " ";
618
619 FILE* f = fopen ( xmlbuildfile.topIncludeFilename.c_str (), "rb" );
620 if ( !f )
621 throw FileNotFoundException ( NormalizeFilename ( xmlbuildfile.topIncludeFilename ) );
622
623 if ( fstat ( fileno ( f ), &statbuf ) != 0 )
624 {
625 fclose ( f );
626 throw AccessDeniedException ( NormalizeFilename ( xmlbuildfile.topIncludeFilename ) );
627 }
628
629 lastWriteTime = statbuf.st_mtime;
630 SystemTime = time(NULL);
631
632 if (SystemTime != -1)
633 {
634 if (difftime (lastWriteTime, SystemTime) > 0)
635 throw InvalidDateException ( NormalizeFilename ( xmlbuildfile.topIncludeFilename ) );
636 }
637
638 fclose ( f );
639
640 xmlbuildFilenames += NormalizeFilename ( xmlbuildfile.topIncludeFilename );
641 if ( numberOfExistingFiles % 5 == 4 || i == ProjectNode.xmlbuildfiles.size () - 1 )
642 {
643 fprintf ( fMakefile,
644 "\t%s",
645 xmlbuildFilenames.c_str ());
646 if ( i == ProjectNode.xmlbuildfiles.size () - 1 )
647 {
648 fprintf ( fMakefile, "\n" );
649 }
650 else
651 {
652 fprintf ( fMakefile,
653 " \\\n" );
654 }
655 xmlbuildFilenames.resize ( 0 );
656 }
657 numberOfExistingFiles++;
658 }
659 fprintf ( fMakefile, "\n" );
660 }
661
662 void
663 MingwBackend::GenerateTestSupportCode ()
664 {
665 printf ( "Generating test support code..." );
666 TestSupportCode testSupportCode ( ProjectNode );
667 testSupportCode.GenerateTestSupportCode ( configuration.Verbose );
668 printf ( "done\n" );
669 }
670
671 void
672 MingwBackend::GenerateCompilationUnitSupportCode ()
673 {
674 if ( configuration.CompilationUnitsEnabled )
675 {
676 printf ( "Generating compilation unit support code..." );
677 CompilationUnitSupportCode compilationUnitSupportCode ( ProjectNode );
678 compilationUnitSupportCode.Generate ( configuration.Verbose );
679 printf ( "done\n" );
680 }
681 }
682
683 void
684 MingwBackend::GenerateSysSetup ()
685 {
686 printf ( "Generating syssetup.inf..." );
687 SysSetupGenerator sysSetupGenerator ( ProjectNode );
688 sysSetupGenerator.Generate ();
689 printf ( "done\n" );
690 }
691
692 string
693 MingwBackend::GetProxyMakefileTree () const
694 {
695 if ( configuration.GenerateProxyMakefilesInSourceTree )
696 return "";
697 else
698 return Environment::GetOutputPath ();
699 }
700
701 void
702 MingwBackend::GenerateProxyMakefiles ()
703 {
704 printf ( "Generating proxy makefiles..." );
705 ProxyMakefile proxyMakefile ( ProjectNode );
706 proxyMakefile.GenerateProxyMakefiles ( configuration.Verbose,
707 GetProxyMakefileTree () );
708 printf ( "done\n" );
709 }
710
711 void
712 MingwBackend::CheckAutomaticDependencies ()
713 {
714 if ( configuration.AutomaticDependencies )
715 {
716 printf ( "Checking automatic dependencies..." );
717 AutomaticDependency automaticDependency ( ProjectNode );
718 automaticDependency.CheckAutomaticDependencies ( configuration.Verbose );
719 printf ( "done\n" );
720 }
721 }
722
723 void
724 MingwBackend::GenerateDirectories ()
725 {
726 printf ( "Creating directories..." );
727 intermediateDirectory->GenerateTree ( IntermediateDirectory, configuration.Verbose );
728 outputDirectory->GenerateTree ( OutputDirectory, configuration.Verbose );
729 if ( !configuration.MakeHandlesInstallDirectories )
730 installDirectory->GenerateTree ( InstallDirectory, configuration.Verbose );
731 printf ( "done\n" );
732 }
733
734 bool
735 MingwBackend::TryToDetectThisCompiler ( const string& compiler )
736 {
737 string command = ssprintf (
738 "%s -v 1>%s 2>%s",
739 FixSeparatorForSystemCommand(compiler).c_str (),
740 NUL,
741 NUL );
742 int exitcode = system ( command.c_str () );
743 return (bool) (exitcode == 0);
744 }
745
746 void
747 MingwBackend::DetectCompiler ()
748 {
749 printf ( "Detecting compiler..." );
750
751 bool detectedCompiler = false;
752 const string& ROS_PREFIXValue = Environment::GetVariable ( "ROS_PREFIX" );
753 if ( ROS_PREFIXValue.length () > 0 )
754 {
755 compilerPrefix = ROS_PREFIXValue;
756 compilerCommand = compilerPrefix + "-gcc";
757 detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
758 }
759 #if defined(WIN32)
760 if ( !detectedCompiler )
761 {
762 compilerPrefix = "";
763 compilerCommand = "gcc";
764 detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
765 }
766 #endif
767 if ( !detectedCompiler )
768 {
769 compilerPrefix = "mingw32";
770 compilerCommand = compilerPrefix + "-gcc";
771 detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
772 }
773
774 if ( detectedCompiler )
775 {
776 string compilerVersion = GetCompilerVersion ( compilerCommand );
777 if ( IsSupportedCompilerVersion ( compilerVersion ) )
778 printf ( "detected (%s %s)\n", compilerCommand.c_str (), compilerVersion.c_str() );
779 else
780 {
781 printf ( "detected (%s), but with unsupported version (%s)\n",
782 compilerCommand.c_str (),
783 compilerVersion.c_str () );
784 throw UnsupportedBuildToolException ( compilerCommand, compilerVersion );
785 }
786 }
787 else
788 printf ( "not detected\n" );
789
790 }
791
792 bool
793 MingwBackend::TryToDetectThisNetwideAssembler ( const string& assembler )
794 {
795 string command = ssprintf (
796 "%s -h 1>%s 2>%s",
797 FixSeparatorForSystemCommand(assembler).c_str (),
798 NUL,
799 NUL );
800 int exitcode = system ( command.c_str () );
801 return (bool) (exitcode == 0);
802 }
803
804 string
805 MingwBackend::GetVersionString ( const string& versionCommand )
806 {
807 FILE *fp;
808 int ch, i;
809 size_t newline;
810 char buffer[81];
811
812 fp = popen ( versionCommand.c_str () , "r" );
813 for( i = 0;
814 ( i < 80 ) &&
815 ( feof ( fp ) == 0 &&
816 ( ( ch = fgetc( fp ) ) != -1 ) );
817 i++ )
818 {
819 buffer[i] = (char) ch;
820 }
821 buffer[i] = '\0';
822 pclose ( fp );
823
824 char separators[] = " ";
825 char *token;
826 char *prevtoken = NULL;
827
828 string version;
829
830 token = strtok ( buffer, separators );
831 while ( token != NULL )
832 {
833 prevtoken = token;
834 version = string( prevtoken );
835 if ( (newline = version.find('\n')) != std::string::npos )
836 version.erase(newline, 1);
837 if ( version.find('.') != std::string::npos )
838 break;
839 token = strtok ( NULL, separators );
840 }
841 return version;
842 }
843
844 string
845 MingwBackend::GetNetwideAssemblerVersion ( const string& nasmCommand )
846 {
847 string versionCommand;
848 if ( nasmCommand.find("yasm") != std::string::npos )
849 {
850 versionCommand = ssprintf ( "%s --version",
851 nasmCommand.c_str (),
852 NUL,
853 NUL );
854 }
855 else
856 {
857 versionCommand = ssprintf ( "%s -v",
858 nasmCommand.c_str (),
859 NUL,
860 NUL );
861 }
862 return GetVersionString( versionCommand );
863 }
864
865 string
866 MingwBackend::GetCompilerVersion ( const string& compilerCommand )
867 {
868 string versionCommand = ssprintf ( "%s --version gcc",
869 compilerCommand.c_str (),
870 NUL,
871 NUL );
872 return GetVersionString( versionCommand );
873 }
874
875 string
876 MingwBackend::GetBinutilsVersion ( const string& binutilsCommand )
877 {
878 string versionCommand = ssprintf ( "%s -v",
879 binutilsCommand.c_str (),
880 NUL,
881 NUL );
882 return GetVersionString( versionCommand );
883 }
884
885 bool
886 MingwBackend::IsSupportedCompilerVersion ( const string& compilerVersion )
887 {
888 if ( strcmp ( compilerVersion.c_str (), "3.4.2") < 0 )
889 return false;
890 else
891 return true;
892 }
893
894 bool
895 MingwBackend::TryToDetectThisBinutils ( const string& binutils )
896 {
897 string command = ssprintf (
898 "%s -v 1>%s 2>%s",
899 FixSeparatorForSystemCommand(binutils).c_str (),
900 NUL,
901 NUL );
902 int exitcode = system ( command.c_str () );
903 return (exitcode == 0);
904 }
905
906 string
907 MingwBackend::GetBinutilsVersionDate ( const string& binutilsCommand )
908 {
909 FILE *fp;
910 int ch, i;
911 char buffer[81];
912
913 string versionCommand = ssprintf ( "%s -v",
914 binutilsCommand.c_str (),
915 NUL,
916 NUL );
917 fp = popen ( versionCommand.c_str () , "r" );
918 for( i = 0;
919 ( i < 80 ) &&
920 ( feof ( fp ) == 0 &&
921 ( ( ch = fgetc( fp ) ) != -1 ) );
922 i++ )
923 {
924 buffer[i] = (char) ch;
925 }
926 buffer[i] = '\0';
927 pclose ( fp );
928
929 char separators[] = " ";
930 char *token;
931 char *prevtoken = NULL;
932
933 token = strtok ( buffer, separators );
934 while ( token != NULL )
935 {
936 prevtoken = token;
937 token = strtok ( NULL, separators );
938 }
939 string version = string ( prevtoken );
940 int lastDigit = version.find_last_not_of ( "\t\r\n" );
941 if ( lastDigit != -1 )
942 return string ( version, 0, lastDigit+1 );
943 else
944 return version;
945 }
946
947 bool
948 MingwBackend::IsSupportedBinutilsVersion ( const string& binutilsVersion )
949 {
950 if ( manualBinutilsSetting ) return true;
951
952 /* linux */
953 if ( binutilsVersion.find('.') != std::string::npos )
954 {
955 /* TODO: blacklist versions on version number instead of date */
956 return true;
957 }
958
959 /*
960 * - Binutils older than 2003/10/01 have broken windres which can't handle
961 * icons with alpha channel.
962 * - Binutils between 2004/09/02 and 2004/10/08 have broken handling of
963 * forward exports in dlltool.
964 */
965 if ( ( ( strcmp ( binutilsVersion.c_str (), "20040902") >= 0 ) &&
966 ( strcmp ( binutilsVersion.c_str (), "20041008") <= 0 ) ) ||
967 ( strcmp ( binutilsVersion.c_str (), "20031001") < 0 ) )
968 return false;
969 else
970 return true;
971 }
972
973 void
974 MingwBackend::DetectBinutils ()
975 {
976 printf ( "Detecting binutils..." );
977
978 bool detectedBinutils = false;
979 const string& ROS_PREFIXValue = Environment::GetVariable ( "ROS_PREFIX" );
980
981 if ( ROS_PREFIXValue.length () > 0 )
982 {
983 binutilsPrefix = ROS_PREFIXValue;
984 binutilsCommand = binutilsPrefix + "-ld";
985 manualBinutilsSetting = true;
986 detectedBinutils = true;
987 }
988 #if defined(WIN32)
989 if ( !detectedBinutils )
990 {
991 binutilsPrefix = "";
992 binutilsCommand = "ld";
993 detectedBinutils = TryToDetectThisBinutils ( binutilsCommand );
994 }
995 #endif
996 if ( !detectedBinutils )
997 {
998 binutilsPrefix = "mingw32";
999 binutilsCommand = binutilsPrefix + "-ld";
1000 detectedBinutils = TryToDetectThisBinutils ( binutilsCommand );
1001 }
1002 if ( detectedBinutils )
1003 {
1004 string binutilsVersion = GetBinutilsVersionDate ( binutilsCommand );
1005 if ( IsSupportedBinutilsVersion ( binutilsVersion ) )
1006 printf ( "detected (%s %s)\n", binutilsCommand.c_str (), GetBinutilsVersion( binutilsCommand ).c_str() );
1007 else
1008 {
1009 printf ( "detected (%s), but with unsupported version (%s)\n",
1010 binutilsCommand.c_str (),
1011 binutilsVersion.c_str () );
1012 throw UnsupportedBuildToolException ( binutilsCommand, binutilsVersion );
1013 }
1014 }
1015 else
1016 printf ( "not detected\n" );
1017
1018 }
1019
1020 void
1021 MingwBackend::DetectNetwideAssembler ()
1022 {
1023 printf ( "Detecting netwide assembler..." );
1024
1025 nasmCommand = "nasm";
1026 bool detectedNasm = TryToDetectThisNetwideAssembler ( nasmCommand );
1027 #if defined(WIN32)
1028 if ( !detectedNasm )
1029 {
1030 nasmCommand = "nasmw";
1031 detectedNasm = TryToDetectThisNetwideAssembler ( nasmCommand );
1032 }
1033 #endif
1034 if ( !detectedNasm )
1035 {
1036 nasmCommand = "yasm";
1037 detectedNasm = TryToDetectThisNetwideAssembler ( nasmCommand );
1038 }
1039 if ( detectedNasm )
1040 printf ( "detected (%s %s)\n", nasmCommand.c_str (), GetNetwideAssemblerVersion( nasmCommand ).c_str() );
1041 else
1042 printf ( "not detected\n" );
1043 }
1044
1045 void
1046 MingwBackend::DetectPipeSupport ()
1047 {
1048 printf ( "Detecting compiler -pipe support..." );
1049
1050 string pipe_detection = "tools" + sSep + "rbuild" + sSep + "backend" + sSep + "mingw" + sSep + "pipe_detection.c";
1051 string pipe_detectionObjectFilename = ReplaceExtension ( pipe_detection,
1052 ".o" );
1053 string command = ssprintf (
1054 "%s -pipe -c %s -o %s 1>%s 2>%s",
1055 FixSeparatorForSystemCommand(compilerCommand).c_str (),
1056 pipe_detection.c_str (),
1057 pipe_detectionObjectFilename.c_str (),
1058 NUL,
1059 NUL );
1060 int exitcode = system ( command.c_str () );
1061 FILE* f = fopen ( pipe_detectionObjectFilename.c_str (), "rb" );
1062 if ( f )
1063 {
1064 usePipe = (exitcode == 0);
1065 fclose ( f );
1066 unlink ( pipe_detectionObjectFilename.c_str () );
1067 }
1068 else
1069 usePipe = false;
1070
1071 if ( usePipe )
1072 printf ( "detected\n" );
1073 else
1074 printf ( "not detected\n" );
1075 }
1076
1077 void
1078 MingwBackend::DetectPCHSupport ()
1079 {
1080 printf ( "Detecting compiler pre-compiled header support..." );
1081
1082 if ( configuration.PrecompiledHeadersEnabled )
1083 {
1084 string path = "tools" + sSep + "rbuild" + sSep + "backend" + sSep + "mingw" + sSep + "pch_detection.h";
1085 string cmd = ssprintf (
1086 "%s -c %s 1>%s 2>%s",
1087 FixSeparatorForSystemCommand(compilerCommand).c_str (),
1088 path.c_str (),
1089 NUL,
1090 NUL );
1091 system ( cmd.c_str () );
1092 path += ".gch";
1093
1094 FILE* f = fopen ( path.c_str (), "rb" );
1095 if ( f )
1096 {
1097 use_pch = true;
1098 fclose ( f );
1099 unlink ( path.c_str () );
1100 }
1101 else
1102 use_pch = false;
1103
1104 if ( use_pch )
1105 printf ( "detected\n" );
1106 else
1107 printf ( "not detected\n" );
1108 }
1109 else
1110 {
1111 use_pch = false;
1112 printf ( "disabled\n" );
1113 }
1114 }
1115
1116 void
1117 MingwBackend::GetNonModuleInstallTargetFiles (
1118 vector<FileLocation>& out ) const
1119 {
1120 for ( size_t i = 0; i < ProjectNode.installfiles.size (); i++ )
1121 {
1122 const InstallFile& installfile = *ProjectNode.installfiles[i];
1123 out.push_back ( *installfile.target );
1124 }
1125 }
1126
1127 void
1128 MingwBackend::GetModuleInstallTargetFiles (
1129 vector<FileLocation>& out ) const
1130 {
1131 for ( std::map<std::string, Module*>::const_iterator p = ProjectNode.modules.begin (); p != ProjectNode.modules.end (); ++ p )
1132 {
1133 const Module& module = *p->second;
1134 if ( !module.enabled )
1135 continue;
1136 if ( module.install )
1137 out.push_back ( *module.install );
1138 }
1139 }
1140
1141 void
1142 MingwBackend::GetInstallTargetFiles (
1143 vector<FileLocation>& out ) const
1144 {
1145 GetNonModuleInstallTargetFiles ( out );
1146 GetModuleInstallTargetFiles ( out );
1147 }
1148
1149 void
1150 MingwBackend::OutputInstallTarget ( const FileLocation& source,
1151 const FileLocation& target )
1152 {
1153 fprintf ( fMakefile,
1154 "%s: %s | %s\n",
1155 GetFullName ( target ).c_str (),
1156 GetFullName ( source ).c_str (),
1157 GetFullPath ( target ).c_str () );
1158 fprintf ( fMakefile,
1159 "\t$(ECHO_CP)\n" );
1160 fprintf ( fMakefile,
1161 "\t${cp} %s %s 1>$(NUL)\n",
1162 GetFullName ( source ).c_str (),
1163 GetFullName ( target ).c_str () );
1164 }
1165
1166 void
1167 MingwBackend::OutputNonModuleInstallTargets ()
1168 {
1169 for ( size_t i = 0; i < ProjectNode.installfiles.size (); i++ )
1170 {
1171 const InstallFile& installfile = *ProjectNode.installfiles[i];
1172 OutputInstallTarget ( *installfile.source, *installfile.target );
1173 }
1174 }
1175
1176 const Module&
1177 MingwBackend::GetAliasedModuleOrModule ( const Module& module ) const
1178 {
1179 if ( module.aliasedModuleName.size () > 0 )
1180 {
1181 const Module* aliasedModule = ProjectNode.LocateModule ( module.aliasedModuleName );
1182 assert ( aliasedModule );
1183 return *aliasedModule;
1184 }
1185 else
1186 return module;
1187 }
1188
1189 void
1190 MingwBackend::OutputModuleInstallTargets ()
1191 {
1192 for ( std::map<std::string, Module*>::const_iterator p = ProjectNode.modules.begin (); p != ProjectNode.modules.end (); ++ p )
1193 {
1194 const Module& module = *p->second;
1195 if ( !module.enabled )
1196 continue;
1197 if ( module.install )
1198 {
1199 const Module& aliasedModule = GetAliasedModuleOrModule ( module );
1200 OutputInstallTarget ( *aliasedModule.output, *module.install );
1201 }
1202 }
1203 }
1204
1205 string
1206 MingwBackend::GetRegistrySourceFiles ()
1207 {
1208 return "boot" + sSep + "bootdata" + sSep + "hivecls_" + Environment::GetArch() + ".inf "
1209 "boot" + sSep + "bootdata" + sSep + "hivedef_" + Environment::GetArch() + ".inf "
1210 "boot" + sSep + "bootdata" + sSep + "hiveinst_" + Environment::GetArch() + ".inf "
1211 "boot" + sSep + "bootdata" + sSep + "hivesft_" + Environment::GetArch() + ".inf "
1212 "boot" + sSep + "bootdata" + sSep + "hivesys_" + Environment::GetArch() + ".inf ";
1213 }
1214
1215 string
1216 MingwBackend::GetRegistryTargetFiles ()
1217 {
1218 string system32ConfigDirectory = "system32" + sSep + "config";
1219 FileLocation system32 ( InstallDirectory, system32ConfigDirectory, "" );
1220
1221 vector<FileLocation> registry_files;
1222 registry_files.push_back ( FileLocation ( InstallDirectory, system32ConfigDirectory, "default" ) );
1223 registry_files.push_back ( FileLocation ( InstallDirectory, system32ConfigDirectory, "sam" ) );
1224 registry_files.push_back ( FileLocation ( InstallDirectory, system32ConfigDirectory, "security" ) );
1225 registry_files.push_back ( FileLocation ( InstallDirectory, system32ConfigDirectory, "software" ) );
1226 registry_files.push_back ( FileLocation ( InstallDirectory, system32ConfigDirectory, "system" ) );
1227
1228 return v2s( this, registry_files, 6 );
1229 }
1230
1231 void
1232 MingwBackend::OutputRegistryInstallTarget ()
1233 {
1234 FileLocation system32 ( InstallDirectory, "system32" + sSep + "config", "" );
1235
1236 string registrySourceFiles = GetRegistrySourceFiles ();
1237 string registryTargetFiles = GetRegistryTargetFiles ();
1238 fprintf ( fMakefile,
1239 "install_registry: %s\n",
1240 registryTargetFiles.c_str () );
1241 fprintf ( fMakefile,
1242 "%s: %s %s $(MKHIVE_TARGET)\n",
1243 registryTargetFiles.c_str (),
1244 registrySourceFiles.c_str (),
1245 GetFullPath ( system32 ).c_str () );
1246 fprintf ( fMakefile,
1247 "\t$(ECHO_MKHIVE)\n" );
1248 fprintf ( fMakefile,
1249 "\t$(MKHIVE_TARGET) boot%cbootdata %s $(ARCH) boot%cbootdata%chiveinst_$(ARCH).inf\n",
1250 cSep, GetFullPath ( system32 ).c_str (),
1251 cSep, cSep );
1252 fprintf ( fMakefile,
1253 "\n" );
1254 }
1255
1256 void
1257 MingwBackend::GenerateInstallTarget ()
1258 {
1259 vector<FileLocation> vInstallTargetFiles;
1260 GetInstallTargetFiles ( vInstallTargetFiles );
1261 string installTargetFiles = v2s ( this, vInstallTargetFiles, 5 );
1262 string registryTargetFiles = GetRegistryTargetFiles ();
1263
1264 fprintf ( fMakefile,
1265 "install: %s %s\n",
1266 installTargetFiles.c_str (),
1267 registryTargetFiles.c_str () );
1268 OutputNonModuleInstallTargets ();
1269 OutputModuleInstallTargets ();
1270 OutputRegistryInstallTarget ();
1271 fprintf ( fMakefile,
1272 "\n" );
1273 }
1274
1275 void
1276 MingwBackend::GetModuleTestTargets (
1277 vector<string>& out ) const
1278 {
1279 for ( std::map<std::string, Module*>::const_iterator p = ProjectNode.modules.begin (); p != ProjectNode.modules.end (); ++ p )
1280 {
1281 const Module& module = *p->second;
1282 if ( !module.enabled )
1283 continue;
1284 if ( module.type == Test )
1285 out.push_back ( module.name );
1286 }
1287 }
1288
1289 void
1290 MingwBackend::GenerateTestTarget ()
1291 {
1292 vector<string> vTestTargets;
1293 GetModuleTestTargets ( vTestTargets );
1294 string testTargets = v2s ( vTestTargets, 5 );
1295
1296 fprintf ( fMakefile,
1297 "test: %s\n",
1298 testTargets.c_str () );
1299 fprintf ( fMakefile,
1300 "\n" );
1301 }
1302
1303 void
1304 MingwBackend::GenerateDirectoryTargets ()
1305 {
1306 intermediateDirectory->CreateRule ( fMakefile, "$(INTERMEDIATE)" );
1307 outputDirectory->CreateRule ( fMakefile, "$(OUTPUT)" );
1308 installDirectory->CreateRule ( fMakefile, "$(INSTALL)" );
1309 }