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