reactos/reactos/tools/rbuild/backend/mingw/mingw.cpp
Timo Kreuzer 579ef7b3cb Revert r46466
svn path=/trunk/; revision=46492
2010-03-27 18:29:08 +00:00

1362 lines
36 KiB
C++

/*
* Copyright (C) 2005 Casper S. Hornstrup
* 2006 Christoph von Wittich
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../../pch.h"
#include "mingw.h"
#include <assert.h>
#include "modulehandler.h"
#ifdef _MSC_VER
#define popen _popen
#define pclose _pclose
#endif//_MSC_VER
using std::string;
using std::vector;
using std::set;
using std::map;
typedef set<string> set_string;
const struct ModuleHandlerInformations ModuleHandlerInformations[] = {
{ HostTrue, "", "", "" }, // BuildTool
{ HostFalse, "", "", "" }, // StaticLibrary
{ HostFalse, "", "", "" }, // ObjectLibrary
{ HostFalse, "", "", "$(LDFLAG_DRIVER)" }, // Kernel
{ HostFalse, "", "", "$(LDFLAG_DRIVER)" }, // KernelModeDLL
{ HostFalse, "-D__NTDRIVER__", "", "$(LDFLAG_DRIVER)" }, // KernelModeDriver
{ HostFalse, "", "", "$(LDFLAG_DLL)" }, // NativeDLL
{ HostFalse, "-D__NTAPP__", "", "$(LDFLAG_NATIVE)" }, // NativeCUI
{ HostFalse, "", "", "$(LDFLAG_DLL)" }, // Win32DLL
{ HostFalse, "", "", "$(LDFLAG_DLL)" }, // Win32OCX
{ HostFalse, "", "", "$(LDFLAG_CONSOLE)" }, // Win32CUI
{ HostFalse, "", "", "$(LDFLAG_WINDOWS)" }, // Win32GUI
{ HostFalse, "", "", "" }, // BootLoader
{ HostFalse, "", "-f bin", "" }, // BootSector
{ HostFalse, "", "", "" }, // Iso
{ HostFalse, "", "", "" }, // LiveIso
{ HostFalse, "", "", "" }, // Test
{ HostFalse, "", "", "" }, // RpcServer
{ HostFalse, "", "", "" }, // RpcClient
{ HostFalse, "", "", "" }, // Alias
{ HostFalse, "", "", "" }, // BootProgram
{ HostFalse, "", "", "$(LDFLAG_WINDOWS)" }, // Win32SCR
{ HostFalse, "", "", "" }, // IdlHeader
{ HostFalse, "", "", "" }, // IdlInterface
{ HostFalse, "", "", "" }, // EmbeddedTypeLib
{ HostFalse, "", "", "" }, // ElfExecutable
{ HostFalse, "", "", "" }, // RpcProxy
{ HostTrue, "", "", "" }, // HostStaticLibrary
{ HostFalse, "", "", "" }, // Cabinet
{ HostFalse, "", "", "$(LDFLAG_DLL)" }, // KeyboardLayout
{ HostFalse, "", "", "" }, // MessageHeader
};
static std::string mscPath;
static std::string mslinkPath;
string
MingwBackend::GetFullPath ( const FileLocation& file ) const
{
MingwModuleHandler::PassThruCacheDirectory ( &file );
string directory;
switch ( file.directory )
{
case SourceDirectory:
directory = "";
break;
case IntermediateDirectory:
directory = "$(INTERMEDIATE)";
break;
case OutputDirectory:
directory = "$(OUTPUT)";
break;
case InstallDirectory:
directory = "$(INSTALL)";
break;
case TemporaryDirectory:
directory = "$(TEMPORARY)";
break;
default:
throw InvalidOperationException ( __FILE__,
__LINE__,
"Invalid directory %d.",
file.directory );
}
if ( file.relative_path.length () > 0 )
{
if ( directory.length () > 0 )
directory += sSep;
directory += file.relative_path;
}
return directory;
}
string
MingwBackend::GetFullName ( const FileLocation& file ) const
{
string directory;
switch ( file.directory )
{
case SourceDirectory:
directory = "";
break;
case IntermediateDirectory:
directory = "$(INTERMEDIATE)";
break;
case OutputDirectory:
directory = "$(OUTPUT)";
break;
case InstallDirectory:
directory = "$(INSTALL)";
break;
case TemporaryDirectory:
directory = "$(TEMPORARY)";
break;
default:
throw InvalidOperationException ( __FILE__,
__LINE__,
"Invalid directory %d.",
file.directory );
}
if ( file.relative_path.length () > 0 )
{
if ( directory.length () > 0 )
directory += sSep;
directory += file.relative_path;
}
if ( directory.length () > 0 )
directory += sSep;
return directory + file.name;
}
string
v2s ( const Backend* backend, const vector<FileLocation>& files, int wrap_at )
{
if ( !files.size() )
return "";
string s;
int wrap_count = 0;
for ( size_t i = 0; i < files.size(); i++ )
{
const FileLocation& file = files[i];
if ( wrap_at > 0 && wrap_count++ == wrap_at )
{
s += " \\\n\t\t";
wrap_count = 1;
}
else if ( s.size() )
s += " ";
s += backend->GetFullName ( file );
}
return s;
}
string
v2s ( const string_list& v, int wrap_at )
{
if ( !v.size() )
return "";
string s;
int wrap_count = 0;
for ( size_t i = 0; i < v.size(); i++ )
{
if ( !v[i].size() )
continue;
if ( wrap_at > 0 && wrap_count++ == wrap_at )
{
s += " \\\n\t\t";
wrap_count = 1;
}
else if ( s.size() )
s += " ";
s += v[i];
}
return s;
}
static class MingwFactory : public Backend::Factory
{
public:
MingwFactory() : Factory ( "mingw", "Minimalist GNU Win32" ) {}
Backend* operator() ( Project& project,
Configuration& configuration )
{
return new MingwBackend ( project,
configuration );
}
} factory;
MingwBackend::MingwBackend ( Project& project,
Configuration& configuration )
: Backend ( project, configuration ),
manualBinutilsSetting( false ),
intermediateDirectory ( new Directory ( "" ) ),
outputDirectory ( new Directory ( "" ) ),
installDirectory ( new Directory ( "" ) )
{
compilerPrefix = "";
}
MingwBackend::~MingwBackend()
{
delete intermediateDirectory;
delete outputDirectory;
delete installDirectory;
}
string
MingwBackend::AddDirectoryTarget ( const string& directory,
Directory* directoryTree )
{
if ( directory.length () > 0)
directoryTree->Add ( directory.c_str() );
return directoryTree->name;
}
bool
MingwBackend::CanEnablePreCompiledHeaderSupportForModule ( const Module& module )
{
if ( !configuration.CompilationUnitsEnabled )
return true;
const vector<CompilationUnit*>& compilationUnits = module.non_if_data.compilationUnits;
size_t i;
for ( i = 0; i < compilationUnits.size (); i++ )
{
CompilationUnit& compilationUnit = *compilationUnits[i];
if ( compilationUnit.GetFiles ().size () != 1 )
return false;
}
return true;
}
void
MingwBackend::ProcessModules ()
{
printf ( "Processing modules..." );
vector<MingwModuleHandler*> v;
size_t i;
for ( std::map<std::string, Module*>::iterator p = ProjectNode.modules.begin (); p != ProjectNode.modules.end (); ++ p )
fprintf ( fMakefile, "%s_TYPE:=%u\n", p->second->name.c_str(), p->second->type );
for ( std::map<std::string, Module*>::iterator p = ProjectNode.modules.begin (); p != ProjectNode.modules.end (); ++ p )
{
Module& module = *p->second;
if ( !module.enabled )
continue;
MingwModuleHandler* h = MingwModuleHandler::InstanciateHandler (
module,
this );
h->AddImplicitLibraries ( module );
if ( use_pch && CanEnablePreCompiledHeaderSupportForModule ( module ) )
h->EnablePreCompiledHeaderSupport ();
v.push_back ( h );
}
size_t iend = v.size ();
for ( i = 0; i < iend; i++ )
v[i]->GenerateSourceMacro();
for ( i = 0; i < iend; i++ )
v[i]->GenerateObjectMacro();
fprintf ( fMakefile, "\n" );
for ( i = 0; i < iend; i++ )
v[i]->GenerateTargetMacro();
fprintf ( fMakefile, "\n" );
GenerateAllTarget ( v );
GenerateRegTestsRunTarget ();
for ( i = 0; i < iend; i++ )
v[i]->GenerateOtherMacros();
for ( i = 0; i < iend; i++ )
{
MingwModuleHandler& h = *v[i];
h.GeneratePreconditionDependencies ();
h.Process ();
h.GenerateInvocations ();
h.GenerateCleanTarget ();
h.GenerateInstallTarget ();
h.GenerateDependsTarget ();
delete v[i];
}
printf ( "done\n" );
}
void
MingwBackend::Process ()
{
if ( configuration.CheckDependenciesForModuleOnly )
CheckAutomaticDependenciesForModuleOnly ();
else
ProcessNormal ();
}
void
MingwBackend::CheckAutomaticDependenciesForModuleOnly ()
{
if ( configuration.Dependencies == AutomaticDependencies )
{
Module* module = ProjectNode.LocateModule ( configuration.CheckDependenciesForModuleOnlyModule );
if ( module == NULL )
{
printf ( "Module '%s' does not exist\n",
configuration.CheckDependenciesForModuleOnlyModule.c_str () );
return;
}
printf ( "Checking automatic dependencies for module '%s'...",
module->name.c_str () );
AutomaticDependency automaticDependency ( ProjectNode );
automaticDependency.CheckAutomaticDependenciesForModule ( *module,
configuration.Verbose );
printf ( "done\n" );
}
}
void
MingwBackend::ProcessNormal ()
{
assert(sizeof(ModuleHandlerInformations)/sizeof(ModuleHandlerInformations[0]) == TypeDontCare);
DetectCompiler ();
DetectBinutils ();
DetectNetwideAssembler ();
DetectPipeSupport ();
DetectPCHSupport ();
CreateMakefile ();
GenerateHeader ();
GenerateGlobalVariables ();
GenerateXmlBuildFilesMacro ();
ProcessModules ();
GenerateInstallTarget ();
GenerateTestTarget ();
GenerateDirectoryTargets ();
GenerateDirectories ();
GenerateTestSupportCode ();
GenerateCompilationUnitSupportCode ();
GenerateSysSetup ();
GenerateProxyMakefiles ();
CheckAutomaticDependencies ();
CloseMakefile ();
}
void
MingwBackend::CreateMakefile ()
{
fMakefile = fopen ( ProjectNode.makefile.c_str (), "w" );
if ( !fMakefile )
throw AccessDeniedException ( ProjectNode.makefile );
MingwModuleHandler::SetBackend ( this );
MingwModuleHandler::SetMakefile ( fMakefile );
}
void
MingwBackend::CloseMakefile () const
{
if (fMakefile)
fclose ( fMakefile );
}
void
MingwBackend::GenerateHeader () const
{
fprintf ( fMakefile, "# THIS FILE IS AUTOMATICALLY GENERATED, EDIT '%s' INSTEAD\n\n",
ProjectNode.GetProjectFilename ().c_str () );
}
void
MingwBackend::GenerateGlobalProperties (
const char* assignmentOperation,
const IfableData& data ) const
{
for ( std::map<std::string, Property*>::const_iterator p = data.properties.begin(); p != data.properties.end(); ++ p )
{
Property& prop = *p->second;
if (!prop.isInternal)
{
fprintf ( fMakefile, "%s := %s\n",
prop.name.c_str(),
prop.value.c_str() );
}
}
}
string
MingwBackend::GenerateProjectLDFLAGS () const
{
string ldflags;
for ( size_t i = 0; i < ProjectNode.linkerFlags.size (); i++ )
{
LinkerFlag& linkerFlag = *ProjectNode.linkerFlags[i];
if ( ldflags.length () > 0 )
ldflags += " ";
ldflags += linkerFlag.flag;
}
return ldflags;
}
void
MingwBackend::GenerateGlobalVariables () const
{
fputs ( "include tools$(SEP)rbuild$(SEP)backend$(SEP)mingw$(SEP)rules.mak\n", fMakefile );
fprintf ( fMakefile, "include tools$(SEP)rbuild$(SEP)backend$(SEP)mingw$(SEP)linkers$(SEP)%s.mak\n", ProjectNode.GetLinkerSet ().c_str () );
fprintf ( fMakefile, "include tools$(SEP)rbuild$(SEP)backend$(SEP)mingw$(SEP)compilers$(SEP)%s.mak\n", ProjectNode.GetCompilerSet ().c_str () );
if ( mscPath.length() )
fprintf ( fMakefile, "export RBUILD_CL_PATH=%s\n", mscPath.c_str () );
if ( mslinkPath.length() )
fprintf ( fMakefile, "export RBUILD_LINK_PATH=%s\n", mslinkPath.c_str () );
if ( configuration.Dependencies == FullDependencies )
{
fprintf ( fMakefile,
"ifeq ($(ROS_BUILDDEPS),)\n"
"ROS_BUILDDEPS:=%s\n"
"endif\n",
"full" );
}
fprintf ( fMakefile,
"PREFIX := %s\n",
compilerPrefix.c_str () );
fprintf ( fMakefile,
"nasm := $(Q)%s\n",
nasmCommand.c_str () );
GenerateGlobalProperties ( "=", ProjectNode.non_if_data );
if ( ProjectNode.configuration.Compiler == GnuGcc )
{
fprintf ( fMakefile, "ifneq ($(OARCH),)\n" );
fprintf ( fMakefile, "PROJECT_ASFLAGS += -march=$(OARCH)\n" );
fprintf ( fMakefile, "PROJECT_CFLAGS += -march=$(OARCH)\n" );
fprintf ( fMakefile, "PROJECT_CXXFLAGS += -march=$(OARCH)\n" );
fprintf ( fMakefile, "endif\n" );
fprintf ( fMakefile, "ifneq ($(TUNE),)\n" );
fprintf ( fMakefile, "PROJECT_CFLAGS += -mtune=$(TUNE)\n" );
fprintf ( fMakefile, "PROJECT_CXXFLAGS += -mtune=$(TUNE)\n" );
fprintf ( fMakefile, "endif\n" );
if ( usePipe )
{
fprintf ( fMakefile, "PROJECT_CFLAGS += -pipe\n" );
fprintf ( fMakefile, "PROJECT_CXXFLAGS += -pipe\n" );
fprintf ( fMakefile, "PROJECT_ASFLAGS += -pipe\n" );
}
// Would be nice to have our own C++ runtime
fputs ( "BUILTIN_CXXINCLUDES+= $(TARGET_CPPFLAGS)\n", fMakefile );
fprintf ( fMakefile, "PROJECT_CCLIBS := \"$(shell ${TARGET_CC} -print-libgcc-file-name)\"\n" );
// We use our proprietary "ofmt_stub.a" to implement a stub for "_get_output_format" required by "libmingwex.a".
// This archive just contains the compiled "ofmt_stub.s" supplied with the MinGW Runtime sources.
fprintf ( fMakefile, "PROJECT_CXXLIBS := \"$(shell ${TARGET_CPP} -print-file-name=libstdc++.a)\" \"$(shell ${TARGET_CPP} -print-libgcc-file-name)\" \"$(shell ${TARGET_CPP} -print-file-name=libmingw32.a)\" \"$(shell ${TARGET_CPP} -print-file-name=libmingwex.a)\" \"$(shell ${TARGET_CPP} -print-file-name=ofmt_stub.a)\" \"$(shell ${TARGET_CPP} -print-file-name=libcoldname.a)\"\n" );
/* hack to get libgcc_eh.a, should check mingw version or something */
if (Environment::GetArch() == "amd64")
{
fprintf ( fMakefile, "PROJECT_LPPFLAGS += $(shell ${TARGET_CPP} -print-file-name=libgcc_eh.a)\n" );
}
}
MingwModuleHandler::GenerateParameters ( "PROJECT", "+=", ProjectNode.non_if_data );
MingwModuleHandler::GenerateParameters ( "PROJECT_HOST", "+=", ProjectNode.host_non_if_data );
fprintf ( fMakefile, "PROJECT_LDFLAGS := %s\n", GenerateProjectLDFLAGS ().c_str () );
// TODO: use symbolic names for module types
for ( size_t i = 0; i < sizeof(ModuleHandlerInformations) / sizeof(ModuleHandlerInformations[0]); ++ i )
{
if ( ModuleHandlerInformations[i].cflags && ModuleHandlerInformations[i].cflags[0] )
{
fprintf ( fMakefile,
"MODULETYPE%d_%sFLAGS:=%s\n",
(int)i,
"C",
ModuleHandlerInformations[i].cflags );
}
if ( ModuleHandlerInformations[i].nasmflags && ModuleHandlerInformations[i].nasmflags[0] )
{
fprintf ( fMakefile,
"MODULETYPE%d_%sFLAGS:=%s\n",
(int)i,
"NASM",
ModuleHandlerInformations[i].nasmflags );
}
if ( ModuleHandlerInformations[i].linkerflags && ModuleHandlerInformations[i].linkerflags[0] )
{
fprintf ( fMakefile,
"MODULETYPE%d_%sFLAGS:=%s\n",
(int)i,
"LD",
ModuleHandlerInformations[i].linkerflags );
}
}
fprintf ( fMakefile,
"MODULETYPE%d_KMODE:=yes\n",
(int)Kernel );
fprintf ( fMakefile,
"MODULETYPE%d_KMODE:=yes\n",
(int)KernelModeDLL );
fprintf ( fMakefile,
"MODULETYPE%d_KMODE:=yes\n",
(int)KernelModeDriver );
fprintf ( fMakefile, "\n" );
}
bool
MingwBackend::IncludeInAllTarget ( const Module& module ) const
{
if ( MingwModuleHandler::ReferenceObjects ( module ) )
return false;
if ( module.type == BootSector )
return false;
if ( module.type == Iso )
return false;
if ( module.type == LiveIso )
return false;
if ( module.type == Test )
return false;
if ( module.type == Alias )
return false;
return true;
}
void
MingwBackend::GenerateAllTarget ( const vector<MingwModuleHandler*>& handlers ) const
{
fprintf ( fMakefile, "all:" );
int wrap_count = 0;
size_t iend = handlers.size ();
for ( size_t i = 0; i < iend; i++ )
{
const Module& module = handlers[i]->module;
if ( IncludeInAllTarget ( module ) )
{
if ( wrap_count++ == 5 )
fprintf ( fMakefile, " \\\n\t\t" ), wrap_count = 0;
fprintf ( fMakefile,
" %s",
GetTargetMacro(module).c_str () );
}
}
fprintf ( fMakefile, "\n\t\n\n" );
}
void
MingwBackend::GenerateRegTestsRunTarget () const
{
fprintf ( fMakefile,
"REGTESTS_RUN_TARGET = regtests.dll\n" );
fprintf ( fMakefile,
"$(REGTESTS_RUN_TARGET): $(REGTESTS_TARGET)\n" );
fprintf ( fMakefile,
"\t$(cp) $(REGTESTS_TARGET) $(REGTESTS_RUN_TARGET)\n" );
fprintf ( fMakefile, "\n" );
}
void
MingwBackend::GenerateXmlBuildFilesMacro() const
{
fprintf ( fMakefile,
"XMLBUILDFILES = %s \\\n",
ProjectNode.GetProjectFilename ().c_str () );
string xmlbuildFilenames;
int numberOfExistingFiles = 0;
struct stat statbuf;
time_t SystemTime, lastWriteTime;
for ( size_t i = 0; i < ProjectNode.xmlbuildfiles.size (); i++ )
{
XMLInclude& xmlbuildfile = *ProjectNode.xmlbuildfiles[i];
if ( !xmlbuildfile.fileExists )
continue;
numberOfExistingFiles++;
if ( xmlbuildFilenames.length () > 0 )
xmlbuildFilenames += " ";
FILE* f = fopen ( xmlbuildfile.topIncludeFilename.c_str (), "rb" );
if ( !f )
throw FileNotFoundException ( NormalizeFilename ( xmlbuildfile.topIncludeFilename ) );
if ( fstat ( fileno ( f ), &statbuf ) != 0 )
{
fclose ( f );
throw AccessDeniedException ( NormalizeFilename ( xmlbuildfile.topIncludeFilename ) );
}
lastWriteTime = statbuf.st_mtime;
SystemTime = time(NULL);
if (SystemTime != -1)
{
if (difftime (lastWriteTime, SystemTime) > 0)
throw InvalidDateException ( NormalizeFilename ( xmlbuildfile.topIncludeFilename ) );
}
fclose ( f );
xmlbuildFilenames += NormalizeFilename ( xmlbuildfile.topIncludeFilename );
if ( numberOfExistingFiles % 5 == 4 || i == ProjectNode.xmlbuildfiles.size () - 1 )
{
fprintf ( fMakefile,
"\t%s",
xmlbuildFilenames.c_str ());
if ( i == ProjectNode.xmlbuildfiles.size () - 1 )
{
fprintf ( fMakefile, "\n" );
}
else
{
fprintf ( fMakefile,
" \\\n" );
}
xmlbuildFilenames.resize ( 0 );
}
numberOfExistingFiles++;
}
fprintf ( fMakefile, "\n" );
}
void
MingwBackend::GenerateTestSupportCode ()
{
printf ( "Generating test support code..." );
TestSupportCode testSupportCode ( ProjectNode );
testSupportCode.GenerateTestSupportCode ( configuration.Verbose );
printf ( "done\n" );
}
void
MingwBackend::GenerateCompilationUnitSupportCode ()
{
if ( configuration.CompilationUnitsEnabled )
{
printf ( "Generating compilation unit support code..." );
CompilationUnitSupportCode compilationUnitSupportCode ( ProjectNode );
compilationUnitSupportCode.Generate ( configuration.Verbose );
printf ( "done\n" );
}
}
void
MingwBackend::GenerateSysSetup ()
{
printf ( "Generating syssetup.inf..." );
SysSetupGenerator sysSetupGenerator ( ProjectNode );
sysSetupGenerator.Generate ();
printf ( "done\n" );
}
string
MingwBackend::GetProxyMakefileTree () const
{
if ( configuration.GenerateProxyMakefilesInSourceTree )
return "";
else
return Environment::GetOutputPath ();
}
void
MingwBackend::GenerateProxyMakefiles ()
{
printf ( "Generating proxy makefiles..." );
ProxyMakefile proxyMakefile ( ProjectNode );
proxyMakefile.GenerateProxyMakefiles ( configuration.Verbose,
GetProxyMakefileTree () );
printf ( "done\n" );
}
void
MingwBackend::CheckAutomaticDependencies ()
{
if ( configuration.Dependencies == AutomaticDependencies )
{
printf ( "Checking automatic dependencies..." );
AutomaticDependency automaticDependency ( ProjectNode );
automaticDependency.CheckAutomaticDependencies ( configuration.Verbose );
printf ( "done\n" );
}
}
void
MingwBackend::GenerateDirectories ()
{
printf ( "Creating directories..." );
intermediateDirectory->GenerateTree ( IntermediateDirectory, configuration.Verbose );
outputDirectory->GenerateTree ( OutputDirectory, configuration.Verbose );
if ( !configuration.MakeHandlesInstallDirectories )
installDirectory->GenerateTree ( InstallDirectory, configuration.Verbose );
printf ( "done\n" );
}
bool
MingwBackend::TryToDetectThisCompiler ( const string& compiler )
{
string command = ssprintf (
"%s -v 1>%s 2>%s",
FixSeparatorForSystemCommand(compiler).c_str (),
NUL,
NUL );
int exitcode = system ( command.c_str () );
return (bool) (exitcode == 0);
}
void
MingwBackend::DetectCompiler ()
{
printf ( "Detecting compiler..." );
bool detectedCompiler = false;
bool supportedCompiler = false;
string compilerVersion;
if ( ProjectNode.configuration.Compiler == GnuGcc )
{
const string& TARGET_CCValue = Environment::GetVariable ( "TARGET_CC" );
const string& ROS_PREFIXValue = Environment::GetVariable ( "ROS_PREFIX" );
if ( TARGET_CCValue.length () > 0 )
{
compilerPrefix = "";
compilerCommand = TARGET_CCValue;
detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
}
if ( !detectedCompiler )
{
if ( ROS_PREFIXValue.length () > 0 )
{
compilerPrefix = ROS_PREFIXValue;
compilerCommand = compilerPrefix + "-gcc";
detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
}
}
#if defined(WIN32)
if ( !detectedCompiler )
{
compilerPrefix = "";
compilerCommand = "gcc";
detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
}
#endif
if ( !detectedCompiler )
{
compilerPrefix = "mingw32";
compilerCommand = compilerPrefix + "-gcc";
detectedCompiler = TryToDetectThisCompiler ( compilerCommand );
}
if ( detectedCompiler )
compilerVersion = GetCompilerVersion ( compilerCommand );
supportedCompiler = IsSupportedCompilerVersion ( compilerVersion );
}
else if ( ProjectNode.configuration.Compiler == MicrosoftC )
{
compilerCommand = "cl";
detectedCompiler = DetectMicrosoftCompiler ( compilerVersion, mscPath );
supportedCompiler = true; // TODO
}
if ( detectedCompiler )
{
if ( supportedCompiler )
printf ( "detected (%s %s)\n", compilerCommand.c_str (), compilerVersion.c_str() );
else
{
printf ( "detected (%s), but with unsupported version (%s)\n",
compilerCommand.c_str (),
compilerVersion.c_str () );
throw UnsupportedBuildToolException ( compilerCommand, compilerVersion );
}
}
else
printf ( "not detected\n" );
}
bool
MingwBackend::TryToDetectThisNetwideAssembler ( const string& assembler )
{
string command = ssprintf (
"%s -h 1>%s 2>%s",
FixSeparatorForSystemCommand(assembler).c_str (),
NUL,
NUL );
int exitcode = system ( command.c_str () );
return (bool) (exitcode == 0);
}
string
MingwBackend::GetVersionString ( const string& versionCommand )
{
FILE *fp;
int ch, i;
size_t newline;
char buffer[81];
fp = popen ( versionCommand.c_str () , "r" );
for( i = 0;
( i < 80 ) &&
( feof ( fp ) == 0 &&
( ( ch = fgetc( fp ) ) != -1 ) );
i++ )
{
buffer[i] = (char) ch;
}
buffer[i] = '\0';
pclose ( fp );
char separators[] = " ()\n";
char *token;
char *prevtoken = NULL;
string version;
token = strtok ( buffer, separators );
while ( token != NULL )
{
prevtoken = token;
version = string( prevtoken );
if ( (newline = version.find('\n')) != std::string::npos )
version.erase(newline, 1);
if ( version.find('.') != std::string::npos )
break;
token = strtok ( NULL, separators );
}
return version;
}
string
MingwBackend::GetNetwideAssemblerVersion ( const string& nasmCommand )
{
string versionCommand;
if ( nasmCommand.find("yasm") != std::string::npos )
{
versionCommand = ssprintf ( "%s --version",
nasmCommand.c_str (),
NUL,
NUL );
}
else
{
versionCommand = ssprintf ( "%s -v",
nasmCommand.c_str (),
NUL,
NUL );
}
return GetVersionString( versionCommand );
}
string
MingwBackend::GetCompilerVersion ( const string& compilerCommand )
{
string versionCommand = ssprintf ( "%s --version",
compilerCommand.c_str (),
NUL,
NUL );
return GetVersionString( versionCommand );
}
string
MingwBackend::GetBinutilsVersion ( const string& binutilsCommand )
{
string versionCommand = ssprintf ( "%s -v",
binutilsCommand.c_str (),
NUL,
NUL );
return GetVersionString( versionCommand );
}
bool
MingwBackend::IsSupportedCompilerVersion ( const string& compilerVersion )
{
if ( strcmp ( compilerVersion.c_str (), "4.4.0") < 0 )
return false;
else
return true;
}
bool
MingwBackend::TryToDetectThisBinutils ( const string& binutils )
{
string command = ssprintf (
"%s -v 1>%s 2>%s",
FixSeparatorForSystemCommand(binutils).c_str (),
NUL,
NUL );
int exitcode = system ( command.c_str () );
return (exitcode == 0);
}
string
MingwBackend::GetBinutilsVersionDate ( const string& binutilsCommand )
{
FILE *fp;
int ch, i;
char buffer[81];
string versionCommand = ssprintf ( "%s -v",
binutilsCommand.c_str (),
NUL,
NUL );
fp = popen ( versionCommand.c_str () , "r" );
for( i = 0;
( i < 80 ) &&
( feof ( fp ) == 0 &&
( ( ch = fgetc( fp ) ) != -1 ) );
i++ )
{
buffer[i] = (char) ch;
}
buffer[i] = '\0';
pclose ( fp );
char separators[] = " ";
char *token;
char *prevtoken = NULL;
token = strtok ( buffer, separators );
while ( token != NULL )
{
prevtoken = token;
token = strtok ( NULL, separators );
}
string version = string ( prevtoken );
int lastDigit = version.find_last_not_of ( "\t\r\n" );
if ( lastDigit != -1 )
return string ( version, 0, lastDigit+1 );
else
return version;
}
bool
MingwBackend::IsSupportedBinutilsVersion ( const string& binutilsVersion )
{
int digit = binutilsVersion.find_last_of(".");
if(digit == -1)
{
printf("Unable to detect binutils version!\n");
return false;
}
string date = string(binutilsVersion, digit + 1);
if(date.length() == 8)
{
/* This is a real date in the format YYYYMMDD.
Check whether we have at least Binutils 20091016 (the oldest one
we were still using after upgrading to RosBE 1.5). */
if(strcmp(date.c_str(), "20091016") < 0)
return false;
}
else
{
/* This is no date, so binutilsVersion should just contain the version
number.
Binutils 2.20 will hopefully contain the required features. */
if(strcmp(binutilsVersion.c_str(), "2.20") < 0)
return false;
}
return true;
}
void
MingwBackend::DetectBinutils ()
{
printf ( "Detecting binutils..." );
bool detectedBinutils = false;
bool supportedBinutils = false;
string binutilsVersion;
if ( ProjectNode.configuration.Linker == GnuLd )
{
const string& ROS_PREFIXValue = Environment::GetVariable ( "ROS_PREFIX" );
if ( ROS_PREFIXValue.length () > 0 )
{
binutilsPrefix = ROS_PREFIXValue;
binutilsCommand = binutilsPrefix + "-ld";
manualBinutilsSetting = true;
detectedBinutils = true;
}
#if defined(WIN32)
if ( !detectedBinutils )
{
binutilsPrefix = "";
binutilsCommand = "ld";
detectedBinutils = TryToDetectThisBinutils ( binutilsCommand );
}
#endif
if ( !detectedBinutils )
{
binutilsPrefix = "mingw32";
binutilsCommand = binutilsPrefix + "-ld";
detectedBinutils = TryToDetectThisBinutils ( binutilsCommand );
}
if ( detectedBinutils )
{
binutilsVersion = GetBinutilsVersionDate ( binutilsCommand );
supportedBinutils = IsSupportedBinutilsVersion ( binutilsVersion );
}
}
else if ( ProjectNode.configuration.Linker == MicrosoftLink )
{
compilerCommand = "link";
detectedBinutils = DetectMicrosoftLinker ( binutilsVersion, mslinkPath );
supportedBinutils = true; // TODO
}
if ( detectedBinutils )
{
if ( supportedBinutils )
printf ( "detected (%s %s)\n", binutilsCommand.c_str (), binutilsVersion.c_str() );
else
{
printf ( "detected (%s), but with unsupported version (%s)\n",
binutilsCommand.c_str (),
binutilsVersion.c_str () );
throw UnsupportedBuildToolException ( binutilsCommand, binutilsVersion );
}
}
else
printf ( "not detected\n" );
}
void
MingwBackend::DetectNetwideAssembler ()
{
printf ( "Detecting netwide assembler..." );
nasmCommand = "nasm";
bool detectedNasm = TryToDetectThisNetwideAssembler ( nasmCommand );
#if defined(WIN32)
if ( !detectedNasm )
{
nasmCommand = "nasmw";
detectedNasm = TryToDetectThisNetwideAssembler ( nasmCommand );
}
#endif
if ( !detectedNasm )
{
nasmCommand = "yasm";
detectedNasm = TryToDetectThisNetwideAssembler ( nasmCommand );
}
if ( detectedNasm )
printf ( "detected (%s %s)\n", nasmCommand.c_str (), GetNetwideAssemblerVersion( nasmCommand ).c_str() );
else
printf ( "not detected\n" );
}
void
MingwBackend::DetectPipeSupport ()
{
if ( ProjectNode.configuration.Compiler == GnuGcc )
{
printf ( "Detecting compiler -pipe support..." );
string pipe_detection = "tools" + sSep + "rbuild" + sSep + "backend" + sSep + "mingw" + sSep + "pipe_detection.c";
string pipe_detectionObjectFilename = ReplaceExtension ( pipe_detection,
".o" );
string command = ssprintf (
"%s -pipe -c %s -o %s 1>%s 2>%s",
FixSeparatorForSystemCommand(compilerCommand).c_str (),
pipe_detection.c_str (),
pipe_detectionObjectFilename.c_str (),
NUL,
NUL );
int exitcode = system ( command.c_str () );
FILE* f = fopen ( pipe_detectionObjectFilename.c_str (), "rb" );
if ( f )
{
usePipe = (exitcode == 0);
fclose ( f );
unlink ( pipe_detectionObjectFilename.c_str () );
}
else
usePipe = false;
if ( usePipe )
printf ( "detected\n" );
else
printf ( "not detected\n" );
}
else
usePipe = false;
}
void
MingwBackend::DetectPCHSupport ()
{
printf ( "Detecting compiler pre-compiled header support..." );
if ( configuration.PrecompiledHeadersEnabled && ProjectNode.configuration.Compiler == GnuGcc )
{
string path = "tools" + sSep + "rbuild" + sSep + "backend" + sSep + "mingw" + sSep + "pch_detection.h";
string cmd = ssprintf (
"%s -c %s 1>%s 2>%s",
FixSeparatorForSystemCommand(compilerCommand).c_str (),
path.c_str (),
NUL,
NUL );
system ( cmd.c_str () );
path += ".gch";
FILE* f = fopen ( path.c_str (), "rb" );
if ( f )
{
use_pch = true;
fclose ( f );
unlink ( path.c_str () );
}
else
use_pch = false;
if ( use_pch )
printf ( "detected\n" );
else
printf ( "not detected\n" );
}
else
{
use_pch = false;
printf ( "disabled\n" );
}
}
void
MingwBackend::GetNonModuleInstallTargetFiles (
vector<FileLocation>& out ) const
{
for ( size_t i = 0; i < ProjectNode.installfiles.size (); i++ )
{
const InstallFile& installfile = *ProjectNode.installfiles[i];
out.push_back ( *installfile.target );
}
}
void
MingwBackend::GetModuleInstallTargetFiles (
vector<FileLocation>& out ) const
{
for ( std::map<std::string, Module*>::const_iterator p = ProjectNode.modules.begin (); p != ProjectNode.modules.end (); ++ p )
{
const Module& module = *p->second;
if ( !module.enabled )
continue;
if ( module.install )
out.push_back ( *module.install );
}
}
void
MingwBackend::GetInstallTargetFiles (
vector<FileLocation>& out ) const
{
GetNonModuleInstallTargetFiles ( out );
GetModuleInstallTargetFiles ( out );
}
void
MingwBackend::OutputInstallTarget ( const FileLocation& source,
const FileLocation& target )
{
fprintf ( fMakefile,
"%s: %s | %s\n",
GetFullName ( target ).c_str (),
GetFullName ( source ).c_str (),
GetFullPath ( target ).c_str () );
fprintf ( fMakefile,
"\t$(ECHO_CP)\n" );
fprintf ( fMakefile,
"\t${cp} %s %s 1>$(NUL)\n",
GetFullName ( source ).c_str (),
GetFullName ( target ).c_str () );
}
void
MingwBackend::OutputNonModuleInstallTargets ()
{
for ( size_t i = 0; i < ProjectNode.installfiles.size (); i++ )
{
const InstallFile& installfile = *ProjectNode.installfiles[i];
OutputInstallTarget ( *installfile.source, *installfile.target );
}
}
const Module&
MingwBackend::GetAliasedModuleOrModule ( const Module& module ) const
{
if ( module.aliasedModuleName.size () > 0 )
{
const Module* aliasedModule = ProjectNode.LocateModule ( module.aliasedModuleName );
assert ( aliasedModule );
return *aliasedModule;
}
else
return module;
}
void
MingwBackend::OutputModuleInstallTargets ()
{
for ( std::map<std::string, Module*>::const_iterator p = ProjectNode.modules.begin (); p != ProjectNode.modules.end (); ++ p )
{
const Module& module = *p->second;
if ( !module.enabled )
continue;
if ( module.install )
{
const Module& aliasedModule = GetAliasedModuleOrModule ( module );
OutputInstallTarget ( *aliasedModule.output, *module.install );
}
}
}
string
MingwBackend::GetRegistrySourceFiles ()
{
return "boot" + sSep + "bootdata" + sSep + "hivecls_" + Environment::GetArch() + ".inf "
"boot" + sSep + "bootdata" + sSep + "hivedef_" + Environment::GetArch() + ".inf "
"boot" + sSep + "bootdata" + sSep + "hiveinst_" + Environment::GetArch() + ".inf "
"boot" + sSep + "bootdata" + sSep + "hivesft_" + Environment::GetArch() + ".inf "
"boot" + sSep + "bootdata" + sSep + "hivesys_" + Environment::GetArch() + ".inf ";
}
string
MingwBackend::GetRegistryTargetFiles ()
{
string system32ConfigDirectory = "system32" + sSep + "config";
FileLocation system32 ( InstallDirectory, system32ConfigDirectory, "" );
vector<FileLocation> registry_files;
registry_files.push_back ( FileLocation ( InstallDirectory, system32ConfigDirectory, "default" ) );
registry_files.push_back ( FileLocation ( InstallDirectory, system32ConfigDirectory, "sam" ) );
registry_files.push_back ( FileLocation ( InstallDirectory, system32ConfigDirectory, "security" ) );
registry_files.push_back ( FileLocation ( InstallDirectory, system32ConfigDirectory, "software" ) );
registry_files.push_back ( FileLocation ( InstallDirectory, system32ConfigDirectory, "system" ) );
return v2s( this, registry_files, 6 );
}
void
MingwBackend::OutputRegistryInstallTarget ()
{
FileLocation system32 ( InstallDirectory, "system32" + sSep + "config", "" );
string registrySourceFiles = GetRegistrySourceFiles ();
string registryTargetFiles = GetRegistryTargetFiles ();
fprintf ( fMakefile,
"install_registry: %s\n",
registryTargetFiles.c_str () );
fprintf ( fMakefile,
"%s: %s %s $(mkhive_TARGET)\n",
registryTargetFiles.c_str (),
registrySourceFiles.c_str (),
GetFullPath ( system32 ).c_str () );
fprintf ( fMakefile,
"\t$(ECHO_MKHIVE)\n" );
fprintf ( fMakefile,
"\t$(mkhive_TARGET) boot%cbootdata %s $(ARCH) boot%cbootdata%chiveinst_$(ARCH).inf\n",
cSep, GetFullPath ( system32 ).c_str (),
cSep, cSep );
fprintf ( fMakefile,
"\n" );
}
void
MingwBackend::GenerateInstallTarget ()
{
vector<FileLocation> vInstallTargetFiles;
GetInstallTargetFiles ( vInstallTargetFiles );
string installTargetFiles = v2s ( this, vInstallTargetFiles, 5 );
string registryTargetFiles = GetRegistryTargetFiles ();
fprintf ( fMakefile,
"install: %s %s\n",
installTargetFiles.c_str (),
registryTargetFiles.c_str () );
OutputNonModuleInstallTargets ();
OutputModuleInstallTargets ();
OutputRegistryInstallTarget ();
fprintf ( fMakefile,
"\n" );
}
void
MingwBackend::GetModuleTestTargets (
vector<string>& out ) const
{
for ( std::map<std::string, Module*>::const_iterator p = ProjectNode.modules.begin (); p != ProjectNode.modules.end (); ++ p )
{
const Module& module = *p->second;
if ( !module.enabled )
continue;
if ( module.type == Test )
out.push_back ( module.name );
}
}
void
MingwBackend::GenerateTestTarget ()
{
vector<string> vTestTargets;
GetModuleTestTargets ( vTestTargets );
string testTargets = v2s ( vTestTargets, 5 );
fprintf ( fMakefile,
"test: %s\n",
testTargets.c_str () );
fprintf ( fMakefile,
"\n" );
}
void
MingwBackend::GenerateDirectoryTargets ()
{
intermediateDirectory->CreateRule ( fMakefile, "$(INTERMEDIATE)" );
outputDirectory->CreateRule ( fMakefile, "$(OUTPUT)" );
installDirectory->CreateRule ( fMakefile, "$(INSTALL)" );
}