2 * Copyright (C) 2005 Casper S. Hornstrup
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "backend/backend.h"
28 Environment::GetVariable ( const string
& name
)
30 char* value
= getenv ( name
.c_str () );
31 if ( value
!= NULL
&& strlen ( value
) > 0 )
32 return ssprintf ( "%s",
39 Environment::GetEnvironmentVariablePathOrDefault ( const string
& name
,
40 const string
& defaultValue
)
42 const string
& environmentVariableValue
= Environment::GetVariable ( name
);
43 if ( environmentVariableValue
.length () > 0 )
44 return NormalizeFilename ( environmentVariableValue
);
50 Environment::GetIntermediatePath ()
52 string defaultIntermediate
=
53 string( "obj-" ) + GetEnvironmentVariablePathOrDefault ( "ROS_CDOUTPUT", "i386" );
54 return GetEnvironmentVariablePathOrDefault ( "ROS_INTERMEDIATE",
55 defaultIntermediate
);
59 Environment::GetOutputPath ()
61 string defaultOutput
=
62 string( "output-" ) + GetEnvironmentVariablePathOrDefault ( "ROS_CDOUTPUT", "i386" );
63 return GetEnvironmentVariablePathOrDefault ( "ROS_OUTPUT",
68 Environment::GetInstallPath ()
70 string defaultInstall
=
71 string( "reactos." ) + GetEnvironmentVariablePathOrDefault ( "ROS_CDOUTPUT", "" );
72 return GetEnvironmentVariablePathOrDefault ( "ROS_INSTALL",
77 Environment::GetCdOutputPath ()
79 return GetEnvironmentVariablePathOrDefault ( "ROS_CDOUTPUT",
84 Environment::GetAutomakeFile ( const std::string
& defaultFile
)
86 return GetEnvironmentVariablePathOrDefault ( "ROS_AUTOMAKE",
90 ParseContext::ParseContext ()
92 compilationUnit (NULL
)
97 FileLocation::FileLocation ( Directory
* directory
,
98 std::string filename
)
99 : directory (directory
),
105 Project::Project ( const Configuration
& configuration
,
106 const string
& filename
)
107 : xmlfile (filename
),
110 configuration (configuration
)
120 #ifdef NOT_NEEDED_SINCE_THESE_ARE_CLEANED_BY_IFABLE_DATA
121 for ( i
= 0; i
< modules
.size (); i
++ )
124 for ( i
= 0; i
< linkerFlags
.size (); i
++ )
125 delete linkerFlags
[i
];
126 for ( i
= 0; i
< cdfiles
.size (); i
++ )
128 for ( i
= 0; i
< installfiles
.size (); i
++ )
129 delete installfiles
[i
];
134 Project::LookupProperty ( const string
& name
) const
136 for ( size_t i
= 0; i
< non_if_data
.properties
.size (); i
++ )
138 const Property
* property
= non_if_data
.properties
[i
];
139 if ( property
->name
== name
)
146 Project::ResolveNextProperty ( string
& s
) const
148 size_t i
= s
.find ( "${" );
149 if ( i
== string::npos
)
151 if ( i
!= string::npos
)
154 if ( s
[i
+ 1] == '{' )
158 size_t j
= s
.find ( endCharacter
);
159 if ( j
!= string::npos
)
161 int propertyNameLength
= j
- i
- 2;
162 string propertyName
= s
.substr ( i
+ 2, propertyNameLength
);
163 const Property
* property
= LookupProperty ( propertyName
);
164 if ( property
!= NULL
)
165 return s
.replace ( i
, propertyNameLength
+ 3, property
->value
);
172 Project::ResolveProperties ( const string
& s
) const
179 s2
= ResolveNextProperty ( s3
);
180 } while ( s2
!= s3
);
185 Project::SetConfigurationOption ( char* s
,
187 string
* alternativeName
)
189 const Property
* property
= LookupProperty ( name
);
190 if ( property
!= NULL
&& property
->value
.length () > 0 )
194 property
->name
.c_str (),
195 property
->value
.c_str () );
197 else if ( property
!= NULL
)
201 property
->name
.c_str () );
203 else if ( alternativeName
!= NULL
)
207 alternativeName
->c_str () );
212 Project::SetConfigurationOption ( char* s
,
215 SetConfigurationOption ( s
, name
, NULL
);
219 Project::WriteConfigurationFile ()
224 buf
= (char*) malloc ( 10*1024 );
226 throw OutOfMemoryException ();
229 s
= s
+ sprintf ( s
, "/* Automatically generated. " );
230 s
= s
+ sprintf ( s
, "Edit config.xml to change configuration */\n" );
231 s
= s
+ sprintf ( s
, "#ifndef __INCLUDE_CONFIG_H\n" );
232 s
= s
+ sprintf ( s
, "#define __INCLUDE_CONFIG_H\n" );
234 SetConfigurationOption ( s
, "ARCH" );
235 SetConfigurationOption ( s
, "OPTIMIZED" );
236 SetConfigurationOption ( s
, "MP", new string ( "UP" ) );
237 SetConfigurationOption ( s
, "ACPI" );
238 SetConfigurationOption ( s
, "_3GB" );
240 s
= s
+ sprintf ( s
, "#endif /* __INCLUDE_CONFIG_H */\n" );
242 FileSupportCode::WriteIfChanged ( buf
, "include" + sSep
+ "roscfg.h" );
248 Project::ExecuteInvocations ()
250 for ( size_t i
= 0; i
< modules
.size (); i
++ )
251 modules
[i
]->InvokeModule ();
258 head
= XMLLoadFile ( xmlfile
, path
, xmlbuildfiles
);
260 for ( size_t i
= 0; i
< head
->subElements
.size (); i
++ )
262 if ( head
->subElements
[i
]->name
== "project" )
264 node
= head
->subElements
[i
];
272 node
= head
->subElements
[0];
274 throw XMLInvalidBuildFileException (
276 "Document contains no 'project' tag." );
280 Project::ProcessXML ( const string
& path
)
282 const XMLAttribute
*att
;
283 if ( node
->name
!= "project" )
284 throw Exception ( "internal tool error: Project::ProcessXML() called with non-<project> node" );
286 att
= node
->GetAttribute ( "name", false );
292 att
= node
->GetAttribute ( "makefile", true );
294 makefile
= Environment::GetAutomakeFile ( att
->value
);
297 for ( i
= 0; i
< node
->subElements
.size (); i
++ )
299 ParseContext parseContext
;
300 ProcessXMLSubElement ( *node
->subElements
[i
], path
, parseContext
);
303 non_if_data
.ProcessXML ();
305 non_if_data
.ExtractModules( modules
);
307 for ( i
= 0; i
< non_if_data
.ifs
.size (); i
++ )
309 const Property
*property
=
310 LookupProperty( non_if_data
.ifs
[i
]->property
);
312 if( !property
) continue;
315 (non_if_data
.ifs
[i
]->negated
&&
316 (property
->value
!= non_if_data
.ifs
[i
]->value
)) ||
317 (property
->value
== non_if_data
.ifs
[i
]->value
);
319 non_if_data
.ifs
[i
]->data
.ExtractModules( modules
);
322 If
* if_data
= non_if_data
.ifs
[i
];
323 non_if_data
.ifs
.erase ( non_if_data
.ifs
.begin () + i
);
328 for ( i
= 0; i
< linkerFlags
.size (); i
++ )
329 linkerFlags
[i
]->ProcessXML ();
330 for ( i
= 0; i
< modules
.size (); i
++ )
331 modules
[i
]->ProcessXML ();
332 for ( i
= 0; i
< cdfiles
.size (); i
++ )
333 cdfiles
[i
]->ProcessXML ();
334 for ( i
= 0; i
< installfiles
.size (); i
++ )
335 installfiles
[i
]->ProcessXML ();
339 Project::ProcessXMLSubElement ( const XMLElement
& e
,
341 ParseContext
& parseContext
)
343 bool subs_invalid
= false;
344 If
* pOldIf
= parseContext
.ifData
;
346 string
subpath(path
);
347 if ( e
.name
== "module" )
349 Module
* module
= new Module ( *this, e
, path
);
350 if ( LocateModule ( module
->name
) )
351 throw XMLInvalidBuildFileException (
353 "module name conflict: '%s' (originally defined at %s)",
354 module
->name
.c_str(),
355 module
->node
.location
.c_str() );
356 if ( parseContext
.ifData
)
357 parseContext
.ifData
->data
.modules
.push_back( module
);
359 non_if_data
.modules
.push_back ( module
);
360 return; // defer processing until later
362 else if ( e
.name
== "cdfile" )
364 CDFile
* cdfile
= new CDFile ( *this, e
, path
);
365 cdfiles
.push_back ( cdfile
);
368 else if ( e
.name
== "installfile" )
370 InstallFile
* installfile
= new InstallFile ( *this, e
, path
);
371 installfiles
.push_back ( installfile
);
374 else if ( e
.name
== "directory" )
376 const XMLAttribute
* att
= e
.GetAttribute ( "name", true );
378 subpath
= GetSubPath ( e
.location
, path
, att
->value
);
380 else if ( e
.name
== "include" )
382 Include
* include
= new Include ( *this, &e
);
383 if ( parseContext
.ifData
)
384 parseContext
.ifData
->data
.includes
.push_back ( include
);
386 non_if_data
.includes
.push_back ( include
);
389 else if ( e
.name
== "define" )
391 Define
* define
= new Define ( *this, e
);
392 if ( parseContext
.ifData
)
393 parseContext
.ifData
->data
.defines
.push_back ( define
);
395 non_if_data
.defines
.push_back ( define
);
398 else if ( e
.name
== "compilerflag" )
400 CompilerFlag
* pCompilerFlag
= new CompilerFlag ( *this, e
);
401 if ( parseContext
.ifData
)
402 parseContext
.ifData
->data
.compilerFlags
.push_back ( pCompilerFlag
);
404 non_if_data
.compilerFlags
.push_back ( pCompilerFlag
);
407 else if ( e
.name
== "linkerflag" )
409 linkerFlags
.push_back ( new LinkerFlag ( *this, e
) );
412 else if ( e
.name
== "if" )
414 parseContext
.ifData
= new If ( e
, *this, NULL
);
416 pOldIf
->data
.ifs
.push_back ( parseContext
.ifData
);
418 non_if_data
.ifs
.push_back ( parseContext
.ifData
);
419 subs_invalid
= false;
421 else if ( e
.name
== "ifnot" )
423 parseContext
.ifData
= new If ( e
, *this, NULL
, true );
425 pOldIf
->data
.ifs
.push_back ( parseContext
.ifData
);
427 non_if_data
.ifs
.push_back ( parseContext
.ifData
);
428 subs_invalid
= false;
430 else if ( e
.name
== "property" )
432 Property
* property
= new Property ( e
, *this, NULL
);
433 if ( parseContext
.ifData
)
434 parseContext
.ifData
->data
.properties
.push_back ( property
);
436 non_if_data
.properties
.push_back ( property
);
438 if ( subs_invalid
&& e
.subElements
.size() )
440 throw XMLInvalidBuildFileException (
442 "<%s> cannot have sub-elements",
445 for ( size_t i
= 0; i
< e
.subElements
.size (); i
++ )
446 ProcessXMLSubElement ( *e
.subElements
[i
], subpath
, parseContext
);
448 parseContext
.ifData
= pOldIf
;
452 Project::LocateModule ( const string
& name
)
454 for ( size_t i
= 0; i
< modules
.size (); i
++ )
456 if (modules
[i
]->name
== name
)
464 Project::LocateModule ( const string
& name
) const
466 for ( size_t i
= 0; i
< modules
.size (); i
++ )
468 if ( modules
[i
]->name
== name
)
476 Project::GetProjectFilename () const