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