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