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