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