-#include "pch.h"\r
-#include <assert.h>\r
-\r
-#include "rbuild.h"\r
-\r
-using std::string;\r
-using std::vector;\r
-\r
-string\r
-FixSeparator ( const string& s )\r
-{\r
- string s2(s);\r
- char* p = strchr ( &s2[0], CBAD_SEP );\r
- while ( p )\r
- {\r
- *p++ = CSEP;\r
- p = strchr ( p, CBAD_SEP );\r
- }\r
- return s2;\r
-}\r
-\r
-string\r
-GetSubPath (\r
- const string& location,\r
- const string& path,\r
- const string& att_value )\r
-{\r
- if ( !att_value.size() )\r
- throw InvalidBuildFileException (\r
- location,\r
- "<directory> tag has empty 'name' attribute" );\r
- if ( strpbrk ( att_value.c_str (), "/\\?*:<>|" ) )\r
- throw InvalidBuildFileException (\r
- location,\r
- "<directory> tag has invalid characters in 'name' attribute" );\r
- if ( !path.size() )\r
- return att_value;\r
- return FixSeparator(path + CSEP + att_value);\r
-}\r
-\r
-string\r
-GetExtension ( const string& filename )\r
-{\r
- size_t index = filename.find_last_of ( '/' );\r
- if (index == string::npos) index = 0;\r
- string tmp = filename.substr( index, filename.size() - index );\r
- size_t ext_index = tmp.find_last_of( '.' );\r
- if (ext_index != string::npos) \r
- return filename.substr ( index + ext_index, filename.size() );\r
- return "";\r
-}\r
-\r
-string\r
-GetDirectory ( const string& filename )\r
-{\r
- size_t index = filename.find_last_of ( CSEP );\r
- if ( index == string::npos )\r
- return filename;\r
- else\r
- return filename.substr ( 0, index );\r
-}\r
-\r
-string\r
-NormalizeFilename ( const string& filename )\r
-{\r
- Path path;\r
- string normalizedPath = path.Fixup ( filename, true );\r
- string relativeNormalizedPath = path.RelativeFromWorkingDirectory ( normalizedPath );\r
- return FixSeparator ( relativeNormalizedPath );\r
-}\r
-\r
-IfableData::~IfableData()\r
-{\r
- size_t i;\r
- for ( i = 0; i < files.size(); i++ )\r
- delete files[i];\r
- for ( i = 0; i < includes.size(); i++ )\r
- delete includes[i];\r
- for ( i = 0; i < defines.size(); i++ )\r
- delete defines[i];\r
- for ( i = 0; i < libraries.size(); i++ )\r
- delete libraries[i];\r
- for ( i = 0; i < properties.size(); i++ )\r
- delete properties[i];\r
- for ( i = 0; i < ifs.size(); i++ )\r
- delete ifs[i];\r
-}\r
-\r
-void IfableData::ProcessXML ()\r
-{\r
- size_t i;\r
- for ( i = 0; i < files.size (); i++ )\r
- files[i]->ProcessXML ();\r
- for ( i = 0; i < includes.size (); i++ )\r
- includes[i]->ProcessXML ();\r
- for ( i = 0; i < defines.size (); i++ )\r
- defines[i]->ProcessXML ();\r
- for ( i = 0; i < libraries.size (); i++ )\r
- libraries[i]->ProcessXML ();\r
- for ( i = 0; i < properties.size(); i++ )\r
- properties[i]->ProcessXML ();\r
- for ( i = 0; i < ifs.size (); i++ )\r
- ifs[i]->ProcessXML ();\r
-}\r
-\r
-Module::Module ( const Project& project,\r
- const XMLElement& moduleNode,\r
- const string& modulePath )\r
- : project (project),\r
- node (moduleNode),\r
- importLibrary (NULL),\r
- bootstrap (NULL),\r
- pch (NULL),\r
- cplusplus (false),\r
- host (HostDefault)\r
-{\r
- if ( node.name != "module" )\r
- throw Exception ( "internal tool error: Module created with non-<module> node" );\r
-\r
- path = FixSeparator ( modulePath );\r
-\r
- const XMLAttribute* att = moduleNode.GetAttribute ( "name", true );\r
- assert(att);\r
- name = att->value;\r
-\r
- att = moduleNode.GetAttribute ( "type", true );\r
- assert(att);\r
- type = GetModuleType ( node.location, *att );\r
-\r
- att = moduleNode.GetAttribute ( "extension", false );\r
- if ( att != NULL )\r
- extension = att->value;\r
- else\r
- extension = GetDefaultModuleExtension ();\r
-\r
- att = moduleNode.GetAttribute ( "entrypoint", false );\r
- if ( att != NULL )\r
- entrypoint = att->value;\r
- else\r
- entrypoint = GetDefaultModuleEntrypoint ();\r
-\r
- att = moduleNode.GetAttribute ( "baseaddress", false );\r
- if ( att != NULL )\r
- baseaddress = att->value;\r
- else\r
- baseaddress = GetDefaultModuleBaseaddress ();\r
-\r
- att = moduleNode.GetAttribute ( "mangledsymbols", false );\r
- if ( att != NULL )\r
- {\r
- const char* p = att->value.c_str();\r
- if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )\r
- mangledSymbols = true;\r
- else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )\r
- mangledSymbols = false;\r
- else\r
- {\r
- throw InvalidAttributeValueException (\r
- moduleNode.location,\r
- "mangledsymbols",\r
- att->value );\r
- }\r
- }\r
- else\r
- mangledSymbols = false;\r
-\r
- att = moduleNode.GetAttribute ( "host", false );\r
- if ( att != NULL )\r
- {\r
- const char* p = att->value.c_str();\r
- if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )\r
- host = HostTrue;\r
- else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )\r
- host = HostFalse;\r
- else\r
- {\r
- throw InvalidAttributeValueException (\r
- moduleNode.location,\r
- "host",\r
- att->value );\r
- }\r
- }\r
-\r
- att = moduleNode.GetAttribute ( "prefix", false );\r
- if ( att != NULL )\r
- prefix = att->value;\r
-}\r
-\r
-Module::~Module ()\r
-{\r
- size_t i;\r
- for ( i = 0; i < invocations.size(); i++ )\r
- delete invocations[i];\r
- for ( i = 0; i < dependencies.size(); i++ )\r
- delete dependencies[i];\r
- for ( i = 0; i < compilerFlags.size(); i++ )\r
- delete compilerFlags[i];\r
- for ( i = 0; i < linkerFlags.size(); i++ )\r
- delete linkerFlags[i];\r
- if ( pch )\r
- delete pch;\r
-}\r
-\r
-void\r
-Module::ProcessXML()\r
-{\r
- size_t i;\r
- for ( i = 0; i < node.subElements.size(); i++ )\r
- ProcessXMLSubElement ( *node.subElements[i], path );\r
- for ( i = 0; i < invocations.size(); i++ )\r
- invocations[i]->ProcessXML ();\r
- for ( i = 0; i < dependencies.size(); i++ )\r
- dependencies[i]->ProcessXML ();\r
- for ( i = 0; i < compilerFlags.size(); i++ )\r
- compilerFlags[i]->ProcessXML();\r
- for ( i = 0; i < linkerFlags.size(); i++ )\r
- linkerFlags[i]->ProcessXML();\r
- non_if_data.ProcessXML();\r
- if ( pch )\r
- pch->ProcessXML();\r
-}\r
-\r
-void\r
-Module::ProcessXMLSubElement ( const XMLElement& e,\r
- const string& path,\r
- If* pIf /*= NULL*/ )\r
-{\r
- bool subs_invalid = false;\r
- string subpath ( path );\r
- if ( e.name == "file" && e.value.size () > 0 )\r
- {\r
- bool first = false;\r
- const XMLAttribute* att = e.GetAttribute ( "first", false );\r
- if ( att )\r
- {\r
- if ( !stricmp ( att->value.c_str(), "true" ) )\r
- first = true;\r
- else if ( stricmp ( att->value.c_str(), "false" ) )\r
- throw InvalidBuildFileException (\r
- e.location,\r
- "attribute 'first' of <file> element can only be 'true' or 'false'" );\r
- }\r
- if ( !cplusplus )\r
- {\r
- // check for c++ file\r
- string ext = GetExtension ( e.value );\r
- if ( !stricmp ( ext.c_str(), ".cpp" ) )\r
- cplusplus = true;\r
- else if ( !stricmp ( ext.c_str(), ".cc" ) )\r
- cplusplus = true;\r
- else if ( !stricmp ( ext.c_str(), ".cxx" ) )\r
- cplusplus = true;\r
- }\r
- File* pFile = new File ( FixSeparator ( path + CSEP + e.value ), first );\r
- if ( pIf )\r
- pIf->data.files.push_back ( pFile );\r
- else\r
- non_if_data.files.push_back ( pFile );\r
- subs_invalid = true;\r
- }\r
- else if ( e.name == "library" && e.value.size () )\r
- {\r
- Library* pLibrary = new Library ( e, *this, e.value );\r
- if ( pIf )\r
- pIf->data.libraries.push_back ( pLibrary );\r
- else\r
- non_if_data.libraries.push_back ( pLibrary );\r
- subs_invalid = true;\r
- }\r
- else if ( e.name == "directory" )\r
- {\r
- const XMLAttribute* att = e.GetAttribute ( "name", true );\r
- assert(att);\r
- subpath = GetSubPath ( e.location, path, att->value );\r
- }\r
- else if ( e.name == "include" )\r
- {\r
- Include* include = new Include ( project, this, e );\r
- if ( pIf )\r
- pIf->data.includes.push_back ( include );\r
- else\r
- non_if_data.includes.push_back ( include );\r
- subs_invalid = true;\r
- }\r
- else if ( e.name == "define" )\r
- {\r
- Define* pDefine = new Define ( project, this, e );\r
- if ( pIf )\r
- pIf->data.defines.push_back ( pDefine );\r
- else\r
- non_if_data.defines.push_back ( pDefine );\r
- subs_invalid = true;\r
- }\r
- else if ( e.name == "invoke" )\r
- {\r
- if ( pIf )\r
- throw InvalidBuildFileException (\r
- e.location,\r
- "<invoke> is not a valid sub-element of <if>" );\r
- invocations.push_back ( new Invoke ( e, *this ) );\r
- subs_invalid = false;\r
- }\r
- else if ( e.name == "dependency" )\r
- {\r
- if ( pIf )\r
- throw InvalidBuildFileException (\r
- e.location,\r
- "<dependency> is not a valid sub-element of <if>" );\r
- dependencies.push_back ( new Dependency ( e, *this ) );\r
- subs_invalid = true;\r
- }\r
- else if ( e.name == "importlibrary" )\r
- {\r
- if ( pIf )\r
- throw InvalidBuildFileException (\r
- e.location,\r
- "<importlibrary> is not a valid sub-element of <if>" );\r
- if ( importLibrary )\r
- throw InvalidBuildFileException (\r
- e.location,\r
- "Only one <importlibrary> is valid per module" );\r
- importLibrary = new ImportLibrary ( e, *this );\r
- subs_invalid = true;\r
- }\r
- else if ( e.name == "if" )\r
- {\r
- If* pOldIf = pIf;\r
- pIf = new If ( e, project, this );\r
- if ( pOldIf )\r
- pOldIf->data.ifs.push_back ( pIf );\r
- else\r
- non_if_data.ifs.push_back ( pIf );\r
- subs_invalid = false;\r
- }\r
- else if ( e.name == "compilerflag" )\r
- {\r
- compilerFlags.push_back ( new CompilerFlag ( project, this, e ) );\r
- subs_invalid = true;\r
- }\r
- else if ( e.name == "linkerflag" )\r
- {\r
- linkerFlags.push_back ( new LinkerFlag ( project, this, e ) );\r
- subs_invalid = true;\r
- }\r
- else if ( e.name == "property" )\r
- {\r
- throw InvalidBuildFileException (\r
- e.location,\r
- "<property> is not a valid sub-element of <module>" );\r
- }\r
- else if ( e.name == "bootstrap" )\r
- {\r
- bootstrap = new Bootstrap ( project, this, e );\r
- subs_invalid = true;\r
- }\r
- else if ( e.name == "pch" )\r
- {\r
- if ( pIf )\r
- throw InvalidBuildFileException (\r
- e.location,\r
- "<pch> is not a valid sub-element of <if>" );\r
- if ( pch )\r
- throw InvalidBuildFileException (\r
- e.location,\r
- "Only one <pch> is valid per module" );\r
- pch = new PchFile (\r
- e, *this, FixSeparator ( path + CSEP + e.value ) );\r
- subs_invalid = true;\r
- }\r
- if ( subs_invalid && e.subElements.size() > 0 )\r
- throw InvalidBuildFileException (\r
- e.location,\r
- "<%s> cannot have sub-elements",\r
- e.name.c_str() );\r
- for ( size_t i = 0; i < e.subElements.size (); i++ )\r
- ProcessXMLSubElement ( *e.subElements[i], subpath, pIf );\r
-}\r
-\r
-ModuleType\r
-Module::GetModuleType ( const string& location, const XMLAttribute& attribute )\r
-{\r
- if ( attribute.value == "buildtool" )\r
- return BuildTool;\r
- if ( attribute.value == "staticlibrary" )\r
- return StaticLibrary;\r
- if ( attribute.value == "objectlibrary" )\r
- return ObjectLibrary;\r
- if ( attribute.value == "kernel" )\r
- return Kernel;\r
- if ( attribute.value == "kernelmodedll" )\r
- return KernelModeDLL;\r
- if ( attribute.value == "kernelmodedriver" )\r
- return KernelModeDriver;\r
- if ( attribute.value == "nativedll" )\r
- return NativeDLL;\r
- if ( attribute.value == "nativecui" )\r
- return NativeCUI;\r
- if ( attribute.value == "win32dll" )\r
- return Win32DLL;\r
- if ( attribute.value == "win32cui" )\r
- return Win32CUI;\r
- if ( attribute.value == "win32gui" )\r
- return Win32GUI;\r
- if ( attribute.value == "bootloader" )\r
- return BootLoader;\r
- if ( attribute.value == "bootsector" )\r
- return BootSector;\r
- if ( attribute.value == "iso" )\r
- return Iso;\r
- throw InvalidAttributeValueException ( location,\r
- attribute.name,\r
- attribute.value );\r
-}\r
-\r
-string\r
-Module::GetDefaultModuleExtension () const\r
-{\r
- switch (type)\r
- {\r
- case BuildTool:\r
- return EXEPOSTFIX;\r
- case StaticLibrary:\r
- return ".a";\r
- case ObjectLibrary:\r
- return ".o";\r
- case Kernel:\r
- case NativeCUI:\r
- case Win32CUI:\r
- case Win32GUI:\r
- return ".exe";\r
- case KernelModeDLL:\r
- case NativeDLL:\r
- case Win32DLL:\r
- return ".dll";\r
- case KernelModeDriver:\r
- case BootLoader:\r
- return ".sys";\r
- case BootSector:\r
- return ".o";\r
- case Iso:\r
- return ".iso";\r
- }\r
- throw InvalidOperationException ( __FILE__,\r
- __LINE__ );\r
-}\r
-\r
-string\r
-Module::GetDefaultModuleEntrypoint () const\r
-{\r
- switch (type)\r
- {\r
- case Kernel:\r
- return "_NtProcessStartup";\r
- case KernelModeDLL:\r
- return "_DriverEntry@8";\r
- case NativeDLL:\r
- return "_DllMainCRTStartup@12";\r
- case NativeCUI:\r
- return "_NtProcessStartup@4";\r
- case Win32DLL:\r
- return "_DllMain@12";\r
- case Win32CUI:\r
- return "_mainCRTStartup";\r
- case Win32GUI:\r
- return "_WinMainCRTStartup";\r
- case KernelModeDriver:\r
- return "_DriverEntry@8";\r
- case BuildTool:\r
- case StaticLibrary:\r
- case ObjectLibrary:\r
- case BootLoader:\r
- case BootSector:\r
- case Iso:\r
- return "";\r
- }\r
- throw InvalidOperationException ( __FILE__,\r
- __LINE__ );\r
-}\r
-\r
-string\r
-Module::GetDefaultModuleBaseaddress () const\r
-{\r
- switch (type)\r
- {\r
- case Kernel:\r
- return "0xc0000000";\r
- case KernelModeDLL:\r
- return "0x10000";\r
- case NativeDLL:\r
- return "0x10000";\r
- case NativeCUI:\r
- return "0x10000";\r
- case Win32DLL:\r
- return "0x10000";\r
- case Win32CUI:\r
- return "0x00400000";\r
- case Win32GUI:\r
- return "0x00400000";\r
- case KernelModeDriver:\r
- return "0x10000";\r
- case BuildTool:\r
- case StaticLibrary:\r
- case ObjectLibrary:\r
- case BootLoader:\r
- case BootSector:\r
- case Iso:\r
- return "";\r
- }\r
- throw InvalidOperationException ( __FILE__,\r
- __LINE__ );\r
-}\r
-\r
-bool\r
-Module::HasImportLibrary () const\r
-{\r
- return importLibrary != NULL;\r
-}\r
-\r
-string\r
-Module::GetTargetName () const\r
-{\r
- return name + extension;\r
-}\r
-\r
-string\r
-Module::GetDependencyPath () const\r
-{\r
- if ( HasImportLibrary () )\r
- {\r
- return ssprintf ( "dk%cnkm%clib%clib%s.a",\r
- CSEP,\r
- CSEP,\r
- CSEP,\r
- name.c_str () );\r
- }\r
- else\r
- return GetPath();\r
-}\r
-\r
-string\r
-Module::GetBasePath () const\r
-{\r
- return path;\r
-}\r
-\r
-string\r
-Module::GetPath () const\r
-{\r
- return path + CSEP + GetTargetName ();\r
-}\r
-\r
-string\r
-Module::GetPathWithPrefix ( const string& prefix ) const\r
-{\r
- return path + CSEP + prefix + GetTargetName ();\r
-}\r
-\r
-string\r
-Module::GetTargets () const\r
-{\r
- if ( invocations.size () > 0 )\r
- {\r
- string targets ( "" );\r
- for ( size_t i = 0; i < invocations.size (); i++ )\r
- {\r
- Invoke& invoke = *invocations[i];\r
- if ( targets.length () > 0 )\r
- targets += " ";\r
- targets += invoke.GetTargets ();\r
- }\r
- return targets;\r
- }\r
- else\r
- return GetPath ();\r
-}\r
-\r
-string\r
-Module::GetInvocationTarget ( const int index ) const\r
-{\r
- return ssprintf ( "%s_invoke_%d",\r
- name.c_str (),\r
- index );\r
-}\r
-\r
-bool\r
-Module::HasFileWithExtension (\r
- const IfableData& data,\r
- const std::string& extension ) const\r
-{\r
- size_t i;\r
- for ( i = 0; i < data.files.size (); i++ )\r
- {\r
- File& file = *data.files[i];\r
- string file_ext = GetExtension ( file.name );\r
- if ( !stricmp ( file_ext.c_str (), extension.c_str () ) )\r
- return true;\r
- }\r
- for ( i = 0; i < data.ifs.size (); i++ )\r
- {\r
- if ( HasFileWithExtension ( data.ifs[i]->data, extension ) )\r
- return true;\r
- }\r
- return false;\r
-}\r
-\r
-void\r
-Module::InvokeModule () const\r
-{\r
- for ( size_t i = 0; i < invocations.size (); i++ )\r
- {\r
- Invoke& invoke = *invocations[i];\r
- string command = invoke.invokeModule->GetPath () + " " + invoke.GetParameters ();\r
- printf ( "Executing '%s'\n\n", command.c_str () );\r
- int exitcode = system ( command.c_str () );\r
- if ( exitcode != 0 )\r
- throw InvocationFailedException ( command,\r
- exitcode );\r
- }\r
-}\r
-\r
-\r
-File::File ( const string& _name, bool _first )\r
- : name(_name), first(_first)\r
-{\r
-}\r
-\r
-void\r
-File::ProcessXML()\r
-{\r
-}\r
-\r
-\r
-Library::Library ( const XMLElement& _node,\r
- const Module& _module,\r
- const string& _name )\r
- : node(_node),\r
- module(_module),\r
- name(_name),\r
- imported_module(_module.project.LocateModule(_name))\r
-{\r
- if ( module.name == name )\r
- throw InvalidBuildFileException (\r
- node.location,\r
- "module '%s' cannot link against itself",\r
- name.c_str() );\r
- if ( !imported_module )\r
- throw InvalidBuildFileException (\r
- node.location,\r
- "module '%s' trying to import non-existant module '%s'",\r
- module.name.c_str(),\r
- name.c_str() );\r
-}\r
-\r
-void\r
-Library::ProcessXML()\r
-{\r
- if ( !module.project.LocateModule ( name ) )\r
- throw InvalidBuildFileException (\r
- node.location,\r
- "module '%s' is trying to link against non-existant module '%s'",\r
- module.name.c_str(),\r
- name.c_str() );\r
-}\r
-\r
-\r
-Invoke::Invoke ( const XMLElement& _node,\r
- const Module& _module )\r
- : node (_node),\r
- module (_module)\r
-{\r
-}\r
-\r
-void\r
-Invoke::ProcessXML()\r
-{\r
- const XMLAttribute* att = node.GetAttribute ( "module", false );\r
- if (att == NULL)\r
- invokeModule = &module;\r
- else\r
- {\r
- invokeModule = module.project.LocateModule ( att->value );\r
- if ( invokeModule == NULL )\r
- throw InvalidBuildFileException (\r
- node.location,\r
- "module '%s' is trying to invoke non-existant module '%s'",\r
- module.name.c_str(),\r
- att->value.c_str() );\r
- }\r
-\r
- for ( size_t i = 0; i < node.subElements.size (); i++ )\r
- ProcessXMLSubElement ( *node.subElements[i] );\r
-}\r
-\r
-void\r
-Invoke::ProcessXMLSubElement ( const XMLElement& e )\r
-{\r
- bool subs_invalid = false;\r
- if ( e.name == "input" )\r
- {\r
- for ( size_t i = 0; i < e.subElements.size (); i++ )\r
- ProcessXMLSubElementInput ( *e.subElements[i] );\r
- }\r
- else if ( e.name == "output" )\r
- {\r
- for ( size_t i = 0; i < e.subElements.size (); i++ )\r
- ProcessXMLSubElementOutput ( *e.subElements[i] );\r
- }\r
- if ( subs_invalid && e.subElements.size() > 0 )\r
- throw InvalidBuildFileException ( e.location,\r
- "<%s> cannot have sub-elements",\r
- e.name.c_str() );\r
-}\r
-\r
-void\r
-Invoke::ProcessXMLSubElementInput ( const XMLElement& e )\r
-{\r
- bool subs_invalid = false;\r
- if ( e.name == "inputfile" && e.value.size () > 0 )\r
- {\r
- input.push_back ( new InvokeFile ( e, FixSeparator ( module.path + CSEP + e.value ) ) );\r
- subs_invalid = true;\r
- }\r
- if ( subs_invalid && e.subElements.size() > 0 )\r
- throw InvalidBuildFileException ( e.location,\r
- "<%s> cannot have sub-elements",\r
- e.name.c_str() );\r
-}\r
-\r
-void\r
-Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )\r
-{\r
- bool subs_invalid = false;\r
- if ( e.name == "outputfile" && e.value.size () > 0 )\r
- {\r
- output.push_back ( new InvokeFile ( e, FixSeparator ( module.path + CSEP + e.value ) ) );\r
- subs_invalid = true;\r
- }\r
- if ( subs_invalid && e.subElements.size() > 0 )\r
- throw InvalidBuildFileException ( e.location,\r
- "<%s> cannot have sub-elements",\r
- e.name.c_str() );\r
-}\r
-\r
-string\r
-Invoke::GetTargets () const\r
-{\r
- string targets ( "" );\r
- for ( size_t i = 0; i < output.size (); i++ )\r
- {\r
- InvokeFile& file = *output[i];\r
- if ( targets.length () > 0 )\r
- targets += " ";\r
- targets += NormalizeFilename ( file.name );\r
- }\r
- return targets;\r
-}\r
-\r
-string\r
-Invoke::GetParameters () const\r
-{\r
- string parameters ( "" );\r
- size_t i;\r
- for ( i = 0; i < output.size (); i++ )\r
- {\r
- if ( parameters.length () > 0)\r
- parameters += " ";\r
- InvokeFile& invokeFile = *output[i];\r
- if ( invokeFile.switches.length () > 0 )\r
- {\r
- parameters += invokeFile.switches;\r
- parameters += " ";\r
- }\r
- parameters += invokeFile.name;\r
- }\r
-\r
- for ( i = 0; i < input.size (); i++ )\r
- {\r
- if ( parameters.length () > 0 )\r
- parameters += " ";\r
- InvokeFile& invokeFile = *input[i];\r
- if ( invokeFile.switches.length () > 0 )\r
- {\r
- parameters += invokeFile.switches;\r
- parameters += " ";\r
- }\r
- parameters += invokeFile.name ;\r
- }\r
-\r
- return parameters;\r
-}\r
-\r
-\r
-InvokeFile::InvokeFile ( const XMLElement& _node,\r
- const string& _name )\r
- : node (_node),\r
- name (_name)\r
-{\r
- const XMLAttribute* att = _node.GetAttribute ( "switches", false );\r
- if (att != NULL)\r
- switches = att->value;\r
- else\r
- switches = "";\r
-}\r
-\r
-void\r
-InvokeFile::ProcessXML()\r
-{\r
-}\r
-\r
-\r
-Dependency::Dependency ( const XMLElement& _node,\r
- const Module& _module )\r
- : node (_node),\r
- module (_module),\r
- dependencyModule (NULL)\r
-{\r
-}\r
-\r
-void\r
-Dependency::ProcessXML()\r
-{\r
- dependencyModule = module.project.LocateModule ( node.value );\r
- if ( dependencyModule == NULL )\r
- throw InvalidBuildFileException ( node.location,\r
- "module '%s' depend on non-existant module '%s'",\r
- module.name.c_str(),\r
- node.value.c_str() );\r
-}\r
-\r
-\r
-ImportLibrary::ImportLibrary ( const XMLElement& _node,\r
- const Module& _module )\r
- : node (_node),\r
- module (_module)\r
-{\r
- const XMLAttribute* att = _node.GetAttribute ( "basename", false );\r
- if (att != NULL)\r
- basename = att->value;\r
- else\r
- basename = module.name;\r
-\r
- att = _node.GetAttribute ( "definition", true );\r
- assert (att);\r
- definition = FixSeparator(att->value);\r
-}\r
-\r
-\r
-If::If ( const XMLElement& node_,\r
- const Project& project_,\r
- const Module* module_ )\r
- : node(node_), project(project_), module(module_)\r
-{\r
- const XMLAttribute* att;\r
-\r
- att = node.GetAttribute ( "property", true );\r
- assert(att);\r
- property = att->value;\r
-\r
- att = node.GetAttribute ( "value", true );\r
- assert(att);\r
- value = att->value;\r
-}\r
-\r
-If::~If ()\r
-{\r
-}\r
-\r
-void\r
-If::ProcessXML()\r
-{\r
-}\r
-\r
-\r
-Property::Property ( const XMLElement& node_,\r
- const Project& project_,\r
- const Module* module_ )\r
- : node(node_), project(project_), module(module_)\r
-{\r
- const XMLAttribute* att;\r
-\r
- att = node.GetAttribute ( "name", true );\r
- assert(att);\r
- name = att->value;\r
-\r
- att = node.GetAttribute ( "value", true );\r
- assert(att);\r
- value = att->value;\r
-}\r
-\r
-void\r
-Property::ProcessXML()\r
-{\r
-}\r
-\r
-\r
-PchFile::PchFile (\r
- const XMLElement& node_,\r
- const Module& module_,\r
- const string& header_ )\r
- : node(node_), module(module_), header(header_)\r
-{\r
-}\r
-\r
-void\r
-PchFile::ProcessXML()\r
-{\r
-}\r
+/*
+ * Copyright (C) 2005 Casper S. Hornstrup
+ *
+ * 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
+FixSeparator ( const string& s )
+{
+ string s2(s);
+ char* p = strchr ( &s2[0], CBAD_SEP );
+ while ( p )
+ {
+ *p++ = CSEP;
+ p = strchr ( p, 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 string& location,
+ const string& path,
+ const string& att_value )
+{
+ if ( !att_value.size() )
+ throw InvalidBuildFileException (
+ location,
+ "<directory> tag has empty 'name' attribute" );
+ if ( strpbrk ( att_value.c_str (), "/\\?*:<>|" ) )
+ throw InvalidBuildFileException (
+ location,
+ "<directory> tag has invalid characters in 'name' attribute" );
+ if ( !path.size() )
+ return att_value;
+ return FixSeparator(path + CSEP + att_value);
+}
+
+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
+GetDirectory ( const string& filename )
+{
+ size_t index = filename.find_last_of ( CSEP );
+ if ( index == string::npos )
+ return "";
+ else
+ return filename.substr ( 0, index );
+}
+
+string
+GetFilename ( const string& filename )
+{
+ size_t index = filename.find_last_of ( CSEP );
+ if ( index == string::npos )
+ return filename;
+ else
+ return filename.substr ( index + 1, filename.length () - index );
+}
+
+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;
+}
+
+IfableData::~IfableData()
+{
+ size_t i;
+ for ( i = 0; i < files.size(); i++ )
+ delete files[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 < ifs.size(); i++ )
+ delete ifs[i];
+}
+
+void IfableData::ProcessXML ()
+{
+ size_t i;
+ for ( i = 0; i < files.size (); i++ )
+ files[i]->ProcessXML ();
+ 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 < ifs.size (); i++ )
+ ifs[i]->ProcessXML ();
+}
+
+Module::Module ( const Project& project,
+ const XMLElement& moduleNode,
+ const string& modulePath )
+ : project (project),
+ node (moduleNode),
+ importLibrary (NULL),
+ bootstrap (NULL),
+ pch (NULL),
+ cplusplus (false),
+ host (HostDefault)
+{
+ if ( node.name != "module" )
+ throw InvalidOperationException ( __FILE__,
+ __LINE__,
+ "Module created with non-<module> node" );
+
+ xmlbuildFile = Path::RelativeFromWorkingDirectory ( moduleNode.xmlFile->filename () );
+
+ path = FixSeparator ( modulePath );
+
+ enabled = true;
+
+ const XMLAttribute* 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 ) );
+
+ att = moduleNode.GetAttribute ( "name", true );
+ assert(att);
+ name = att->value;
+
+ 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 );
+ }
+ }
+
+ att = moduleNode.GetAttribute ( "entrypoint", false );
+ if ( att != NULL )
+ entrypoint = att->value;
+ else
+ entrypoint = GetDefaultModuleEntrypoint ();
+
+ 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 ( "host", false );
+ if ( att != NULL )
+ {
+ const char* p = att->value.c_str();
+ if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
+ host = HostTrue;
+ else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
+ host = HostFalse;
+ else
+ {
+ throw InvalidAttributeValueException (
+ moduleNode.location,
+ "host",
+ att->value );
+ }
+ }
+
+ att = moduleNode.GetAttribute ( "prefix", false );
+ if ( att != NULL )
+ prefix = att->value;
+
+ att = moduleNode.GetAttribute ( "installbase", false );
+ if ( att != NULL )
+ installBase = att->value;
+ else
+ installBase = "";
+
+ att = moduleNode.GetAttribute ( "installname", false );
+ if ( att != NULL )
+ installName = att->value;
+ else
+ installName = "";
+
+ att = moduleNode.GetAttribute ( "usewrc", false );
+ if ( att != NULL )
+ useWRC = att->value == "true";
+ else
+ useWRC = true;
+
+ 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 = "";
+}
+
+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 ( pch )
+ delete pch;
+}
+
+void
+Module::ProcessXML()
+{
+ if ( type == Alias )
+ {
+ if ( aliasedModuleName == name )
+ throw InvalidBuildFileException (
+ node.location,
+ "module '%s' cannot link against itself",
+ name.c_str() );
+ const Module* m = project.LocateModule ( aliasedModuleName );
+ if ( !m )
+ throw InvalidBuildFileException (
+ 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++ )
+ ProcessXMLSubElement ( *node.subElements[i], path );
+ 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 ( pch )
+ pch->ProcessXML();
+}
+
+void
+Module::ProcessXMLSubElement ( const XMLElement& e,
+ const string& path,
+ If* pIf /*= NULL*/ )
+{
+ bool subs_invalid = false;
+ string subpath ( path );
+ 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 InvalidBuildFileException (
+ 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 ( FixSeparator ( path + CSEP + e.value ),
+ first,
+ switches,
+ false );
+ if ( pIf )
+ pIf->data.files.push_back ( pFile );
+ else
+ 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 );
+ if ( pIf )
+ pIf->data.libraries.push_back ( pLibrary );
+ else
+ non_if_data.libraries.push_back ( pLibrary );
+ subs_invalid = true;
+ }
+ else if ( e.name == "directory" )
+ {
+ const XMLAttribute* att = e.GetAttribute ( "name", true );
+ assert(att);
+ subpath = GetSubPath ( e.location, path, att->value );
+ }
+ else if ( e.name == "include" )
+ {
+ Include* include = new Include ( project, this, &e );
+ if ( pIf )
+ pIf->data.includes.push_back ( include );
+ else
+ non_if_data.includes.push_back ( include );
+ subs_invalid = true;
+ }
+ else if ( e.name == "define" )
+ {
+ Define* pDefine = new Define ( project, this, e );
+ if ( pIf )
+ pIf->data.defines.push_back ( pDefine );
+ else
+ non_if_data.defines.push_back ( pDefine );
+ subs_invalid = true;
+ }
+ else if ( e.name == "invoke" )
+ {
+ if ( pIf )
+ throw InvalidBuildFileException (
+ e.location,
+ "<invoke> is not a valid sub-element of <if>" );
+ invocations.push_back ( new Invoke ( e, *this ) );
+ subs_invalid = false;
+ }
+ else if ( e.name == "dependency" )
+ {
+ if ( pIf )
+ throw InvalidBuildFileException (
+ e.location,
+ "<dependency> is not a valid sub-element of <if>" );
+ dependencies.push_back ( new Dependency ( e, *this ) );
+ subs_invalid = true;
+ }
+ else if ( e.name == "importlibrary" )
+ {
+ if ( pIf )
+ throw InvalidBuildFileException (
+ e.location,
+ "<importlibrary> is not a valid sub-element of <if>" );
+ if ( importLibrary )
+ throw InvalidBuildFileException (
+ e.location,
+ "Only one <importlibrary> is valid per module" );
+ importLibrary = new ImportLibrary ( e, *this );
+ subs_invalid = true;
+ }
+ else if ( e.name == "if" )
+ {
+ If* pOldIf = pIf;
+ pIf = new If ( e, project, this );
+ if ( pOldIf )
+ pOldIf->data.ifs.push_back ( pIf );
+ else
+ non_if_data.ifs.push_back ( pIf );
+ subs_invalid = false;
+ }
+ else if ( e.name == "ifnot" )
+ {
+ If* pOldIf = pIf;
+ pIf = new If ( e, project, this, true );
+ if ( pOldIf )
+ pOldIf->data.ifs.push_back ( pIf );
+ else
+ non_if_data.ifs.push_back ( pIf );
+ subs_invalid = false;
+ }
+ else if ( e.name == "compilerflag" )
+ {
+ CompilerFlag* pCompilerFlag = new CompilerFlag ( project, this, e );
+ if ( pIf )
+ pIf->data.compilerFlags.push_back ( pCompilerFlag );
+ else
+ 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 == "component" )
+ {
+ stubbedComponents.push_back ( new StubbedComponent ( this, e ) );
+ subs_invalid = false;
+ }
+ else if ( e.name == "property" )
+ {
+ throw InvalidBuildFileException (
+ 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 ( pIf )
+ throw InvalidBuildFileException (
+ e.location,
+ "<pch> is not a valid sub-element of <if>" );
+ if ( pch )
+ throw InvalidBuildFileException (
+ e.location,
+ "Only one <pch> is valid per module" );
+ pch = new PchFile (
+ e, *this, File ( FixSeparator ( path + CSEP + e.value ), false, "", true ) );
+ subs_invalid = true;
+ }
+ if ( subs_invalid && e.subElements.size() > 0 )
+ throw InvalidBuildFileException (
+ 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], subpath, pIf );
+}
+
+ModuleType
+Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
+{
+ if ( attribute.value == "buildtool" )
+ return BuildTool;
+ if ( attribute.value == "staticlibrary" )
+ return StaticLibrary;
+ 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 == "win32dll" )
+ return Win32DLL;
+ if ( attribute.value == "win32cui" )
+ return Win32CUI;
+ if ( attribute.value == "win32gui" )
+ return Win32GUI;
+ if ( attribute.value == "bootloader" )
+ return BootLoader;
+ if ( attribute.value == "bootsector" )
+ return BootSector;
+ if ( attribute.value == "iso" )
+ return Iso;
+ if ( attribute.value == "liveiso" )
+ return LiveIso;
+ if ( attribute.value == "test" )
+ return Test;
+ if ( attribute.value == "rpcserver" )
+ return RpcServer;
+ if ( attribute.value == "rpcclient" )
+ return RpcClient;
+ if ( attribute.value == "alias" )
+ return Alias;
+ throw InvalidAttributeValueException ( location,
+ attribute.name,
+ attribute.value );
+}
+
+string
+Module::GetDefaultModuleExtension () const
+{
+ switch (type)
+ {
+ case BuildTool:
+ return EXEPOSTFIX;
+ case StaticLibrary:
+ return ".a";
+ case ObjectLibrary:
+ return ".o";
+ case Kernel:
+ case NativeCUI:
+ case Win32CUI:
+ case Win32GUI:
+ return ".exe";
+ case KernelModeDLL:
+ case NativeDLL:
+ case Win32DLL:
+ return ".dll";
+ case KernelModeDriver:
+ case BootLoader:
+ return ".sys";
+ case BootSector:
+ return ".o";
+ case Iso:
+ case LiveIso:
+ return ".iso";
+ case Test:
+ return ".exe";
+ case RpcServer:
+ return ".o";
+ case RpcClient:
+ return ".o";
+ case Alias:
+ return "";
+ }
+ throw InvalidOperationException ( __FILE__,
+ __LINE__ );
+}
+
+string
+Module::GetDefaultModuleEntrypoint () const
+{
+ switch ( type )
+ {
+ case Kernel:
+ return "_NtProcessStartup";
+ case KernelModeDLL:
+ return "_DriverEntry@8";
+ case NativeDLL:
+ return "_DllMainCRTStartup@12";
+ case NativeCUI:
+ return "_NtProcessStartup@4";
+ case Win32DLL:
+ return "_DllMain@12";
+ case Win32CUI:
+ case Test:
+ if ( isUnicode )
+ return "_wmainCRTStartup";
+ else
+ return "_mainCRTStartup";
+ case Win32GUI:
+ if ( isUnicode )
+ return "_wWinMainCRTStartup";
+ else
+ return "_WinMainCRTStartup";
+ case KernelModeDriver:
+ return "_DriverEntry@8";
+ case BuildTool:
+ case StaticLibrary:
+ case ObjectLibrary:
+ case BootLoader:
+ case BootSector:
+ case Iso:
+ case LiveIso:
+ case RpcServer:
+ case RpcClient:
+ case Alias:
+ return "";
+ }
+ throw InvalidOperationException ( __FILE__,
+ __LINE__ );
+}
+
+string
+Module::GetDefaultModuleBaseaddress () const
+{
+ switch ( type )
+ {
+ case Kernel:
+ return "0x80000000";
+ case Win32DLL:
+ return "0x10000000";
+ case NativeDLL:
+ case NativeCUI:
+ case Win32CUI:
+ case Test:
+ return "0x00400000";
+ case Win32GUI:
+ return "0x00400000";
+ case KernelModeDLL:
+ case KernelModeDriver:
+ return "0x00010000";
+ case BuildTool:
+ case StaticLibrary:
+ case ObjectLibrary:
+ case BootLoader:
+ case BootSector:
+ case Iso:
+ case LiveIso:
+ case RpcServer:
+ case RpcClient:
+ case Alias:
+ return "";
+ }
+ throw InvalidOperationException ( __FILE__,
+ __LINE__ );
+}
+
+bool
+Module::HasImportLibrary () const
+{
+ return importLibrary != NULL;
+}
+
+bool
+Module::IsDLL () const
+{
+ switch ( type )
+ {
+ case Kernel:
+ case KernelModeDLL:
+ case NativeDLL:
+ case Win32DLL:
+ case KernelModeDriver:
+ return true;
+ case NativeCUI:
+ case Win32CUI:
+ case Test:
+ case Win32GUI:
+ case BuildTool:
+ case StaticLibrary:
+ case ObjectLibrary:
+ case BootLoader:
+ case BootSector:
+ case Iso:
+ case LiveIso:
+ case RpcServer:
+ case RpcClient:
+ case Alias:
+ return false;
+ }
+ throw InvalidOperationException ( __FILE__,
+ __LINE__ );
+}
+
+bool
+Module::GenerateInOutputTree () const
+{
+ switch ( type )
+ {
+ case Kernel:
+ case KernelModeDLL:
+ case NativeDLL:
+ case Win32DLL:
+ case KernelModeDriver:
+ case NativeCUI:
+ case Win32CUI:
+ case Test:
+ case Win32GUI:
+ case BuildTool:
+ case BootLoader:
+ case BootSector:
+ case Iso:
+ case LiveIso:
+ return true;
+ case StaticLibrary:
+ case ObjectLibrary:
+ case RpcServer:
+ case RpcClient:
+ case Alias:
+ return false;
+ }
+ throw InvalidOperationException ( __FILE__,
+ __LINE__ );
+}
+
+string
+Module::GetTargetName () const
+{
+ return name + extension;
+}
+
+string
+Module::GetDependencyPath () const
+{
+ if ( HasImportLibrary () )
+ return ReplaceExtension ( GetPathWithPrefix ( "lib" ), ".a" );
+ else
+ return GetPath();
+}
+
+string
+Module::GetBasePath () const
+{
+ return path;
+}
+
+string
+Module::GetPath () const
+{
+ if ( path.length() > 0 )
+ return path + CSEP + GetTargetName ();
+ else
+ return GetTargetName ();
+}
+
+string
+Module::GetPathWithPrefix ( const string& prefix ) const
+{
+ return path + CSEP + prefix + GetTargetName ();
+}
+
+string
+Module::GetInvocationTarget ( const int index ) const
+{
+ return ssprintf ( "%s_invoke_%d",
+ name.c_str (),
+ index );
+}
+
+bool
+Module::HasFileWithExtension (
+ const IfableData& data,
+ const std::string& extension ) const
+{
+ size_t i;
+ for ( i = 0; i < data.files.size (); i++ )
+ {
+ File& file = *data.files[i];
+ string file_ext = GetExtension ( file.name );
+ if ( !stricmp ( file_ext.c_str (), extension.c_str () ) )
+ return true;
+ }
+ for ( i = 0; i < data.ifs.size (); i++ )
+ {
+ if ( HasFileWithExtension ( data.ifs[i]->data, extension ) )
+ return true;
+ }
+ return false;
+}
+
+void
+Module::InvokeModule () const
+{
+ for ( size_t i = 0; i < invocations.size (); i++ )
+ {
+ Invoke& invoke = *invocations[i];
+ string command = invoke.invokeModule->GetPath () + " " + invoke.GetParameters ();
+ printf ( "Executing '%s'\n\n", command.c_str () );
+ int exitcode = system ( command.c_str () );
+ if ( exitcode != 0 )
+ throw InvocationFailedException ( command,
+ exitcode );
+ }
+}
+
+
+File::File ( const string& _name, bool _first,
+ std::string _switches,
+ bool _isPreCompiledHeader )
+ : name(_name),
+ first(_first),
+ switches(_switches),
+ isPreCompiledHeader(_isPreCompiledHeader)
+{
+}
+
+void
+File::ProcessXML()
+{
+}
+
+bool
+File::IsGeneratedFile () const
+{
+ string extension = GetExtension ( name );
+ return ( extension == ".spec" || extension == ".SPEC" );
+}
+
+
+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 InvalidBuildFileException (
+ node.location,
+ "module '%s' cannot link against itself",
+ name.c_str() );
+ if ( !importedModule )
+ throw InvalidBuildFileException (
+ node.location,
+ "module '%s' trying to import non-existant module '%s'",
+ module.name.c_str(),
+ name.c_str() );
+}
+
+void
+Library::ProcessXML()
+{
+ if ( !module.project.LocateModule ( name ) )
+ throw InvalidBuildFileException (
+ 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 InvalidBuildFileException (
+ 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 InvalidBuildFileException ( 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.path + CSEP + e.value ) ) );
+ subs_invalid = true;
+ }
+ if ( subs_invalid && e.subElements.size() > 0 )
+ throw InvalidBuildFileException ( 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.path + CSEP + e.value ) ) );
+ subs_invalid = true;
+ }
+ if ( subs_invalid && e.subElements.size() > 0 )
+ throw InvalidBuildFileException (
+ 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 InvalidBuildFileException ( node.location,
+ "module '%s' depend on non-existant module '%s'",
+ module.name.c_str(),
+ node.value.c_str() );
+}
+
+
+ImportLibrary::ImportLibrary ( const XMLElement& _node,
+ const Module& _module )
+ : node (_node),
+ module (_module)
+{
+ const XMLAttribute* att = _node.GetAttribute ( "basename", false );
+ if (att != NULL)
+ basename = att->value;
+ else
+ basename = module.name;
+
+ att = _node.GetAttribute ( "definition", true );
+ assert (att);
+ definition = FixSeparator(att->value);
+}
+
+
+If::If ( const XMLElement& node_,
+ const Project& project_,
+ const Module* module_,
+ const bool negated_ )
+ : node(node_), project(project_), module(module_), negated(negated_)
+{
+ const XMLAttribute* att;
+
+ att = node.GetAttribute ( "property", true );
+ assert(att);
+ property = att->value;
+
+ att = node.GetAttribute ( "value", true );
+ assert(att);
+ value = att->value;
+}
+
+If::~If ()
+{
+}
+
+void
+If::ProcessXML()
+{
+}
+
+
+Property::Property ( const XMLElement& node_,
+ const Project& project_,
+ const Module* module_ )
+ : node(node_), project(project_), module(module_)
+{
+ const XMLAttribute* att;
+
+ att = node.GetAttribute ( "name", true );
+ assert(att);
+ name = att->value;
+
+ att = node.GetAttribute ( "value", true );
+ assert(att);
+ value = att->value;
+}
+
+void
+Property::ProcessXML()
+{
+}
+
+
+PchFile::PchFile (
+ const XMLElement& node_,
+ const Module& module_,
+ const File file_ )
+ : node(node_), module(module_), file(file_)
+{
+}
+
+void
+PchFile::ProcessXML()
+{
+}