e30dbc248842c8fa46888bc30338c0ad9fc1946d
[reactos.git] / reactos / tools / rbuild / module.cpp
1 // module.cpp
2
3 #include "pch.h"
4 #include <assert.h>
5
6 #include "rbuild.h"
7
8 using std::string;
9 using std::vector;
10
11 string
12 FixSeparator ( const string& s )
13 {
14 string s2(s);
15 char* p = strchr ( &s2[0], CBAD_SEP );
16 while ( p )
17 {
18 *p++ = CSEP;
19 p = strchr ( p, CBAD_SEP );
20 }
21 return s2;
22 }
23
24 string
25 NormalizeFilename ( const string& filename )
26 {
27 Path path;
28 string normalizedPath = path.Fixup ( filename, true );
29 string relativeNormalizedPath = path.RelativeFromWorkingDirectory ( normalizedPath );
30 return FixSeparator ( relativeNormalizedPath );
31 }
32
33 Module::Module ( const Project& project,
34 const XMLElement& moduleNode,
35 const string& modulePath )
36 : project (project),
37 node (moduleNode),
38 importLibrary (NULL)
39 {
40 if ( node.name != "module" )
41 throw Exception ( "internal tool error: Module created with non-<module> node" );
42
43 path = FixSeparator ( modulePath );
44
45 const XMLAttribute* att = moduleNode.GetAttribute ( "name", true );
46 assert(att);
47 name = att->value;
48
49 att = moduleNode.GetAttribute ( "type", true );
50 assert(att);
51 type = GetModuleType ( node.location, *att );
52
53 att = moduleNode.GetAttribute ( "extension", false );
54 if (att != NULL)
55 extension = att->value;
56 else
57 extension = GetDefaultModuleExtension ();
58 }
59
60 Module::~Module ()
61 {
62 size_t i;
63 for ( i = 0; i < files.size(); i++ )
64 delete files[i];
65 for ( i = 0; i < libraries.size(); i++ )
66 delete libraries[i];
67 for ( i = 0; i < includes.size(); i++ )
68 delete includes[i];
69 for ( i = 0; i < defines.size(); i++ )
70 delete defines[i];
71 for ( i = 0; i < invocations.size(); i++ )
72 delete invocations[i];
73 for ( i = 0; i < dependencies.size(); i++ )
74 delete dependencies[i];
75 for ( i = 0; i < ifs.size(); i++ )
76 delete ifs[i];
77 for ( i = 0; i < linkerFlags.size(); i++ )
78 delete linkerFlags[i];
79 }
80
81 void
82 Module::ProcessXML()
83 {
84 size_t i;
85 for ( i = 0; i < node.subElements.size(); i++ )
86 ProcessXMLSubElement ( *node.subElements[i], path );
87 for ( i = 0; i < files.size (); i++ )
88 files[i]->ProcessXML ();
89 for ( i = 0; i < libraries.size(); i++ )
90 libraries[i]->ProcessXML ();
91 for ( i = 0; i < includes.size(); i++ )
92 includes[i]->ProcessXML ();
93 for ( i = 0; i < defines.size(); i++ )
94 defines[i]->ProcessXML ();
95 for ( i = 0; i < invocations.size(); i++ )
96 invocations[i]->ProcessXML ();
97 for ( i = 0; i < dependencies.size(); i++ )
98 dependencies[i]->ProcessXML ();
99 for ( i = 0; i < ifs.size(); i++ )
100 ifs[i]->ProcessXML();
101 for ( i = 0; i < linkerFlags.size(); i++ )
102 linkerFlags[i]->ProcessXML();
103 }
104
105 void
106 Module::ProcessXMLSubElement ( const XMLElement& e,
107 const string& path,
108 If* pIf /*= NULL*/ )
109 {
110 bool subs_invalid = false;
111 string subpath ( path );
112 if ( e.name == "file" && e.value.size () > 0 )
113 {
114 const XMLAttribute* att = e.GetAttribute ( "first", false );
115 File* pFile = new File ( FixSeparator ( path + CSEP + e.value ),
116 att && atoi(att->value.c_str()) != 0 );
117 if ( pIf )
118 pIf->files.push_back ( pFile );
119 else
120 files.push_back ( pFile );
121 subs_invalid = true;
122 }
123 else if ( e.name == "library" && e.value.size () )
124 {
125 if ( pIf )
126 throw InvalidBuildFileException (
127 e.location,
128 "<library> is not a valid sub-element of <if>" );
129 libraries.push_back ( new Library ( e, *this, e.value ) );
130 subs_invalid = true;
131 }
132 else if ( e.name == "directory" )
133 {
134 const XMLAttribute* att = e.GetAttribute ( "name", true );
135 assert(att);
136 subpath = FixSeparator ( path + CSEP + att->value );
137 }
138 else if ( e.name == "include" )
139 {
140 Include* include = new Include ( project, this, e );
141 if ( pIf )
142 pIf->includes.push_back ( include );
143 else
144 includes.push_back ( include );
145 subs_invalid = true;
146 }
147 else if ( e.name == "define" )
148 {
149 Define* pDefine = new Define ( project, this, e );
150 if ( pIf )
151 pIf->defines.push_back ( pDefine );
152 else
153 defines.push_back ( pDefine );
154 subs_invalid = true;
155 }
156 else if ( e.name == "invoke" )
157 {
158 if ( pIf )
159 throw InvalidBuildFileException (
160 e.location,
161 "<invoke> is not a valid sub-element of <if>" );
162 invocations.push_back ( new Invoke ( e, *this ) );
163 subs_invalid = false;
164 }
165 else if ( e.name == "dependency" )
166 {
167 if ( pIf )
168 throw InvalidBuildFileException (
169 e.location,
170 "<dependency> is not a valid sub-element of <if>" );
171 dependencies.push_back ( new Dependency ( e, *this ) );
172 subs_invalid = true;
173 }
174 else if ( e.name == "importlibrary" )
175 {
176 if ( pIf )
177 throw InvalidBuildFileException (
178 e.location,
179 "<importlibrary> is not a valid sub-element of <if>" );
180 if ( importLibrary )
181 throw InvalidBuildFileException (
182 e.location,
183 "Only one <importlibrary> is valid per module" );
184 importLibrary = new ImportLibrary ( e, *this );
185 subs_invalid = true;
186 }
187 else if ( e.name == "if" )
188 {
189 If* pOldIf = pIf;
190 pIf = new If ( e, project, this );
191 if ( pOldIf )
192 pOldIf->ifs.push_back ( pIf );
193 else
194 ifs.push_back ( pIf );
195 subs_invalid = false;
196 }
197 else if ( e.name == "linkerflag" )
198 {
199 linkerFlags.push_back ( new LinkerFlag ( project, this, e ) );
200 subs_invalid = true;
201 }
202 else if ( e.name == "property" )
203 {
204 throw InvalidBuildFileException (
205 e.location,
206 "<property> is not a valid sub-element of <module>" );
207 }
208 if ( subs_invalid && e.subElements.size() > 0 )
209 throw InvalidBuildFileException (
210 e.location,
211 "<%s> cannot have sub-elements",
212 e.name.c_str() );
213 for ( size_t i = 0; i < e.subElements.size (); i++ )
214 ProcessXMLSubElement ( *e.subElements[i], subpath, pIf );
215 }
216
217 ModuleType
218 Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
219 {
220 if ( attribute.value == "buildtool" )
221 return BuildTool;
222 if ( attribute.value == "staticlibrary" )
223 return StaticLibrary;
224 if ( attribute.value == "kernel" )
225 return Kernel;
226 if ( attribute.value == "kernelmodedll" )
227 return KernelModeDLL;
228 if ( attribute.value == "kernelmodedriver" )
229 return KernelModeDriver;
230 if ( attribute.value == "nativedll" )
231 return NativeDLL;
232 if ( attribute.value == "win32dll" )
233 return Win32DLL;
234 if ( attribute.value == "win32gui" )
235 return Win32GUI;
236 throw InvalidAttributeValueException ( location,
237 attribute.name,
238 attribute.value );
239 }
240
241 string
242 Module::GetDefaultModuleExtension () const
243 {
244 switch (type)
245 {
246 case BuildTool:
247 return EXEPOSTFIX;
248 case StaticLibrary:
249 return ".a";
250 case Kernel:
251 case Win32GUI:
252 return ".exe";
253 case KernelModeDLL:
254 case NativeDLL:
255 case Win32DLL:
256 return ".dll";
257 case KernelModeDriver:
258 return ".sys";
259 }
260 throw InvalidOperationException ( __FILE__,
261 __LINE__ );
262 }
263
264 bool
265 Module::HasImportLibrary () const
266 {
267 return importLibrary != NULL;
268 }
269
270 string
271 Module::GetTargetName () const
272 {
273 return name + extension;
274 }
275
276 string
277 Module::GetDependencyPath () const
278 {
279 if ( HasImportLibrary () )
280 {
281 return ssprintf ( "dk%snkm%slib%slib%s.a",
282 SSEP,
283 SSEP,
284 SSEP,
285 name.c_str () );
286 }
287 else
288 return GetPath();
289 }
290
291 string
292 Module::GetBasePath () const
293 {
294 return path;
295 }
296
297 string
298 Module::GetPath () const
299 {
300 return path + CSEP + GetTargetName ();
301 }
302
303 string
304 Module::GetPathWithPrefix ( const string& prefix ) const
305 {
306 return path + CSEP + prefix + GetTargetName ();
307 }
308
309 string
310 Module::GetTargets () const
311 {
312 if ( invocations.size () > 0 )
313 {
314 string targets ( "" );
315 for ( size_t i = 0; i < invocations.size (); i++ )
316 {
317 Invoke& invoke = *invocations[i];
318 if ( targets.length () > 0 )
319 targets += " ";
320 targets += invoke.GetTargets ();
321 }
322 return targets;
323 }
324 else
325 return GetPath ();
326 }
327
328 string
329 Module::GetInvocationTarget ( const int index ) const
330 {
331 return ssprintf ( "%s_invoke_%d",
332 name.c_str (),
333 index );
334 }
335
336
337 File::File ( const string& _name, bool _first )
338 : name(_name), first(_first)
339 {
340 }
341
342 void
343 File::ProcessXML()
344 {
345 }
346
347
348 Library::Library ( const XMLElement& _node,
349 const Module& _module,
350 const string& _name )
351 : node(_node),
352 module(_module),
353 name(_name)
354 {
355 if ( module.name == name )
356 throw InvalidBuildFileException (
357 node.location,
358 "module '%s' cannot link against itself",
359 name.c_str() );
360 }
361
362 void
363 Library::ProcessXML()
364 {
365 if ( !module.project.LocateModule ( name ) )
366 throw InvalidBuildFileException (
367 node.location,
368 "module '%s' is trying to link against non-existant module '%s'",
369 module.name.c_str(),
370 name.c_str() );
371 }
372
373
374 Invoke::Invoke ( const XMLElement& _node,
375 const Module& _module )
376 : node (_node),
377 module (_module)
378 {
379 }
380
381 void
382 Invoke::ProcessXML()
383 {
384 const XMLAttribute* att = node.GetAttribute ( "module", false );
385 if (att == NULL)
386 invokeModule = &module;
387 else
388 {
389 invokeModule = module.project.LocateModule ( att->value );
390 if ( invokeModule == NULL )
391 throw InvalidBuildFileException (
392 node.location,
393 "module '%s' is trying to invoke non-existant module '%s'",
394 module.name.c_str(),
395 att->value.c_str() );
396 }
397
398 for ( size_t i = 0; i < node.subElements.size (); i++ )
399 ProcessXMLSubElement ( *node.subElements[i] );
400 }
401
402 void
403 Invoke::ProcessXMLSubElement ( const XMLElement& e )
404 {
405 bool subs_invalid = false;
406 if ( e.name == "input" )
407 {
408 for ( size_t i = 0; i < e.subElements.size (); i++ )
409 ProcessXMLSubElementInput ( *e.subElements[i] );
410 }
411 else if ( e.name == "output" )
412 {
413 for ( size_t i = 0; i < e.subElements.size (); i++ )
414 ProcessXMLSubElementOutput ( *e.subElements[i] );
415 }
416 if ( subs_invalid && e.subElements.size() > 0 )
417 throw InvalidBuildFileException ( e.location,
418 "<%s> cannot have sub-elements",
419 e.name.c_str() );
420 }
421
422 void
423 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
424 {
425 bool subs_invalid = false;
426 if ( e.name == "inputfile" && e.value.size () > 0 )
427 {
428 input.push_back ( new InvokeFile ( e, FixSeparator ( module.path + CSEP + e.value ) ) );
429 subs_invalid = true;
430 }
431 if ( subs_invalid && e.subElements.size() > 0 )
432 throw InvalidBuildFileException ( e.location,
433 "<%s> cannot have sub-elements",
434 e.name.c_str() );
435 }
436
437 void
438 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
439 {
440 bool subs_invalid = false;
441 if ( e.name == "outputfile" && e.value.size () > 0 )
442 {
443 output.push_back ( new InvokeFile ( e, FixSeparator ( module.path + CSEP + e.value ) ) );
444 subs_invalid = true;
445 }
446 if ( subs_invalid && e.subElements.size() > 0 )
447 throw InvalidBuildFileException ( e.location,
448 "<%s> cannot have sub-elements",
449 e.name.c_str() );
450 }
451
452 string
453 Invoke::GetTargets () const
454 {
455 string targets ( "" );
456 for ( size_t i = 0; i < output.size (); i++ )
457 {
458 InvokeFile& file = *output[i];
459 if ( targets.length () > 0 )
460 targets += " ";
461 targets += NormalizeFilename ( file.name );
462 }
463 return targets;
464 }
465
466
467 InvokeFile::InvokeFile ( const XMLElement& _node,
468 const string& _name )
469 : node (_node),
470 name (_name)
471 {
472 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
473 if (att != NULL)
474 switches = att->value;
475 else
476 switches = "";
477 }
478
479 void
480 InvokeFile::ProcessXML()
481 {
482 }
483
484
485 Dependency::Dependency ( const XMLElement& _node,
486 const Module& _module )
487 : node (_node),
488 module (_module),
489 dependencyModule (NULL)
490 {
491 }
492
493 void
494 Dependency::ProcessXML()
495 {
496 dependencyModule = module.project.LocateModule ( node.value );
497 if ( dependencyModule == NULL )
498 throw InvalidBuildFileException ( node.location,
499 "module '%s' depend on non-existant module '%s'",
500 module.name.c_str(),
501 node.value.c_str() );
502 }
503
504
505 ImportLibrary::ImportLibrary ( const XMLElement& _node,
506 const Module& _module )
507 : node (_node),
508 module (_module)
509 {
510 const XMLAttribute* att = _node.GetAttribute ( "basename", false );
511 if (att != NULL)
512 basename = att->value;
513 else
514 basename = module.name;
515
516 att = _node.GetAttribute ( "definition", true );
517 assert (att);
518 definition = FixSeparator(att->value);
519 }
520
521
522 If::If ( const XMLElement& node_,
523 const Project& project_,
524 const Module* module_ )
525 : node(node_), project(project_), module(module_)
526 {
527 const XMLAttribute* att;
528
529 att = node.GetAttribute ( "property", true );
530 assert(att);
531 property = att->value;
532
533 att = node.GetAttribute ( "value", true );
534 assert(att);
535 value = att->value;
536 }
537
538 If::~If ()
539 {
540 size_t i;
541 for ( i = 0; i < files.size(); i++ )
542 delete files[i];
543 for ( i = 0; i < includes.size(); i++ )
544 delete includes[i];
545 for ( i = 0; i < defines.size(); i++ )
546 delete defines[i];
547 for ( i = 0; i < ifs.size(); i++ )
548 delete ifs[i];
549 }
550
551 void
552 If::ProcessXML()
553 {
554 }
555
556
557 Property::Property ( const XMLElement& node_,
558 const Project& project_,
559 const Module* module_ )
560 : node(node_), project(project_), module(module_)
561 {
562 const XMLAttribute* att;
563
564 att = node.GetAttribute ( "name", true );
565 assert(att);
566 name = att->value;
567
568 att = node.GetAttribute ( "value", true );
569 assert(att);
570 value = att->value;
571 }
572
573 void
574 Property::ProcessXML()
575 {
576 }