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