Merge trunk head (r45466)
[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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 isStartupLib = GetBooleanAttribute ( moduleNode, "isstartuplib" );
347 isCRT = GetBooleanAttribute ( moduleNode, "iscrt", GetDefaultModuleIsCRT () );
348
349 att = moduleNode.GetAttribute ( "crt", false );
350 if ( att != NULL)
351 {
352 CRT = att->value;
353
354 if ( stricmp ( CRT.c_str (), "auto" ) == 0 )
355 CRT = GetDefaultModuleCRT ();
356 }
357 else
358 CRT = GetDefaultModuleCRT ();
359
360 const char * crtAttr = CRT.c_str ();
361 if ( crtAttr == NULL || stricmp ( crtAttr, "none" ) == 0 )
362 dynamicCRT = false;
363 else if ( stricmp ( crtAttr, "libc" ) == 0 )
364 dynamicCRT = false;
365 else if ( stricmp ( crtAttr, "msvcrt" ) == 0 )
366 dynamicCRT = true;
367 else if ( stricmp ( crtAttr, "libcntpr" ) == 0 )
368 dynamicCRT = false;
369 else if ( stricmp ( crtAttr, "ntdll" ) == 0 )
370 dynamicCRT = true;
371 else if ( stricmp ( crtAttr, "static" ) == 0 )
372 dynamicCRT = false;
373 else if ( stricmp ( crtAttr, "dll" ) == 0 )
374 dynamicCRT = true;
375 else
376 {
377 throw InvalidAttributeValueException (
378 moduleNode.location,
379 "crt",
380 std::string ( crtAttr ) );
381 }
382
383 if ( isCRT && dynamicCRT )
384 {
385 throw XMLInvalidBuildFileException (
386 moduleNode.location,
387 "C runtime module '%s' cannot be compiled for a dynamically-linked C runtime",
388 name.c_str() );
389 }
390
391 att = moduleNode.GetAttribute ( "prefix", false );
392 if ( att != NULL )
393 prefix = att->value;
394
395 att = moduleNode.GetAttribute ( "installname", false );
396 if ( att != NULL )
397 {
398 const XMLAttribute* installbase = moduleNode.GetAttribute ( "installbase", false );
399
400 if(installbase)
401 this->installbase = installbase->value;
402 else
403 this->installbase = "";
404
405 install = new FileLocation ( InstallDirectory,
406 installbase ? installbase->value : "",
407 att->value,
408 &moduleNode );
409
410 output = new FileLocation ( GetTargetDirectoryTree (),
411 modulePath,
412 att->value,
413 &moduleNode );
414 }
415
416 att = moduleNode.GetAttribute ( "output", false );
417 if ( att != NULL )
418 {
419 if (output != NULL)
420 {
421 printf ( "%s: WARNING: 'installname' overrides 'output' also defined for this module.\n",
422 moduleNode.location.c_str() );
423 }
424 else
425 {
426 output = new FileLocation ( GetTargetDirectoryTree (),
427 modulePath,
428 att->value,
429 &moduleNode );
430 }
431 }
432
433 /* If no one has set the output file for this module set it automatically */
434 if (output == NULL)
435 {
436 output = new FileLocation ( GetTargetDirectoryTree (),
437 modulePath,
438 name + extension,
439 &moduleNode );
440 }
441
442 att = moduleNode.GetAttribute ( "allowwarnings", false );
443 if ( att == NULL )
444 {
445 att = moduleNode.GetAttribute ( "warnings", false );
446 if ( att != NULL )
447 {
448 printf ( "%s: WARNING: 'warnings' attribute of <module> is deprecated, use 'allowwarnings' instead\n",
449 moduleNode.location.c_str() );
450 }
451 }
452 if ( att != NULL )
453 allowWarnings = att->value == "true";
454 else if ( project.allowWarningsSet )
455 allowWarnings = project.allowWarnings;
456 else
457 allowWarnings = false;
458
459 att = moduleNode.GetAttribute ( "aliasof", false );
460 if ( type == Alias && att != NULL )
461 aliasedModuleName = att->value;
462 else
463 aliasedModuleName = "";
464
465 if ( type == BootProgram )
466 {
467 att = moduleNode.GetAttribute ( "payload", true );
468 payload = att->value;
469 }
470
471 if ( type == BootProgram || type == ElfExecutable )
472 {
473 att = moduleNode.GetAttribute ( "buildtype", false );
474 if ( att != NULL )
475 {
476 buildtype = att->value;
477 }
478 else
479 {
480 buildtype = "BOOTPROG";
481 }
482 }
483
484 att = moduleNode.GetAttribute ( "description", false );
485 if (att != NULL )
486 {
487 description = project.ResolveProperties(att->value);
488 }
489 else
490 description = "";
491
492 att = moduleNode.GetAttribute ( "lcid", false );
493 if (type == KeyboardLayout && att != NULL )
494 lcid = att->value;
495 else
496 lcid = "";
497
498 att = moduleNode.GetAttribute ( "layoutid", false );
499 if (type == KeyboardLayout && att != NULL )
500 layoutId = att->value;
501 else
502 layoutId = "";
503
504 att = moduleNode.GetAttribute ( "layoutnameresid", false );
505 if (type == KeyboardLayout && att != NULL )
506 layoutNameResId = att->value;
507 else
508 layoutNameResId = "";
509
510 SetImportLibrary ( NULL );
511 }
512
513 Module::~Module ()
514 {
515 size_t i;
516 for ( i = 0; i < invocations.size(); i++ )
517 delete invocations[i];
518 for ( i = 0; i < dependencies.size(); i++ )
519 delete dependencies[i];
520 for ( i = 0; i < compilerFlags.size(); i++ )
521 delete compilerFlags[i];
522 for ( i = 0; i < linkerFlags.size(); i++ )
523 delete linkerFlags[i];
524 for ( i = 0; i < stubbedComponents.size(); i++ )
525 delete stubbedComponents[i];
526 for ( i = 0; i < cdfiles.size (); i++ )
527 delete cdfiles[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 else if ( e.name == "cdfile" )
921 {
922 CDFile* cdfile = new CDFile ( project, e, subpath );
923 cdfiles.push_back ( cdfile );
924 subs_invalid = true;
925 }
926 if ( subs_invalid && e.subElements.size() > 0 )
927 {
928 throw XMLInvalidBuildFileException (
929 e.location,
930 "<%s> cannot have sub-elements",
931 e.name.c_str() );
932 }
933 for ( size_t i = 0; i < cdfiles.size (); i++ )
934 cdfiles[i]->ProcessXML ();
935 for ( size_t i = 0; i < e.subElements.size (); i++ )
936 ProcessXMLSubElement ( *e.subElements[i], subdirectory, subpath, parseContext );
937 parseContext.compilationUnit = pOldCompilationUnit;
938 }
939
940 ModuleType
941 Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
942 {
943 if ( attribute.value == "buildtool" )
944 return BuildTool;
945 if ( attribute.value == "staticlibrary" )
946 return StaticLibrary;
947 if ( attribute.value == "hoststaticlibrary" )
948 return HostStaticLibrary;
949 if ( attribute.value == "objectlibrary" )
950 return ObjectLibrary;
951 if ( attribute.value == "kernel" )
952 return Kernel;
953 if ( attribute.value == "kernelmodedll" )
954 return KernelModeDLL;
955 if ( attribute.value == "kernelmodedriver" )
956 return KernelModeDriver;
957 if ( attribute.value == "nativedll" )
958 return NativeDLL;
959 if ( attribute.value == "nativecui" )
960 return NativeCUI;
961 if ( attribute.value == "keyboardlayout" )
962 return KeyboardLayout;
963 if ( attribute.value == "win32dll" )
964 return Win32DLL;
965 if ( attribute.value == "win32ocx" )
966 return Win32OCX;
967 if ( attribute.value == "win32cui" )
968 return Win32CUI;
969 if ( attribute.value == "win32gui" )
970 return Win32GUI;
971 if ( attribute.value == "win32scr" )
972 return Win32SCR;
973 if ( attribute.value == "bootloader" )
974 return BootLoader;
975 if ( attribute.value == "bootsector" )
976 return BootSector;
977 if ( attribute.value == "bootprogram" )
978 return BootProgram;
979 if ( attribute.value == "iso" )
980 return Iso;
981 if ( attribute.value == "liveiso" )
982 return LiveIso;
983 if ( attribute.value == "test" )
984 return Test;
985 if ( attribute.value == "rpcserver" )
986 return RpcServer;
987 if ( attribute.value == "rpcclient" )
988 return RpcClient;
989 if ( attribute.value == "rpcproxy" )
990 return RpcProxy;
991 if ( attribute.value == "alias" )
992 return Alias;
993 if ( attribute.value == "idlheader" )
994 return IdlHeader;
995 if ( attribute.value == "idlinterface" )
996 return IdlInterface;
997 if ( attribute.value == "embeddedtypelib" )
998 return EmbeddedTypeLib;
999 if ( attribute.value == "elfexecutable" )
1000 return ElfExecutable;
1001 if ( attribute.value == "cabinet" )
1002 return Cabinet;
1003 if ( attribute.value == "messageheader" )
1004 return MessageHeader;
1005 throw InvalidAttributeValueException ( location,
1006 attribute.name,
1007 attribute.value );
1008 }
1009
1010 DirectoryLocation
1011 Module::GetTargetDirectoryTree () const
1012 {
1013 switch ( type )
1014 {
1015 case Kernel:
1016 case KernelModeDLL:
1017 case KeyboardLayout:
1018 case NativeDLL:
1019 case Win32DLL:
1020 case Win32OCX:
1021 case KernelModeDriver:
1022 case NativeCUI:
1023 case Win32CUI:
1024 case Test:
1025 case Win32SCR:
1026 case Win32GUI:
1027 case BuildTool:
1028 case BootLoader:
1029 case BootSector:
1030 case BootProgram:
1031 case Iso:
1032 case LiveIso:
1033 case ElfExecutable:
1034 case Cabinet:
1035 return OutputDirectory;
1036 case EmbeddedTypeLib:
1037 case StaticLibrary:
1038 case HostStaticLibrary:
1039 case ObjectLibrary:
1040 case RpcServer:
1041 case RpcClient:
1042 case RpcProxy:
1043 case Alias:
1044 case IdlHeader:
1045 case IdlInterface:
1046 case MessageHeader:
1047 return IntermediateDirectory;
1048 case TypeDontCare:
1049 break;
1050 }
1051 throw InvalidOperationException ( __FILE__,
1052 __LINE__,
1053 "Invalid module type %d.",
1054 type );
1055 }
1056
1057 string
1058 Module::GetDefaultModuleExtension () const
1059 {
1060 switch (type)
1061 {
1062 case BuildTool:
1063 return ExePostfix;
1064 case BootProgram:
1065 case StaticLibrary:
1066 case HostStaticLibrary:
1067 return ".a";
1068 case ObjectLibrary:
1069 return ".o";
1070 case Kernel:
1071 case NativeCUI:
1072 case Win32CUI:
1073 case Win32GUI:
1074 return ".exe";
1075 case Win32SCR:
1076 return ".scr";
1077
1078 case KernelModeDLL:
1079 case NativeDLL:
1080 case KeyboardLayout:
1081 case Win32DLL:
1082 return ".dll";
1083 case Win32OCX:
1084 return ".ocx";
1085 case KernelModeDriver:
1086 case BootLoader:
1087 return ".sys";
1088 case Cabinet:
1089 return ".cab";
1090 case BootSector:
1091 return ".o";
1092 case Iso:
1093 case LiveIso:
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 if (Environment::GetArch() == "arm") return "KiSystemStartup";
1123 return "KiSystemStartup@4";
1124 case KeyboardLayout:
1125 case KernelModeDLL:
1126 case KernelModeDriver:
1127 if (Environment::GetArch() == "arm") return "DriverEntry";
1128 return "DriverEntry@8";
1129 case NativeDLL:
1130 if (Environment::GetArch() == "arm") return "DllMainCRTStartup";
1131 return "DllMainCRTStartup@12";
1132 case NativeCUI:
1133 if (Environment::GetArch() == "arm") return "NtProcessStartup";
1134 return "NtProcessStartup@4";
1135 case Win32DLL:
1136 case Win32OCX:
1137 if (Environment::GetArch() == "arm") return "DllMain";
1138 return "DllMain@12";
1139 case Win32CUI:
1140 case Test:
1141 return "mainCRTStartup";
1142 case Win32SCR:
1143 case Win32GUI:
1144 return "WinMainCRTStartup";
1145 case BuildTool:
1146 case StaticLibrary:
1147 case HostStaticLibrary:
1148 case ObjectLibrary:
1149 case BootLoader:
1150 case BootSector:
1151 case Iso:
1152 case LiveIso:
1153 case RpcServer:
1154 case RpcClient:
1155 case RpcProxy:
1156 case Alias:
1157 case BootProgram:
1158 case IdlHeader:
1159 case IdlInterface:
1160 case MessageHeader:
1161 case ElfExecutable:
1162 case EmbeddedTypeLib:
1163 case Cabinet:
1164 return "";
1165 case TypeDontCare:
1166 break;
1167 }
1168 throw InvalidOperationException ( __FILE__,
1169 __LINE__ );
1170 }
1171
1172 string
1173 Module::GetDefaultModuleBaseaddress () const
1174 {
1175 switch ( type )
1176 {
1177 case Kernel:
1178 return "0x80800000";
1179 case Win32DLL:
1180 case Win32OCX:
1181 return "0x10000000";
1182 case NativeDLL:
1183 case NativeCUI:
1184 case Win32CUI:
1185 case Test:
1186 return "0x00400000";
1187 case Win32SCR:
1188 case Win32GUI:
1189 return "0x00400000";
1190 case KeyboardLayout:
1191 case KernelModeDLL:
1192 case KernelModeDriver:
1193 return "0x00010000";
1194 case ElfExecutable:
1195 return "0xe00000";
1196 case BuildTool:
1197 case StaticLibrary:
1198 case HostStaticLibrary:
1199 case ObjectLibrary:
1200 case BootLoader:
1201 case BootSector:
1202 case Iso:
1203 case LiveIso:
1204 case RpcServer:
1205 case RpcClient:
1206 case RpcProxy:
1207 case Alias:
1208 case BootProgram:
1209 case IdlHeader:
1210 case IdlInterface:
1211 case MessageHeader:
1212 case EmbeddedTypeLib:
1213 case Cabinet:
1214 return "";
1215 case TypeDontCare:
1216 break;
1217 }
1218 throw InvalidOperationException ( __FILE__,
1219 __LINE__ );
1220 }
1221
1222 std::string
1223 Module::GetDefaultModuleCRT () const
1224 {
1225 if ( isCRT )
1226 return "static";
1227
1228 switch ( type )
1229 {
1230 case Kernel:
1231 return "static";
1232 case Win32DLL:
1233 case Win32OCX:
1234 return "ntdll";
1235 case NativeDLL:
1236 case NativeCUI:
1237 return "ntdll";
1238 case Win32CUI:
1239 case Win32SCR:
1240 case Win32GUI:
1241 return "msvcrt";
1242 case Test:
1243 return "msvcrt"; // BUGBUG: not sure about this
1244 case KeyboardLayout:
1245 return "none";
1246 case KernelModeDLL:
1247 case KernelModeDriver:
1248 return "dll";
1249 case BootLoader:
1250 return "libcntpr";
1251 case ElfExecutable:
1252 case BuildTool:
1253 case StaticLibrary:
1254 case HostStaticLibrary:
1255 case ObjectLibrary:
1256 case BootSector:
1257 case Iso:
1258 case LiveIso:
1259 case RpcServer:
1260 case RpcClient:
1261 case RpcProxy:
1262 case Alias:
1263 case BootProgram:
1264 case IdlHeader:
1265 case IdlInterface:
1266 case MessageHeader:
1267 case EmbeddedTypeLib:
1268 case Cabinet:
1269 case TypeDontCare:
1270 return "none";
1271 }
1272 throw InvalidOperationException ( __FILE__,
1273 __LINE__ );
1274 }
1275
1276 bool
1277 Module::GetDefaultModuleIsCRT () const
1278 {
1279 return type == Kernel;
1280 }
1281
1282 bool
1283 Module::HasImportLibrary () const
1284 {
1285 return importLibrary != NULL && type != StaticLibrary && type != HostStaticLibrary;
1286 }
1287
1288 bool
1289 Module::IsDLL () const
1290 {
1291 switch ( type )
1292 {
1293 case Kernel:
1294 case KernelModeDLL:
1295 case NativeDLL:
1296 case KeyboardLayout:
1297 case Win32DLL:
1298 case Win32OCX:
1299 case KernelModeDriver:
1300 return true;
1301 case NativeCUI:
1302 case Win32CUI:
1303 case Test:
1304 case Win32SCR:
1305 case Win32GUI:
1306 case BuildTool:
1307 case StaticLibrary:
1308 case HostStaticLibrary:
1309 case ObjectLibrary:
1310 case BootLoader:
1311 case BootSector:
1312 case BootProgram:
1313 case Iso:
1314 case LiveIso:
1315 case RpcServer:
1316 case RpcClient:
1317 case RpcProxy:
1318 case Alias:
1319 case IdlHeader:
1320 case IdlInterface:
1321 case MessageHeader:
1322 case EmbeddedTypeLib:
1323 case ElfExecutable:
1324 case Cabinet:
1325 return false;
1326 case TypeDontCare:
1327 break;
1328 }
1329 throw InvalidOperationException ( __FILE__,
1330 __LINE__ );
1331 }
1332
1333 string
1334 Module::GetPathWithPrefix ( const string& prefix ) const
1335 {
1336 return output->relative_path + cSep + prefix + output->name;
1337 }
1338
1339 string
1340 Module::GetPathToBaseDir () const
1341 {
1342 string temp_path = output->relative_path;
1343 string result = "..\\";
1344 while(temp_path.find ('\\') != string::npos)
1345 {
1346 temp_path.erase (0, temp_path.find('\\')+1);
1347 result += "..\\";
1348 }
1349 return result;
1350 }
1351
1352 string
1353 Module::GetInvocationTarget ( const int index ) const
1354 {
1355 return ssprintf ( "%s_invoke_%d",
1356 name.c_str (),
1357 index );
1358 }
1359
1360 string
1361 Module::GetEntryPoint() const
1362 {
1363 string result = "";
1364 if (entrypoint == "0" || entrypoint == "0x0")
1365 return "0";
1366
1367 if (Environment::GetArch() != "arm" && Environment::GetArch() != "amd64")
1368 result = "_";
1369
1370 result += entrypoint;
1371
1372 if (Environment::GetArch() == "amd64")
1373 {
1374 size_t at_index = result.find_last_of( '@' );
1375 if ( at_index != result.npos )
1376 return result.substr (0, at_index );
1377 }
1378
1379 return result;
1380 }
1381
1382 bool
1383 Module::HasFileWithExtension (
1384 const IfableData& data,
1385 const std::string& extension ) const
1386 {
1387 size_t i;
1388 for ( i = 0; i < data.compilationUnits.size (); i++ )
1389 {
1390 CompilationUnit* compilationUnit = data.compilationUnits[i];
1391 if ( compilationUnit->HasFileWithExtension ( extension ) )
1392 return true;
1393 }
1394 return false;
1395 }
1396
1397 void
1398 Module::InvokeModule () const
1399 {
1400 for ( size_t i = 0; i < invocations.size (); i++ )
1401 {
1402 Invoke& invoke = *invocations[i];
1403 string command = FixSeparatorForSystemCommand(invoke.invokeModule->output->relative_path + "/" + invoke.invokeModule->output->name ) + " " + invoke.GetParameters ();
1404 printf ( "Executing '%s'\n\n", command.c_str () );
1405 int exitcode = system ( command.c_str () );
1406 if ( exitcode != 0 )
1407 throw InvocationFailedException ( command,
1408 exitcode );
1409 }
1410 }
1411
1412
1413 void
1414 Module::SetImportLibrary ( ImportLibrary* importLibrary )
1415 {
1416 this->importLibrary = importLibrary;
1417 dependency = new FileLocation ( HasImportLibrary () ? IntermediateDirectory : output->directory,
1418 output->relative_path,
1419 HasImportLibrary () ? "lib" + name + ".a" : output->name );
1420 }
1421
1422 void
1423 Module::SetDelayImportLibrary ( ImportLibrary* importLibrary )
1424 {
1425 this->delayImportLibrary = importLibrary;
1426 }
1427
1428 std::string
1429 Module::GetDllName () const
1430 {
1431 if ( importLibrary && !importLibrary->dllname.empty() )
1432 return importLibrary->dllname;
1433 else if ( output )
1434 return output->name;
1435 else
1436 throw new InvalidOperationException ( __FILE__, __LINE__, "Module %s has no dllname." );
1437 }
1438
1439 File::File ( DirectoryLocation directory,
1440 const string& relative_path,
1441 const string& name,
1442 bool _first,
1443 const string& _switches,
1444 bool _isPreCompiledHeader )
1445 : file ( directory, relative_path, name ),
1446 first(_first),
1447 switches(_switches),
1448 isPreCompiledHeader(_isPreCompiledHeader)
1449 {
1450 }
1451
1452
1453 void
1454 File::ProcessXML()
1455 {
1456 }
1457
1458
1459 std::string File::GetFullPath () const
1460 {
1461 string directory ( "" );
1462 switch ( file.directory )
1463 {
1464 case SourceDirectory:
1465 break;
1466 case IntermediateDirectory:
1467 directory = Environment::GetIntermediatePath () + sSep;
1468 break;
1469 default:
1470 throw InvalidOperationException ( __FILE__,
1471 __LINE__,
1472 "Invalid directory %d.",
1473 file.directory );
1474 }
1475
1476 if ( file.relative_path.length () > 0 )
1477 directory += file.relative_path + sSep;
1478
1479
1480 return directory + file.name;
1481 }
1482
1483
1484 Library::Library ( const XMLElement& _node,
1485 const Module& _module,
1486 const string& _name )
1487 : node(&_node),
1488 module(_module),
1489 name(_name),
1490 importedModule(_module.project.LocateModule(_name)),
1491 delayimp(false)
1492 {
1493 if ( module.name == name )
1494 {
1495 throw XMLInvalidBuildFileException (
1496 node->location,
1497 "module '%s' cannot link against itself",
1498 name.c_str() );
1499 }
1500 if ( !importedModule )
1501 {
1502 throw XMLInvalidBuildFileException (
1503 node->location,
1504 "module '%s' trying to import non-existant module '%s'",
1505 module.name.c_str(),
1506 name.c_str() );
1507 }
1508 }
1509
1510 Library::Library ( const Module& _module,
1511 const string& _name )
1512 : node(NULL),
1513 module(_module),
1514 name(_name),
1515 importedModule(_module.project.LocateModule(_name)),
1516 delayimp(false)
1517 {
1518 if ( !importedModule )
1519 {
1520 throw XMLInvalidBuildFileException (
1521 "<internal>",
1522 "module '%s' trying to import non-existant module '%s'",
1523 module.name.c_str(),
1524 name.c_str() );
1525 }
1526 }
1527
1528 void
1529 Library::ProcessXML()
1530 {
1531 if ( node && !module.project.LocateModule ( name ) )
1532 {
1533 throw XMLInvalidBuildFileException (
1534 node->location,
1535 "module '%s' is trying to link against non-existant module '%s'",
1536 module.name.c_str(),
1537 name.c_str() );
1538 }
1539 }
1540
1541
1542 Invoke::Invoke ( const XMLElement& _node,
1543 const Module& _module )
1544 : node (_node),
1545 module (_module)
1546 {
1547 }
1548
1549 void
1550 Invoke::ProcessXML()
1551 {
1552 const XMLAttribute* att = node.GetAttribute ( "module", false );
1553 if (att == NULL)
1554 invokeModule = &module;
1555 else
1556 {
1557 invokeModule = module.project.LocateModule ( att->value );
1558 if ( invokeModule == NULL )
1559 {
1560 throw XMLInvalidBuildFileException (
1561 node.location,
1562 "module '%s' is trying to invoke non-existant module '%s'",
1563 module.name.c_str(),
1564 att->value.c_str() );
1565 }
1566 }
1567
1568 for ( size_t i = 0; i < node.subElements.size (); i++ )
1569 ProcessXMLSubElement ( *node.subElements[i] );
1570 }
1571
1572 void
1573 Invoke::ProcessXMLSubElement ( const XMLElement& e )
1574 {
1575 bool subs_invalid = false;
1576 if ( e.name == "input" )
1577 {
1578 for ( size_t i = 0; i < e.subElements.size (); i++ )
1579 ProcessXMLSubElementInput ( *e.subElements[i] );
1580 }
1581 else if ( e.name == "output" )
1582 {
1583 for ( size_t i = 0; i < e.subElements.size (); i++ )
1584 ProcessXMLSubElementOutput ( *e.subElements[i] );
1585 }
1586 if ( subs_invalid && e.subElements.size() > 0 )
1587 {
1588 throw XMLInvalidBuildFileException (
1589 e.location,
1590 "<%s> cannot have sub-elements",
1591 e.name.c_str() );
1592 }
1593 }
1594
1595 void
1596 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
1597 {
1598 bool subs_invalid = false;
1599 if ( e.name == "inputfile" && e.value.size () > 0 )
1600 {
1601 input.push_back ( new InvokeFile (
1602 e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
1603 subs_invalid = true;
1604 }
1605 if ( subs_invalid && e.subElements.size() > 0 )
1606 {
1607 throw XMLInvalidBuildFileException (
1608 e.location,
1609 "<%s> cannot have sub-elements",
1610 e.name.c_str() );
1611 }
1612 }
1613
1614 void
1615 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
1616 {
1617 bool subs_invalid = false;
1618 if ( e.name == "outputfile" && e.value.size () > 0 )
1619 {
1620 output.push_back ( new InvokeFile (
1621 e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
1622 subs_invalid = true;
1623 }
1624 if ( subs_invalid && e.subElements.size() > 0 )
1625 {
1626 throw XMLInvalidBuildFileException (
1627 e.location,
1628 "<%s> cannot have sub-elements",
1629 e.name.c_str() );
1630 }
1631 }
1632
1633 void
1634 Invoke::GetTargets ( string_list& targets ) const
1635 {
1636 for ( size_t i = 0; i < output.size (); i++ )
1637 {
1638 InvokeFile& file = *output[i];
1639 targets.push_back ( NormalizeFilename ( file.name ) );
1640 }
1641 }
1642
1643 string
1644 Invoke::GetParameters () const
1645 {
1646 string parameters ( "" );
1647 size_t i;
1648 for ( i = 0; i < output.size (); i++ )
1649 {
1650 if ( parameters.length () > 0)
1651 parameters += " ";
1652 InvokeFile& invokeFile = *output[i];
1653 if ( invokeFile.switches.length () > 0 )
1654 {
1655 parameters += invokeFile.switches + " ";
1656 }
1657 parameters += invokeFile.name;
1658 }
1659
1660 for ( i = 0; i < input.size (); i++ )
1661 {
1662 if ( parameters.length () > 0 )
1663 parameters += " ";
1664 InvokeFile& invokeFile = *input[i];
1665 if ( invokeFile.switches.length () > 0 )
1666 {
1667 parameters += invokeFile.switches;
1668 parameters += " ";
1669 }
1670 parameters += invokeFile.name ;
1671 }
1672
1673 return parameters;
1674 }
1675
1676
1677 InvokeFile::InvokeFile ( const XMLElement& _node,
1678 const string& _name )
1679 : node (_node),
1680 name (_name)
1681 {
1682 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
1683 if (att != NULL)
1684 switches = att->value;
1685 else
1686 switches = "";
1687 }
1688
1689 void
1690 InvokeFile::ProcessXML()
1691 {
1692 }
1693
1694
1695 Dependency::Dependency ( const XMLElement& _node,
1696 const Module& _module )
1697 : node (_node),
1698 module (_module),
1699 dependencyModule (NULL)
1700 {
1701 }
1702
1703 void
1704 Dependency::ProcessXML()
1705 {
1706 dependencyModule = module.project.LocateModule ( node.value );
1707 if ( dependencyModule == NULL )
1708 {
1709 throw XMLInvalidBuildFileException (
1710 node.location,
1711 "module '%s' depend on non-existant module '%s'",
1712 module.name.c_str(),
1713 node.value.c_str() );
1714 }
1715 }
1716
1717 Bootsector::Bootsector ( const XMLElement& _node,
1718 const Module* _module )
1719 : node (_node),
1720 module (_module),
1721 bootSectorModule (NULL)
1722 {
1723 if ( !IsSupportedModuleType ( module->type ) )
1724 {
1725 throw XMLInvalidBuildFileException (
1726 node.location,
1727 "<bootsector> is not applicable for this module type." );
1728 }
1729
1730 bootSectorModule = module->project.LocateModule ( node.value );
1731 if ( bootSectorModule == NULL )
1732 {
1733 throw XMLInvalidBuildFileException (
1734 node.location,
1735 "module '%s' depend on non-existant module '%s'",
1736 module->name.c_str(),
1737 node.value.c_str() );
1738 }
1739
1740 if (bootSectorModule->type != BootSector)
1741 {
1742 throw XMLInvalidBuildFileException (
1743 node.location,
1744 "module '%s' is referencing non BootSector module '%s'",
1745 module->name.c_str(),
1746 node.value.c_str() );
1747 }
1748 }
1749
1750 void
1751 Bootsector::ProcessXML()
1752 {
1753 }
1754
1755 bool
1756 Bootsector::IsSupportedModuleType ( ModuleType type )
1757 {
1758 if ( type == Iso ||
1759 type == LiveIso )
1760 {
1761 return true;
1762 }
1763
1764 return false;
1765 }
1766
1767 Metadata::Metadata ( const XMLElement& _node,
1768 const Module& _module )
1769 : node (_node),
1770 module (_module)
1771 {
1772 /* The module name */
1773 const XMLAttribute* att = _node.GetAttribute ( "name", false );
1774 if (att != NULL)
1775 name = att->value;
1776 else
1777 name = module.name;
1778
1779 /* The module description */
1780 att = _node.GetAttribute ( "description", false );
1781 if (att != NULL)
1782 description = att->value;
1783 else
1784 description = "";
1785
1786 /* The module version */
1787 att = _node.GetAttribute ( "version", false );
1788 if (att != NULL)
1789 version = att->value;
1790 else
1791 version = "";
1792
1793 /* The module copyright */
1794 att = _node.GetAttribute ( "copyright", false );
1795 if (att != NULL)
1796 copyright = att->value;
1797 else
1798 copyright = "";
1799
1800 att = _node.GetAttribute ( "url", false );
1801 if (att != NULL)
1802 url = att->value;
1803 else
1804 url = "";
1805
1806 /* When was this module updated */
1807 att = _node.GetAttribute ( "date", false );
1808 if (att != NULL)
1809 date = att->value;
1810 else
1811 date = "?";
1812
1813 /* When was this module updated */
1814 att = _node.GetAttribute ( "owner", false );
1815 if (att != NULL)
1816 owner = att->value;
1817 else
1818 owner = "ReactOS";
1819 }
1820
1821
1822 ImportLibrary::~ImportLibrary ()
1823 {
1824 delete source;
1825 delete target;
1826 }
1827
1828
1829 ImportLibrary::ImportLibrary ( const Project& project,
1830 const XMLElement& node,
1831 const Module* module,
1832 bool delayimp )
1833 : XmlNode ( project, node ),
1834 module (module)
1835 {
1836 DirectoryLocation directory = SourceDirectory;
1837 const Module* base = module;
1838 const XMLAttribute* dllname = node.GetAttribute ( "dllname", false );
1839 const XMLAttribute* definition = node.GetAttribute ( "definition", true );
1840 assert ( definition );
1841
1842 string relative_path;
1843 const XMLAttribute* att = node.GetAttribute ( "base", false );
1844 if ( att )
1845 {
1846 base = project.LocateModule ( att->value );
1847 if ( !base )
1848 throw XMLInvalidBuildFileException (
1849 node.location,
1850 "<importlibrary> attribute 'base' references non-existant module '%s'",
1851 att->value.c_str() );
1852
1853 }
1854
1855 if ( base )
1856 {
1857 relative_path = base->output->relative_path;
1858 if ( node.value.length () > 0 && node.value != "." )
1859 relative_path += sSep + node.value;
1860 }
1861 else
1862 relative_path = node.value;
1863
1864 att = node.GetAttribute ( "root", false );
1865 if ( att )
1866 {
1867 if ( att->value == "intermediate" )
1868 directory = IntermediateDirectory;
1869 else
1870 throw InvalidAttributeValueException ( node.location,
1871 "root",
1872 att->value );
1873 }
1874
1875 if ( dllname )
1876 this->dllname = dllname->value;
1877
1878 size_t index = definition->value.find_last_of ( "/\\" );
1879 if ( index == string::npos )
1880 {
1881 source = new FileLocation ( directory,
1882 base->output->relative_path,
1883 definition->value,
1884 &node );
1885 }
1886 else
1887 {
1888 string dir = definition->value.substr ( 0, index );
1889 string name = definition->value.substr ( index + 1);
1890 source = new FileLocation ( directory,
1891 NormalizeFilename ( base->output->relative_path + sSep + dir ),
1892 name,
1893 &node );
1894 }
1895
1896 target = new FileLocation ( IntermediateDirectory,
1897 base->output->relative_path,
1898 "lib" + module->name + (delayimp ? ".delayimp.a" : ".a" ));
1899
1900 }
1901
1902
1903 Property::Property ( const XMLElement& node_,
1904 const Project& project_,
1905 const Module* module_ )
1906 : project(project_), module(module_)
1907 {
1908 const XMLAttribute* att;
1909
1910 att = node_.GetAttribute ( "name", true );
1911 assert(att);
1912 name = project.ResolveProperties ( att->value );
1913
1914 att = node_.GetAttribute ( "value", true );
1915 assert(att);
1916 value = att->value;
1917
1918 att = node_.GetAttribute ( "internal", false );
1919 if ( att != NULL )
1920 {
1921 const char* p = att->value.c_str();
1922 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
1923 isInternal = true;
1924 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
1925 isInternal = false;
1926 else
1927 {
1928 throw InvalidAttributeValueException (
1929 node_.location,
1930 "internal",
1931 att->value );
1932 }
1933 }
1934 else
1935 isInternal = false;
1936 }
1937
1938 Property::Property ( const Project& project_,
1939 const Module* module_,
1940 const std::string& name_,
1941 const std::string& value_ )
1942 : project(project_), module(module_), name(name_), value(value_)
1943 {
1944 }
1945
1946 void
1947 Property::ProcessXML()
1948 {
1949 }
1950
1951
1952 PchFile::PchFile (
1953 const XMLElement& node_,
1954 const Module& module_,
1955 const FileLocation *file_ )
1956 : node(node_), module(module_), file(file_)
1957 {
1958 }
1959
1960 PchFile::~PchFile()
1961 {
1962 delete file;
1963 }
1964
1965 void
1966 PchFile::ProcessXML()
1967 {
1968 }