- Add "base" and "root" support to ImportLibrary. <importlibrary definition="../hal...
[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 Project& project,
122 const string& location,
123 const string& path,
124 const string& att_value )
125 {
126 if ( !att_value.size() )
127 throw XMLInvalidBuildFileException (
128 location,
129 "<directory> tag has empty 'name' attribute" );
130 if ( strpbrk ( att_value.c_str (), "/\\?*:<>|" ) )
131 throw XMLInvalidBuildFileException (
132 location,
133 "<directory> tag has invalid characters in 'name' attribute" );
134 if ( !path.size() )
135 return att_value;
136
137 return FixSeparator(path + cSep + att_value);
138 }
139
140 static string
141 GetExtension ( const string& filename )
142 {
143 size_t index = filename.find_last_of ( '/' );
144 if (index == string::npos) index = 0;
145 string tmp = filename.substr( index, filename.size() - index );
146 size_t ext_index = tmp.find_last_of( '.' );
147 if (ext_index != string::npos)
148 return filename.substr ( index + ext_index, filename.size() );
149 return "";
150 }
151
152 string
153 GetExtension ( const FileLocation& file )
154 {
155 return GetExtension ( file.name );
156 }
157
158 string
159 NormalizeFilename ( const string& filename )
160 {
161 if ( filename == "" )
162 return "";
163 Path path;
164 string normalizedPath = path.Fixup ( filename, true );
165 string relativeNormalizedPath = path.RelativeFromWorkingDirectory ( normalizedPath );
166 return FixSeparator ( relativeNormalizedPath );
167 }
168
169 bool
170 GetBooleanValue ( const string& value )
171 {
172 if ( value == "1" )
173 return true;
174 else
175 return false;
176 }
177
178 string
179 ToLower ( string filename )
180 {
181 for ( size_t i = 1; i < filename.length (); i++ )
182 filename[i] = tolower ( filename[i] );
183 return filename;
184 }
185
186 IfableData::IfableData( )
187 : asmFiles ( 0 )
188 {
189 }
190
191 void IfableData::ExtractModules( std::vector<Module*> &modules )
192 {
193 size_t i;
194 for ( i = 0; i < this->modules.size (); i++ )
195 modules.push_back(this->modules[i]);
196 }
197
198 IfableData::~IfableData()
199 {
200 size_t i;
201 for ( i = 0; i < includes.size (); i++ )
202 delete includes[i];
203 for ( i = 0; i < defines.size (); i++ )
204 delete defines[i];
205 for ( i = 0; i < libraries.size (); i++ )
206 delete libraries[i];
207 for ( i = 0; i < properties.size (); i++ )
208 delete properties[i];
209 for ( i = 0; i < compilerFlags.size (); i++ )
210 delete compilerFlags[i];
211 for ( i = 0; i < modules.size(); i++ )
212 delete modules[i];
213 for ( i = 0; i < ifs.size (); i++ )
214 delete ifs[i];
215 for ( i = 0; i < compilationUnits.size (); i++ )
216 delete compilationUnits[i];
217 }
218
219 void IfableData::ProcessXML ()
220 {
221 size_t i;
222 for ( i = 0; i < includes.size (); i++ )
223 includes[i]->ProcessXML ();
224 for ( i = 0; i < defines.size (); i++ )
225 defines[i]->ProcessXML ();
226 for ( i = 0; i < libraries.size (); i++ )
227 libraries[i]->ProcessXML ();
228 for ( i = 0; i < properties.size(); i++ )
229 properties[i]->ProcessXML ();
230 for ( i = 0; i < compilerFlags.size(); i++ )
231 compilerFlags[i]->ProcessXML ();
232 for ( i = 0; i < ifs.size (); i++ )
233 ifs[i]->ProcessXML ();
234 for ( i = 0; i < compilationUnits.size (); i++ )
235 compilationUnits[i]->ProcessXML ();
236 }
237
238 Module::Module ( const Project& project,
239 const XMLElement& moduleNode,
240 const string& modulePath )
241 : project (project),
242 node (moduleNode),
243 importLibrary (NULL),
244 metadata (NULL),
245 bootSector (NULL),
246 bootstrap (NULL),
247 autoRegister(NULL),
248 linkerScript (NULL),
249 pch (NULL),
250 cplusplus (false),
251 host (HostDefault),
252 output (NULL),
253 install (NULL)
254 {
255 if ( node.name != "module" )
256 throw InvalidOperationException ( __FILE__,
257 __LINE__,
258 "Module created with non-<module> node" );
259
260 xmlbuildFile = FixSeparator ( Path::RelativeFromWorkingDirectory ( moduleNode.xmlFile->filename () ) );
261
262 const XMLAttribute* att = moduleNode.GetAttribute ( "name", true );
263 assert(att);
264 name = att->value;
265
266 enabled = true;
267
268 att = moduleNode.GetAttribute ( "if", false );
269 if ( att != NULL )
270 enabled = GetBooleanValue ( project.ResolveProperties ( att->value ) );
271
272 att = moduleNode.GetAttribute ( "ifnot", false );
273 if ( att != NULL )
274 enabled = !GetBooleanValue ( project.ResolveProperties ( att->value ) );
275
276 if ( !enabled && project.configuration.Verbose )
277 printf("Module '%s' has been disabled.\n", name.c_str () );
278
279 att = moduleNode.GetAttribute ( "type", true );
280 assert(att);
281 type = GetModuleType ( node.location, *att );
282
283 att = moduleNode.GetAttribute ( "extension", false );
284 if ( att != NULL )
285 extension = att->value;
286 else
287 extension = GetDefaultModuleExtension ();
288
289 att = moduleNode.GetAttribute ( "unicode", false );
290 if ( att != NULL )
291 {
292 const char* p = att->value.c_str();
293 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
294 isUnicode = true;
295 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
296 isUnicode = false;
297 else
298 {
299 throw InvalidAttributeValueException (
300 moduleNode.location,
301 "unicode",
302 att->value );
303 }
304 }
305 else
306 isUnicode = false;
307
308 if (isUnicode)
309 {
310 // Always define UNICODE and _UNICODE
311 Define* pDefine = new Define ( project, this, "UNICODE" );
312 non_if_data.defines.push_back ( pDefine );
313
314 pDefine = new Define ( project, this, "_UNICODE" );
315 non_if_data.defines.push_back ( pDefine );
316 }
317
318 att = moduleNode.GetAttribute ( "entrypoint", false );
319 if ( att != NULL )
320 {
321 if ( att->value == "" )
322 {
323 throw InvalidAttributeValueException (
324 moduleNode.location,
325 "entrypoint",
326 att->value );
327 }
328
329 entrypoint = att->value;
330 isDefaultEntryPoint = false;
331 }
332 else
333 {
334 entrypoint = GetDefaultModuleEntrypoint ();
335 isDefaultEntryPoint = true;
336 }
337
338 att = moduleNode.GetAttribute ( "baseaddress", false );
339 if ( att != NULL )
340 baseaddress = att->value;
341 else
342 baseaddress = GetDefaultModuleBaseaddress ();
343
344 att = moduleNode.GetAttribute ( "mangledsymbols", false );
345 if ( att != NULL )
346 {
347 const char* p = att->value.c_str();
348 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
349 mangledSymbols = true;
350 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
351 mangledSymbols = false;
352 else
353 {
354 throw InvalidAttributeValueException (
355 moduleNode.location,
356 "mangledsymbols",
357 att->value );
358 }
359 }
360 else
361 mangledSymbols = false;
362
363 att = moduleNode.GetAttribute ( "underscoresymbols", false );
364 if ( att != NULL )
365 underscoreSymbols = att->value == "true";
366 else
367 underscoreSymbols = false;
368
369 att = moduleNode.GetAttribute ( "host", false );
370 if ( att != NULL )
371 {
372 const char* p = att->value.c_str();
373 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
374 host = HostTrue;
375 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
376 host = HostFalse;
377 else
378 {
379 throw InvalidAttributeValueException (
380 moduleNode.location,
381 "host",
382 att->value );
383 }
384 }
385
386 att = moduleNode.GetAttribute ( "isstartuplib", false );
387 if ( att != NULL )
388 {
389 const char* p = att->value.c_str();
390 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
391 isStartupLib = true;
392 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
393 isStartupLib = false;
394 else
395 {
396 throw InvalidAttributeValueException (
397 moduleNode.location,
398 "host",
399 att->value );
400 }
401 }
402 else
403 isStartupLib = false;
404
405 att = moduleNode.GetAttribute ( "prefix", false );
406 if ( att != NULL )
407 prefix = att->value;
408
409 att = moduleNode.GetAttribute ( "installname", false );
410 if ( att != NULL )
411 {
412 const XMLAttribute* installbase = moduleNode.GetAttribute ( "installbase", false );
413 install = new FileLocation ( InstallDirectory,
414 installbase ? installbase->value : "",
415 att->value,
416 &moduleNode );
417
418 output = new FileLocation ( GetTargetDirectoryTree (),
419 modulePath,
420 att->value,
421 &moduleNode );
422 }
423
424 att = moduleNode.GetAttribute ( "output", false );
425 if ( att != NULL )
426 {
427 if (output != NULL)
428 {
429 printf ( "%s: WARNING: 'installname' overrides 'output' also defined for this module.\n",
430 moduleNode.location.c_str() );
431 }
432 else
433 {
434 output = new FileLocation ( GetTargetDirectoryTree (),
435 modulePath,
436 att->value,
437 &moduleNode );
438 }
439 }
440
441 /* If no one has set the output file for this module set it automatically */
442 if (output == NULL)
443 {
444 output = new FileLocation ( GetTargetDirectoryTree (),
445 modulePath,
446 name + extension,
447 &moduleNode );
448 }
449
450 att = moduleNode.GetAttribute ( "allowwarnings", false );
451 if ( att == NULL )
452 {
453 att = moduleNode.GetAttribute ( "warnings", false );
454 if ( att != NULL )
455 {
456 printf ( "%s: WARNING: 'warnings' attribute of <module> is deprecated, use 'allowwarnings' instead\n",
457 moduleNode.location.c_str() );
458 }
459 }
460 if ( att != NULL )
461 allowWarnings = att->value == "true";
462 else
463 allowWarnings = false;
464
465 att = moduleNode.GetAttribute ( "aliasof", false );
466 if ( type == Alias && att != NULL )
467 aliasedModuleName = att->value;
468 else
469 aliasedModuleName = "";
470
471 if ( type == BootProgram )
472 {
473 att = moduleNode.GetAttribute ( "payload", true );
474 payload = att->value;
475 }
476
477 if ( type == BootProgram || type == ElfExecutable )
478 {
479 att = moduleNode.GetAttribute ( "buildtype", false );
480 if ( att != NULL )
481 {
482 buildtype = att->value;
483 }
484 else
485 {
486 buildtype = "BOOTPROG";
487 }
488 }
489
490 att = moduleNode.GetAttribute ( "description", false );
491 if (att != NULL )
492 {
493 description = project.ResolveProperties(att->value);
494 }
495 else
496 description = "";
497
498 att = moduleNode.GetAttribute ( "lcid", false );
499 if (type == KeyboardLayout && att != NULL )
500 lcid = att->value;
501 else
502 lcid = "";
503
504 att = moduleNode.GetAttribute ( "layoutid", false );
505 if (type == KeyboardLayout && att != NULL )
506 layoutId = att->value;
507 else
508 layoutId = "";
509
510 att = moduleNode.GetAttribute ( "layoutnameresid", false );
511 if (type == KeyboardLayout && att != NULL )
512 layoutNameResId = att->value;
513 else
514 layoutNameResId = "";
515
516 SetImportLibrary ( NULL );
517 }
518
519 Module::~Module ()
520 {
521 size_t i;
522 for ( i = 0; i < invocations.size(); i++ )
523 delete invocations[i];
524 for ( i = 0; i < dependencies.size(); i++ )
525 delete dependencies[i];
526 for ( i = 0; i < compilerFlags.size(); i++ )
527 delete compilerFlags[i];
528 for ( i = 0; i < linkerFlags.size(); i++ )
529 delete linkerFlags[i];
530 for ( i = 0; i < stubbedComponents.size(); i++ )
531 delete stubbedComponents[i];
532 if ( linkerScript )
533 delete linkerScript;
534 if ( pch )
535 delete pch;
536 if ( install )
537 delete install;
538 if ( metadata )
539 delete metadata;
540 if ( bootstrap )
541 delete bootstrap;
542 if ( importLibrary )
543 delete importLibrary;
544 if ( bootSector )
545 delete bootSector;
546 if ( dependency )
547 delete dependency;
548 if ( autoRegister )
549 delete autoRegister;
550 if ( output )
551 delete output;
552 }
553
554 void
555 Module::ProcessXML()
556 {
557 if ( type == Alias )
558 {
559 aliasedModuleName = project.ResolveProperties ( aliasedModuleName );
560 if ( aliasedModuleName == name )
561 {
562 throw XMLInvalidBuildFileException (
563 node.location,
564 "module '%s' cannot link against itself",
565 name.c_str() );
566 }
567 const Module* m = project.LocateModule ( aliasedModuleName );
568 if ( !m && enabled )
569 {
570 throw XMLInvalidBuildFileException (
571 node.location,
572 "module '%s' trying to alias non-existant module '%s'",
573 name.c_str(),
574 aliasedModuleName.c_str() );
575 }
576 }
577
578 size_t i;
579 for ( i = 0; i < node.subElements.size(); i++ )
580 {
581 ParseContext parseContext;
582 ProcessXMLSubElement ( *node.subElements[i], SourceDirectory, output->relative_path, parseContext );
583 }
584 for ( i = 0; i < invocations.size(); i++ )
585 invocations[i]->ProcessXML ();
586 for ( i = 0; i < dependencies.size(); i++ )
587 dependencies[i]->ProcessXML ();
588 for ( i = 0; i < compilerFlags.size(); i++ )
589 compilerFlags[i]->ProcessXML();
590 for ( i = 0; i < linkerFlags.size(); i++ )
591 linkerFlags[i]->ProcessXML();
592 for ( i = 0; i < stubbedComponents.size(); i++ )
593 stubbedComponents[i]->ProcessXML();
594 non_if_data.ProcessXML();
595 if ( linkerScript )
596 linkerScript->ProcessXML();
597 if ( pch )
598 pch->ProcessXML();
599 if ( autoRegister )
600 autoRegister->ProcessXML();
601 }
602
603 void
604 Module::ProcessXMLSubElement ( const XMLElement& e,
605 DirectoryLocation directory,
606 const string& relative_path,
607 ParseContext& parseContext )
608 {
609 If* pOldIf = parseContext.ifData;
610 CompilationUnit* pOldCompilationUnit = parseContext.compilationUnit;
611 bool subs_invalid = false;
612 string subpath ( relative_path );
613 DirectoryLocation subdirectory = SourceDirectory;
614 if ( e.name == "file" && e.value.size () > 0 )
615 {
616 bool first = false;
617 const XMLAttribute* att = e.GetAttribute ( "first", false );
618 if ( att != NULL )
619 {
620 if ( !stricmp ( att->value.c_str(), "true" ) )
621 first = true;
622 else if ( stricmp ( att->value.c_str(), "false" ) )
623 {
624 throw XMLInvalidBuildFileException (
625 e.location,
626 "attribute 'first' of <file> element can only be 'true' or 'false'" );
627 }
628 }
629 string switches = "";
630 att = e.GetAttribute ( "switches", false );
631 if ( att != NULL )
632 switches = att->value;
633 if ( !cplusplus )
634 {
635 // check for c++ file
636 string ext = GetExtension ( e.value );
637 if ( !stricmp ( ext.c_str(), ".cpp" ) )
638 cplusplus = true;
639 else if ( !stricmp ( ext.c_str(), ".cc" ) )
640 cplusplus = true;
641 else if ( !stricmp ( ext.c_str(), ".cxx" ) )
642 cplusplus = true;
643 }
644 File* pFile = new File ( directory,
645 relative_path,
646 e.value,
647 first,
648 switches,
649 false );
650 if ( parseContext.compilationUnit )
651 parseContext.compilationUnit->AddFile ( pFile );
652 else
653 {
654 CompilationUnit* pCompilationUnit = new CompilationUnit ( pFile );
655 if ( parseContext.ifData )
656 parseContext.ifData->data.compilationUnits.push_back ( pCompilationUnit );
657 else
658 {
659 string ext = ToLower ( GetExtension ( e.value ) );
660 if ( ext == ".idl" )
661 {
662 // put .idl files at the start of the module
663 non_if_data.compilationUnits.insert (
664 non_if_data.compilationUnits.begin(),
665 pCompilationUnit );
666 }
667 else if ( ext == ".asm" || ext == ".s" )
668 {
669 // put .asm files at the end of the module
670 non_if_data.compilationUnits.push_back ( pCompilationUnit );
671 non_if_data.asmFiles++;
672 }
673 else
674 {
675 // put other files in the middle
676 non_if_data.compilationUnits.insert (
677 non_if_data.compilationUnits.end() - non_if_data.asmFiles,
678 pCompilationUnit );
679 }
680 }
681 }
682 if ( parseContext.ifData )
683 parseContext.ifData->data.files.push_back ( pFile );
684 else
685 non_if_data.files.push_back ( pFile );
686 subs_invalid = true;
687 }
688 else if ( e.name == "library" && e.value.size () )
689 {
690 Library* pLibrary = new Library ( e, *this, e.value );
691 if ( parseContext.ifData )
692 parseContext.ifData->data.libraries.push_back ( pLibrary );
693 else
694 non_if_data.libraries.push_back ( pLibrary );
695 subs_invalid = true;
696 }
697 else if ( e.name == "directory" )
698 {
699 const XMLAttribute* att = e.GetAttribute ( "name", true );
700 const XMLAttribute* root = e.GetAttribute ( "root", false );
701 assert(att);
702 if ( root )
703 {
704 if ( root->value == "intermediate" )
705 subdirectory = IntermediateDirectory;
706 else if ( root->value == "output" )
707 subdirectory = OutputDirectory;
708 else
709 {
710 throw InvalidAttributeValueException (
711 e.location,
712 "root",
713 root->value );
714 }
715 }
716 subpath = GetSubPath ( this->project, e.location, relative_path, att->value );
717 }
718 else if ( e.name == "include" )
719 {
720 Include* include = new Include ( project, &e, this );
721 if ( parseContext.ifData )
722 parseContext.ifData->data.includes.push_back ( include );
723 else
724 non_if_data.includes.push_back ( include );
725 subs_invalid = true;
726 }
727 else if ( e.name == "define" )
728 {
729 Define* pDefine = new Define ( project, this, e );
730 if ( parseContext.ifData )
731 parseContext.ifData->data.defines.push_back ( pDefine );
732 else
733 non_if_data.defines.push_back ( pDefine );
734 subs_invalid = true;
735 }
736 else if ( e.name == "metadata" )
737 {
738 if ( parseContext.ifData )
739 {
740 throw XMLInvalidBuildFileException (
741 e.location,
742 "<metadata> is not a valid sub-element of <if>" );
743 }
744 metadata = new Metadata ( e, *this );
745 subs_invalid = false;
746 }
747 else if ( e.name == "invoke" )
748 {
749 if ( parseContext.ifData )
750 {
751 throw XMLInvalidBuildFileException (
752 e.location,
753 "<invoke> is not a valid sub-element of <if>" );
754 }
755 invocations.push_back ( new Invoke ( e, *this ) );
756 subs_invalid = false;
757 }
758 else if ( e.name == "dependency" )
759 {
760 if ( parseContext.ifData )
761 {
762 throw XMLInvalidBuildFileException (
763 e.location,
764 "<dependency> is not a valid sub-element of <if>" );
765 }
766 dependencies.push_back ( new Dependency ( e, *this ) );
767 subs_invalid = true;
768 }
769 else if ( e.name == "bootsector" )
770 {
771 if ( parseContext.ifData )
772 {
773 throw XMLInvalidBuildFileException (
774 e.location,
775 "<bootsector> is not a valid sub-element of <if>" );
776 }
777 bootSector = new Bootsector ( e, this );
778 subs_invalid = true;
779 }
780 else if ( e.name == "importlibrary" )
781 {
782 if ( parseContext.ifData )
783 {
784 throw XMLInvalidBuildFileException (
785 e.location,
786 "<importlibrary> is not a valid sub-element of <if>" );
787 }
788 if ( importLibrary )
789 {
790 throw XMLInvalidBuildFileException (
791 e.location,
792 "Only one <importlibrary> is valid per module" );
793 }
794 SetImportLibrary ( new ImportLibrary ( project, e, this ) );
795 subs_invalid = true;
796 }
797 else if ( e.name == "if" )
798 {
799 parseContext.ifData = new If ( e, project, this );
800 if ( pOldIf )
801 pOldIf->data.ifs.push_back ( parseContext.ifData );
802 else
803 non_if_data.ifs.push_back ( parseContext.ifData );
804 subs_invalid = false;
805 }
806 else if ( e.name == "ifnot" )
807 {
808 parseContext.ifData = new If ( e, project, this, true );
809 if ( pOldIf )
810 pOldIf->data.ifs.push_back ( parseContext.ifData );
811 else
812 non_if_data.ifs.push_back ( parseContext.ifData );
813 subs_invalid = false;
814 }
815 else if ( e.name == "compilerflag" )
816 {
817 CompilerFlag* pCompilerFlag = new CompilerFlag ( project, this, e );
818 if ( parseContext.ifData )
819 parseContext.ifData->data.compilerFlags.push_back ( pCompilerFlag );
820 else
821 non_if_data.compilerFlags.push_back ( pCompilerFlag );
822 subs_invalid = true;
823 }
824 else if ( e.name == "linkerflag" )
825 {
826 linkerFlags.push_back ( new LinkerFlag ( project, this, e ) );
827 subs_invalid = true;
828 }
829 else if ( e.name == "linkerscript" )
830 {
831 if ( parseContext.ifData )
832 {
833 throw XMLInvalidBuildFileException (
834 e.location,
835 "<linkerscript> is not a valid sub-element of <if>" );
836 }
837 if ( linkerScript )
838 {
839 throw XMLInvalidBuildFileException (
840 e.location,
841 "Only one <linkerscript> is valid per module" );
842 }
843 size_t pos = e.value.find_last_of ( "/\\" );
844 if ( pos == string::npos )
845 {
846 linkerScript = new LinkerScript (
847 e, *this, new FileLocation ( SourceDirectory, relative_path, e.value, &e ) );
848 }
849 else
850 {
851 string dir = e.value.substr ( 0, pos );
852 string name = e.value.substr ( pos + 1);
853 linkerScript = new LinkerScript (
854 e, *this, new FileLocation ( SourceDirectory, relative_path + sSep + dir, name, &e ) );
855 }
856 subs_invalid = true;
857 }
858 else if ( e.name == "component" )
859 {
860 stubbedComponents.push_back ( new StubbedComponent ( this, e ) );
861 subs_invalid = false;
862 }
863 else if ( e.name == "property" )
864 {
865 throw XMLInvalidBuildFileException (
866 e.location,
867 "<property> is not a valid sub-element of <module>" );
868 }
869 else if ( e.name == "bootstrap" )
870 {
871 bootstrap = new Bootstrap ( project, this, e );
872 subs_invalid = true;
873 }
874 else if ( e.name == "pch" )
875 {
876 if ( parseContext.ifData )
877 {
878 throw XMLInvalidBuildFileException (
879 e.location,
880 "<pch> is not a valid sub-element of <if>" );
881 }
882 if ( pch )
883 {
884 throw XMLInvalidBuildFileException (
885 e.location,
886 "Only one <pch> is valid per module" );
887 }
888 size_t pos = e.value.find_last_of ( "/\\" );
889 if ( pos == string::npos )
890 {
891 pch = new PchFile (
892 e, *this, new FileLocation ( SourceDirectory, relative_path, e.value, &e ) );
893 }
894 else
895 {
896 string dir = e.value.substr ( 0, pos );
897 string name = e.value.substr ( pos + 1);
898 pch = new PchFile (
899 e, *this, new FileLocation ( SourceDirectory, relative_path + sSep + dir, name, &e ) );
900 }
901 subs_invalid = true;
902 }
903 else if ( e.name == "compilationunit" )
904 {
905 if ( project.configuration.CompilationUnitsEnabled )
906 {
907 CompilationUnit* pCompilationUnit = new CompilationUnit ( &project, this, &e );
908 if ( parseContext.ifData )
909 parseContext.ifData->data.compilationUnits.push_back ( pCompilationUnit );
910 else
911 non_if_data.compilationUnits.push_back ( pCompilationUnit );
912 parseContext.compilationUnit = pCompilationUnit;
913 }
914 subs_invalid = false;
915 }
916 else if ( e.name == "autoregister" )
917 {
918 if ( autoRegister != NULL)
919 {
920 throw XMLInvalidBuildFileException (
921 e.location,
922 "there can be only one <%s> element for a module",
923 e.name.c_str() );
924 }
925 autoRegister = new AutoRegister ( project, this, e );
926 subs_invalid = true;
927 }
928 if ( subs_invalid && e.subElements.size() > 0 )
929 {
930 throw XMLInvalidBuildFileException (
931 e.location,
932 "<%s> cannot have sub-elements",
933 e.name.c_str() );
934 }
935 for ( size_t i = 0; i < e.subElements.size (); i++ )
936 ProcessXMLSubElement ( *e.subElements[i], subdirectory, subpath, parseContext );
937 parseContext.ifData = pOldIf;
938 parseContext.compilationUnit = pOldCompilationUnit;
939 }
940
941 ModuleType
942 Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
943 {
944 if ( attribute.value == "buildtool" )
945 return BuildTool;
946 if ( attribute.value == "staticlibrary" )
947 return StaticLibrary;
948 if ( attribute.value == "hoststaticlibrary" )
949 return HostStaticLibrary;
950 if ( attribute.value == "objectlibrary" )
951 return ObjectLibrary;
952 if ( attribute.value == "kernel" )
953 return Kernel;
954 if ( attribute.value == "kernelmodedll" )
955 return KernelModeDLL;
956 if ( attribute.value == "kernelmodedriver" )
957 return KernelModeDriver;
958 if ( attribute.value == "nativedll" )
959 return NativeDLL;
960 if ( attribute.value == "nativecui" )
961 return NativeCUI;
962 if ( attribute.value == "keyboardlayout" )
963 return KeyboardLayout;
964 if ( attribute.value == "win32dll" )
965 return Win32DLL;
966 if ( attribute.value == "win32ocx" )
967 return Win32OCX;
968 if ( attribute.value == "win32cui" )
969 return Win32CUI;
970 if ( attribute.value == "win32gui" )
971 return Win32GUI;
972 if ( attribute.value == "win32scr" )
973 return Win32SCR;
974 if ( attribute.value == "bootloader" )
975 return BootLoader;
976 if ( attribute.value == "bootsector" )
977 return BootSector;
978 if ( attribute.value == "bootprogram" )
979 return BootProgram;
980 if ( attribute.value == "iso" )
981 return Iso;
982 if ( attribute.value == "liveiso" )
983 return LiveIso;
984 if ( attribute.value == "isoregtest" )
985 return IsoRegTest;
986 if ( attribute.value == "liveisoregtest" )
987 return LiveIsoRegTest;
988 if ( attribute.value == "test" )
989 return Test;
990 if ( attribute.value == "rpcserver" )
991 return RpcServer;
992 if ( attribute.value == "rpcclient" )
993 return RpcClient;
994 if ( attribute.value == "rpcproxy" )
995 return RpcProxy;
996 if ( attribute.value == "alias" )
997 return Alias;
998 if ( attribute.value == "idlheader" )
999 return IdlHeader;
1000 if ( attribute.value == "embeddedtypelib" )
1001 return EmbeddedTypeLib;
1002 if ( attribute.value == "elfexecutable" )
1003 return ElfExecutable;
1004 if ( attribute.value == "cabinet" )
1005 return Cabinet;
1006 if ( attribute.value == "messageheader" )
1007 return MessageHeader;
1008 throw InvalidAttributeValueException ( location,
1009 attribute.name,
1010 attribute.value );
1011 }
1012
1013 DirectoryLocation
1014 Module::GetTargetDirectoryTree () const
1015 {
1016 switch ( type )
1017 {
1018 case Kernel:
1019 case KernelModeDLL:
1020 case KeyboardLayout:
1021 case NativeDLL:
1022 case Win32DLL:
1023 case Win32OCX:
1024 case KernelModeDriver:
1025 case NativeCUI:
1026 case Win32CUI:
1027 case Test:
1028 case Win32SCR:
1029 case Win32GUI:
1030 case BuildTool:
1031 case BootLoader:
1032 case BootSector:
1033 case BootProgram:
1034 case Iso:
1035 case LiveIso:
1036 case IsoRegTest:
1037 case LiveIsoRegTest:
1038 case ElfExecutable:
1039 case Cabinet:
1040 return OutputDirectory;
1041 case EmbeddedTypeLib:
1042 case StaticLibrary:
1043 case HostStaticLibrary:
1044 case ObjectLibrary:
1045 case RpcServer:
1046 case RpcClient:
1047 case RpcProxy:
1048 case Alias:
1049 case IdlHeader:
1050 case MessageHeader:
1051 return IntermediateDirectory;
1052 case TypeDontCare:
1053 break;
1054 }
1055 throw InvalidOperationException ( __FILE__,
1056 __LINE__,
1057 "Invalid module type %d.",
1058 type );
1059 }
1060
1061 string
1062 Module::GetDefaultModuleExtension () const
1063 {
1064 switch (type)
1065 {
1066 case BuildTool:
1067 return ExePostfix;
1068 case BootProgram:
1069 case StaticLibrary:
1070 case HostStaticLibrary:
1071 return ".a";
1072 case ObjectLibrary:
1073 return ".o";
1074 case Kernel:
1075 case NativeCUI:
1076 case Win32CUI:
1077 case Win32GUI:
1078 return ".exe";
1079 case Win32SCR:
1080 return ".scr";
1081
1082 case KernelModeDLL:
1083 case NativeDLL:
1084 case KeyboardLayout:
1085 case Win32DLL:
1086 return ".dll";
1087 case Win32OCX:
1088 return ".ocx";
1089 case KernelModeDriver:
1090 case BootLoader:
1091 return ".sys";
1092 case Cabinet:
1093 return ".cab";
1094 case BootSector:
1095 return ".o";
1096 case Iso:
1097 case LiveIso:
1098 case IsoRegTest:
1099 case LiveIsoRegTest:
1100 return ".iso";
1101 case Test:
1102 return ".exe";
1103 case RpcServer:
1104 case RpcClient:
1105 case RpcProxy:
1106 return ".o";
1107 case Alias:
1108 case ElfExecutable:
1109 case IdlHeader:
1110 case MessageHeader:
1111 return "";
1112 case EmbeddedTypeLib:
1113 return ".tlb";
1114 case TypeDontCare:
1115 break;
1116 }
1117 throw InvalidOperationException ( __FILE__,
1118 __LINE__ );
1119 }
1120
1121 string
1122 Module::GetDefaultModuleEntrypoint () const
1123 {
1124 switch ( type )
1125 {
1126 case Kernel:
1127 return "KiSystemStartup";
1128 case KeyboardLayout:
1129 case KernelModeDLL:
1130 case KernelModeDriver:
1131 return "DriverEntry@8";
1132 case NativeDLL:
1133 return "DllMainCRTStartup@12";
1134 case NativeCUI:
1135 return "NtProcessStartup@4";
1136 case Win32DLL:
1137 case Win32OCX:
1138 return "DllMain@12";
1139 case Win32CUI:
1140 case Test:
1141 if ( isUnicode )
1142 return "wmainCRTStartup";
1143 else
1144 return "mainCRTStartup";
1145 case Win32SCR:
1146 case Win32GUI:
1147 if ( isUnicode )
1148 return "wWinMainCRTStartup";
1149 else
1150 return "WinMainCRTStartup";
1151 case BuildTool:
1152 case StaticLibrary:
1153 case HostStaticLibrary:
1154 case ObjectLibrary:
1155 case BootLoader:
1156 case BootSector:
1157 case Iso:
1158 case LiveIso:
1159 case IsoRegTest:
1160 case LiveIsoRegTest:
1161 case RpcServer:
1162 case RpcClient:
1163 case RpcProxy:
1164 case Alias:
1165 case BootProgram:
1166 case IdlHeader:
1167 case MessageHeader:
1168 case ElfExecutable:
1169 case EmbeddedTypeLib:
1170 case Cabinet:
1171 return "";
1172 case TypeDontCare:
1173 break;
1174 }
1175 throw InvalidOperationException ( __FILE__,
1176 __LINE__ );
1177 }
1178
1179 string
1180 Module::GetDefaultModuleBaseaddress () const
1181 {
1182 switch ( type )
1183 {
1184 case Kernel:
1185 return "0x80800000";
1186 case Win32DLL:
1187 case Win32OCX:
1188 return "0x10000000";
1189 case NativeDLL:
1190 case NativeCUI:
1191 case Win32CUI:
1192 case Test:
1193 return "0x00400000";
1194 case Win32SCR:
1195 case Win32GUI:
1196 return "0x00400000";
1197 case KeyboardLayout:
1198 case KernelModeDLL:
1199 case KernelModeDriver:
1200 return "0x00010000";
1201 case ElfExecutable:
1202 return "0xe00000";
1203 case BuildTool:
1204 case StaticLibrary:
1205 case HostStaticLibrary:
1206 case ObjectLibrary:
1207 case BootLoader:
1208 case BootSector:
1209 case Iso:
1210 case LiveIso:
1211 case IsoRegTest:
1212 case LiveIsoRegTest:
1213 case RpcServer:
1214 case RpcClient:
1215 case RpcProxy:
1216 case Alias:
1217 case BootProgram:
1218 case IdlHeader:
1219 case MessageHeader:
1220 case EmbeddedTypeLib:
1221 case Cabinet:
1222 return "";
1223 case TypeDontCare:
1224 break;
1225 }
1226 throw InvalidOperationException ( __FILE__,
1227 __LINE__ );
1228 }
1229
1230 bool
1231 Module::HasImportLibrary () const
1232 {
1233 return importLibrary != NULL && type != StaticLibrary && type != HostStaticLibrary;
1234 }
1235
1236 bool
1237 Module::IsDLL () const
1238 {
1239 switch ( type )
1240 {
1241 case Kernel:
1242 case KernelModeDLL:
1243 case NativeDLL:
1244 case KeyboardLayout:
1245 case Win32DLL:
1246 case Win32OCX:
1247 case KernelModeDriver:
1248 return true;
1249 case NativeCUI:
1250 case Win32CUI:
1251 case Test:
1252 case Win32SCR:
1253 case Win32GUI:
1254 case BuildTool:
1255 case StaticLibrary:
1256 case HostStaticLibrary:
1257 case ObjectLibrary:
1258 case BootLoader:
1259 case BootSector:
1260 case BootProgram:
1261 case Iso:
1262 case LiveIso:
1263 case IsoRegTest:
1264 case LiveIsoRegTest:
1265 case RpcServer:
1266 case RpcClient:
1267 case RpcProxy:
1268 case Alias:
1269 case IdlHeader:
1270 case MessageHeader:
1271 case EmbeddedTypeLib:
1272 case ElfExecutable:
1273 case Cabinet:
1274 return false;
1275 case TypeDontCare:
1276 break;
1277 }
1278 throw InvalidOperationException ( __FILE__,
1279 __LINE__ );
1280 }
1281
1282 string
1283 Module::GetPathWithPrefix ( const string& prefix ) const
1284 {
1285 return output->relative_path + cSep + prefix + output->name;
1286 }
1287
1288 string
1289 Module::GetPathToBaseDir () const
1290 {
1291 string temp_path = output->relative_path;
1292 string result = "..\\";
1293 while(temp_path.find ('\\') != string::npos)
1294 {
1295 temp_path.erase (0, temp_path.find('\\')+1);
1296 result += "..\\";
1297 }
1298 return result;
1299 }
1300
1301 string
1302 Module::GetInvocationTarget ( const int index ) const
1303 {
1304 return ssprintf ( "%s_invoke_%d",
1305 name.c_str (),
1306 index );
1307 }
1308
1309 string
1310 Module::GetEntryPoint(bool leadingUnderscore) const
1311 {
1312 string result = "";
1313 if (entrypoint == "0" || entrypoint == "0x0")
1314 return "0";
1315 if (leadingUnderscore)
1316 result = "_";
1317
1318 result += entrypoint;
1319 return result;
1320 }
1321
1322 bool
1323 Module::HasFileWithExtension (
1324 const IfableData& data,
1325 const std::string& extension ) const
1326 {
1327 size_t i;
1328 for ( i = 0; i < data.compilationUnits.size (); i++ )
1329 {
1330 CompilationUnit* compilationUnit = data.compilationUnits[i];
1331 if ( compilationUnit->HasFileWithExtension ( extension ) )
1332 return true;
1333 }
1334 for ( i = 0; i < data.ifs.size (); i++ )
1335 {
1336 if ( HasFileWithExtension ( data.ifs[i]->data, extension ) )
1337 return true;
1338 }
1339 return false;
1340 }
1341
1342 void
1343 Module::InvokeModule () const
1344 {
1345 for ( size_t i = 0; i < invocations.size (); i++ )
1346 {
1347 Invoke& invoke = *invocations[i];
1348 string command = FixSeparatorForSystemCommand(invoke.invokeModule->output->relative_path + "/" + invoke.invokeModule->output->name ) + " " + invoke.GetParameters ();
1349 printf ( "Executing '%s'\n\n", command.c_str () );
1350 int exitcode = system ( command.c_str () );
1351 if ( exitcode != 0 )
1352 throw InvocationFailedException ( command,
1353 exitcode );
1354 }
1355 }
1356
1357
1358 void
1359 Module::SetImportLibrary ( ImportLibrary* importLibrary )
1360 {
1361 this->importLibrary = importLibrary;
1362 dependency = new FileLocation ( HasImportLibrary () ? IntermediateDirectory : output->directory,
1363 output->relative_path,
1364 HasImportLibrary () ? "lib" + name + ".a" : output->name );
1365 }
1366
1367
1368 File::File ( DirectoryLocation directory,
1369 const string& relative_path,
1370 const string& name,
1371 bool _first,
1372 const string& _switches,
1373 bool _isPreCompiledHeader )
1374 : file ( directory, relative_path, name ),
1375 first(_first),
1376 switches(_switches),
1377 isPreCompiledHeader(_isPreCompiledHeader)
1378 {
1379 }
1380
1381
1382 void
1383 File::ProcessXML()
1384 {
1385 }
1386
1387
1388 std::string File::GetFullPath () const
1389 {
1390 string directory ( "" );
1391 switch ( file.directory )
1392 {
1393 case SourceDirectory:
1394 break;
1395 case IntermediateDirectory:
1396 directory = Environment::GetIntermediatePath () + sSep;
1397 break;
1398 default:
1399 throw InvalidOperationException ( __FILE__,
1400 __LINE__,
1401 "Invalid directory %d.",
1402 file.directory );
1403 }
1404
1405 if ( file.relative_path.length () > 0 )
1406 directory += file.relative_path + sSep;
1407
1408
1409 return directory + file.name;
1410 }
1411
1412
1413 Library::Library ( const XMLElement& _node,
1414 const Module& _module,
1415 const string& _name )
1416 : node(&_node),
1417 module(_module),
1418 name(_name),
1419 importedModule(_module.project.LocateModule(_name))
1420 {
1421 if ( module.name == name )
1422 {
1423 throw XMLInvalidBuildFileException (
1424 node->location,
1425 "module '%s' cannot link against itself",
1426 name.c_str() );
1427 }
1428 if ( !importedModule )
1429 {
1430 throw XMLInvalidBuildFileException (
1431 node->location,
1432 "module '%s' trying to import non-existant module '%s'",
1433 module.name.c_str(),
1434 name.c_str() );
1435 }
1436 }
1437
1438 Library::Library ( const Module& _module,
1439 const string& _name )
1440 : node(NULL),
1441 module(_module),
1442 name(_name),
1443 importedModule(_module.project.LocateModule(_name))
1444 {
1445 }
1446
1447 void
1448 Library::ProcessXML()
1449 {
1450 if ( node && !module.project.LocateModule ( name ) )
1451 {
1452 throw XMLInvalidBuildFileException (
1453 node->location,
1454 "module '%s' is trying to link against non-existant module '%s'",
1455 module.name.c_str(),
1456 name.c_str() );
1457 }
1458 }
1459
1460
1461 Invoke::Invoke ( const XMLElement& _node,
1462 const Module& _module )
1463 : node (_node),
1464 module (_module)
1465 {
1466 }
1467
1468 void
1469 Invoke::ProcessXML()
1470 {
1471 const XMLAttribute* att = node.GetAttribute ( "module", false );
1472 if (att == NULL)
1473 invokeModule = &module;
1474 else
1475 {
1476 invokeModule = module.project.LocateModule ( att->value );
1477 if ( invokeModule == NULL )
1478 {
1479 throw XMLInvalidBuildFileException (
1480 node.location,
1481 "module '%s' is trying to invoke non-existant module '%s'",
1482 module.name.c_str(),
1483 att->value.c_str() );
1484 }
1485 }
1486
1487 for ( size_t i = 0; i < node.subElements.size (); i++ )
1488 ProcessXMLSubElement ( *node.subElements[i] );
1489 }
1490
1491 void
1492 Invoke::ProcessXMLSubElement ( const XMLElement& e )
1493 {
1494 bool subs_invalid = false;
1495 if ( e.name == "input" )
1496 {
1497 for ( size_t i = 0; i < e.subElements.size (); i++ )
1498 ProcessXMLSubElementInput ( *e.subElements[i] );
1499 }
1500 else if ( e.name == "output" )
1501 {
1502 for ( size_t i = 0; i < e.subElements.size (); i++ )
1503 ProcessXMLSubElementOutput ( *e.subElements[i] );
1504 }
1505 if ( subs_invalid && e.subElements.size() > 0 )
1506 {
1507 throw XMLInvalidBuildFileException (
1508 e.location,
1509 "<%s> cannot have sub-elements",
1510 e.name.c_str() );
1511 }
1512 }
1513
1514 void
1515 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
1516 {
1517 bool subs_invalid = false;
1518 if ( e.name == "inputfile" && e.value.size () > 0 )
1519 {
1520 input.push_back ( new InvokeFile (
1521 e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
1522 subs_invalid = true;
1523 }
1524 if ( subs_invalid && e.subElements.size() > 0 )
1525 {
1526 throw XMLInvalidBuildFileException (
1527 e.location,
1528 "<%s> cannot have sub-elements",
1529 e.name.c_str() );
1530 }
1531 }
1532
1533 void
1534 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
1535 {
1536 bool subs_invalid = false;
1537 if ( e.name == "outputfile" && e.value.size () > 0 )
1538 {
1539 output.push_back ( new InvokeFile (
1540 e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
1541 subs_invalid = true;
1542 }
1543 if ( subs_invalid && e.subElements.size() > 0 )
1544 {
1545 throw XMLInvalidBuildFileException (
1546 e.location,
1547 "<%s> cannot have sub-elements",
1548 e.name.c_str() );
1549 }
1550 }
1551
1552 void
1553 Invoke::GetTargets ( string_list& targets ) const
1554 {
1555 for ( size_t i = 0; i < output.size (); i++ )
1556 {
1557 InvokeFile& file = *output[i];
1558 targets.push_back ( NormalizeFilename ( file.name ) );
1559 }
1560 }
1561
1562 string
1563 Invoke::GetParameters () const
1564 {
1565 string parameters ( "" );
1566 size_t i;
1567 for ( i = 0; i < output.size (); i++ )
1568 {
1569 if ( parameters.length () > 0)
1570 parameters += " ";
1571 InvokeFile& invokeFile = *output[i];
1572 if ( invokeFile.switches.length () > 0 )
1573 {
1574 parameters += invokeFile.switches + " ";
1575 }
1576 parameters += invokeFile.name;
1577 }
1578
1579 for ( i = 0; i < input.size (); i++ )
1580 {
1581 if ( parameters.length () > 0 )
1582 parameters += " ";
1583 InvokeFile& invokeFile = *input[i];
1584 if ( invokeFile.switches.length () > 0 )
1585 {
1586 parameters += invokeFile.switches;
1587 parameters += " ";
1588 }
1589 parameters += invokeFile.name ;
1590 }
1591
1592 return parameters;
1593 }
1594
1595
1596 InvokeFile::InvokeFile ( const XMLElement& _node,
1597 const string& _name )
1598 : node (_node),
1599 name (_name)
1600 {
1601 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
1602 if (att != NULL)
1603 switches = att->value;
1604 else
1605 switches = "";
1606 }
1607
1608 void
1609 InvokeFile::ProcessXML()
1610 {
1611 }
1612
1613
1614 Dependency::Dependency ( const XMLElement& _node,
1615 const Module& _module )
1616 : node (_node),
1617 module (_module),
1618 dependencyModule (NULL)
1619 {
1620 }
1621
1622 void
1623 Dependency::ProcessXML()
1624 {
1625 dependencyModule = module.project.LocateModule ( node.value );
1626 if ( dependencyModule == NULL )
1627 {
1628 throw XMLInvalidBuildFileException (
1629 node.location,
1630 "module '%s' depend on non-existant module '%s'",
1631 module.name.c_str(),
1632 node.value.c_str() );
1633 }
1634 }
1635
1636 Bootsector::Bootsector ( const XMLElement& _node,
1637 const Module* _module )
1638 : node (_node),
1639 module (_module),
1640 bootSectorModule (NULL)
1641 {
1642 if ( !IsSupportedModuleType ( module->type ) )
1643 {
1644 throw XMLInvalidBuildFileException (
1645 node.location,
1646 "<bootsector> is not applicable for this module type." );
1647 }
1648
1649 bootSectorModule = module->project.LocateModule ( node.value );
1650 if ( bootSectorModule == NULL )
1651 {
1652 throw XMLInvalidBuildFileException (
1653 node.location,
1654 "module '%s' depend on non-existant module '%s'",
1655 module->name.c_str(),
1656 node.value.c_str() );
1657 }
1658
1659 if (bootSectorModule->type != BootSector)
1660 {
1661 throw XMLInvalidBuildFileException (
1662 node.location,
1663 "module '%s' is referencing non BootSector module '%s'",
1664 module->name.c_str(),
1665 node.value.c_str() );
1666 }
1667 }
1668
1669 void
1670 Bootsector::ProcessXML()
1671 {
1672 }
1673
1674 bool
1675 Bootsector::IsSupportedModuleType ( ModuleType type )
1676 {
1677 if ( type == Iso ||
1678 type == LiveIso ||
1679 type == IsoRegTest ||
1680 type == LiveIsoRegTest )
1681 {
1682 return true;
1683 }
1684
1685 return false;
1686 }
1687
1688 Metadata::Metadata ( const XMLElement& _node,
1689 const Module& _module )
1690 : node (_node),
1691 module (_module)
1692 {
1693 /* The module name */
1694 const XMLAttribute* att = _node.GetAttribute ( "name", false );
1695 if (att != NULL)
1696 name = att->value;
1697 else
1698 name = module.name;
1699
1700 /* The module description */
1701 att = _node.GetAttribute ( "description", false );
1702 if (att != NULL)
1703 description = att->value;
1704 else
1705 description = "";
1706
1707 /* The module version */
1708 att = _node.GetAttribute ( "version", false );
1709 if (att != NULL)
1710 version = att->value;
1711 else
1712 version = "";
1713
1714 /* The module copyright */
1715 att = _node.GetAttribute ( "copyright", false );
1716 if (att != NULL)
1717 copyright = att->value;
1718 else
1719 copyright = "";
1720
1721 att = _node.GetAttribute ( "url", false );
1722 if (att != NULL)
1723 url = att->value;
1724 else
1725 url = "";
1726
1727 /* When was this module updated */
1728 att = _node.GetAttribute ( "date", false );
1729 if (att != NULL)
1730 date = att->value;
1731 else
1732 date = "?";
1733
1734 /* When was this module updated */
1735 att = _node.GetAttribute ( "owner", false );
1736 if (att != NULL)
1737 owner = att->value;
1738 else
1739 owner = "ReactOS";
1740 }
1741
1742
1743 ImportLibrary::~ImportLibrary ()
1744 {
1745 delete source;
1746 }
1747
1748
1749 ImportLibrary::ImportLibrary ( const Project& project,
1750 const XMLElement& node,
1751 const Module* module )
1752 : XmlNode ( project, node ),
1753 module (module)
1754 {
1755 DirectoryLocation directory = SourceDirectory;
1756 const Module* base = module;
1757 const XMLAttribute* dllname = node.GetAttribute ( "dllname", false );
1758 const XMLAttribute* definition = node.GetAttribute ( "definition", true );
1759 assert ( definition );
1760
1761 string relative_path;
1762 const XMLAttribute* att = node.GetAttribute ( "base", false );
1763 if ( att )
1764 {
1765 base = project.LocateModule ( att->value );
1766 if ( !base )
1767 throw XMLInvalidBuildFileException (
1768 node.location,
1769 "<importlibrary> attribute 'base' references non-existant module '%s'",
1770 att->value.c_str() );
1771
1772 }
1773
1774 if ( base )
1775 {
1776 relative_path = base->output->relative_path;
1777 if ( node.value.length () > 0 && node.value != "." )
1778 relative_path += sSep + node.value;
1779 }
1780 else
1781 relative_path = node.value;
1782
1783 att = node.GetAttribute ( "root", false );
1784 if ( att )
1785 {
1786 if ( att->value == "intermediate" )
1787 directory = IntermediateDirectory;
1788 else
1789 throw InvalidAttributeValueException ( node.location,
1790 "root",
1791 att->value );
1792 }
1793 else
1794 {
1795 size_t index = definition->value.rfind ( ".spec.def" );
1796 if ( index != string::npos )
1797 directory = IntermediateDirectory;
1798 }
1799
1800 if ( dllname )
1801 this->dllname = dllname->value;
1802 else if ( module->type == StaticLibrary || module->type == HostStaticLibrary )
1803 throw XMLInvalidBuildFileException (
1804 node.location,
1805 "<importlibrary> dllname attribute required." );
1806
1807 size_t index = definition->value.find_last_of ( "/\\" );
1808 if ( index == string::npos )
1809 {
1810 source = new FileLocation ( directory,
1811 base->output->relative_path,
1812 definition->value,
1813 &node );
1814 }
1815 else
1816 {
1817 string dir = definition->value.substr ( 0, index );
1818 string name = definition->value.substr ( index + 1);
1819 source = new FileLocation ( directory,
1820 NormalizeFilename ( base->output->relative_path + sSep + dir ),
1821 name,
1822 &node );
1823 }
1824 }
1825
1826
1827 If::If ( const XMLElement& node_,
1828 const Project& project_,
1829 const Module* module_,
1830 const bool negated_ )
1831 : node(node_), project(project_), module(module_), negated(negated_)
1832 {
1833 const XMLAttribute* att;
1834
1835 att = node.GetAttribute ( "property", true );
1836 assert(att);
1837 property = att->value;
1838
1839 att = node.GetAttribute ( "value", true );
1840 assert(att);
1841 value = att->value;
1842 }
1843
1844 If::~If ()
1845 {
1846 }
1847
1848 void
1849 If::ProcessXML()
1850 {
1851
1852 }
1853
1854
1855 Property::Property ( const XMLElement& node_,
1856 const Project& project_,
1857 const Module* module_ )
1858 : project(project_), module(module_)
1859 {
1860 const XMLAttribute* att;
1861
1862 att = node_.GetAttribute ( "name", true );
1863 assert(att);
1864 name = project.ResolveProperties ( att->value );
1865
1866 att = node_.GetAttribute ( "value", true );
1867 assert(att);
1868 value = att->value;
1869
1870 att = node_.GetAttribute ( "internal", false );
1871 if ( att != NULL )
1872 {
1873 const char* p = att->value.c_str();
1874 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
1875 isInternal = true;
1876 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
1877 isInternal = false;
1878 else
1879 {
1880 throw InvalidAttributeValueException (
1881 node_.location,
1882 "internal",
1883 att->value );
1884 }
1885 }
1886 else
1887 isInternal = false;
1888 }
1889
1890 Property::Property ( const Project& project_,
1891 const Module* module_,
1892 const std::string& name_,
1893 const std::string& value_ )
1894 : project(project_), module(module_), name(name_), value(value_)
1895 {
1896 }
1897
1898 void
1899 Property::ProcessXML()
1900 {
1901 }
1902
1903
1904 PchFile::PchFile (
1905 const XMLElement& node_,
1906 const Module& module_,
1907 const FileLocation *file_ )
1908 : node(node_), module(module_), file(file_)
1909 {
1910 }
1911
1912 PchFile::~PchFile()
1913 {
1914 delete file;
1915 }
1916
1917 void
1918 PchFile::ProcessXML()
1919 {
1920 }