Supersedes r40538, r40539; RosBE bug fixed with a RosBE-specific hack (-nostdinc...
[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" || e.name == "redefine" )
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 == "idlinterface" )
945 return IdlInterface;
946 if ( attribute.value == "embeddedtypelib" )
947 return EmbeddedTypeLib;
948 if ( attribute.value == "elfexecutable" )
949 return ElfExecutable;
950 if ( attribute.value == "cabinet" )
951 return Cabinet;
952 if ( attribute.value == "messageheader" )
953 return MessageHeader;
954 throw InvalidAttributeValueException ( location,
955 attribute.name,
956 attribute.value );
957 }
958
959 DirectoryLocation
960 Module::GetTargetDirectoryTree () const
961 {
962 switch ( type )
963 {
964 case Kernel:
965 case KernelModeDLL:
966 case KeyboardLayout:
967 case NativeDLL:
968 case Win32DLL:
969 case Win32OCX:
970 case KernelModeDriver:
971 case NativeCUI:
972 case Win32CUI:
973 case Test:
974 case Win32SCR:
975 case Win32GUI:
976 case BuildTool:
977 case BootLoader:
978 case BootSector:
979 case BootProgram:
980 case Iso:
981 case LiveIso:
982 case IsoRegTest:
983 case LiveIsoRegTest:
984 case ElfExecutable:
985 case Cabinet:
986 return OutputDirectory;
987 case EmbeddedTypeLib:
988 case StaticLibrary:
989 case HostStaticLibrary:
990 case ObjectLibrary:
991 case RpcServer:
992 case RpcClient:
993 case RpcProxy:
994 case Alias:
995 case IdlHeader:
996 case IdlInterface:
997 case MessageHeader:
998 return IntermediateDirectory;
999 case TypeDontCare:
1000 break;
1001 }
1002 throw InvalidOperationException ( __FILE__,
1003 __LINE__,
1004 "Invalid module type %d.",
1005 type );
1006 }
1007
1008 string
1009 Module::GetDefaultModuleExtension () const
1010 {
1011 switch (type)
1012 {
1013 case BuildTool:
1014 return ExePostfix;
1015 case BootProgram:
1016 case StaticLibrary:
1017 case HostStaticLibrary:
1018 return ".a";
1019 case ObjectLibrary:
1020 return ".o";
1021 case Kernel:
1022 case NativeCUI:
1023 case Win32CUI:
1024 case Win32GUI:
1025 return ".exe";
1026 case Win32SCR:
1027 return ".scr";
1028
1029 case KernelModeDLL:
1030 case NativeDLL:
1031 case KeyboardLayout:
1032 case Win32DLL:
1033 return ".dll";
1034 case Win32OCX:
1035 return ".ocx";
1036 case KernelModeDriver:
1037 case BootLoader:
1038 return ".sys";
1039 case Cabinet:
1040 return ".cab";
1041 case BootSector:
1042 return ".o";
1043 case Iso:
1044 case LiveIso:
1045 case IsoRegTest:
1046 case LiveIsoRegTest:
1047 return ".iso";
1048 case Test:
1049 return ".exe";
1050 case RpcServer:
1051 case RpcClient:
1052 case RpcProxy:
1053 case IdlInterface:
1054 return ".o";
1055 case Alias:
1056 case ElfExecutable:
1057 case IdlHeader:
1058 case MessageHeader:
1059 return "";
1060 case EmbeddedTypeLib:
1061 return ".tlb";
1062 case TypeDontCare:
1063 break;
1064 }
1065 throw InvalidOperationException ( __FILE__,
1066 __LINE__ );
1067 }
1068
1069 string
1070 Module::GetDefaultModuleEntrypoint () const
1071 {
1072 switch ( type )
1073 {
1074 case Kernel:
1075 return "KiSystemStartup";
1076 case KeyboardLayout:
1077 case KernelModeDLL:
1078 case KernelModeDriver:
1079 if (Environment::GetArch() == "arm") return "DriverEntry";
1080 return "DriverEntry@8";
1081 case NativeDLL:
1082 if (Environment::GetArch() == "arm") return "DllMainCRTStartup";
1083 return "DllMainCRTStartup@12";
1084 case NativeCUI:
1085 if (Environment::GetArch() == "arm") return "NtProcessStartup";
1086 return "NtProcessStartup@4";
1087 case Win32DLL:
1088 case Win32OCX:
1089 if (Environment::GetArch() == "arm") return "DllMain";
1090 return "DllMain@12";
1091 case Win32CUI:
1092 case Test:
1093 return "mainCRTStartup";
1094 case Win32SCR:
1095 case Win32GUI:
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 IdlInterface:
1114 case MessageHeader:
1115 case ElfExecutable:
1116 case EmbeddedTypeLib:
1117 case Cabinet:
1118 return "";
1119 case TypeDontCare:
1120 break;
1121 }
1122 throw InvalidOperationException ( __FILE__,
1123 __LINE__ );
1124 }
1125
1126 string
1127 Module::GetDefaultModuleBaseaddress () const
1128 {
1129 switch ( type )
1130 {
1131 case Kernel:
1132 return "0x80800000";
1133 case Win32DLL:
1134 case Win32OCX:
1135 return "0x10000000";
1136 case NativeDLL:
1137 case NativeCUI:
1138 case Win32CUI:
1139 case Test:
1140 return "0x00400000";
1141 case Win32SCR:
1142 case Win32GUI:
1143 return "0x00400000";
1144 case KeyboardLayout:
1145 case KernelModeDLL:
1146 case KernelModeDriver:
1147 return "0x00010000";
1148 case ElfExecutable:
1149 return "0xe00000";
1150 case BuildTool:
1151 case StaticLibrary:
1152 case HostStaticLibrary:
1153 case ObjectLibrary:
1154 case BootLoader:
1155 case BootSector:
1156 case Iso:
1157 case LiveIso:
1158 case IsoRegTest:
1159 case LiveIsoRegTest:
1160 case RpcServer:
1161 case RpcClient:
1162 case RpcProxy:
1163 case Alias:
1164 case BootProgram:
1165 case IdlHeader:
1166 case IdlInterface:
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 IdlInterface:
1224 case MessageHeader:
1225 case EmbeddedTypeLib:
1226 case Cabinet:
1227 case TypeDontCare:
1228 return "none";
1229 }
1230 throw InvalidOperationException ( __FILE__,
1231 __LINE__ );
1232 }
1233
1234 bool
1235 Module::GetDefaultModuleIsCRT () const
1236 {
1237 return type == Kernel;
1238 }
1239
1240 bool
1241 Module::HasImportLibrary () const
1242 {
1243 return importLibrary != NULL && type != StaticLibrary && type != HostStaticLibrary;
1244 }
1245
1246 bool
1247 Module::IsDLL () const
1248 {
1249 switch ( type )
1250 {
1251 case Kernel:
1252 case KernelModeDLL:
1253 case NativeDLL:
1254 case KeyboardLayout:
1255 case Win32DLL:
1256 case Win32OCX:
1257 case KernelModeDriver:
1258 return true;
1259 case NativeCUI:
1260 case Win32CUI:
1261 case Test:
1262 case Win32SCR:
1263 case Win32GUI:
1264 case BuildTool:
1265 case StaticLibrary:
1266 case HostStaticLibrary:
1267 case ObjectLibrary:
1268 case BootLoader:
1269 case BootSector:
1270 case BootProgram:
1271 case Iso:
1272 case LiveIso:
1273 case IsoRegTest:
1274 case LiveIsoRegTest:
1275 case RpcServer:
1276 case RpcClient:
1277 case RpcProxy:
1278 case Alias:
1279 case IdlHeader:
1280 case IdlInterface:
1281 case MessageHeader:
1282 case EmbeddedTypeLib:
1283 case ElfExecutable:
1284 case Cabinet:
1285 return false;
1286 case TypeDontCare:
1287 break;
1288 }
1289 throw InvalidOperationException ( __FILE__,
1290 __LINE__ );
1291 }
1292
1293 string
1294 Module::GetPathWithPrefix ( const string& prefix ) const
1295 {
1296 return output->relative_path + cSep + prefix + output->name;
1297 }
1298
1299 string
1300 Module::GetPathToBaseDir () const
1301 {
1302 string temp_path = output->relative_path;
1303 string result = "..\\";
1304 while(temp_path.find ('\\') != string::npos)
1305 {
1306 temp_path.erase (0, temp_path.find('\\')+1);
1307 result += "..\\";
1308 }
1309 return result;
1310 }
1311
1312 string
1313 Module::GetInvocationTarget ( const int index ) const
1314 {
1315 return ssprintf ( "%s_invoke_%d",
1316 name.c_str (),
1317 index );
1318 }
1319
1320 string
1321 Module::GetEntryPoint(bool leadingUnderscore) const
1322 {
1323 string result = "";
1324 if (entrypoint == "0" || entrypoint == "0x0")
1325 return "0";
1326 if (leadingUnderscore)
1327 result = "_";
1328
1329 result += entrypoint;
1330
1331 if (Environment::GetArch() == "amd64")
1332 {
1333 size_t at_index = result.find_last_of( '@' );
1334 if ( at_index != result.npos )
1335 return result.substr (0, at_index );
1336 }
1337
1338 return result;
1339 }
1340
1341 bool
1342 Module::HasFileWithExtension (
1343 const IfableData& data,
1344 const std::string& extension ) const
1345 {
1346 size_t i;
1347 for ( i = 0; i < data.compilationUnits.size (); i++ )
1348 {
1349 CompilationUnit* compilationUnit = data.compilationUnits[i];
1350 if ( compilationUnit->HasFileWithExtension ( extension ) )
1351 return true;
1352 }
1353 return false;
1354 }
1355
1356 void
1357 Module::InvokeModule () const
1358 {
1359 for ( size_t i = 0; i < invocations.size (); i++ )
1360 {
1361 Invoke& invoke = *invocations[i];
1362 string command = FixSeparatorForSystemCommand(invoke.invokeModule->output->relative_path + "/" + invoke.invokeModule->output->name ) + " " + invoke.GetParameters ();
1363 printf ( "Executing '%s'\n\n", command.c_str () );
1364 int exitcode = system ( command.c_str () );
1365 if ( exitcode != 0 )
1366 throw InvocationFailedException ( command,
1367 exitcode );
1368 }
1369 }
1370
1371
1372 void
1373 Module::SetImportLibrary ( ImportLibrary* importLibrary )
1374 {
1375 this->importLibrary = importLibrary;
1376 dependency = new FileLocation ( HasImportLibrary () ? IntermediateDirectory : output->directory,
1377 output->relative_path,
1378 HasImportLibrary () ? "lib" + name + ".a" : output->name );
1379 }
1380
1381 std::string
1382 Module::GetDllName () const
1383 {
1384 if ( importLibrary && !importLibrary->dllname.empty() )
1385 return importLibrary->dllname;
1386 else if ( output )
1387 return output->name;
1388 else
1389 throw new InvalidOperationException ( __FILE__, __LINE__, "Module %s has no dllname." );
1390 }
1391
1392 File::File ( DirectoryLocation directory,
1393 const string& relative_path,
1394 const string& name,
1395 bool _first,
1396 const string& _switches,
1397 bool _isPreCompiledHeader )
1398 : file ( directory, relative_path, name ),
1399 first(_first),
1400 switches(_switches),
1401 isPreCompiledHeader(_isPreCompiledHeader)
1402 {
1403 }
1404
1405
1406 void
1407 File::ProcessXML()
1408 {
1409 }
1410
1411
1412 std::string File::GetFullPath () const
1413 {
1414 string directory ( "" );
1415 switch ( file.directory )
1416 {
1417 case SourceDirectory:
1418 break;
1419 case IntermediateDirectory:
1420 directory = Environment::GetIntermediatePath () + sSep;
1421 break;
1422 default:
1423 throw InvalidOperationException ( __FILE__,
1424 __LINE__,
1425 "Invalid directory %d.",
1426 file.directory );
1427 }
1428
1429 if ( file.relative_path.length () > 0 )
1430 directory += file.relative_path + sSep;
1431
1432
1433 return directory + file.name;
1434 }
1435
1436
1437 Library::Library ( const XMLElement& _node,
1438 const Module& _module,
1439 const string& _name )
1440 : node(&_node),
1441 module(_module),
1442 name(_name),
1443 importedModule(_module.project.LocateModule(_name))
1444 {
1445 if ( module.name == name )
1446 {
1447 throw XMLInvalidBuildFileException (
1448 node->location,
1449 "module '%s' cannot link against itself",
1450 name.c_str() );
1451 }
1452 if ( !importedModule )
1453 {
1454 throw XMLInvalidBuildFileException (
1455 node->location,
1456 "module '%s' trying to import non-existant module '%s'",
1457 module.name.c_str(),
1458 name.c_str() );
1459 }
1460 }
1461
1462 Library::Library ( const Module& _module,
1463 const string& _name )
1464 : node(NULL),
1465 module(_module),
1466 name(_name),
1467 importedModule(_module.project.LocateModule(_name))
1468 {
1469 if ( !importedModule )
1470 {
1471 throw XMLInvalidBuildFileException (
1472 "<internal>",
1473 "module '%s' trying to import non-existant module '%s'",
1474 module.name.c_str(),
1475 name.c_str() );
1476 }
1477 }
1478
1479 void
1480 Library::ProcessXML()
1481 {
1482 if ( node && !module.project.LocateModule ( name ) )
1483 {
1484 throw XMLInvalidBuildFileException (
1485 node->location,
1486 "module '%s' is trying to link against non-existant module '%s'",
1487 module.name.c_str(),
1488 name.c_str() );
1489 }
1490 }
1491
1492
1493 Invoke::Invoke ( const XMLElement& _node,
1494 const Module& _module )
1495 : node (_node),
1496 module (_module)
1497 {
1498 }
1499
1500 void
1501 Invoke::ProcessXML()
1502 {
1503 const XMLAttribute* att = node.GetAttribute ( "module", false );
1504 if (att == NULL)
1505 invokeModule = &module;
1506 else
1507 {
1508 invokeModule = module.project.LocateModule ( att->value );
1509 if ( invokeModule == NULL )
1510 {
1511 throw XMLInvalidBuildFileException (
1512 node.location,
1513 "module '%s' is trying to invoke non-existant module '%s'",
1514 module.name.c_str(),
1515 att->value.c_str() );
1516 }
1517 }
1518
1519 for ( size_t i = 0; i < node.subElements.size (); i++ )
1520 ProcessXMLSubElement ( *node.subElements[i] );
1521 }
1522
1523 void
1524 Invoke::ProcessXMLSubElement ( const XMLElement& e )
1525 {
1526 bool subs_invalid = false;
1527 if ( e.name == "input" )
1528 {
1529 for ( size_t i = 0; i < e.subElements.size (); i++ )
1530 ProcessXMLSubElementInput ( *e.subElements[i] );
1531 }
1532 else if ( e.name == "output" )
1533 {
1534 for ( size_t i = 0; i < e.subElements.size (); i++ )
1535 ProcessXMLSubElementOutput ( *e.subElements[i] );
1536 }
1537 if ( subs_invalid && e.subElements.size() > 0 )
1538 {
1539 throw XMLInvalidBuildFileException (
1540 e.location,
1541 "<%s> cannot have sub-elements",
1542 e.name.c_str() );
1543 }
1544 }
1545
1546 void
1547 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
1548 {
1549 bool subs_invalid = false;
1550 if ( e.name == "inputfile" && e.value.size () > 0 )
1551 {
1552 input.push_back ( new InvokeFile (
1553 e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
1554 subs_invalid = true;
1555 }
1556 if ( subs_invalid && e.subElements.size() > 0 )
1557 {
1558 throw XMLInvalidBuildFileException (
1559 e.location,
1560 "<%s> cannot have sub-elements",
1561 e.name.c_str() );
1562 }
1563 }
1564
1565 void
1566 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
1567 {
1568 bool subs_invalid = false;
1569 if ( e.name == "outputfile" && e.value.size () > 0 )
1570 {
1571 output.push_back ( new InvokeFile (
1572 e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
1573 subs_invalid = true;
1574 }
1575 if ( subs_invalid && e.subElements.size() > 0 )
1576 {
1577 throw XMLInvalidBuildFileException (
1578 e.location,
1579 "<%s> cannot have sub-elements",
1580 e.name.c_str() );
1581 }
1582 }
1583
1584 void
1585 Invoke::GetTargets ( string_list& targets ) const
1586 {
1587 for ( size_t i = 0; i < output.size (); i++ )
1588 {
1589 InvokeFile& file = *output[i];
1590 targets.push_back ( NormalizeFilename ( file.name ) );
1591 }
1592 }
1593
1594 string
1595 Invoke::GetParameters () const
1596 {
1597 string parameters ( "" );
1598 size_t i;
1599 for ( i = 0; i < output.size (); i++ )
1600 {
1601 if ( parameters.length () > 0)
1602 parameters += " ";
1603 InvokeFile& invokeFile = *output[i];
1604 if ( invokeFile.switches.length () > 0 )
1605 {
1606 parameters += invokeFile.switches + " ";
1607 }
1608 parameters += invokeFile.name;
1609 }
1610
1611 for ( i = 0; i < input.size (); i++ )
1612 {
1613 if ( parameters.length () > 0 )
1614 parameters += " ";
1615 InvokeFile& invokeFile = *input[i];
1616 if ( invokeFile.switches.length () > 0 )
1617 {
1618 parameters += invokeFile.switches;
1619 parameters += " ";
1620 }
1621 parameters += invokeFile.name ;
1622 }
1623
1624 return parameters;
1625 }
1626
1627
1628 InvokeFile::InvokeFile ( const XMLElement& _node,
1629 const string& _name )
1630 : node (_node),
1631 name (_name)
1632 {
1633 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
1634 if (att != NULL)
1635 switches = att->value;
1636 else
1637 switches = "";
1638 }
1639
1640 void
1641 InvokeFile::ProcessXML()
1642 {
1643 }
1644
1645
1646 Dependency::Dependency ( const XMLElement& _node,
1647 const Module& _module )
1648 : node (_node),
1649 module (_module),
1650 dependencyModule (NULL)
1651 {
1652 }
1653
1654 void
1655 Dependency::ProcessXML()
1656 {
1657 dependencyModule = module.project.LocateModule ( node.value );
1658 if ( dependencyModule == NULL )
1659 {
1660 throw XMLInvalidBuildFileException (
1661 node.location,
1662 "module '%s' depend on non-existant module '%s'",
1663 module.name.c_str(),
1664 node.value.c_str() );
1665 }
1666 }
1667
1668 Bootsector::Bootsector ( const XMLElement& _node,
1669 const Module* _module )
1670 : node (_node),
1671 module (_module),
1672 bootSectorModule (NULL)
1673 {
1674 if ( !IsSupportedModuleType ( module->type ) )
1675 {
1676 throw XMLInvalidBuildFileException (
1677 node.location,
1678 "<bootsector> is not applicable for this module type." );
1679 }
1680
1681 bootSectorModule = module->project.LocateModule ( node.value );
1682 if ( bootSectorModule == NULL )
1683 {
1684 throw XMLInvalidBuildFileException (
1685 node.location,
1686 "module '%s' depend on non-existant module '%s'",
1687 module->name.c_str(),
1688 node.value.c_str() );
1689 }
1690
1691 if (bootSectorModule->type != BootSector)
1692 {
1693 throw XMLInvalidBuildFileException (
1694 node.location,
1695 "module '%s' is referencing non BootSector module '%s'",
1696 module->name.c_str(),
1697 node.value.c_str() );
1698 }
1699 }
1700
1701 void
1702 Bootsector::ProcessXML()
1703 {
1704 }
1705
1706 bool
1707 Bootsector::IsSupportedModuleType ( ModuleType type )
1708 {
1709 if ( type == Iso ||
1710 type == LiveIso ||
1711 type == IsoRegTest ||
1712 type == LiveIsoRegTest )
1713 {
1714 return true;
1715 }
1716
1717 return false;
1718 }
1719
1720 Metadata::Metadata ( const XMLElement& _node,
1721 const Module& _module )
1722 : node (_node),
1723 module (_module)
1724 {
1725 /* The module name */
1726 const XMLAttribute* att = _node.GetAttribute ( "name", false );
1727 if (att != NULL)
1728 name = att->value;
1729 else
1730 name = module.name;
1731
1732 /* The module description */
1733 att = _node.GetAttribute ( "description", false );
1734 if (att != NULL)
1735 description = att->value;
1736 else
1737 description = "";
1738
1739 /* The module version */
1740 att = _node.GetAttribute ( "version", false );
1741 if (att != NULL)
1742 version = att->value;
1743 else
1744 version = "";
1745
1746 /* The module copyright */
1747 att = _node.GetAttribute ( "copyright", false );
1748 if (att != NULL)
1749 copyright = att->value;
1750 else
1751 copyright = "";
1752
1753 att = _node.GetAttribute ( "url", false );
1754 if (att != NULL)
1755 url = att->value;
1756 else
1757 url = "";
1758
1759 /* When was this module updated */
1760 att = _node.GetAttribute ( "date", false );
1761 if (att != NULL)
1762 date = att->value;
1763 else
1764 date = "?";
1765
1766 /* When was this module updated */
1767 att = _node.GetAttribute ( "owner", false );
1768 if (att != NULL)
1769 owner = att->value;
1770 else
1771 owner = "ReactOS";
1772 }
1773
1774
1775 ImportLibrary::~ImportLibrary ()
1776 {
1777 delete source;
1778 }
1779
1780
1781 ImportLibrary::ImportLibrary ( const Project& project,
1782 const XMLElement& node,
1783 const Module* module )
1784 : XmlNode ( project, node ),
1785 module (module)
1786 {
1787 DirectoryLocation directory = SourceDirectory;
1788 const Module* base = module;
1789 const XMLAttribute* dllname = node.GetAttribute ( "dllname", false );
1790 const XMLAttribute* definition = node.GetAttribute ( "definition", true );
1791 assert ( definition );
1792
1793 string relative_path;
1794 const XMLAttribute* att = node.GetAttribute ( "base", false );
1795 if ( att )
1796 {
1797 base = project.LocateModule ( att->value );
1798 if ( !base )
1799 throw XMLInvalidBuildFileException (
1800 node.location,
1801 "<importlibrary> attribute 'base' references non-existant module '%s'",
1802 att->value.c_str() );
1803
1804 }
1805
1806 if ( base )
1807 {
1808 relative_path = base->output->relative_path;
1809 if ( node.value.length () > 0 && node.value != "." )
1810 relative_path += sSep + node.value;
1811 }
1812 else
1813 relative_path = node.value;
1814
1815 att = node.GetAttribute ( "root", false );
1816 if ( att )
1817 {
1818 if ( att->value == "intermediate" )
1819 directory = IntermediateDirectory;
1820 else
1821 throw InvalidAttributeValueException ( node.location,
1822 "root",
1823 att->value );
1824 }
1825
1826 if ( dllname )
1827 this->dllname = dllname->value;
1828 else if ( module->type == StaticLibrary || module->type == HostStaticLibrary )
1829 throw XMLInvalidBuildFileException (
1830 node.location,
1831 "<importlibrary> dllname attribute required." );
1832
1833 size_t index = definition->value.find_last_of ( "/\\" );
1834 if ( index == string::npos )
1835 {
1836 source = new FileLocation ( directory,
1837 base->output->relative_path,
1838 definition->value,
1839 &node );
1840 }
1841 else
1842 {
1843 string dir = definition->value.substr ( 0, index );
1844 string name = definition->value.substr ( index + 1);
1845 source = new FileLocation ( directory,
1846 NormalizeFilename ( base->output->relative_path + sSep + dir ),
1847 name,
1848 &node );
1849 }
1850 }
1851
1852
1853 Property::Property ( const XMLElement& node_,
1854 const Project& project_,
1855 const Module* module_ )
1856 : project(project_), module(module_)
1857 {
1858 const XMLAttribute* att;
1859
1860 att = node_.GetAttribute ( "name", true );
1861 assert(att);
1862 name = project.ResolveProperties ( att->value );
1863
1864 att = node_.GetAttribute ( "value", true );
1865 assert(att);
1866 value = att->value;
1867
1868 att = node_.GetAttribute ( "internal", false );
1869 if ( att != NULL )
1870 {
1871 const char* p = att->value.c_str();
1872 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
1873 isInternal = true;
1874 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
1875 isInternal = false;
1876 else
1877 {
1878 throw InvalidAttributeValueException (
1879 node_.location,
1880 "internal",
1881 att->value );
1882 }
1883 }
1884 else
1885 isInternal = false;
1886 }
1887
1888 Property::Property ( const Project& project_,
1889 const Module* module_,
1890 const std::string& name_,
1891 const std::string& value_ )
1892 : project(project_), module(module_), name(name_), value(value_)
1893 {
1894 }
1895
1896 void
1897 Property::ProcessXML()
1898 {
1899 }
1900
1901
1902 PchFile::PchFile (
1903 const XMLElement& node_,
1904 const Module& module_,
1905 const FileLocation *file_ )
1906 : node(node_), module(module_), file(file_)
1907 {
1908 }
1909
1910 PchFile::~PchFile()
1911 {
1912 delete file;
1913 }
1914
1915 void
1916 PchFile::ProcessXML()
1917 {
1918 }