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