Merge 13511:13830 from trunk
[reactos.git] / reactos / tools / rbuild / project.cpp
1
2 #include "pch.h"
3 #include <assert.h>
4
5 #include "rbuild.h"
6
7 using std::string;
8 using std::vector;
9
10 Project::Project ( const string& filename )
11 : xmlfile (filename),
12 node (NULL),
13 head (NULL)
14 {
15 ReadXml();
16 }
17
18 Project::~Project ()
19 {
20 size_t i;
21 for ( i = 0; i < modules.size (); i++ )
22 delete modules[i];
23 for ( i = 0; i < includes.size (); i++ )
24 delete includes[i];
25 for ( i = 0; i < defines.size (); i++ )
26 delete defines[i];
27 for ( i = 0; i < linkerFlags.size (); i++ )
28 delete linkerFlags[i];
29 for ( i = 0; i < properties.size (); i++ )
30 delete properties[i];
31 for ( i = 0; i < ifs.size (); i++ )
32 delete ifs[i];
33 for ( i = 0; i < cdfiles.size (); i++ )
34 delete cdfiles[i];
35 delete head;
36 }
37
38 const Property*
39 Project::LookupProperty ( const string& name ) const
40 {
41 for ( size_t i = 0; i < properties.size (); i++ )
42 {
43 const Property* property = properties[i];
44 if ( property->name == name )
45 return property;
46 }
47 return NULL;
48 }
49
50 void
51 Project::WriteIfChanged ( char* outbuf,
52 string filename )
53 {
54 FILE* out;
55 unsigned int end;
56 char* cmpbuf;
57 unsigned int stat;
58
59 out = fopen ( filename.c_str (), "rb" );
60 if ( out == NULL )
61 {
62 out = fopen ( filename.c_str (), "wb" );
63 if ( out == NULL )
64 throw AccessDeniedException ( filename );
65 fputs ( outbuf, out );
66 fclose ( out );
67 return;
68 }
69
70 fseek ( out, 0, SEEK_END );
71 end = ftell ( out );
72 cmpbuf = (char*) malloc ( end );
73 if ( cmpbuf == NULL )
74 {
75 fclose ( out );
76 throw OutOfMemoryException ();
77 }
78
79 fseek ( out, 0, SEEK_SET );
80 stat = fread ( cmpbuf, 1, end, out );
81 if ( stat != end )
82 {
83 free ( cmpbuf );
84 fclose ( out );
85 throw AccessDeniedException ( filename );
86 }
87 if ( end == strlen ( outbuf ) && memcmp ( cmpbuf, outbuf, end ) == 0 )
88 {
89 free ( cmpbuf );
90 fclose ( out );
91 return;
92 }
93
94 free ( cmpbuf );
95 fclose ( out );
96 out = fopen ( filename.c_str (), "wb" );
97 if ( out == NULL )
98 {
99 throw AccessDeniedException ( filename );
100 }
101
102 stat = fwrite ( outbuf, 1, strlen ( outbuf ), out);
103 if ( strlen ( outbuf ) != stat )
104 {
105 fclose ( out );
106 throw AccessDeniedException ( filename );
107 }
108
109 fclose ( out );
110 }
111
112 void
113 Project::SetConfigurationOption ( char* s,
114 string name,
115 string* alternativeName )
116 {
117 const Property* property = LookupProperty ( name );
118 if ( property != NULL && property->value.length () > 0 )
119 {
120 s = s + sprintf ( s,
121 "#define %s=%s\n",
122 property->name.c_str (),
123 property->value.c_str () );
124 }
125 else if ( property != NULL )
126 {
127 s = s + sprintf ( s,
128 "#define %s\n",
129 property->name.c_str () );
130 }
131 else if ( alternativeName != NULL )
132 {
133 s = s + sprintf ( s,
134 "#define %s\n",
135 alternativeName->c_str () );
136 }
137 }
138
139 void
140 Project::SetConfigurationOption ( char* s,
141 string name )
142 {
143 SetConfigurationOption ( s, name, NULL );
144 }
145
146 void
147 Project::WriteConfigurationFile ()
148 {
149 char* buf;
150 char* s;
151
152 buf = (char*) malloc ( 10*1024 );
153 if ( buf == NULL )
154 throw OutOfMemoryException ();
155
156 s = buf;
157 s = s + sprintf ( s, "/* Automatically generated. " );
158 s = s + sprintf ( s, "Edit config.xml to change configuration */\n" );
159 s = s + sprintf ( s, "#ifndef __INCLUDE_CONFIG_H\n" );
160 s = s + sprintf ( s, "#define __INCLUDE_CONFIG_H\n" );
161
162 SetConfigurationOption ( s, "ARCH" );
163 SetConfigurationOption ( s, "OPTIMIZED" );
164 SetConfigurationOption ( s, "MP", new string ( "UP" ) );
165 SetConfigurationOption ( s, "ACPI" );
166 SetConfigurationOption ( s, "_3GB" );
167
168 s = s + sprintf ( s, "#endif /* __INCLUDE_CONFIG_H */\n" );
169
170 WriteIfChanged ( buf, "include" SSEP "roscfg.h" );
171
172 free ( buf );
173 }
174
175 void
176 Project::ExecuteInvocations ()
177 {
178 for ( size_t i = 0; i < modules.size (); i++ )
179 modules[i]->InvokeModule ();
180 }
181
182 void
183 Project::ReadXml ()
184 {
185 Path path;
186 head = XMLLoadFile ( xmlfile, path );
187 node = NULL;
188 for ( size_t i = 0; i < head->subElements.size (); i++ )
189 {
190 if ( head->subElements[i]->name == "project" )
191 {
192 node = head->subElements[i];
193 this->ProcessXML ( "." );
194 return;
195 }
196 }
197
198 throw InvalidBuildFileException (
199 node->location,
200 "Document contains no 'project' tag." );
201 }
202
203 void
204 Project::ProcessXML ( const string& path )
205 {
206 const XMLAttribute *att;
207 if ( node->name != "project" )
208 throw Exception ( "internal tool error: Project::ProcessXML() called with non-<project> node" );
209
210 att = node->GetAttribute ( "name", false );
211 if ( !att )
212 name = "Unnamed";
213 else
214 name = att->value;
215
216 att = node->GetAttribute ( "makefile", true );
217 assert(att);
218 makefile = att->value;
219
220 size_t i;
221 for ( i = 0; i < node->subElements.size (); i++ )
222 ProcessXMLSubElement ( *node->subElements[i], path );
223 for ( i = 0; i < modules.size (); i++ )
224 modules[i]->ProcessXML ();
225 for ( i = 0; i < includes.size (); i++ )
226 includes[i]->ProcessXML ();
227 for ( i = 0; i < defines.size (); i++ )
228 defines[i]->ProcessXML ();
229 for ( i = 0; i < linkerFlags.size (); i++ )
230 linkerFlags[i]->ProcessXML ();
231 for ( i = 0; i < properties.size(); i++ )
232 properties[i]->ProcessXML ();
233 for ( i = 0; i < ifs.size (); i++ )
234 ifs[i]->ProcessXML ();
235 for ( i = 0; i < cdfiles.size (); i++ )
236 ifs[i]->ProcessXML ();
237 }
238
239 void
240 Project::ProcessXMLSubElement ( const XMLElement& e,
241 const string& path,
242 If* pIf )
243 {
244 bool subs_invalid = false;
245 string subpath(path);
246 if ( e.name == "module" )
247 {
248 if ( pIf )
249 throw InvalidBuildFileException (
250 e.location,
251 "<module> is not a valid sub-element of <if>" );
252 Module* module = new Module ( *this, e, path );
253 if ( LocateModule ( module->name ) )
254 throw InvalidBuildFileException (
255 node->location,
256 "module name conflict: '%s' (originally defined at %s)",
257 module->name.c_str(),
258 module->node.location.c_str() );
259 modules.push_back ( module );
260 return; // defer processing until later
261 }
262 else if ( e.name == "cdfile" )
263 {
264 CDFile* cdfile = new CDFile ( *this, e, path );
265 cdfiles.push_back ( cdfile );
266 subs_invalid = true;
267 }
268 else if ( e.name == "directory" )
269 {
270 const XMLAttribute* att = e.GetAttribute ( "name", true );
271 assert(att);
272 subpath = path + CSEP + att->value;
273 }
274 else if ( e.name == "include" )
275 {
276 Include* include = new Include ( *this, e );
277 if ( pIf )
278 pIf->includes.push_back ( include );
279 else
280 includes.push_back ( include );
281 subs_invalid = true;
282 }
283 else if ( e.name == "define" )
284 {
285 Define* define = new Define ( *this, e );
286 if ( pIf )
287 pIf->defines.push_back ( define );
288 else
289 defines.push_back ( define );
290 subs_invalid = true;
291 }
292 else if ( e.name == "linkerflag" )
293 {
294 linkerFlags.push_back ( new LinkerFlag ( *this, e ) );
295 subs_invalid = true;
296 }
297 else if ( e.name == "if" )
298 {
299 If* pOldIf = pIf;
300 pIf = new If ( e, *this, NULL );
301 if ( pOldIf )
302 pOldIf->ifs.push_back ( pIf );
303 else
304 ifs.push_back ( pIf );
305 subs_invalid = false;
306 }
307 else if ( e.name == "property" )
308 {
309 Property* property = new Property ( e, *this, NULL );
310 if ( pIf )
311 pIf->properties.push_back ( property );
312 else
313 properties.push_back ( property );
314 }
315 if ( subs_invalid && e.subElements.size() )
316 throw InvalidBuildFileException (
317 e.location,
318 "<%s> cannot have sub-elements",
319 e.name.c_str() );
320 for ( size_t i = 0; i < e.subElements.size (); i++ )
321 ProcessXMLSubElement ( *e.subElements[i], subpath, pIf );
322 }
323
324 Module*
325 Project::LocateModule ( const string& name )
326 {
327 for ( size_t i = 0; i < modules.size (); i++ )
328 {
329 if (modules[i]->name == name)
330 return modules[i];
331 }
332
333 return NULL;
334 }
335
336 const Module*
337 Project::LocateModule ( const string& name ) const
338 {
339 for ( size_t i = 0; i < modules.size (); i++ )
340 {
341 if ( modules[i]->name == name )
342 return modules[i];
343 }
344
345 return NULL;
346 }