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