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