2 * Copyright (C) 2005 Casper S. Hornstrup
3 * 2006 Christoph von Wittich
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.
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.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "../../pch.h"
23 #include "modulehandler.h"
27 #define pclose _pclose
35 typedef set
<string
> set_string
;
37 const struct ModuleHandlerInformations ModuleHandlerInformations
[] = {
38 { HostTrue
, "", "", "" }, // BuildTool
39 { HostFalse
, "", "", "" }, // StaticLibrary
40 { HostFalse
, "", "", "" }, // ObjectLibrary
41 { HostFalse
, "", "", "$(LDFLAG_DRIVER)" }, // Kernel
42 { HostFalse
, "", "", "$(LDFLAG_DRIVER)" }, // KernelModeDLL
43 { HostFalse
, "-D__NTDRIVER__", "", "$(LDFLAG_DRIVER)" }, // KernelModeDriver
44 { HostFalse
, "", "", "$(LDFLAG_DLL)" }, // NativeDLL
45 { HostFalse
, "-D__NTAPP__", "", "$(LDFLAG_NATIVE)" }, // NativeCUI
46 { HostFalse
, "", "", "$(LDFLAG_DLL)" }, // Win32DLL
47 { HostFalse
, "", "", "$(LDFLAG_DLL)" }, // Win32OCX
48 { HostFalse
, "", "", "$(LDFLAG_CONSOLE)" }, // Win32CUI
49 { HostFalse
, "", "", "$(LDFLAG_WINDOWS)" }, // Win32GUI
50 { HostFalse
, "", "", "" }, // 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
, "", "", "" }, // BootProgram
59 { HostFalse
, "", "", "$(LDFLAG_WINDOWS)" }, // Win32SCR
60 { HostFalse
, "", "", "" }, // IdlHeader
61 { HostFalse
, "", "", "" }, // IdlInterface
62 { HostFalse
, "", "", "" }, // EmbeddedTypeLib
63 { HostFalse
, "", "", "" }, // ElfExecutable
64 { HostFalse
, "", "", "" }, // RpcProxy
65 { HostTrue
, "", "", "" }, // HostStaticLibrary
66 { HostFalse
, "", "", "" }, // Cabinet
67 { HostFalse
, "", "", "$(LDFLAG_DLL)" }, // KeyboardLayout
68 { HostFalse
, "", "", "" }, // MessageHeader
71 static std::string mscPath
;
72 static std::string mslinkPath
;
75 MingwBackend::GetFullPath ( const FileLocation
& file
) const
77 MingwModuleHandler::PassThruCacheDirectory ( &file
);
80 switch ( file
.directory
)
85 case IntermediateDirectory
:
86 directory
= "$(INTERMEDIATE)";
89 directory
= "$(OUTPUT)";
91 case InstallDirectory
:
92 directory
= "$(INSTALL)";
94 case TemporaryDirectory
:
95 directory
= "$(TEMPORARY)";
98 throw InvalidOperationException ( __FILE__
,
100 "Invalid directory %d.",
104 if ( file
.relative_path
.length () > 0 )
106 if ( directory
.length () > 0 )
108 directory
+= file
.relative_path
;
114 MingwBackend::GetFullName ( const FileLocation
& file
) const
117 switch ( file
.directory
)
119 case SourceDirectory
:
122 case IntermediateDirectory
:
123 directory
= "$(INTERMEDIATE)";
125 case OutputDirectory
:
126 directory
= "$(OUTPUT)";
128 case InstallDirectory
:
129 directory
= "$(INSTALL)";
131 case TemporaryDirectory
:
132 directory
= "$(TEMPORARY)";
135 throw InvalidOperationException ( __FILE__
,
137 "Invalid directory %d.",
141 if ( file
.relative_path
.length () > 0 )
143 if ( directory
.length () > 0 )
145 directory
+= file
.relative_path
;
148 if ( directory
.length () > 0 )
151 return directory
+ file
.name
;
155 v2s ( const Backend
* backend
, const vector
<FileLocation
>& files
, int wrap_at
)
161 for ( size_t i
= 0; i
< files
.size(); i
++ )
163 const FileLocation
& file
= files
[i
];
164 if ( wrap_at
> 0 && wrap_count
++ == wrap_at
)
171 s
+= backend
->GetFullName ( file
);
178 v2s ( const string_list
& v
, int wrap_at
)
184 for ( size_t i
= 0; i
< v
.size(); i
++ )
188 if ( wrap_at
> 0 && wrap_count
++ == wrap_at
)
201 static class MingwFactory
: public Backend::Factory
204 MingwFactory() : Factory ( "mingw", "Minimalist GNU Win32" ) {}
205 Backend
* operator() ( Project
& project
,
206 Configuration
& configuration
)
208 return new MingwBackend ( project
,
214 MingwBackend::MingwBackend ( Project
& project
,
215 Configuration
& configuration
)
216 : Backend ( project
, configuration
),
217 manualBinutilsSetting( false ),
218 intermediateDirectory ( new Directory ( "" ) ),
219 outputDirectory ( new Directory ( "" ) ),
220 installDirectory ( new Directory ( "" ) )
225 MingwBackend::~MingwBackend()
227 delete intermediateDirectory
;
228 delete outputDirectory
;
229 delete installDirectory
;
233 MingwBackend::AddDirectoryTarget ( const string
& directory
,
234 Directory
* directoryTree
)
236 if ( directory
.length () > 0)
237 directoryTree
->Add ( directory
.c_str() );
238 return directoryTree
->name
;
242 MingwBackend::CanEnablePreCompiledHeaderSupportForModule ( const Module
& module
)
244 if ( !configuration
.CompilationUnitsEnabled
)
247 const vector
<CompilationUnit
*>& compilationUnits
= module
.non_if_data
.compilationUnits
;
249 for ( i
= 0; i
< compilationUnits
.size (); i
++ )
251 CompilationUnit
& compilationUnit
= *compilationUnits
[i
];
252 if ( compilationUnit
.GetFiles ().size () != 1 )
259 MingwBackend::ProcessModules ()
261 printf ( "Processing modules..." );
263 vector
<MingwModuleHandler
*> v
;
266 for ( std::map
<std::string
, Module
*>::iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
267 fprintf ( fMakefile
, "%s_TYPE:=%u\n", p
->second
->name
.c_str(), p
->second
->type
);
269 for ( std::map
<std::string
, Module
*>::iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
271 Module
& module
= *p
->second
;
272 if ( !module
.enabled
)
274 MingwModuleHandler
* h
= MingwModuleHandler::InstanciateHandler (
277 h
->AddImplicitLibraries ( module
);
278 if ( use_pch
&& CanEnablePreCompiledHeaderSupportForModule ( module
) )
279 h
->EnablePreCompiledHeaderSupport ();
283 size_t iend
= v
.size ();
285 for ( i
= 0; i
< iend
; i
++ )
286 v
[i
]->GenerateSourceMacro();
287 for ( i
= 0; i
< iend
; i
++ )
288 v
[i
]->GenerateObjectMacro();
289 fprintf ( fMakefile
, "\n" );
290 for ( i
= 0; i
< iend
; i
++ )
291 v
[i
]->GenerateTargetMacro();
292 fprintf ( fMakefile
, "\n" );
294 GenerateAllTarget ( v
);
295 GenerateRegTestsRunTarget ();
297 for ( i
= 0; i
< iend
; i
++ )
298 v
[i
]->GenerateOtherMacros();
300 for ( i
= 0; i
< iend
; i
++ )
302 MingwModuleHandler
& h
= *v
[i
];
303 h
.GeneratePreconditionDependencies ();
305 h
.GenerateInvocations ();
306 h
.GenerateCleanTarget ();
307 h
.GenerateInstallTarget ();
308 h
.GenerateDependsTarget ();
316 MingwBackend::Process ()
318 if ( configuration
.CheckDependenciesForModuleOnly
)
319 CheckAutomaticDependenciesForModuleOnly ();
325 MingwBackend::CheckAutomaticDependenciesForModuleOnly ()
327 if ( configuration
.Dependencies
== AutomaticDependencies
)
329 Module
* module
= ProjectNode
.LocateModule ( configuration
.CheckDependenciesForModuleOnlyModule
);
330 if ( module
== NULL
)
332 printf ( "Module '%s' does not exist\n",
333 configuration
.CheckDependenciesForModuleOnlyModule
.c_str () );
337 printf ( "Checking automatic dependencies for module '%s'...",
338 module
->name
.c_str () );
339 AutomaticDependency
automaticDependency ( ProjectNode
);
340 automaticDependency
.CheckAutomaticDependenciesForModule ( *module
,
341 configuration
.Verbose
);
347 MingwBackend::ProcessNormal ()
349 assert(sizeof(ModuleHandlerInformations
)/sizeof(ModuleHandlerInformations
[0]) == TypeDontCare
);
353 DetectNetwideAssembler ();
354 DetectPipeSupport ();
358 GenerateGlobalVariables ();
359 GenerateXmlBuildFilesMacro ();
361 GenerateInstallTarget ();
362 GenerateTestTarget ();
363 GenerateDirectoryTargets ();
364 GenerateDirectories ();
365 GenerateTestSupportCode ();
366 GenerateCompilationUnitSupportCode ();
368 GenerateInstallerFileList();
369 GenerateProxyMakefiles ();
370 CheckAutomaticDependencies ();
375 MingwBackend::GenerateInstallerFileList()
377 this->ProjectNode
.GenerateInstallerFileList();
381 MingwBackend::CreateMakefile ()
383 fMakefile
= fopen ( ProjectNode
.makefile
.c_str (), "w" );
385 throw AccessDeniedException ( ProjectNode
.makefile
);
386 MingwModuleHandler::SetBackend ( this );
387 MingwModuleHandler::SetMakefile ( fMakefile
);
391 MingwBackend::CloseMakefile () const
394 fclose ( fMakefile
);
398 MingwBackend::GenerateHeader () const
400 fprintf ( fMakefile
, "# THIS FILE IS AUTOMATICALLY GENERATED, EDIT '%s' INSTEAD\n\n",
401 ProjectNode
.GetProjectFilename ().c_str () );
405 MingwBackend::GenerateGlobalProperties (
406 const char* assignmentOperation
,
407 const IfableData
& data
) const
409 for ( std::map
<std::string
, Property
*>::const_iterator p
= data
.properties
.begin(); p
!= data
.properties
.end(); ++ p
)
411 Property
& prop
= *p
->second
;
413 if (!prop
.isInternal
)
415 fprintf ( fMakefile
, "%s := %s\n",
417 prop
.value
.c_str() );
423 MingwBackend::GenerateProjectLDFLAGS () const
426 for ( size_t i
= 0; i
< ProjectNode
.linkerFlags
.size (); i
++ )
428 LinkerFlag
& linkerFlag
= *ProjectNode
.linkerFlags
[i
];
429 if ( ldflags
.length () > 0 )
431 ldflags
+= linkerFlag
.flag
;
437 MingwBackend::GenerateGlobalVariables () const
439 fputs ( "include tools$(SEP)rbuild$(SEP)backend$(SEP)mingw$(SEP)rules.mak\n", fMakefile
);
440 fprintf ( fMakefile
, "include tools$(SEP)rbuild$(SEP)backend$(SEP)mingw$(SEP)linkers$(SEP)%s.mak\n", ProjectNode
.GetLinkerSet ().c_str () );
441 fprintf ( fMakefile
, "include tools$(SEP)rbuild$(SEP)backend$(SEP)mingw$(SEP)compilers$(SEP)%s.mak\n", ProjectNode
.GetCompilerSet ().c_str () );
443 if ( mscPath
.length() )
444 fprintf ( fMakefile
, "export RBUILD_CL_PATH=%s\n", mscPath
.c_str () );
446 if ( mslinkPath
.length() )
447 fprintf ( fMakefile
, "export RBUILD_LINK_PATH=%s\n", mslinkPath
.c_str () );
449 if ( configuration
.Dependencies
== FullDependencies
)
452 "ifeq ($(ROS_BUILDDEPS),)\n"
453 "ROS_BUILDDEPS:=%s\n"
460 compilerPrefix
.c_str () );
463 nasmCommand
.c_str () );
465 GenerateGlobalProperties ( "=", ProjectNode
.non_if_data
);
467 if ( ProjectNode
.configuration
.Compiler
== GnuGcc
)
469 fprintf ( fMakefile
, "ifneq ($(OARCH),)\n" );
470 fprintf ( fMakefile
, "PROJECT_ASFLAGS += -march=$(OARCH)\n" );
471 fprintf ( fMakefile
, "PROJECT_CFLAGS += -march=$(OARCH)\n" );
472 fprintf ( fMakefile
, "PROJECT_CXXFLAGS += -march=$(OARCH)\n" );
473 fprintf ( fMakefile
, "endif\n" );
474 fprintf ( fMakefile
, "ifneq ($(TUNE),)\n" );
475 fprintf ( fMakefile
, "PROJECT_CFLAGS += -mtune=$(TUNE)\n" );
476 fprintf ( fMakefile
, "PROJECT_CXXFLAGS += -mtune=$(TUNE)\n" );
477 fprintf ( fMakefile
, "endif\n" );
481 fprintf ( fMakefile
, "PROJECT_CFLAGS += -pipe\n" );
482 fprintf ( fMakefile
, "PROJECT_CXXFLAGS += -pipe\n" );
483 fprintf ( fMakefile
, "PROJECT_ASFLAGS += -pipe\n" );
486 // Would be nice to have our own C++ runtime
487 fputs ( "BUILTIN_CXXINCLUDES+= $(TARGET_CPPFLAGS)\n", fMakefile
);
489 fprintf ( fMakefile
, "PROJECT_CCLIBS := \"$(shell ${TARGET_CC} -print-libgcc-file-name)\"\n" );
491 // We use our proprietary "ofmt_stub.a" to implement a stub for "_get_output_format" required by "libmingwex.a".
492 // This archive just contains the compiled "ofmt_stub.s" supplied with the MinGW Runtime sources.
493 fprintf ( fMakefile
, "PROJECT_CXXLIBS := \"$(shell ${TARGET_CPP} -print-file-name=libstdc++.a)\" \"$(shell ${TARGET_CPP} -print-libgcc-file-name)\" \"$(shell ${TARGET_CPP} -print-file-name=libmingw32.a)\" \"$(shell ${TARGET_CPP} -print-file-name=libmingwex.a)\" \"$(shell ${TARGET_CPP} -print-file-name=ofmt_stub.a)\" \"$(shell ${TARGET_CPP} -print-file-name=libcoldname.a)\"\n" );
495 /* hack to get libgcc_eh.a, should check mingw version or something */
496 if (Environment::GetArch() == "amd64")
497 fprintf ( fMakefile
, " \"$(shell ${TARGET_CPP} -print-file-name=libgcc_eh.a)\"" );
498 /* hack to get _get_output_format, needed by libmingwex */
499 else if (Environment::GetArch() == "i386")
500 fprintf ( fMakefile
, "\"$(shell ${TARGET_CPP} -print-file-name=ofmt_stub.a)\"");
501 fprintf ( fMakefile
,"\n");
503 MingwModuleHandler::GenerateParameters ( "PROJECT", "+=", ProjectNode
.non_if_data
);
504 MingwModuleHandler::GenerateParameters ( "PROJECT_HOST", "+=", ProjectNode
.host_non_if_data
);
506 fprintf ( fMakefile
, "PROJECT_LDFLAGS := %s\n", GenerateProjectLDFLAGS ().c_str () );
508 // TODO: use symbolic names for module types
509 for ( size_t i
= 0; i
< sizeof(ModuleHandlerInformations
) / sizeof(ModuleHandlerInformations
[0]); ++ i
)
511 if ( ModuleHandlerInformations
[i
].cflags
&& ModuleHandlerInformations
[i
].cflags
[0] )
514 "MODULETYPE%d_%sFLAGS:=%s\n",
517 ModuleHandlerInformations
[i
].cflags
);
520 if ( ModuleHandlerInformations
[i
].nasmflags
&& ModuleHandlerInformations
[i
].nasmflags
[0] )
523 "MODULETYPE%d_%sFLAGS:=%s\n",
526 ModuleHandlerInformations
[i
].nasmflags
);
529 if ( ModuleHandlerInformations
[i
].linkerflags
&& ModuleHandlerInformations
[i
].linkerflags
[0] )
532 "MODULETYPE%d_%sFLAGS:=%s\n",
535 ModuleHandlerInformations
[i
].linkerflags
);
540 "MODULETYPE%d_KMODE:=yes\n",
544 "MODULETYPE%d_KMODE:=yes\n",
545 (int)KernelModeDLL
);
548 "MODULETYPE%d_KMODE:=yes\n",
549 (int)KernelModeDriver
);
551 fprintf ( fMakefile
, "\n" );
555 MingwBackend::IncludeInAllTarget ( const Module
& module
) const
557 if ( MingwModuleHandler::ReferenceObjects ( module
) )
559 if ( module
.type
== BootSector
)
561 if ( module
.type
== Iso
)
563 if ( module
.type
== LiveIso
)
565 if ( module
.type
== Test
)
567 if ( module
.type
== Alias
)
573 MingwBackend::GenerateAllTarget ( const vector
<MingwModuleHandler
*>& handlers
) const
575 fprintf ( fMakefile
, "all:" );
577 size_t iend
= handlers
.size ();
578 for ( size_t i
= 0; i
< iend
; i
++ )
580 const Module
& module
= handlers
[i
]->module
;
581 if ( IncludeInAllTarget ( module
) )
583 if ( wrap_count
++ == 5 )
584 fprintf ( fMakefile
, " \\\n\t\t" ), wrap_count
= 0;
587 GetTargetMacro(module
).c_str () );
590 fprintf ( fMakefile
, "\n\t\n\n" );
594 MingwBackend::GenerateRegTestsRunTarget () const
597 "REGTESTS_RUN_TARGET = regtests.dll\n" );
599 "$(REGTESTS_RUN_TARGET): $(REGTESTS_TARGET)\n" );
601 "\t$(cp) $(REGTESTS_TARGET) $(REGTESTS_RUN_TARGET)\n" );
602 fprintf ( fMakefile
, "\n" );
606 MingwBackend::GenerateXmlBuildFilesMacro() const
609 "XMLBUILDFILES = %s \\\n",
610 ProjectNode
.GetProjectFilename ().c_str () );
611 string xmlbuildFilenames
;
612 int numberOfExistingFiles
= 0;
614 time_t SystemTime
, lastWriteTime
;
616 for ( size_t i
= 0; i
< ProjectNode
.xmlbuildfiles
.size (); i
++ )
618 XMLInclude
& xmlbuildfile
= *ProjectNode
.xmlbuildfiles
[i
];
619 if ( !xmlbuildfile
.fileExists
)
621 numberOfExistingFiles
++;
622 if ( xmlbuildFilenames
.length () > 0 )
623 xmlbuildFilenames
+= " ";
625 FILE* f
= fopen ( xmlbuildfile
.topIncludeFilename
.c_str (), "rb" );
627 throw FileNotFoundException ( NormalizeFilename ( xmlbuildfile
.topIncludeFilename
) );
629 if ( fstat ( fileno ( f
), &statbuf
) != 0 )
632 throw AccessDeniedException ( NormalizeFilename ( xmlbuildfile
.topIncludeFilename
) );
635 lastWriteTime
= statbuf
.st_mtime
;
636 SystemTime
= time(NULL
);
638 if (SystemTime
!= -1)
640 if (difftime (lastWriteTime
, SystemTime
) > 0)
641 throw InvalidDateException ( NormalizeFilename ( xmlbuildfile
.topIncludeFilename
) );
646 xmlbuildFilenames
+= NormalizeFilename ( xmlbuildfile
.topIncludeFilename
);
647 if ( numberOfExistingFiles
% 5 == 4 || i
== ProjectNode
.xmlbuildfiles
.size () - 1 )
651 xmlbuildFilenames
.c_str ());
652 if ( i
== ProjectNode
.xmlbuildfiles
.size () - 1 )
654 fprintf ( fMakefile
, "\n" );
661 xmlbuildFilenames
.resize ( 0 );
663 numberOfExistingFiles
++;
665 fprintf ( fMakefile
, "\n" );
669 MingwBackend::GenerateTestSupportCode ()
671 printf ( "Generating test support code..." );
672 TestSupportCode
testSupportCode ( ProjectNode
);
673 testSupportCode
.GenerateTestSupportCode ( configuration
.Verbose
);
678 MingwBackend::GenerateCompilationUnitSupportCode ()
680 if ( configuration
.CompilationUnitsEnabled
)
682 printf ( "Generating compilation unit support code..." );
683 CompilationUnitSupportCode
compilationUnitSupportCode ( ProjectNode
);
684 compilationUnitSupportCode
.Generate ( configuration
.Verbose
);
690 MingwBackend::GenerateSysSetup ()
692 printf ( "Generating syssetup.inf..." );
693 SysSetupGenerator
sysSetupGenerator ( ProjectNode
);
694 sysSetupGenerator
.Generate ();
699 MingwBackend::GetProxyMakefileTree () const
701 if ( configuration
.GenerateProxyMakefilesInSourceTree
)
704 return Environment::GetOutputPath ();
708 MingwBackend::GenerateProxyMakefiles ()
710 printf ( "Generating proxy makefiles..." );
711 ProxyMakefile
proxyMakefile ( ProjectNode
);
712 proxyMakefile
.GenerateProxyMakefiles ( configuration
.Verbose
,
713 GetProxyMakefileTree () );
718 MingwBackend::CheckAutomaticDependencies ()
720 if ( configuration
.Dependencies
== AutomaticDependencies
)
722 printf ( "Checking automatic dependencies..." );
723 AutomaticDependency
automaticDependency ( ProjectNode
);
724 automaticDependency
.CheckAutomaticDependencies ( configuration
.Verbose
);
730 MingwBackend::GenerateDirectories ()
732 printf ( "Creating directories..." );
733 intermediateDirectory
->GenerateTree ( IntermediateDirectory
, configuration
.Verbose
);
734 outputDirectory
->GenerateTree ( OutputDirectory
, configuration
.Verbose
);
735 if ( !configuration
.MakeHandlesInstallDirectories
)
736 installDirectory
->GenerateTree ( InstallDirectory
, configuration
.Verbose
);
741 MingwBackend::TryToDetectThisCompiler ( const string
& compiler
)
743 string command
= ssprintf (
745 FixSeparatorForSystemCommand(compiler
).c_str (),
748 int exitcode
= system ( command
.c_str () );
749 return (bool) (exitcode
== 0);
753 MingwBackend::DetectCompiler ()
755 printf ( "Detecting compiler..." );
757 bool detectedCompiler
= false;
758 bool supportedCompiler
= false;
759 string compilerVersion
;
761 if ( ProjectNode
.configuration
.Compiler
== GnuGcc
)
763 const string
& TARGET_CCValue
= Environment::GetVariable ( "TARGET_CC" );
764 const string
& ROS_PREFIXValue
= Environment::GetVariable ( "ROS_PREFIX" );
766 if ( TARGET_CCValue
.length () > 0 )
769 compilerCommand
= TARGET_CCValue
;
770 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
773 if ( !detectedCompiler
)
775 if ( ROS_PREFIXValue
.length () > 0 )
777 compilerPrefix
= ROS_PREFIXValue
;
778 compilerCommand
= compilerPrefix
+ "-gcc";
779 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
783 if ( !detectedCompiler
)
786 compilerCommand
= "gcc";
787 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
790 if ( !detectedCompiler
)
792 compilerPrefix
= "mingw32";
793 compilerCommand
= compilerPrefix
+ "-gcc";
794 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
797 if ( detectedCompiler
)
798 compilerVersion
= GetCompilerVersion ( compilerCommand
);
800 supportedCompiler
= IsSupportedCompilerVersion ( compilerVersion
);
802 else if ( ProjectNode
.configuration
.Compiler
== MicrosoftC
)
804 compilerCommand
= "cl";
805 detectedCompiler
= DetectMicrosoftCompiler ( compilerVersion
, mscPath
);
806 supportedCompiler
= true; // TODO
809 if ( detectedCompiler
)
811 if ( supportedCompiler
)
812 printf ( "detected (%s %s)\n", compilerCommand
.c_str (), compilerVersion
.c_str() );
815 printf ( "detected (%s), but with unsupported version (%s)\n",
816 compilerCommand
.c_str (),
817 compilerVersion
.c_str () );
818 throw UnsupportedBuildToolException ( compilerCommand
, compilerVersion
);
822 printf ( "not detected\n" );
827 MingwBackend::TryToDetectThisNetwideAssembler ( const string
& assembler
)
829 string command
= ssprintf (
831 FixSeparatorForSystemCommand(assembler
).c_str (),
834 int exitcode
= system ( command
.c_str () );
835 return (bool) (exitcode
== 0);
839 MingwBackend::GetVersionString ( const string
& versionCommand
)
846 fp
= popen ( versionCommand
.c_str () , "r" );
849 ( feof ( fp
) == 0 &&
850 ( ( ch
= fgetc( fp
) ) != -1 ) );
853 buffer
[i
] = (char) ch
;
858 char separators
[] = " ()\n";
860 char *prevtoken
= NULL
;
864 token
= strtok ( buffer
, separators
);
865 while ( token
!= NULL
)
868 version
= string( prevtoken
);
869 if ( (newline
= version
.find('\n')) != std::string::npos
)
870 version
.erase(newline
, 1);
871 if ( version
.find('.') != std::string::npos
)
873 token
= strtok ( NULL
, separators
);
879 MingwBackend::GetNetwideAssemblerVersion ( const string
& nasmCommand
)
881 string versionCommand
;
882 if ( nasmCommand
.find("yasm") != std::string::npos
)
884 versionCommand
= ssprintf ( "%s --version",
885 nasmCommand
.c_str (),
891 versionCommand
= ssprintf ( "%s -v",
892 nasmCommand
.c_str (),
896 return GetVersionString( versionCommand
);
900 MingwBackend::GetCompilerVersion ( const string
& compilerCommand
)
902 string versionCommand
= ssprintf ( "%s --version",
903 compilerCommand
.c_str (),
906 return GetVersionString( versionCommand
);
910 MingwBackend::GetBinutilsVersion ( const string
& binutilsCommand
)
912 string versionCommand
= ssprintf ( "%s -v",
913 binutilsCommand
.c_str (),
916 return GetVersionString( versionCommand
);
920 MingwBackend::IsSupportedCompilerVersion ( const string
& compilerVersion
)
922 if ( strcmp ( compilerVersion
.c_str (), "4.4.0") < 0 )
929 MingwBackend::TryToDetectThisBinutils ( const string
& binutils
)
931 string command
= ssprintf (
933 FixSeparatorForSystemCommand(binutils
).c_str (),
936 int exitcode
= system ( command
.c_str () );
937 return (exitcode
== 0);
941 MingwBackend::GetBinutilsVersionDate ( const string
& binutilsCommand
)
947 string versionCommand
= ssprintf ( "%s -v",
948 binutilsCommand
.c_str (),
951 fp
= popen ( versionCommand
.c_str () , "r" );
954 ( feof ( fp
) == 0 &&
955 ( ( ch
= fgetc( fp
) ) != -1 ) );
958 buffer
[i
] = (char) ch
;
963 char separators
[] = " ";
965 char *prevtoken
= NULL
;
967 token
= strtok ( buffer
, separators
);
968 while ( token
!= NULL
)
971 token
= strtok ( NULL
, separators
);
973 string version
= string ( prevtoken
);
974 int lastDigit
= version
.find_last_not_of ( "\t\r\n" );
975 if ( lastDigit
!= -1 )
976 return string ( version
, 0, lastDigit
+1 );
982 MingwBackend::IsSupportedBinutilsVersion ( const string
& binutilsVersion
)
984 int digit
= binutilsVersion
.find_last_of(".");
987 printf("Unable to detect binutils version!\n");
991 string date
= string(binutilsVersion
, digit
+ 1);
992 if(date
.length() == 8)
994 /* This is a real date in the format YYYYMMDD.
995 Check whether we have at least Binutils 20091016 (the oldest one
996 we were still using after upgrading to RosBE 1.5). */
997 if(strcmp(date
.c_str(), "20091016") < 0)
1002 /* This is no date, so binutilsVersion should just contain the version
1004 Binutils 2.20 will hopefully contain the required features. */
1005 if(strcmp(binutilsVersion
.c_str(), "2.20") < 0)
1013 MingwBackend::DetectBinutils ()
1015 printf ( "Detecting binutils..." );
1017 bool detectedBinutils
= false;
1018 bool supportedBinutils
= false;
1019 string binutilsVersion
;
1021 if ( ProjectNode
.configuration
.Linker
== GnuLd
)
1023 const string
& ROS_PREFIXValue
= Environment::GetVariable ( "ROS_PREFIX" );
1025 if ( ROS_PREFIXValue
.length () > 0 )
1027 binutilsPrefix
= ROS_PREFIXValue
;
1028 binutilsCommand
= binutilsPrefix
+ "-ld";
1029 manualBinutilsSetting
= true;
1030 detectedBinutils
= true;
1033 if ( !detectedBinutils
)
1035 binutilsPrefix
= "";
1036 binutilsCommand
= "ld";
1037 detectedBinutils
= TryToDetectThisBinutils ( binutilsCommand
);
1040 if ( !detectedBinutils
)
1042 binutilsPrefix
= "mingw32";
1043 binutilsCommand
= binutilsPrefix
+ "-ld";
1044 detectedBinutils
= TryToDetectThisBinutils ( binutilsCommand
);
1046 if ( detectedBinutils
)
1048 binutilsVersion
= GetBinutilsVersionDate ( binutilsCommand
);
1049 supportedBinutils
= IsSupportedBinutilsVersion ( binutilsVersion
);
1052 else if ( ProjectNode
.configuration
.Linker
== MicrosoftLink
)
1054 compilerCommand
= "link";
1055 detectedBinutils
= DetectMicrosoftLinker ( binutilsVersion
, mslinkPath
);
1056 supportedBinutils
= true; // TODO
1059 if ( detectedBinutils
)
1061 if ( supportedBinutils
)
1062 printf ( "detected (%s %s)\n", binutilsCommand
.c_str (), binutilsVersion
.c_str() );
1065 printf ( "detected (%s), but with unsupported version (%s)\n",
1066 binutilsCommand
.c_str (),
1067 binutilsVersion
.c_str () );
1068 throw UnsupportedBuildToolException ( binutilsCommand
, binutilsVersion
);
1072 printf ( "not detected\n" );
1077 MingwBackend::DetectNetwideAssembler ()
1079 printf ( "Detecting netwide assembler..." );
1081 nasmCommand
= "nasm";
1082 bool detectedNasm
= TryToDetectThisNetwideAssembler ( nasmCommand
);
1084 if ( !detectedNasm
)
1086 nasmCommand
= "nasmw";
1087 detectedNasm
= TryToDetectThisNetwideAssembler ( nasmCommand
);
1090 if ( !detectedNasm
)
1092 nasmCommand
= "yasm";
1093 detectedNasm
= TryToDetectThisNetwideAssembler ( nasmCommand
);
1096 printf ( "detected (%s %s)\n", nasmCommand
.c_str (), GetNetwideAssemblerVersion( nasmCommand
).c_str() );
1098 printf ( "not detected\n" );
1102 MingwBackend::DetectPipeSupport ()
1104 if ( ProjectNode
.configuration
.Compiler
== GnuGcc
)
1106 printf ( "Detecting compiler -pipe support..." );
1108 string pipe_detection
= "tools" + sSep
+ "rbuild" + sSep
+ "backend" + sSep
+ "mingw" + sSep
+ "pipe_detection.c";
1109 string pipe_detectionObjectFilename
= ReplaceExtension ( pipe_detection
,
1111 string command
= ssprintf (
1112 "%s -pipe -c %s -o %s 1>%s 2>%s",
1113 FixSeparatorForSystemCommand(compilerCommand
).c_str (),
1114 pipe_detection
.c_str (),
1115 pipe_detectionObjectFilename
.c_str (),
1118 int exitcode
= system ( command
.c_str () );
1119 FILE* f
= fopen ( pipe_detectionObjectFilename
.c_str (), "rb" );
1122 usePipe
= (exitcode
== 0);
1124 unlink ( pipe_detectionObjectFilename
.c_str () );
1130 printf ( "detected\n" );
1132 printf ( "not detected\n" );
1139 MingwBackend::DetectPCHSupport ()
1141 printf ( "Detecting compiler pre-compiled header support..." );
1143 if ( configuration
.PrecompiledHeadersEnabled
&& ProjectNode
.configuration
.Compiler
== GnuGcc
)
1145 string path
= "tools" + sSep
+ "rbuild" + sSep
+ "backend" + sSep
+ "mingw" + sSep
+ "pch_detection.h";
1146 string cmd
= ssprintf (
1147 "%s -c %s 1>%s 2>%s",
1148 FixSeparatorForSystemCommand(compilerCommand
).c_str (),
1152 system ( cmd
.c_str () );
1155 FILE* f
= fopen ( path
.c_str (), "rb" );
1160 unlink ( path
.c_str () );
1166 printf ( "detected\n" );
1168 printf ( "not detected\n" );
1173 printf ( "disabled\n" );
1178 MingwBackend::GetNonModuleInstallTargetFiles (
1179 vector
<FileLocation
>& out
) const
1181 for ( size_t i
= 0; i
< ProjectNode
.installfiles
.size (); i
++ )
1183 const InstallFile
& installfile
= *ProjectNode
.installfiles
[i
];
1184 out
.push_back ( *installfile
.target
);
1189 MingwBackend::GetModuleInstallTargetFiles (
1190 vector
<FileLocation
>& out
) const
1192 for ( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
1194 const Module
& module
= *p
->second
;
1195 if ( !module
.enabled
)
1197 if ( module
.install
)
1198 out
.push_back ( *module
.install
);
1203 MingwBackend::GetInstallTargetFiles (
1204 vector
<FileLocation
>& out
) const
1206 GetNonModuleInstallTargetFiles ( out
);
1207 GetModuleInstallTargetFiles ( out
);
1211 MingwBackend::OutputInstallTarget ( const FileLocation
& source
,
1212 const FileLocation
& target
)
1214 fprintf ( fMakefile
,
1216 GetFullName ( target
).c_str (),
1217 GetFullName ( source
).c_str (),
1218 GetFullPath ( target
).c_str () );
1219 fprintf ( fMakefile
,
1221 fprintf ( fMakefile
,
1222 "\t${cp} %s %s 1>$(NUL)\n",
1223 GetFullName ( source
).c_str (),
1224 GetFullName ( target
).c_str () );
1228 MingwBackend::OutputNonModuleInstallTargets ()
1230 for ( size_t i
= 0; i
< ProjectNode
.installfiles
.size (); i
++ )
1232 const InstallFile
& installfile
= *ProjectNode
.installfiles
[i
];
1233 OutputInstallTarget ( *installfile
.source
, *installfile
.target
);
1238 MingwBackend::GetAliasedModuleOrModule ( const Module
& module
) const
1240 if ( module
.aliasedModuleName
.size () > 0 )
1242 const Module
* aliasedModule
= ProjectNode
.LocateModule ( module
.aliasedModuleName
);
1243 assert ( aliasedModule
);
1244 return *aliasedModule
;
1251 MingwBackend::OutputModuleInstallTargets ()
1253 for ( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
1255 const Module
& module
= *p
->second
;
1256 if ( !module
.enabled
)
1258 if ( module
.install
)
1260 const Module
& aliasedModule
= GetAliasedModuleOrModule ( module
);
1261 OutputInstallTarget ( *aliasedModule
.output
, *module
.install
);
1267 MingwBackend::GetRegistrySourceFiles ()
1269 return "boot" + sSep
+ "bootdata" + sSep
+ "hivecls_" + Environment::GetArch() + ".inf "
1270 "boot" + sSep
+ "bootdata" + sSep
+ "hivedef_" + Environment::GetArch() + ".inf "
1271 "boot" + sSep
+ "bootdata" + sSep
+ "hiveinst_" + Environment::GetArch() + ".inf "
1272 "boot" + sSep
+ "bootdata" + sSep
+ "hivesft_" + Environment::GetArch() + ".inf "
1273 "boot" + sSep
+ "bootdata" + sSep
+ "hivesys_" + Environment::GetArch() + ".inf ";
1277 MingwBackend::GetRegistryTargetFiles ()
1279 string system32ConfigDirectory
= "system32" + sSep
+ "config";
1280 FileLocation
system32 ( InstallDirectory
, system32ConfigDirectory
, "" );
1282 vector
<FileLocation
> registry_files
;
1283 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "default" ) );
1284 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "sam" ) );
1285 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "security" ) );
1286 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "software" ) );
1287 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "system" ) );
1289 return v2s( this, registry_files
, 6 );
1293 MingwBackend::OutputRegistryInstallTarget ()
1295 FileLocation
system32 ( InstallDirectory
, "system32" + sSep
+ "config", "" );
1297 string registrySourceFiles
= GetRegistrySourceFiles ();
1298 string registryTargetFiles
= GetRegistryTargetFiles ();
1299 fprintf ( fMakefile
,
1300 "install_registry: %s\n",
1301 registryTargetFiles
.c_str () );
1302 fprintf ( fMakefile
,
1303 "%s: %s %s $(mkhive_TARGET)\n",
1304 registryTargetFiles
.c_str (),
1305 registrySourceFiles
.c_str (),
1306 GetFullPath ( system32
).c_str () );
1307 fprintf ( fMakefile
,
1308 "\t$(ECHO_MKHIVE)\n" );
1309 fprintf ( fMakefile
,
1310 "\t$(mkhive_TARGET) boot%cbootdata %s $(ARCH) boot%cbootdata%chiveinst_$(ARCH).inf\n",
1311 cSep
, GetFullPath ( system32
).c_str (),
1313 fprintf ( fMakefile
,
1318 MingwBackend::GenerateInstallTarget ()
1320 vector
<FileLocation
> vInstallTargetFiles
;
1321 GetInstallTargetFiles ( vInstallTargetFiles
);
1322 string installTargetFiles
= v2s ( this, vInstallTargetFiles
, 5 );
1323 string registryTargetFiles
= GetRegistryTargetFiles ();
1325 fprintf ( fMakefile
,
1327 installTargetFiles
.c_str (),
1328 registryTargetFiles
.c_str () );
1329 OutputNonModuleInstallTargets ();
1330 OutputModuleInstallTargets ();
1331 OutputRegistryInstallTarget ();
1332 fprintf ( fMakefile
,
1337 MingwBackend::GetModuleTestTargets (
1338 vector
<string
>& out
) const
1340 for ( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
1342 const Module
& module
= *p
->second
;
1343 if ( !module
.enabled
)
1345 if ( module
.type
== Test
)
1346 out
.push_back ( module
.name
);
1351 MingwBackend::GenerateTestTarget ()
1353 vector
<string
> vTestTargets
;
1354 GetModuleTestTargets ( vTestTargets
);
1355 string testTargets
= v2s ( vTestTargets
, 5 );
1357 fprintf ( fMakefile
,
1359 testTargets
.c_str () );
1360 fprintf ( fMakefile
,
1365 MingwBackend::GenerateDirectoryTargets ()
1367 intermediateDirectory
->CreateRule ( fMakefile
, "$(INTERMEDIATE)" );
1368 outputDirectory
->CreateRule ( fMakefile
, "$(OUTPUT)" );
1369 installDirectory
->CreateRule ( fMakefile
, "$(INSTALL)" );