Hopefully, the definitive spec files commit. Dedicated to Samuel Serapión, who report...
[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 return result;
1323 }
1324
1325 bool
1326 Module::HasFileWithExtension (
1327 const IfableData& data,
1328 const std::string& extension ) const
1329 {
1330 size_t i;
1331 for ( i = 0; i < data.compilationUnits.size (); i++ )
1332 {
1333 CompilationUnit* compilationUnit = data.compilationUnits[i];
1334 if ( compilationUnit->HasFileWithExtension ( extension ) )
1335 return true;
1336 }
1337 return false;
1338 }
1339
1340 void
1341 Module::InvokeModule () const
1342 {
1343 for ( size_t i = 0; i < invocations.size (); i++ )
1344 {
1345 Invoke& invoke = *invocations[i];
1346 string command = FixSeparatorForSystemCommand(invoke.invokeModule->output->relative_path + "/" + invoke.invokeModule->output->name ) + " " + invoke.GetParameters ();
1347 printf ( "Executing '%s'\n\n", command.c_str () );
1348 int exitcode = system ( command.c_str () );
1349 if ( exitcode != 0 )
1350 throw InvocationFailedException ( command,
1351 exitcode );
1352 }
1353 }
1354
1355
1356 void
1357 Module::SetImportLibrary ( ImportLibrary* importLibrary )
1358 {
1359 this->importLibrary = importLibrary;
1360 dependency = new FileLocation ( HasImportLibrary () ? IntermediateDirectory : output->directory,
1361 output->relative_path,
1362 HasImportLibrary () ? "lib" + name + ".a" : output->name );
1363 }
1364
1365 std::string
1366 Module::GetDllName () const
1367 {
1368 if ( importLibrary && !importLibrary->dllname.empty() )
1369 return importLibrary->dllname;
1370 else if ( output )
1371 return output->name;
1372 else
1373 throw new InvalidOperationException ( __FILE__, __LINE__, "Module %s has no dllname." );
1374 }
1375
1376 File::File ( DirectoryLocation directory,
1377 const string& relative_path,
1378 const string& name,
1379 bool _first,
1380 const string& _switches,
1381 bool _isPreCompiledHeader )
1382 : file ( directory, relative_path, name ),
1383 first(_first),
1384 switches(_switches),
1385 isPreCompiledHeader(_isPreCompiledHeader)
1386 {
1387 }
1388
1389
1390 void
1391 File::ProcessXML()
1392 {
1393 }
1394
1395
1396 std::string File::GetFullPath () const
1397 {
1398 string directory ( "" );
1399 switch ( file.directory )
1400 {
1401 case SourceDirectory:
1402 break;
1403 case IntermediateDirectory:
1404 directory = Environment::GetIntermediatePath () + sSep;
1405 break;
1406 default:
1407 throw InvalidOperationException ( __FILE__,
1408 __LINE__,
1409 "Invalid directory %d.",
1410 file.directory );
1411 }
1412
1413 if ( file.relative_path.length () > 0 )
1414 directory += file.relative_path + sSep;
1415
1416
1417 return directory + file.name;
1418 }
1419
1420
1421 Library::Library ( const XMLElement& _node,
1422 const Module& _module,
1423 const string& _name )
1424 : node(&_node),
1425 module(_module),
1426 name(_name),
1427 importedModule(_module.project.LocateModule(_name))
1428 {
1429 if ( module.name == name )
1430 {
1431 throw XMLInvalidBuildFileException (
1432 node->location,
1433 "module '%s' cannot link against itself",
1434 name.c_str() );
1435 }
1436 if ( !importedModule )
1437 {
1438 throw XMLInvalidBuildFileException (
1439 node->location,
1440 "module '%s' trying to import non-existant module '%s'",
1441 module.name.c_str(),
1442 name.c_str() );
1443 }
1444 }
1445
1446 Library::Library ( const Module& _module,
1447 const string& _name )
1448 : node(NULL),
1449 module(_module),
1450 name(_name),
1451 importedModule(_module.project.LocateModule(_name))
1452 {
1453 }
1454
1455 void
1456 Library::ProcessXML()
1457 {
1458 if ( node && !module.project.LocateModule ( name ) )
1459 {
1460 throw XMLInvalidBuildFileException (
1461 node->location,
1462 "module '%s' is trying to link against non-existant module '%s'",
1463 module.name.c_str(),
1464 name.c_str() );
1465 }
1466 }
1467
1468
1469 Invoke::Invoke ( const XMLElement& _node,
1470 const Module& _module )
1471 : node (_node),
1472 module (_module)
1473 {
1474 }
1475
1476 void
1477 Invoke::ProcessXML()
1478 {
1479 const XMLAttribute* att = node.GetAttribute ( "module", false );
1480 if (att == NULL)
1481 invokeModule = &module;
1482 else
1483 {
1484 invokeModule = module.project.LocateModule ( att->value );
1485 if ( invokeModule == NULL )
1486 {
1487 throw XMLInvalidBuildFileException (
1488 node.location,
1489 "module '%s' is trying to invoke non-existant module '%s'",
1490 module.name.c_str(),
1491 att->value.c_str() );
1492 }
1493 }
1494
1495 for ( size_t i = 0; i < node.subElements.size (); i++ )
1496 ProcessXMLSubElement ( *node.subElements[i] );
1497 }
1498
1499 void
1500 Invoke::ProcessXMLSubElement ( const XMLElement& e )
1501 {
1502 bool subs_invalid = false;
1503 if ( e.name == "input" )
1504 {
1505 for ( size_t i = 0; i < e.subElements.size (); i++ )
1506 ProcessXMLSubElementInput ( *e.subElements[i] );
1507 }
1508 else if ( e.name == "output" )
1509 {
1510 for ( size_t i = 0; i < e.subElements.size (); i++ )
1511 ProcessXMLSubElementOutput ( *e.subElements[i] );
1512 }
1513 if ( subs_invalid && e.subElements.size() > 0 )
1514 {
1515 throw XMLInvalidBuildFileException (
1516 e.location,
1517 "<%s> cannot have sub-elements",
1518 e.name.c_str() );
1519 }
1520 }
1521
1522 void
1523 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
1524 {
1525 bool subs_invalid = false;
1526 if ( e.name == "inputfile" && e.value.size () > 0 )
1527 {
1528 input.push_back ( new InvokeFile (
1529 e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
1530 subs_invalid = true;
1531 }
1532 if ( subs_invalid && e.subElements.size() > 0 )
1533 {
1534 throw XMLInvalidBuildFileException (
1535 e.location,
1536 "<%s> cannot have sub-elements",
1537 e.name.c_str() );
1538 }
1539 }
1540
1541 void
1542 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
1543 {
1544 bool subs_invalid = false;
1545 if ( e.name == "outputfile" && e.value.size () > 0 )
1546 {
1547 output.push_back ( new InvokeFile (
1548 e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
1549 subs_invalid = true;
1550 }
1551 if ( subs_invalid && e.subElements.size() > 0 )
1552 {
1553 throw XMLInvalidBuildFileException (
1554 e.location,
1555 "<%s> cannot have sub-elements",
1556 e.name.c_str() );
1557 }
1558 }
1559
1560 void
1561 Invoke::GetTargets ( string_list& targets ) const
1562 {
1563 for ( size_t i = 0; i < output.size (); i++ )
1564 {
1565 InvokeFile& file = *output[i];
1566 targets.push_back ( NormalizeFilename ( file.name ) );
1567 }
1568 }
1569
1570 string
1571 Invoke::GetParameters () const
1572 {
1573 string parameters ( "" );
1574 size_t i;
1575 for ( i = 0; i < output.size (); i++ )
1576 {
1577 if ( parameters.length () > 0)
1578 parameters += " ";
1579 InvokeFile& invokeFile = *output[i];
1580 if ( invokeFile.switches.length () > 0 )
1581 {
1582 parameters += invokeFile.switches + " ";
1583 }
1584 parameters += invokeFile.name;
1585 }
1586
1587 for ( i = 0; i < input.size (); i++ )
1588 {
1589 if ( parameters.length () > 0 )
1590 parameters += " ";
1591 InvokeFile& invokeFile = *input[i];
1592 if ( invokeFile.switches.length () > 0 )
1593 {
1594 parameters += invokeFile.switches;
1595 parameters += " ";
1596 }
1597 parameters += invokeFile.name ;
1598 }
1599
1600 return parameters;
1601 }
1602
1603
1604 InvokeFile::InvokeFile ( const XMLElement& _node,
1605 const string& _name )
1606 : node (_node),
1607 name (_name)
1608 {
1609 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
1610 if (att != NULL)
1611 switches = att->value;
1612 else
1613 switches = "";
1614 }
1615
1616 void
1617 InvokeFile::ProcessXML()
1618 {
1619 }
1620
1621
1622 Dependency::Dependency ( const XMLElement& _node,
1623 const Module& _module )
1624 : node (_node),
1625 module (_module),
1626 dependencyModule (NULL)
1627 {
1628 }
1629
1630 void
1631 Dependency::ProcessXML()
1632 {
1633 dependencyModule = module.project.LocateModule ( node.value );
1634 if ( dependencyModule == NULL )
1635 {
1636 throw XMLInvalidBuildFileException (
1637 node.location,
1638 "module '%s' depend on non-existant module '%s'",
1639 module.name.c_str(),
1640 node.value.c_str() );
1641 }
1642 }
1643
1644 Bootsector::Bootsector ( const XMLElement& _node,
1645 const Module* _module )
1646 : node (_node),
1647 module (_module),
1648 bootSectorModule (NULL)
1649 {
1650 if ( !IsSupportedModuleType ( module->type ) )
1651 {
1652 throw XMLInvalidBuildFileException (
1653 node.location,
1654 "<bootsector> is not applicable for this module type." );
1655 }
1656
1657 bootSectorModule = module->project.LocateModule ( node.value );
1658 if ( bootSectorModule == 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 if (bootSectorModule->type != BootSector)
1668 {
1669 throw XMLInvalidBuildFileException (
1670 node.location,
1671 "module '%s' is referencing non BootSector module '%s'",
1672 module->name.c_str(),
1673 node.value.c_str() );
1674 }
1675 }
1676
1677 void
1678 Bootsector::ProcessXML()
1679 {
1680 }
1681
1682 bool
1683 Bootsector::IsSupportedModuleType ( ModuleType type )
1684 {
1685 if ( type == Iso ||
1686 type == LiveIso ||
1687 type == IsoRegTest ||
1688 type == LiveIsoRegTest )
1689 {
1690 return true;
1691 }
1692
1693 return false;
1694 }
1695
1696 Metadata::Metadata ( const XMLElement& _node,
1697 const Module& _module )
1698 : node (_node),
1699 module (_module)
1700 {
1701 /* The module name */
1702 const XMLAttribute* att = _node.GetAttribute ( "name", false );
1703 if (att != NULL)
1704 name = att->value;
1705 else
1706 name = module.name;
1707
1708 /* The module description */
1709 att = _node.GetAttribute ( "description", false );
1710 if (att != NULL)
1711 description = att->value;
1712 else
1713 description = "";
1714
1715 /* The module version */
1716 att = _node.GetAttribute ( "version", false );
1717 if (att != NULL)
1718 version = att->value;
1719 else
1720 version = "";
1721
1722 /* The module copyright */
1723 att = _node.GetAttribute ( "copyright", false );
1724 if (att != NULL)
1725 copyright = att->value;
1726 else
1727 copyright = "";
1728
1729 att = _node.GetAttribute ( "url", false );
1730 if (att != NULL)
1731 url = att->value;
1732 else
1733 url = "";
1734
1735 /* When was this module updated */
1736 att = _node.GetAttribute ( "date", false );
1737 if (att != NULL)
1738 date = att->value;
1739 else
1740 date = "?";
1741
1742 /* When was this module updated */
1743 att = _node.GetAttribute ( "owner", false );
1744 if (att != NULL)
1745 owner = att->value;
1746 else
1747 owner = "ReactOS";
1748 }
1749
1750
1751 ImportLibrary::~ImportLibrary ()
1752 {
1753 delete source;
1754 }
1755
1756
1757 ImportLibrary::ImportLibrary ( const Project& project,
1758 const XMLElement& node,
1759 const Module* module )
1760 : XmlNode ( project, node ),
1761 module (module)
1762 {
1763 DirectoryLocation directory = SourceDirectory;
1764 const Module* base = module;
1765 const XMLAttribute* dllname = node.GetAttribute ( "dllname", false );
1766 const XMLAttribute* definition = node.GetAttribute ( "definition", true );
1767 assert ( definition );
1768
1769 string relative_path;
1770 const XMLAttribute* att = node.GetAttribute ( "base", false );
1771 if ( att )
1772 {
1773 base = project.LocateModule ( att->value );
1774 if ( !base )
1775 throw XMLInvalidBuildFileException (
1776 node.location,
1777 "<importlibrary> attribute 'base' references non-existant module '%s'",
1778 att->value.c_str() );
1779
1780 }
1781
1782 if ( base )
1783 {
1784 relative_path = base->output->relative_path;
1785 if ( node.value.length () > 0 && node.value != "." )
1786 relative_path += sSep + node.value;
1787 }
1788 else
1789 relative_path = node.value;
1790
1791 att = node.GetAttribute ( "root", false );
1792 if ( att )
1793 {
1794 if ( att->value == "intermediate" )
1795 directory = IntermediateDirectory;
1796 else
1797 throw InvalidAttributeValueException ( node.location,
1798 "root",
1799 att->value );
1800 }
1801
1802 if ( dllname )
1803 this->dllname = dllname->value;
1804 else if ( module->type == StaticLibrary || module->type == HostStaticLibrary )
1805 throw XMLInvalidBuildFileException (
1806 node.location,
1807 "<importlibrary> dllname attribute required." );
1808
1809 size_t index = definition->value.find_last_of ( "/\\" );
1810 if ( index == string::npos )
1811 {
1812 source = new FileLocation ( directory,
1813 base->output->relative_path,
1814 definition->value,
1815 &node );
1816 }
1817 else
1818 {
1819 string dir = definition->value.substr ( 0, index );
1820 string name = definition->value.substr ( index + 1);
1821 source = new FileLocation ( directory,
1822 NormalizeFilename ( base->output->relative_path + sSep + dir ),
1823 name,
1824 &node );
1825 }
1826 }
1827
1828
1829 Property::Property ( const XMLElement& node_,
1830 const Project& project_,
1831 const Module* module_ )
1832 : project(project_), module(module_)
1833 {
1834 const XMLAttribute* att;
1835
1836 att = node_.GetAttribute ( "name", true );
1837 assert(att);
1838 name = project.ResolveProperties ( att->value );
1839
1840 att = node_.GetAttribute ( "value", true );
1841 assert(att);
1842 value = att->value;
1843
1844 att = node_.GetAttribute ( "internal", false );
1845 if ( att != NULL )
1846 {
1847 const char* p = att->value.c_str();
1848 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
1849 isInternal = true;
1850 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
1851 isInternal = false;
1852 else
1853 {
1854 throw InvalidAttributeValueException (
1855 node_.location,
1856 "internal",
1857 att->value );
1858 }
1859 }
1860 else
1861 isInternal = false;
1862 }
1863
1864 Property::Property ( const Project& project_,
1865 const Module* module_,
1866 const std::string& name_,
1867 const std::string& value_ )
1868 : project(project_), module(module_), name(name_), value(value_)
1869 {
1870 }
1871
1872 void
1873 Property::ProcessXML()
1874 {
1875 }
1876
1877
1878 PchFile::PchFile (
1879 const XMLElement& node_,
1880 const Module& module_,
1881 const FileLocation *file_ )
1882 : node(node_), module(module_), file(file_)
1883 {
1884 }
1885
1886 PchFile::~PchFile()
1887 {
1888 delete file;
1889 }
1890
1891 void
1892 PchFile::ProcessXML()
1893 {
1894 }