reactos/reactos/tools/rbuild/module.cpp
Hervé Poussineau 8bfedb5a6d Remove host attribute of module element. It wasn't used and can be deduced from module type
Remove MingwBootSectorModuleHandler class
Move module specific cflags, nasmflags and linkerflags to an array. One day, we won't be forced to create a new MingwModuleHandler each time we add a module type

svn path=/trunk/; revision=36076
2008-09-09 07:12:30 +00:00

1815 lines
42 KiB
C++

/*
* Copyright (C) 2005 Casper S. Hornstrup
* Copyright (C) 2008 Hervé Poussineau
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "pch.h"
#include <assert.h>
#include "rbuild.h"
using std::string;
using std::vector;
string
Right ( const string& s, size_t n )
{
if ( n > s.size() )
return s;
return string ( &s[s.size()-n] );
}
string
Replace ( const string& s, const string& find, const string& with )
{
string ret;
const char* p = s.c_str();
while ( p )
{
const char* p2 = strstr ( p, find.c_str() );
if ( !p2 )
break;
if ( p2 > p )
ret += string ( p, p2-p );
ret += with;
p = p2 + find.size();
}
if ( *p )
ret += p;
return ret;
}
string
ChangeSeparator ( const string& s,
const char fromSeparator,
const char toSeparator )
{
string s2(s);
char* p = strchr ( &s2[0], fromSeparator );
while ( p )
{
*p++ = toSeparator;
p = strchr ( p, fromSeparator );
}
return s2;
}
string
FixSeparator ( const string& s )
{
return ChangeSeparator ( s, cBadSep, cSep );
}
string
FixSeparatorForSystemCommand ( const string& s )
{
string s2(s);
char* p = strchr ( &s2[0], DEF_CBAD_SEP );
while ( p )
{
*p++ = DEF_CSEP;
p = strchr ( p, DEF_CBAD_SEP );
}
return s2;
}
string
DosSeparator ( const string& s )
{
string s2(s);
char* p = strchr ( &s2[0], '/' );
while ( p )
{
*p++ = '\\';
p = strchr ( p, '/' );
}
return s2;
}
string
ReplaceExtension (
const string& filename,
const string& newExtension )
{
size_t index = filename.find_last_of ( '/' );
if ( index == string::npos )
index = 0;
size_t index2 = filename.find_last_of ( '\\' );
if ( index2 != string::npos && index2 > index )
index = index2;
string tmp = filename.substr( index /*, filename.size() - index*/ );
size_t ext_index = tmp.find_last_of( '.' );
if ( ext_index != string::npos )
return filename.substr ( 0, index + ext_index ) + newExtension;
return filename + newExtension;
}
string
GetSubPath (
const Project& project,
const string& location,
const string& path,
const string& att_value )
{
if ( !att_value.size() )
throw XMLInvalidBuildFileException (
location,
"<directory> tag has empty 'name' attribute" );
if ( strpbrk ( att_value.c_str (), "/\\?*:<>|" ) )
throw XMLInvalidBuildFileException (
location,
"<directory> tag has invalid characters in 'name' attribute" );
if ( !path.size() )
return att_value;
return FixSeparator(path + cSep + att_value);
}
static string
GetExtension ( const string& filename )
{
size_t index = filename.find_last_of ( '/' );
if (index == string::npos) index = 0;
string tmp = filename.substr( index, filename.size() - index );
size_t ext_index = tmp.find_last_of( '.' );
if (ext_index != string::npos)
return filename.substr ( index + ext_index, filename.size() );
return "";
}
string
GetExtension ( const FileLocation& file )
{
return GetExtension ( file.name );
}
string
NormalizeFilename ( const string& filename )
{
if ( filename == "" )
return "";
Path path;
string normalizedPath = path.Fixup ( filename, true );
string relativeNormalizedPath = path.RelativeFromWorkingDirectory ( normalizedPath );
return FixSeparator ( relativeNormalizedPath );
}
bool
GetBooleanValue ( const string& value )
{
if ( value == "1" )
return true;
else
return false;
}
string
ToLower ( string filename )
{
for ( size_t i = 1; i < filename.length (); i++ )
filename[i] = tolower ( filename[i] );
return filename;
}
IfableData::IfableData( )
: asmFiles ( 0 )
{
}
void IfableData::ExtractModules( std::vector<Module*> &modules )
{
size_t i;
for ( i = 0; i < this->modules.size (); i++ )
modules.push_back(this->modules[i]);
}
IfableData::~IfableData()
{
size_t i;
for ( i = 0; i < includes.size (); i++ )
delete includes[i];
for ( i = 0; i < defines.size (); i++ )
delete defines[i];
for ( i = 0; i < libraries.size (); i++ )
delete libraries[i];
for ( i = 0; i < properties.size (); i++ )
delete properties[i];
for ( i = 0; i < compilerFlags.size (); i++ )
delete compilerFlags[i];
for ( i = 0; i < modules.size(); i++ )
delete modules[i];
for ( i = 0; i < compilationUnits.size (); i++ )
delete compilationUnits[i];
}
void IfableData::ProcessXML ()
{
size_t i;
for ( i = 0; i < includes.size (); i++ )
includes[i]->ProcessXML ();
for ( i = 0; i < defines.size (); i++ )
defines[i]->ProcessXML ();
for ( i = 0; i < libraries.size (); i++ )
libraries[i]->ProcessXML ();
for ( i = 0; i < properties.size(); i++ )
properties[i]->ProcessXML ();
for ( i = 0; i < compilerFlags.size(); i++ )
compilerFlags[i]->ProcessXML ();
for ( i = 0; i < compilationUnits.size (); i++ )
compilationUnits[i]->ProcessXML ();
}
Module::Module ( const Project& project,
const XMLElement& moduleNode,
const string& modulePath )
: project (project),
node (moduleNode),
importLibrary (NULL),
metadata (NULL),
bootSector (NULL),
bootstrap (NULL),
autoRegister(NULL),
linkerScript (NULL),
pch (NULL),
cplusplus (false),
output (NULL),
install (NULL)
{
if ( node.name != "module" )
throw InvalidOperationException ( __FILE__,
__LINE__,
"Module created with non-<module> node" );
xmlbuildFile = FixSeparator ( Path::RelativeFromWorkingDirectory ( moduleNode.xmlFile->filename () ) );
const XMLAttribute* att = moduleNode.GetAttribute ( "name", true );
assert(att);
name = att->value;
enabled = true;
att = moduleNode.GetAttribute ( "if", false );
if ( att != NULL )
enabled = GetBooleanValue ( project.ResolveProperties ( att->value ) );
att = moduleNode.GetAttribute ( "ifnot", false );
if ( att != NULL )
enabled = !GetBooleanValue ( project.ResolveProperties ( att->value ) );
if ( !enabled && project.configuration.Verbose )
printf("Module '%s' has been disabled.\n", name.c_str () );
att = moduleNode.GetAttribute ( "type", true );
assert(att);
type = GetModuleType ( node.location, *att );
att = moduleNode.GetAttribute ( "extension", false );
if ( att != NULL )
extension = att->value;
else
extension = GetDefaultModuleExtension ();
att = moduleNode.GetAttribute ( "unicode", false );
if ( att != NULL )
{
const char* p = att->value.c_str();
if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
isUnicode = true;
else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
isUnicode = false;
else
{
throw InvalidAttributeValueException (
moduleNode.location,
"unicode",
att->value );
}
}
else
isUnicode = false;
if (isUnicode)
{
// Always define UNICODE and _UNICODE
Define* pDefine = new Define ( project, this, "UNICODE" );
non_if_data.defines.push_back ( pDefine );
pDefine = new Define ( project, this, "_UNICODE" );
non_if_data.defines.push_back ( pDefine );
}
att = moduleNode.GetAttribute ( "entrypoint", false );
if ( att != NULL )
{
if ( att->value == "" )
{
throw InvalidAttributeValueException (
moduleNode.location,
"entrypoint",
att->value );
}
entrypoint = att->value;
isDefaultEntryPoint = false;
}
else
{
entrypoint = GetDefaultModuleEntrypoint ();
isDefaultEntryPoint = true;
}
att = moduleNode.GetAttribute ( "baseaddress", false );
if ( att != NULL )
baseaddress = att->value;
else
baseaddress = GetDefaultModuleBaseaddress ();
att = moduleNode.GetAttribute ( "mangledsymbols", false );
if ( att != NULL )
{
const char* p = att->value.c_str();
if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
mangledSymbols = true;
else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
mangledSymbols = false;
else
{
throw InvalidAttributeValueException (
moduleNode.location,
"mangledsymbols",
att->value );
}
}
else
mangledSymbols = false;
att = moduleNode.GetAttribute ( "underscoresymbols", false );
if ( att != NULL )
underscoreSymbols = att->value == "true";
else
underscoreSymbols = false;
att = moduleNode.GetAttribute ( "isstartuplib", false );
if ( att != NULL )
{
const char* p = att->value.c_str();
if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
isStartupLib = true;
else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
isStartupLib = false;
else
{
throw InvalidAttributeValueException (
moduleNode.location,
"isstartuplib",
att->value );
}
}
else
isStartupLib = false;
att = moduleNode.GetAttribute ( "prefix", false );
if ( att != NULL )
prefix = att->value;
att = moduleNode.GetAttribute ( "installname", false );
if ( att != NULL )
{
const XMLAttribute* installbase = moduleNode.GetAttribute ( "installbase", false );
install = new FileLocation ( InstallDirectory,
installbase ? installbase->value : "",
att->value,
&moduleNode );
output = new FileLocation ( GetTargetDirectoryTree (),
modulePath,
att->value,
&moduleNode );
}
att = moduleNode.GetAttribute ( "output", false );
if ( att != NULL )
{
if (output != NULL)
{
printf ( "%s: WARNING: 'installname' overrides 'output' also defined for this module.\n",
moduleNode.location.c_str() );
}
else
{
output = new FileLocation ( GetTargetDirectoryTree (),
modulePath,
att->value,
&moduleNode );
}
}
/* If no one has set the output file for this module set it automatically */
if (output == NULL)
{
output = new FileLocation ( GetTargetDirectoryTree (),
modulePath,
name + extension,
&moduleNode );
}
att = moduleNode.GetAttribute ( "allowwarnings", false );
if ( att == NULL )
{
att = moduleNode.GetAttribute ( "warnings", false );
if ( att != NULL )
{
printf ( "%s: WARNING: 'warnings' attribute of <module> is deprecated, use 'allowwarnings' instead\n",
moduleNode.location.c_str() );
}
}
if ( att != NULL )
allowWarnings = att->value == "true";
else
allowWarnings = false;
att = moduleNode.GetAttribute ( "aliasof", false );
if ( type == Alias && att != NULL )
aliasedModuleName = att->value;
else
aliasedModuleName = "";
if ( type == BootProgram )
{
att = moduleNode.GetAttribute ( "payload", true );
payload = att->value;
}
if ( type == BootProgram || type == ElfExecutable )
{
att = moduleNode.GetAttribute ( "buildtype", false );
if ( att != NULL )
{
buildtype = att->value;
}
else
{
buildtype = "BOOTPROG";
}
}
att = moduleNode.GetAttribute ( "description", false );
if (att != NULL )
{
description = project.ResolveProperties(att->value);
}
else
description = "";
att = moduleNode.GetAttribute ( "lcid", false );
if (type == KeyboardLayout && att != NULL )
lcid = att->value;
else
lcid = "";
att = moduleNode.GetAttribute ( "layoutid", false );
if (type == KeyboardLayout && att != NULL )
layoutId = att->value;
else
layoutId = "";
att = moduleNode.GetAttribute ( "layoutnameresid", false );
if (type == KeyboardLayout && att != NULL )
layoutNameResId = att->value;
else
layoutNameResId = "";
SetImportLibrary ( NULL );
}
Module::~Module ()
{
size_t i;
for ( i = 0; i < invocations.size(); i++ )
delete invocations[i];
for ( i = 0; i < dependencies.size(); i++ )
delete dependencies[i];
for ( i = 0; i < compilerFlags.size(); i++ )
delete compilerFlags[i];
for ( i = 0; i < linkerFlags.size(); i++ )
delete linkerFlags[i];
for ( i = 0; i < stubbedComponents.size(); i++ )
delete stubbedComponents[i];
if ( linkerScript )
delete linkerScript;
if ( pch )
delete pch;
if ( install )
delete install;
if ( metadata )
delete metadata;
if ( bootstrap )
delete bootstrap;
if ( importLibrary )
delete importLibrary;
if ( bootSector )
delete bootSector;
if ( dependency )
delete dependency;
if ( autoRegister )
delete autoRegister;
if ( output )
delete output;
}
void
Module::ProcessXML()
{
if ( type == Alias )
{
aliasedModuleName = project.ResolveProperties ( aliasedModuleName );
if ( aliasedModuleName == name )
{
throw XMLInvalidBuildFileException (
node.location,
"module '%s' cannot link against itself",
name.c_str() );
}
const Module* m = project.LocateModule ( aliasedModuleName );
if ( !m && enabled )
{
throw XMLInvalidBuildFileException (
node.location,
"module '%s' trying to alias non-existant module '%s'",
name.c_str(),
aliasedModuleName.c_str() );
}
}
size_t i;
for ( i = 0; i < node.subElements.size(); i++ )
{
ParseContext parseContext;
ProcessXMLSubElement ( *node.subElements[i], SourceDirectory, output->relative_path, parseContext );
}
for ( i = 0; i < invocations.size(); i++ )
invocations[i]->ProcessXML ();
for ( i = 0; i < dependencies.size(); i++ )
dependencies[i]->ProcessXML ();
for ( i = 0; i < compilerFlags.size(); i++ )
compilerFlags[i]->ProcessXML();
for ( i = 0; i < linkerFlags.size(); i++ )
linkerFlags[i]->ProcessXML();
for ( i = 0; i < stubbedComponents.size(); i++ )
stubbedComponents[i]->ProcessXML();
non_if_data.ProcessXML();
if ( linkerScript )
linkerScript->ProcessXML();
if ( pch )
pch->ProcessXML();
if ( autoRegister )
autoRegister->ProcessXML();
}
void
Module::ProcessXMLSubElement ( const XMLElement& e,
DirectoryLocation directory,
const string& relative_path,
ParseContext& parseContext )
{
CompilationUnit* pOldCompilationUnit = parseContext.compilationUnit;
bool subs_invalid = false;
string subpath ( relative_path );
DirectoryLocation subdirectory = SourceDirectory;
if ( e.name == "file" && e.value.size () > 0 )
{
bool first = false;
const XMLAttribute* att = e.GetAttribute ( "first", false );
if ( att != NULL )
{
if ( !stricmp ( att->value.c_str(), "true" ) )
first = true;
else if ( stricmp ( att->value.c_str(), "false" ) )
{
throw XMLInvalidBuildFileException (
e.location,
"attribute 'first' of <file> element can only be 'true' or 'false'" );
}
}
string switches = "";
att = e.GetAttribute ( "switches", false );
if ( att != NULL )
switches = att->value;
if ( !cplusplus )
{
// check for c++ file
string ext = GetExtension ( e.value );
if ( !stricmp ( ext.c_str(), ".cpp" ) )
cplusplus = true;
else if ( !stricmp ( ext.c_str(), ".cc" ) )
cplusplus = true;
else if ( !stricmp ( ext.c_str(), ".cxx" ) )
cplusplus = true;
}
File* pFile = new File ( directory,
relative_path,
e.value,
first,
switches,
false );
if ( parseContext.compilationUnit )
parseContext.compilationUnit->AddFile ( pFile );
else
{
CompilationUnit* pCompilationUnit = new CompilationUnit ( pFile );
string ext = ToLower ( GetExtension ( e.value ) );
if ( ext == ".idl" )
{
// put .idl files at the start of the module
non_if_data.compilationUnits.insert (
non_if_data.compilationUnits.begin(),
pCompilationUnit );
}
else if ( ext == ".asm" || ext == ".s" )
{
// put .asm files at the end of the module
non_if_data.compilationUnits.push_back ( pCompilationUnit );
non_if_data.asmFiles++;
}
else
{
// put other files in the middle
non_if_data.compilationUnits.insert (
non_if_data.compilationUnits.end() - non_if_data.asmFiles,
pCompilationUnit );
}
}
non_if_data.files.push_back ( pFile );
subs_invalid = true;
}
else if ( e.name == "library" && e.value.size () )
{
Library* pLibrary = new Library ( e, *this, e.value );
non_if_data.libraries.push_back ( pLibrary );
subs_invalid = true;
}
else if ( e.name == "directory" )
{
const XMLAttribute* att = e.GetAttribute ( "name", true );
const XMLAttribute* root = e.GetAttribute ( "root", false );
assert(att);
if ( root )
{
if ( root->value == "intermediate" )
subdirectory = IntermediateDirectory;
else if ( root->value == "output" )
subdirectory = OutputDirectory;
else
{
throw InvalidAttributeValueException (
e.location,
"root",
root->value );
}
}
subpath = GetSubPath ( this->project, e.location, relative_path, att->value );
}
else if ( e.name == "include" )
{
Include* include = new Include ( project, &e, this );
non_if_data.includes.push_back ( include );
subs_invalid = true;
}
else if ( e.name == "define" )
{
Define* pDefine = new Define ( project, this, e );
non_if_data.defines.push_back ( pDefine );
subs_invalid = true;
}
else if ( e.name == "metadata" )
{
metadata = new Metadata ( e, *this );
subs_invalid = false;
}
else if ( e.name == "invoke" )
{
invocations.push_back ( new Invoke ( e, *this ) );
subs_invalid = false;
}
else if ( e.name == "dependency" )
{
dependencies.push_back ( new Dependency ( e, *this ) );
subs_invalid = true;
}
else if ( e.name == "bootsector" )
{
bootSector = new Bootsector ( e, this );
subs_invalid = true;
}
else if ( e.name == "importlibrary" )
{
if ( importLibrary )
{
throw XMLInvalidBuildFileException (
e.location,
"Only one <importlibrary> is valid per module" );
}
SetImportLibrary ( new ImportLibrary ( project, e, this ) );
subs_invalid = true;
}
else if ( e.name == "if" || e.name == "ifnot" )
{
const XMLAttribute* name;
name = e.GetAttribute ( "property", true );
assert( name );
const Property *property = project.LookupProperty( name->value );
if ( !property )
{
// Property not found
throw InvalidOperationException ( __FILE__,
__LINE__,
"Test on unknown property '%s' at %s",
name->value.c_str (), e.location.c_str () );
}
const XMLAttribute* value;
value = e.GetAttribute ( "value", true );
assert( value );
bool negate = ( e.name == "ifnot" );
bool equality = ( property->value == value->value );
if ( equality == negate )
{
// Failed, skip this element
if ( project.configuration.Verbose )
printf("Skipping 'If' at %s\n", e.location.c_str () );
return;
}
subs_invalid = false;
}
else if ( e.name == "compilerflag" )
{
CompilerFlag* pCompilerFlag = new CompilerFlag ( project, this, e );
non_if_data.compilerFlags.push_back ( pCompilerFlag );
subs_invalid = true;
}
else if ( e.name == "linkerflag" )
{
linkerFlags.push_back ( new LinkerFlag ( project, this, e ) );
subs_invalid = true;
}
else if ( e.name == "linkerscript" )
{
if ( linkerScript )
{
throw XMLInvalidBuildFileException (
e.location,
"Only one <linkerscript> is valid per module" );
}
size_t pos = e.value.find_last_of ( "/\\" );
if ( pos == string::npos )
{
linkerScript = new LinkerScript (
e, *this, new FileLocation ( SourceDirectory, relative_path, e.value, &e ) );
}
else
{
string dir = e.value.substr ( 0, pos );
string name = e.value.substr ( pos + 1);
linkerScript = new LinkerScript (
e, *this, new FileLocation ( SourceDirectory, relative_path + sSep + dir, name, &e ) );
}
subs_invalid = true;
}
else if ( e.name == "component" )
{
stubbedComponents.push_back ( new StubbedComponent ( this, e ) );
subs_invalid = false;
}
else if ( e.name == "property" )
{
throw XMLInvalidBuildFileException (
e.location,
"<property> is not a valid sub-element of <module>" );
}
else if ( e.name == "bootstrap" )
{
bootstrap = new Bootstrap ( project, this, e );
subs_invalid = true;
}
else if ( e.name == "pch" )
{
if ( pch )
{
throw XMLInvalidBuildFileException (
e.location,
"Only one <pch> is valid per module" );
}
size_t pos = e.value.find_last_of ( "/\\" );
if ( pos == string::npos )
{
pch = new PchFile (
e, *this, new FileLocation ( SourceDirectory, relative_path, e.value, &e ) );
}
else
{
string dir = e.value.substr ( 0, pos );
string name = e.value.substr ( pos + 1);
pch = new PchFile (
e, *this, new FileLocation ( SourceDirectory, relative_path + sSep + dir, name, &e ) );
}
subs_invalid = true;
}
else if ( e.name == "compilationunit" )
{
if ( project.configuration.CompilationUnitsEnabled )
{
CompilationUnit* pCompilationUnit = new CompilationUnit ( &project, this, &e );
non_if_data.compilationUnits.push_back ( pCompilationUnit );
parseContext.compilationUnit = pCompilationUnit;
}
subs_invalid = false;
}
else if ( e.name == "autoregister" )
{
if ( autoRegister != NULL)
{
throw XMLInvalidBuildFileException (
e.location,
"there can be only one <%s> element for a module",
e.name.c_str() );
}
autoRegister = new AutoRegister ( project, this, e );
subs_invalid = true;
}
if ( subs_invalid && e.subElements.size() > 0 )
{
throw XMLInvalidBuildFileException (
e.location,
"<%s> cannot have sub-elements",
e.name.c_str() );
}
for ( size_t i = 0; i < e.subElements.size (); i++ )
ProcessXMLSubElement ( *e.subElements[i], subdirectory, subpath, parseContext );
parseContext.compilationUnit = pOldCompilationUnit;
}
ModuleType
Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
{
if ( attribute.value == "buildtool" )
return BuildTool;
if ( attribute.value == "staticlibrary" )
return StaticLibrary;
if ( attribute.value == "hoststaticlibrary" )
return HostStaticLibrary;
if ( attribute.value == "objectlibrary" )
return ObjectLibrary;
if ( attribute.value == "kernel" )
return Kernel;
if ( attribute.value == "kernelmodedll" )
return KernelModeDLL;
if ( attribute.value == "kernelmodedriver" )
return KernelModeDriver;
if ( attribute.value == "nativedll" )
return NativeDLL;
if ( attribute.value == "nativecui" )
return NativeCUI;
if ( attribute.value == "keyboardlayout" )
return KeyboardLayout;
if ( attribute.value == "win32dll" )
return Win32DLL;
if ( attribute.value == "win32ocx" )
return Win32OCX;
if ( attribute.value == "win32cui" )
return Win32CUI;
if ( attribute.value == "win32gui" )
return Win32GUI;
if ( attribute.value == "win32scr" )
return Win32SCR;
if ( attribute.value == "bootloader" )
return BootLoader;
if ( attribute.value == "bootsector" )
return BootSector;
if ( attribute.value == "bootprogram" )
return BootProgram;
if ( attribute.value == "iso" )
return Iso;
if ( attribute.value == "liveiso" )
return LiveIso;
if ( attribute.value == "isoregtest" )
return IsoRegTest;
if ( attribute.value == "liveisoregtest" )
return LiveIsoRegTest;
if ( attribute.value == "test" )
return Test;
if ( attribute.value == "rpcserver" )
return RpcServer;
if ( attribute.value == "rpcclient" )
return RpcClient;
if ( attribute.value == "rpcproxy" )
return RpcProxy;
if ( attribute.value == "alias" )
return Alias;
if ( attribute.value == "idlheader" )
return IdlHeader;
if ( attribute.value == "embeddedtypelib" )
return EmbeddedTypeLib;
if ( attribute.value == "elfexecutable" )
return ElfExecutable;
if ( attribute.value == "cabinet" )
return Cabinet;
if ( attribute.value == "messageheader" )
return MessageHeader;
throw InvalidAttributeValueException ( location,
attribute.name,
attribute.value );
}
DirectoryLocation
Module::GetTargetDirectoryTree () const
{
switch ( type )
{
case Kernel:
case KernelModeDLL:
case KeyboardLayout:
case NativeDLL:
case Win32DLL:
case Win32OCX:
case KernelModeDriver:
case NativeCUI:
case Win32CUI:
case Test:
case Win32SCR:
case Win32GUI:
case BuildTool:
case BootLoader:
case BootSector:
case BootProgram:
case Iso:
case LiveIso:
case IsoRegTest:
case LiveIsoRegTest:
case ElfExecutable:
case Cabinet:
return OutputDirectory;
case EmbeddedTypeLib:
case StaticLibrary:
case HostStaticLibrary:
case ObjectLibrary:
case RpcServer:
case RpcClient:
case RpcProxy:
case Alias:
case IdlHeader:
case MessageHeader:
return IntermediateDirectory;
case TypeDontCare:
break;
}
throw InvalidOperationException ( __FILE__,
__LINE__,
"Invalid module type %d.",
type );
}
string
Module::GetDefaultModuleExtension () const
{
switch (type)
{
case BuildTool:
return ExePostfix;
case BootProgram:
case StaticLibrary:
case HostStaticLibrary:
return ".a";
case ObjectLibrary:
return ".o";
case Kernel:
case NativeCUI:
case Win32CUI:
case Win32GUI:
return ".exe";
case Win32SCR:
return ".scr";
case KernelModeDLL:
case NativeDLL:
case KeyboardLayout:
case Win32DLL:
return ".dll";
case Win32OCX:
return ".ocx";
case KernelModeDriver:
case BootLoader:
return ".sys";
case Cabinet:
return ".cab";
case BootSector:
return ".o";
case Iso:
case LiveIso:
case IsoRegTest:
case LiveIsoRegTest:
return ".iso";
case Test:
return ".exe";
case RpcServer:
case RpcClient:
case RpcProxy:
return ".o";
case Alias:
case ElfExecutable:
case IdlHeader:
case MessageHeader:
return "";
case EmbeddedTypeLib:
return ".tlb";
case TypeDontCare:
break;
}
throw InvalidOperationException ( __FILE__,
__LINE__ );
}
string
Module::GetDefaultModuleEntrypoint () const
{
switch ( type )
{
case Kernel:
return "KiSystemStartup";
case KeyboardLayout:
case KernelModeDLL:
case KernelModeDriver:
if (Environment::GetArch() == "arm") return "DriverEntry";
return "DriverEntry@8";
case NativeDLL:
if (Environment::GetArch() == "arm") return "DllMainCRTStartup";
return "DllMainCRTStartup@12";
case NativeCUI:
if (Environment::GetArch() == "arm") return "NtProcessStartup";
return "NtProcessStartup@4";
case Win32DLL:
case Win32OCX:
if (Environment::GetArch() == "arm") return "DllMain";
return "DllMain@12";
case Win32CUI:
case Test:
if ( isUnicode )
return "wmainCRTStartup";
else
return "mainCRTStartup";
case Win32SCR:
case Win32GUI:
if ( isUnicode )
return "wWinMainCRTStartup";
else
return "WinMainCRTStartup";
case BuildTool:
case StaticLibrary:
case HostStaticLibrary:
case ObjectLibrary:
case BootLoader:
case BootSector:
case Iso:
case LiveIso:
case IsoRegTest:
case LiveIsoRegTest:
case RpcServer:
case RpcClient:
case RpcProxy:
case Alias:
case BootProgram:
case IdlHeader:
case MessageHeader:
case ElfExecutable:
case EmbeddedTypeLib:
case Cabinet:
return "";
case TypeDontCare:
break;
}
throw InvalidOperationException ( __FILE__,
__LINE__ );
}
string
Module::GetDefaultModuleBaseaddress () const
{
switch ( type )
{
case Kernel:
return "0x80800000";
case Win32DLL:
case Win32OCX:
return "0x10000000";
case NativeDLL:
case NativeCUI:
case Win32CUI:
case Test:
return "0x00400000";
case Win32SCR:
case Win32GUI:
return "0x00400000";
case KeyboardLayout:
case KernelModeDLL:
case KernelModeDriver:
return "0x00010000";
case ElfExecutable:
return "0xe00000";
case BuildTool:
case StaticLibrary:
case HostStaticLibrary:
case ObjectLibrary:
case BootLoader:
case BootSector:
case Iso:
case LiveIso:
case IsoRegTest:
case LiveIsoRegTest:
case RpcServer:
case RpcClient:
case RpcProxy:
case Alias:
case BootProgram:
case IdlHeader:
case MessageHeader:
case EmbeddedTypeLib:
case Cabinet:
return "";
case TypeDontCare:
break;
}
throw InvalidOperationException ( __FILE__,
__LINE__ );
}
bool
Module::HasImportLibrary () const
{
return importLibrary != NULL && type != StaticLibrary && type != HostStaticLibrary;
}
bool
Module::IsDLL () const
{
switch ( type )
{
case Kernel:
case KernelModeDLL:
case NativeDLL:
case KeyboardLayout:
case Win32DLL:
case Win32OCX:
case KernelModeDriver:
return true;
case NativeCUI:
case Win32CUI:
case Test:
case Win32SCR:
case Win32GUI:
case BuildTool:
case StaticLibrary:
case HostStaticLibrary:
case ObjectLibrary:
case BootLoader:
case BootSector:
case BootProgram:
case Iso:
case LiveIso:
case IsoRegTest:
case LiveIsoRegTest:
case RpcServer:
case RpcClient:
case RpcProxy:
case Alias:
case IdlHeader:
case MessageHeader:
case EmbeddedTypeLib:
case ElfExecutable:
case Cabinet:
return false;
case TypeDontCare:
break;
}
throw InvalidOperationException ( __FILE__,
__LINE__ );
}
string
Module::GetPathWithPrefix ( const string& prefix ) const
{
return output->relative_path + cSep + prefix + output->name;
}
string
Module::GetPathToBaseDir () const
{
string temp_path = output->relative_path;
string result = "..\\";
while(temp_path.find ('\\') != string::npos)
{
temp_path.erase (0, temp_path.find('\\')+1);
result += "..\\";
}
return result;
}
string
Module::GetInvocationTarget ( const int index ) const
{
return ssprintf ( "%s_invoke_%d",
name.c_str (),
index );
}
string
Module::GetEntryPoint(bool leadingUnderscore) const
{
string result = "";
if (entrypoint == "0" || entrypoint == "0x0")
return "0";
if (leadingUnderscore)
result = "_";
result += entrypoint;
return result;
}
bool
Module::HasFileWithExtension (
const IfableData& data,
const std::string& extension ) const
{
size_t i;
for ( i = 0; i < data.compilationUnits.size (); i++ )
{
CompilationUnit* compilationUnit = data.compilationUnits[i];
if ( compilationUnit->HasFileWithExtension ( extension ) )
return true;
}
return false;
}
void
Module::InvokeModule () const
{
for ( size_t i = 0; i < invocations.size (); i++ )
{
Invoke& invoke = *invocations[i];
string command = FixSeparatorForSystemCommand(invoke.invokeModule->output->relative_path + "/" + invoke.invokeModule->output->name ) + " " + invoke.GetParameters ();
printf ( "Executing '%s'\n\n", command.c_str () );
int exitcode = system ( command.c_str () );
if ( exitcode != 0 )
throw InvocationFailedException ( command,
exitcode );
}
}
void
Module::SetImportLibrary ( ImportLibrary* importLibrary )
{
this->importLibrary = importLibrary;
dependency = new FileLocation ( HasImportLibrary () ? IntermediateDirectory : output->directory,
output->relative_path,
HasImportLibrary () ? "lib" + name + ".a" : output->name );
}
File::File ( DirectoryLocation directory,
const string& relative_path,
const string& name,
bool _first,
const string& _switches,
bool _isPreCompiledHeader )
: file ( directory, relative_path, name ),
first(_first),
switches(_switches),
isPreCompiledHeader(_isPreCompiledHeader)
{
}
void
File::ProcessXML()
{
}
std::string File::GetFullPath () const
{
string directory ( "" );
switch ( file.directory )
{
case SourceDirectory:
break;
case IntermediateDirectory:
directory = Environment::GetIntermediatePath () + sSep;
break;
default:
throw InvalidOperationException ( __FILE__,
__LINE__,
"Invalid directory %d.",
file.directory );
}
if ( file.relative_path.length () > 0 )
directory += file.relative_path + sSep;
return directory + file.name;
}
Library::Library ( const XMLElement& _node,
const Module& _module,
const string& _name )
: node(&_node),
module(_module),
name(_name),
importedModule(_module.project.LocateModule(_name))
{
if ( module.name == name )
{
throw XMLInvalidBuildFileException (
node->location,
"module '%s' cannot link against itself",
name.c_str() );
}
if ( !importedModule )
{
throw XMLInvalidBuildFileException (
node->location,
"module '%s' trying to import non-existant module '%s'",
module.name.c_str(),
name.c_str() );
}
}
Library::Library ( const Module& _module,
const string& _name )
: node(NULL),
module(_module),
name(_name),
importedModule(_module.project.LocateModule(_name))
{
}
void
Library::ProcessXML()
{
if ( node && !module.project.LocateModule ( name ) )
{
throw XMLInvalidBuildFileException (
node->location,
"module '%s' is trying to link against non-existant module '%s'",
module.name.c_str(),
name.c_str() );
}
}
Invoke::Invoke ( const XMLElement& _node,
const Module& _module )
: node (_node),
module (_module)
{
}
void
Invoke::ProcessXML()
{
const XMLAttribute* att = node.GetAttribute ( "module", false );
if (att == NULL)
invokeModule = &module;
else
{
invokeModule = module.project.LocateModule ( att->value );
if ( invokeModule == NULL )
{
throw XMLInvalidBuildFileException (
node.location,
"module '%s' is trying to invoke non-existant module '%s'",
module.name.c_str(),
att->value.c_str() );
}
}
for ( size_t i = 0; i < node.subElements.size (); i++ )
ProcessXMLSubElement ( *node.subElements[i] );
}
void
Invoke::ProcessXMLSubElement ( const XMLElement& e )
{
bool subs_invalid = false;
if ( e.name == "input" )
{
for ( size_t i = 0; i < e.subElements.size (); i++ )
ProcessXMLSubElementInput ( *e.subElements[i] );
}
else if ( e.name == "output" )
{
for ( size_t i = 0; i < e.subElements.size (); i++ )
ProcessXMLSubElementOutput ( *e.subElements[i] );
}
if ( subs_invalid && e.subElements.size() > 0 )
{
throw XMLInvalidBuildFileException (
e.location,
"<%s> cannot have sub-elements",
e.name.c_str() );
}
}
void
Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
{
bool subs_invalid = false;
if ( e.name == "inputfile" && e.value.size () > 0 )
{
input.push_back ( new InvokeFile (
e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
subs_invalid = true;
}
if ( subs_invalid && e.subElements.size() > 0 )
{
throw XMLInvalidBuildFileException (
e.location,
"<%s> cannot have sub-elements",
e.name.c_str() );
}
}
void
Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
{
bool subs_invalid = false;
if ( e.name == "outputfile" && e.value.size () > 0 )
{
output.push_back ( new InvokeFile (
e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
subs_invalid = true;
}
if ( subs_invalid && e.subElements.size() > 0 )
{
throw XMLInvalidBuildFileException (
e.location,
"<%s> cannot have sub-elements",
e.name.c_str() );
}
}
void
Invoke::GetTargets ( string_list& targets ) const
{
for ( size_t i = 0; i < output.size (); i++ )
{
InvokeFile& file = *output[i];
targets.push_back ( NormalizeFilename ( file.name ) );
}
}
string
Invoke::GetParameters () const
{
string parameters ( "" );
size_t i;
for ( i = 0; i < output.size (); i++ )
{
if ( parameters.length () > 0)
parameters += " ";
InvokeFile& invokeFile = *output[i];
if ( invokeFile.switches.length () > 0 )
{
parameters += invokeFile.switches + " ";
}
parameters += invokeFile.name;
}
for ( i = 0; i < input.size (); i++ )
{
if ( parameters.length () > 0 )
parameters += " ";
InvokeFile& invokeFile = *input[i];
if ( invokeFile.switches.length () > 0 )
{
parameters += invokeFile.switches;
parameters += " ";
}
parameters += invokeFile.name ;
}
return parameters;
}
InvokeFile::InvokeFile ( const XMLElement& _node,
const string& _name )
: node (_node),
name (_name)
{
const XMLAttribute* att = _node.GetAttribute ( "switches", false );
if (att != NULL)
switches = att->value;
else
switches = "";
}
void
InvokeFile::ProcessXML()
{
}
Dependency::Dependency ( const XMLElement& _node,
const Module& _module )
: node (_node),
module (_module),
dependencyModule (NULL)
{
}
void
Dependency::ProcessXML()
{
dependencyModule = module.project.LocateModule ( node.value );
if ( dependencyModule == NULL )
{
throw XMLInvalidBuildFileException (
node.location,
"module '%s' depend on non-existant module '%s'",
module.name.c_str(),
node.value.c_str() );
}
}
Bootsector::Bootsector ( const XMLElement& _node,
const Module* _module )
: node (_node),
module (_module),
bootSectorModule (NULL)
{
if ( !IsSupportedModuleType ( module->type ) )
{
throw XMLInvalidBuildFileException (
node.location,
"<bootsector> is not applicable for this module type." );
}
bootSectorModule = module->project.LocateModule ( node.value );
if ( bootSectorModule == NULL )
{
throw XMLInvalidBuildFileException (
node.location,
"module '%s' depend on non-existant module '%s'",
module->name.c_str(),
node.value.c_str() );
}
if (bootSectorModule->type != BootSector)
{
throw XMLInvalidBuildFileException (
node.location,
"module '%s' is referencing non BootSector module '%s'",
module->name.c_str(),
node.value.c_str() );
}
}
void
Bootsector::ProcessXML()
{
}
bool
Bootsector::IsSupportedModuleType ( ModuleType type )
{
if ( type == Iso ||
type == LiveIso ||
type == IsoRegTest ||
type == LiveIsoRegTest )
{
return true;
}
return false;
}
Metadata::Metadata ( const XMLElement& _node,
const Module& _module )
: node (_node),
module (_module)
{
/* The module name */
const XMLAttribute* att = _node.GetAttribute ( "name", false );
if (att != NULL)
name = att->value;
else
name = module.name;
/* The module description */
att = _node.GetAttribute ( "description", false );
if (att != NULL)
description = att->value;
else
description = "";
/* The module version */
att = _node.GetAttribute ( "version", false );
if (att != NULL)
version = att->value;
else
version = "";
/* The module copyright */
att = _node.GetAttribute ( "copyright", false );
if (att != NULL)
copyright = att->value;
else
copyright = "";
att = _node.GetAttribute ( "url", false );
if (att != NULL)
url = att->value;
else
url = "";
/* When was this module updated */
att = _node.GetAttribute ( "date", false );
if (att != NULL)
date = att->value;
else
date = "?";
/* When was this module updated */
att = _node.GetAttribute ( "owner", false );
if (att != NULL)
owner = att->value;
else
owner = "ReactOS";
}
ImportLibrary::~ImportLibrary ()
{
delete source;
}
ImportLibrary::ImportLibrary ( const Project& project,
const XMLElement& node,
const Module* module )
: XmlNode ( project, node ),
module (module)
{
DirectoryLocation directory = SourceDirectory;
const Module* base = module;
const XMLAttribute* dllname = node.GetAttribute ( "dllname", false );
const XMLAttribute* definition = node.GetAttribute ( "definition", true );
assert ( definition );
string relative_path;
const XMLAttribute* att = node.GetAttribute ( "base", false );
if ( att )
{
base = project.LocateModule ( att->value );
if ( !base )
throw XMLInvalidBuildFileException (
node.location,
"<importlibrary> attribute 'base' references non-existant module '%s'",
att->value.c_str() );
}
if ( base )
{
relative_path = base->output->relative_path;
if ( node.value.length () > 0 && node.value != "." )
relative_path += sSep + node.value;
}
else
relative_path = node.value;
att = node.GetAttribute ( "root", false );
if ( att )
{
if ( att->value == "intermediate" )
directory = IntermediateDirectory;
else
throw InvalidAttributeValueException ( node.location,
"root",
att->value );
}
else
{
size_t index = definition->value.rfind ( ".spec.def" );
if ( index != string::npos )
directory = IntermediateDirectory;
}
if ( dllname )
this->dllname = dllname->value;
else if ( module->type == StaticLibrary || module->type == HostStaticLibrary )
throw XMLInvalidBuildFileException (
node.location,
"<importlibrary> dllname attribute required." );
size_t index = definition->value.find_last_of ( "/\\" );
if ( index == string::npos )
{
source = new FileLocation ( directory,
base->output->relative_path,
definition->value,
&node );
}
else
{
string dir = definition->value.substr ( 0, index );
string name = definition->value.substr ( index + 1);
source = new FileLocation ( directory,
NormalizeFilename ( base->output->relative_path + sSep + dir ),
name,
&node );
}
}
Property::Property ( const XMLElement& node_,
const Project& project_,
const Module* module_ )
: project(project_), module(module_)
{
const XMLAttribute* att;
att = node_.GetAttribute ( "name", true );
assert(att);
name = project.ResolveProperties ( att->value );
att = node_.GetAttribute ( "value", true );
assert(att);
value = att->value;
att = node_.GetAttribute ( "internal", false );
if ( att != NULL )
{
const char* p = att->value.c_str();
if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
isInternal = true;
else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
isInternal = false;
else
{
throw InvalidAttributeValueException (
node_.location,
"internal",
att->value );
}
}
else
isInternal = false;
}
Property::Property ( const Project& project_,
const Module* module_,
const std::string& name_,
const std::string& value_ )
: project(project_), module(module_), name(name_), value(value_)
{
}
void
Property::ProcessXML()
{
}
PchFile::PchFile (
const XMLElement& node_,
const Module& module_,
const FileLocation *file_ )
: node(node_), module(module_), file(file_)
{
}
PchFile::~PchFile()
{
delete file;
}
void
PchFile::ProcessXML()
{
}