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