Generate proxy makefiles in output tree.
[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 == "compilerflag" )
428 {
429 CompilerFlag* pCompilerFlag = new CompilerFlag ( project, this, e );
430 if ( pIf )
431 pIf->data.compilerFlags.push_back ( pCompilerFlag );
432 else
433 non_if_data.compilerFlags.push_back ( pCompilerFlag );
434 subs_invalid = true;
435 }
436 else if ( e.name == "linkerflag" )
437 {
438 linkerFlags.push_back ( new LinkerFlag ( project, this, e ) );
439 subs_invalid = true;
440 }
441 else if ( e.name == "component" )
442 {
443 stubbedComponents.push_back ( new StubbedComponent ( this, e ) );
444 subs_invalid = false;
445 }
446 else if ( e.name == "property" )
447 {
448 throw InvalidBuildFileException (
449 e.location,
450 "<property> is not a valid sub-element of <module>" );
451 }
452 else if ( e.name == "bootstrap" )
453 {
454 bootstrap = new Bootstrap ( project, this, e );
455 subs_invalid = true;
456 }
457 else if ( e.name == "pch" )
458 {
459 if ( pIf )
460 throw InvalidBuildFileException (
461 e.location,
462 "<pch> is not a valid sub-element of <if>" );
463 if ( pch )
464 throw InvalidBuildFileException (
465 e.location,
466 "Only one <pch> is valid per module" );
467 pch = new PchFile (
468 e, *this, File ( FixSeparator ( path + CSEP + e.value ), false, "", true ) );
469 subs_invalid = true;
470 }
471 if ( subs_invalid && e.subElements.size() > 0 )
472 throw InvalidBuildFileException (
473 e.location,
474 "<%s> cannot have sub-elements",
475 e.name.c_str() );
476 for ( size_t i = 0; i < e.subElements.size (); i++ )
477 ProcessXMLSubElement ( *e.subElements[i], subpath, pIf );
478 }
479
480 ModuleType
481 Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
482 {
483 if ( attribute.value == "buildtool" )
484 return BuildTool;
485 if ( attribute.value == "staticlibrary" )
486 return StaticLibrary;
487 if ( attribute.value == "objectlibrary" )
488 return ObjectLibrary;
489 if ( attribute.value == "kernel" )
490 return Kernel;
491 if ( attribute.value == "kernelmodedll" )
492 return KernelModeDLL;
493 if ( attribute.value == "kernelmodedriver" )
494 return KernelModeDriver;
495 if ( attribute.value == "nativedll" )
496 return NativeDLL;
497 if ( attribute.value == "nativecui" )
498 return NativeCUI;
499 if ( attribute.value == "win32dll" )
500 return Win32DLL;
501 if ( attribute.value == "win32cui" )
502 return Win32CUI;
503 if ( attribute.value == "win32gui" )
504 return Win32GUI;
505 if ( attribute.value == "bootloader" )
506 return BootLoader;
507 if ( attribute.value == "bootsector" )
508 return BootSector;
509 if ( attribute.value == "iso" )
510 return Iso;
511 if ( attribute.value == "liveiso" )
512 return LiveIso;
513 if ( attribute.value == "test" )
514 return Test;
515 if ( attribute.value == "rpcserver" )
516 return RpcServer;
517 if ( attribute.value == "rpcclient" )
518 return RpcClient;
519 throw InvalidAttributeValueException ( location,
520 attribute.name,
521 attribute.value );
522 }
523
524 string
525 Module::GetDefaultModuleExtension () const
526 {
527 switch (type)
528 {
529 case BuildTool:
530 return EXEPOSTFIX;
531 case StaticLibrary:
532 return ".a";
533 case ObjectLibrary:
534 return ".o";
535 case Kernel:
536 case NativeCUI:
537 case Win32CUI:
538 case Win32GUI:
539 return ".exe";
540 case KernelModeDLL:
541 case NativeDLL:
542 case Win32DLL:
543 return ".dll";
544 case KernelModeDriver:
545 case BootLoader:
546 return ".sys";
547 case BootSector:
548 return ".o";
549 case Iso:
550 case LiveIso:
551 return ".iso";
552 case Test:
553 return ".exe";
554 case RpcServer:
555 return ".o";
556 case RpcClient:
557 return ".o";
558 }
559 throw InvalidOperationException ( __FILE__,
560 __LINE__ );
561 }
562
563 string
564 Module::GetDefaultModuleEntrypoint () const
565 {
566 switch ( type )
567 {
568 case Kernel:
569 return "_NtProcessStartup";
570 case KernelModeDLL:
571 return "_DriverEntry@8";
572 case NativeDLL:
573 return "_DllMainCRTStartup@12";
574 case NativeCUI:
575 return "_NtProcessStartup@4";
576 case Win32DLL:
577 return "_DllMain@12";
578 case Win32CUI:
579 case Test:
580 return "_mainCRTStartup";
581 case Win32GUI:
582 return "_WinMainCRTStartup";
583 case KernelModeDriver:
584 return "_DriverEntry@8";
585 case BuildTool:
586 case StaticLibrary:
587 case ObjectLibrary:
588 case BootLoader:
589 case BootSector:
590 case Iso:
591 case LiveIso:
592 case RpcServer:
593 case RpcClient:
594 return "";
595 }
596 throw InvalidOperationException ( __FILE__,
597 __LINE__ );
598 }
599
600 string
601 Module::GetDefaultModuleBaseaddress () const
602 {
603 switch ( type )
604 {
605 case Kernel:
606 return "0x80000000";
607 case Win32DLL:
608 return "0x10000000";
609 case NativeDLL:
610 case NativeCUI:
611 case Win32CUI:
612 case Test:
613 return "0x00400000";
614 case Win32GUI:
615 return "0x00400000";
616 case KernelModeDLL:
617 case KernelModeDriver:
618 return "0x00010000";
619 case BuildTool:
620 case StaticLibrary:
621 case ObjectLibrary:
622 case BootLoader:
623 case BootSector:
624 case Iso:
625 case LiveIso:
626 case RpcServer:
627 case RpcClient:
628 return "";
629 }
630 throw InvalidOperationException ( __FILE__,
631 __LINE__ );
632 }
633
634 bool
635 Module::HasImportLibrary () const
636 {
637 return importLibrary != NULL;
638 }
639
640 bool
641 Module::IsDLL () const
642 {
643 switch ( type )
644 {
645 case Kernel:
646 case KernelModeDLL:
647 case NativeDLL:
648 case Win32DLL:
649 case KernelModeDriver:
650 return true;
651 case NativeCUI:
652 case Win32CUI:
653 case Test:
654 case Win32GUI:
655 case BuildTool:
656 case StaticLibrary:
657 case ObjectLibrary:
658 case BootLoader:
659 case BootSector:
660 case Iso:
661 case LiveIso:
662 case RpcServer:
663 case RpcClient:
664 return false;
665 }
666 throw InvalidOperationException ( __FILE__,
667 __LINE__ );
668 }
669
670 bool
671 Module::GenerateInOutputTree () const
672 {
673 switch ( type )
674 {
675 case Kernel:
676 case KernelModeDLL:
677 case NativeDLL:
678 case Win32DLL:
679 case KernelModeDriver:
680 case NativeCUI:
681 case Win32CUI:
682 case Test:
683 case Win32GUI:
684 case BuildTool:
685 case BootLoader:
686 case BootSector:
687 case Iso:
688 case LiveIso:
689 return true;
690 case StaticLibrary:
691 case ObjectLibrary:
692 case RpcServer:
693 case RpcClient:
694 return false;
695 }
696 throw InvalidOperationException ( __FILE__,
697 __LINE__ );
698 }
699
700 string
701 Module::GetTargetName () const
702 {
703 return name + extension;
704 }
705
706 string
707 Module::GetDependencyPath () const
708 {
709 if ( HasImportLibrary () )
710 return ReplaceExtension ( GetPathWithPrefix ( "lib" ), ".a" );
711 else
712 return GetPath();
713 }
714
715 string
716 Module::GetBasePath () const
717 {
718 return path;
719 }
720
721 string
722 Module::GetPath () const
723 {
724 if ( path.length() > 0 )
725 return path + CSEP + GetTargetName ();
726 else
727 return GetTargetName ();
728 }
729
730 string
731 Module::GetPathWithPrefix ( const string& prefix ) const
732 {
733 return path + CSEP + prefix + GetTargetName ();
734 }
735
736 string
737 Module::GetInvocationTarget ( const int index ) const
738 {
739 return ssprintf ( "%s_invoke_%d",
740 name.c_str (),
741 index );
742 }
743
744 bool
745 Module::HasFileWithExtension (
746 const IfableData& data,
747 const std::string& extension ) const
748 {
749 size_t i;
750 for ( i = 0; i < data.files.size (); i++ )
751 {
752 File& file = *data.files[i];
753 string file_ext = GetExtension ( file.name );
754 if ( !stricmp ( file_ext.c_str (), extension.c_str () ) )
755 return true;
756 }
757 for ( i = 0; i < data.ifs.size (); i++ )
758 {
759 if ( HasFileWithExtension ( data.ifs[i]->data, extension ) )
760 return true;
761 }
762 return false;
763 }
764
765 void
766 Module::InvokeModule () const
767 {
768 for ( size_t i = 0; i < invocations.size (); i++ )
769 {
770 Invoke& invoke = *invocations[i];
771 string command = invoke.invokeModule->GetPath () + " " + invoke.GetParameters ();
772 printf ( "Executing '%s'\n\n", command.c_str () );
773 int exitcode = system ( command.c_str () );
774 if ( exitcode != 0 )
775 throw InvocationFailedException ( command,
776 exitcode );
777 }
778 }
779
780
781 File::File ( const string& _name, bool _first,
782 std::string _switches,
783 bool _isPreCompiledHeader )
784 : name(_name),
785 first(_first),
786 switches(_switches),
787 isPreCompiledHeader(_isPreCompiledHeader)
788 {
789 }
790
791 void
792 File::ProcessXML()
793 {
794 }
795
796 bool
797 File::IsGeneratedFile () const
798 {
799 string extension = GetExtension ( name );
800 return ( extension == ".spec" || extension == ".SPEC" );
801 }
802
803
804 Library::Library ( const XMLElement& _node,
805 const Module& _module,
806 const string& _name )
807 : node(_node),
808 module(_module),
809 name(_name),
810 imported_module(_module.project.LocateModule(_name))
811 {
812 if ( module.name == name )
813 throw InvalidBuildFileException (
814 node.location,
815 "module '%s' cannot link against itself",
816 name.c_str() );
817 if ( !imported_module )
818 throw InvalidBuildFileException (
819 node.location,
820 "module '%s' trying to import non-existant module '%s'",
821 module.name.c_str(),
822 name.c_str() );
823 }
824
825 void
826 Library::ProcessXML()
827 {
828 if ( !module.project.LocateModule ( name ) )
829 throw InvalidBuildFileException (
830 node.location,
831 "module '%s' is trying to link against non-existant module '%s'",
832 module.name.c_str(),
833 name.c_str() );
834 }
835
836
837 Invoke::Invoke ( const XMLElement& _node,
838 const Module& _module )
839 : node (_node),
840 module (_module)
841 {
842 }
843
844 void
845 Invoke::ProcessXML()
846 {
847 const XMLAttribute* att = node.GetAttribute ( "module", false );
848 if (att == NULL)
849 invokeModule = &module;
850 else
851 {
852 invokeModule = module.project.LocateModule ( att->value );
853 if ( invokeModule == NULL )
854 throw InvalidBuildFileException (
855 node.location,
856 "module '%s' is trying to invoke non-existant module '%s'",
857 module.name.c_str(),
858 att->value.c_str() );
859 }
860
861 for ( size_t i = 0; i < node.subElements.size (); i++ )
862 ProcessXMLSubElement ( *node.subElements[i] );
863 }
864
865 void
866 Invoke::ProcessXMLSubElement ( const XMLElement& e )
867 {
868 bool subs_invalid = false;
869 if ( e.name == "input" )
870 {
871 for ( size_t i = 0; i < e.subElements.size (); i++ )
872 ProcessXMLSubElementInput ( *e.subElements[i] );
873 }
874 else if ( e.name == "output" )
875 {
876 for ( size_t i = 0; i < e.subElements.size (); i++ )
877 ProcessXMLSubElementOutput ( *e.subElements[i] );
878 }
879 if ( subs_invalid && e.subElements.size() > 0 )
880 throw InvalidBuildFileException ( e.location,
881 "<%s> cannot have sub-elements",
882 e.name.c_str() );
883 }
884
885 void
886 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
887 {
888 bool subs_invalid = false;
889 if ( e.name == "inputfile" && e.value.size () > 0 )
890 {
891 input.push_back ( new InvokeFile ( e, FixSeparator ( module.path + CSEP + e.value ) ) );
892 subs_invalid = true;
893 }
894 if ( subs_invalid && e.subElements.size() > 0 )
895 throw InvalidBuildFileException ( e.location,
896 "<%s> cannot have sub-elements",
897 e.name.c_str() );
898 }
899
900 void
901 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
902 {
903 bool subs_invalid = false;
904 if ( e.name == "outputfile" && e.value.size () > 0 )
905 {
906 output.push_back ( new InvokeFile ( e, FixSeparator ( module.path + CSEP + e.value ) ) );
907 subs_invalid = true;
908 }
909 if ( subs_invalid && e.subElements.size() > 0 )
910 throw InvalidBuildFileException (
911 e.location,
912 "<%s> cannot have sub-elements",
913 e.name.c_str() );
914 }
915
916 void
917 Invoke::GetTargets ( string_list& targets ) const
918 {
919 for ( size_t i = 0; i < output.size (); i++ )
920 {
921 InvokeFile& file = *output[i];
922 targets.push_back ( NormalizeFilename ( file.name ) );
923 }
924 }
925
926 string
927 Invoke::GetParameters () const
928 {
929 string parameters ( "" );
930 size_t i;
931 for ( i = 0; i < output.size (); i++ )
932 {
933 if ( parameters.length () > 0)
934 parameters += " ";
935 InvokeFile& invokeFile = *output[i];
936 if ( invokeFile.switches.length () > 0 )
937 {
938 parameters += invokeFile.switches + " ";
939 }
940 parameters += invokeFile.name;
941 }
942
943 for ( i = 0; i < input.size (); i++ )
944 {
945 if ( parameters.length () > 0 )
946 parameters += " ";
947 InvokeFile& invokeFile = *input[i];
948 if ( invokeFile.switches.length () > 0 )
949 {
950 parameters += invokeFile.switches;
951 parameters += " ";
952 }
953 parameters += invokeFile.name ;
954 }
955
956 return parameters;
957 }
958
959
960 InvokeFile::InvokeFile ( const XMLElement& _node,
961 const string& _name )
962 : node (_node),
963 name (_name)
964 {
965 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
966 if (att != NULL)
967 switches = att->value;
968 else
969 switches = "";
970 }
971
972 void
973 InvokeFile::ProcessXML()
974 {
975 }
976
977
978 Dependency::Dependency ( const XMLElement& _node,
979 const Module& _module )
980 : node (_node),
981 module (_module),
982 dependencyModule (NULL)
983 {
984 }
985
986 void
987 Dependency::ProcessXML()
988 {
989 dependencyModule = module.project.LocateModule ( node.value );
990 if ( dependencyModule == NULL )
991 throw InvalidBuildFileException ( node.location,
992 "module '%s' depend on non-existant module '%s'",
993 module.name.c_str(),
994 node.value.c_str() );
995 }
996
997
998 ImportLibrary::ImportLibrary ( const XMLElement& _node,
999 const Module& _module )
1000 : node (_node),
1001 module (_module)
1002 {
1003 const XMLAttribute* att = _node.GetAttribute ( "basename", false );
1004 if (att != NULL)
1005 basename = att->value;
1006 else
1007 basename = module.name;
1008
1009 att = _node.GetAttribute ( "definition", true );
1010 assert (att);
1011 definition = FixSeparator(att->value);
1012 }
1013
1014
1015 If::If ( const XMLElement& node_,
1016 const Project& project_,
1017 const Module* module_ )
1018 : node(node_), project(project_), module(module_)
1019 {
1020 const XMLAttribute* att;
1021
1022 att = node.GetAttribute ( "property", true );
1023 assert(att);
1024 property = att->value;
1025
1026 att = node.GetAttribute ( "value", true );
1027 assert(att);
1028 value = att->value;
1029 }
1030
1031 If::~If ()
1032 {
1033 }
1034
1035 void
1036 If::ProcessXML()
1037 {
1038 }
1039
1040
1041 Property::Property ( const XMLElement& node_,
1042 const Project& project_,
1043 const Module* module_ )
1044 : node(node_), project(project_), module(module_)
1045 {
1046 const XMLAttribute* att;
1047
1048 att = node.GetAttribute ( "name", true );
1049 assert(att);
1050 name = att->value;
1051
1052 att = node.GetAttribute ( "value", true );
1053 assert(att);
1054 value = att->value;
1055 }
1056
1057 void
1058 Property::ProcessXML()
1059 {
1060 }
1061
1062
1063 PchFile::PchFile (
1064 const XMLElement& node_,
1065 const Module& module_,
1066 const File file_ )
1067 : node(node_), module(module_), file(file_)
1068 {
1069 }
1070
1071 void
1072 PchFile::ProcessXML()
1073 {
1074 }