af4b2530b18e6f79d2ff14674eb13adfdd9e0255
[reactos.git] / reactos / tools / rbuild / module.cpp
1 /*
2 * Copyright (C) 2005 Casper S. Hornstrup
3 * Copyright (C) 2008 Hervé Poussineau
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 #include "pch.h"
20 #include <assert.h>
21
22 #include "rbuild.h"
23
24 using std::string;
25 using std::vector;
26
27 string
28 Right ( const string& s, size_t n )
29 {
30 if ( n > s.size() )
31 return s;
32 return string ( &s[s.size()-n] );
33 }
34
35 string
36 Replace ( const string& s, const string& find, const string& with )
37 {
38 string ret;
39 const char* p = s.c_str();
40 while ( p )
41 {
42 const char* p2 = strstr ( p, find.c_str() );
43 if ( !p2 )
44 break;
45 if ( p2 > p )
46 ret += string ( p, p2-p );
47 ret += with;
48 p = p2 + find.size();
49 }
50 if ( *p )
51 ret += p;
52 return ret;
53 }
54
55 string
56 ChangeSeparator ( const string& s,
57 const char fromSeparator,
58 const char toSeparator )
59 {
60 string s2(s);
61 char* p = strchr ( &s2[0], fromSeparator );
62 while ( p )
63 {
64 *p++ = toSeparator;
65 p = strchr ( p, fromSeparator );
66 }
67 return s2;
68 }
69
70 string
71 FixSeparator ( const string& s )
72 {
73 return ChangeSeparator ( s, cBadSep, cSep );
74 }
75
76 string
77 FixSeparatorForSystemCommand ( const string& s )
78 {
79 string s2(s);
80 char* p = strchr ( &s2[0], DEF_CBAD_SEP );
81 while ( p )
82 {
83 *p++ = DEF_CSEP;
84 p = strchr ( p, DEF_CBAD_SEP );
85 }
86 return s2;
87 }
88
89 string
90 DosSeparator ( const string& s )
91 {
92 string s2(s);
93 char* p = strchr ( &s2[0], '/' );
94 while ( p )
95 {
96 *p++ = '\\';
97 p = strchr ( p, '/' );
98 }
99 return s2;
100 }
101
102 string
103 ReplaceExtension (
104 const string& filename,
105 const string& newExtension )
106 {
107 size_t index = filename.find_last_of ( '/' );
108 if ( index == string::npos )
109 index = 0;
110 size_t index2 = filename.find_last_of ( '\\' );
111 if ( index2 != string::npos && index2 > index )
112 index = index2;
113 string tmp = filename.substr( index /*, filename.size() - index*/ );
114 size_t ext_index = tmp.find_last_of( '.' );
115 if ( ext_index != string::npos )
116 return filename.substr ( 0, index + ext_index ) + newExtension;
117 return filename + newExtension;
118 }
119
120 string
121 GetSubPath (
122 const Project& project,
123 const string& location,
124 const string& path,
125 const string& att_value )
126 {
127 if ( !att_value.size() )
128 throw XMLInvalidBuildFileException (
129 location,
130 "<directory> tag has empty 'name' attribute" );
131 if ( strpbrk ( att_value.c_str (), "/\\?*:<>|" ) )
132 throw XMLInvalidBuildFileException (
133 location,
134 "<directory> tag has invalid characters in 'name' attribute" );
135 if ( !path.size() )
136 return att_value;
137
138 return FixSeparator(path + cSep + att_value);
139 }
140
141 static string
142 GetExtension ( const string& filename )
143 {
144 size_t index = filename.find_last_of ( '/' );
145 if (index == string::npos) index = 0;
146 string tmp = filename.substr( index, filename.size() - index );
147 size_t ext_index = tmp.find_last_of( '.' );
148 if (ext_index != string::npos)
149 return filename.substr ( index + ext_index, filename.size() );
150 return "";
151 }
152
153 string
154 GetExtension ( const FileLocation& file )
155 {
156 return GetExtension ( file.name );
157 }
158
159 string
160 NormalizeFilename ( const string& filename )
161 {
162 if ( filename == "" )
163 return "";
164 Path path;
165 string normalizedPath = path.Fixup ( filename, true );
166 string relativeNormalizedPath = path.RelativeFromWorkingDirectory ( normalizedPath );
167 return FixSeparator ( relativeNormalizedPath );
168 }
169
170 bool
171 GetBooleanValue ( const string& value )
172 {
173 if ( value == "1" )
174 return true;
175 else
176 return false;
177 }
178
179 string
180 ToLower ( string filename )
181 {
182 for ( size_t i = 1; i < filename.length (); i++ )
183 filename[i] = tolower ( filename[i] );
184 return filename;
185 }
186
187 IfableData::IfableData( )
188 : asmFiles ( 0 )
189 {
190 }
191
192 void IfableData::ExtractModules( std::map<std::string, Module*> &modules )
193 {
194 size_t i;
195 for ( i = 0; i < this->modules.size (); i++ )
196 modules.insert(std::make_pair(this->modules[i]->name, this->modules[i]));
197 }
198
199 IfableData::~IfableData()
200 {
201 size_t i;
202 for ( i = 0; i < includes.size (); i++ )
203 delete includes[i];
204 for ( i = 0; i < defines.size (); i++ )
205 delete defines[i];
206 for ( i = 0; i < libraries.size (); i++ )
207 delete libraries[i];
208 for ( std::map<std::string, Property*>::const_iterator p = properties.begin(); p != properties.end(); ++ p )
209 delete p->second;
210 for ( i = 0; i < compilerFlags.size (); i++ )
211 delete compilerFlags[i];
212 for ( i = 0; i < modules.size(); i++ )
213 delete modules[i];
214 for ( i = 0; i < compilationUnits.size (); i++ )
215 delete compilationUnits[i];
216 }
217
218 void IfableData::ProcessXML ()
219 {
220 size_t i;
221 for ( i = 0; i < includes.size (); i++ )
222 includes[i]->ProcessXML ();
223 for ( i = 0; i < defines.size (); i++ )
224 defines[i]->ProcessXML ();
225 for ( i = 0; i < libraries.size (); i++ )
226 libraries[i]->ProcessXML ();
227 for ( std::map<std::string, Property*>::const_iterator p = properties.begin(); p != properties.end(); ++ p )
228 p->second->ProcessXML ();
229 for ( i = 0; i < compilerFlags.size(); i++ )
230 compilerFlags[i]->ProcessXML ();
231 for ( i = 0; i < compilationUnits.size (); i++ )
232 compilationUnits[i]->ProcessXML ();
233 }
234
235 bool Module::GetBooleanAttribute ( const XMLElement& moduleNode, const char * name, bool default_value )
236 {
237 const XMLAttribute* att = moduleNode.GetAttribute ( name, false );
238 if ( att != NULL )
239 {
240 const char* p = att->value.c_str();
241 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
242 return true;
243 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
244 return false;
245 else
246 {
247 throw InvalidAttributeValueException (
248 moduleNode.location,
249 name,
250 att->value );
251 }
252 }
253 else
254 return default_value;
255 }
256
257 Module::Module ( const Project& project,
258 const XMLElement& moduleNode,
259 const string& modulePath )
260 : project (project),
261 node (moduleNode),
262 importLibrary (NULL),
263 delayImportLibrary (NULL),
264 metadata (NULL),
265 bootSector (NULL),
266 bootstrap (NULL),
267 autoRegister(NULL),
268 linkerScript (NULL),
269 pch (NULL),
270 cplusplus (false),
271 output (NULL),
272 install (NULL)
273 {
274 if ( node.name != "module" )
275 throw InvalidOperationException ( __FILE__,
276 __LINE__,
277 "Module created with non-<module> node" );
278
279 xmlbuildFile = FixSeparator ( Path::RelativeFromWorkingDirectory ( moduleNode.xmlFile->filename () ) );
280
281 const XMLAttribute* att = moduleNode.GetAttribute ( "name", true );
282 assert(att);
283 name = att->value;
284
285 enabled = true;
286
287 att = moduleNode.GetAttribute ( "if", false );
288 if ( att != NULL )
289 enabled = GetBooleanValue ( project.ResolveProperties ( att->value ) );
290
291 att = moduleNode.GetAttribute ( "ifnot", false );
292 if ( att != NULL )
293 enabled = !GetBooleanValue ( project.ResolveProperties ( att->value ) );
294
295 if ( !enabled && project.configuration.Verbose )
296 printf("Module '%s' has been disabled.\n", name.c_str () );
297
298 att = moduleNode.GetAttribute ( "type", true );
299 assert(att);
300 type = GetModuleType ( node.location, *att );
301
302 att = moduleNode.GetAttribute ( "extension", false );
303 if ( att != NULL )
304 extension = att->value;
305 else
306 extension = GetDefaultModuleExtension ();
307
308 isUnicode = GetBooleanAttribute ( moduleNode, "unicode" );
309
310 if (isUnicode)
311 {
312 // Always define UNICODE and _UNICODE
313 Define* pDefine = new Define ( project, this, "UNICODE" );
314 non_if_data.defines.push_back ( pDefine );
315
316 pDefine = new Define ( project, this, "_UNICODE" );
317 non_if_data.defines.push_back ( pDefine );
318 }
319
320 att = moduleNode.GetAttribute ( "entrypoint", false );
321 if ( att != NULL )
322 {
323 if ( att->value == "" )
324 {
325 throw InvalidAttributeValueException (
326 moduleNode.location,
327 "entrypoint",
328 att->value );
329 }
330
331 entrypoint = att->value;
332 isDefaultEntryPoint = false;
333 }
334 else
335 {
336 entrypoint = GetDefaultModuleEntrypoint ();
337 isDefaultEntryPoint = true;
338 }
339
340 att = moduleNode.GetAttribute ( "baseaddress", false );
341 if ( att != NULL )
342 baseaddress = att->value;
343 else
344 baseaddress = GetDefaultModuleBaseaddress ();
345
346 mangledSymbols = GetBooleanAttribute ( moduleNode, "mangledsymbols" );
347
348 att = moduleNode.GetAttribute ( "underscoresymbols", false );
349 if ( att != NULL )
350 underscoreSymbols = att->value == "true";
351 else
352 underscoreSymbols = false;
353
354 isStartupLib = GetBooleanAttribute ( moduleNode, "isstartuplib" );
355 isCRT = GetBooleanAttribute ( moduleNode, "iscrt", GetDefaultModuleIsCRT () );
356
357 att = moduleNode.GetAttribute ( "crt", false );
358 if ( att != NULL)
359 {
360 CRT = att->value;
361
362 if ( stricmp ( CRT.c_str (), "auto" ) == 0 )
363 CRT = GetDefaultModuleCRT ();
364 }
365 else
366 CRT = GetDefaultModuleCRT ();
367
368 const char * crtAttr = CRT.c_str ();
369 if ( crtAttr == NULL || stricmp ( crtAttr, "none" ) == 0 )
370 dynamicCRT = false;
371 else if ( stricmp ( crtAttr, "libc" ) == 0 )
372 dynamicCRT = false;
373 else if ( stricmp ( crtAttr, "msvcrt" ) == 0 )
374 dynamicCRT = true;
375 else if ( stricmp ( crtAttr, "libcntpr" ) == 0 )
376 dynamicCRT = false;
377 else if ( stricmp ( crtAttr, "ntdll" ) == 0 )
378 dynamicCRT = true;
379 else if ( stricmp ( crtAttr, "static" ) == 0 )
380 dynamicCRT = false;
381 else if ( stricmp ( crtAttr, "dll" ) == 0 )
382 dynamicCRT = true;
383 else
384 {
385 throw InvalidAttributeValueException (
386 moduleNode.location,
387 "crt",
388 std::string ( crtAttr ) );
389 }
390
391 if ( isCRT && dynamicCRT )
392 {
393 throw XMLInvalidBuildFileException (
394 moduleNode.location,
395 "C runtime module '%s' cannot be compiled for a dynamically-linked C runtime",
396 name.c_str() );
397 }
398
399 att = moduleNode.GetAttribute ( "prefix", false );
400 if ( att != NULL )
401 prefix = att->value;
402
403 att = moduleNode.GetAttribute ( "installname", false );
404 if ( att != NULL )
405 {
406 const XMLAttribute* installbase = moduleNode.GetAttribute ( "installbase", false );
407 install = new FileLocation ( InstallDirectory,
408 installbase ? installbase->value : "",
409 att->value,
410 &moduleNode );
411
412 output = new FileLocation ( GetTargetDirectoryTree (),
413 modulePath,
414 att->value,
415 &moduleNode );
416 }
417
418 att = moduleNode.GetAttribute ( "output", false );
419 if ( att != NULL )
420 {
421 if (output != NULL)
422 {
423 printf ( "%s: WARNING: 'installname' overrides 'output' also defined for this module.\n",
424 moduleNode.location.c_str() );
425 }
426 else
427 {
428 output = new FileLocation ( GetTargetDirectoryTree (),
429 modulePath,
430 att->value,
431 &moduleNode );
432 }
433 }
434
435 /* If no one has set the output file for this module set it automatically */
436 if (output == NULL)
437 {
438 output = new FileLocation ( GetTargetDirectoryTree (),
439 modulePath,
440 name + extension,
441 &moduleNode );
442 }
443
444 att = moduleNode.GetAttribute ( "allowwarnings", false );
445 if ( att == NULL )
446 {
447 att = moduleNode.GetAttribute ( "warnings", false );
448 if ( att != NULL )
449 {
450 printf ( "%s: WARNING: 'warnings' attribute of <module> is deprecated, use 'allowwarnings' instead\n",
451 moduleNode.location.c_str() );
452 }
453 }
454 if ( att != NULL )
455 allowWarnings = att->value == "true";
456 else if ( project.allowWarningsSet )
457 allowWarnings = project.allowWarnings;
458 else
459 allowWarnings = false;
460
461 att = moduleNode.GetAttribute ( "aliasof", false );
462 if ( type == Alias && att != NULL )
463 aliasedModuleName = att->value;
464 else
465 aliasedModuleName = "";
466
467 if ( type == BootProgram )
468 {
469 att = moduleNode.GetAttribute ( "payload", true );
470 payload = att->value;
471 }
472
473 if ( type == BootProgram || type == ElfExecutable )
474 {
475 att = moduleNode.GetAttribute ( "buildtype", false );
476 if ( att != NULL )
477 {
478 buildtype = att->value;
479 }
480 else
481 {
482 buildtype = "BOOTPROG";
483 }
484 }
485
486 att = moduleNode.GetAttribute ( "description", false );
487 if (att != NULL )
488 {
489 description = project.ResolveProperties(att->value);
490 }
491 else
492 description = "";
493
494 att = moduleNode.GetAttribute ( "lcid", false );
495 if (type == KeyboardLayout && att != NULL )
496 lcid = att->value;
497 else
498 lcid = "";
499
500 att = moduleNode.GetAttribute ( "layoutid", false );
501 if (type == KeyboardLayout && att != NULL )
502 layoutId = att->value;
503 else
504 layoutId = "";
505
506 att = moduleNode.GetAttribute ( "layoutnameresid", false );
507 if (type == KeyboardLayout && att != NULL )
508 layoutNameResId = att->value;
509 else
510 layoutNameResId = "";
511
512 SetImportLibrary ( NULL );
513 }
514
515 Module::~Module ()
516 {
517 size_t i;
518 for ( i = 0; i < invocations.size(); i++ )
519 delete invocations[i];
520 for ( i = 0; i < dependencies.size(); i++ )
521 delete dependencies[i];
522 for ( i = 0; i < compilerFlags.size(); i++ )
523 delete compilerFlags[i];
524 for ( i = 0; i < linkerFlags.size(); i++ )
525 delete linkerFlags[i];
526 for ( i = 0; i < stubbedComponents.size(); i++ )
527 delete stubbedComponents[i];
528 if ( linkerScript )
529 delete linkerScript;
530 if ( pch )
531 delete pch;
532 if ( install )
533 delete install;
534 if ( metadata )
535 delete metadata;
536 if ( bootstrap )
537 delete bootstrap;
538 if ( importLibrary )
539 delete importLibrary;
540 if ( bootSector )
541 delete bootSector;
542 if ( dependency )
543 delete dependency;
544 if ( autoRegister )
545 delete autoRegister;
546 if ( output )
547 delete output;
548 }
549
550 void
551 Module::ProcessXML()
552 {
553 if ( type == Alias )
554 {
555 aliasedModuleName = project.ResolveProperties ( aliasedModuleName );
556 if ( aliasedModuleName == name )
557 {
558 throw XMLInvalidBuildFileException (
559 node.location,
560 "module '%s' cannot link against itself",
561 name.c_str() );
562 }
563 const Module* m = project.LocateModule ( aliasedModuleName );
564 if ( !m && enabled )
565 {
566 throw XMLInvalidBuildFileException (
567 node.location,
568 "module '%s' trying to alias non-existant module '%s'",
569 name.c_str(),
570 aliasedModuleName.c_str() );
571 }
572 }
573
574 size_t i;
575 for ( i = 0; i < node.subElements.size(); i++ )
576 {
577 ParseContext parseContext;
578 ProcessXMLSubElement ( *node.subElements[i], SourceDirectory, output->relative_path, parseContext );
579 }
580 for ( i = 0; i < invocations.size(); i++ )
581 invocations[i]->ProcessXML ();
582 for ( i = 0; i < dependencies.size(); i++ )
583 dependencies[i]->ProcessXML ();
584 for ( i = 0; i < compilerFlags.size(); i++ )
585 compilerFlags[i]->ProcessXML();
586 for ( i = 0; i < linkerFlags.size(); i++ )
587 linkerFlags[i]->ProcessXML();
588 for ( i = 0; i < stubbedComponents.size(); i++ )
589 stubbedComponents[i]->ProcessXML();
590 non_if_data.ProcessXML();
591 if ( linkerScript )
592 linkerScript->ProcessXML();
593 if ( pch )
594 pch->ProcessXML();
595 if ( autoRegister )
596 autoRegister->ProcessXML();
597 }
598
599 void
600 Module::ProcessXMLSubElement ( const XMLElement& e,
601 DirectoryLocation directory,
602 const string& relative_path,
603 ParseContext& parseContext )
604 {
605 const XMLAttribute* att;
606
607 att = e.GetAttribute ( "compilerset", false );
608
609 if ( att )
610 {
611 CompilerSet compilerSet;
612
613 if ( att->value == "msc" )
614 compilerSet = MicrosoftC;
615 else if ( att->value == "gcc" )
616 compilerSet = GnuGcc;
617 else
618 throw InvalidAttributeValueException (
619 e.location,
620 "compilerset",
621 att->value );
622
623 if ( compilerSet != project.configuration.Compiler )
624 return;
625 }
626
627 att = e.GetAttribute ( "linkerset", false );
628
629 if ( att )
630 {
631 LinkerSet linkerSet;
632
633 if ( att->value == "mslink" )
634 linkerSet = MicrosoftLink;
635 else if ( att->value == "ld" )
636 linkerSet = GnuLd;
637 else
638 throw InvalidAttributeValueException (
639 e.location,
640 "linkerset",
641 att->value );
642
643 if ( linkerSet != project.configuration.Linker )
644 return;
645 }
646
647 CompilationUnit* pOldCompilationUnit = parseContext.compilationUnit;
648 bool subs_invalid = false;
649 string subpath ( relative_path );
650 DirectoryLocation subdirectory = SourceDirectory;
651 if ( e.name == "file" && e.value.size () > 0 )
652 {
653 bool first = false;
654 const XMLAttribute* att = e.GetAttribute ( "first", false );
655 if ( att != NULL )
656 {
657 if ( !stricmp ( att->value.c_str(), "true" ) )
658 first = true;
659 else if ( stricmp ( att->value.c_str(), "false" ) )
660 {
661 throw XMLInvalidBuildFileException (
662 e.location,
663 "attribute 'first' of <file> element can only be 'true' or 'false'" );
664 }
665 }
666 string switches = "";
667 att = e.GetAttribute ( "switches", false );
668 if ( att != NULL )
669 switches = att->value;
670 if ( !cplusplus )
671 {
672 // check for c++ file
673 string ext = GetExtension ( e.value );
674 if ( !stricmp ( ext.c_str(), ".cpp" ) )
675 cplusplus = true;
676 else if ( !stricmp ( ext.c_str(), ".cc" ) )
677 cplusplus = true;
678 else if ( !stricmp ( ext.c_str(), ".cxx" ) )
679 cplusplus = true;
680 }
681 File* pFile = new File ( directory,
682 relative_path,
683 e.value,
684 first,
685 switches,
686 false );
687 if ( parseContext.compilationUnit )
688 parseContext.compilationUnit->AddFile ( pFile );
689 else
690 {
691 CompilationUnit* pCompilationUnit = new CompilationUnit ( pFile );
692 string ext = ToLower ( GetExtension ( e.value ) );
693 if ( ext == ".idl" )
694 {
695 // put .idl files at the start of the module
696 non_if_data.compilationUnits.insert (
697 non_if_data.compilationUnits.begin(),
698 pCompilationUnit );
699 }
700 else if ( ext == ".asm" || ext == ".s" )
701 {
702 // put .asm files at the end of the module
703 non_if_data.compilationUnits.push_back ( pCompilationUnit );
704 non_if_data.asmFiles++;
705 }
706 else
707 {
708 // put other files in the middle
709 non_if_data.compilationUnits.insert (
710 non_if_data.compilationUnits.end() - non_if_data.asmFiles,
711 pCompilationUnit );
712 }
713 }
714 non_if_data.files.push_back ( pFile );
715 subs_invalid = true;
716 }
717 else if ( e.name == "library" && e.value.size () )
718 {
719 const XMLAttribute* att = e.GetAttribute ( "delayimport", false );
720 Library* pLibrary = new Library ( e, *this, e.value );
721 if ( att && !stricmp ( att->value.c_str(), "true" ) )
722 pLibrary->delayimp = true;
723 non_if_data.libraries.push_back ( pLibrary );
724 subs_invalid = true;
725 }
726 else if ( e.name == "directory" )
727 {
728 const XMLAttribute* att = e.GetAttribute ( "name", true );
729 const XMLAttribute* root = e.GetAttribute ( "root", false );
730 assert(att);
731 if ( root )
732 {
733 if ( root->value == "intermediate" )
734 subdirectory = IntermediateDirectory;
735 else if ( root->value == "output" )
736 subdirectory = OutputDirectory;
737 else
738 {
739 throw InvalidAttributeValueException (
740 e.location,
741 "root",
742 root->value );
743 }
744 }
745 subpath = GetSubPath ( this->project, e.location, relative_path, att->value );
746 }
747 else if ( e.name == "include" )
748 {
749 Include* include = new Include ( project, &e, this );
750 non_if_data.includes.push_back ( include );
751 subs_invalid = true;
752 }
753 else if ( e.name == "define" || e.name == "redefine" )
754 {
755 Define* pDefine = new Define ( project, this, e );
756 non_if_data.defines.push_back ( pDefine );
757 subs_invalid = true;
758 }
759 else if ( e.name == "metadata" )
760 {
761 metadata = new Metadata ( e, *this );
762 subs_invalid = false;
763 }
764 else if ( e.name == "invoke" )
765 {
766 invocations.push_back ( new Invoke ( e, *this ) );
767 subs_invalid = false;
768 }
769 else if ( e.name == "dependency" )
770 {
771 dependencies.push_back ( new Dependency ( e, *this ) );
772 subs_invalid = true;
773 }
774 else if ( e.name == "bootsector" )
775 {
776 bootSector = new Bootsector ( e, this );
777 subs_invalid = true;
778 }
779 else if ( e.name == "importlibrary" )
780 {
781 if ( importLibrary )
782 {
783 throw XMLInvalidBuildFileException (
784 e.location,
785 "Only one <importlibrary> is valid per module" );
786 }
787 SetImportLibrary ( new ImportLibrary ( project, e, this, false ) );
788 SetDelayImportLibrary ( new ImportLibrary ( project, e, this, true ) );
789 subs_invalid = true;
790 }
791 else if ( e.name == "if" || e.name == "ifnot" )
792 {
793 const XMLAttribute* name;
794 name = e.GetAttribute ( "property", true );
795 assert( name );
796 const Property *property = project.LookupProperty( name->value );
797 const string *PropertyValue;
798 const string EmptyString;
799
800 if (property)
801 {
802 PropertyValue = &property->value;
803 }
804 else
805 {
806 // Property does not exist, treat it as being empty
807 PropertyValue = &EmptyString;
808 }
809
810 const XMLAttribute* value;
811 value = e.GetAttribute ( "value", true );
812 assert( value );
813
814 bool negate = ( e.name == "ifnot" );
815 bool equality = ( *PropertyValue == value->value );
816 if ( equality == negate )
817 {
818 // Failed, skip this element
819 if ( project.configuration.Verbose )
820 printf("Skipping 'If' at %s\n", e.location.c_str () );
821 return;
822 }
823 subs_invalid = false;
824 }
825 else if ( e.name == "compilerflag" )
826 {
827 CompilerFlag* pCompilerFlag = new CompilerFlag ( project, this, e );
828 non_if_data.compilerFlags.push_back ( pCompilerFlag );
829 subs_invalid = true;
830 }
831 else if ( e.name == "linkerflag" )
832 {
833 linkerFlags.push_back ( new LinkerFlag ( project, this, e ) );
834 subs_invalid = true;
835 }
836 else if ( e.name == "linkerscript" )
837 {
838 if ( linkerScript )
839 {
840 throw XMLInvalidBuildFileException (
841 e.location,
842 "Only one <linkerscript> is valid per module" );
843 }
844 size_t pos = e.value.find_last_of ( "/\\" );
845 if ( pos == string::npos )
846 {
847 linkerScript = new LinkerScript (
848 e, *this, new FileLocation ( SourceDirectory, relative_path, e.value, &e ) );
849 }
850 else
851 {
852 string dir = e.value.substr ( 0, pos );
853 string name = e.value.substr ( pos + 1);
854 linkerScript = new LinkerScript (
855 e, *this, new FileLocation ( SourceDirectory, relative_path + sSep + dir, name, &e ) );
856 }
857 subs_invalid = true;
858 }
859 else if ( e.name == "component" )
860 {
861 stubbedComponents.push_back ( new StubbedComponent ( this, e ) );
862 subs_invalid = false;
863 }
864 else if ( e.name == "property" )
865 {
866 throw XMLInvalidBuildFileException (
867 e.location,
868 "<property> is not a valid sub-element of <module>" );
869 }
870 else if ( e.name == "bootstrap" )
871 {
872 bootstrap = new Bootstrap ( project, this, e );
873 subs_invalid = true;
874 }
875 else if ( e.name == "pch" )
876 {
877 if ( pch )
878 {
879 throw XMLInvalidBuildFileException (
880 e.location,
881 "Only one <pch> is valid per module" );
882 }
883 size_t pos = e.value.find_last_of ( "/\\" );
884 if ( pos == string::npos )
885 {
886 pch = new PchFile (
887 e, *this, new FileLocation ( SourceDirectory, relative_path, e.value, &e ) );
888 }
889 else
890 {
891 string dir = e.value.substr ( 0, pos );
892 string name = e.value.substr ( pos + 1);
893 pch = new PchFile (
894 e, *this, new FileLocation ( SourceDirectory, relative_path + sSep + dir, name, &e ) );
895 }
896 subs_invalid = true;
897 }
898 else if ( e.name == "compilationunit" )
899 {
900 if ( project.configuration.CompilationUnitsEnabled )
901 {
902 CompilationUnit* pCompilationUnit = new CompilationUnit ( &project, this, &e );
903 non_if_data.compilationUnits.push_back ( pCompilationUnit );
904 parseContext.compilationUnit = pCompilationUnit;
905 }
906 subs_invalid = false;
907 }
908 else if ( e.name == "autoregister" )
909 {
910 if ( autoRegister != NULL)
911 {
912 throw XMLInvalidBuildFileException (
913 e.location,
914 "there can be only one <%s> element for a module",
915 e.name.c_str() );
916 }
917 autoRegister = new AutoRegister ( project, this, e );
918 subs_invalid = true;
919 }
920 if ( subs_invalid && e.subElements.size() > 0 )
921 {
922 throw XMLInvalidBuildFileException (
923 e.location,
924 "<%s> cannot have sub-elements",
925 e.name.c_str() );
926 }
927 for ( size_t i = 0; i < e.subElements.size (); i++ )
928 ProcessXMLSubElement ( *e.subElements[i], subdirectory, subpath, parseContext );
929 parseContext.compilationUnit = pOldCompilationUnit;
930 }
931
932 ModuleType
933 Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
934 {
935 if ( attribute.value == "buildtool" )
936 return BuildTool;
937 if ( attribute.value == "staticlibrary" )
938 return StaticLibrary;
939 if ( attribute.value == "hoststaticlibrary" )
940 return HostStaticLibrary;
941 if ( attribute.value == "objectlibrary" )
942 return ObjectLibrary;
943 if ( attribute.value == "kernel" )
944 return Kernel;
945 if ( attribute.value == "kernelmodedll" )
946 return KernelModeDLL;
947 if ( attribute.value == "kernelmodedriver" )
948 return KernelModeDriver;
949 if ( attribute.value == "nativedll" )
950 return NativeDLL;
951 if ( attribute.value == "nativecui" )
952 return NativeCUI;
953 if ( attribute.value == "keyboardlayout" )
954 return KeyboardLayout;
955 if ( attribute.value == "win32dll" )
956 return Win32DLL;
957 if ( attribute.value == "win32ocx" )
958 return Win32OCX;
959 if ( attribute.value == "win32cui" )
960 return Win32CUI;
961 if ( attribute.value == "win32gui" )
962 return Win32GUI;
963 if ( attribute.value == "win32scr" )
964 return Win32SCR;
965 if ( attribute.value == "bootloader" )
966 return BootLoader;
967 if ( attribute.value == "bootsector" )
968 return BootSector;
969 if ( attribute.value == "bootprogram" )
970 return BootProgram;
971 if ( attribute.value == "iso" )
972 return Iso;
973 if ( attribute.value == "liveiso" )
974 return LiveIso;
975 if ( attribute.value == "isoregtest" )
976 return IsoRegTest;
977 if ( attribute.value == "liveisoregtest" )
978 return LiveIsoRegTest;
979 if ( attribute.value == "test" )
980 return Test;
981 if ( attribute.value == "rpcserver" )
982 return RpcServer;
983 if ( attribute.value == "rpcclient" )
984 return RpcClient;
985 if ( attribute.value == "rpcproxy" )
986 return RpcProxy;
987 if ( attribute.value == "alias" )
988 return Alias;
989 if ( attribute.value == "idlheader" )
990 return IdlHeader;
991 if ( attribute.value == "idlinterface" )
992 return IdlInterface;
993 if ( attribute.value == "embeddedtypelib" )
994 return EmbeddedTypeLib;
995 if ( attribute.value == "elfexecutable" )
996 return ElfExecutable;
997 if ( attribute.value == "cabinet" )
998 return Cabinet;
999 if ( attribute.value == "messageheader" )
1000 return MessageHeader;
1001 throw InvalidAttributeValueException ( location,
1002 attribute.name,
1003 attribute.value );
1004 }
1005
1006 DirectoryLocation
1007 Module::GetTargetDirectoryTree () const
1008 {
1009 switch ( type )
1010 {
1011 case Kernel:
1012 case KernelModeDLL:
1013 case KeyboardLayout:
1014 case NativeDLL:
1015 case Win32DLL:
1016 case Win32OCX:
1017 case KernelModeDriver:
1018 case NativeCUI:
1019 case Win32CUI:
1020 case Test:
1021 case Win32SCR:
1022 case Win32GUI:
1023 case BuildTool:
1024 case BootLoader:
1025 case BootSector:
1026 case BootProgram:
1027 case Iso:
1028 case LiveIso:
1029 case IsoRegTest:
1030 case LiveIsoRegTest:
1031 case ElfExecutable:
1032 case Cabinet:
1033 return OutputDirectory;
1034 case EmbeddedTypeLib:
1035 case StaticLibrary:
1036 case HostStaticLibrary:
1037 case ObjectLibrary:
1038 case RpcServer:
1039 case RpcClient:
1040 case RpcProxy:
1041 case Alias:
1042 case IdlHeader:
1043 case IdlInterface:
1044 case MessageHeader:
1045 return IntermediateDirectory;
1046 case TypeDontCare:
1047 break;
1048 }
1049 throw InvalidOperationException ( __FILE__,
1050 __LINE__,
1051 "Invalid module type %d.",
1052 type );
1053 }
1054
1055 string
1056 Module::GetDefaultModuleExtension () const
1057 {
1058 switch (type)
1059 {
1060 case BuildTool:
1061 return ExePostfix;
1062 case BootProgram:
1063 case StaticLibrary:
1064 case HostStaticLibrary:
1065 return ".a";
1066 case ObjectLibrary:
1067 return ".o";
1068 case Kernel:
1069 case NativeCUI:
1070 case Win32CUI:
1071 case Win32GUI:
1072 return ".exe";
1073 case Win32SCR:
1074 return ".scr";
1075
1076 case KernelModeDLL:
1077 case NativeDLL:
1078 case KeyboardLayout:
1079 case Win32DLL:
1080 return ".dll";
1081 case Win32OCX:
1082 return ".ocx";
1083 case KernelModeDriver:
1084 case BootLoader:
1085 return ".sys";
1086 case Cabinet:
1087 return ".cab";
1088 case BootSector:
1089 return ".o";
1090 case Iso:
1091 case LiveIso:
1092 case IsoRegTest:
1093 case LiveIsoRegTest:
1094 return ".iso";
1095 case Test:
1096 return ".exe";
1097 case RpcServer:
1098 case RpcClient:
1099 case RpcProxy:
1100 case IdlInterface:
1101 return ".o";
1102 case Alias:
1103 case ElfExecutable:
1104 case IdlHeader:
1105 case MessageHeader:
1106 return "";
1107 case EmbeddedTypeLib:
1108 return ".tlb";
1109 case TypeDontCare:
1110 break;
1111 }
1112 throw InvalidOperationException ( __FILE__,
1113 __LINE__ );
1114 }
1115
1116 string
1117 Module::GetDefaultModuleEntrypoint () const
1118 {
1119 switch ( type )
1120 {
1121 case Kernel:
1122 return "KiSystemStartup";
1123 case KeyboardLayout:
1124 case KernelModeDLL:
1125 case KernelModeDriver:
1126 if (Environment::GetArch() == "arm") return "DriverEntry";
1127 return "DriverEntry@8";
1128 case NativeDLL:
1129 if (Environment::GetArch() == "arm") return "DllMainCRTStartup";
1130 return "DllMainCRTStartup@12";
1131 case NativeCUI:
1132 if (Environment::GetArch() == "arm") return "NtProcessStartup";
1133 return "NtProcessStartup@4";
1134 case Win32DLL:
1135 case Win32OCX:
1136 if (Environment::GetArch() == "arm") return "DllMain";
1137 return "DllMain@12";
1138 case Win32CUI:
1139 case Test:
1140 return "mainCRTStartup";
1141 case Win32SCR:
1142 case Win32GUI:
1143 return "WinMainCRTStartup";
1144 case BuildTool:
1145 case StaticLibrary:
1146 case HostStaticLibrary:
1147 case ObjectLibrary:
1148 case BootLoader:
1149 case BootSector:
1150 case Iso:
1151 case LiveIso:
1152 case IsoRegTest:
1153 case LiveIsoRegTest:
1154 case RpcServer:
1155 case RpcClient:
1156 case RpcProxy:
1157 case Alias:
1158 case BootProgram:
1159 case IdlHeader:
1160 case IdlInterface:
1161 case MessageHeader:
1162 case ElfExecutable:
1163 case EmbeddedTypeLib:
1164 case Cabinet:
1165 return "";
1166 case TypeDontCare:
1167 break;
1168 }
1169 throw InvalidOperationException ( __FILE__,
1170 __LINE__ );
1171 }
1172
1173 string
1174 Module::GetDefaultModuleBaseaddress () const
1175 {
1176 switch ( type )
1177 {
1178 case Kernel:
1179 return "0x80800000";
1180 case Win32DLL:
1181 case Win32OCX:
1182 return "0x10000000";
1183 case NativeDLL:
1184 case NativeCUI:
1185 case Win32CUI:
1186 case Test:
1187 return "0x00400000";
1188 case Win32SCR:
1189 case Win32GUI:
1190 return "0x00400000";
1191 case KeyboardLayout:
1192 case KernelModeDLL:
1193 case KernelModeDriver:
1194 return "0x00010000";
1195 case ElfExecutable:
1196 return "0xe00000";
1197 case BuildTool:
1198 case StaticLibrary:
1199 case HostStaticLibrary:
1200 case ObjectLibrary:
1201 case BootLoader:
1202 case BootSector:
1203 case Iso:
1204 case LiveIso:
1205 case IsoRegTest:
1206 case LiveIsoRegTest:
1207 case RpcServer:
1208 case RpcClient:
1209 case RpcProxy:
1210 case Alias:
1211 case BootProgram:
1212 case IdlHeader:
1213 case IdlInterface:
1214 case MessageHeader:
1215 case EmbeddedTypeLib:
1216 case Cabinet:
1217 return "";
1218 case TypeDontCare:
1219 break;
1220 }
1221 throw InvalidOperationException ( __FILE__,
1222 __LINE__ );
1223 }
1224
1225 std::string
1226 Module::GetDefaultModuleCRT () const
1227 {
1228 if ( isCRT )
1229 return "static";
1230
1231 switch ( type )
1232 {
1233 case Kernel:
1234 return "static";
1235 case Win32DLL:
1236 case Win32OCX:
1237 return "ntdll";
1238 case NativeDLL:
1239 case NativeCUI:
1240 return "ntdll";
1241 case Win32CUI:
1242 case Win32SCR:
1243 case Win32GUI:
1244 return "msvcrt";
1245 case Test:
1246 return "msvcrt"; // BUGBUG: not sure about this
1247 case KeyboardLayout:
1248 return "none";
1249 case KernelModeDLL:
1250 case KernelModeDriver:
1251 return "dll";
1252 case BootLoader:
1253 return "libcntpr";
1254 case ElfExecutable:
1255 case BuildTool:
1256 case StaticLibrary:
1257 case HostStaticLibrary:
1258 case ObjectLibrary:
1259 case BootSector:
1260 case Iso:
1261 case LiveIso:
1262 case IsoRegTest:
1263 case LiveIsoRegTest:
1264 case RpcServer:
1265 case RpcClient:
1266 case RpcProxy:
1267 case Alias:
1268 case BootProgram:
1269 case IdlHeader:
1270 case IdlInterface:
1271 case MessageHeader:
1272 case EmbeddedTypeLib:
1273 case Cabinet:
1274 case TypeDontCare:
1275 return "none";
1276 }
1277 throw InvalidOperationException ( __FILE__,
1278 __LINE__ );
1279 }
1280
1281 bool
1282 Module::GetDefaultModuleIsCRT () const
1283 {
1284 return type == Kernel;
1285 }
1286
1287 bool
1288 Module::HasImportLibrary () const
1289 {
1290 return importLibrary != NULL && type != StaticLibrary && type != HostStaticLibrary;
1291 }
1292
1293 bool
1294 Module::IsDLL () const
1295 {
1296 switch ( type )
1297 {
1298 case Kernel:
1299 case KernelModeDLL:
1300 case NativeDLL:
1301 case KeyboardLayout:
1302 case Win32DLL:
1303 case Win32OCX:
1304 case KernelModeDriver:
1305 return true;
1306 case NativeCUI:
1307 case Win32CUI:
1308 case Test:
1309 case Win32SCR:
1310 case Win32GUI:
1311 case BuildTool:
1312 case StaticLibrary:
1313 case HostStaticLibrary:
1314 case ObjectLibrary:
1315 case BootLoader:
1316 case BootSector:
1317 case BootProgram:
1318 case Iso:
1319 case LiveIso:
1320 case IsoRegTest:
1321 case LiveIsoRegTest:
1322 case RpcServer:
1323 case RpcClient:
1324 case RpcProxy:
1325 case Alias:
1326 case IdlHeader:
1327 case IdlInterface:
1328 case MessageHeader:
1329 case EmbeddedTypeLib:
1330 case ElfExecutable:
1331 case Cabinet:
1332 return false;
1333 case TypeDontCare:
1334 break;
1335 }
1336 throw InvalidOperationException ( __FILE__,
1337 __LINE__ );
1338 }
1339
1340 string
1341 Module::GetPathWithPrefix ( const string& prefix ) const
1342 {
1343 return output->relative_path + cSep + prefix + output->name;
1344 }
1345
1346 string
1347 Module::GetPathToBaseDir () const
1348 {
1349 string temp_path = output->relative_path;
1350 string result = "..\\";
1351 while(temp_path.find ('\\') != string::npos)
1352 {
1353 temp_path.erase (0, temp_path.find('\\')+1);
1354 result += "..\\";
1355 }
1356 return result;
1357 }
1358
1359 string
1360 Module::GetInvocationTarget ( const int index ) const
1361 {
1362 return ssprintf ( "%s_invoke_%d",
1363 name.c_str (),
1364 index );
1365 }
1366
1367 string
1368 Module::GetEntryPoint(bool leadingUnderscore) const
1369 {
1370 string result = "";
1371 if (entrypoint == "0" || entrypoint == "0x0")
1372 return "0";
1373 if (leadingUnderscore)
1374 result = "_";
1375
1376 result += entrypoint;
1377
1378 if (Environment::GetArch() == "amd64")
1379 {
1380 size_t at_index = result.find_last_of( '@' );
1381 if ( at_index != result.npos )
1382 return result.substr (0, at_index );
1383 }
1384
1385 return result;
1386 }
1387
1388 bool
1389 Module::HasFileWithExtension (
1390 const IfableData& data,
1391 const std::string& extension ) const
1392 {
1393 size_t i;
1394 for ( i = 0; i < data.compilationUnits.size (); i++ )
1395 {
1396 CompilationUnit* compilationUnit = data.compilationUnits[i];
1397 if ( compilationUnit->HasFileWithExtension ( extension ) )
1398 return true;
1399 }
1400 return false;
1401 }
1402
1403 void
1404 Module::InvokeModule () const
1405 {
1406 for ( size_t i = 0; i < invocations.size (); i++ )
1407 {
1408 Invoke& invoke = *invocations[i];
1409 string command = FixSeparatorForSystemCommand(invoke.invokeModule->output->relative_path + "/" + invoke.invokeModule->output->name ) + " " + invoke.GetParameters ();
1410 printf ( "Executing '%s'\n\n", command.c_str () );
1411 int exitcode = system ( command.c_str () );
1412 if ( exitcode != 0 )
1413 throw InvocationFailedException ( command,
1414 exitcode );
1415 }
1416 }
1417
1418
1419 void
1420 Module::SetImportLibrary ( ImportLibrary* importLibrary )
1421 {
1422 this->importLibrary = importLibrary;
1423 dependency = new FileLocation ( HasImportLibrary () ? IntermediateDirectory : output->directory,
1424 output->relative_path,
1425 HasImportLibrary () ? "lib" + name + ".a" : output->name );
1426 }
1427
1428 void
1429 Module::SetDelayImportLibrary ( ImportLibrary* importLibrary )
1430 {
1431 this->delayImportLibrary = importLibrary;
1432 }
1433
1434 std::string
1435 Module::GetDllName () const
1436 {
1437 if ( importLibrary && !importLibrary->dllname.empty() )
1438 return importLibrary->dllname;
1439 else if ( output )
1440 return output->name;
1441 else
1442 throw new InvalidOperationException ( __FILE__, __LINE__, "Module %s has no dllname." );
1443 }
1444
1445 File::File ( DirectoryLocation directory,
1446 const string& relative_path,
1447 const string& name,
1448 bool _first,
1449 const string& _switches,
1450 bool _isPreCompiledHeader )
1451 : file ( directory, relative_path, name ),
1452 first(_first),
1453 switches(_switches),
1454 isPreCompiledHeader(_isPreCompiledHeader)
1455 {
1456 }
1457
1458
1459 void
1460 File::ProcessXML()
1461 {
1462 }
1463
1464
1465 std::string File::GetFullPath () const
1466 {
1467 string directory ( "" );
1468 switch ( file.directory )
1469 {
1470 case SourceDirectory:
1471 break;
1472 case IntermediateDirectory:
1473 directory = Environment::GetIntermediatePath () + sSep;
1474 break;
1475 default:
1476 throw InvalidOperationException ( __FILE__,
1477 __LINE__,
1478 "Invalid directory %d.",
1479 file.directory );
1480 }
1481
1482 if ( file.relative_path.length () > 0 )
1483 directory += file.relative_path + sSep;
1484
1485
1486 return directory + file.name;
1487 }
1488
1489
1490 Library::Library ( const XMLElement& _node,
1491 const Module& _module,
1492 const string& _name )
1493 : node(&_node),
1494 module(_module),
1495 name(_name),
1496 importedModule(_module.project.LocateModule(_name)),
1497 delayimp(false)
1498 {
1499 if ( module.name == name )
1500 {
1501 throw XMLInvalidBuildFileException (
1502 node->location,
1503 "module '%s' cannot link against itself",
1504 name.c_str() );
1505 }
1506 if ( !importedModule )
1507 {
1508 throw XMLInvalidBuildFileException (
1509 node->location,
1510 "module '%s' trying to import non-existant module '%s'",
1511 module.name.c_str(),
1512 name.c_str() );
1513 }
1514 }
1515
1516 Library::Library ( const Module& _module,
1517 const string& _name )
1518 : node(NULL),
1519 module(_module),
1520 name(_name),
1521 importedModule(_module.project.LocateModule(_name)),
1522 delayimp(false)
1523 {
1524 if ( !importedModule )
1525 {
1526 throw XMLInvalidBuildFileException (
1527 "<internal>",
1528 "module '%s' trying to import non-existant module '%s'",
1529 module.name.c_str(),
1530 name.c_str() );
1531 }
1532 }
1533
1534 void
1535 Library::ProcessXML()
1536 {
1537 if ( node && !module.project.LocateModule ( name ) )
1538 {
1539 throw XMLInvalidBuildFileException (
1540 node->location,
1541 "module '%s' is trying to link against non-existant module '%s'",
1542 module.name.c_str(),
1543 name.c_str() );
1544 }
1545 }
1546
1547
1548 Invoke::Invoke ( const XMLElement& _node,
1549 const Module& _module )
1550 : node (_node),
1551 module (_module)
1552 {
1553 }
1554
1555 void
1556 Invoke::ProcessXML()
1557 {
1558 const XMLAttribute* att = node.GetAttribute ( "module", false );
1559 if (att == NULL)
1560 invokeModule = &module;
1561 else
1562 {
1563 invokeModule = module.project.LocateModule ( att->value );
1564 if ( invokeModule == NULL )
1565 {
1566 throw XMLInvalidBuildFileException (
1567 node.location,
1568 "module '%s' is trying to invoke non-existant module '%s'",
1569 module.name.c_str(),
1570 att->value.c_str() );
1571 }
1572 }
1573
1574 for ( size_t i = 0; i < node.subElements.size (); i++ )
1575 ProcessXMLSubElement ( *node.subElements[i] );
1576 }
1577
1578 void
1579 Invoke::ProcessXMLSubElement ( const XMLElement& e )
1580 {
1581 bool subs_invalid = false;
1582 if ( e.name == "input" )
1583 {
1584 for ( size_t i = 0; i < e.subElements.size (); i++ )
1585 ProcessXMLSubElementInput ( *e.subElements[i] );
1586 }
1587 else if ( e.name == "output" )
1588 {
1589 for ( size_t i = 0; i < e.subElements.size (); i++ )
1590 ProcessXMLSubElementOutput ( *e.subElements[i] );
1591 }
1592 if ( subs_invalid && e.subElements.size() > 0 )
1593 {
1594 throw XMLInvalidBuildFileException (
1595 e.location,
1596 "<%s> cannot have sub-elements",
1597 e.name.c_str() );
1598 }
1599 }
1600
1601 void
1602 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
1603 {
1604 bool subs_invalid = false;
1605 if ( e.name == "inputfile" && e.value.size () > 0 )
1606 {
1607 input.push_back ( new InvokeFile (
1608 e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
1609 subs_invalid = true;
1610 }
1611 if ( subs_invalid && e.subElements.size() > 0 )
1612 {
1613 throw XMLInvalidBuildFileException (
1614 e.location,
1615 "<%s> cannot have sub-elements",
1616 e.name.c_str() );
1617 }
1618 }
1619
1620 void
1621 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
1622 {
1623 bool subs_invalid = false;
1624 if ( e.name == "outputfile" && e.value.size () > 0 )
1625 {
1626 output.push_back ( new InvokeFile (
1627 e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
1628 subs_invalid = true;
1629 }
1630 if ( subs_invalid && e.subElements.size() > 0 )
1631 {
1632 throw XMLInvalidBuildFileException (
1633 e.location,
1634 "<%s> cannot have sub-elements",
1635 e.name.c_str() );
1636 }
1637 }
1638
1639 void
1640 Invoke::GetTargets ( string_list& targets ) const
1641 {
1642 for ( size_t i = 0; i < output.size (); i++ )
1643 {
1644 InvokeFile& file = *output[i];
1645 targets.push_back ( NormalizeFilename ( file.name ) );
1646 }
1647 }
1648
1649 string
1650 Invoke::GetParameters () const
1651 {
1652 string parameters ( "" );
1653 size_t i;
1654 for ( i = 0; i < output.size (); i++ )
1655 {
1656 if ( parameters.length () > 0)
1657 parameters += " ";
1658 InvokeFile& invokeFile = *output[i];
1659 if ( invokeFile.switches.length () > 0 )
1660 {
1661 parameters += invokeFile.switches + " ";
1662 }
1663 parameters += invokeFile.name;
1664 }
1665
1666 for ( i = 0; i < input.size (); i++ )
1667 {
1668 if ( parameters.length () > 0 )
1669 parameters += " ";
1670 InvokeFile& invokeFile = *input[i];
1671 if ( invokeFile.switches.length () > 0 )
1672 {
1673 parameters += invokeFile.switches;
1674 parameters += " ";
1675 }
1676 parameters += invokeFile.name ;
1677 }
1678
1679 return parameters;
1680 }
1681
1682
1683 InvokeFile::InvokeFile ( const XMLElement& _node,
1684 const string& _name )
1685 : node (_node),
1686 name (_name)
1687 {
1688 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
1689 if (att != NULL)
1690 switches = att->value;
1691 else
1692 switches = "";
1693 }
1694
1695 void
1696 InvokeFile::ProcessXML()
1697 {
1698 }
1699
1700
1701 Dependency::Dependency ( const XMLElement& _node,
1702 const Module& _module )
1703 : node (_node),
1704 module (_module),
1705 dependencyModule (NULL)
1706 {
1707 }
1708
1709 void
1710 Dependency::ProcessXML()
1711 {
1712 dependencyModule = module.project.LocateModule ( node.value );
1713 if ( dependencyModule == NULL )
1714 {
1715 throw XMLInvalidBuildFileException (
1716 node.location,
1717 "module '%s' depend on non-existant module '%s'",
1718 module.name.c_str(),
1719 node.value.c_str() );
1720 }
1721 }
1722
1723 Bootsector::Bootsector ( const XMLElement& _node,
1724 const Module* _module )
1725 : node (_node),
1726 module (_module),
1727 bootSectorModule (NULL)
1728 {
1729 if ( !IsSupportedModuleType ( module->type ) )
1730 {
1731 throw XMLInvalidBuildFileException (
1732 node.location,
1733 "<bootsector> is not applicable for this module type." );
1734 }
1735
1736 bootSectorModule = module->project.LocateModule ( node.value );
1737 if ( bootSectorModule == NULL )
1738 {
1739 throw XMLInvalidBuildFileException (
1740 node.location,
1741 "module '%s' depend on non-existant module '%s'",
1742 module->name.c_str(),
1743 node.value.c_str() );
1744 }
1745
1746 if (bootSectorModule->type != BootSector)
1747 {
1748 throw XMLInvalidBuildFileException (
1749 node.location,
1750 "module '%s' is referencing non BootSector module '%s'",
1751 module->name.c_str(),
1752 node.value.c_str() );
1753 }
1754 }
1755
1756 void
1757 Bootsector::ProcessXML()
1758 {
1759 }
1760
1761 bool
1762 Bootsector::IsSupportedModuleType ( ModuleType type )
1763 {
1764 if ( type == Iso ||
1765 type == LiveIso ||
1766 type == IsoRegTest ||
1767 type == LiveIsoRegTest )
1768 {
1769 return true;
1770 }
1771
1772 return false;
1773 }
1774
1775 Metadata::Metadata ( const XMLElement& _node,
1776 const Module& _module )
1777 : node (_node),
1778 module (_module)
1779 {
1780 /* The module name */
1781 const XMLAttribute* att = _node.GetAttribute ( "name", false );
1782 if (att != NULL)
1783 name = att->value;
1784 else
1785 name = module.name;
1786
1787 /* The module description */
1788 att = _node.GetAttribute ( "description", false );
1789 if (att != NULL)
1790 description = att->value;
1791 else
1792 description = "";
1793
1794 /* The module version */
1795 att = _node.GetAttribute ( "version", false );
1796 if (att != NULL)
1797 version = att->value;
1798 else
1799 version = "";
1800
1801 /* The module copyright */
1802 att = _node.GetAttribute ( "copyright", false );
1803 if (att != NULL)
1804 copyright = att->value;
1805 else
1806 copyright = "";
1807
1808 att = _node.GetAttribute ( "url", false );
1809 if (att != NULL)
1810 url = att->value;
1811 else
1812 url = "";
1813
1814 /* When was this module updated */
1815 att = _node.GetAttribute ( "date", false );
1816 if (att != NULL)
1817 date = att->value;
1818 else
1819 date = "?";
1820
1821 /* When was this module updated */
1822 att = _node.GetAttribute ( "owner", false );
1823 if (att != NULL)
1824 owner = att->value;
1825 else
1826 owner = "ReactOS";
1827 }
1828
1829
1830 ImportLibrary::~ImportLibrary ()
1831 {
1832 delete source;
1833 delete target;
1834 }
1835
1836
1837 ImportLibrary::ImportLibrary ( const Project& project,
1838 const XMLElement& node,
1839 const Module* module,
1840 bool delayimp )
1841 : XmlNode ( project, node ),
1842 module (module)
1843 {
1844 DirectoryLocation directory = SourceDirectory;
1845 const Module* base = module;
1846 const XMLAttribute* dllname = node.GetAttribute ( "dllname", false );
1847 const XMLAttribute* definition = node.GetAttribute ( "definition", true );
1848 assert ( definition );
1849
1850 string relative_path;
1851 const XMLAttribute* att = node.GetAttribute ( "base", false );
1852 if ( att )
1853 {
1854 base = project.LocateModule ( att->value );
1855 if ( !base )
1856 throw XMLInvalidBuildFileException (
1857 node.location,
1858 "<importlibrary> attribute 'base' references non-existant module '%s'",
1859 att->value.c_str() );
1860
1861 }
1862
1863 if ( base )
1864 {
1865 relative_path = base->output->relative_path;
1866 if ( node.value.length () > 0 && node.value != "." )
1867 relative_path += sSep + node.value;
1868 }
1869 else
1870 relative_path = node.value;
1871
1872 att = node.GetAttribute ( "root", false );
1873 if ( att )
1874 {
1875 if ( att->value == "intermediate" )
1876 directory = IntermediateDirectory;
1877 else
1878 throw InvalidAttributeValueException ( node.location,
1879 "root",
1880 att->value );
1881 }
1882
1883 if ( dllname )
1884 this->dllname = dllname->value;
1885 else if ( module->type == StaticLibrary || module->type == HostStaticLibrary )
1886 throw XMLInvalidBuildFileException (
1887 node.location,
1888 "<importlibrary> dllname attribute required." );
1889
1890 size_t index = definition->value.find_last_of ( "/\\" );
1891 if ( index == string::npos )
1892 {
1893 source = new FileLocation ( directory,
1894 base->output->relative_path,
1895 definition->value,
1896 &node );
1897 }
1898 else
1899 {
1900 string dir = definition->value.substr ( 0, index );
1901 string name = definition->value.substr ( index + 1);
1902 source = new FileLocation ( directory,
1903 NormalizeFilename ( base->output->relative_path + sSep + dir ),
1904 name,
1905 &node );
1906 }
1907
1908 target = new FileLocation ( IntermediateDirectory,
1909 base->output->relative_path,
1910 "lib" + module->name + (delayimp ? ".delayimp.a" : ".a" ));
1911
1912 }
1913
1914
1915 Property::Property ( const XMLElement& node_,
1916 const Project& project_,
1917 const Module* module_ )
1918 : project(project_), module(module_)
1919 {
1920 const XMLAttribute* att;
1921
1922 att = node_.GetAttribute ( "name", true );
1923 assert(att);
1924 name = project.ResolveProperties ( att->value );
1925
1926 att = node_.GetAttribute ( "value", true );
1927 assert(att);
1928 value = att->value;
1929
1930 att = node_.GetAttribute ( "internal", false );
1931 if ( att != NULL )
1932 {
1933 const char* p = att->value.c_str();
1934 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
1935 isInternal = true;
1936 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
1937 isInternal = false;
1938 else
1939 {
1940 throw InvalidAttributeValueException (
1941 node_.location,
1942 "internal",
1943 att->value );
1944 }
1945 }
1946 else
1947 isInternal = false;
1948 }
1949
1950 Property::Property ( const Project& project_,
1951 const Module* module_,
1952 const std::string& name_,
1953 const std::string& value_ )
1954 : project(project_), module(module_), name(name_), value(value_)
1955 {
1956 }
1957
1958 void
1959 Property::ProcessXML()
1960 {
1961 }
1962
1963
1964 PchFile::PchFile (
1965 const XMLElement& node_,
1966 const Module& module_,
1967 const FileLocation *file_ )
1968 : node(node_), module(module_), file(file_)
1969 {
1970 }
1971
1972 PchFile::~PchFile()
1973 {
1974 delete file;
1975 }
1976
1977 void
1978 PchFile::ProcessXML()
1979 {
1980 }