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