Build and run tests
[reactos.git] / reactos / tools / rbuild / module.cpp
1 #include "pch.h"
2 #include <assert.h>
3
4 #include "rbuild.h"
5
6 using std::string;
7 using std::vector;
8
9 string
10 FixSeparator ( const string& s )
11 {
12 string s2(s);
13 char* p = strchr ( &s2[0], CBAD_SEP );
14 while ( p )
15 {
16 *p++ = CSEP;
17 p = strchr ( p, CBAD_SEP );
18 }
19 return s2;
20 }
21
22 string
23 ReplaceExtension (
24 const string& filename,
25 const string& newExtension )
26 {
27 size_t index = filename.find_last_of ( '/' );
28 if ( index == string::npos )
29 index = 0;
30 size_t index2 = filename.find_last_of ( '\\' );
31 if ( index2 != string::npos && index2 > index )
32 index = index2;
33 string tmp = filename.substr( index /*, filename.size() - index*/ );
34 size_t ext_index = tmp.find_last_of( '.' );
35 if ( ext_index != string::npos )
36 return filename.substr ( 0, index + ext_index ) + newExtension;
37 return filename + newExtension;
38 }
39
40 string
41 GetSubPath (
42 const string& location,
43 const string& path,
44 const string& att_value )
45 {
46 if ( !att_value.size() )
47 throw InvalidBuildFileException (
48 location,
49 "<directory> tag has empty 'name' attribute" );
50 if ( strpbrk ( att_value.c_str (), "/\\?*:<>|" ) )
51 throw InvalidBuildFileException (
52 location,
53 "<directory> tag has invalid characters in 'name' attribute" );
54 if ( !path.size() )
55 return att_value;
56 return FixSeparator(path + CSEP + att_value);
57 }
58
59 string
60 GetExtension ( const string& filename )
61 {
62 size_t index = filename.find_last_of ( '/' );
63 if (index == string::npos) index = 0;
64 string tmp = filename.substr( index, filename.size() - index );
65 size_t ext_index = tmp.find_last_of( '.' );
66 if (ext_index != string::npos)
67 return filename.substr ( index + ext_index, filename.size() );
68 return "";
69 }
70
71 string
72 GetDirectory ( const string& filename )
73 {
74 size_t index = filename.find_last_of ( CSEP );
75 if ( index == string::npos )
76 return "";
77 else
78 return filename.substr ( 0, index );
79 }
80
81 string
82 GetFilename ( const string& filename )
83 {
84 size_t index = filename.find_last_of ( CSEP );
85 if ( index == string::npos )
86 return filename;
87 else
88 return filename.substr ( index + 1, filename.length () - index );
89 }
90
91 string
92 NormalizeFilename ( const string& filename )
93 {
94 if ( filename == "" )
95 return "";
96 Path path;
97 string normalizedPath = path.Fixup ( filename, true );
98 string relativeNormalizedPath = path.RelativeFromWorkingDirectory ( normalizedPath );
99 return FixSeparator ( relativeNormalizedPath );
100 }
101
102 IfableData::~IfableData()
103 {
104 size_t i;
105 for ( i = 0; i < files.size(); i++ )
106 delete files[i];
107 for ( i = 0; i < includes.size(); i++ )
108 delete includes[i];
109 for ( i = 0; i < defines.size(); i++ )
110 delete defines[i];
111 for ( i = 0; i < libraries.size(); i++ )
112 delete libraries[i];
113 for ( i = 0; i < properties.size(); i++ )
114 delete properties[i];
115 for ( i = 0; i < compilerFlags.size(); i++ )
116 delete compilerFlags[i];
117 for ( i = 0; i < ifs.size(); i++ )
118 delete ifs[i];
119 }
120
121 void IfableData::ProcessXML ()
122 {
123 size_t i;
124 for ( i = 0; i < files.size (); i++ )
125 files[i]->ProcessXML ();
126 for ( i = 0; i < includes.size (); i++ )
127 includes[i]->ProcessXML ();
128 for ( i = 0; i < defines.size (); i++ )
129 defines[i]->ProcessXML ();
130 for ( i = 0; i < libraries.size (); i++ )
131 libraries[i]->ProcessXML ();
132 for ( i = 0; i < properties.size(); i++ )
133 properties[i]->ProcessXML ();
134 for ( i = 0; i < compilerFlags.size(); i++ )
135 compilerFlags[i]->ProcessXML ();
136 for ( i = 0; i < ifs.size (); i++ )
137 ifs[i]->ProcessXML ();
138 }
139
140 Module::Module ( const Project& project,
141 const XMLElement& moduleNode,
142 const string& modulePath )
143 : project (project),
144 node (moduleNode),
145 importLibrary (NULL),
146 bootstrap (NULL),
147 pch (NULL),
148 cplusplus (false),
149 host (HostDefault)
150 {
151 if ( node.name != "module" )
152 throw InvalidOperationException ( __FILE__,
153 __LINE__,
154 "Module created with non-<module> node" );
155
156 xmlbuildFile = Path::RelativeFromWorkingDirectory ( moduleNode.xmlFile->filename() );
157
158 path = FixSeparator ( modulePath );
159
160 const XMLAttribute* att = moduleNode.GetAttribute ( "name", true );
161 assert(att);
162 name = att->value;
163
164 att = moduleNode.GetAttribute ( "type", true );
165 assert(att);
166 type = GetModuleType ( node.location, *att );
167
168 att = moduleNode.GetAttribute ( "extension", false );
169 if ( att != NULL )
170 extension = att->value;
171 else
172 extension = GetDefaultModuleExtension ();
173
174 att = moduleNode.GetAttribute ( "entrypoint", false );
175 if ( att != NULL )
176 entrypoint = att->value;
177 else
178 entrypoint = GetDefaultModuleEntrypoint ();
179
180 att = moduleNode.GetAttribute ( "baseaddress", false );
181 if ( att != NULL )
182 baseaddress = att->value;
183 else
184 baseaddress = GetDefaultModuleBaseaddress ();
185
186 att = moduleNode.GetAttribute ( "mangledsymbols", false );
187 if ( att != NULL )
188 {
189 const char* p = att->value.c_str();
190 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
191 mangledSymbols = true;
192 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
193 mangledSymbols = false;
194 else
195 {
196 throw InvalidAttributeValueException (
197 moduleNode.location,
198 "mangledsymbols",
199 att->value );
200 }
201 }
202 else
203 mangledSymbols = false;
204
205 att = moduleNode.GetAttribute ( "host", false );
206 if ( att != NULL )
207 {
208 const char* p = att->value.c_str();
209 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
210 host = HostTrue;
211 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
212 host = HostFalse;
213 else
214 {
215 throw InvalidAttributeValueException (
216 moduleNode.location,
217 "host",
218 att->value );
219 }
220 }
221
222 att = moduleNode.GetAttribute ( "prefix", false );
223 if ( att != NULL )
224 prefix = att->value;
225
226 att = moduleNode.GetAttribute ( "installbase", false );
227 if ( att != NULL )
228 installBase = att->value;
229 else
230 installBase = "";
231
232 att = moduleNode.GetAttribute ( "installname", false );
233 if ( att != NULL )
234 installName = att->value;
235 else
236 installName = "";
237
238 att = moduleNode.GetAttribute ( "usewrc", false );
239 if ( att != NULL )
240 useWRC = att->value == "true";
241 else
242 useWRC = true;
243
244 att = moduleNode.GetAttribute ( "warnings", false );
245 if ( att != NULL )
246 enableWarnings = att->value == "true";
247 else
248 enableWarnings = false;
249 }
250
251 Module::~Module ()
252 {
253 size_t i;
254 for ( i = 0; i < invocations.size(); i++ )
255 delete invocations[i];
256 for ( i = 0; i < dependencies.size(); i++ )
257 delete dependencies[i];
258 for ( i = 0; i < compilerFlags.size(); i++ )
259 delete compilerFlags[i];
260 for ( i = 0; i < linkerFlags.size(); i++ )
261 delete linkerFlags[i];
262 for ( i = 0; i < stubbedComponents.size(); i++ )
263 delete stubbedComponents[i];
264 if ( pch )
265 delete pch;
266 }
267
268 void
269 Module::ProcessXML()
270 {
271 size_t i;
272 for ( i = 0; i < node.subElements.size(); i++ )
273 ProcessXMLSubElement ( *node.subElements[i], path );
274 for ( i = 0; i < invocations.size(); i++ )
275 invocations[i]->ProcessXML ();
276 for ( i = 0; i < dependencies.size(); i++ )
277 dependencies[i]->ProcessXML ();
278 for ( i = 0; i < compilerFlags.size(); i++ )
279 compilerFlags[i]->ProcessXML();
280 for ( i = 0; i < linkerFlags.size(); i++ )
281 linkerFlags[i]->ProcessXML();
282 for ( i = 0; i < stubbedComponents.size(); i++ )
283 stubbedComponents[i]->ProcessXML();
284 non_if_data.ProcessXML();
285 if ( pch )
286 pch->ProcessXML();
287 }
288
289 void
290 Module::ProcessXMLSubElement ( const XMLElement& e,
291 const string& path,
292 If* pIf /*= NULL*/ )
293 {
294 bool subs_invalid = false;
295 string subpath ( path );
296 if ( e.name == "file" && e.value.size () > 0 )
297 {
298 bool first = false;
299 const XMLAttribute* att = e.GetAttribute ( "first", false );
300 if ( att != NULL )
301 {
302 if ( !stricmp ( att->value.c_str(), "true" ) )
303 first = true;
304 else if ( stricmp ( att->value.c_str(), "false" ) )
305 throw InvalidBuildFileException (
306 e.location,
307 "attribute 'first' of <file> element can only be 'true' or 'false'" );
308 }
309 string switches = "";
310 att = e.GetAttribute ( "switches", false );
311 if ( att != NULL )
312 switches = att->value;
313 if ( !cplusplus )
314 {
315 // check for c++ file
316 string ext = GetExtension ( e.value );
317 if ( !stricmp ( ext.c_str(), ".cpp" ) )
318 cplusplus = true;
319 else if ( !stricmp ( ext.c_str(), ".cc" ) )
320 cplusplus = true;
321 else if ( !stricmp ( ext.c_str(), ".cxx" ) )
322 cplusplus = true;
323 }
324 File* pFile = new File ( FixSeparator ( path + CSEP + e.value ),
325 first,
326 switches );
327 if ( pIf )
328 pIf->data.files.push_back ( pFile );
329 else
330 non_if_data.files.push_back ( pFile );
331 subs_invalid = true;
332 }
333 else if ( e.name == "library" && e.value.size () )
334 {
335 Library* pLibrary = new Library ( e, *this, e.value );
336 if ( pIf )
337 pIf->data.libraries.push_back ( pLibrary );
338 else
339 non_if_data.libraries.push_back ( pLibrary );
340 subs_invalid = true;
341 }
342 else if ( e.name == "directory" )
343 {
344 const XMLAttribute* att = e.GetAttribute ( "name", true );
345 assert(att);
346 subpath = GetSubPath ( e.location, path, att->value );
347 }
348 else if ( e.name == "include" )
349 {
350 Include* include = new Include ( project, this, e );
351 if ( pIf )
352 pIf->data.includes.push_back ( include );
353 else
354 non_if_data.includes.push_back ( include );
355 subs_invalid = true;
356 }
357 else if ( e.name == "define" )
358 {
359 Define* pDefine = new Define ( project, this, e );
360 if ( pIf )
361 pIf->data.defines.push_back ( pDefine );
362 else
363 non_if_data.defines.push_back ( pDefine );
364 subs_invalid = true;
365 }
366 else if ( e.name == "invoke" )
367 {
368 if ( pIf )
369 throw InvalidBuildFileException (
370 e.location,
371 "<invoke> is not a valid sub-element of <if>" );
372 invocations.push_back ( new Invoke ( e, *this ) );
373 subs_invalid = false;
374 }
375 else if ( e.name == "dependency" )
376 {
377 if ( pIf )
378 throw InvalidBuildFileException (
379 e.location,
380 "<dependency> is not a valid sub-element of <if>" );
381 dependencies.push_back ( new Dependency ( e, *this ) );
382 subs_invalid = true;
383 }
384 else if ( e.name == "importlibrary" )
385 {
386 if ( pIf )
387 throw InvalidBuildFileException (
388 e.location,
389 "<importlibrary> is not a valid sub-element of <if>" );
390 if ( importLibrary )
391 throw InvalidBuildFileException (
392 e.location,
393 "Only one <importlibrary> is valid per module" );
394 importLibrary = new ImportLibrary ( e, *this );
395 subs_invalid = true;
396 }
397 else if ( e.name == "if" )
398 {
399 If* pOldIf = pIf;
400 pIf = new If ( e, project, this );
401 if ( pOldIf )
402 pOldIf->data.ifs.push_back ( pIf );
403 else
404 non_if_data.ifs.push_back ( pIf );
405 subs_invalid = false;
406 }
407 else if ( e.name == "compilerflag" )
408 {
409 CompilerFlag* pCompilerFlag = new CompilerFlag ( project, this, e );
410 if ( pIf )
411 pIf->data.compilerFlags.push_back ( pCompilerFlag );
412 else
413 non_if_data.compilerFlags.push_back ( pCompilerFlag );
414 subs_invalid = true;
415 }
416 else if ( e.name == "linkerflag" )
417 {
418 linkerFlags.push_back ( new LinkerFlag ( project, this, e ) );
419 subs_invalid = true;
420 }
421 else if ( e.name == "component" )
422 {
423 stubbedComponents.push_back ( new StubbedComponent ( this, e ) );
424 subs_invalid = false;
425 }
426 else if ( e.name == "property" )
427 {
428 throw InvalidBuildFileException (
429 e.location,
430 "<property> is not a valid sub-element of <module>" );
431 }
432 else if ( e.name == "bootstrap" )
433 {
434 bootstrap = new Bootstrap ( project, this, e );
435 subs_invalid = true;
436 }
437 else if ( e.name == "pch" )
438 {
439 if ( pIf )
440 throw InvalidBuildFileException (
441 e.location,
442 "<pch> is not a valid sub-element of <if>" );
443 if ( pch )
444 throw InvalidBuildFileException (
445 e.location,
446 "Only one <pch> is valid per module" );
447 pch = new PchFile (
448 e, *this, FixSeparator ( path + CSEP + e.value ) );
449 subs_invalid = true;
450 }
451 if ( subs_invalid && e.subElements.size() > 0 )
452 throw InvalidBuildFileException (
453 e.location,
454 "<%s> cannot have sub-elements",
455 e.name.c_str() );
456 for ( size_t i = 0; i < e.subElements.size (); i++ )
457 ProcessXMLSubElement ( *e.subElements[i], subpath, pIf );
458 }
459
460 ModuleType
461 Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
462 {
463 if ( attribute.value == "buildtool" )
464 return BuildTool;
465 if ( attribute.value == "staticlibrary" )
466 return StaticLibrary;
467 if ( attribute.value == "objectlibrary" )
468 return ObjectLibrary;
469 if ( attribute.value == "kernel" )
470 return Kernel;
471 if ( attribute.value == "kernelmodedll" )
472 return KernelModeDLL;
473 if ( attribute.value == "kernelmodedriver" )
474 return KernelModeDriver;
475 if ( attribute.value == "nativedll" )
476 return NativeDLL;
477 if ( attribute.value == "nativecui" )
478 return NativeCUI;
479 if ( attribute.value == "win32dll" )
480 return Win32DLL;
481 if ( attribute.value == "win32cui" )
482 return Win32CUI;
483 if ( attribute.value == "win32gui" )
484 return Win32GUI;
485 if ( attribute.value == "bootloader" )
486 return BootLoader;
487 if ( attribute.value == "bootsector" )
488 return BootSector;
489 if ( attribute.value == "iso" )
490 return Iso;
491 if ( attribute.value == "liveiso" )
492 return LiveIso;
493 if ( attribute.value == "test" )
494 return Test;
495 if ( attribute.value == "rpcserver" )
496 return RpcServer;
497 if ( attribute.value == "rpcclient" )
498 return RpcClient;
499 throw InvalidAttributeValueException ( location,
500 attribute.name,
501 attribute.value );
502 }
503
504 string
505 Module::GetDefaultModuleExtension () const
506 {
507 switch (type)
508 {
509 case BuildTool:
510 return EXEPOSTFIX;
511 case StaticLibrary:
512 return ".a";
513 case ObjectLibrary:
514 return ".o";
515 case Kernel:
516 case NativeCUI:
517 case Win32CUI:
518 case Win32GUI:
519 return ".exe";
520 case KernelModeDLL:
521 case NativeDLL:
522 case Win32DLL:
523 return ".dll";
524 case KernelModeDriver:
525 case BootLoader:
526 return ".sys";
527 case BootSector:
528 return ".o";
529 case Iso:
530 case LiveIso:
531 return ".iso";
532 case Test:
533 return ".exe";
534 case RpcServer:
535 return ".o";
536 case RpcClient:
537 return ".o";
538 }
539 throw InvalidOperationException ( __FILE__,
540 __LINE__ );
541 }
542
543 string
544 Module::GetDefaultModuleEntrypoint () const
545 {
546 switch ( type )
547 {
548 case Kernel:
549 return "_NtProcessStartup";
550 case KernelModeDLL:
551 return "_DriverEntry@8";
552 case NativeDLL:
553 return "_DllMainCRTStartup@12";
554 case NativeCUI:
555 return "_NtProcessStartup@4";
556 case Win32DLL:
557 return "_DllMain@12";
558 case Win32CUI:
559 case Test:
560 return "_mainCRTStartup";
561 case Win32GUI:
562 return "_WinMainCRTStartup";
563 case KernelModeDriver:
564 return "_DriverEntry@8";
565 case BuildTool:
566 case StaticLibrary:
567 case ObjectLibrary:
568 case BootLoader:
569 case BootSector:
570 case Iso:
571 case LiveIso:
572 case RpcServer:
573 case RpcClient:
574 return "";
575 }
576 throw InvalidOperationException ( __FILE__,
577 __LINE__ );
578 }
579
580 string
581 Module::GetDefaultModuleBaseaddress () const
582 {
583 switch ( type )
584 {
585 case Kernel:
586 return "0xc0000000";
587 case Win32DLL:
588 return "0x10000000";
589 case NativeDLL:
590 case NativeCUI:
591 case Win32CUI:
592 case Test:
593 return "0x00400000";
594 case Win32GUI:
595 return "0x00400000";
596 case KernelModeDLL:
597 case KernelModeDriver:
598 return "0x00010000";
599 case BuildTool:
600 case StaticLibrary:
601 case ObjectLibrary:
602 case BootLoader:
603 case BootSector:
604 case Iso:
605 case LiveIso:
606 case RpcServer:
607 case RpcClient:
608 return "";
609 }
610 throw InvalidOperationException ( __FILE__,
611 __LINE__ );
612 }
613
614 bool
615 Module::HasImportLibrary () const
616 {
617 return importLibrary != NULL;
618 }
619
620 bool
621 Module::IsDLL () const
622 {
623 switch ( type )
624 {
625 case Kernel:
626 case KernelModeDLL:
627 case NativeDLL:
628 case Win32DLL:
629 case KernelModeDriver:
630 return true;
631 case NativeCUI:
632 case Win32CUI:
633 case Test:
634 case Win32GUI:
635 case BuildTool:
636 case StaticLibrary:
637 case ObjectLibrary:
638 case BootLoader:
639 case BootSector:
640 case Iso:
641 case LiveIso:
642 case RpcServer:
643 case RpcClient:
644 return false;
645 }
646 throw InvalidOperationException ( __FILE__,
647 __LINE__ );
648 }
649
650 string
651 Module::GetTargetName () const
652 {
653 return name + extension;
654 }
655
656 string
657 Module::GetDependencyPath () const
658 {
659 if ( HasImportLibrary () )
660 return ReplaceExtension ( GetPathWithPrefix ( "lib" ), ".a" );
661 else
662 return GetPath();
663 }
664
665 string
666 Module::GetBasePath () const
667 {
668 return path;
669 }
670
671 string
672 Module::GetPath () const
673 {
674 if ( path.length() > 0 )
675 return path + CSEP + GetTargetName ();
676 else
677 return GetTargetName ();
678 }
679
680 string
681 Module::GetPathWithPrefix ( const string& prefix ) const
682 {
683 return path + CSEP + prefix + GetTargetName ();
684 }
685
686 string
687 Module::GetInvocationTarget ( const int index ) const
688 {
689 return ssprintf ( "%s_invoke_%d",
690 name.c_str (),
691 index );
692 }
693
694 bool
695 Module::HasFileWithExtension (
696 const IfableData& data,
697 const std::string& extension ) const
698 {
699 size_t i;
700 for ( i = 0; i < data.files.size (); i++ )
701 {
702 File& file = *data.files[i];
703 string file_ext = GetExtension ( file.name );
704 if ( !stricmp ( file_ext.c_str (), extension.c_str () ) )
705 return true;
706 }
707 for ( i = 0; i < data.ifs.size (); i++ )
708 {
709 if ( HasFileWithExtension ( data.ifs[i]->data, extension ) )
710 return true;
711 }
712 return false;
713 }
714
715 void
716 Module::InvokeModule () const
717 {
718 for ( size_t i = 0; i < invocations.size (); i++ )
719 {
720 Invoke& invoke = *invocations[i];
721 string command = invoke.invokeModule->GetPath () + " " + invoke.GetParameters ();
722 printf ( "Executing '%s'\n\n", command.c_str () );
723 int exitcode = system ( command.c_str () );
724 if ( exitcode != 0 )
725 throw InvocationFailedException ( command,
726 exitcode );
727 }
728 }
729
730
731 File::File ( const string& _name, bool _first,
732 std::string _switches )
733 : name(_name),
734 first(_first),
735 switches(_switches)
736 {
737 }
738
739 void
740 File::ProcessXML()
741 {
742 }
743
744 bool
745 File::IsGeneratedFile () const
746 {
747 string extension = GetExtension ( name );
748 return ( extension == ".spec" || extension == ".SPEC" );
749 }
750
751
752 Library::Library ( const XMLElement& _node,
753 const Module& _module,
754 const string& _name )
755 : node(_node),
756 module(_module),
757 name(_name),
758 imported_module(_module.project.LocateModule(_name))
759 {
760 if ( module.name == name )
761 throw InvalidBuildFileException (
762 node.location,
763 "module '%s' cannot link against itself",
764 name.c_str() );
765 if ( !imported_module )
766 throw InvalidBuildFileException (
767 node.location,
768 "module '%s' trying to import non-existant module '%s'",
769 module.name.c_str(),
770 name.c_str() );
771 }
772
773 void
774 Library::ProcessXML()
775 {
776 if ( !module.project.LocateModule ( name ) )
777 throw InvalidBuildFileException (
778 node.location,
779 "module '%s' is trying to link against non-existant module '%s'",
780 module.name.c_str(),
781 name.c_str() );
782 }
783
784
785 Invoke::Invoke ( const XMLElement& _node,
786 const Module& _module )
787 : node (_node),
788 module (_module)
789 {
790 }
791
792 void
793 Invoke::ProcessXML()
794 {
795 const XMLAttribute* att = node.GetAttribute ( "module", false );
796 if (att == NULL)
797 invokeModule = &module;
798 else
799 {
800 invokeModule = module.project.LocateModule ( att->value );
801 if ( invokeModule == NULL )
802 throw InvalidBuildFileException (
803 node.location,
804 "module '%s' is trying to invoke non-existant module '%s'",
805 module.name.c_str(),
806 att->value.c_str() );
807 }
808
809 for ( size_t i = 0; i < node.subElements.size (); i++ )
810 ProcessXMLSubElement ( *node.subElements[i] );
811 }
812
813 void
814 Invoke::ProcessXMLSubElement ( const XMLElement& e )
815 {
816 bool subs_invalid = false;
817 if ( e.name == "input" )
818 {
819 for ( size_t i = 0; i < e.subElements.size (); i++ )
820 ProcessXMLSubElementInput ( *e.subElements[i] );
821 }
822 else if ( e.name == "output" )
823 {
824 for ( size_t i = 0; i < e.subElements.size (); i++ )
825 ProcessXMLSubElementOutput ( *e.subElements[i] );
826 }
827 if ( subs_invalid && e.subElements.size() > 0 )
828 throw InvalidBuildFileException ( e.location,
829 "<%s> cannot have sub-elements",
830 e.name.c_str() );
831 }
832
833 void
834 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
835 {
836 bool subs_invalid = false;
837 if ( e.name == "inputfile" && e.value.size () > 0 )
838 {
839 input.push_back ( new InvokeFile ( e, FixSeparator ( module.path + CSEP + e.value ) ) );
840 subs_invalid = true;
841 }
842 if ( subs_invalid && e.subElements.size() > 0 )
843 throw InvalidBuildFileException ( e.location,
844 "<%s> cannot have sub-elements",
845 e.name.c_str() );
846 }
847
848 void
849 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
850 {
851 bool subs_invalid = false;
852 if ( e.name == "outputfile" && e.value.size () > 0 )
853 {
854 output.push_back ( new InvokeFile ( e, FixSeparator ( module.path + CSEP + e.value ) ) );
855 subs_invalid = true;
856 }
857 if ( subs_invalid && e.subElements.size() > 0 )
858 throw InvalidBuildFileException (
859 e.location,
860 "<%s> cannot have sub-elements",
861 e.name.c_str() );
862 }
863
864 void
865 Invoke::GetTargets ( string_list& targets ) const
866 {
867 for ( size_t i = 0; i < output.size (); i++ )
868 {
869 InvokeFile& file = *output[i];
870 targets.push_back ( NormalizeFilename ( file.name ) );
871 }
872 }
873
874 string
875 Invoke::GetParameters () const
876 {
877 string parameters ( "" );
878 size_t i;
879 for ( i = 0; i < output.size (); i++ )
880 {
881 if ( parameters.length () > 0)
882 parameters += " ";
883 InvokeFile& invokeFile = *output[i];
884 if ( invokeFile.switches.length () > 0 )
885 {
886 parameters += invokeFile.switches + " ";
887 }
888 parameters += invokeFile.name;
889 }
890
891 for ( i = 0; i < input.size (); i++ )
892 {
893 if ( parameters.length () > 0 )
894 parameters += " ";
895 InvokeFile& invokeFile = *input[i];
896 if ( invokeFile.switches.length () > 0 )
897 {
898 parameters += invokeFile.switches;
899 parameters += " ";
900 }
901 parameters += invokeFile.name ;
902 }
903
904 return parameters;
905 }
906
907
908 InvokeFile::InvokeFile ( const XMLElement& _node,
909 const string& _name )
910 : node (_node),
911 name (_name)
912 {
913 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
914 if (att != NULL)
915 switches = att->value;
916 else
917 switches = "";
918 }
919
920 void
921 InvokeFile::ProcessXML()
922 {
923 }
924
925
926 Dependency::Dependency ( const XMLElement& _node,
927 const Module& _module )
928 : node (_node),
929 module (_module),
930 dependencyModule (NULL)
931 {
932 }
933
934 void
935 Dependency::ProcessXML()
936 {
937 dependencyModule = module.project.LocateModule ( node.value );
938 if ( dependencyModule == NULL )
939 throw InvalidBuildFileException ( node.location,
940 "module '%s' depend on non-existant module '%s'",
941 module.name.c_str(),
942 node.value.c_str() );
943 }
944
945
946 ImportLibrary::ImportLibrary ( const XMLElement& _node,
947 const Module& _module )
948 : node (_node),
949 module (_module)
950 {
951 const XMLAttribute* att = _node.GetAttribute ( "basename", false );
952 if (att != NULL)
953 basename = att->value;
954 else
955 basename = module.name;
956
957 att = _node.GetAttribute ( "definition", true );
958 assert (att);
959 definition = FixSeparator(att->value);
960 }
961
962
963 If::If ( const XMLElement& node_,
964 const Project& project_,
965 const Module* module_ )
966 : node(node_), project(project_), module(module_)
967 {
968 const XMLAttribute* att;
969
970 att = node.GetAttribute ( "property", true );
971 assert(att);
972 property = att->value;
973
974 att = node.GetAttribute ( "value", true );
975 assert(att);
976 value = att->value;
977 }
978
979 If::~If ()
980 {
981 }
982
983 void
984 If::ProcessXML()
985 {
986 }
987
988
989 Property::Property ( const XMLElement& node_,
990 const Project& project_,
991 const Module* module_ )
992 : node(node_), project(project_), module(module_)
993 {
994 const XMLAttribute* att;
995
996 att = node.GetAttribute ( "name", true );
997 assert(att);
998 name = att->value;
999
1000 att = node.GetAttribute ( "value", true );
1001 assert(att);
1002 value = att->value;
1003 }
1004
1005 void
1006 Property::ProcessXML()
1007 {
1008 }
1009
1010
1011 PchFile::PchFile (
1012 const XMLElement& node_,
1013 const Module& module_,
1014 const string& header_ )
1015 : node(node_), module(module_), header(header_)
1016 {
1017 }
1018
1019 void
1020 PchFile::ProcessXML()
1021 {
1022 }