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