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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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
, "", "", "" }, // 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
73 MingwBackend::GetFullPath ( const FileLocation
& file
) const
75 MingwModuleHandler::PassThruCacheDirectory ( &file
);
78 switch ( file
.directory
)
83 case IntermediateDirectory
:
84 directory
= "$(INTERMEDIATE)";
87 directory
= "$(OUTPUT)";
89 case InstallDirectory
:
90 directory
= "$(INSTALL)";
92 case TemporaryDirectory
:
93 directory
= "$(TEMPORARY)";
96 throw InvalidOperationException ( __FILE__
,
98 "Invalid directory %d.",
102 if ( file
.relative_path
.length () > 0 )
104 if ( directory
.length () > 0 )
106 directory
+= file
.relative_path
;
112 MingwBackend::GetFullName ( const FileLocation
& file
) const
115 switch ( file
.directory
)
117 case SourceDirectory
:
120 case IntermediateDirectory
:
121 directory
= "$(INTERMEDIATE)";
123 case OutputDirectory
:
124 directory
= "$(OUTPUT)";
126 case InstallDirectory
:
127 directory
= "$(INSTALL)";
129 case TemporaryDirectory
:
130 directory
= "$(TEMPORARY)";
133 throw InvalidOperationException ( __FILE__
,
135 "Invalid directory %d.",
139 if ( file
.relative_path
.length () > 0 )
141 if ( directory
.length () > 0 )
143 directory
+= file
.relative_path
;
146 if ( directory
.length () > 0 )
149 return directory
+ file
.name
;
153 v2s ( const Backend
* backend
, const vector
<FileLocation
>& files
, int wrap_at
)
159 for ( size_t i
= 0; i
< files
.size(); i
++ )
161 const FileLocation
& file
= files
[i
];
162 if ( wrap_at
> 0 && wrap_count
++ == wrap_at
)
166 s
+= backend
->GetFullName ( file
);
173 v2s ( const string_list
& v
, int wrap_at
)
179 for ( size_t i
= 0; i
< v
.size(); i
++ )
183 if ( wrap_at
> 0 && wrap_count
++ == wrap_at
)
193 static class MingwFactory
: public Backend::Factory
196 MingwFactory() : Factory ( "mingw", "Minimalist GNU Win32" ) {}
197 Backend
* operator() ( Project
& project
,
198 Configuration
& configuration
)
200 return new MingwBackend ( project
,
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 ( "" ) )
217 MingwBackend::~MingwBackend()
219 delete intermediateDirectory
;
220 delete outputDirectory
;
221 delete installDirectory
;
225 MingwBackend::AddDirectoryTarget ( const string
& directory
,
226 Directory
* directoryTree
)
228 if ( directory
.length () > 0)
229 directoryTree
->Add ( directory
.c_str() );
230 return directoryTree
->name
;
234 MingwBackend::CanEnablePreCompiledHeaderSupportForModule ( const Module
& module
)
236 if ( !configuration
.CompilationUnitsEnabled
)
239 const vector
<CompilationUnit
*>& compilationUnits
= module
.non_if_data
.compilationUnits
;
241 for ( i
= 0; i
< compilationUnits
.size (); i
++ )
243 CompilationUnit
& compilationUnit
= *compilationUnits
[i
];
244 if ( compilationUnit
.GetFiles ().size () != 1 )
251 MingwBackend::ProcessModules ()
253 printf ( "Processing modules..." );
255 vector
<MingwModuleHandler
*> v
;
258 for ( std::map
<std::string
, Module
*>::iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
260 Module
& module
= *p
->second
;
261 if ( !module
.enabled
)
263 MingwModuleHandler
* h
= MingwModuleHandler::InstanciateHandler (
266 h
->AddImplicitLibraries ( module
);
267 if ( use_pch
&& CanEnablePreCompiledHeaderSupportForModule ( module
) )
268 h
->EnablePreCompiledHeaderSupport ();
272 size_t iend
= v
.size ();
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" );
283 GenerateAllTarget ( v
);
284 GenerateRegTestsRunTarget ();
286 for ( i
= 0; i
< iend
; i
++ )
287 v
[i
]->GenerateOtherMacros();
289 for ( i
= 0; i
< iend
; i
++ )
291 MingwModuleHandler
& h
= *v
[i
];
292 h
.GeneratePreconditionDependencies ();
294 h
.GenerateInvocations ();
295 h
.GenerateCleanTarget ();
296 h
.GenerateInstallTarget ();
297 h
.GenerateDependsTarget ();
305 MingwBackend::Process ()
307 if ( configuration
.CheckDependenciesForModuleOnly
)
308 CheckAutomaticDependenciesForModuleOnly ();
314 MingwBackend::CheckAutomaticDependenciesForModuleOnly ()
316 if ( configuration
.Dependencies
== AutomaticDependencies
)
318 Module
* module
= ProjectNode
.LocateModule ( configuration
.CheckDependenciesForModuleOnlyModule
);
319 if ( module
== NULL
)
321 printf ( "Module '%s' does not exist\n",
322 configuration
.CheckDependenciesForModuleOnlyModule
.c_str () );
326 printf ( "Checking automatic dependencies for module '%s'...",
327 module
->name
.c_str () );
328 AutomaticDependency
automaticDependency ( ProjectNode
);
329 automaticDependency
.CheckAutomaticDependenciesForModule ( *module
,
330 configuration
.Verbose
);
336 MingwBackend::ProcessNormal ()
338 assert(sizeof(ModuleHandlerInformations
)/sizeof(ModuleHandlerInformations
[0]) == TypeDontCare
);
342 DetectNetwideAssembler ();
343 DetectPipeSupport ();
347 GenerateGlobalVariables ();
348 GenerateXmlBuildFilesMacro ();
350 GenerateInstallTarget ();
351 GenerateTestTarget ();
352 GenerateDirectoryTargets ();
353 GenerateDirectories ();
354 GenerateTestSupportCode ();
355 GenerateCompilationUnitSupportCode ();
357 GenerateProxyMakefiles ();
358 CheckAutomaticDependencies ();
363 MingwBackend::CreateMakefile ()
365 fMakefile
= fopen ( ProjectNode
.makefile
.c_str (), "w" );
367 throw AccessDeniedException ( ProjectNode
.makefile
);
368 MingwModuleHandler::SetBackend ( this );
369 MingwModuleHandler::SetMakefile ( fMakefile
);
373 MingwBackend::CloseMakefile () const
376 fclose ( fMakefile
);
380 MingwBackend::GenerateHeader () const
382 fprintf ( fMakefile
, "# THIS FILE IS AUTOMATICALLY GENERATED, EDIT '%s' INSTEAD\n\n",
383 ProjectNode
.GetProjectFilename ().c_str () );
387 MingwBackend::GenerateProjectCFlagsMacro ( const char* assignmentOperation
,
388 const IfableData
& data
) const
390 set
<string
> used_defs
;
392 if ( data
.includes
.size () > 0 )
395 "PROJECT_CINCLUDES %s %s\n",
397 MingwModuleHandler::GenerateGccIncludeParametersFromVector ( data
.includes
).c_str ());
399 if ( data
.defines
.size () > 0 )
402 "PROJECT_CDEFINES %s %s\n",
404 MingwModuleHandler::GenerateGccDefineParametersFromVector ( data
.defines
, used_defs
).c_str ());
408 MingwBackend::GenerateGlobalCFlagsAndProperties (
409 const char* assignmentOperation
,
410 const IfableData
& data
) const
412 for ( std::map
<std::string
, Property
*>::const_iterator p
= data
.properties
.begin(); p
!= data
.properties
.end(); ++ p
)
414 Property
& prop
= *p
->second
;
416 if (!prop
.isInternal
)
418 fprintf ( fMakefile
, "%s := %s\n",
420 prop
.value
.c_str() );
424 if ( data
.includes
.size() || data
.defines
.size() )
426 GenerateProjectCFlagsMacro ( assignmentOperation
,
432 MingwBackend::GenerateProjectGccOptionsMacro ( const char* assignmentOperation
,
433 IfableData
& data
) const
439 "PROJECT_GCCOPTIONS %s",
440 assignmentOperation
);
442 for ( i
= 0; i
< data
.compilerFlags
.size(); i
++ )
444 if ( data
.compilerFlags
[i
]->compiler
== CompilerTypeDontCare
)
449 data
.compilerFlags
[i
]->flag
.c_str() );
453 fputs ( "\n", fMakefile
);
455 // TODO: reference these from somewhere
458 "PROJECT_GCC_CFLAGS %s",
459 assignmentOperation
);
461 for ( i
= 0; i
< data
.compilerFlags
.size(); i
++ )
463 if ( data
.compilerFlags
[i
]->compiler
== CompilerTypeCC
)
468 data
.compilerFlags
[i
]->flag
.c_str() );
472 fputs ( "\n", fMakefile
);
476 "PROJECT_GCC_CXXFLAGS %s",
477 assignmentOperation
);
479 for ( i
= 0; i
< data
.compilerFlags
.size(); i
++ )
481 if ( data
.compilerFlags
[i
]->compiler
== CompilerTypeCPP
)
486 data
.compilerFlags
[i
]->flag
.c_str() );
490 fputs ( "\n", fMakefile
);
494 MingwBackend::GenerateProjectGccOptions (
495 const char* assignmentOperation
,
496 IfableData
& data
) const
498 if ( data
.compilerFlags
.size() )
500 GenerateProjectGccOptionsMacro ( assignmentOperation
,
506 MingwBackend::GenerateProjectLFLAGS () const
509 for ( size_t i
= 0; i
< ProjectNode
.linkerFlags
.size (); i
++ )
511 LinkerFlag
& linkerFlag
= *ProjectNode
.linkerFlags
[i
];
512 if ( lflags
.length () > 0 )
514 lflags
+= linkerFlag
.flag
;
520 MingwBackend::GenerateGlobalVariables () const
522 fputs ( "include tools$(SEP)rbuild$(SEP)backend$(SEP)mingw$(SEP)rules.mak\n", fMakefile
);
524 if ( configuration
.Dependencies
== FullDependencies
)
527 "ifeq ($(ROS_BUILDDEPS),)\n"
528 "ROS_BUILDDEPS:=%s\n"
535 compilerPrefix
.c_str () );
538 nasmCommand
.c_str () );
540 GenerateGlobalCFlagsAndProperties ( "=", ProjectNode
.non_if_data
);
541 GenerateProjectGccOptions ( "=", ProjectNode
.non_if_data
);
543 fprintf ( fMakefile
, "PROJECT_RCFLAGS := $(PROJECT_CINCLUDES) $(PROJECT_CDEFINES)\n" );
544 fprintf ( fMakefile
, "PROJECT_WIDLFLAGS := $(PROJECT_CINCLUDES) $(PROJECT_CDEFINES)\n" );
545 fprintf ( fMakefile
, "PROJECT_LFLAGS := '$(shell ${TARGET_CC} -print-libgcc-file-name)' %s\n", GenerateProjectLFLAGS ().c_str () );
546 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)' '$(shell ${TARGET_CPP} -print-file-name=libcoldname.a)'\n" );
547 /* hack to get libgcc_eh.a, should check mingw version or something */
548 fprintf ( fMakefile
, "ifeq ($(ARCH),amd64)\n" );
549 fprintf ( fMakefile
, "PROJECT_LPPFLAGS += '$(shell ${TARGET_CPP} -print-file-name=libgcc_eh.a)'\n" );
550 fprintf ( fMakefile
, "endif\n" );
551 fprintf ( fMakefile
, "PROJECT_GCCOPTIONS += -Wall\n" );
552 fprintf ( fMakefile
, "ifneq ($(OARCH),)\n" );
553 fprintf ( fMakefile
, "PROJECT_GCCOPTIONS += -march=$(OARCH)\n" );
554 fprintf ( fMakefile
, "endif\n" );
555 fprintf ( fMakefile
, "ifneq ($(TUNE),)\n" );
556 fprintf ( fMakefile
, "PROJECT_GCCOPTIONS += -mtune=$(TUNE)\n" );
557 fprintf ( fMakefile
, "endif\n" );
558 fprintf ( fMakefile
, "PROJECT_CFLAGS = $(PROJECT_GCCOPTIONS) $(PROJECT_GCC_CFLAGS)\n" );
559 fprintf ( fMakefile
, "PROJECT_CXXFLAGS = $(PROJECT_GCCOPTIONS) $(PROJECT_GCC_CXXFLAGS)\n" );
560 fprintf ( fMakefile
, "\n" );
564 MingwBackend::IncludeInAllTarget ( const Module
& module
) const
566 if ( MingwModuleHandler::ReferenceObjects ( module
) )
568 if ( module
.type
== BootSector
)
570 if ( module
.type
== Iso
)
572 if ( module
.type
== LiveIso
)
574 if ( module
.type
== IsoRegTest
)
576 if ( module
.type
== LiveIsoRegTest
)
578 if ( module
.type
== Test
)
580 if ( module
.type
== Alias
)
586 MingwBackend::GenerateAllTarget ( const vector
<MingwModuleHandler
*>& handlers
) const
588 fprintf ( fMakefile
, "all:" );
590 size_t iend
= handlers
.size ();
591 for ( size_t i
= 0; i
< iend
; i
++ )
593 const Module
& module
= handlers
[i
]->module
;
594 if ( IncludeInAllTarget ( module
) )
596 if ( wrap_count
++ == 5 )
597 fprintf ( fMakefile
, " \\\n\t\t" ), wrap_count
= 0;
600 GetTargetMacro(module
).c_str () );
603 fprintf ( fMakefile
, "\n\t\n\n" );
607 MingwBackend::GenerateRegTestsRunTarget () const
610 "REGTESTS_RUN_TARGET = regtests.dll\n" );
612 "$(REGTESTS_RUN_TARGET): $(REGTESTS_TARGET)\n" );
614 "\t$(cp) $(REGTESTS_TARGET) $(REGTESTS_RUN_TARGET)\n" );
615 fprintf ( fMakefile
, "\n" );
619 MingwBackend::GenerateXmlBuildFilesMacro() const
622 "XMLBUILDFILES = %s \\\n",
623 ProjectNode
.GetProjectFilename ().c_str () );
624 string xmlbuildFilenames
;
625 int numberOfExistingFiles
= 0;
627 time_t SystemTime
, lastWriteTime
;
629 for ( size_t i
= 0; i
< ProjectNode
.xmlbuildfiles
.size (); i
++ )
631 XMLInclude
& xmlbuildfile
= *ProjectNode
.xmlbuildfiles
[i
];
632 if ( !xmlbuildfile
.fileExists
)
634 numberOfExistingFiles
++;
635 if ( xmlbuildFilenames
.length () > 0 )
636 xmlbuildFilenames
+= " ";
638 FILE* f
= fopen ( xmlbuildfile
.topIncludeFilename
.c_str (), "rb" );
640 throw FileNotFoundException ( NormalizeFilename ( xmlbuildfile
.topIncludeFilename
) );
642 if ( fstat ( fileno ( f
), &statbuf
) != 0 )
645 throw AccessDeniedException ( NormalizeFilename ( xmlbuildfile
.topIncludeFilename
) );
648 lastWriteTime
= statbuf
.st_mtime
;
649 SystemTime
= time(NULL
);
651 if (SystemTime
!= -1)
653 if (difftime (lastWriteTime
, SystemTime
) > 0)
654 throw InvalidDateException ( NormalizeFilename ( xmlbuildfile
.topIncludeFilename
) );
659 xmlbuildFilenames
+= NormalizeFilename ( xmlbuildfile
.topIncludeFilename
);
660 if ( numberOfExistingFiles
% 5 == 4 || i
== ProjectNode
.xmlbuildfiles
.size () - 1 )
664 xmlbuildFilenames
.c_str ());
665 if ( i
== ProjectNode
.xmlbuildfiles
.size () - 1 )
667 fprintf ( fMakefile
, "\n" );
674 xmlbuildFilenames
.resize ( 0 );
676 numberOfExistingFiles
++;
678 fprintf ( fMakefile
, "\n" );
682 MingwBackend::GenerateTestSupportCode ()
684 printf ( "Generating test support code..." );
685 TestSupportCode
testSupportCode ( ProjectNode
);
686 testSupportCode
.GenerateTestSupportCode ( configuration
.Verbose
);
691 MingwBackend::GenerateCompilationUnitSupportCode ()
693 if ( configuration
.CompilationUnitsEnabled
)
695 printf ( "Generating compilation unit support code..." );
696 CompilationUnitSupportCode
compilationUnitSupportCode ( ProjectNode
);
697 compilationUnitSupportCode
.Generate ( configuration
.Verbose
);
703 MingwBackend::GenerateSysSetup ()
705 printf ( "Generating syssetup.inf..." );
706 SysSetupGenerator
sysSetupGenerator ( ProjectNode
);
707 sysSetupGenerator
.Generate ();
712 MingwBackend::GetProxyMakefileTree () const
714 if ( configuration
.GenerateProxyMakefilesInSourceTree
)
717 return Environment::GetOutputPath ();
721 MingwBackend::GenerateProxyMakefiles ()
723 printf ( "Generating proxy makefiles..." );
724 ProxyMakefile
proxyMakefile ( ProjectNode
);
725 proxyMakefile
.GenerateProxyMakefiles ( configuration
.Verbose
,
726 GetProxyMakefileTree () );
731 MingwBackend::CheckAutomaticDependencies ()
733 if ( configuration
.Dependencies
== AutomaticDependencies
)
735 printf ( "Checking automatic dependencies..." );
736 AutomaticDependency
automaticDependency ( ProjectNode
);
737 automaticDependency
.CheckAutomaticDependencies ( configuration
.Verbose
);
743 MingwBackend::GenerateDirectories ()
745 printf ( "Creating directories..." );
746 intermediateDirectory
->GenerateTree ( IntermediateDirectory
, configuration
.Verbose
);
747 outputDirectory
->GenerateTree ( OutputDirectory
, configuration
.Verbose
);
748 if ( !configuration
.MakeHandlesInstallDirectories
)
749 installDirectory
->GenerateTree ( InstallDirectory
, configuration
.Verbose
);
754 MingwBackend::TryToDetectThisCompiler ( const string
& compiler
)
756 string command
= ssprintf (
758 FixSeparatorForSystemCommand(compiler
).c_str (),
761 int exitcode
= system ( command
.c_str () );
762 return (bool) (exitcode
== 0);
766 MingwBackend::DetectCompiler ()
768 printf ( "Detecting compiler..." );
770 bool detectedCompiler
= false;
771 const string
& ROS_PREFIXValue
= Environment::GetVariable ( "ROS_PREFIX" );
772 if ( ROS_PREFIXValue
.length () > 0 )
774 compilerPrefix
= ROS_PREFIXValue
;
775 compilerCommand
= compilerPrefix
+ "-gcc";
776 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
779 if ( !detectedCompiler
)
782 compilerCommand
= "gcc";
783 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
786 if ( !detectedCompiler
)
788 compilerPrefix
= "mingw32";
789 compilerCommand
= compilerPrefix
+ "-gcc";
790 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
793 if ( detectedCompiler
)
795 string compilerVersion
= GetCompilerVersion ( compilerCommand
);
796 if ( IsSupportedCompilerVersion ( compilerVersion
) )
797 printf ( "detected (%s %s)\n", compilerCommand
.c_str (), compilerVersion
.c_str() );
800 printf ( "detected (%s), but with unsupported version (%s)\n",
801 compilerCommand
.c_str (),
802 compilerVersion
.c_str () );
803 throw UnsupportedBuildToolException ( compilerCommand
, compilerVersion
);
807 printf ( "not detected\n" );
812 MingwBackend::TryToDetectThisNetwideAssembler ( const string
& assembler
)
814 string command
= ssprintf (
816 FixSeparatorForSystemCommand(assembler
).c_str (),
819 int exitcode
= system ( command
.c_str () );
820 return (bool) (exitcode
== 0);
824 MingwBackend::GetVersionString ( const string
& versionCommand
)
831 fp
= popen ( versionCommand
.c_str () , "r" );
834 ( feof ( fp
) == 0 &&
835 ( ( ch
= fgetc( fp
) ) != -1 ) );
838 buffer
[i
] = (char) ch
;
843 char separators
[] = " ()";
845 char *prevtoken
= NULL
;
849 token
= strtok ( buffer
, separators
);
850 while ( token
!= NULL
)
853 version
= string( prevtoken
);
854 if ( (newline
= version
.find('\n')) != std::string::npos
)
855 version
.erase(newline
, 1);
856 if ( version
.find('.') != std::string::npos
)
858 token
= strtok ( NULL
, separators
);
864 MingwBackend::GetNetwideAssemblerVersion ( const string
& nasmCommand
)
866 string versionCommand
;
867 if ( nasmCommand
.find("yasm") != std::string::npos
)
869 versionCommand
= ssprintf ( "%s --version",
870 nasmCommand
.c_str (),
876 versionCommand
= ssprintf ( "%s -v",
877 nasmCommand
.c_str (),
881 return GetVersionString( versionCommand
);
885 MingwBackend::GetCompilerVersion ( const string
& compilerCommand
)
887 string versionCommand
= ssprintf ( "%s --version gcc",
888 compilerCommand
.c_str (),
891 return GetVersionString( versionCommand
);
895 MingwBackend::GetBinutilsVersion ( const string
& binutilsCommand
)
897 string versionCommand
= ssprintf ( "%s -v",
898 binutilsCommand
.c_str (),
901 return GetVersionString( versionCommand
);
905 MingwBackend::IsSupportedCompilerVersion ( const string
& compilerVersion
)
907 if ( strcmp ( compilerVersion
.c_str (), "3.4.2") < 0 )
914 MingwBackend::TryToDetectThisBinutils ( const string
& binutils
)
916 string command
= ssprintf (
918 FixSeparatorForSystemCommand(binutils
).c_str (),
921 int exitcode
= system ( command
.c_str () );
922 return (exitcode
== 0);
926 MingwBackend::GetBinutilsVersionDate ( const string
& binutilsCommand
)
932 string versionCommand
= ssprintf ( "%s -v",
933 binutilsCommand
.c_str (),
936 fp
= popen ( versionCommand
.c_str () , "r" );
939 ( feof ( fp
) == 0 &&
940 ( ( ch
= fgetc( fp
) ) != -1 ) );
943 buffer
[i
] = (char) ch
;
948 char separators
[] = " ";
950 char *prevtoken
= NULL
;
952 token
= strtok ( buffer
, separators
);
953 while ( token
!= NULL
)
956 token
= strtok ( NULL
, separators
);
958 string version
= string ( prevtoken
);
959 int lastDigit
= version
.find_last_not_of ( "\t\r\n" );
960 if ( lastDigit
!= -1 )
961 return string ( version
, 0, lastDigit
+1 );
967 MingwBackend::IsSupportedBinutilsVersion ( const string
& binutilsVersion
)
969 if ( manualBinutilsSetting
) return true;
972 if ( binutilsVersion
.find('.') != std::string::npos
)
974 /* TODO: blacklist versions on version number instead of date */
979 * - Binutils older than 2003/10/01 have broken windres which can't handle
980 * icons with alpha channel.
981 * - Binutils between 2004/09/02 and 2004/10/08 have broken handling of
982 * forward exports in dlltool.
984 if ( ( ( strcmp ( binutilsVersion
.c_str (), "20040902") >= 0 ) &&
985 ( strcmp ( binutilsVersion
.c_str (), "20041008") <= 0 ) ) ||
986 ( strcmp ( binutilsVersion
.c_str (), "20031001") < 0 ) )
993 MingwBackend::DetectBinutils ()
995 printf ( "Detecting binutils..." );
997 bool detectedBinutils
= false;
998 const string
& ROS_PREFIXValue
= Environment::GetVariable ( "ROS_PREFIX" );
1000 if ( ROS_PREFIXValue
.length () > 0 )
1002 binutilsPrefix
= ROS_PREFIXValue
;
1003 binutilsCommand
= binutilsPrefix
+ "-ld";
1004 manualBinutilsSetting
= true;
1005 detectedBinutils
= true;
1008 if ( !detectedBinutils
)
1010 binutilsPrefix
= "";
1011 binutilsCommand
= "ld";
1012 detectedBinutils
= TryToDetectThisBinutils ( binutilsCommand
);
1015 if ( !detectedBinutils
)
1017 binutilsPrefix
= "mingw32";
1018 binutilsCommand
= binutilsPrefix
+ "-ld";
1019 detectedBinutils
= TryToDetectThisBinutils ( binutilsCommand
);
1021 if ( detectedBinutils
)
1023 string binutilsVersion
= GetBinutilsVersionDate ( binutilsCommand
);
1024 if ( IsSupportedBinutilsVersion ( binutilsVersion
) )
1025 printf ( "detected (%s %s)\n", binutilsCommand
.c_str (), GetBinutilsVersion( binutilsCommand
).c_str() );
1028 printf ( "detected (%s), but with unsupported version (%s)\n",
1029 binutilsCommand
.c_str (),
1030 binutilsVersion
.c_str () );
1031 throw UnsupportedBuildToolException ( binutilsCommand
, binutilsVersion
);
1035 printf ( "not detected\n" );
1040 MingwBackend::DetectNetwideAssembler ()
1042 printf ( "Detecting netwide assembler..." );
1044 nasmCommand
= "nasm";
1045 bool detectedNasm
= TryToDetectThisNetwideAssembler ( nasmCommand
);
1047 if ( !detectedNasm
)
1049 nasmCommand
= "nasmw";
1050 detectedNasm
= TryToDetectThisNetwideAssembler ( nasmCommand
);
1053 if ( !detectedNasm
)
1055 nasmCommand
= "yasm";
1056 detectedNasm
= TryToDetectThisNetwideAssembler ( nasmCommand
);
1059 printf ( "detected (%s %s)\n", nasmCommand
.c_str (), GetNetwideAssemblerVersion( nasmCommand
).c_str() );
1061 printf ( "not detected\n" );
1065 MingwBackend::DetectPipeSupport ()
1067 printf ( "Detecting compiler -pipe support..." );
1069 string pipe_detection
= "tools" + sSep
+ "rbuild" + sSep
+ "backend" + sSep
+ "mingw" + sSep
+ "pipe_detection.c";
1070 string pipe_detectionObjectFilename
= ReplaceExtension ( pipe_detection
,
1072 string command
= ssprintf (
1073 "%s -pipe -c %s -o %s 1>%s 2>%s",
1074 FixSeparatorForSystemCommand(compilerCommand
).c_str (),
1075 pipe_detection
.c_str (),
1076 pipe_detectionObjectFilename
.c_str (),
1079 int exitcode
= system ( command
.c_str () );
1080 FILE* f
= fopen ( pipe_detectionObjectFilename
.c_str (), "rb" );
1083 usePipe
= (exitcode
== 0);
1085 unlink ( pipe_detectionObjectFilename
.c_str () );
1091 printf ( "detected\n" );
1093 printf ( "not detected\n" );
1097 MingwBackend::DetectPCHSupport ()
1099 printf ( "Detecting compiler pre-compiled header support..." );
1101 if ( configuration
.PrecompiledHeadersEnabled
)
1103 string path
= "tools" + sSep
+ "rbuild" + sSep
+ "backend" + sSep
+ "mingw" + sSep
+ "pch_detection.h";
1104 string cmd
= ssprintf (
1105 "%s -c %s 1>%s 2>%s",
1106 FixSeparatorForSystemCommand(compilerCommand
).c_str (),
1110 system ( cmd
.c_str () );
1113 FILE* f
= fopen ( path
.c_str (), "rb" );
1118 unlink ( path
.c_str () );
1124 printf ( "detected\n" );
1126 printf ( "not detected\n" );
1131 printf ( "disabled\n" );
1136 MingwBackend::GetNonModuleInstallTargetFiles (
1137 vector
<FileLocation
>& out
) const
1139 for ( size_t i
= 0; i
< ProjectNode
.installfiles
.size (); i
++ )
1141 const InstallFile
& installfile
= *ProjectNode
.installfiles
[i
];
1142 out
.push_back ( *installfile
.target
);
1147 MingwBackend::GetModuleInstallTargetFiles (
1148 vector
<FileLocation
>& out
) const
1150 for ( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
1152 const Module
& module
= *p
->second
;
1153 if ( !module
.enabled
)
1155 if ( module
.install
)
1156 out
.push_back ( *module
.install
);
1161 MingwBackend::GetInstallTargetFiles (
1162 vector
<FileLocation
>& out
) const
1164 GetNonModuleInstallTargetFiles ( out
);
1165 GetModuleInstallTargetFiles ( out
);
1169 MingwBackend::OutputInstallTarget ( const FileLocation
& source
,
1170 const FileLocation
& target
)
1172 fprintf ( fMakefile
,
1174 GetFullName ( target
).c_str (),
1175 GetFullName ( source
).c_str (),
1176 GetFullPath ( target
).c_str () );
1177 fprintf ( fMakefile
,
1179 fprintf ( fMakefile
,
1180 "\t${cp} %s %s 1>$(NUL)\n",
1181 GetFullName ( source
).c_str (),
1182 GetFullName ( target
).c_str () );
1186 MingwBackend::OutputNonModuleInstallTargets ()
1188 for ( size_t i
= 0; i
< ProjectNode
.installfiles
.size (); i
++ )
1190 const InstallFile
& installfile
= *ProjectNode
.installfiles
[i
];
1191 OutputInstallTarget ( *installfile
.source
, *installfile
.target
);
1196 MingwBackend::GetAliasedModuleOrModule ( const Module
& module
) const
1198 if ( module
.aliasedModuleName
.size () > 0 )
1200 const Module
* aliasedModule
= ProjectNode
.LocateModule ( module
.aliasedModuleName
);
1201 assert ( aliasedModule
);
1202 return *aliasedModule
;
1209 MingwBackend::OutputModuleInstallTargets ()
1211 for ( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
1213 const Module
& module
= *p
->second
;
1214 if ( !module
.enabled
)
1216 if ( module
.install
)
1218 const Module
& aliasedModule
= GetAliasedModuleOrModule ( module
);
1219 OutputInstallTarget ( *aliasedModule
.output
, *module
.install
);
1225 MingwBackend::GetRegistrySourceFiles ()
1227 return "boot" + sSep
+ "bootdata" + sSep
+ "hivecls_" + Environment::GetArch() + ".inf "
1228 "boot" + sSep
+ "bootdata" + sSep
+ "hivedef_" + Environment::GetArch() + ".inf "
1229 "boot" + sSep
+ "bootdata" + sSep
+ "hiveinst_" + Environment::GetArch() + ".inf "
1230 "boot" + sSep
+ "bootdata" + sSep
+ "hivesft_" + Environment::GetArch() + ".inf "
1231 "boot" + sSep
+ "bootdata" + sSep
+ "hivesys_" + Environment::GetArch() + ".inf ";
1235 MingwBackend::GetRegistryTargetFiles ()
1237 string system32ConfigDirectory
= "system32" + sSep
+ "config";
1238 FileLocation
system32 ( InstallDirectory
, system32ConfigDirectory
, "" );
1240 vector
<FileLocation
> registry_files
;
1241 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "default" ) );
1242 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "sam" ) );
1243 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "security" ) );
1244 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "software" ) );
1245 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "system" ) );
1247 return v2s( this, registry_files
, 6 );
1251 MingwBackend::OutputRegistryInstallTarget ()
1253 FileLocation
system32 ( InstallDirectory
, "system32" + sSep
+ "config", "" );
1255 string registrySourceFiles
= GetRegistrySourceFiles ();
1256 string registryTargetFiles
= GetRegistryTargetFiles ();
1257 fprintf ( fMakefile
,
1258 "install_registry: %s\n",
1259 registryTargetFiles
.c_str () );
1260 fprintf ( fMakefile
,
1261 "%s: %s %s $(MKHIVE_TARGET)\n",
1262 registryTargetFiles
.c_str (),
1263 registrySourceFiles
.c_str (),
1264 GetFullPath ( system32
).c_str () );
1265 fprintf ( fMakefile
,
1266 "\t$(ECHO_MKHIVE)\n" );
1267 fprintf ( fMakefile
,
1268 "\t$(MKHIVE_TARGET) boot%cbootdata %s $(ARCH) boot%cbootdata%chiveinst_$(ARCH).inf\n",
1269 cSep
, GetFullPath ( system32
).c_str (),
1271 fprintf ( fMakefile
,
1276 MingwBackend::GenerateInstallTarget ()
1278 vector
<FileLocation
> vInstallTargetFiles
;
1279 GetInstallTargetFiles ( vInstallTargetFiles
);
1280 string installTargetFiles
= v2s ( this, vInstallTargetFiles
, 5 );
1281 string registryTargetFiles
= GetRegistryTargetFiles ();
1283 fprintf ( fMakefile
,
1285 installTargetFiles
.c_str (),
1286 registryTargetFiles
.c_str () );
1287 OutputNonModuleInstallTargets ();
1288 OutputModuleInstallTargets ();
1289 OutputRegistryInstallTarget ();
1290 fprintf ( fMakefile
,
1295 MingwBackend::GetModuleTestTargets (
1296 vector
<string
>& out
) const
1298 for ( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
1300 const Module
& module
= *p
->second
;
1301 if ( !module
.enabled
)
1303 if ( module
.type
== Test
)
1304 out
.push_back ( module
.name
);
1309 MingwBackend::GenerateTestTarget ()
1311 vector
<string
> vTestTargets
;
1312 GetModuleTestTargets ( vTestTargets
);
1313 string testTargets
= v2s ( vTestTargets
, 5 );
1315 fprintf ( fMakefile
,
1317 testTargets
.c_str () );
1318 fprintf ( fMakefile
,
1323 MingwBackend::GenerateDirectoryTargets ()
1325 intermediateDirectory
->CreateRule ( fMakefile
, "$(INTERMEDIATE)" );
1326 outputDirectory
->CreateRule ( fMakefile
, "$(OUTPUT)" );
1327 installDirectory
->CreateRule ( fMakefile
, "$(INSTALL)" );