-\r
-#include "pch.h"\r
-#include <assert.h>\r
-\r
-#include "rbuild.h"\r
-\r
-using std::string;\r
-using std::vector;\r
-\r
-Project::Project ( const string& filename )\r
- : xmlfile (filename),\r
- node (NULL),\r
- head (NULL)\r
-{\r
- ReadXml();\r
-}\r
-\r
-Project::~Project ()\r
-{\r
- size_t i;\r
- for ( i = 0; i < modules.size (); i++ )\r
- delete modules[i];\r
- for ( i = 0; i < linkerFlags.size (); i++ )\r
- delete linkerFlags[i];\r
- for ( i = 0; i < cdfiles.size (); i++ )\r
- delete cdfiles[i];\r
- delete head;\r
-}\r
-\r
-const Property*\r
-Project::LookupProperty ( const string& name ) const\r
-{\r
- for ( size_t i = 0; i < non_if_data.properties.size (); i++ )\r
- {\r
- const Property* property = non_if_data.properties[i];\r
- if ( property->name == name )\r
- return property;\r
- }\r
- return NULL;\r
-}\r
-\r
-void\r
-Project::WriteIfChanged ( char* outbuf,\r
- string filename )\r
-{\r
- FILE* out;\r
- unsigned int end;\r
- char* cmpbuf;\r
- unsigned int stat;\r
- \r
- out = fopen ( filename.c_str (), "rb" );\r
- if ( out == NULL )\r
- {\r
- out = fopen ( filename.c_str (), "wb" );\r
- if ( out == NULL )\r
- throw AccessDeniedException ( filename );\r
- fputs ( outbuf, out );\r
- fclose ( out );\r
- return;\r
- }\r
- \r
- fseek ( out, 0, SEEK_END );\r
- end = ftell ( out );\r
- cmpbuf = (char*) malloc ( end );\r
- if ( cmpbuf == NULL )\r
- {\r
- fclose ( out );\r
- throw OutOfMemoryException ();\r
- }\r
- \r
- fseek ( out, 0, SEEK_SET );\r
- stat = fread ( cmpbuf, 1, end, out );\r
- if ( stat != end )\r
- {\r
- free ( cmpbuf );\r
- fclose ( out );\r
- throw AccessDeniedException ( filename );\r
- }\r
- if ( end == strlen ( outbuf ) && memcmp ( cmpbuf, outbuf, end ) == 0 )\r
- {\r
- free ( cmpbuf );\r
- fclose ( out );\r
- return;\r
- }\r
- \r
- free ( cmpbuf );\r
- fclose ( out );\r
- out = fopen ( filename.c_str (), "wb" );\r
- if ( out == NULL )\r
- {\r
- throw AccessDeniedException ( filename );\r
- }\r
- \r
- stat = fwrite ( outbuf, 1, strlen ( outbuf ), out);\r
- if ( strlen ( outbuf ) != stat )\r
- {\r
- fclose ( out );\r
- throw AccessDeniedException ( filename );\r
- }\r
-\r
- fclose ( out );\r
-}\r
-\r
-void\r
-Project::SetConfigurationOption ( char* s,\r
- string name,\r
- string* alternativeName )\r
-{\r
- const Property* property = LookupProperty ( name );\r
- if ( property != NULL && property->value.length () > 0 )\r
- {\r
- s = s + sprintf ( s,\r
- "#define %s=%s\n",\r
- property->name.c_str (),\r
- property->value.c_str () );\r
- }\r
- else if ( property != NULL )\r
- {\r
- s = s + sprintf ( s,\r
- "#define %s\n",\r
- property->name.c_str () );\r
- }\r
- else if ( alternativeName != NULL )\r
- {\r
- s = s + sprintf ( s,\r
- "#define %s\n",\r
- alternativeName->c_str () );\r
- }\r
-}\r
-\r
-void\r
-Project::SetConfigurationOption ( char* s,\r
- string name )\r
-{\r
- SetConfigurationOption ( s, name, NULL );\r
-}\r
-\r
-void\r
-Project::WriteConfigurationFile ()\r
-{\r
- char* buf;\r
- char* s;\r
-\r
- buf = (char*) malloc ( 10*1024 );\r
- if ( buf == NULL )\r
- throw OutOfMemoryException ();\r
- \r
- s = buf;\r
- s = s + sprintf ( s, "/* Automatically generated. " );\r
- s = s + sprintf ( s, "Edit config.xml to change configuration */\n" );\r
- s = s + sprintf ( s, "#ifndef __INCLUDE_CONFIG_H\n" );\r
- s = s + sprintf ( s, "#define __INCLUDE_CONFIG_H\n" );\r
-\r
- SetConfigurationOption ( s, "ARCH" );\r
- SetConfigurationOption ( s, "OPTIMIZED" );\r
- SetConfigurationOption ( s, "MP", new string ( "UP" ) );\r
- SetConfigurationOption ( s, "ACPI" );\r
- SetConfigurationOption ( s, "_3GB" );\r
-\r
- s = s + sprintf ( s, "#endif /* __INCLUDE_CONFIG_H */\n" );\r
-\r
- WriteIfChanged ( buf, "include" SSEP "roscfg.h" );\r
-\r
- free ( buf );\r
-}\r
-\r
-void\r
-Project::ExecuteInvocations ()\r
-{\r
- for ( size_t i = 0; i < modules.size (); i++ )\r
- modules[i]->InvokeModule ();\r
-}\r
-\r
-void\r
-Project::ReadXml ()\r
-{\r
- Path path;\r
- head = XMLLoadFile ( xmlfile, path, xmlbuildfiles );\r
- node = NULL;\r
- for ( size_t i = 0; i < head->subElements.size (); i++ )\r
- {\r
- if ( head->subElements[i]->name == "project" )\r
- {\r
- node = head->subElements[i];\r
- this->ProcessXML ( "." );\r
- return;\r
- }\r
- }\r
-\r
- throw InvalidBuildFileException (\r
- node->location,\r
- "Document contains no 'project' tag." );\r
-}\r
-\r
-void\r
-Project::ProcessXML ( const string& path )\r
-{\r
- const XMLAttribute *att;\r
- if ( node->name != "project" )\r
- throw Exception ( "internal tool error: Project::ProcessXML() called with non-<project> node" );\r
-\r
- att = node->GetAttribute ( "name", false );\r
- if ( !att )\r
- name = "Unnamed";\r
- else\r
- name = att->value;\r
-\r
- att = node->GetAttribute ( "makefile", true );\r
- assert(att);\r
- makefile = att->value;\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 < modules.size (); i++ )\r
- modules[i]->ProcessXML ();\r
- for ( i = 0; i < linkerFlags.size (); i++ )\r
- linkerFlags[i]->ProcessXML ();\r
- non_if_data.ProcessXML ();\r
- for ( i = 0; i < cdfiles.size (); i++ )\r
- cdfiles[i]->ProcessXML ();\r
-}\r
-\r
-void\r
-Project::ProcessXMLSubElement ( const XMLElement& e,\r
- const string& path,\r
- If* pIf )\r
-{\r
- bool subs_invalid = false;\r
- string subpath(path);\r
- if ( e.name == "module" )\r
- {\r
- if ( pIf )\r
- throw InvalidBuildFileException (\r
- e.location,\r
- "<module> is not a valid sub-element of <if>" );\r
- Module* module = new Module ( *this, e, path );\r
- if ( LocateModule ( module->name ) )\r
- throw InvalidBuildFileException (\r
- node->location,\r
- "module name conflict: '%s' (originally defined at %s)",\r
- module->name.c_str(),\r
- module->node.location.c_str() );\r
- modules.push_back ( module );\r
- return; // defer processing until later\r
- }\r
- else if ( e.name == "cdfile" )\r
- {\r
- CDFile* cdfile = new CDFile ( *this, e, path );\r
- cdfiles.push_back ( cdfile );\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 = path + CSEP + att->value;\r
- }\r
- else if ( e.name == "include" )\r
- {\r
- Include* include = new Include ( *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* define = new Define ( *this, e );\r
- if ( pIf )\r
- pIf->data.defines.push_back ( define );\r
- else\r
- non_if_data.defines.push_back ( define );\r
- subs_invalid = true;\r
- }\r
- else if ( e.name == "linkerflag" )\r
- {\r
- linkerFlags.push_back ( new LinkerFlag ( *this, e ) );\r
- subs_invalid = true;\r
- }\r
- else if ( e.name == "if" )\r
- {\r
- If* pOldIf = pIf;\r
- pIf = new If ( e, *this, NULL );\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 == "property" )\r
- {\r
- Property* property = new Property ( e, *this, NULL );\r
- if ( pIf )\r
- pIf->data.properties.push_back ( property );\r
- else\r
- non_if_data.properties.push_back ( property );\r
- }\r
- if ( subs_invalid && e.subElements.size() )\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
-Module*\r
-Project::LocateModule ( const string& name )\r
-{\r
- for ( size_t i = 0; i < modules.size (); i++ )\r
- {\r
- if (modules[i]->name == name)\r
- return modules[i];\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-const Module*\r
-Project::LocateModule ( const string& name ) const\r
-{\r
- for ( size_t i = 0; i < modules.size (); i++ )\r
- {\r
- if ( modules[i]->name == name )\r
- return modules[i];\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-std::string\r
-Project::GetProjectFilename () const\r
-{\r
- return xmlfile;\r
-}\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"
+#include "backend/backend.h"
+
+using std::string;
+using std::vector;
+
+/* static */ string
+Environment::GetVariable ( const string& name )
+{
+ char* value = getenv ( name.c_str () );
+ if ( value != NULL && strlen ( value ) > 0 )
+ return ssprintf ( "%s",
+ value );
+ else
+ return "";
+}
+
+/* static */ string
+Environment::GetEnvironmentVariablePathOrDefault ( const string& name,
+ const string& defaultValue )
+{
+ const string& environmentVariableValue = Environment::GetVariable ( name );
+ if ( environmentVariableValue.length () > 0 )
+ return NormalizeFilename ( environmentVariableValue );
+ else
+ return defaultValue;
+}
+
+/* static */ string
+Environment::GetIntermediatePath ()
+{
+ string defaultIntermediate =
+ string( "obj-" ) + GetEnvironmentVariablePathOrDefault ( "ROS_CDOUTPUT", "i386" );
+ return GetEnvironmentVariablePathOrDefault ( "ROS_INTERMEDIATE",
+ defaultIntermediate );
+}
+
+/* static */ string
+Environment::GetOutputPath ()
+{
+ string defaultOutput =
+ string( "output-" ) + GetEnvironmentVariablePathOrDefault ( "ROS_CDOUTPUT", "i386" );
+ return GetEnvironmentVariablePathOrDefault ( "ROS_OUTPUT",
+ defaultOutput );
+}
+
+/* static */ string
+Environment::GetInstallPath ()
+{
+ string defaultInstall =
+ string( "reactos." ) + GetEnvironmentVariablePathOrDefault ( "ROS_CDOUTPUT", "" );
+ return GetEnvironmentVariablePathOrDefault ( "ROS_INSTALL",
+ defaultInstall );
+}
+
+/* static */ string
+Environment::GetCdOutputPath ()
+{
+ return GetEnvironmentVariablePathOrDefault ( "ROS_CDOUTPUT",
+ "reactos" );
+}
+
+/* static */ string
+Environment::GetAutomakeFile ( const std::string& defaultFile )
+{
+ return GetEnvironmentVariablePathOrDefault ( "ROS_AUTOMAKE",
+ defaultFile );
+}
+
+ParseContext::ParseContext ()
+ : ifData (NULL),
+ compilationUnit (NULL)
+{
+}
+
+
+FileLocation::FileLocation ( Directory* directory,
+ std::string filename )
+ : directory (directory),
+ filename (filename)
+{
+}
+
+
+Project::Project ( const Configuration& configuration,
+ const string& filename )
+ : xmlfile (filename),
+ node (NULL),
+ head (NULL),
+ configuration (configuration)
+{
+ _backend = NULL;
+ ReadXml();
+}
+
+Project::~Project ()
+{
+ size_t i;
+ if ( _backend )
+ delete _backend;
+#ifdef NOT_NEEDED_SINCE_THESE_ARE_CLEANED_BY_IFABLE_DATA
+ for ( i = 0; i < modules.size (); i++ )
+ delete modules[i];
+#endif
+ for ( i = 0; i < linkerFlags.size (); i++ )
+ delete linkerFlags[i];
+ for ( i = 0; i < cdfiles.size (); i++ )
+ delete cdfiles[i];
+ for ( i = 0; i < installfiles.size (); i++ )
+ delete installfiles[i];
+ delete head;
+}
+
+const Property*
+Project::LookupProperty ( const string& name ) const
+{
+ for ( size_t i = 0; i < non_if_data.properties.size (); i++ )
+ {
+ const Property* property = non_if_data.properties[i];
+ if ( property->name == name )
+ return property;
+ }
+ return NULL;
+}
+
+string
+Project::ResolveNextProperty ( string& s ) const
+{
+ size_t i = s.find ( "${" );
+ if ( i == string::npos )
+ i = s.find ( "$(" );
+ if ( i != string::npos )
+ {
+ string endCharacter;
+ if ( s[i + 1] == '{' )
+ endCharacter = "}";
+ else
+ endCharacter = ")";
+ size_t j = s.find ( endCharacter );
+ if ( j != string::npos )
+ {
+ int propertyNameLength = j - i - 2;
+ string propertyName = s.substr ( i + 2, propertyNameLength );
+ const Property* property = LookupProperty ( propertyName );
+ if ( property != NULL )
+ return s.replace ( i, propertyNameLength + 3, property->value );
+ }
+ }
+ return s;
+}
+
+string
+Project::ResolveProperties ( const string& s ) const
+{
+ string s2 = s;
+ string s3;
+ do
+ {
+ s3 = s2;
+ s2 = ResolveNextProperty ( s3 );
+ } while ( s2 != s3 );
+ return s2;
+}
+
+void
+Project::SetConfigurationOption ( char* s,
+ string name,
+ string* alternativeName )
+{
+ const Property* property = LookupProperty ( name );
+ if ( property != NULL && property->value.length () > 0 )
+ {
+ s = s + sprintf ( s,
+ "#define %s=%s\n",
+ property->name.c_str (),
+ property->value.c_str () );
+ }
+ else if ( property != NULL )
+ {
+ s = s + sprintf ( s,
+ "#define %s\n",
+ property->name.c_str () );
+ }
+ else if ( alternativeName != NULL )
+ {
+ s = s + sprintf ( s,
+ "#define %s\n",
+ alternativeName->c_str () );
+ }
+}
+
+void
+Project::SetConfigurationOption ( char* s,
+ string name )
+{
+ SetConfigurationOption ( s, name, NULL );
+}
+
+void
+Project::WriteConfigurationFile ()
+{
+ char* buf;
+ char* s;
+
+ buf = (char*) malloc ( 10*1024 );
+ if ( buf == NULL )
+ throw OutOfMemoryException ();
+
+ s = buf;
+ s = s + sprintf ( s, "/* Automatically generated. " );
+ s = s + sprintf ( s, "Edit config.xml to change configuration */\n" );
+ s = s + sprintf ( s, "#ifndef __INCLUDE_CONFIG_H\n" );
+ s = s + sprintf ( s, "#define __INCLUDE_CONFIG_H\n" );
+
+ SetConfigurationOption ( s, "ARCH" );
+ SetConfigurationOption ( s, "OPTIMIZED" );
+ SetConfigurationOption ( s, "MP", new string ( "UP" ) );
+ SetConfigurationOption ( s, "ACPI" );
+ SetConfigurationOption ( s, "_3GB" );
+
+ s = s + sprintf ( s, "#endif /* __INCLUDE_CONFIG_H */\n" );
+
+ FileSupportCode::WriteIfChanged ( buf, Environment::GetIntermediatePath() + sSep + "include" + sSep + "roscfg.h" );
+
+ free ( buf );
+}
+
+void
+Project::ExecuteInvocations ()
+{
+ for ( size_t i = 0; i < modules.size (); i++ )
+ modules[i]->InvokeModule ();
+}
+
+void
+Project::ReadXml ()
+{
+ Path path;
+ head = XMLLoadFile ( xmlfile, path, xmlbuildfiles );
+ node = NULL;
+ for ( size_t i = 0; i < head->subElements.size (); i++ )
+ {
+ if ( head->subElements[i]->name == "project" )
+ {
+ node = head->subElements[i];
+ string path;
+ ProcessXML ( path );
+ return;
+ }
+ }
+
+ if (node == NULL)
+ node = head->subElements[0];
+
+ throw XMLInvalidBuildFileException (
+ node->location,
+ "Document contains no 'project' tag." );
+}
+
+void
+Project::ProcessXML ( const string& path )
+{
+ const XMLAttribute *att;
+ if ( node->name != "project" )
+ throw Exception ( "internal tool error: Project::ProcessXML() called with non-<project> node" );
+
+ att = node->GetAttribute ( "name", false );
+ if ( !att )
+ name = "Unnamed";
+ else
+ name = att->value;
+
+ att = node->GetAttribute ( "makefile", true );
+ assert(att);
+ makefile = Environment::GetAutomakeFile ( att->value );
+
+ size_t i;
+ for ( i = 0; i < node->subElements.size (); i++ )
+ {
+ ParseContext parseContext;
+ ProcessXMLSubElement ( *node->subElements[i], path, parseContext );
+ }
+
+ non_if_data.ProcessXML ();
+
+ non_if_data.ExtractModules( modules );
+
+ for ( i = 0; i < non_if_data.ifs.size (); i++ )
+ {
+ const Property *property =
+ LookupProperty( non_if_data.ifs[i]->property );
+
+ if( !property ) continue;
+
+ bool conditionTrue =
+ (non_if_data.ifs[i]->negated &&
+ (property->value != non_if_data.ifs[i]->value)) ||
+ (property->value == non_if_data.ifs[i]->value);
+ if ( conditionTrue )
+ non_if_data.ifs[i]->data.ExtractModules( modules );
+ else
+ {
+ If * if_data = non_if_data.ifs[i];
+ non_if_data.ifs.erase ( non_if_data.ifs.begin () + i );
+ delete if_data;
+ i--;
+ }
+ }
+ for ( i = 0; i < linkerFlags.size (); i++ )
+ linkerFlags[i]->ProcessXML ();
+ for ( i = 0; i < modules.size (); i++ )
+ modules[i]->ProcessXML ();
+ for ( i = 0; i < cdfiles.size (); i++ )
+ cdfiles[i]->ProcessXML ();
+ for ( i = 0; i < installfiles.size (); i++ )
+ installfiles[i]->ProcessXML ();
+}
+
+void
+Project::ProcessXMLSubElement ( const XMLElement& e,
+ const string& path,
+ ParseContext& parseContext )
+{
+ bool subs_invalid = false;
+ If* pOldIf = parseContext.ifData;
+
+ string subpath(path);
+ if ( e.name == "module" )
+ {
+ Module* module = new Module ( *this, e, path );
+ if ( LocateModule ( module->name ) )
+ throw XMLInvalidBuildFileException (
+ node->location,
+ "module name conflict: '%s' (originally defined at %s)",
+ module->name.c_str(),
+ module->node.location.c_str() );
+ if ( parseContext.ifData )
+ parseContext.ifData->data.modules.push_back( module );
+ else
+ non_if_data.modules.push_back ( module );
+ return; // defer processing until later
+ }
+ else if ( e.name == "cdfile" )
+ {
+ CDFile* cdfile = new CDFile ( *this, e, path );
+ cdfiles.push_back ( cdfile );
+ subs_invalid = true;
+ }
+ else if ( e.name == "installfile" )
+ {
+ InstallFile* installfile = new InstallFile ( *this, e, path );
+ installfiles.push_back ( installfile );
+ subs_invalid = true;
+ }
+ else if ( e.name == "directory" )
+ {
+ const XMLAttribute* att = e.GetAttribute ( "name", true );
+ const XMLAttribute* base = e.GetAttribute ( "root", false );
+ assert(att);
+ subpath = GetSubPath ( *this, e.location, path, base, att->value );
+ }
+ else if ( e.name == "include" )
+ {
+ Include* include = new Include ( *this, &e );
+ if ( parseContext.ifData )
+ parseContext.ifData->data.includes.push_back ( include );
+ else
+ non_if_data.includes.push_back ( include );
+ subs_invalid = true;
+ }
+ else if ( e.name == "define" )
+ {
+ Define* define = new Define ( *this, e );
+ if ( parseContext.ifData )
+ parseContext.ifData->data.defines.push_back ( define );
+ else
+ non_if_data.defines.push_back ( define );
+ subs_invalid = true;
+ }
+ else if ( e.name == "compilerflag" )
+ {
+ CompilerFlag* pCompilerFlag = new CompilerFlag ( *this, e );
+ if ( parseContext.ifData )
+ parseContext.ifData->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 ( *this, e ) );
+ subs_invalid = true;
+ }
+ else if ( e.name == "if" )
+ {
+ parseContext.ifData = new If ( e, *this, NULL );
+ if ( pOldIf )
+ pOldIf->data.ifs.push_back ( parseContext.ifData );
+ else
+ non_if_data.ifs.push_back ( parseContext.ifData );
+ subs_invalid = false;
+ }
+ else if ( e.name == "ifnot" )
+ {
+ parseContext.ifData = new If ( e, *this, NULL, true );
+ if ( pOldIf )
+ pOldIf->data.ifs.push_back ( parseContext.ifData );
+ else
+ non_if_data.ifs.push_back ( parseContext.ifData );
+ subs_invalid = false;
+ }
+ else if ( e.name == "property" )
+ {
+ Property* property = new Property ( e, *this, NULL );
+ if ( parseContext.ifData )
+ parseContext.ifData->data.properties.push_back ( property );
+ else
+ non_if_data.properties.push_back ( property );
+ }
+ if ( subs_invalid && e.subElements.size() )
+ {
+ 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], subpath, parseContext );
+
+ parseContext.ifData = pOldIf;
+}
+
+Module*
+Project::LocateModule ( const string& name )
+{
+ for ( size_t i = 0; i < modules.size (); i++ )
+ {
+ if (modules[i]->name == name)
+ return modules[i];
+ }
+
+ return NULL;
+}
+
+const Module*
+Project::LocateModule ( const string& name ) const
+{
+ for ( size_t i = 0; i < modules.size (); i++ )
+ {
+ if ( modules[i]->name == name )
+ return modules[i];
+ }
+
+ return NULL;
+}
+
+const std::string&
+Project::GetProjectFilename () const
+{
+ return xmlfile;
+}