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
, "", "", "" }, // IdlInterface
62 { HostFalse
, "", "", "" }, // IsoRegTest
63 { HostFalse
, "", "", "" }, // LiveIsoRegTest
64 { HostFalse
, "", "", "" }, // EmbeddedTypeLib
65 { HostFalse
, "", "", "" }, // ElfExecutable
66 { HostFalse
, "", "", "" }, // RpcProxy
67 { HostTrue
, "", "", "" }, // HostStaticLibrary
68 { HostFalse
, "", "", "" }, // Cabinet
69 { HostFalse
, "", "", "" }, // KeyboardLayout
70 { HostFalse
, "", "", "" }, // MessageHeader
74 MingwBackend::GetFullPath ( const FileLocation
& file
) const
76 MingwModuleHandler::PassThruCacheDirectory ( &file
);
79 switch ( file
.directory
)
84 case IntermediateDirectory
:
85 directory
= "$(INTERMEDIATE)";
88 directory
= "$(OUTPUT)";
90 case InstallDirectory
:
91 directory
= "$(INSTALL)";
93 case TemporaryDirectory
:
94 directory
= "$(TEMPORARY)";
97 throw InvalidOperationException ( __FILE__
,
99 "Invalid directory %d.",
103 if ( file
.relative_path
.length () > 0 )
105 if ( directory
.length () > 0 )
107 directory
+= file
.relative_path
;
113 MingwBackend::GetFullName ( const FileLocation
& file
) const
116 switch ( file
.directory
)
118 case SourceDirectory
:
121 case IntermediateDirectory
:
122 directory
= "$(INTERMEDIATE)";
124 case OutputDirectory
:
125 directory
= "$(OUTPUT)";
127 case InstallDirectory
:
128 directory
= "$(INSTALL)";
130 case TemporaryDirectory
:
131 directory
= "$(TEMPORARY)";
134 throw InvalidOperationException ( __FILE__
,
136 "Invalid directory %d.",
140 if ( file
.relative_path
.length () > 0 )
142 if ( directory
.length () > 0 )
144 directory
+= file
.relative_path
;
147 if ( directory
.length () > 0 )
150 return directory
+ file
.name
;
154 v2s ( const Backend
* backend
, const vector
<FileLocation
>& files
, int wrap_at
)
160 for ( size_t i
= 0; i
< files
.size(); i
++ )
162 const FileLocation
& file
= files
[i
];
163 if ( wrap_at
> 0 && wrap_count
++ == wrap_at
)
167 s
+= backend
->GetFullName ( file
);
174 v2s ( const string_list
& v
, int wrap_at
)
180 for ( size_t i
= 0; i
< v
.size(); i
++ )
184 if ( wrap_at
> 0 && wrap_count
++ == wrap_at
)
194 static class MingwFactory
: public Backend::Factory
197 MingwFactory() : Factory ( "mingw", "Minimalist GNU Win32" ) {}
198 Backend
* operator() ( Project
& project
,
199 Configuration
& configuration
)
201 return new MingwBackend ( project
,
207 MingwBackend::MingwBackend ( Project
& project
,
208 Configuration
& configuration
)
209 : Backend ( project
, configuration
),
210 manualBinutilsSetting( false ),
211 intermediateDirectory ( new Directory ( "" ) ),
212 outputDirectory ( new Directory ( "" ) ),
213 installDirectory ( new Directory ( "" ) )
218 MingwBackend::~MingwBackend()
220 delete intermediateDirectory
;
221 delete outputDirectory
;
222 delete installDirectory
;
226 MingwBackend::AddDirectoryTarget ( const string
& directory
,
227 Directory
* directoryTree
)
229 if ( directory
.length () > 0)
230 directoryTree
->Add ( directory
.c_str() );
231 return directoryTree
->name
;
235 MingwBackend::CanEnablePreCompiledHeaderSupportForModule ( const Module
& module
)
237 if ( !configuration
.CompilationUnitsEnabled
)
240 const vector
<CompilationUnit
*>& compilationUnits
= module
.non_if_data
.compilationUnits
;
242 for ( i
= 0; i
< compilationUnits
.size (); i
++ )
244 CompilationUnit
& compilationUnit
= *compilationUnits
[i
];
245 if ( compilationUnit
.GetFiles ().size () != 1 )
252 MingwBackend::ProcessModules ()
254 printf ( "Processing modules..." );
256 vector
<MingwModuleHandler
*> v
;
259 for ( std::map
<std::string
, Module
*>::iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
260 fprintf ( fMakefile
, "%s_TYPE:=%u\n", p
->second
->name
.c_str(), p
->second
->type
);
262 for ( std::map
<std::string
, Module
*>::iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
264 Module
& module
= *p
->second
;
265 if ( !module
.enabled
)
267 MingwModuleHandler
* h
= MingwModuleHandler::InstanciateHandler (
270 h
->AddImplicitLibraries ( module
);
271 if ( use_pch
&& CanEnablePreCompiledHeaderSupportForModule ( module
) )
272 h
->EnablePreCompiledHeaderSupport ();
276 size_t iend
= v
.size ();
278 for ( i
= 0; i
< iend
; i
++ )
279 v
[i
]->GenerateSourceMacro();
280 for ( i
= 0; i
< iend
; i
++ )
281 v
[i
]->GenerateObjectMacro();
282 fprintf ( fMakefile
, "\n" );
283 for ( i
= 0; i
< iend
; i
++ )
284 v
[i
]->GenerateTargetMacro();
285 fprintf ( fMakefile
, "\n" );
287 GenerateAllTarget ( v
);
288 GenerateRegTestsRunTarget ();
290 for ( i
= 0; i
< iend
; i
++ )
291 v
[i
]->GenerateOtherMacros();
293 for ( i
= 0; i
< iend
; i
++ )
295 MingwModuleHandler
& h
= *v
[i
];
296 h
.GeneratePreconditionDependencies ();
298 h
.GenerateInvocations ();
299 h
.GenerateCleanTarget ();
300 h
.GenerateInstallTarget ();
301 h
.GenerateDependsTarget ();
309 MingwBackend::Process ()
311 if ( configuration
.CheckDependenciesForModuleOnly
)
312 CheckAutomaticDependenciesForModuleOnly ();
318 MingwBackend::CheckAutomaticDependenciesForModuleOnly ()
320 if ( configuration
.Dependencies
== AutomaticDependencies
)
322 Module
* module
= ProjectNode
.LocateModule ( configuration
.CheckDependenciesForModuleOnlyModule
);
323 if ( module
== NULL
)
325 printf ( "Module '%s' does not exist\n",
326 configuration
.CheckDependenciesForModuleOnlyModule
.c_str () );
330 printf ( "Checking automatic dependencies for module '%s'...",
331 module
->name
.c_str () );
332 AutomaticDependency
automaticDependency ( ProjectNode
);
333 automaticDependency
.CheckAutomaticDependenciesForModule ( *module
,
334 configuration
.Verbose
);
340 MingwBackend::ProcessNormal ()
342 assert(sizeof(ModuleHandlerInformations
)/sizeof(ModuleHandlerInformations
[0]) == TypeDontCare
);
346 DetectNetwideAssembler ();
347 DetectPipeSupport ();
351 GenerateGlobalVariables ();
352 GenerateXmlBuildFilesMacro ();
354 GenerateInstallTarget ();
355 GenerateTestTarget ();
356 GenerateDirectoryTargets ();
357 GenerateDirectories ();
358 GenerateTestSupportCode ();
359 GenerateCompilationUnitSupportCode ();
361 GenerateProxyMakefiles ();
362 CheckAutomaticDependencies ();
367 MingwBackend::CreateMakefile ()
369 fMakefile
= fopen ( ProjectNode
.makefile
.c_str (), "w" );
371 throw AccessDeniedException ( ProjectNode
.makefile
);
372 MingwModuleHandler::SetBackend ( this );
373 MingwModuleHandler::SetMakefile ( fMakefile
);
377 MingwBackend::CloseMakefile () const
380 fclose ( fMakefile
);
384 MingwBackend::GenerateHeader () const
386 fprintf ( fMakefile
, "# THIS FILE IS AUTOMATICALLY GENERATED, EDIT '%s' INSTEAD\n\n",
387 ProjectNode
.GetProjectFilename ().c_str () );
391 MingwBackend::GenerateGlobalProperties (
392 const char* assignmentOperation
,
393 const IfableData
& data
) const
395 for ( std::map
<std::string
, Property
*>::const_iterator p
= data
.properties
.begin(); p
!= data
.properties
.end(); ++ p
)
397 Property
& prop
= *p
->second
;
399 if (!prop
.isInternal
)
401 fprintf ( fMakefile
, "%s := %s\n",
403 prop
.value
.c_str() );
409 MingwBackend::GenerateProjectLFLAGS () const
412 for ( size_t i
= 0; i
< ProjectNode
.linkerFlags
.size (); i
++ )
414 LinkerFlag
& linkerFlag
= *ProjectNode
.linkerFlags
[i
];
415 if ( lflags
.length () > 0 )
417 lflags
+= linkerFlag
.flag
;
423 MingwBackend::GenerateGlobalVariables () const
425 fputs ( "include tools$(SEP)rbuild$(SEP)backend$(SEP)mingw$(SEP)rules.mak\n", fMakefile
);
427 if ( configuration
.Dependencies
== FullDependencies
)
430 "ifeq ($(ROS_BUILDDEPS),)\n"
431 "ROS_BUILDDEPS:=%s\n"
438 compilerPrefix
.c_str () );
441 nasmCommand
.c_str () );
443 GenerateGlobalProperties ( "=", ProjectNode
.non_if_data
);
445 fprintf ( fMakefile
, "PROJECT_CFLAGS += -Wall\n" );
446 fprintf ( fMakefile
, "PROJECT_CXXFLAGS += -Wall\n" );
447 fprintf ( fMakefile
, "ifneq ($(OARCH),)\n" );
448 fprintf ( fMakefile
, "PROJECT_CFLAGS += -march=$(OARCH)\n" );
449 fprintf ( fMakefile
, "PROJECT_CXXFLAGS += -march=$(OARCH)\n" );
450 fprintf ( fMakefile
, "endif\n" );
451 fprintf ( fMakefile
, "ifneq ($(TUNE),)\n" );
452 fprintf ( fMakefile
, "PROJECT_CFLAGS += -mtune=$(TUNE)\n" );
453 fprintf ( fMakefile
, "PROJECT_CXXFLAGS += -mtune=$(TUNE)\n" );
454 fprintf ( fMakefile
, "endif\n" );
456 fprintf ( fMakefile
, "PROJECT_CFLAGS += -g%s\n", Environment::GetArch() == "amd64" ? "dwarf-2" : "stabs+" );
457 fprintf ( fMakefile
, "PROJECT_CXXFLAGS += -g%s\n", Environment::GetArch() == "amd64" ? "dwarf-2" : "stabs+" );
458 fprintf ( fMakefile
, "PROJECT_ASFLAGS += -g%s\n", Environment::GetArch() == "amd64" ? "dwarf-2" : "stabs+" );
460 MingwModuleHandler::GenerateParameters ( "PROJECT", "+=", ProjectNode
.non_if_data
);
461 MingwModuleHandler::GenerateParameters ( "PROJECT_HOST", "+=", ProjectNode
.host_non_if_data
);
465 fprintf ( fMakefile
, "PROJECT_CFLAGS += -pipe\n" );
466 fprintf ( fMakefile
, "PROJECT_CXXFLAGS += -pipe\n" );
467 fprintf ( fMakefile
, "PROJECT_ASFLAGS += -pipe\n" );
470 // Because RosBE gcc is built to suck
471 fputs ( "BUILTIN_HOST_CINCLUDES+= $(HOST_CFLAGS)\n", fMakefile
);
472 fputs ( "BUILTIN_HOST_CPPINCLUDES+= $(HOST_CFLAGS)\n", fMakefile
);
473 fputs ( "BUILTIN_HOST_CXXINCLUDES+= $(HOST_CPPFLAGS)\n", fMakefile
);
475 // Would be nice to have our own C++ runtime
476 fputs ( "BUILTIN_CXXINCLUDES+= $(TARGET_CPPFLAGS)\n", fMakefile
);
478 // TODO: linker flags
479 fprintf ( fMakefile
, "PROJECT_LFLAGS := '$(shell ${TARGET_CC} -print-libgcc-file-name)' %s\n", GenerateProjectLFLAGS ().c_str () );
480 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" );
481 /* hack to get libgcc_eh.a, should check mingw version or something */
482 if (Environment::GetArch() == "amd64")
484 fprintf ( fMakefile
, "PROJECT_LPPFLAGS += '$(shell ${TARGET_CPP} -print-file-name=libgcc_eh.a)'\n" );
487 // TODO: use symbolic names for module types
488 for ( size_t i
= 0; i
< sizeof(ModuleHandlerInformations
) / sizeof(ModuleHandlerInformations
[0]); ++ i
)
490 if ( ModuleHandlerInformations
[i
].cflags
&& ModuleHandlerInformations
[i
].cflags
[0] )
493 "MODULETYPE%d_%sFLAGS:=%s\n",
496 ModuleHandlerInformations
[i
].cflags
);
499 if ( ModuleHandlerInformations
[i
].cflags
&& ModuleHandlerInformations
[i
].cflags
[0] )
502 "MODULETYPE%d_%sFLAGS:=%s\n",
505 ModuleHandlerInformations
[i
].cflags
);
508 if ( ModuleHandlerInformations
[i
].nasmflags
&& ModuleHandlerInformations
[i
].nasmflags
[0] )
511 "MODULETYPE%d_%sFLAGS:=%s\n",
514 ModuleHandlerInformations
[i
].nasmflags
);
518 fprintf ( fMakefile
, "\n" );
522 MingwBackend::IncludeInAllTarget ( const Module
& module
) const
524 if ( MingwModuleHandler::ReferenceObjects ( module
) )
526 if ( module
.type
== BootSector
)
528 if ( module
.type
== Iso
)
530 if ( module
.type
== LiveIso
)
532 if ( module
.type
== IsoRegTest
)
534 if ( module
.type
== LiveIsoRegTest
)
536 if ( module
.type
== Test
)
538 if ( module
.type
== Alias
)
544 MingwBackend::GenerateAllTarget ( const vector
<MingwModuleHandler
*>& handlers
) const
546 fprintf ( fMakefile
, "all:" );
548 size_t iend
= handlers
.size ();
549 for ( size_t i
= 0; i
< iend
; i
++ )
551 const Module
& module
= handlers
[i
]->module
;
552 if ( IncludeInAllTarget ( module
) )
554 if ( wrap_count
++ == 5 )
555 fprintf ( fMakefile
, " \\\n\t\t" ), wrap_count
= 0;
558 GetTargetMacro(module
).c_str () );
561 fprintf ( fMakefile
, "\n\t\n\n" );
565 MingwBackend::GenerateRegTestsRunTarget () const
568 "REGTESTS_RUN_TARGET = regtests.dll\n" );
570 "$(REGTESTS_RUN_TARGET): $(REGTESTS_TARGET)\n" );
572 "\t$(cp) $(REGTESTS_TARGET) $(REGTESTS_RUN_TARGET)\n" );
573 fprintf ( fMakefile
, "\n" );
577 MingwBackend::GenerateXmlBuildFilesMacro() const
580 "XMLBUILDFILES = %s \\\n",
581 ProjectNode
.GetProjectFilename ().c_str () );
582 string xmlbuildFilenames
;
583 int numberOfExistingFiles
= 0;
585 time_t SystemTime
, lastWriteTime
;
587 for ( size_t i
= 0; i
< ProjectNode
.xmlbuildfiles
.size (); i
++ )
589 XMLInclude
& xmlbuildfile
= *ProjectNode
.xmlbuildfiles
[i
];
590 if ( !xmlbuildfile
.fileExists
)
592 numberOfExistingFiles
++;
593 if ( xmlbuildFilenames
.length () > 0 )
594 xmlbuildFilenames
+= " ";
596 FILE* f
= fopen ( xmlbuildfile
.topIncludeFilename
.c_str (), "rb" );
598 throw FileNotFoundException ( NormalizeFilename ( xmlbuildfile
.topIncludeFilename
) );
600 if ( fstat ( fileno ( f
), &statbuf
) != 0 )
603 throw AccessDeniedException ( NormalizeFilename ( xmlbuildfile
.topIncludeFilename
) );
606 lastWriteTime
= statbuf
.st_mtime
;
607 SystemTime
= time(NULL
);
609 if (SystemTime
!= -1)
611 if (difftime (lastWriteTime
, SystemTime
) > 0)
612 throw InvalidDateException ( NormalizeFilename ( xmlbuildfile
.topIncludeFilename
) );
617 xmlbuildFilenames
+= NormalizeFilename ( xmlbuildfile
.topIncludeFilename
);
618 if ( numberOfExistingFiles
% 5 == 4 || i
== ProjectNode
.xmlbuildfiles
.size () - 1 )
622 xmlbuildFilenames
.c_str ());
623 if ( i
== ProjectNode
.xmlbuildfiles
.size () - 1 )
625 fprintf ( fMakefile
, "\n" );
632 xmlbuildFilenames
.resize ( 0 );
634 numberOfExistingFiles
++;
636 fprintf ( fMakefile
, "\n" );
640 MingwBackend::GenerateTestSupportCode ()
642 printf ( "Generating test support code..." );
643 TestSupportCode
testSupportCode ( ProjectNode
);
644 testSupportCode
.GenerateTestSupportCode ( configuration
.Verbose
);
649 MingwBackend::GenerateCompilationUnitSupportCode ()
651 if ( configuration
.CompilationUnitsEnabled
)
653 printf ( "Generating compilation unit support code..." );
654 CompilationUnitSupportCode
compilationUnitSupportCode ( ProjectNode
);
655 compilationUnitSupportCode
.Generate ( configuration
.Verbose
);
661 MingwBackend::GenerateSysSetup ()
663 printf ( "Generating syssetup.inf..." );
664 SysSetupGenerator
sysSetupGenerator ( ProjectNode
);
665 sysSetupGenerator
.Generate ();
670 MingwBackend::GetProxyMakefileTree () const
672 if ( configuration
.GenerateProxyMakefilesInSourceTree
)
675 return Environment::GetOutputPath ();
679 MingwBackend::GenerateProxyMakefiles ()
681 printf ( "Generating proxy makefiles..." );
682 ProxyMakefile
proxyMakefile ( ProjectNode
);
683 proxyMakefile
.GenerateProxyMakefiles ( configuration
.Verbose
,
684 GetProxyMakefileTree () );
689 MingwBackend::CheckAutomaticDependencies ()
691 if ( configuration
.Dependencies
== AutomaticDependencies
)
693 printf ( "Checking automatic dependencies..." );
694 AutomaticDependency
automaticDependency ( ProjectNode
);
695 automaticDependency
.CheckAutomaticDependencies ( configuration
.Verbose
);
701 MingwBackend::GenerateDirectories ()
703 printf ( "Creating directories..." );
704 intermediateDirectory
->GenerateTree ( IntermediateDirectory
, configuration
.Verbose
);
705 outputDirectory
->GenerateTree ( OutputDirectory
, configuration
.Verbose
);
706 if ( !configuration
.MakeHandlesInstallDirectories
)
707 installDirectory
->GenerateTree ( InstallDirectory
, configuration
.Verbose
);
712 MingwBackend::TryToDetectThisCompiler ( const string
& compiler
)
714 string command
= ssprintf (
716 FixSeparatorForSystemCommand(compiler
).c_str (),
719 int exitcode
= system ( command
.c_str () );
720 return (bool) (exitcode
== 0);
724 MingwBackend::DetectCompiler ()
726 printf ( "Detecting compiler..." );
728 bool detectedCompiler
= false;
729 const string
& ROS_PREFIXValue
= Environment::GetVariable ( "ROS_PREFIX" );
730 if ( ROS_PREFIXValue
.length () > 0 )
732 compilerPrefix
= ROS_PREFIXValue
;
733 compilerCommand
= compilerPrefix
+ "-gcc";
734 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
737 if ( !detectedCompiler
)
740 compilerCommand
= "gcc";
741 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
744 if ( !detectedCompiler
)
746 compilerPrefix
= "mingw32";
747 compilerCommand
= compilerPrefix
+ "-gcc";
748 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
751 if ( detectedCompiler
)
753 string compilerVersion
= GetCompilerVersion ( compilerCommand
);
754 if ( IsSupportedCompilerVersion ( compilerVersion
) )
755 printf ( "detected (%s %s)\n", compilerCommand
.c_str (), compilerVersion
.c_str() );
758 printf ( "detected (%s), but with unsupported version (%s)\n",
759 compilerCommand
.c_str (),
760 compilerVersion
.c_str () );
761 throw UnsupportedBuildToolException ( compilerCommand
, compilerVersion
);
765 printf ( "not detected\n" );
770 MingwBackend::TryToDetectThisNetwideAssembler ( const string
& assembler
)
772 string command
= ssprintf (
774 FixSeparatorForSystemCommand(assembler
).c_str (),
777 int exitcode
= system ( command
.c_str () );
778 return (bool) (exitcode
== 0);
782 MingwBackend::GetVersionString ( const string
& versionCommand
)
789 fp
= popen ( versionCommand
.c_str () , "r" );
792 ( feof ( fp
) == 0 &&
793 ( ( ch
= fgetc( fp
) ) != -1 ) );
796 buffer
[i
] = (char) ch
;
801 char separators
[] = " ()";
803 char *prevtoken
= NULL
;
807 token
= strtok ( buffer
, separators
);
808 while ( token
!= NULL
)
811 version
= string( prevtoken
);
812 if ( (newline
= version
.find('\n')) != std::string::npos
)
813 version
.erase(newline
, 1);
814 if ( version
.find('.') != std::string::npos
)
816 token
= strtok ( NULL
, separators
);
822 MingwBackend::GetNetwideAssemblerVersion ( const string
& nasmCommand
)
824 string versionCommand
;
825 if ( nasmCommand
.find("yasm") != std::string::npos
)
827 versionCommand
= ssprintf ( "%s --version",
828 nasmCommand
.c_str (),
834 versionCommand
= ssprintf ( "%s -v",
835 nasmCommand
.c_str (),
839 return GetVersionString( versionCommand
);
843 MingwBackend::GetCompilerVersion ( const string
& compilerCommand
)
845 string versionCommand
= ssprintf ( "%s --version gcc",
846 compilerCommand
.c_str (),
849 return GetVersionString( versionCommand
);
853 MingwBackend::GetBinutilsVersion ( const string
& binutilsCommand
)
855 string versionCommand
= ssprintf ( "%s -v",
856 binutilsCommand
.c_str (),
859 return GetVersionString( versionCommand
);
863 MingwBackend::IsSupportedCompilerVersion ( const string
& compilerVersion
)
865 if ( strcmp ( compilerVersion
.c_str (), "3.4.2") < 0 )
872 MingwBackend::TryToDetectThisBinutils ( const string
& binutils
)
874 string command
= ssprintf (
876 FixSeparatorForSystemCommand(binutils
).c_str (),
879 int exitcode
= system ( command
.c_str () );
880 return (exitcode
== 0);
884 MingwBackend::GetBinutilsVersionDate ( const string
& binutilsCommand
)
890 string versionCommand
= ssprintf ( "%s -v",
891 binutilsCommand
.c_str (),
894 fp
= popen ( versionCommand
.c_str () , "r" );
897 ( feof ( fp
) == 0 &&
898 ( ( ch
= fgetc( fp
) ) != -1 ) );
901 buffer
[i
] = (char) ch
;
906 char separators
[] = " ";
908 char *prevtoken
= NULL
;
910 token
= strtok ( buffer
, separators
);
911 while ( token
!= NULL
)
914 token
= strtok ( NULL
, separators
);
916 string version
= string ( prevtoken
);
917 int lastDigit
= version
.find_last_not_of ( "\t\r\n" );
918 if ( lastDigit
!= -1 )
919 return string ( version
, 0, lastDigit
+1 );
925 MingwBackend::IsSupportedBinutilsVersion ( const string
& binutilsVersion
)
927 if ( manualBinutilsSetting
) return true;
930 if ( binutilsVersion
.find('.') != std::string::npos
)
932 /* TODO: blacklist versions on version number instead of date */
937 * - Binutils older than 2003/10/01 have broken windres which can't handle
938 * icons with alpha channel.
939 * - Binutils between 2004/09/02 and 2004/10/08 have broken handling of
940 * forward exports in dlltool.
942 if ( ( ( strcmp ( binutilsVersion
.c_str (), "20040902") >= 0 ) &&
943 ( strcmp ( binutilsVersion
.c_str (), "20041008") <= 0 ) ) ||
944 ( strcmp ( binutilsVersion
.c_str (), "20031001") < 0 ) )
951 MingwBackend::DetectBinutils ()
953 printf ( "Detecting binutils..." );
955 bool detectedBinutils
= false;
956 const string
& ROS_PREFIXValue
= Environment::GetVariable ( "ROS_PREFIX" );
958 if ( ROS_PREFIXValue
.length () > 0 )
960 binutilsPrefix
= ROS_PREFIXValue
;
961 binutilsCommand
= binutilsPrefix
+ "-ld";
962 manualBinutilsSetting
= true;
963 detectedBinutils
= true;
966 if ( !detectedBinutils
)
969 binutilsCommand
= "ld";
970 detectedBinutils
= TryToDetectThisBinutils ( binutilsCommand
);
973 if ( !detectedBinutils
)
975 binutilsPrefix
= "mingw32";
976 binutilsCommand
= binutilsPrefix
+ "-ld";
977 detectedBinutils
= TryToDetectThisBinutils ( binutilsCommand
);
979 if ( detectedBinutils
)
981 string binutilsVersion
= GetBinutilsVersionDate ( binutilsCommand
);
982 if ( IsSupportedBinutilsVersion ( binutilsVersion
) )
983 printf ( "detected (%s %s)\n", binutilsCommand
.c_str (), GetBinutilsVersion( binutilsCommand
).c_str() );
986 printf ( "detected (%s), but with unsupported version (%s)\n",
987 binutilsCommand
.c_str (),
988 binutilsVersion
.c_str () );
989 throw UnsupportedBuildToolException ( binutilsCommand
, binutilsVersion
);
993 printf ( "not detected\n" );
998 MingwBackend::DetectNetwideAssembler ()
1000 printf ( "Detecting netwide assembler..." );
1002 nasmCommand
= "nasm";
1003 bool detectedNasm
= TryToDetectThisNetwideAssembler ( nasmCommand
);
1005 if ( !detectedNasm
)
1007 nasmCommand
= "nasmw";
1008 detectedNasm
= TryToDetectThisNetwideAssembler ( nasmCommand
);
1011 if ( !detectedNasm
)
1013 nasmCommand
= "yasm";
1014 detectedNasm
= TryToDetectThisNetwideAssembler ( nasmCommand
);
1017 printf ( "detected (%s %s)\n", nasmCommand
.c_str (), GetNetwideAssemblerVersion( nasmCommand
).c_str() );
1019 printf ( "not detected\n" );
1023 MingwBackend::DetectPipeSupport ()
1025 printf ( "Detecting compiler -pipe support..." );
1027 string pipe_detection
= "tools" + sSep
+ "rbuild" + sSep
+ "backend" + sSep
+ "mingw" + sSep
+ "pipe_detection.c";
1028 string pipe_detectionObjectFilename
= ReplaceExtension ( pipe_detection
,
1030 string command
= ssprintf (
1031 "%s -pipe -c %s -o %s 1>%s 2>%s",
1032 FixSeparatorForSystemCommand(compilerCommand
).c_str (),
1033 pipe_detection
.c_str (),
1034 pipe_detectionObjectFilename
.c_str (),
1037 int exitcode
= system ( command
.c_str () );
1038 FILE* f
= fopen ( pipe_detectionObjectFilename
.c_str (), "rb" );
1041 usePipe
= (exitcode
== 0);
1043 unlink ( pipe_detectionObjectFilename
.c_str () );
1049 printf ( "detected\n" );
1051 printf ( "not detected\n" );
1055 MingwBackend::DetectPCHSupport ()
1057 printf ( "Detecting compiler pre-compiled header support..." );
1059 if ( configuration
.PrecompiledHeadersEnabled
)
1061 string path
= "tools" + sSep
+ "rbuild" + sSep
+ "backend" + sSep
+ "mingw" + sSep
+ "pch_detection.h";
1062 string cmd
= ssprintf (
1063 "%s -c %s 1>%s 2>%s",
1064 FixSeparatorForSystemCommand(compilerCommand
).c_str (),
1068 system ( cmd
.c_str () );
1071 FILE* f
= fopen ( path
.c_str (), "rb" );
1076 unlink ( path
.c_str () );
1082 printf ( "detected\n" );
1084 printf ( "not detected\n" );
1089 printf ( "disabled\n" );
1094 MingwBackend::GetNonModuleInstallTargetFiles (
1095 vector
<FileLocation
>& out
) const
1097 for ( size_t i
= 0; i
< ProjectNode
.installfiles
.size (); i
++ )
1099 const InstallFile
& installfile
= *ProjectNode
.installfiles
[i
];
1100 out
.push_back ( *installfile
.target
);
1105 MingwBackend::GetModuleInstallTargetFiles (
1106 vector
<FileLocation
>& out
) const
1108 for ( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
1110 const Module
& module
= *p
->second
;
1111 if ( !module
.enabled
)
1113 if ( module
.install
)
1114 out
.push_back ( *module
.install
);
1119 MingwBackend::GetInstallTargetFiles (
1120 vector
<FileLocation
>& out
) const
1122 GetNonModuleInstallTargetFiles ( out
);
1123 GetModuleInstallTargetFiles ( out
);
1127 MingwBackend::OutputInstallTarget ( const FileLocation
& source
,
1128 const FileLocation
& target
)
1130 fprintf ( fMakefile
,
1132 GetFullName ( target
).c_str (),
1133 GetFullName ( source
).c_str (),
1134 GetFullPath ( target
).c_str () );
1135 fprintf ( fMakefile
,
1137 fprintf ( fMakefile
,
1138 "\t${cp} %s %s 1>$(NUL)\n",
1139 GetFullName ( source
).c_str (),
1140 GetFullName ( target
).c_str () );
1144 MingwBackend::OutputNonModuleInstallTargets ()
1146 for ( size_t i
= 0; i
< ProjectNode
.installfiles
.size (); i
++ )
1148 const InstallFile
& installfile
= *ProjectNode
.installfiles
[i
];
1149 OutputInstallTarget ( *installfile
.source
, *installfile
.target
);
1154 MingwBackend::GetAliasedModuleOrModule ( const Module
& module
) const
1156 if ( module
.aliasedModuleName
.size () > 0 )
1158 const Module
* aliasedModule
= ProjectNode
.LocateModule ( module
.aliasedModuleName
);
1159 assert ( aliasedModule
);
1160 return *aliasedModule
;
1167 MingwBackend::OutputModuleInstallTargets ()
1169 for ( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
1171 const Module
& module
= *p
->second
;
1172 if ( !module
.enabled
)
1174 if ( module
.install
)
1176 const Module
& aliasedModule
= GetAliasedModuleOrModule ( module
);
1177 OutputInstallTarget ( *aliasedModule
.output
, *module
.install
);
1183 MingwBackend::GetRegistrySourceFiles ()
1185 return "boot" + sSep
+ "bootdata" + sSep
+ "hivecls_" + Environment::GetArch() + ".inf "
1186 "boot" + sSep
+ "bootdata" + sSep
+ "hivedef_" + Environment::GetArch() + ".inf "
1187 "boot" + sSep
+ "bootdata" + sSep
+ "hiveinst_" + Environment::GetArch() + ".inf "
1188 "boot" + sSep
+ "bootdata" + sSep
+ "hivesft_" + Environment::GetArch() + ".inf "
1189 "boot" + sSep
+ "bootdata" + sSep
+ "hivesys_" + Environment::GetArch() + ".inf ";
1193 MingwBackend::GetRegistryTargetFiles ()
1195 string system32ConfigDirectory
= "system32" + sSep
+ "config";
1196 FileLocation
system32 ( InstallDirectory
, system32ConfigDirectory
, "" );
1198 vector
<FileLocation
> registry_files
;
1199 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "default" ) );
1200 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "sam" ) );
1201 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "security" ) );
1202 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "software" ) );
1203 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "system" ) );
1205 return v2s( this, registry_files
, 6 );
1209 MingwBackend::OutputRegistryInstallTarget ()
1211 FileLocation
system32 ( InstallDirectory
, "system32" + sSep
+ "config", "" );
1213 string registrySourceFiles
= GetRegistrySourceFiles ();
1214 string registryTargetFiles
= GetRegistryTargetFiles ();
1215 fprintf ( fMakefile
,
1216 "install_registry: %s\n",
1217 registryTargetFiles
.c_str () );
1218 fprintf ( fMakefile
,
1219 "%s: %s %s $(MKHIVE_TARGET)\n",
1220 registryTargetFiles
.c_str (),
1221 registrySourceFiles
.c_str (),
1222 GetFullPath ( system32
).c_str () );
1223 fprintf ( fMakefile
,
1224 "\t$(ECHO_MKHIVE)\n" );
1225 fprintf ( fMakefile
,
1226 "\t$(MKHIVE_TARGET) boot%cbootdata %s $(ARCH) boot%cbootdata%chiveinst_$(ARCH).inf\n",
1227 cSep
, GetFullPath ( system32
).c_str (),
1229 fprintf ( fMakefile
,
1234 MingwBackend::GenerateInstallTarget ()
1236 vector
<FileLocation
> vInstallTargetFiles
;
1237 GetInstallTargetFiles ( vInstallTargetFiles
);
1238 string installTargetFiles
= v2s ( this, vInstallTargetFiles
, 5 );
1239 string registryTargetFiles
= GetRegistryTargetFiles ();
1241 fprintf ( fMakefile
,
1243 installTargetFiles
.c_str (),
1244 registryTargetFiles
.c_str () );
1245 OutputNonModuleInstallTargets ();
1246 OutputModuleInstallTargets ();
1247 OutputRegistryInstallTarget ();
1248 fprintf ( fMakefile
,
1253 MingwBackend::GetModuleTestTargets (
1254 vector
<string
>& out
) const
1256 for ( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
1258 const Module
& module
= *p
->second
;
1259 if ( !module
.enabled
)
1261 if ( module
.type
== Test
)
1262 out
.push_back ( module
.name
);
1267 MingwBackend::GenerateTestTarget ()
1269 vector
<string
> vTestTargets
;
1270 GetModuleTestTargets ( vTestTargets
);
1271 string testTargets
= v2s ( vTestTargets
, 5 );
1273 fprintf ( fMakefile
,
1275 testTargets
.c_str () );
1276 fprintf ( fMakefile
,
1281 MingwBackend::GenerateDirectoryTargets ()
1283 intermediateDirectory
->CreateRule ( fMakefile
, "$(INTERMEDIATE)" );
1284 outputDirectory
->CreateRule ( fMakefile
, "$(OUTPUT)" );
1285 installDirectory
->CreateRule ( fMakefile
, "$(INSTALL)" );