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