[RTL]
[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 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() == "i386") return "KiSystemStartup@4";
1117 return "KiSystemStartup";
1118 case KeyboardLayout:
1119 case KernelModeDLL:
1120 case KernelModeDriver:
1121 if (Environment::GetArch() == "i386") return "DriverEntry@8";
1122 return "DriverEntry";
1123 case NativeDLL:
1124 if (Environment::GetArch() == "i386") return "DllMainCRTStartup@12";
1125 return "DllMainCRTStartup";
1126 case NativeCUI:
1127 if (Environment::GetArch() == "i386") return "NtProcessStartup@4";
1128 return "NtProcessStartup";
1129 case Win32DLL:
1130 case Win32OCX:
1131 if (Environment::GetArch() == "i386") return "DllMain@12";
1132 return "DllMain";
1133 case Win32CUI:
1134 case Test:
1135 case BootLoader:
1136 return "mainCRTStartup";
1137 case Win32SCR:
1138 case Win32GUI:
1139 return "WinMainCRTStartup";
1140 case BuildTool:
1141 case StaticLibrary:
1142 case HostStaticLibrary:
1143 case ObjectLibrary:
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 BootLoader:
1191 return "0x8000";
1192 case BuildTool:
1193 case StaticLibrary:
1194 case HostStaticLibrary:
1195 case ObjectLibrary:
1196 case BootSector:
1197 case Iso:
1198 case LiveIso:
1199 case RpcServer:
1200 case RpcClient:
1201 case RpcProxy:
1202 case Alias:
1203 case BootProgram:
1204 case IdlHeader:
1205 case IdlInterface:
1206 case MessageHeader:
1207 case EmbeddedTypeLib:
1208 case Cabinet:
1209 return "";
1210 case TypeDontCare:
1211 break;
1212 }
1213 throw InvalidOperationException ( __FILE__,
1214 __LINE__ );
1215 }
1216
1217 std::string
1218 Module::GetDefaultModuleCRT () const
1219 {
1220 if ( isCRT )
1221 return "static";
1222
1223 switch ( type )
1224 {
1225 case Kernel:
1226 return "static";
1227 case Win32DLL:
1228 case Win32OCX:
1229 return "msvcrt";
1230 case NativeDLL:
1231 case NativeCUI:
1232 return "ntdll";
1233 case Win32CUI:
1234 case Win32SCR:
1235 case Win32GUI:
1236 return "msvcrt";
1237 case Test:
1238 return "msvcrt"; // BUGBUG: not sure about this
1239 case KeyboardLayout:
1240 return "none";
1241 case KernelModeDLL:
1242 case KernelModeDriver:
1243 return "dll";
1244 case BootLoader:
1245 return "libcntpr";
1246 case ElfExecutable:
1247 case BuildTool:
1248 case StaticLibrary:
1249 case HostStaticLibrary:
1250 case ObjectLibrary:
1251 case BootSector:
1252 case Iso:
1253 case LiveIso:
1254 case RpcServer:
1255 case RpcClient:
1256 case RpcProxy:
1257 case Alias:
1258 case BootProgram:
1259 case IdlHeader:
1260 case IdlInterface:
1261 case MessageHeader:
1262 case EmbeddedTypeLib:
1263 case Cabinet:
1264 case TypeDontCare:
1265 return "none";
1266 }
1267 throw InvalidOperationException ( __FILE__,
1268 __LINE__ );
1269 }
1270
1271 bool
1272 Module::GetDefaultModuleIsCRT () const
1273 {
1274 return type == Kernel;
1275 }
1276
1277 bool
1278 Module::HasImportLibrary () const
1279 {
1280 return importLibrary != NULL && type != StaticLibrary && type != HostStaticLibrary;
1281 }
1282
1283 bool
1284 Module::IsDLL () const
1285 {
1286 switch ( type )
1287 {
1288 case Kernel:
1289 case KernelModeDLL:
1290 case NativeDLL:
1291 case KeyboardLayout:
1292 case Win32DLL:
1293 case Win32OCX:
1294 case KernelModeDriver:
1295 return true;
1296 case NativeCUI:
1297 case Win32CUI:
1298 case Test:
1299 case Win32SCR:
1300 case Win32GUI:
1301 case BuildTool:
1302 case StaticLibrary:
1303 case HostStaticLibrary:
1304 case ObjectLibrary:
1305 case BootLoader:
1306 case BootSector:
1307 case BootProgram:
1308 case Iso:
1309 case LiveIso:
1310 case RpcServer:
1311 case RpcClient:
1312 case RpcProxy:
1313 case Alias:
1314 case IdlHeader:
1315 case IdlInterface:
1316 case MessageHeader:
1317 case EmbeddedTypeLib:
1318 case ElfExecutable:
1319 case Cabinet:
1320 return false;
1321 case TypeDontCare:
1322 break;
1323 }
1324 throw InvalidOperationException ( __FILE__,
1325 __LINE__ );
1326 }
1327
1328 string
1329 Module::GetPathWithPrefix ( const string& prefix ) const
1330 {
1331 return output->relative_path + cSep + prefix + output->name;
1332 }
1333
1334 string
1335 Module::GetPathToBaseDir () const
1336 {
1337 string temp_path = output->relative_path;
1338 string result = "..\\";
1339 while(temp_path.find ('\\') != string::npos)
1340 {
1341 temp_path.erase (0, temp_path.find('\\')+1);
1342 result += "..\\";
1343 }
1344 return result;
1345 }
1346
1347 string
1348 Module::GetInvocationTarget ( const int index ) const
1349 {
1350 return ssprintf ( "%s_invoke_%d",
1351 name.c_str (),
1352 index );
1353 }
1354
1355 string
1356 Module::GetEntryPoint() const
1357 {
1358 string result = "";
1359 if (entrypoint == "0" || entrypoint == "0x0")
1360 return "0";
1361
1362 if (Environment::GetArch() != "arm" && Environment::GetArch() != "amd64")
1363 result = "_";
1364
1365 result += entrypoint;
1366
1367 if (Environment::GetArch() == "amd64")
1368 {
1369 size_t at_index = result.find_last_of( '@' );
1370 if ( at_index != result.npos )
1371 return result.substr (0, at_index );
1372 }
1373
1374 return result;
1375 }
1376
1377 bool
1378 Module::HasFileWithExtension (
1379 const IfableData& data,
1380 const std::string& extension ) const
1381 {
1382 size_t i;
1383 for ( i = 0; i < data.compilationUnits.size (); i++ )
1384 {
1385 CompilationUnit* compilationUnit = data.compilationUnits[i];
1386 if ( compilationUnit->HasFileWithExtension ( extension ) )
1387 return true;
1388 }
1389 return false;
1390 }
1391
1392 void
1393 Module::InvokeModule () const
1394 {
1395 for ( size_t i = 0; i < invocations.size (); i++ )
1396 {
1397 Invoke& invoke = *invocations[i];
1398 string command = FixSeparatorForSystemCommand(invoke.invokeModule->output->relative_path + "/" + invoke.invokeModule->output->name ) + " " + invoke.GetParameters ();
1399 printf ( "Executing '%s'\n\n", command.c_str () );
1400 int exitcode = system ( command.c_str () );
1401 if ( exitcode != 0 )
1402 throw InvocationFailedException ( command,
1403 exitcode );
1404 }
1405 }
1406
1407
1408 void
1409 Module::SetImportLibrary ( ImportLibrary* importLibrary )
1410 {
1411 this->importLibrary = importLibrary;
1412 dependency = new FileLocation ( HasImportLibrary () ? IntermediateDirectory : output->directory,
1413 output->relative_path,
1414 HasImportLibrary () ? "lib" + name + ".a" : output->name );
1415 }
1416
1417 void
1418 Module::SetDelayImportLibrary ( ImportLibrary* importLibrary )
1419 {
1420 this->delayImportLibrary = importLibrary;
1421 }
1422
1423 std::string
1424 Module::GetDllName () const
1425 {
1426 if ( importLibrary && !importLibrary->dllname.empty() )
1427 return importLibrary->dllname;
1428 else if ( output )
1429 return output->name;
1430 else
1431 throw new InvalidOperationException ( __FILE__, __LINE__, "Module %s has no dllname." );
1432 }
1433
1434 SpecFileType
1435 Module::IsSpecDefinitionFile () const
1436 {
1437 if(!importLibrary)
1438 return None;
1439
1440 std::string ext = GetExtension ( *importLibrary->source );
1441
1442 if ( ext == ".spec" )
1443 return Spec;
1444
1445 if ( ext == ".pspec" )
1446 return PSpec;
1447
1448 return None;
1449 }
1450
1451
1452 File::File ( DirectoryLocation directory,
1453 const string& relative_path,
1454 const string& name,
1455 bool _first,
1456 const string& _switches,
1457 bool _isPreCompiledHeader )
1458 : file ( directory, relative_path, name ),
1459 first(_first),
1460 switches(_switches),
1461 isPreCompiledHeader(_isPreCompiledHeader)
1462 {
1463 }
1464
1465
1466 void
1467 File::ProcessXML()
1468 {
1469 }
1470
1471
1472 std::string File::GetFullPath () const
1473 {
1474 string directory ( "" );
1475 switch ( file.directory )
1476 {
1477 case SourceDirectory:
1478 break;
1479 case IntermediateDirectory:
1480 directory = Environment::GetIntermediatePath () + sSep;
1481 break;
1482 default:
1483 throw InvalidOperationException ( __FILE__,
1484 __LINE__,
1485 "Invalid directory %d.",
1486 file.directory );
1487 }
1488
1489 if ( file.relative_path.length () > 0 )
1490 directory += file.relative_path + sSep;
1491
1492
1493 return directory + file.name;
1494 }
1495
1496
1497 Library::Library ( const XMLElement& _node,
1498 const Module& _module,
1499 const string& _name )
1500 : node(&_node),
1501 module(_module),
1502 name(_name),
1503 importedModule(_module.project.LocateModule(_name)),
1504 delayimp(false)
1505 {
1506 if ( module.name == name )
1507 {
1508 throw XMLInvalidBuildFileException (
1509 node->location,
1510 "module '%s' cannot link against itself",
1511 name.c_str() );
1512 }
1513 if ( !importedModule )
1514 {
1515 throw XMLInvalidBuildFileException (
1516 node->location,
1517 "module '%s' trying to import non-existant module '%s'",
1518 module.name.c_str(),
1519 name.c_str() );
1520 }
1521 }
1522
1523 Library::Library ( const Module& _module,
1524 const string& _name )
1525 : node(NULL),
1526 module(_module),
1527 name(_name),
1528 importedModule(_module.project.LocateModule(_name)),
1529 delayimp(false)
1530 {
1531 if ( !importedModule )
1532 {
1533 throw XMLInvalidBuildFileException (
1534 "<internal>",
1535 "module '%s' trying to import non-existant module '%s'",
1536 module.name.c_str(),
1537 name.c_str() );
1538 }
1539 }
1540
1541 void
1542 Library::ProcessXML()
1543 {
1544 if ( node && !module.project.LocateModule ( name ) )
1545 {
1546 throw XMLInvalidBuildFileException (
1547 node->location,
1548 "module '%s' is trying to link against non-existant module '%s'",
1549 module.name.c_str(),
1550 name.c_str() );
1551 }
1552 }
1553
1554
1555 Invoke::Invoke ( const XMLElement& _node,
1556 const Module& _module )
1557 : node (_node),
1558 module (_module)
1559 {
1560 }
1561
1562 void
1563 Invoke::ProcessXML()
1564 {
1565 const XMLAttribute* att = node.GetAttribute ( "module", false );
1566 if (att == NULL)
1567 invokeModule = &module;
1568 else
1569 {
1570 invokeModule = module.project.LocateModule ( att->value );
1571 if ( invokeModule == NULL )
1572 {
1573 throw XMLInvalidBuildFileException (
1574 node.location,
1575 "module '%s' is trying to invoke non-existant module '%s'",
1576 module.name.c_str(),
1577 att->value.c_str() );
1578 }
1579 }
1580
1581 for ( size_t i = 0; i < node.subElements.size (); i++ )
1582 ProcessXMLSubElement ( *node.subElements[i] );
1583 }
1584
1585 void
1586 Invoke::ProcessXMLSubElement ( const XMLElement& e )
1587 {
1588 bool subs_invalid = false;
1589 if ( e.name == "input" )
1590 {
1591 for ( size_t i = 0; i < e.subElements.size (); i++ )
1592 ProcessXMLSubElementInput ( *e.subElements[i] );
1593 }
1594 else if ( e.name == "output" )
1595 {
1596 for ( size_t i = 0; i < e.subElements.size (); i++ )
1597 ProcessXMLSubElementOutput ( *e.subElements[i] );
1598 }
1599 if ( subs_invalid && e.subElements.size() > 0 )
1600 {
1601 throw XMLInvalidBuildFileException (
1602 e.location,
1603 "<%s> cannot have sub-elements",
1604 e.name.c_str() );
1605 }
1606 }
1607
1608 void
1609 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
1610 {
1611 bool subs_invalid = false;
1612 if ( e.name == "inputfile" && e.value.size () > 0 )
1613 {
1614 input.push_back ( new InvokeFile (
1615 e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
1616 subs_invalid = true;
1617 }
1618 if ( subs_invalid && e.subElements.size() > 0 )
1619 {
1620 throw XMLInvalidBuildFileException (
1621 e.location,
1622 "<%s> cannot have sub-elements",
1623 e.name.c_str() );
1624 }
1625 }
1626
1627 void
1628 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
1629 {
1630 bool subs_invalid = false;
1631 if ( e.name == "outputfile" && e.value.size () > 0 )
1632 {
1633 output.push_back ( new InvokeFile (
1634 e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
1635 subs_invalid = true;
1636 }
1637 if ( subs_invalid && e.subElements.size() > 0 )
1638 {
1639 throw XMLInvalidBuildFileException (
1640 e.location,
1641 "<%s> cannot have sub-elements",
1642 e.name.c_str() );
1643 }
1644 }
1645
1646 void
1647 Invoke::GetTargets ( string_list& targets ) const
1648 {
1649 for ( size_t i = 0; i < output.size (); i++ )
1650 {
1651 InvokeFile& file = *output[i];
1652 targets.push_back ( NormalizeFilename ( file.name ) );
1653 }
1654 }
1655
1656 string
1657 Invoke::GetParameters () const
1658 {
1659 string parameters ( "" );
1660 size_t i;
1661 for ( i = 0; i < output.size (); i++ )
1662 {
1663 if ( parameters.length () > 0)
1664 parameters += " ";
1665 InvokeFile& invokeFile = *output[i];
1666 if ( invokeFile.switches.length () > 0 )
1667 {
1668 parameters += invokeFile.switches + " ";
1669 }
1670 parameters += invokeFile.name;
1671 }
1672
1673 for ( i = 0; i < input.size (); i++ )
1674 {
1675 if ( parameters.length () > 0 )
1676 parameters += " ";
1677 InvokeFile& invokeFile = *input[i];
1678 if ( invokeFile.switches.length () > 0 )
1679 {
1680 parameters += invokeFile.switches;
1681 parameters += " ";
1682 }
1683 parameters += invokeFile.name ;
1684 }
1685
1686 return parameters;
1687 }
1688
1689
1690 InvokeFile::InvokeFile ( const XMLElement& _node,
1691 const string& _name )
1692 : node (_node),
1693 name (_name)
1694 {
1695 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
1696 if (att != NULL)
1697 switches = att->value;
1698 else
1699 switches = "";
1700 }
1701
1702 void
1703 InvokeFile::ProcessXML()
1704 {
1705 }
1706
1707
1708 Dependency::Dependency ( const XMLElement& _node,
1709 const Module& _module )
1710 : node (_node),
1711 module (_module),
1712 dependencyModule (NULL)
1713 {
1714 }
1715
1716 void
1717 Dependency::ProcessXML()
1718 {
1719 dependencyModule = module.project.LocateModule ( node.value );
1720 if ( dependencyModule == NULL )
1721 {
1722 throw XMLInvalidBuildFileException (
1723 node.location,
1724 "module '%s' depend on non-existant module '%s'",
1725 module.name.c_str(),
1726 node.value.c_str() );
1727 }
1728 }
1729
1730 Bootsector::Bootsector ( const XMLElement& _node,
1731 const Module* _module )
1732 : node (_node),
1733 module (_module),
1734 bootSectorModule (NULL)
1735 {
1736 if ( !IsSupportedModuleType ( module->type ) )
1737 {
1738 throw XMLInvalidBuildFileException (
1739 node.location,
1740 "<bootsector> is not applicable for this module type." );
1741 }
1742
1743 bootSectorModule = module->project.LocateModule ( node.value );
1744 if ( bootSectorModule == NULL )
1745 {
1746 throw XMLInvalidBuildFileException (
1747 node.location,
1748 "module '%s' depend on non-existant module '%s'",
1749 module->name.c_str(),
1750 node.value.c_str() );
1751 }
1752
1753 if (bootSectorModule->type != BootSector)
1754 {
1755 throw XMLInvalidBuildFileException (
1756 node.location,
1757 "module '%s' is referencing non BootSector module '%s'",
1758 module->name.c_str(),
1759 node.value.c_str() );
1760 }
1761 }
1762
1763 void
1764 Bootsector::ProcessXML()
1765 {
1766 }
1767
1768 bool
1769 Bootsector::IsSupportedModuleType ( ModuleType type )
1770 {
1771 if ( type == Iso ||
1772 type == LiveIso )
1773 {
1774 return true;
1775 }
1776
1777 return false;
1778 }
1779
1780 Metadata::Metadata ( const XMLElement& _node,
1781 const Module& _module )
1782 : node (_node),
1783 module (_module)
1784 {
1785 /* The module name */
1786 const XMLAttribute* att = _node.GetAttribute ( "name", false );
1787 if (att != NULL)
1788 name = att->value;
1789 else
1790 name = module.name;
1791
1792 /* The module description */
1793 att = _node.GetAttribute ( "description", false );
1794 if (att != NULL)
1795 description = att->value;
1796 else
1797 description = "";
1798
1799 /* The module version */
1800 att = _node.GetAttribute ( "version", false );
1801 if (att != NULL)
1802 version = att->value;
1803 else
1804 version = "";
1805
1806 /* The module copyright */
1807 att = _node.GetAttribute ( "copyright", false );
1808 if (att != NULL)
1809 copyright = att->value;
1810 else
1811 copyright = "";
1812
1813 att = _node.GetAttribute ( "url", false );
1814 if (att != NULL)
1815 url = att->value;
1816 else
1817 url = "";
1818
1819 /* When was this module updated */
1820 att = _node.GetAttribute ( "date", false );
1821 if (att != NULL)
1822 date = att->value;
1823 else
1824 date = "?";
1825
1826 /* When was this module updated */
1827 att = _node.GetAttribute ( "owner", false );
1828 if (att != NULL)
1829 owner = att->value;
1830 else
1831 owner = "ReactOS";
1832 }
1833
1834
1835 ImportLibrary::~ImportLibrary ()
1836 {
1837 delete source;
1838 delete target;
1839 }
1840
1841
1842 ImportLibrary::ImportLibrary ( const Project& project,
1843 const XMLElement& node,
1844 const Module* module,
1845 bool delayimp )
1846 : XmlNode ( project, node ),
1847 module (module)
1848 {
1849 DirectoryLocation directory = SourceDirectory;
1850 const Module* base = module;
1851 const XMLAttribute* dllname = node.GetAttribute ( "dllname", false );
1852 const XMLAttribute* definition = node.GetAttribute ( "definition", true );
1853 assert ( definition );
1854
1855 string relative_path;
1856 const XMLAttribute* att = node.GetAttribute ( "base", false );
1857 if ( att )
1858 {
1859 base = project.LocateModule ( att->value );
1860 if ( !base )
1861 throw XMLInvalidBuildFileException (
1862 node.location,
1863 "<importlibrary> attribute 'base' references non-existant module '%s'",
1864 att->value.c_str() );
1865
1866 }
1867
1868 if ( base )
1869 {
1870 relative_path = base->output->relative_path;
1871 if ( node.value.length () > 0 && node.value != "." )
1872 relative_path += sSep + node.value;
1873 }
1874 else
1875 relative_path = node.value;
1876
1877 att = node.GetAttribute ( "root", false );
1878 if ( att )
1879 {
1880 if ( att->value == "intermediate" )
1881 directory = IntermediateDirectory;
1882 else
1883 throw InvalidAttributeValueException ( node.location,
1884 "root",
1885 att->value );
1886 }
1887
1888 if ( dllname )
1889 this->dllname = dllname->value;
1890
1891 size_t index = definition->value.find_last_of ( "/\\" );
1892 if ( index == string::npos )
1893 {
1894 source = new FileLocation ( directory,
1895 base->output->relative_path,
1896 definition->value,
1897 &node );
1898 }
1899 else
1900 {
1901 string dir = definition->value.substr ( 0, index );
1902 string name = definition->value.substr ( index + 1);
1903 source = new FileLocation ( directory,
1904 NormalizeFilename ( base->output->relative_path + sSep + dir ),
1905 name,
1906 &node );
1907 }
1908
1909 target = new FileLocation ( IntermediateDirectory,
1910 base->output->relative_path,
1911 "lib" + module->name + (delayimp ? ".delayimp.a" : ".a" ));
1912
1913 }
1914
1915
1916 Property::Property ( const XMLElement& node_,
1917 const Project& project_,
1918 const Module* module_ )
1919 : project(project_), module(module_)
1920 {
1921 const XMLAttribute* att;
1922
1923 att = node_.GetAttribute ( "name", true );
1924 assert(att);
1925 name = project.ResolveProperties ( att->value );
1926
1927 att = node_.GetAttribute ( "value", true );
1928 assert(att);
1929 value = att->value;
1930
1931 att = node_.GetAttribute ( "internal", false );
1932 if ( att != NULL )
1933 {
1934 const char* p = att->value.c_str();
1935 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
1936 isInternal = true;
1937 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
1938 isInternal = false;
1939 else
1940 {
1941 throw InvalidAttributeValueException (
1942 node_.location,
1943 "internal",
1944 att->value );
1945 }
1946 }
1947 else
1948 isInternal = false;
1949 }
1950
1951 Property::Property ( const Project& project_,
1952 const Module* module_,
1953 const std::string& name_,
1954 const std::string& value_ )
1955 : project(project_), module(module_), name(name_), value(value_)
1956 {
1957 }
1958
1959 void
1960 Property::ProcessXML()
1961 {
1962 }
1963
1964
1965 PchFile::PchFile (
1966 const XMLElement& node_,
1967 const Module& module_,
1968 const FileLocation *file_ )
1969 : node(node_), module(module_), file(file_)
1970 {
1971 }
1972
1973 PchFile::~PchFile()
1974 {
1975 delete file;
1976 }
1977
1978 void
1979 PchFile::ProcessXML()
1980 {
1981 }