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