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
73 static std::string mscPath
;
74 static std::string mslinkPath
;
77 MingwBackend::GetFullPath ( const FileLocation
& file
) const
79 MingwModuleHandler::PassThruCacheDirectory ( &file
);
82 switch ( file
.directory
)
87 case IntermediateDirectory
:
88 directory
= "$(INTERMEDIATE)";
91 directory
= "$(OUTPUT)";
93 case InstallDirectory
:
94 directory
= "$(INSTALL)";
96 case TemporaryDirectory
:
97 directory
= "$(TEMPORARY)";
100 throw InvalidOperationException ( __FILE__
,
102 "Invalid directory %d.",
106 if ( file
.relative_path
.length () > 0 )
108 if ( directory
.length () > 0 )
110 directory
+= file
.relative_path
;
116 MingwBackend::GetFullName ( const FileLocation
& file
) const
119 switch ( file
.directory
)
121 case SourceDirectory
:
124 case IntermediateDirectory
:
125 directory
= "$(INTERMEDIATE)";
127 case OutputDirectory
:
128 directory
= "$(OUTPUT)";
130 case InstallDirectory
:
131 directory
= "$(INSTALL)";
133 case TemporaryDirectory
:
134 directory
= "$(TEMPORARY)";
137 throw InvalidOperationException ( __FILE__
,
139 "Invalid directory %d.",
143 if ( file
.relative_path
.length () > 0 )
145 if ( directory
.length () > 0 )
147 directory
+= file
.relative_path
;
150 if ( directory
.length () > 0 )
153 return directory
+ file
.name
;
157 v2s ( const Backend
* backend
, const vector
<FileLocation
>& files
, int wrap_at
)
163 for ( size_t i
= 0; i
< files
.size(); i
++ )
165 const FileLocation
& file
= files
[i
];
166 if ( wrap_at
> 0 && wrap_count
++ == wrap_at
)
170 s
+= backend
->GetFullName ( file
);
177 v2s ( const string_list
& v
, int wrap_at
)
183 for ( size_t i
= 0; i
< v
.size(); i
++ )
187 if ( wrap_at
> 0 && wrap_count
++ == wrap_at
)
197 static class MingwFactory
: public Backend::Factory
200 MingwFactory() : Factory ( "mingw", "Minimalist GNU Win32" ) {}
201 Backend
* operator() ( Project
& project
,
202 Configuration
& configuration
)
204 return new MingwBackend ( project
,
210 MingwBackend::MingwBackend ( Project
& project
,
211 Configuration
& configuration
)
212 : Backend ( project
, configuration
),
213 manualBinutilsSetting( false ),
214 intermediateDirectory ( new Directory ( "" ) ),
215 outputDirectory ( new Directory ( "" ) ),
216 installDirectory ( new Directory ( "" ) )
221 MingwBackend::~MingwBackend()
223 delete intermediateDirectory
;
224 delete outputDirectory
;
225 delete installDirectory
;
229 MingwBackend::AddDirectoryTarget ( const string
& directory
,
230 Directory
* directoryTree
)
232 if ( directory
.length () > 0)
233 directoryTree
->Add ( directory
.c_str() );
234 return directoryTree
->name
;
238 MingwBackend::CanEnablePreCompiledHeaderSupportForModule ( const Module
& module
)
240 if ( !configuration
.CompilationUnitsEnabled
)
243 const vector
<CompilationUnit
*>& compilationUnits
= module
.non_if_data
.compilationUnits
;
245 for ( i
= 0; i
< compilationUnits
.size (); i
++ )
247 CompilationUnit
& compilationUnit
= *compilationUnits
[i
];
248 if ( compilationUnit
.GetFiles ().size () != 1 )
255 MingwBackend::ProcessModules ()
257 printf ( "Processing modules..." );
259 vector
<MingwModuleHandler
*> v
;
262 for ( std::map
<std::string
, Module
*>::iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
263 fprintf ( fMakefile
, "%s_TYPE:=%u\n", p
->second
->name
.c_str(), p
->second
->type
);
265 for ( std::map
<std::string
, Module
*>::iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
267 Module
& module
= *p
->second
;
268 if ( !module
.enabled
)
270 MingwModuleHandler
* h
= MingwModuleHandler::InstanciateHandler (
273 h
->AddImplicitLibraries ( module
);
274 if ( use_pch
&& CanEnablePreCompiledHeaderSupportForModule ( module
) )
275 h
->EnablePreCompiledHeaderSupport ();
279 size_t iend
= v
.size ();
281 for ( i
= 0; i
< iend
; i
++ )
282 v
[i
]->GenerateSourceMacro();
283 for ( i
= 0; i
< iend
; i
++ )
284 v
[i
]->GenerateObjectMacro();
285 fprintf ( fMakefile
, "\n" );
286 for ( i
= 0; i
< iend
; i
++ )
287 v
[i
]->GenerateTargetMacro();
288 fprintf ( fMakefile
, "\n" );
290 GenerateAllTarget ( v
);
291 GenerateRegTestsRunTarget ();
293 for ( i
= 0; i
< iend
; i
++ )
294 v
[i
]->GenerateOtherMacros();
296 for ( i
= 0; i
< iend
; i
++ )
298 MingwModuleHandler
& h
= *v
[i
];
299 h
.GeneratePreconditionDependencies ();
301 h
.GenerateInvocations ();
302 h
.GenerateCleanTarget ();
303 h
.GenerateInstallTarget ();
304 h
.GenerateDependsTarget ();
312 MingwBackend::Process ()
314 if ( configuration
.CheckDependenciesForModuleOnly
)
315 CheckAutomaticDependenciesForModuleOnly ();
321 MingwBackend::CheckAutomaticDependenciesForModuleOnly ()
323 if ( configuration
.Dependencies
== AutomaticDependencies
)
325 Module
* module
= ProjectNode
.LocateModule ( configuration
.CheckDependenciesForModuleOnlyModule
);
326 if ( module
== NULL
)
328 printf ( "Module '%s' does not exist\n",
329 configuration
.CheckDependenciesForModuleOnlyModule
.c_str () );
333 printf ( "Checking automatic dependencies for module '%s'...",
334 module
->name
.c_str () );
335 AutomaticDependency
automaticDependency ( ProjectNode
);
336 automaticDependency
.CheckAutomaticDependenciesForModule ( *module
,
337 configuration
.Verbose
);
343 MingwBackend::ProcessNormal ()
345 assert(sizeof(ModuleHandlerInformations
)/sizeof(ModuleHandlerInformations
[0]) == TypeDontCare
);
349 DetectNetwideAssembler ();
350 DetectPipeSupport ();
354 GenerateGlobalVariables ();
355 GenerateXmlBuildFilesMacro ();
357 GenerateInstallTarget ();
358 GenerateTestTarget ();
359 GenerateDirectoryTargets ();
360 GenerateDirectories ();
361 GenerateTestSupportCode ();
362 GenerateCompilationUnitSupportCode ();
364 GenerateProxyMakefiles ();
365 CheckAutomaticDependencies ();
370 MingwBackend::CreateMakefile ()
372 fMakefile
= fopen ( ProjectNode
.makefile
.c_str (), "w" );
374 throw AccessDeniedException ( ProjectNode
.makefile
);
375 MingwModuleHandler::SetBackend ( this );
376 MingwModuleHandler::SetMakefile ( fMakefile
);
380 MingwBackend::CloseMakefile () const
383 fclose ( fMakefile
);
387 MingwBackend::GenerateHeader () const
389 fprintf ( fMakefile
, "# THIS FILE IS AUTOMATICALLY GENERATED, EDIT '%s' INSTEAD\n\n",
390 ProjectNode
.GetProjectFilename ().c_str () );
394 MingwBackend::GenerateGlobalProperties (
395 const char* assignmentOperation
,
396 const IfableData
& data
) const
398 for ( std::map
<std::string
, Property
*>::const_iterator p
= data
.properties
.begin(); p
!= data
.properties
.end(); ++ p
)
400 Property
& prop
= *p
->second
;
402 if (!prop
.isInternal
)
404 fprintf ( fMakefile
, "%s := %s\n",
406 prop
.value
.c_str() );
412 MingwBackend::GenerateProjectLFLAGS () const
415 for ( size_t i
= 0; i
< ProjectNode
.linkerFlags
.size (); i
++ )
417 LinkerFlag
& linkerFlag
= *ProjectNode
.linkerFlags
[i
];
418 if ( lflags
.length () > 0 )
420 lflags
+= linkerFlag
.flag
;
426 MingwBackend::GenerateGlobalVariables () const
428 fputs ( "include tools$(SEP)rbuild$(SEP)backend$(SEP)mingw$(SEP)rules.mak\n", fMakefile
);
429 fprintf ( fMakefile
, "include tools$(SEP)rbuild$(SEP)backend$(SEP)mingw$(SEP)linkers$(SEP)%s.mak\n", ProjectNode
.GetLinkerSet ().c_str () );
430 fprintf ( fMakefile
, "include tools$(SEP)rbuild$(SEP)backend$(SEP)mingw$(SEP)compilers$(SEP)%s.mak\n", ProjectNode
.GetCompilerSet ().c_str () );
432 if ( mscPath
.length() )
433 fprintf ( fMakefile
, "export RBUILD_CL_PATH=%s\n", mscPath
.c_str () );
435 if ( mslinkPath
.length() )
436 fprintf ( fMakefile
, "export RBUILD_LINK_PATH=%s\n", mslinkPath
.c_str () );
438 if ( configuration
.Dependencies
== FullDependencies
)
441 "ifeq ($(ROS_BUILDDEPS),)\n"
442 "ROS_BUILDDEPS:=%s\n"
449 compilerPrefix
.c_str () );
452 nasmCommand
.c_str () );
454 GenerateGlobalProperties ( "=", ProjectNode
.non_if_data
);
456 if ( ProjectNode
.configuration
.Compiler
== GnuGcc
)
458 fprintf ( fMakefile
, "PROJECT_CFLAGS += -Wall\n" );
459 fprintf ( fMakefile
, "PROJECT_CXXFLAGS += -Wall\n" );
460 fprintf ( fMakefile
, "ifneq ($(OARCH),)\n" );
461 fprintf ( fMakefile
, "PROJECT_CFLAGS += -march=$(OARCH)\n" );
462 fprintf ( fMakefile
, "PROJECT_CXXFLAGS += -march=$(OARCH)\n" );
463 fprintf ( fMakefile
, "endif\n" );
464 fprintf ( fMakefile
, "ifneq ($(TUNE),)\n" );
465 fprintf ( fMakefile
, "PROJECT_CFLAGS += -mtune=$(TUNE)\n" );
466 fprintf ( fMakefile
, "PROJECT_CXXFLAGS += -mtune=$(TUNE)\n" );
467 fprintf ( fMakefile
, "endif\n" );
469 fprintf ( fMakefile
, "PROJECT_CFLAGS += -g%s\n", Environment::GetArch() == "amd64" ? "dwarf-2" : "stabs+" );
470 fprintf ( fMakefile
, "PROJECT_CXXFLAGS += -g%s\n", Environment::GetArch() == "amd64" ? "dwarf-2" : "stabs+" );
471 fprintf ( fMakefile
, "PROJECT_ASFLAGS += -g%s\n", Environment::GetArch() == "amd64" ? "dwarf-2" : "stabs+" );
475 fprintf ( fMakefile
, "PROJECT_CFLAGS += -pipe\n" );
476 fprintf ( fMakefile
, "PROJECT_CXXFLAGS += -pipe\n" );
477 fprintf ( fMakefile
, "PROJECT_ASFLAGS += -pipe\n" );
480 // Would be nice to have our own C++ runtime
481 fputs ( "BUILTIN_CXXINCLUDES+= $(TARGET_CPPFLAGS)\n", fMakefile
);
484 // Because RosBE gcc is built to suck
485 fputs ( "BUILTIN_HOST_CINCLUDES+= $(HOST_CFLAGS)\n", fMakefile
);
486 fputs ( "BUILTIN_HOST_CPPINCLUDES+= $(HOST_CFLAGS)\n", fMakefile
);
487 fputs ( "BUILTIN_HOST_CXXINCLUDES+= $(HOST_CPPFLAGS)\n", fMakefile
);
489 MingwModuleHandler::GenerateParameters ( "PROJECT", "+=", ProjectNode
.non_if_data
);
490 MingwModuleHandler::GenerateParameters ( "PROJECT_HOST", "+=", ProjectNode
.host_non_if_data
);
492 // TODO: linker flags
493 fprintf ( fMakefile
, "PROJECT_LFLAGS := '$(shell ${TARGET_CC} -print-libgcc-file-name)' %s\n", GenerateProjectLFLAGS ().c_str () );
494 fprintf ( fMakefile
, "PROJECT_LPPFLAGS := '$(shell ${TARGET_CPP} -print-file-name=libstdc++.a)' '$(shell ${TARGET_CPP} -print-file-name=libgcc.a)' '$(shell ${TARGET_CPP} -print-file-name=libmingw32.a)' '$(shell ${TARGET_CPP} -print-file-name=libmingwex.a)'\n" );
495 /* hack to get libgcc_eh.a, should check mingw version or something */
496 if (Environment::GetArch() == "amd64")
498 fprintf ( fMakefile
, "PROJECT_LPPFLAGS += '$(shell ${TARGET_CPP} -print-file-name=libgcc_eh.a)'\n" );
501 // TODO: use symbolic names for module types
502 for ( size_t i
= 0; i
< sizeof(ModuleHandlerInformations
) / sizeof(ModuleHandlerInformations
[0]); ++ i
)
504 if ( ModuleHandlerInformations
[i
].cflags
&& ModuleHandlerInformations
[i
].cflags
[0] )
507 "MODULETYPE%d_%sFLAGS:=%s\n",
510 ModuleHandlerInformations
[i
].cflags
);
513 if ( ModuleHandlerInformations
[i
].cflags
&& ModuleHandlerInformations
[i
].cflags
[0] )
516 "MODULETYPE%d_%sFLAGS:=%s\n",
519 ModuleHandlerInformations
[i
].cflags
);
522 if ( ModuleHandlerInformations
[i
].nasmflags
&& ModuleHandlerInformations
[i
].nasmflags
[0] )
525 "MODULETYPE%d_%sFLAGS:=%s\n",
528 ModuleHandlerInformations
[i
].nasmflags
);
532 fprintf ( fMakefile
, "\n" );
536 MingwBackend::IncludeInAllTarget ( const Module
& module
) const
538 if ( MingwModuleHandler::ReferenceObjects ( module
) )
540 if ( module
.type
== BootSector
)
542 if ( module
.type
== Iso
)
544 if ( module
.type
== LiveIso
)
546 if ( module
.type
== IsoRegTest
)
548 if ( module
.type
== LiveIsoRegTest
)
550 if ( module
.type
== Test
)
552 if ( module
.type
== Alias
)
558 MingwBackend::GenerateAllTarget ( const vector
<MingwModuleHandler
*>& handlers
) const
560 fprintf ( fMakefile
, "all:" );
562 size_t iend
= handlers
.size ();
563 for ( size_t i
= 0; i
< iend
; i
++ )
565 const Module
& module
= handlers
[i
]->module
;
566 if ( IncludeInAllTarget ( module
) )
568 if ( wrap_count
++ == 5 )
569 fprintf ( fMakefile
, " \\\n\t\t" ), wrap_count
= 0;
572 GetTargetMacro(module
).c_str () );
575 fprintf ( fMakefile
, "\n\t\n\n" );
579 MingwBackend::GenerateRegTestsRunTarget () const
582 "REGTESTS_RUN_TARGET = regtests.dll\n" );
584 "$(REGTESTS_RUN_TARGET): $(REGTESTS_TARGET)\n" );
586 "\t$(cp) $(REGTESTS_TARGET) $(REGTESTS_RUN_TARGET)\n" );
587 fprintf ( fMakefile
, "\n" );
591 MingwBackend::GenerateXmlBuildFilesMacro() const
594 "XMLBUILDFILES = %s \\\n",
595 ProjectNode
.GetProjectFilename ().c_str () );
596 string xmlbuildFilenames
;
597 int numberOfExistingFiles
= 0;
599 time_t SystemTime
, lastWriteTime
;
601 for ( size_t i
= 0; i
< ProjectNode
.xmlbuildfiles
.size (); i
++ )
603 XMLInclude
& xmlbuildfile
= *ProjectNode
.xmlbuildfiles
[i
];
604 if ( !xmlbuildfile
.fileExists
)
606 numberOfExistingFiles
++;
607 if ( xmlbuildFilenames
.length () > 0 )
608 xmlbuildFilenames
+= " ";
610 FILE* f
= fopen ( xmlbuildfile
.topIncludeFilename
.c_str (), "rb" );
612 throw FileNotFoundException ( NormalizeFilename ( xmlbuildfile
.topIncludeFilename
) );
614 if ( fstat ( fileno ( f
), &statbuf
) != 0 )
617 throw AccessDeniedException ( NormalizeFilename ( xmlbuildfile
.topIncludeFilename
) );
620 lastWriteTime
= statbuf
.st_mtime
;
621 SystemTime
= time(NULL
);
623 if (SystemTime
!= -1)
625 if (difftime (lastWriteTime
, SystemTime
) > 0)
626 throw InvalidDateException ( NormalizeFilename ( xmlbuildfile
.topIncludeFilename
) );
631 xmlbuildFilenames
+= NormalizeFilename ( xmlbuildfile
.topIncludeFilename
);
632 if ( numberOfExistingFiles
% 5 == 4 || i
== ProjectNode
.xmlbuildfiles
.size () - 1 )
636 xmlbuildFilenames
.c_str ());
637 if ( i
== ProjectNode
.xmlbuildfiles
.size () - 1 )
639 fprintf ( fMakefile
, "\n" );
646 xmlbuildFilenames
.resize ( 0 );
648 numberOfExistingFiles
++;
650 fprintf ( fMakefile
, "\n" );
654 MingwBackend::GenerateTestSupportCode ()
656 printf ( "Generating test support code..." );
657 TestSupportCode
testSupportCode ( ProjectNode
);
658 testSupportCode
.GenerateTestSupportCode ( configuration
.Verbose
);
663 MingwBackend::GenerateCompilationUnitSupportCode ()
665 if ( configuration
.CompilationUnitsEnabled
)
667 printf ( "Generating compilation unit support code..." );
668 CompilationUnitSupportCode
compilationUnitSupportCode ( ProjectNode
);
669 compilationUnitSupportCode
.Generate ( configuration
.Verbose
);
675 MingwBackend::GenerateSysSetup ()
677 printf ( "Generating syssetup.inf..." );
678 SysSetupGenerator
sysSetupGenerator ( ProjectNode
);
679 sysSetupGenerator
.Generate ();
684 MingwBackend::GetProxyMakefileTree () const
686 if ( configuration
.GenerateProxyMakefilesInSourceTree
)
689 return Environment::GetOutputPath ();
693 MingwBackend::GenerateProxyMakefiles ()
695 printf ( "Generating proxy makefiles..." );
696 ProxyMakefile
proxyMakefile ( ProjectNode
);
697 proxyMakefile
.GenerateProxyMakefiles ( configuration
.Verbose
,
698 GetProxyMakefileTree () );
703 MingwBackend::CheckAutomaticDependencies ()
705 if ( configuration
.Dependencies
== AutomaticDependencies
)
707 printf ( "Checking automatic dependencies..." );
708 AutomaticDependency
automaticDependency ( ProjectNode
);
709 automaticDependency
.CheckAutomaticDependencies ( configuration
.Verbose
);
715 MingwBackend::GenerateDirectories ()
717 printf ( "Creating directories..." );
718 intermediateDirectory
->GenerateTree ( IntermediateDirectory
, configuration
.Verbose
);
719 outputDirectory
->GenerateTree ( OutputDirectory
, configuration
.Verbose
);
720 if ( !configuration
.MakeHandlesInstallDirectories
)
721 installDirectory
->GenerateTree ( InstallDirectory
, configuration
.Verbose
);
726 MingwBackend::TryToDetectThisCompiler ( const string
& compiler
)
728 string command
= ssprintf (
730 FixSeparatorForSystemCommand(compiler
).c_str (),
733 int exitcode
= system ( command
.c_str () );
734 return (bool) (exitcode
== 0);
738 MingwBackend::DetectCompiler ()
740 printf ( "Detecting compiler..." );
742 bool detectedCompiler
= false;
743 bool supportedCompiler
= false;
744 string compilerVersion
;
746 if ( ProjectNode
.configuration
.Compiler
== GnuGcc
)
748 const string
& ROS_PREFIXValue
= Environment::GetVariable ( "ROS_PREFIX" );
749 if ( ROS_PREFIXValue
.length () > 0 )
751 compilerPrefix
= ROS_PREFIXValue
;
752 compilerCommand
= compilerPrefix
+ "-gcc";
753 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
756 if ( !detectedCompiler
)
759 compilerCommand
= "gcc";
760 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
763 if ( !detectedCompiler
)
765 compilerPrefix
= "mingw32";
766 compilerCommand
= compilerPrefix
+ "-gcc";
767 detectedCompiler
= TryToDetectThisCompiler ( compilerCommand
);
770 if ( detectedCompiler
)
771 compilerVersion
= GetCompilerVersion ( compilerCommand
);
773 supportedCompiler
= IsSupportedCompilerVersion ( compilerVersion
);
775 else if ( ProjectNode
.configuration
.Compiler
== MicrosoftC
)
777 compilerCommand
= "cl";
778 detectedCompiler
= DetectMicrosoftCompiler ( compilerVersion
, mscPath
);
779 supportedCompiler
= true; // TODO
782 if ( detectedCompiler
)
784 if ( supportedCompiler
)
785 printf ( "detected (%s %s)\n", compilerCommand
.c_str (), compilerVersion
.c_str() );
788 printf ( "detected (%s), but with unsupported version (%s)\n",
789 compilerCommand
.c_str (),
790 compilerVersion
.c_str () );
791 throw UnsupportedBuildToolException ( compilerCommand
, compilerVersion
);
795 printf ( "not detected\n" );
800 MingwBackend::TryToDetectThisNetwideAssembler ( const string
& assembler
)
802 string command
= ssprintf (
804 FixSeparatorForSystemCommand(assembler
).c_str (),
807 int exitcode
= system ( command
.c_str () );
808 return (bool) (exitcode
== 0);
812 MingwBackend::GetVersionString ( const string
& versionCommand
)
819 fp
= popen ( versionCommand
.c_str () , "r" );
822 ( feof ( fp
) == 0 &&
823 ( ( ch
= fgetc( fp
) ) != -1 ) );
826 buffer
[i
] = (char) ch
;
831 char separators
[] = " ()";
833 char *prevtoken
= NULL
;
837 token
= strtok ( buffer
, separators
);
838 while ( token
!= NULL
)
841 version
= string( prevtoken
);
842 if ( (newline
= version
.find('\n')) != std::string::npos
)
843 version
.erase(newline
, 1);
844 if ( version
.find('.') != std::string::npos
)
846 token
= strtok ( NULL
, separators
);
852 MingwBackend::GetNetwideAssemblerVersion ( const string
& nasmCommand
)
854 string versionCommand
;
855 if ( nasmCommand
.find("yasm") != std::string::npos
)
857 versionCommand
= ssprintf ( "%s --version",
858 nasmCommand
.c_str (),
864 versionCommand
= ssprintf ( "%s -v",
865 nasmCommand
.c_str (),
869 return GetVersionString( versionCommand
);
873 MingwBackend::GetCompilerVersion ( const string
& compilerCommand
)
875 string versionCommand
= ssprintf ( "%s --version gcc",
876 compilerCommand
.c_str (),
879 return GetVersionString( versionCommand
);
883 MingwBackend::GetBinutilsVersion ( const string
& binutilsCommand
)
885 string versionCommand
= ssprintf ( "%s -v",
886 binutilsCommand
.c_str (),
889 return GetVersionString( versionCommand
);
893 MingwBackend::IsSupportedCompilerVersion ( const string
& compilerVersion
)
895 if ( strcmp ( compilerVersion
.c_str (), "3.4.2") < 0 )
902 MingwBackend::TryToDetectThisBinutils ( const string
& binutils
)
904 string command
= ssprintf (
906 FixSeparatorForSystemCommand(binutils
).c_str (),
909 int exitcode
= system ( command
.c_str () );
910 return (exitcode
== 0);
914 MingwBackend::GetBinutilsVersionDate ( const string
& binutilsCommand
)
920 string versionCommand
= ssprintf ( "%s -v",
921 binutilsCommand
.c_str (),
924 fp
= popen ( versionCommand
.c_str () , "r" );
927 ( feof ( fp
) == 0 &&
928 ( ( ch
= fgetc( fp
) ) != -1 ) );
931 buffer
[i
] = (char) ch
;
936 char separators
[] = " ";
938 char *prevtoken
= NULL
;
940 token
= strtok ( buffer
, separators
);
941 while ( token
!= NULL
)
944 token
= strtok ( NULL
, separators
);
946 string version
= string ( prevtoken
);
947 int lastDigit
= version
.find_last_not_of ( "\t\r\n" );
948 if ( lastDigit
!= -1 )
949 return string ( version
, 0, lastDigit
+1 );
955 MingwBackend::IsSupportedBinutilsVersion ( const string
& binutilsVersion
)
957 if ( manualBinutilsSetting
) return true;
960 if ( binutilsVersion
.find('.') != std::string::npos
)
962 /* TODO: blacklist versions on version number instead of date */
967 * - Binutils older than 2003/10/01 have broken windres which can't handle
968 * icons with alpha channel.
969 * - Binutils between 2004/09/02 and 2004/10/08 have broken handling of
970 * forward exports in dlltool.
972 if ( ( ( strcmp ( binutilsVersion
.c_str (), "20040902") >= 0 ) &&
973 ( strcmp ( binutilsVersion
.c_str (), "20041008") <= 0 ) ) ||
974 ( strcmp ( binutilsVersion
.c_str (), "20031001") < 0 ) )
981 MingwBackend::DetectBinutils ()
983 printf ( "Detecting binutils..." );
985 bool detectedBinutils
= false;
986 bool supportedBinutils
= false;
987 string binutilsVersion
;
989 if ( ProjectNode
.configuration
.Linker
== GnuLd
)
991 const string
& ROS_PREFIXValue
= Environment::GetVariable ( "ROS_PREFIX" );
993 if ( ROS_PREFIXValue
.length () > 0 )
995 binutilsPrefix
= ROS_PREFIXValue
;
996 binutilsCommand
= binutilsPrefix
+ "-ld";
997 manualBinutilsSetting
= true;
998 detectedBinutils
= true;
1001 if ( !detectedBinutils
)
1003 binutilsPrefix
= "";
1004 binutilsCommand
= "ld";
1005 detectedBinutils
= TryToDetectThisBinutils ( binutilsCommand
);
1008 if ( !detectedBinutils
)
1010 binutilsPrefix
= "mingw32";
1011 binutilsCommand
= binutilsPrefix
+ "-ld";
1012 detectedBinutils
= TryToDetectThisBinutils ( binutilsCommand
);
1014 if ( detectedBinutils
)
1016 binutilsVersion
= GetBinutilsVersionDate ( binutilsCommand
);
1017 supportedBinutils
= IsSupportedBinutilsVersion ( binutilsVersion
);
1020 else if ( ProjectNode
.configuration
.Linker
== MicrosoftLink
)
1022 compilerCommand
= "link";
1023 detectedBinutils
= DetectMicrosoftLinker ( binutilsVersion
, mslinkPath
);
1024 supportedBinutils
= true; // TODO
1027 if ( detectedBinutils
)
1029 if ( supportedBinutils
)
1030 printf ( "detected (%s %s)\n", binutilsCommand
.c_str (), binutilsVersion
.c_str() );
1033 printf ( "detected (%s), but with unsupported version (%s)\n",
1034 binutilsCommand
.c_str (),
1035 binutilsVersion
.c_str () );
1036 throw UnsupportedBuildToolException ( binutilsCommand
, binutilsVersion
);
1040 printf ( "not detected\n" );
1045 MingwBackend::DetectNetwideAssembler ()
1047 printf ( "Detecting netwide assembler..." );
1049 nasmCommand
= "nasm";
1050 bool detectedNasm
= TryToDetectThisNetwideAssembler ( nasmCommand
);
1052 if ( !detectedNasm
)
1054 nasmCommand
= "nasmw";
1055 detectedNasm
= TryToDetectThisNetwideAssembler ( nasmCommand
);
1058 if ( !detectedNasm
)
1060 nasmCommand
= "yasm";
1061 detectedNasm
= TryToDetectThisNetwideAssembler ( nasmCommand
);
1064 printf ( "detected (%s %s)\n", nasmCommand
.c_str (), GetNetwideAssemblerVersion( nasmCommand
).c_str() );
1066 printf ( "not detected\n" );
1070 MingwBackend::DetectPipeSupport ()
1072 if ( ProjectNode
.configuration
.Compiler
== GnuGcc
)
1074 printf ( "Detecting compiler -pipe support..." );
1076 string pipe_detection
= "tools" + sSep
+ "rbuild" + sSep
+ "backend" + sSep
+ "mingw" + sSep
+ "pipe_detection.c";
1077 string pipe_detectionObjectFilename
= ReplaceExtension ( pipe_detection
,
1079 string command
= ssprintf (
1080 "%s -pipe -c %s -o %s 1>%s 2>%s",
1081 FixSeparatorForSystemCommand(compilerCommand
).c_str (),
1082 pipe_detection
.c_str (),
1083 pipe_detectionObjectFilename
.c_str (),
1086 int exitcode
= system ( command
.c_str () );
1087 FILE* f
= fopen ( pipe_detectionObjectFilename
.c_str (), "rb" );
1090 usePipe
= (exitcode
== 0);
1092 unlink ( pipe_detectionObjectFilename
.c_str () );
1098 printf ( "detected\n" );
1100 printf ( "not detected\n" );
1107 MingwBackend::DetectPCHSupport ()
1109 printf ( "Detecting compiler pre-compiled header support..." );
1111 if ( configuration
.PrecompiledHeadersEnabled
&& ProjectNode
.configuration
.Compiler
== GnuGcc
)
1113 string path
= "tools" + sSep
+ "rbuild" + sSep
+ "backend" + sSep
+ "mingw" + sSep
+ "pch_detection.h";
1114 string cmd
= ssprintf (
1115 "%s -c %s 1>%s 2>%s",
1116 FixSeparatorForSystemCommand(compilerCommand
).c_str (),
1120 system ( cmd
.c_str () );
1123 FILE* f
= fopen ( path
.c_str (), "rb" );
1128 unlink ( path
.c_str () );
1134 printf ( "detected\n" );
1136 printf ( "not detected\n" );
1141 printf ( "disabled\n" );
1146 MingwBackend::GetNonModuleInstallTargetFiles (
1147 vector
<FileLocation
>& out
) const
1149 for ( size_t i
= 0; i
< ProjectNode
.installfiles
.size (); i
++ )
1151 const InstallFile
& installfile
= *ProjectNode
.installfiles
[i
];
1152 out
.push_back ( *installfile
.target
);
1157 MingwBackend::GetModuleInstallTargetFiles (
1158 vector
<FileLocation
>& out
) const
1160 for ( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
1162 const Module
& module
= *p
->second
;
1163 if ( !module
.enabled
)
1165 if ( module
.install
)
1166 out
.push_back ( *module
.install
);
1171 MingwBackend::GetInstallTargetFiles (
1172 vector
<FileLocation
>& out
) const
1174 GetNonModuleInstallTargetFiles ( out
);
1175 GetModuleInstallTargetFiles ( out
);
1179 MingwBackend::OutputInstallTarget ( const FileLocation
& source
,
1180 const FileLocation
& target
)
1182 fprintf ( fMakefile
,
1184 GetFullName ( target
).c_str (),
1185 GetFullName ( source
).c_str (),
1186 GetFullPath ( target
).c_str () );
1187 fprintf ( fMakefile
,
1189 fprintf ( fMakefile
,
1190 "\t${cp} %s %s 1>$(NUL)\n",
1191 GetFullName ( source
).c_str (),
1192 GetFullName ( target
).c_str () );
1196 MingwBackend::OutputNonModuleInstallTargets ()
1198 for ( size_t i
= 0; i
< ProjectNode
.installfiles
.size (); i
++ )
1200 const InstallFile
& installfile
= *ProjectNode
.installfiles
[i
];
1201 OutputInstallTarget ( *installfile
.source
, *installfile
.target
);
1206 MingwBackend::GetAliasedModuleOrModule ( const Module
& module
) const
1208 if ( module
.aliasedModuleName
.size () > 0 )
1210 const Module
* aliasedModule
= ProjectNode
.LocateModule ( module
.aliasedModuleName
);
1211 assert ( aliasedModule
);
1212 return *aliasedModule
;
1219 MingwBackend::OutputModuleInstallTargets ()
1221 for ( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
1223 const Module
& module
= *p
->second
;
1224 if ( !module
.enabled
)
1226 if ( module
.install
)
1228 const Module
& aliasedModule
= GetAliasedModuleOrModule ( module
);
1229 OutputInstallTarget ( *aliasedModule
.output
, *module
.install
);
1235 MingwBackend::GetRegistrySourceFiles ()
1237 return "boot" + sSep
+ "bootdata" + sSep
+ "hivecls_" + Environment::GetArch() + ".inf "
1238 "boot" + sSep
+ "bootdata" + sSep
+ "hivedef_" + Environment::GetArch() + ".inf "
1239 "boot" + sSep
+ "bootdata" + sSep
+ "hiveinst_" + Environment::GetArch() + ".inf "
1240 "boot" + sSep
+ "bootdata" + sSep
+ "hivesft_" + Environment::GetArch() + ".inf "
1241 "boot" + sSep
+ "bootdata" + sSep
+ "hivesys_" + Environment::GetArch() + ".inf ";
1245 MingwBackend::GetRegistryTargetFiles ()
1247 string system32ConfigDirectory
= "system32" + sSep
+ "config";
1248 FileLocation
system32 ( InstallDirectory
, system32ConfigDirectory
, "" );
1250 vector
<FileLocation
> registry_files
;
1251 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "default" ) );
1252 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "sam" ) );
1253 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "security" ) );
1254 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "software" ) );
1255 registry_files
.push_back ( FileLocation ( InstallDirectory
, system32ConfigDirectory
, "system" ) );
1257 return v2s( this, registry_files
, 6 );
1261 MingwBackend::OutputRegistryInstallTarget ()
1263 FileLocation
system32 ( InstallDirectory
, "system32" + sSep
+ "config", "" );
1265 string registrySourceFiles
= GetRegistrySourceFiles ();
1266 string registryTargetFiles
= GetRegistryTargetFiles ();
1267 fprintf ( fMakefile
,
1268 "install_registry: %s\n",
1269 registryTargetFiles
.c_str () );
1270 fprintf ( fMakefile
,
1271 "%s: %s %s $(MKHIVE_TARGET)\n",
1272 registryTargetFiles
.c_str (),
1273 registrySourceFiles
.c_str (),
1274 GetFullPath ( system32
).c_str () );
1275 fprintf ( fMakefile
,
1276 "\t$(ECHO_MKHIVE)\n" );
1277 fprintf ( fMakefile
,
1278 "\t$(MKHIVE_TARGET) boot%cbootdata %s $(ARCH) boot%cbootdata%chiveinst_$(ARCH).inf\n",
1279 cSep
, GetFullPath ( system32
).c_str (),
1281 fprintf ( fMakefile
,
1286 MingwBackend::GenerateInstallTarget ()
1288 vector
<FileLocation
> vInstallTargetFiles
;
1289 GetInstallTargetFiles ( vInstallTargetFiles
);
1290 string installTargetFiles
= v2s ( this, vInstallTargetFiles
, 5 );
1291 string registryTargetFiles
= GetRegistryTargetFiles ();
1293 fprintf ( fMakefile
,
1295 installTargetFiles
.c_str (),
1296 registryTargetFiles
.c_str () );
1297 OutputNonModuleInstallTargets ();
1298 OutputModuleInstallTargets ();
1299 OutputRegistryInstallTarget ();
1300 fprintf ( fMakefile
,
1305 MingwBackend::GetModuleTestTargets (
1306 vector
<string
>& out
) const
1308 for ( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin (); p
!= ProjectNode
.modules
.end (); ++ p
)
1310 const Module
& module
= *p
->second
;
1311 if ( !module
.enabled
)
1313 if ( module
.type
== Test
)
1314 out
.push_back ( module
.name
);
1319 MingwBackend::GenerateTestTarget ()
1321 vector
<string
> vTestTargets
;
1322 GetModuleTestTargets ( vTestTargets
);
1323 string testTargets
= v2s ( vTestTargets
, 5 );
1325 fprintf ( fMakefile
,
1327 testTargets
.c_str () );
1328 fprintf ( fMakefile
,
1333 MingwBackend::GenerateDirectoryTargets ()
1335 intermediateDirectory
->CreateRule ( fMakefile
, "$(INTERMEDIATE)" );
1336 outputDirectory
->CreateRule ( fMakefile
, "$(OUTPUT)" );
1337 installDirectory
->CreateRule ( fMakefile
, "$(INSTALL)" );