add a 'unicode' property to modules (not yet supported by mingw, need to add a librar...
[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 ( "unicode", false );
252 if ( att != NULL )
253 {
254 const char* p = att->value.c_str();
255 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
256 isUnicode = true;
257 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
258 isUnicode = false;
259 else
260 {
261 throw InvalidAttributeValueException (
262 moduleNode.location,
263 "unicode",
264 att->value );
265 }
266 }
267
268 att = moduleNode.GetAttribute ( "entrypoint", false );
269 if ( att != NULL )
270 entrypoint = att->value;
271 else
272 entrypoint = GetDefaultModuleEntrypoint ();
273
274 att = moduleNode.GetAttribute ( "baseaddress", false );
275 if ( att != NULL )
276 baseaddress = att->value;
277 else
278 baseaddress = GetDefaultModuleBaseaddress ();
279
280 att = moduleNode.GetAttribute ( "mangledsymbols", false );
281 if ( att != NULL )
282 {
283 const char* p = att->value.c_str();
284 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
285 mangledSymbols = true;
286 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
287 mangledSymbols = false;
288 else
289 {
290 throw InvalidAttributeValueException (
291 moduleNode.location,
292 "mangledsymbols",
293 att->value );
294 }
295 }
296 else
297 mangledSymbols = false;
298
299 att = moduleNode.GetAttribute ( "host", false );
300 if ( att != NULL )
301 {
302 const char* p = att->value.c_str();
303 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
304 host = HostTrue;
305 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
306 host = HostFalse;
307 else
308 {
309 throw InvalidAttributeValueException (
310 moduleNode.location,
311 "host",
312 att->value );
313 }
314 }
315
316 att = moduleNode.GetAttribute ( "prefix", false );
317 if ( att != NULL )
318 prefix = att->value;
319
320 att = moduleNode.GetAttribute ( "installbase", false );
321 if ( att != NULL )
322 installBase = att->value;
323 else
324 installBase = "";
325
326 att = moduleNode.GetAttribute ( "installname", false );
327 if ( att != NULL )
328 installName = att->value;
329 else
330 installName = "";
331
332 att = moduleNode.GetAttribute ( "usewrc", false );
333 if ( att != NULL )
334 useWRC = att->value == "true";
335 else
336 useWRC = true;
337
338 att = moduleNode.GetAttribute ( "allowwarnings", false );
339 if ( att == NULL )
340 {
341 att = moduleNode.GetAttribute ( "warnings", false );
342 if ( att != NULL )
343 {
344 printf ( "%s: WARNING: 'warnings' attribute of <module> is deprecated, use 'allowwarnings' instead\n",
345 moduleNode.location.c_str() );
346 }
347 }
348 if ( att != NULL )
349 allowWarnings = att->value == "true";
350 else
351 allowWarnings = false;
352
353 att = moduleNode.GetAttribute ( "aliasof", false );
354 if ( type == Alias && att != NULL )
355 aliasedModuleName = att->value;
356 else
357 aliasedModuleName = "";
358 }
359
360 Module::~Module ()
361 {
362 size_t i;
363 for ( i = 0; i < invocations.size(); i++ )
364 delete invocations[i];
365 for ( i = 0; i < dependencies.size(); i++ )
366 delete dependencies[i];
367 for ( i = 0; i < compilerFlags.size(); i++ )
368 delete compilerFlags[i];
369 for ( i = 0; i < linkerFlags.size(); i++ )
370 delete linkerFlags[i];
371 for ( i = 0; i < stubbedComponents.size(); i++ )
372 delete stubbedComponents[i];
373 if ( pch )
374 delete pch;
375 }
376
377 void
378 Module::ProcessXML()
379 {
380 if ( type == Alias )
381 {
382 if ( aliasedModuleName == name )
383 throw InvalidBuildFileException (
384 node.location,
385 "module '%s' cannot link against itself",
386 name.c_str() );
387 const Module* m = project.LocateModule ( aliasedModuleName );
388 if ( !m )
389 throw InvalidBuildFileException (
390 node.location,
391 "module '%s' trying to alias non-existant module '%s'",
392 name.c_str(),
393 aliasedModuleName.c_str() );
394 }
395
396 size_t i;
397 for ( i = 0; i < node.subElements.size(); i++ )
398 ProcessXMLSubElement ( *node.subElements[i], path );
399 for ( i = 0; i < invocations.size(); i++ )
400 invocations[i]->ProcessXML ();
401 for ( i = 0; i < dependencies.size(); i++ )
402 dependencies[i]->ProcessXML ();
403 for ( i = 0; i < compilerFlags.size(); i++ )
404 compilerFlags[i]->ProcessXML();
405 for ( i = 0; i < linkerFlags.size(); i++ )
406 linkerFlags[i]->ProcessXML();
407 for ( i = 0; i < stubbedComponents.size(); i++ )
408 stubbedComponents[i]->ProcessXML();
409 non_if_data.ProcessXML();
410 if ( pch )
411 pch->ProcessXML();
412 }
413
414 void
415 Module::ProcessXMLSubElement ( const XMLElement& e,
416 const string& path,
417 If* pIf /*= NULL*/ )
418 {
419 bool subs_invalid = false;
420 string subpath ( path );
421 if ( e.name == "file" && e.value.size () > 0 )
422 {
423 bool first = false;
424 const XMLAttribute* att = e.GetAttribute ( "first", false );
425 if ( att != NULL )
426 {
427 if ( !stricmp ( att->value.c_str(), "true" ) )
428 first = true;
429 else if ( stricmp ( att->value.c_str(), "false" ) )
430 throw InvalidBuildFileException (
431 e.location,
432 "attribute 'first' of <file> element can only be 'true' or 'false'" );
433 }
434 string switches = "";
435 att = e.GetAttribute ( "switches", false );
436 if ( att != NULL )
437 switches = att->value;
438 if ( !cplusplus )
439 {
440 // check for c++ file
441 string ext = GetExtension ( e.value );
442 if ( !stricmp ( ext.c_str(), ".cpp" ) )
443 cplusplus = true;
444 else if ( !stricmp ( ext.c_str(), ".cc" ) )
445 cplusplus = true;
446 else if ( !stricmp ( ext.c_str(), ".cxx" ) )
447 cplusplus = true;
448 }
449 File* pFile = new File ( FixSeparator ( path + CSEP + e.value ),
450 first,
451 switches,
452 false );
453 if ( pIf )
454 pIf->data.files.push_back ( pFile );
455 else
456 non_if_data.files.push_back ( pFile );
457 subs_invalid = true;
458 }
459 else if ( e.name == "library" && e.value.size () )
460 {
461 Library* pLibrary = new Library ( e, *this, e.value );
462 if ( pIf )
463 pIf->data.libraries.push_back ( pLibrary );
464 else
465 non_if_data.libraries.push_back ( pLibrary );
466 subs_invalid = true;
467 }
468 else if ( e.name == "directory" )
469 {
470 const XMLAttribute* att = e.GetAttribute ( "name", true );
471 assert(att);
472 subpath = GetSubPath ( e.location, path, att->value );
473 }
474 else if ( e.name == "include" )
475 {
476 Include* include = new Include ( project, this, &e );
477 if ( pIf )
478 pIf->data.includes.push_back ( include );
479 else
480 non_if_data.includes.push_back ( include );
481 subs_invalid = true;
482 }
483 else if ( e.name == "define" )
484 {
485 Define* pDefine = new Define ( project, this, e );
486 if ( pIf )
487 pIf->data.defines.push_back ( pDefine );
488 else
489 non_if_data.defines.push_back ( pDefine );
490 subs_invalid = true;
491 }
492 else if ( e.name == "invoke" )
493 {
494 if ( pIf )
495 throw InvalidBuildFileException (
496 e.location,
497 "<invoke> is not a valid sub-element of <if>" );
498 invocations.push_back ( new Invoke ( e, *this ) );
499 subs_invalid = false;
500 }
501 else if ( e.name == "dependency" )
502 {
503 if ( pIf )
504 throw InvalidBuildFileException (
505 e.location,
506 "<dependency> is not a valid sub-element of <if>" );
507 dependencies.push_back ( new Dependency ( e, *this ) );
508 subs_invalid = true;
509 }
510 else if ( e.name == "importlibrary" )
511 {
512 if ( pIf )
513 throw InvalidBuildFileException (
514 e.location,
515 "<importlibrary> is not a valid sub-element of <if>" );
516 if ( importLibrary )
517 throw InvalidBuildFileException (
518 e.location,
519 "Only one <importlibrary> is valid per module" );
520 importLibrary = new ImportLibrary ( e, *this );
521 subs_invalid = true;
522 }
523 else if ( e.name == "if" )
524 {
525 If* pOldIf = pIf;
526 pIf = new If ( e, project, this );
527 if ( pOldIf )
528 pOldIf->data.ifs.push_back ( pIf );
529 else
530 non_if_data.ifs.push_back ( pIf );
531 subs_invalid = false;
532 }
533 else if ( e.name == "ifnot" )
534 {
535 If* pOldIf = pIf;
536 pIf = new If ( e, project, this, true );
537 if ( pOldIf )
538 pOldIf->data.ifs.push_back ( pIf );
539 else
540 non_if_data.ifs.push_back ( pIf );
541 subs_invalid = false;
542 }
543 else if ( e.name == "compilerflag" )
544 {
545 CompilerFlag* pCompilerFlag = new CompilerFlag ( project, this, e );
546 if ( pIf )
547 pIf->data.compilerFlags.push_back ( pCompilerFlag );
548 else
549 non_if_data.compilerFlags.push_back ( pCompilerFlag );
550 subs_invalid = true;
551 }
552 else if ( e.name == "linkerflag" )
553 {
554 linkerFlags.push_back ( new LinkerFlag ( project, this, e ) );
555 subs_invalid = true;
556 }
557 else if ( e.name == "component" )
558 {
559 stubbedComponents.push_back ( new StubbedComponent ( this, e ) );
560 subs_invalid = false;
561 }
562 else if ( e.name == "property" )
563 {
564 throw InvalidBuildFileException (
565 e.location,
566 "<property> is not a valid sub-element of <module>" );
567 }
568 else if ( e.name == "bootstrap" )
569 {
570 bootstrap = new Bootstrap ( project, this, e );
571 subs_invalid = true;
572 }
573 else if ( e.name == "pch" )
574 {
575 if ( pIf )
576 throw InvalidBuildFileException (
577 e.location,
578 "<pch> is not a valid sub-element of <if>" );
579 if ( pch )
580 throw InvalidBuildFileException (
581 e.location,
582 "Only one <pch> is valid per module" );
583 pch = new PchFile (
584 e, *this, File ( FixSeparator ( path + CSEP + e.value ), false, "", true ) );
585 subs_invalid = true;
586 }
587 if ( subs_invalid && e.subElements.size() > 0 )
588 throw InvalidBuildFileException (
589 e.location,
590 "<%s> cannot have sub-elements",
591 e.name.c_str() );
592 for ( size_t i = 0; i < e.subElements.size (); i++ )
593 ProcessXMLSubElement ( *e.subElements[i], subpath, pIf );
594 }
595
596 ModuleType
597 Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
598 {
599 if ( attribute.value == "buildtool" )
600 return BuildTool;
601 if ( attribute.value == "staticlibrary" )
602 return StaticLibrary;
603 if ( attribute.value == "objectlibrary" )
604 return ObjectLibrary;
605 if ( attribute.value == "kernel" )
606 return Kernel;
607 if ( attribute.value == "kernelmodedll" )
608 return KernelModeDLL;
609 if ( attribute.value == "kernelmodedriver" )
610 return KernelModeDriver;
611 if ( attribute.value == "nativedll" )
612 return NativeDLL;
613 if ( attribute.value == "nativecui" )
614 return NativeCUI;
615 if ( attribute.value == "win32dll" )
616 return Win32DLL;
617 if ( attribute.value == "win32cui" )
618 return Win32CUI;
619 if ( attribute.value == "win32gui" )
620 return Win32GUI;
621 if ( attribute.value == "bootloader" )
622 return BootLoader;
623 if ( attribute.value == "bootsector" )
624 return BootSector;
625 if ( attribute.value == "iso" )
626 return Iso;
627 if ( attribute.value == "liveiso" )
628 return LiveIso;
629 if ( attribute.value == "test" )
630 return Test;
631 if ( attribute.value == "rpcserver" )
632 return RpcServer;
633 if ( attribute.value == "rpcclient" )
634 return RpcClient;
635 if ( attribute.value == "alias" )
636 return Alias;
637 throw InvalidAttributeValueException ( location,
638 attribute.name,
639 attribute.value );
640 }
641
642 string
643 Module::GetDefaultModuleExtension () const
644 {
645 switch (type)
646 {
647 case BuildTool:
648 return EXEPOSTFIX;
649 case StaticLibrary:
650 return ".a";
651 case ObjectLibrary:
652 return ".o";
653 case Kernel:
654 case NativeCUI:
655 case Win32CUI:
656 case Win32GUI:
657 return ".exe";
658 case KernelModeDLL:
659 case NativeDLL:
660 case Win32DLL:
661 return ".dll";
662 case KernelModeDriver:
663 case BootLoader:
664 return ".sys";
665 case BootSector:
666 return ".o";
667 case Iso:
668 case LiveIso:
669 return ".iso";
670 case Test:
671 return ".exe";
672 case RpcServer:
673 return ".o";
674 case RpcClient:
675 return ".o";
676 case Alias:
677 return "";
678 }
679 throw InvalidOperationException ( __FILE__,
680 __LINE__ );
681 }
682
683 string
684 Module::GetDefaultModuleEntrypoint () const
685 {
686 switch ( type )
687 {
688 case Kernel:
689 return "_NtProcessStartup";
690 case KernelModeDLL:
691 return "_DriverEntry@8";
692 case NativeDLL:
693 return "_DllMainCRTStartup@12";
694 case NativeCUI:
695 return "_NtProcessStartup@4";
696 case Win32DLL:
697 return "_DllMain@12";
698 case Win32CUI:
699 case Test:
700 if ( isUnicode )
701 return "_wmainCRTStartup";
702 else
703 return "_mainCRTStartup";
704 case Win32GUI:
705 if ( isUnicode )
706 return "_wWinMainCRTStartup";
707 else
708 return "_WinMainCRTStartup";
709 case KernelModeDriver:
710 return "_DriverEntry@8";
711 case BuildTool:
712 case StaticLibrary:
713 case ObjectLibrary:
714 case BootLoader:
715 case BootSector:
716 case Iso:
717 case LiveIso:
718 case RpcServer:
719 case RpcClient:
720 case Alias:
721 return "";
722 }
723 throw InvalidOperationException ( __FILE__,
724 __LINE__ );
725 }
726
727 string
728 Module::GetDefaultModuleBaseaddress () const
729 {
730 switch ( type )
731 {
732 case Kernel:
733 return "0x80000000";
734 case Win32DLL:
735 return "0x10000000";
736 case NativeDLL:
737 case NativeCUI:
738 case Win32CUI:
739 case Test:
740 return "0x00400000";
741 case Win32GUI:
742 return "0x00400000";
743 case KernelModeDLL:
744 case KernelModeDriver:
745 return "0x00010000";
746 case BuildTool:
747 case StaticLibrary:
748 case ObjectLibrary:
749 case BootLoader:
750 case BootSector:
751 case Iso:
752 case LiveIso:
753 case RpcServer:
754 case RpcClient:
755 case Alias:
756 return "";
757 }
758 throw InvalidOperationException ( __FILE__,
759 __LINE__ );
760 }
761
762 bool
763 Module::HasImportLibrary () const
764 {
765 return importLibrary != NULL;
766 }
767
768 bool
769 Module::IsDLL () const
770 {
771 switch ( type )
772 {
773 case Kernel:
774 case KernelModeDLL:
775 case NativeDLL:
776 case Win32DLL:
777 case KernelModeDriver:
778 return true;
779 case NativeCUI:
780 case Win32CUI:
781 case Test:
782 case Win32GUI:
783 case BuildTool:
784 case StaticLibrary:
785 case ObjectLibrary:
786 case BootLoader:
787 case BootSector:
788 case Iso:
789 case LiveIso:
790 case RpcServer:
791 case RpcClient:
792 case Alias:
793 return false;
794 }
795 throw InvalidOperationException ( __FILE__,
796 __LINE__ );
797 }
798
799 bool
800 Module::GenerateInOutputTree () const
801 {
802 switch ( type )
803 {
804 case Kernel:
805 case KernelModeDLL:
806 case NativeDLL:
807 case Win32DLL:
808 case KernelModeDriver:
809 case NativeCUI:
810 case Win32CUI:
811 case Test:
812 case Win32GUI:
813 case BuildTool:
814 case BootLoader:
815 case BootSector:
816 case Iso:
817 case LiveIso:
818 return true;
819 case StaticLibrary:
820 case ObjectLibrary:
821 case RpcServer:
822 case RpcClient:
823 case Alias:
824 return false;
825 }
826 throw InvalidOperationException ( __FILE__,
827 __LINE__ );
828 }
829
830 string
831 Module::GetTargetName () const
832 {
833 return name + extension;
834 }
835
836 string
837 Module::GetDependencyPath () const
838 {
839 if ( HasImportLibrary () )
840 return ReplaceExtension ( GetPathWithPrefix ( "lib" ), ".a" );
841 else
842 return GetPath();
843 }
844
845 string
846 Module::GetBasePath () const
847 {
848 return path;
849 }
850
851 string
852 Module::GetPath () const
853 {
854 if ( path.length() > 0 )
855 return path + CSEP + GetTargetName ();
856 else
857 return GetTargetName ();
858 }
859
860 string
861 Module::GetPathWithPrefix ( const string& prefix ) const
862 {
863 return path + CSEP + prefix + GetTargetName ();
864 }
865
866 string
867 Module::GetInvocationTarget ( const int index ) const
868 {
869 return ssprintf ( "%s_invoke_%d",
870 name.c_str (),
871 index );
872 }
873
874 bool
875 Module::HasFileWithExtension (
876 const IfableData& data,
877 const std::string& extension ) const
878 {
879 size_t i;
880 for ( i = 0; i < data.files.size (); i++ )
881 {
882 File& file = *data.files[i];
883 string file_ext = GetExtension ( file.name );
884 if ( !stricmp ( file_ext.c_str (), extension.c_str () ) )
885 return true;
886 }
887 for ( i = 0; i < data.ifs.size (); i++ )
888 {
889 if ( HasFileWithExtension ( data.ifs[i]->data, extension ) )
890 return true;
891 }
892 return false;
893 }
894
895 void
896 Module::InvokeModule () const
897 {
898 for ( size_t i = 0; i < invocations.size (); i++ )
899 {
900 Invoke& invoke = *invocations[i];
901 string command = invoke.invokeModule->GetPath () + " " + invoke.GetParameters ();
902 printf ( "Executing '%s'\n\n", command.c_str () );
903 int exitcode = system ( command.c_str () );
904 if ( exitcode != 0 )
905 throw InvocationFailedException ( command,
906 exitcode );
907 }
908 }
909
910
911 File::File ( const string& _name, bool _first,
912 std::string _switches,
913 bool _isPreCompiledHeader )
914 : name(_name),
915 first(_first),
916 switches(_switches),
917 isPreCompiledHeader(_isPreCompiledHeader)
918 {
919 }
920
921 void
922 File::ProcessXML()
923 {
924 }
925
926 bool
927 File::IsGeneratedFile () const
928 {
929 string extension = GetExtension ( name );
930 return ( extension == ".spec" || extension == ".SPEC" );
931 }
932
933
934 Library::Library ( const XMLElement& _node,
935 const Module& _module,
936 const string& _name )
937 : node(_node),
938 module(_module),
939 name(_name),
940 importedModule(_module.project.LocateModule(_name))
941 {
942 if ( module.name == name )
943 throw InvalidBuildFileException (
944 node.location,
945 "module '%s' cannot link against itself",
946 name.c_str() );
947 if ( !importedModule )
948 throw InvalidBuildFileException (
949 node.location,
950 "module '%s' trying to import non-existant module '%s'",
951 module.name.c_str(),
952 name.c_str() );
953 }
954
955 void
956 Library::ProcessXML()
957 {
958 if ( !module.project.LocateModule ( name ) )
959 throw InvalidBuildFileException (
960 node.location,
961 "module '%s' is trying to link against non-existant module '%s'",
962 module.name.c_str(),
963 name.c_str() );
964 }
965
966
967 Invoke::Invoke ( const XMLElement& _node,
968 const Module& _module )
969 : node (_node),
970 module (_module)
971 {
972 }
973
974 void
975 Invoke::ProcessXML()
976 {
977 const XMLAttribute* att = node.GetAttribute ( "module", false );
978 if (att == NULL)
979 invokeModule = &module;
980 else
981 {
982 invokeModule = module.project.LocateModule ( att->value );
983 if ( invokeModule == NULL )
984 throw InvalidBuildFileException (
985 node.location,
986 "module '%s' is trying to invoke non-existant module '%s'",
987 module.name.c_str(),
988 att->value.c_str() );
989 }
990
991 for ( size_t i = 0; i < node.subElements.size (); i++ )
992 ProcessXMLSubElement ( *node.subElements[i] );
993 }
994
995 void
996 Invoke::ProcessXMLSubElement ( const XMLElement& e )
997 {
998 bool subs_invalid = false;
999 if ( e.name == "input" )
1000 {
1001 for ( size_t i = 0; i < e.subElements.size (); i++ )
1002 ProcessXMLSubElementInput ( *e.subElements[i] );
1003 }
1004 else if ( e.name == "output" )
1005 {
1006 for ( size_t i = 0; i < e.subElements.size (); i++ )
1007 ProcessXMLSubElementOutput ( *e.subElements[i] );
1008 }
1009 if ( subs_invalid && e.subElements.size() > 0 )
1010 throw InvalidBuildFileException ( e.location,
1011 "<%s> cannot have sub-elements",
1012 e.name.c_str() );
1013 }
1014
1015 void
1016 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
1017 {
1018 bool subs_invalid = false;
1019 if ( e.name == "inputfile" && e.value.size () > 0 )
1020 {
1021 input.push_back ( new InvokeFile ( e, FixSeparator ( module.path + CSEP + e.value ) ) );
1022 subs_invalid = true;
1023 }
1024 if ( subs_invalid && e.subElements.size() > 0 )
1025 throw InvalidBuildFileException ( e.location,
1026 "<%s> cannot have sub-elements",
1027 e.name.c_str() );
1028 }
1029
1030 void
1031 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
1032 {
1033 bool subs_invalid = false;
1034 if ( e.name == "outputfile" && e.value.size () > 0 )
1035 {
1036 output.push_back ( new InvokeFile ( e, FixSeparator ( module.path + CSEP + e.value ) ) );
1037 subs_invalid = true;
1038 }
1039 if ( subs_invalid && e.subElements.size() > 0 )
1040 throw InvalidBuildFileException (
1041 e.location,
1042 "<%s> cannot have sub-elements",
1043 e.name.c_str() );
1044 }
1045
1046 void
1047 Invoke::GetTargets ( string_list& targets ) const
1048 {
1049 for ( size_t i = 0; i < output.size (); i++ )
1050 {
1051 InvokeFile& file = *output[i];
1052 targets.push_back ( NormalizeFilename ( file.name ) );
1053 }
1054 }
1055
1056 string
1057 Invoke::GetParameters () const
1058 {
1059 string parameters ( "" );
1060 size_t i;
1061 for ( i = 0; i < output.size (); i++ )
1062 {
1063 if ( parameters.length () > 0)
1064 parameters += " ";
1065 InvokeFile& invokeFile = *output[i];
1066 if ( invokeFile.switches.length () > 0 )
1067 {
1068 parameters += invokeFile.switches + " ";
1069 }
1070 parameters += invokeFile.name;
1071 }
1072
1073 for ( i = 0; i < input.size (); i++ )
1074 {
1075 if ( parameters.length () > 0 )
1076 parameters += " ";
1077 InvokeFile& invokeFile = *input[i];
1078 if ( invokeFile.switches.length () > 0 )
1079 {
1080 parameters += invokeFile.switches;
1081 parameters += " ";
1082 }
1083 parameters += invokeFile.name ;
1084 }
1085
1086 return parameters;
1087 }
1088
1089
1090 InvokeFile::InvokeFile ( const XMLElement& _node,
1091 const string& _name )
1092 : node (_node),
1093 name (_name)
1094 {
1095 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
1096 if (att != NULL)
1097 switches = att->value;
1098 else
1099 switches = "";
1100 }
1101
1102 void
1103 InvokeFile::ProcessXML()
1104 {
1105 }
1106
1107
1108 Dependency::Dependency ( const XMLElement& _node,
1109 const Module& _module )
1110 : node (_node),
1111 module (_module),
1112 dependencyModule (NULL)
1113 {
1114 }
1115
1116 void
1117 Dependency::ProcessXML()
1118 {
1119 dependencyModule = module.project.LocateModule ( node.value );
1120 if ( dependencyModule == NULL )
1121 throw InvalidBuildFileException ( node.location,
1122 "module '%s' depend on non-existant module '%s'",
1123 module.name.c_str(),
1124 node.value.c_str() );
1125 }
1126
1127
1128 ImportLibrary::ImportLibrary ( const XMLElement& _node,
1129 const Module& _module )
1130 : node (_node),
1131 module (_module)
1132 {
1133 const XMLAttribute* att = _node.GetAttribute ( "basename", false );
1134 if (att != NULL)
1135 basename = att->value;
1136 else
1137 basename = module.name;
1138
1139 att = _node.GetAttribute ( "definition", true );
1140 assert (att);
1141 definition = FixSeparator(att->value);
1142 }
1143
1144
1145 If::If ( const XMLElement& node_,
1146 const Project& project_,
1147 const Module* module_,
1148 const bool negated_ )
1149 : node(node_), project(project_), module(module_), negated(negated_)
1150 {
1151 const XMLAttribute* att;
1152
1153 att = node.GetAttribute ( "property", true );
1154 assert(att);
1155 property = att->value;
1156
1157 att = node.GetAttribute ( "value", true );
1158 assert(att);
1159 value = att->value;
1160 }
1161
1162 If::~If ()
1163 {
1164 }
1165
1166 void
1167 If::ProcessXML()
1168 {
1169 }
1170
1171
1172 Property::Property ( const XMLElement& node_,
1173 const Project& project_,
1174 const Module* module_ )
1175 : node(node_), project(project_), module(module_)
1176 {
1177 const XMLAttribute* att;
1178
1179 att = node.GetAttribute ( "name", true );
1180 assert(att);
1181 name = att->value;
1182
1183 att = node.GetAttribute ( "value", true );
1184 assert(att);
1185 value = att->value;
1186 }
1187
1188 void
1189 Property::ProcessXML()
1190 {
1191 }
1192
1193
1194 PchFile::PchFile (
1195 const XMLElement& node_,
1196 const Module& module_,
1197 const File file_ )
1198 : node(node_), module(module_), file(file_)
1199 {
1200 }
1201
1202 void
1203 PchFile::ProcessXML()
1204 {
1205 }