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