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