8ada94d8da1a5857f7d84384db72783286248b06
[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 < includes.size (); i++ )
186 delete includes[i];
187 for ( i = 0; i < defines.size (); i++ )
188 delete defines[i];
189 for ( i = 0; i < libraries.size (); i++ )
190 delete libraries[i];
191 for ( i = 0; i < properties.size (); i++ )
192 delete properties[i];
193 for ( i = 0; i < compilerFlags.size (); i++ )
194 delete compilerFlags[i];
195 for ( i = 0; i < ifs.size (); i++ )
196 delete ifs[i];
197 for ( i = 0; i < compilationUnits.size (); i++ )
198 delete compilationUnits[i];
199 }
200
201 void IfableData::ProcessXML ()
202 {
203 size_t i;
204 for ( i = 0; i < includes.size (); i++ )
205 includes[i]->ProcessXML ();
206 for ( i = 0; i < defines.size (); i++ )
207 defines[i]->ProcessXML ();
208 for ( i = 0; i < libraries.size (); i++ )
209 libraries[i]->ProcessXML ();
210 for ( i = 0; i < properties.size(); i++ )
211 properties[i]->ProcessXML ();
212 for ( i = 0; i < compilerFlags.size(); i++ )
213 compilerFlags[i]->ProcessXML ();
214 for ( i = 0; i < ifs.size (); i++ )
215 ifs[i]->ProcessXML ();
216 for ( i = 0; i < compilationUnits.size (); i++ )
217 compilationUnits[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 {
417 ParseContext parseContext;
418 ProcessXMLSubElement ( *node.subElements[i], path, parseContext );
419 }
420 for ( i = 0; i < invocations.size(); i++ )
421 invocations[i]->ProcessXML ();
422 for ( i = 0; i < dependencies.size(); i++ )
423 dependencies[i]->ProcessXML ();
424 for ( i = 0; i < compilerFlags.size(); i++ )
425 compilerFlags[i]->ProcessXML();
426 for ( i = 0; i < linkerFlags.size(); i++ )
427 linkerFlags[i]->ProcessXML();
428 for ( i = 0; i < stubbedComponents.size(); i++ )
429 stubbedComponents[i]->ProcessXML();
430 non_if_data.ProcessXML();
431 if ( linkerScript )
432 linkerScript->ProcessXML();
433 if ( pch )
434 pch->ProcessXML();
435 }
436
437 void
438 Module::ProcessXMLSubElement ( const XMLElement& e,
439 const string& path,
440 ParseContext& parseContext )
441 {
442 If* pOldIf = parseContext.ifData;
443 bool subs_invalid = false;
444 string subpath ( path );
445 if ( e.name == "file" && e.value.size () > 0 )
446 {
447 bool first = false;
448 const XMLAttribute* att = e.GetAttribute ( "first", false );
449 if ( att != NULL )
450 {
451 if ( !stricmp ( att->value.c_str(), "true" ) )
452 first = true;
453 else if ( stricmp ( att->value.c_str(), "false" ) )
454 throw InvalidBuildFileException (
455 e.location,
456 "attribute 'first' of <file> element can only be 'true' or 'false'" );
457 }
458 string switches = "";
459 att = e.GetAttribute ( "switches", false );
460 if ( att != NULL )
461 switches = att->value;
462 if ( !cplusplus )
463 {
464 // check for c++ file
465 string ext = GetExtension ( e.value );
466 if ( !stricmp ( ext.c_str(), ".cpp" ) )
467 cplusplus = true;
468 else if ( !stricmp ( ext.c_str(), ".cc" ) )
469 cplusplus = true;
470 else if ( !stricmp ( ext.c_str(), ".cxx" ) )
471 cplusplus = true;
472 }
473 File* pFile = new File ( FixSeparator ( path + cSep + e.value ),
474 first,
475 switches,
476 false );
477 if ( parseContext.compilationUnit )
478 parseContext.compilationUnit->files.push_back ( pFile );
479 else
480 {
481 CompilationUnit* pCompilationUnit = new CompilationUnit ( pFile );
482 if ( parseContext.ifData )
483 parseContext.ifData->data.compilationUnits.push_back ( pCompilationUnit );
484 else
485 non_if_data.compilationUnits.push_back ( pCompilationUnit );
486 }
487 if ( parseContext.ifData )
488 parseContext.ifData->data.files.push_back ( pFile );
489 else
490 non_if_data.files.push_back ( pFile );
491 subs_invalid = true;
492 }
493 else if ( e.name == "library" && e.value.size () )
494 {
495 Library* pLibrary = new Library ( e, *this, e.value );
496 if ( parseContext.ifData )
497 parseContext.ifData->data.libraries.push_back ( pLibrary );
498 else
499 non_if_data.libraries.push_back ( pLibrary );
500 subs_invalid = true;
501 }
502 else if ( e.name == "directory" )
503 {
504 const XMLAttribute* att = e.GetAttribute ( "name", true );
505 assert(att);
506 subpath = GetSubPath ( e.location, path, att->value );
507 }
508 else if ( e.name == "include" )
509 {
510 Include* include = new Include ( project, this, &e );
511 if ( parseContext.ifData )
512 parseContext.ifData->data.includes.push_back ( include );
513 else
514 non_if_data.includes.push_back ( include );
515 subs_invalid = true;
516 }
517 else if ( e.name == "define" )
518 {
519 Define* pDefine = new Define ( project, this, e );
520 if ( parseContext.ifData )
521 parseContext.ifData->data.defines.push_back ( pDefine );
522 else
523 non_if_data.defines.push_back ( pDefine );
524 subs_invalid = true;
525 }
526 else if ( e.name == "invoke" )
527 {
528 if ( parseContext.ifData )
529 throw InvalidBuildFileException (
530 e.location,
531 "<invoke> is not a valid sub-element of <if>" );
532 invocations.push_back ( new Invoke ( e, *this ) );
533 subs_invalid = false;
534 }
535 else if ( e.name == "dependency" )
536 {
537 if ( parseContext.ifData )
538 throw InvalidBuildFileException (
539 e.location,
540 "<dependency> is not a valid sub-element of <if>" );
541 dependencies.push_back ( new Dependency ( e, *this ) );
542 subs_invalid = true;
543 }
544 else if ( e.name == "importlibrary" )
545 {
546 if ( parseContext.ifData )
547 throw InvalidBuildFileException (
548 e.location,
549 "<importlibrary> is not a valid sub-element of <if>" );
550 if ( importLibrary )
551 throw InvalidBuildFileException (
552 e.location,
553 "Only one <importlibrary> is valid per module" );
554 importLibrary = new ImportLibrary ( e, *this );
555 subs_invalid = true;
556 }
557 else if ( e.name == "if" )
558 {
559 parseContext.ifData = new If ( e, project, this );
560 if ( pOldIf )
561 pOldIf->data.ifs.push_back ( parseContext.ifData );
562 else
563 non_if_data.ifs.push_back ( parseContext.ifData );
564 subs_invalid = false;
565 }
566 else if ( e.name == "ifnot" )
567 {
568 parseContext.ifData = new If ( e, project, this, true );
569 if ( pOldIf )
570 pOldIf->data.ifs.push_back ( parseContext.ifData );
571 else
572 non_if_data.ifs.push_back ( parseContext.ifData );
573 subs_invalid = false;
574 }
575 else if ( e.name == "compilerflag" )
576 {
577 CompilerFlag* pCompilerFlag = new CompilerFlag ( project, this, e );
578 if ( parseContext.ifData )
579 parseContext.ifData->data.compilerFlags.push_back ( pCompilerFlag );
580 else
581 non_if_data.compilerFlags.push_back ( pCompilerFlag );
582 subs_invalid = true;
583 }
584 else if ( e.name == "linkerflag" )
585 {
586 linkerFlags.push_back ( new LinkerFlag ( project, this, e ) );
587 subs_invalid = true;
588 }
589 else if ( e.name == "linkerscript" )
590 {
591 if ( linkerScript )
592 throw InvalidBuildFileException (
593 e.location,
594 "Only one <linkerscript> is valid per module" );
595 linkerScript = new LinkerScript ( project, this, e );
596 subs_invalid = true;
597 }
598 else if ( e.name == "component" )
599 {
600 stubbedComponents.push_back ( new StubbedComponent ( this, e ) );
601 subs_invalid = false;
602 }
603 else if ( e.name == "property" )
604 {
605 throw InvalidBuildFileException (
606 e.location,
607 "<property> is not a valid sub-element of <module>" );
608 }
609 else if ( e.name == "bootstrap" )
610 {
611 bootstrap = new Bootstrap ( project, this, e );
612 subs_invalid = true;
613 }
614 else if ( e.name == "pch" )
615 {
616 if ( parseContext.ifData )
617 throw InvalidBuildFileException (
618 e.location,
619 "<pch> is not a valid sub-element of <if>" );
620 if ( pch )
621 throw InvalidBuildFileException (
622 e.location,
623 "Only one <pch> is valid per module" );
624 pch = new PchFile (
625 e, *this, File ( FixSeparator ( path + cSep + e.value ), false, "", true ) );
626 subs_invalid = true;
627 }
628 else if ( e.name == "compilationunit" )
629 {
630 CompilationUnit* pCompilationUnit = new CompilationUnit ( &project, this, &e );
631 if ( parseContext.ifData )
632 parseContext.ifData->data.compilationUnits.push_back ( pCompilationUnit );
633 else
634 non_if_data.compilationUnits.push_back ( pCompilationUnit );
635 parseContext.compilationUnit = pCompilationUnit;
636 subs_invalid = false;
637 }
638 if ( subs_invalid && e.subElements.size() > 0 )
639 throw InvalidBuildFileException (
640 e.location,
641 "<%s> cannot have sub-elements",
642 e.name.c_str() );
643 for ( size_t i = 0; i < e.subElements.size (); i++ )
644 ProcessXMLSubElement ( *e.subElements[i], subpath, parseContext );
645 parseContext.ifData = pOldIf;
646 }
647
648 ModuleType
649 Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
650 {
651 if ( attribute.value == "buildtool" )
652 return BuildTool;
653 if ( attribute.value == "staticlibrary" )
654 return StaticLibrary;
655 if ( attribute.value == "objectlibrary" )
656 return ObjectLibrary;
657 if ( attribute.value == "kernel" )
658 return Kernel;
659 if ( attribute.value == "kernelmodedll" )
660 return KernelModeDLL;
661 if ( attribute.value == "kernelmodedriver" )
662 return KernelModeDriver;
663 if ( attribute.value == "nativedll" )
664 return NativeDLL;
665 if ( attribute.value == "nativecui" )
666 return NativeCUI;
667 if ( attribute.value == "win32dll" )
668 return Win32DLL;
669 if ( attribute.value == "win32cui" )
670 return Win32CUI;
671 if ( attribute.value == "win32gui" )
672 return Win32GUI;
673 if ( attribute.value == "bootloader" )
674 return BootLoader;
675 if ( attribute.value == "bootsector" )
676 return BootSector;
677 if ( attribute.value == "iso" )
678 return Iso;
679 if ( attribute.value == "liveiso" )
680 return LiveIso;
681 if ( attribute.value == "test" )
682 return Test;
683 if ( attribute.value == "rpcserver" )
684 return RpcServer;
685 if ( attribute.value == "rpcclient" )
686 return RpcClient;
687 if ( attribute.value == "alias" )
688 return Alias;
689 throw InvalidAttributeValueException ( location,
690 attribute.name,
691 attribute.value );
692 }
693
694 string
695 Module::GetDefaultModuleExtension () const
696 {
697 switch (type)
698 {
699 case BuildTool:
700 return ExePostfix;
701 case StaticLibrary:
702 return ".a";
703 case ObjectLibrary:
704 return ".o";
705 case Kernel:
706 case NativeCUI:
707 case Win32CUI:
708 case Win32GUI:
709 return ".exe";
710 case KernelModeDLL:
711 case NativeDLL:
712 case Win32DLL:
713 return ".dll";
714 case KernelModeDriver:
715 case BootLoader:
716 return ".sys";
717 case BootSector:
718 return ".o";
719 case Iso:
720 case LiveIso:
721 return ".iso";
722 case Test:
723 return ".exe";
724 case RpcServer:
725 return ".o";
726 case RpcClient:
727 return ".o";
728 case Alias:
729 return "";
730 }
731 throw InvalidOperationException ( __FILE__,
732 __LINE__ );
733 }
734
735 string
736 Module::GetDefaultModuleEntrypoint () const
737 {
738 switch ( type )
739 {
740 case Kernel:
741 return "_NtProcessStartup";
742 case KernelModeDLL:
743 return "_DriverEntry@8";
744 case NativeDLL:
745 return "_DllMainCRTStartup@12";
746 case NativeCUI:
747 return "_NtProcessStartup@4";
748 case Win32DLL:
749 return "_DllMain@12";
750 case Win32CUI:
751 case Test:
752 if ( isUnicode )
753 return "_wmainCRTStartup";
754 else
755 return "_mainCRTStartup";
756 case Win32GUI:
757 if ( isUnicode )
758 return "_wWinMainCRTStartup";
759 else
760 return "_WinMainCRTStartup";
761 case KernelModeDriver:
762 return "_DriverEntry@8";
763 case BuildTool:
764 case StaticLibrary:
765 case ObjectLibrary:
766 case BootLoader:
767 case BootSector:
768 case Iso:
769 case LiveIso:
770 case RpcServer:
771 case RpcClient:
772 case Alias:
773 return "";
774 }
775 throw InvalidOperationException ( __FILE__,
776 __LINE__ );
777 }
778
779 string
780 Module::GetDefaultModuleBaseaddress () const
781 {
782 switch ( type )
783 {
784 case Kernel:
785 return "0x80000000";
786 case Win32DLL:
787 return "0x10000000";
788 case NativeDLL:
789 case NativeCUI:
790 case Win32CUI:
791 case Test:
792 return "0x00400000";
793 case Win32GUI:
794 return "0x00400000";
795 case KernelModeDLL:
796 case KernelModeDriver:
797 return "0x00010000";
798 case BuildTool:
799 case StaticLibrary:
800 case ObjectLibrary:
801 case BootLoader:
802 case BootSector:
803 case Iso:
804 case LiveIso:
805 case RpcServer:
806 case RpcClient:
807 case Alias:
808 return "";
809 }
810 throw InvalidOperationException ( __FILE__,
811 __LINE__ );
812 }
813
814 bool
815 Module::HasImportLibrary () const
816 {
817 return importLibrary != NULL;
818 }
819
820 bool
821 Module::IsDLL () const
822 {
823 switch ( type )
824 {
825 case Kernel:
826 case KernelModeDLL:
827 case NativeDLL:
828 case Win32DLL:
829 case KernelModeDriver:
830 return true;
831 case NativeCUI:
832 case Win32CUI:
833 case Test:
834 case Win32GUI:
835 case BuildTool:
836 case StaticLibrary:
837 case ObjectLibrary:
838 case BootLoader:
839 case BootSector:
840 case Iso:
841 case LiveIso:
842 case RpcServer:
843 case RpcClient:
844 case Alias:
845 return false;
846 }
847 throw InvalidOperationException ( __FILE__,
848 __LINE__ );
849 }
850
851 bool
852 Module::GenerateInOutputTree () const
853 {
854 switch ( type )
855 {
856 case Kernel:
857 case KernelModeDLL:
858 case NativeDLL:
859 case Win32DLL:
860 case KernelModeDriver:
861 case NativeCUI:
862 case Win32CUI:
863 case Test:
864 case Win32GUI:
865 case BuildTool:
866 case BootLoader:
867 case BootSector:
868 case Iso:
869 case LiveIso:
870 return true;
871 case StaticLibrary:
872 case ObjectLibrary:
873 case RpcServer:
874 case RpcClient:
875 case Alias:
876 return false;
877 }
878 throw InvalidOperationException ( __FILE__,
879 __LINE__ );
880 }
881
882 string
883 Module::GetTargetName () const
884 {
885 return name + extension;
886 }
887
888 string
889 Module::GetDependencyPath () const
890 {
891 if ( HasImportLibrary () )
892 return ReplaceExtension ( GetPathWithPrefix ( "lib" ), ".a" );
893 else
894 return GetPath();
895 }
896
897 string
898 Module::GetBasePath () const
899 {
900 return path;
901 }
902
903 string
904 Module::GetPath () const
905 {
906 if ( path.length() > 0 )
907 return path + cSep + GetTargetName ();
908 else
909 return GetTargetName ();
910 }
911
912 string
913 Module::GetPathWithPrefix ( const string& prefix ) const
914 {
915 return path + cSep + prefix + GetTargetName ();
916 }
917
918 string
919 Module::GetInvocationTarget ( const int index ) const
920 {
921 return ssprintf ( "%s_invoke_%d",
922 name.c_str (),
923 index );
924 }
925
926 bool
927 Module::HasFileWithExtension (
928 const IfableData& data,
929 const std::string& extension ) const
930 {
931 size_t i;
932 for ( i = 0; i < data.compilationUnits.size (); i++ )
933 {
934 CompilationUnit* compilationUnit = data.compilationUnits[i];
935 if ( compilationUnit->HasFileWithExtension ( extension ) )
936 return true;
937 }
938 for ( i = 0; i < data.ifs.size (); i++ )
939 {
940 if ( HasFileWithExtension ( data.ifs[i]->data, extension ) )
941 return true;
942 }
943 return false;
944 }
945
946 void
947 Module::InvokeModule () const
948 {
949 for ( size_t i = 0; i < invocations.size (); i++ )
950 {
951 Invoke& invoke = *invocations[i];
952 string command = FixSeparatorForSystemCommand(invoke.invokeModule->GetPath ()) + " " + invoke.GetParameters ();
953 printf ( "Executing '%s'\n\n", command.c_str () );
954 int exitcode = system ( command.c_str () );
955 if ( exitcode != 0 )
956 throw InvocationFailedException ( command,
957 exitcode );
958 }
959 }
960
961
962 File::File ( const string& _name, bool _first,
963 std::string _switches,
964 bool _isPreCompiledHeader )
965 : name(_name),
966 first(_first),
967 switches(_switches),
968 isPreCompiledHeader(_isPreCompiledHeader)
969 {
970 }
971
972 void
973 File::ProcessXML()
974 {
975 }
976
977
978 Library::Library ( const XMLElement& _node,
979 const Module& _module,
980 const string& _name )
981 : node(_node),
982 module(_module),
983 name(_name),
984 importedModule(_module.project.LocateModule(_name))
985 {
986 if ( module.name == name )
987 throw InvalidBuildFileException (
988 node.location,
989 "module '%s' cannot link against itself",
990 name.c_str() );
991 if ( !importedModule )
992 throw InvalidBuildFileException (
993 node.location,
994 "module '%s' trying to import non-existant module '%s'",
995 module.name.c_str(),
996 name.c_str() );
997 }
998
999 void
1000 Library::ProcessXML()
1001 {
1002 if ( !module.project.LocateModule ( name ) )
1003 throw InvalidBuildFileException (
1004 node.location,
1005 "module '%s' is trying to link against non-existant module '%s'",
1006 module.name.c_str(),
1007 name.c_str() );
1008 }
1009
1010
1011 Invoke::Invoke ( const XMLElement& _node,
1012 const Module& _module )
1013 : node (_node),
1014 module (_module)
1015 {
1016 }
1017
1018 void
1019 Invoke::ProcessXML()
1020 {
1021 const XMLAttribute* att = node.GetAttribute ( "module", false );
1022 if (att == NULL)
1023 invokeModule = &module;
1024 else
1025 {
1026 invokeModule = module.project.LocateModule ( att->value );
1027 if ( invokeModule == NULL )
1028 throw InvalidBuildFileException (
1029 node.location,
1030 "module '%s' is trying to invoke non-existant module '%s'",
1031 module.name.c_str(),
1032 att->value.c_str() );
1033 }
1034
1035 for ( size_t i = 0; i < node.subElements.size (); i++ )
1036 ProcessXMLSubElement ( *node.subElements[i] );
1037 }
1038
1039 void
1040 Invoke::ProcessXMLSubElement ( const XMLElement& e )
1041 {
1042 bool subs_invalid = false;
1043 if ( e.name == "input" )
1044 {
1045 for ( size_t i = 0; i < e.subElements.size (); i++ )
1046 ProcessXMLSubElementInput ( *e.subElements[i] );
1047 }
1048 else if ( e.name == "output" )
1049 {
1050 for ( size_t i = 0; i < e.subElements.size (); i++ )
1051 ProcessXMLSubElementOutput ( *e.subElements[i] );
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::ProcessXMLSubElementInput ( const XMLElement& e )
1061 {
1062 bool subs_invalid = false;
1063 if ( e.name == "inputfile" && e.value.size () > 0 )
1064 {
1065 input.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 ( e.location,
1070 "<%s> cannot have sub-elements",
1071 e.name.c_str() );
1072 }
1073
1074 void
1075 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
1076 {
1077 bool subs_invalid = false;
1078 if ( e.name == "outputfile" && e.value.size () > 0 )
1079 {
1080 output.push_back ( new InvokeFile ( e, FixSeparator ( module.path + cSep + e.value ) ) );
1081 subs_invalid = true;
1082 }
1083 if ( subs_invalid && e.subElements.size() > 0 )
1084 throw InvalidBuildFileException (
1085 e.location,
1086 "<%s> cannot have sub-elements",
1087 e.name.c_str() );
1088 }
1089
1090 void
1091 Invoke::GetTargets ( string_list& targets ) const
1092 {
1093 for ( size_t i = 0; i < output.size (); i++ )
1094 {
1095 InvokeFile& file = *output[i];
1096 targets.push_back ( NormalizeFilename ( file.name ) );
1097 }
1098 }
1099
1100 string
1101 Invoke::GetParameters () const
1102 {
1103 string parameters ( "" );
1104 size_t i;
1105 for ( i = 0; i < output.size (); i++ )
1106 {
1107 if ( parameters.length () > 0)
1108 parameters += " ";
1109 InvokeFile& invokeFile = *output[i];
1110 if ( invokeFile.switches.length () > 0 )
1111 {
1112 parameters += invokeFile.switches + " ";
1113 }
1114 parameters += invokeFile.name;
1115 }
1116
1117 for ( i = 0; i < input.size (); i++ )
1118 {
1119 if ( parameters.length () > 0 )
1120 parameters += " ";
1121 InvokeFile& invokeFile = *input[i];
1122 if ( invokeFile.switches.length () > 0 )
1123 {
1124 parameters += invokeFile.switches;
1125 parameters += " ";
1126 }
1127 parameters += invokeFile.name ;
1128 }
1129
1130 return parameters;
1131 }
1132
1133
1134 InvokeFile::InvokeFile ( const XMLElement& _node,
1135 const string& _name )
1136 : node (_node),
1137 name (_name)
1138 {
1139 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
1140 if (att != NULL)
1141 switches = att->value;
1142 else
1143 switches = "";
1144 }
1145
1146 void
1147 InvokeFile::ProcessXML()
1148 {
1149 }
1150
1151
1152 Dependency::Dependency ( const XMLElement& _node,
1153 const Module& _module )
1154 : node (_node),
1155 module (_module),
1156 dependencyModule (NULL)
1157 {
1158 }
1159
1160 void
1161 Dependency::ProcessXML()
1162 {
1163 dependencyModule = module.project.LocateModule ( node.value );
1164 if ( dependencyModule == NULL )
1165 throw InvalidBuildFileException ( node.location,
1166 "module '%s' depend on non-existant module '%s'",
1167 module.name.c_str(),
1168 node.value.c_str() );
1169 }
1170
1171
1172 ImportLibrary::ImportLibrary ( const XMLElement& _node,
1173 const Module& _module )
1174 : node (_node),
1175 module (_module)
1176 {
1177 const XMLAttribute* att = _node.GetAttribute ( "basename", false );
1178 if (att != NULL)
1179 basename = att->value;
1180 else
1181 basename = module.name;
1182
1183 att = _node.GetAttribute ( "definition", true );
1184 assert (att);
1185 definition = FixSeparator(att->value);
1186 }
1187
1188
1189 If::If ( const XMLElement& node_,
1190 const Project& project_,
1191 const Module* module_,
1192 const bool negated_ )
1193 : node(node_), project(project_), module(module_), negated(negated_)
1194 {
1195 const XMLAttribute* att;
1196
1197 att = node.GetAttribute ( "property", true );
1198 assert(att);
1199 property = att->value;
1200
1201 att = node.GetAttribute ( "value", true );
1202 assert(att);
1203 value = att->value;
1204 }
1205
1206 If::~If ()
1207 {
1208 }
1209
1210 void
1211 If::ProcessXML()
1212 {
1213 }
1214
1215
1216 Property::Property ( const XMLElement& node_,
1217 const Project& project_,
1218 const Module* module_ )
1219 : node(node_), project(project_), module(module_)
1220 {
1221 const XMLAttribute* att;
1222
1223 att = node.GetAttribute ( "name", true );
1224 assert(att);
1225 name = att->value;
1226
1227 att = node.GetAttribute ( "value", true );
1228 assert(att);
1229 value = att->value;
1230 }
1231
1232 void
1233 Property::ProcessXML()
1234 {
1235 }
1236
1237
1238 PchFile::PchFile (
1239 const XMLElement& node_,
1240 const Module& module_,
1241 const File file_ )
1242 : node(node_), module(module_), file(file_)
1243 {
1244 }
1245
1246 void
1247 PchFile::ProcessXML()
1248 {
1249 }