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