Remove ExportDriver concept.
[reactos.git] / reactos / tools / rbuild / module.cpp
1 /*
2 * Copyright (C) 2005 Casper S. Hornstrup
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18 #include "pch.h"
19 #include <assert.h>
20
21 #include "rbuild.h"
22
23 using std::string;
24 using std::vector;
25
26 string
27 Right ( const string& s, size_t n )
28 {
29 if ( n > s.size() )
30 return s;
31 return string ( &s[s.size()-n] );
32 }
33
34 string
35 Replace ( const string& s, const string& find, const string& with )
36 {
37 string ret;
38 const char* p = s.c_str();
39 while ( p )
40 {
41 const char* p2 = strstr ( p, find.c_str() );
42 if ( !p2 )
43 break;
44 if ( p2 > p )
45 ret += string ( p, p2-p );
46 ret += with;
47 p = p2 + find.size();
48 }
49 if ( *p )
50 ret += p;
51 return ret;
52 }
53
54 string
55 ChangeSeparator ( const string& s,
56 const char fromSeparator,
57 const char toSeparator )
58 {
59 string s2(s);
60 char* p = strchr ( &s2[0], fromSeparator );
61 while ( p )
62 {
63 *p++ = toSeparator;
64 p = strchr ( p, fromSeparator );
65 }
66 return s2;
67 }
68
69 string
70 FixSeparator ( const string& s )
71 {
72 return ChangeSeparator ( s, cBadSep, cSep );
73 }
74
75 string
76 FixSeparatorForSystemCommand ( const string& s )
77 {
78 string s2(s);
79 char* p = strchr ( &s2[0], DEF_CBAD_SEP );
80 while ( p )
81 {
82 *p++ = DEF_CSEP;
83 p = strchr ( p, DEF_CBAD_SEP );
84 }
85 return s2;
86 }
87
88 string
89 DosSeparator ( const string& s )
90 {
91 string s2(s);
92 char* p = strchr ( &s2[0], '/' );
93 while ( p )
94 {
95 *p++ = '\\';
96 p = strchr ( p, '/' );
97 }
98 return s2;
99 }
100
101 string
102 ReplaceExtension (
103 const string& filename,
104 const string& newExtension )
105 {
106 size_t index = filename.find_last_of ( '/' );
107 if ( index == string::npos )
108 index = 0;
109 size_t index2 = filename.find_last_of ( '\\' );
110 if ( index2 != string::npos && index2 > index )
111 index = index2;
112 string tmp = filename.substr( index /*, filename.size() - index*/ );
113 size_t ext_index = tmp.find_last_of( '.' );
114 if ( ext_index != string::npos )
115 return filename.substr ( 0, index + ext_index ) + newExtension;
116 return filename + newExtension;
117 }
118
119 string
120 GetSubPath (
121 const string& location,
122 const string& path,
123 const string& att_value )
124 {
125 if ( !att_value.size() )
126 throw XMLInvalidBuildFileException (
127 location,
128 "<directory> tag has empty 'name' attribute" );
129 if ( strpbrk ( att_value.c_str (), "/\\?*:<>|" ) )
130 throw XMLInvalidBuildFileException (
131 location,
132 "<directory> tag has invalid characters in 'name' attribute" );
133 if ( !path.size() )
134 return att_value;
135 return FixSeparator(path + cSep + att_value);
136 }
137
138 string
139 GetExtension ( const string& filename )
140 {
141 size_t index = filename.find_last_of ( '/' );
142 if (index == string::npos) index = 0;
143 string tmp = filename.substr( index, filename.size() - index );
144 size_t ext_index = tmp.find_last_of( '.' );
145 if (ext_index != string::npos)
146 return filename.substr ( index + ext_index, filename.size() );
147 return "";
148 }
149
150 string
151 GetDirectory ( const string& filename )
152 {
153 size_t index = filename.find_last_of ( cSep );
154 if ( index == string::npos )
155 return "";
156 else
157 return filename.substr ( 0, index );
158 }
159
160 string
161 GetFilename ( const string& filename )
162 {
163 size_t index = filename.find_last_of ( cSep );
164 if ( index == string::npos )
165 return filename;
166 else
167 return filename.substr ( index + 1, filename.length () - index );
168 }
169
170 string
171 NormalizeFilename ( const string& filename )
172 {
173 if ( filename == "" )
174 return "";
175 Path path;
176 string normalizedPath = path.Fixup ( filename, true );
177 string relativeNormalizedPath = path.RelativeFromWorkingDirectory ( normalizedPath );
178 return FixSeparator ( relativeNormalizedPath );
179 }
180
181 bool
182 GetBooleanValue ( const string& value )
183 {
184 if ( value == "1" )
185 return true;
186 else
187 return false;
188 }
189
190 string
191 ToLower ( string filename )
192 {
193 for ( size_t i = 1; i < filename.length (); i++ )
194 filename[i] = tolower ( filename[i] );
195 return filename;
196 }
197
198 void IfableData::ExtractModules( std::vector<Module*> &modules )
199 {
200 size_t i;
201 for ( i = 0; i < this->modules.size (); i++ )
202 modules.push_back(this->modules[i]);
203 }
204
205 IfableData::~IfableData()
206 {
207 size_t i;
208 for ( i = 0; i < includes.size (); i++ )
209 delete includes[i];
210 for ( i = 0; i < defines.size (); i++ )
211 delete defines[i];
212 for ( i = 0; i < libraries.size (); i++ )
213 delete libraries[i];
214 for ( i = 0; i < properties.size (); i++ )
215 delete properties[i];
216 for ( i = 0; i < compilerFlags.size (); i++ )
217 delete compilerFlags[i];
218 for ( i = 0; i < modules.size(); i++ )
219 delete modules[i];
220 for ( i = 0; i < ifs.size (); i++ )
221 delete ifs[i];
222 for ( i = 0; i < compilationUnits.size (); i++ )
223 delete compilationUnits[i];
224 }
225
226 void IfableData::ProcessXML ()
227 {
228 size_t i;
229 for ( i = 0; i < includes.size (); i++ )
230 includes[i]->ProcessXML ();
231 for ( i = 0; i < defines.size (); i++ )
232 defines[i]->ProcessXML ();
233 for ( i = 0; i < libraries.size (); i++ )
234 libraries[i]->ProcessXML ();
235 for ( i = 0; i < properties.size(); i++ )
236 properties[i]->ProcessXML ();
237 for ( i = 0; i < compilerFlags.size(); i++ )
238 compilerFlags[i]->ProcessXML ();
239 for ( i = 0; i < ifs.size (); i++ )
240 ifs[i]->ProcessXML ();
241 for ( i = 0; i < compilationUnits.size (); i++ )
242 compilationUnits[i]->ProcessXML ();
243 }
244
245 Module::Module ( const Project& project,
246 const XMLElement& moduleNode,
247 const string& modulePath )
248 : project (project),
249 node (moduleNode),
250 importLibrary (NULL),
251 bootstrap (NULL),
252 autoRegister(NULL),
253 linkerScript (NULL),
254 pch (NULL),
255 cplusplus (false),
256 host (HostDefault)
257 {
258 if ( node.name != "module" )
259 throw InvalidOperationException ( __FILE__,
260 __LINE__,
261 "Module created with non-<module> node" );
262
263 xmlbuildFile = Path::RelativeFromWorkingDirectory ( moduleNode.xmlFile->filename () );
264
265 path = FixSeparator ( modulePath );
266
267 enabled = true;
268
269 const XMLAttribute* att = moduleNode.GetAttribute ( "if", false );
270 if ( att != NULL )
271 enabled = GetBooleanValue ( project.ResolveProperties ( att->value ) );
272
273 att = moduleNode.GetAttribute ( "ifnot", false );
274 if ( att != NULL )
275 enabled = !GetBooleanValue ( project.ResolveProperties ( att->value ) );
276
277 att = moduleNode.GetAttribute ( "name", true );
278 assert(att);
279 name = att->value;
280
281 att = moduleNode.GetAttribute ( "type", true );
282 assert(att);
283 type = GetModuleType ( node.location, *att );
284
285 att = moduleNode.GetAttribute ( "extension", false );
286 if ( att != NULL )
287 extension = att->value;
288 else
289 extension = GetDefaultModuleExtension ();
290
291 att = moduleNode.GetAttribute ( "unicode", false );
292 if ( att != NULL )
293 {
294 const char* p = att->value.c_str();
295 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
296 isUnicode = true;
297 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
298 isUnicode = false;
299 else
300 {
301 throw InvalidAttributeValueException (
302 moduleNode.location,
303 "unicode",
304 att->value );
305 }
306 }
307 else
308 isUnicode = false;
309
310 att = moduleNode.GetAttribute ( "stdlib", false );
311 if ( att != NULL )
312 {
313 const char* p = att->value.c_str();
314 if ( !stricmp ( p, "host" ) )
315 useHostStdlib = true;
316 else if ( !stricmp ( p, "default" ) )
317 useHostStdlib = false;
318 else
319 {
320 throw InvalidAttributeValueException (
321 moduleNode.location,
322 "stdlib",
323 att->value );
324 }
325 }
326 else
327 useHostStdlib = false;
328
329 if (isUnicode)
330 {
331 // Always define UNICODE and _UNICODE
332 Define* pDefine = new Define ( project, this, "UNICODE" );
333 non_if_data.defines.push_back ( pDefine );
334
335 pDefine = new Define ( project, this, "_UNICODE" );
336 non_if_data.defines.push_back ( pDefine );
337 }
338
339 att = moduleNode.GetAttribute ( "entrypoint", false );
340 if ( att != NULL )
341 {
342 if ( att->value == "" )
343 {
344 throw InvalidAttributeValueException (
345 moduleNode.location,
346 "entrypoint",
347 att->value );
348 }
349
350 entrypoint = att->value;
351 isDefaultEntryPoint = false;
352 }
353 else
354 {
355 entrypoint = GetDefaultModuleEntrypoint ();
356 isDefaultEntryPoint = true;
357 }
358
359 att = moduleNode.GetAttribute ( "baseaddress", false );
360 if ( att != NULL )
361 baseaddress = att->value;
362 else
363 baseaddress = GetDefaultModuleBaseaddress ();
364
365 att = moduleNode.GetAttribute ( "mangledsymbols", false );
366 if ( att != NULL )
367 {
368 const char* p = att->value.c_str();
369 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
370 mangledSymbols = true;
371 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
372 mangledSymbols = false;
373 else
374 {
375 throw InvalidAttributeValueException (
376 moduleNode.location,
377 "mangledsymbols",
378 att->value );
379 }
380 }
381 else
382 mangledSymbols = false;
383
384 att = moduleNode.GetAttribute ( "underscoresymbols", false );
385 if ( att != NULL )
386 underscoreSymbols = att->value == "true";
387 else
388 underscoreSymbols = false;
389
390 att = moduleNode.GetAttribute ( "host", false );
391 if ( att != NULL )
392 {
393 const char* p = att->value.c_str();
394 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
395 host = HostTrue;
396 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
397 host = HostFalse;
398 else
399 {
400 throw InvalidAttributeValueException (
401 moduleNode.location,
402 "host",
403 att->value );
404 }
405 }
406
407 att = moduleNode.GetAttribute ( "isstartuplib", false );
408 if ( att != NULL )
409 {
410 const char* p = att->value.c_str();
411 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
412 isStartupLib = true;
413 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
414 isStartupLib = false;
415 else
416 {
417 throw InvalidAttributeValueException (
418 moduleNode.location,
419 "host",
420 att->value );
421 }
422 }
423 else
424 isStartupLib = false;
425
426 att = moduleNode.GetAttribute ( "prefix", false );
427 if ( att != NULL )
428 prefix = att->value;
429
430 att = moduleNode.GetAttribute ( "installbase", false );
431 if ( att != NULL )
432 installBase = att->value;
433 else
434 installBase = "";
435
436 att = moduleNode.GetAttribute ( "installname", false );
437 if ( att != NULL )
438 installName = att->value;
439 else
440 installName = "";
441
442 att = moduleNode.GetAttribute ( "usewrc", false );
443 if ( att != NULL )
444 useWRC = att->value == "true";
445 else
446 useWRC = true;
447
448 att = moduleNode.GetAttribute ( "allowwarnings", false );
449 if ( att == NULL )
450 {
451 att = moduleNode.GetAttribute ( "warnings", false );
452 if ( att != NULL )
453 {
454 printf ( "%s: WARNING: 'warnings' attribute of <module> is deprecated, use 'allowwarnings' instead\n",
455 moduleNode.location.c_str() );
456 }
457 }
458 if ( att != NULL )
459 allowWarnings = att->value == "true";
460 else
461 allowWarnings = false;
462
463 att = moduleNode.GetAttribute ( "aliasof", false );
464 if ( type == Alias && att != NULL )
465 aliasedModuleName = att->value;
466 else
467 aliasedModuleName = "";
468
469 if ( type == BootProgram )
470 {
471 att = moduleNode.GetAttribute ( "payload", true );
472 payload = att->value;
473 }
474 }
475
476 Module::~Module ()
477 {
478 size_t i;
479 for ( i = 0; i < invocations.size(); i++ )
480 delete invocations[i];
481 for ( i = 0; i < dependencies.size(); i++ )
482 delete dependencies[i];
483 for ( i = 0; i < compilerFlags.size(); i++ )
484 delete compilerFlags[i];
485 for ( i = 0; i < linkerFlags.size(); i++ )
486 delete linkerFlags[i];
487 for ( i = 0; i < stubbedComponents.size(); i++ )
488 delete stubbedComponents[i];
489 if ( linkerScript )
490 delete linkerScript;
491 if ( pch )
492 delete pch;
493 }
494
495 void
496 Module::ProcessXML()
497 {
498 if ( type == Alias )
499 {
500 if ( aliasedModuleName == name )
501 {
502 throw XMLInvalidBuildFileException (
503 node.location,
504 "module '%s' cannot link against itself",
505 name.c_str() );
506 }
507 const Module* m = project.LocateModule ( aliasedModuleName );
508 if ( !m )
509 {
510 throw XMLInvalidBuildFileException (
511 node.location,
512 "module '%s' trying to alias non-existant module '%s'",
513 name.c_str(),
514 aliasedModuleName.c_str() );
515 }
516 }
517
518 size_t i;
519 for ( i = 0; i < node.subElements.size(); i++ )
520 {
521 ParseContext parseContext;
522 ProcessXMLSubElement ( *node.subElements[i], path, parseContext );
523 }
524 for ( i = 0; i < invocations.size(); i++ )
525 invocations[i]->ProcessXML ();
526 for ( i = 0; i < dependencies.size(); i++ )
527 dependencies[i]->ProcessXML ();
528 for ( i = 0; i < compilerFlags.size(); i++ )
529 compilerFlags[i]->ProcessXML();
530 for ( i = 0; i < linkerFlags.size(); i++ )
531 linkerFlags[i]->ProcessXML();
532 for ( i = 0; i < stubbedComponents.size(); i++ )
533 stubbedComponents[i]->ProcessXML();
534 non_if_data.ProcessXML();
535 if ( linkerScript )
536 linkerScript->ProcessXML();
537 if ( pch )
538 pch->ProcessXML();
539 if ( autoRegister )
540 autoRegister->ProcessXML();
541 }
542
543 void
544 Module::ProcessXMLSubElement ( const XMLElement& e,
545 const string& path,
546 ParseContext& parseContext )
547 {
548 If* pOldIf = parseContext.ifData;
549 CompilationUnit* pOldCompilationUnit = parseContext.compilationUnit;
550 bool subs_invalid = false;
551 string subpath ( path );
552 if ( e.name == "file" && e.value.size () > 0 )
553 {
554 bool first = false;
555 const XMLAttribute* att = e.GetAttribute ( "first", false );
556 if ( att != NULL )
557 {
558 if ( !stricmp ( att->value.c_str(), "true" ) )
559 first = true;
560 else if ( stricmp ( att->value.c_str(), "false" ) )
561 {
562 throw XMLInvalidBuildFileException (
563 e.location,
564 "attribute 'first' of <file> element can only be 'true' or 'false'" );
565 }
566 }
567 string switches = "";
568 att = e.GetAttribute ( "switches", false );
569 if ( att != NULL )
570 switches = att->value;
571 if ( !cplusplus )
572 {
573 // check for c++ file
574 string ext = GetExtension ( e.value );
575 if ( !stricmp ( ext.c_str(), ".cpp" ) )
576 cplusplus = true;
577 else if ( !stricmp ( ext.c_str(), ".cc" ) )
578 cplusplus = true;
579 else if ( !stricmp ( ext.c_str(), ".cxx" ) )
580 cplusplus = true;
581 }
582 File* pFile = new File ( FixSeparator ( path + cSep + e.value ),
583 first,
584 switches,
585 false );
586 if ( parseContext.compilationUnit )
587 parseContext.compilationUnit->files.push_back ( pFile );
588 else
589 {
590 CompilationUnit* pCompilationUnit = new CompilationUnit ( pFile );
591 if ( parseContext.ifData )
592 parseContext.ifData->data.compilationUnits.push_back ( pCompilationUnit );
593 else
594 {
595 string ext = GetExtension ( e.value );
596 if ( !stricmp ( ext.c_str(), ".idl" ) )
597 non_if_data.compilationUnits.insert ( non_if_data.compilationUnits.begin(), pCompilationUnit );
598 else
599 non_if_data.compilationUnits.push_back ( pCompilationUnit );
600 }
601 }
602 if ( parseContext.ifData )
603 parseContext.ifData->data.files.push_back ( pFile );
604 else
605 non_if_data.files.push_back ( pFile );
606 subs_invalid = true;
607 }
608 else if ( e.name == "library" && e.value.size () )
609 {
610 Library* pLibrary = new Library ( e, *this, e.value );
611 if ( parseContext.ifData )
612 parseContext.ifData->data.libraries.push_back ( pLibrary );
613 else
614 non_if_data.libraries.push_back ( pLibrary );
615 subs_invalid = true;
616 }
617 else if ( e.name == "directory" )
618 {
619 const XMLAttribute* att = e.GetAttribute ( "name", true );
620 assert(att);
621 subpath = GetSubPath ( e.location, path, att->value );
622 }
623 else if ( e.name == "include" )
624 {
625 Include* include = new Include ( project, this, &e );
626 if ( parseContext.ifData )
627 parseContext.ifData->data.includes.push_back ( include );
628 else
629 non_if_data.includes.push_back ( include );
630 subs_invalid = true;
631 }
632 else if ( e.name == "define" )
633 {
634 Define* pDefine = new Define ( project, this, e );
635 if ( parseContext.ifData )
636 parseContext.ifData->data.defines.push_back ( pDefine );
637 else
638 non_if_data.defines.push_back ( pDefine );
639 subs_invalid = true;
640 }
641 else if ( e.name == "invoke" )
642 {
643 if ( parseContext.ifData )
644 {
645 throw XMLInvalidBuildFileException (
646 e.location,
647 "<invoke> is not a valid sub-element of <if>" );
648 }
649 invocations.push_back ( new Invoke ( e, *this ) );
650 subs_invalid = false;
651 }
652 else if ( e.name == "dependency" )
653 {
654 if ( parseContext.ifData )
655 {
656 throw XMLInvalidBuildFileException (
657 e.location,
658 "<dependency> is not a valid sub-element of <if>" );
659 }
660 dependencies.push_back ( new Dependency ( e, *this ) );
661 subs_invalid = true;
662 }
663 else if ( e.name == "importlibrary" )
664 {
665 if ( parseContext.ifData )
666 {
667 throw XMLInvalidBuildFileException (
668 e.location,
669 "<importlibrary> is not a valid sub-element of <if>" );
670 }
671 if ( importLibrary )
672 {
673 throw XMLInvalidBuildFileException (
674 e.location,
675 "Only one <importlibrary> is valid per module" );
676 }
677 importLibrary = new ImportLibrary ( e, *this );
678 subs_invalid = true;
679 }
680 else if ( e.name == "if" )
681 {
682 parseContext.ifData = new If ( e, project, this );
683 if ( pOldIf )
684 pOldIf->data.ifs.push_back ( parseContext.ifData );
685 else
686 non_if_data.ifs.push_back ( parseContext.ifData );
687 subs_invalid = false;
688 }
689 else if ( e.name == "ifnot" )
690 {
691 parseContext.ifData = new If ( e, project, this, true );
692 if ( pOldIf )
693 pOldIf->data.ifs.push_back ( parseContext.ifData );
694 else
695 non_if_data.ifs.push_back ( parseContext.ifData );
696 subs_invalid = false;
697 }
698 else if ( e.name == "compilerflag" )
699 {
700 CompilerFlag* pCompilerFlag = new CompilerFlag ( project, this, e );
701 if ( parseContext.ifData )
702 parseContext.ifData->data.compilerFlags.push_back ( pCompilerFlag );
703 else
704 non_if_data.compilerFlags.push_back ( pCompilerFlag );
705 subs_invalid = true;
706 }
707 else if ( e.name == "linkerflag" )
708 {
709 linkerFlags.push_back ( new LinkerFlag ( project, this, e ) );
710 subs_invalid = true;
711 }
712 else if ( e.name == "linkerscript" )
713 {
714 if ( linkerScript )
715 {
716 throw XMLInvalidBuildFileException (
717 e.location,
718 "Only one <linkerscript> is valid per module" );
719 }
720 linkerScript = new LinkerScript ( project, this, e );
721 subs_invalid = true;
722 }
723 else if ( e.name == "component" )
724 {
725 stubbedComponents.push_back ( new StubbedComponent ( this, e ) );
726 subs_invalid = false;
727 }
728 else if ( e.name == "property" )
729 {
730 throw XMLInvalidBuildFileException (
731 e.location,
732 "<property> is not a valid sub-element of <module>" );
733 }
734 else if ( e.name == "bootstrap" )
735 {
736 bootstrap = new Bootstrap ( project, this, e );
737 subs_invalid = true;
738 }
739 else if ( e.name == "pch" )
740 {
741 if ( parseContext.ifData )
742 {
743 throw XMLInvalidBuildFileException (
744 e.location,
745 "<pch> is not a valid sub-element of <if>" );
746 }
747 if ( pch )
748 {
749 throw XMLInvalidBuildFileException (
750 e.location,
751 "Only one <pch> is valid per module" );
752 }
753 pch = new PchFile (
754 e, *this, File ( FixSeparator ( path + cSep + e.value ), false, "", true ) );
755 subs_invalid = true;
756 }
757 else if ( e.name == "compilationunit" )
758 {
759 if ( project.configuration.CompilationUnitsEnabled )
760 {
761 CompilationUnit* pCompilationUnit = new CompilationUnit ( &project, this, &e );
762 if ( parseContext.ifData )
763 parseContext.ifData->data.compilationUnits.push_back ( pCompilationUnit );
764 else
765 non_if_data.compilationUnits.push_back ( pCompilationUnit );
766 parseContext.compilationUnit = pCompilationUnit;
767 }
768 subs_invalid = false;
769 }
770 else if ( e.name == "autoregister" )
771 {
772 if ( autoRegister != NULL)
773 {
774 throw XMLInvalidBuildFileException (
775 e.location,
776 "there can be only one <%s> element for a module",
777 e.name.c_str() );
778 }
779 autoRegister = new AutoRegister ( project, this, e );
780 subs_invalid = true;
781 }
782 if ( subs_invalid && e.subElements.size() > 0 )
783 {
784 throw XMLInvalidBuildFileException (
785 e.location,
786 "<%s> cannot have sub-elements",
787 e.name.c_str() );
788 }
789 for ( size_t i = 0; i < e.subElements.size (); i++ )
790 ProcessXMLSubElement ( *e.subElements[i], subpath, parseContext );
791 parseContext.ifData = pOldIf;
792 parseContext.compilationUnit = pOldCompilationUnit;
793 }
794
795 ModuleType
796 Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
797 {
798 if ( attribute.value == "buildtool" )
799 return BuildTool;
800 if ( attribute.value == "staticlibrary" )
801 return StaticLibrary;
802 if ( attribute.value == "objectlibrary" )
803 return ObjectLibrary;
804 if ( attribute.value == "kernel" )
805 return Kernel;
806 if ( attribute.value == "kernelmodedll" )
807 return KernelModeDLL;
808 if ( attribute.value == "kernelmodedriver" )
809 return KernelModeDriver;
810 if ( attribute.value == "nativedll" )
811 return NativeDLL;
812 if ( attribute.value == "nativecui" )
813 return NativeCUI;
814 if ( attribute.value == "win32dll" )
815 return Win32DLL;
816 if ( attribute.value == "win32ocx" )
817 return Win32OCX;
818 if ( attribute.value == "win32cui" )
819 return Win32CUI;
820 if ( attribute.value == "win32gui" )
821 return Win32GUI;
822 if ( attribute.value == "win32scr" )
823 return Win32SCR;
824 if ( attribute.value == "bootloader" )
825 return BootLoader;
826 if ( attribute.value == "bootsector" )
827 return BootSector;
828 if ( attribute.value == "bootprogram" )
829 return BootProgram;
830 if ( attribute.value == "iso" )
831 return Iso;
832 if ( attribute.value == "liveiso" )
833 return LiveIso;
834 if ( attribute.value == "isoregtest" )
835 return IsoRegTest;
836 if ( attribute.value == "liveisoregtest" )
837 return LiveIsoRegTest;
838 if ( attribute.value == "test" )
839 return Test;
840 if ( attribute.value == "rpcserver" )
841 return RpcServer;
842 if ( attribute.value == "rpcclient" )
843 return RpcClient;
844 if ( attribute.value == "alias" )
845 return Alias;
846 if ( attribute.value == "idlheader" )
847 return IdlHeader;
848 if ( attribute.value == "embeddedtypelib" )
849 return EmbeddedTypeLib;
850 throw InvalidAttributeValueException ( location,
851 attribute.name,
852 attribute.value );
853 }
854
855 string
856 Module::GetDefaultModuleExtension () const
857 {
858 switch (type)
859 {
860 case BuildTool:
861 return ExePostfix;
862 case StaticLibrary:
863 return ".a";
864 case ObjectLibrary:
865 return ".o";
866 case Kernel:
867 case NativeCUI:
868 case Win32CUI:
869 case Win32GUI:
870 return ".exe";
871 case Win32SCR:
872 return ".scr";
873
874 case KernelModeDLL:
875 case NativeDLL:
876 case Win32DLL:
877 return ".dll";
878 case Win32OCX:
879 return ".ocx";
880 case KernelModeDriver:
881 case BootLoader:
882 return ".sys";
883 case BootSector:
884 return ".o";
885 case Iso:
886 case LiveIso:
887 case IsoRegTest:
888 case LiveIsoRegTest:
889 return ".iso";
890 case Test:
891 return ".exe";
892 case RpcServer:
893 return ".o";
894 case RpcClient:
895 return ".o";
896 case Alias:
897 case BootProgram:
898 case IdlHeader:
899 return "";
900 case EmbeddedTypeLib:
901 return ".tlb";
902 }
903 throw InvalidOperationException ( __FILE__,
904 __LINE__ );
905 }
906
907 string
908 Module::GetDefaultModuleEntrypoint () const
909 {
910 switch ( type )
911 {
912 case Kernel:
913 return "NtProcessStartup";
914 case KernelModeDLL:
915 case KernelModeDriver:
916 return "DriverEntry@8";
917 case NativeDLL:
918 return "DllMainCRTStartup@12";
919 case NativeCUI:
920 return "NtProcessStartup@4";
921 case Win32DLL:
922 case Win32OCX:
923 return "DllMain@12";
924 case Win32CUI:
925 case Test:
926 if ( isUnicode )
927 return "wmainCRTStartup";
928 else
929 return "mainCRTStartup";
930 case Win32SCR:
931 case Win32GUI:
932 if ( isUnicode )
933 return "wWinMainCRTStartup";
934 else
935 return "WinMainCRTStartup";
936 case BuildTool:
937 case StaticLibrary:
938 case ObjectLibrary:
939 case BootLoader:
940 case BootSector:
941 case Iso:
942 case LiveIso:
943 case IsoRegTest:
944 case LiveIsoRegTest:
945 case RpcServer:
946 case RpcClient:
947 case Alias:
948 case BootProgram:
949 case IdlHeader:
950 case EmbeddedTypeLib:
951 return "";
952 }
953 throw InvalidOperationException ( __FILE__,
954 __LINE__ );
955 }
956
957 string
958 Module::GetDefaultModuleBaseaddress () const
959 {
960 switch ( type )
961 {
962 case Kernel:
963 return "0x80000000";
964 case Win32DLL:
965 case Win32OCX:
966 return "0x10000000";
967 case NativeDLL:
968 case NativeCUI:
969 case Win32CUI:
970 case Test:
971 return "0x00400000";
972 case Win32SCR:
973 case Win32GUI:
974 return "0x00400000";
975 case KernelModeDLL:
976 case KernelModeDriver:
977 return "0x00010000";
978 case BuildTool:
979 case StaticLibrary:
980 case ObjectLibrary:
981 case BootLoader:
982 case BootSector:
983 case Iso:
984 case LiveIso:
985 case IsoRegTest:
986 case LiveIsoRegTest:
987 case RpcServer:
988 case RpcClient:
989 case Alias:
990 case BootProgram:
991 case IdlHeader:
992 case EmbeddedTypeLib:
993 return "";
994 }
995 throw InvalidOperationException ( __FILE__,
996 __LINE__ );
997 }
998
999 bool
1000 Module::HasImportLibrary () const
1001 {
1002 return importLibrary != NULL && type != StaticLibrary;
1003 }
1004
1005 bool
1006 Module::IsDLL () const
1007 {
1008 switch ( type )
1009 {
1010 case Kernel:
1011 case KernelModeDLL:
1012 case NativeDLL:
1013 case Win32DLL:
1014 case Win32OCX:
1015 case KernelModeDriver:
1016 return true;
1017 case NativeCUI:
1018 case Win32CUI:
1019 case Test:
1020 case Win32SCR:
1021 case Win32GUI:
1022 case BuildTool:
1023 case StaticLibrary:
1024 case ObjectLibrary:
1025 case BootLoader:
1026 case BootSector:
1027 case BootProgram:
1028 case Iso:
1029 case LiveIso:
1030 case IsoRegTest:
1031 case LiveIsoRegTest:
1032 case RpcServer:
1033 case RpcClient:
1034 case Alias:
1035 case IdlHeader:
1036 case EmbeddedTypeLib:
1037 return false;
1038 }
1039 throw InvalidOperationException ( __FILE__,
1040 __LINE__ );
1041 }
1042
1043 bool
1044 Module::GenerateInOutputTree () const
1045 {
1046 switch ( type )
1047 {
1048 case Kernel:
1049 case KernelModeDLL:
1050 case NativeDLL:
1051 case Win32DLL:
1052 case Win32OCX:
1053 case KernelModeDriver:
1054 case NativeCUI:
1055 case Win32CUI:
1056 case Test:
1057 case Win32SCR:
1058 case Win32GUI:
1059 case BuildTool:
1060 case BootLoader:
1061 case BootSector:
1062 case BootProgram:
1063 case Iso:
1064 case LiveIso:
1065 case IsoRegTest:
1066 case LiveIsoRegTest:
1067 case EmbeddedTypeLib:
1068 return true;
1069 case StaticLibrary:
1070 case ObjectLibrary:
1071 case RpcServer:
1072 case RpcClient:
1073 case Alias:
1074 case IdlHeader:
1075 return false;
1076 }
1077 throw InvalidOperationException ( __FILE__,
1078 __LINE__ );
1079 }
1080
1081 string
1082 Module::GetTargetName () const
1083 {
1084 return name + extension;
1085 }
1086
1087 string
1088 Module::GetDependencyPath () const
1089 {
1090 if ( HasImportLibrary () )
1091 return ReplaceExtension ( GetPathWithPrefix ( "lib" ), ".a" );
1092 else
1093 return GetPath();
1094 }
1095
1096 string
1097 Module::GetBasePath () const
1098 {
1099 return path;
1100 }
1101
1102 string
1103 Module::GetPath () const
1104 {
1105 if ( path.length() > 0 )
1106 return path + cSep + GetTargetName ();
1107 else
1108 return GetTargetName ();
1109 }
1110
1111 string
1112 Module::GetPathWithPrefix ( const string& prefix ) const
1113 {
1114 return path + cSep + prefix + GetTargetName ();
1115 }
1116
1117 string
1118 Module::GetPathToBaseDir () const
1119 {
1120 string temp_path = path;
1121 string result = "..\\";
1122 while(temp_path.find ('\\') != string::npos)
1123 {
1124 temp_path.erase (0, temp_path.find('\\')+1);
1125 result += "..\\";
1126 }
1127 return result;
1128 }
1129
1130 string
1131 Module::GetInvocationTarget ( const int index ) const
1132 {
1133 return ssprintf ( "%s_invoke_%d",
1134 name.c_str (),
1135 index );
1136 }
1137
1138 string
1139 Module::GetEntryPoint(bool leadingUnderscore) const
1140 {
1141 string result = "";
1142 if (entrypoint == "0" || entrypoint == "0x0")
1143 return "0";
1144 if (leadingUnderscore)
1145 result = "_";
1146
1147 result += entrypoint;
1148 return result;
1149 }
1150
1151 bool
1152 Module::HasFileWithExtension (
1153 const IfableData& data,
1154 const std::string& extension ) const
1155 {
1156 size_t i;
1157 for ( i = 0; i < data.compilationUnits.size (); i++ )
1158 {
1159 CompilationUnit* compilationUnit = data.compilationUnits[i];
1160 if ( compilationUnit->HasFileWithExtension ( extension ) )
1161 return true;
1162 }
1163 for ( i = 0; i < data.ifs.size (); i++ )
1164 {
1165 if ( HasFileWithExtension ( data.ifs[i]->data, extension ) )
1166 return true;
1167 }
1168 return false;
1169 }
1170
1171 void
1172 Module::InvokeModule () const
1173 {
1174 for ( size_t i = 0; i < invocations.size (); i++ )
1175 {
1176 Invoke& invoke = *invocations[i];
1177 string command = FixSeparatorForSystemCommand(invoke.invokeModule->GetPath ()) + " " + invoke.GetParameters ();
1178 printf ( "Executing '%s'\n\n", command.c_str () );
1179 int exitcode = system ( command.c_str () );
1180 if ( exitcode != 0 )
1181 throw InvocationFailedException ( command,
1182 exitcode );
1183 }
1184 }
1185
1186
1187 File::File ( const string& _name, bool _first,
1188 std::string _switches,
1189 bool _isPreCompiledHeader )
1190 : name(_name),
1191 first(_first),
1192 switches(_switches),
1193 isPreCompiledHeader(_isPreCompiledHeader)
1194 {
1195 }
1196
1197 void
1198 File::ProcessXML()
1199 {
1200 }
1201
1202
1203 Library::Library ( const XMLElement& _node,
1204 const Module& _module,
1205 const string& _name )
1206 : node(&_node),
1207 module(_module),
1208 name(_name),
1209 importedModule(_module.project.LocateModule(_name))
1210 {
1211 if ( module.name == name )
1212 {
1213 throw XMLInvalidBuildFileException (
1214 node->location,
1215 "module '%s' cannot link against itself",
1216 name.c_str() );
1217 }
1218 if ( !importedModule )
1219 {
1220 throw XMLInvalidBuildFileException (
1221 node->location,
1222 "module '%s' trying to import non-existant module '%s'",
1223 module.name.c_str(),
1224 name.c_str() );
1225 }
1226 }
1227
1228 Library::Library ( const Module& _module,
1229 const string& _name )
1230 : node(NULL),
1231 module(_module),
1232 name(_name),
1233 importedModule(_module.project.LocateModule(_name))
1234 {
1235 }
1236
1237 void
1238 Library::ProcessXML()
1239 {
1240 if ( node && !module.project.LocateModule ( name ) )
1241 {
1242 throw XMLInvalidBuildFileException (
1243 node->location,
1244 "module '%s' is trying to link against non-existant module '%s'",
1245 module.name.c_str(),
1246 name.c_str() );
1247 }
1248 }
1249
1250
1251 Invoke::Invoke ( const XMLElement& _node,
1252 const Module& _module )
1253 : node (_node),
1254 module (_module)
1255 {
1256 }
1257
1258 void
1259 Invoke::ProcessXML()
1260 {
1261 const XMLAttribute* att = node.GetAttribute ( "module", false );
1262 if (att == NULL)
1263 invokeModule = &module;
1264 else
1265 {
1266 invokeModule = module.project.LocateModule ( att->value );
1267 if ( invokeModule == NULL )
1268 {
1269 throw XMLInvalidBuildFileException (
1270 node.location,
1271 "module '%s' is trying to invoke non-existant module '%s'",
1272 module.name.c_str(),
1273 att->value.c_str() );
1274 }
1275 }
1276
1277 for ( size_t i = 0; i < node.subElements.size (); i++ )
1278 ProcessXMLSubElement ( *node.subElements[i] );
1279 }
1280
1281 void
1282 Invoke::ProcessXMLSubElement ( const XMLElement& e )
1283 {
1284 bool subs_invalid = false;
1285 if ( e.name == "input" )
1286 {
1287 for ( size_t i = 0; i < e.subElements.size (); i++ )
1288 ProcessXMLSubElementInput ( *e.subElements[i] );
1289 }
1290 else if ( e.name == "output" )
1291 {
1292 for ( size_t i = 0; i < e.subElements.size (); i++ )
1293 ProcessXMLSubElementOutput ( *e.subElements[i] );
1294 }
1295 if ( subs_invalid && e.subElements.size() > 0 )
1296 {
1297 throw XMLInvalidBuildFileException (
1298 e.location,
1299 "<%s> cannot have sub-elements",
1300 e.name.c_str() );
1301 }
1302 }
1303
1304 void
1305 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
1306 {
1307 bool subs_invalid = false;
1308 if ( e.name == "inputfile" && e.value.size () > 0 )
1309 {
1310 input.push_back ( new InvokeFile (
1311 e, FixSeparator ( module.path + cSep + e.value ) ) );
1312 subs_invalid = true;
1313 }
1314 if ( subs_invalid && e.subElements.size() > 0 )
1315 {
1316 throw XMLInvalidBuildFileException (
1317 e.location,
1318 "<%s> cannot have sub-elements",
1319 e.name.c_str() );
1320 }
1321 }
1322
1323 void
1324 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
1325 {
1326 bool subs_invalid = false;
1327 if ( e.name == "outputfile" && e.value.size () > 0 )
1328 {
1329 output.push_back ( new InvokeFile (
1330 e, FixSeparator ( module.path + cSep + e.value ) ) );
1331 subs_invalid = true;
1332 }
1333 if ( subs_invalid && e.subElements.size() > 0 )
1334 {
1335 throw XMLInvalidBuildFileException (
1336 e.location,
1337 "<%s> cannot have sub-elements",
1338 e.name.c_str() );
1339 }
1340 }
1341
1342 void
1343 Invoke::GetTargets ( string_list& targets ) const
1344 {
1345 for ( size_t i = 0; i < output.size (); i++ )
1346 {
1347 InvokeFile& file = *output[i];
1348 targets.push_back ( NormalizeFilename ( file.name ) );
1349 }
1350 }
1351
1352 string
1353 Invoke::GetParameters () const
1354 {
1355 string parameters ( "" );
1356 size_t i;
1357 for ( i = 0; i < output.size (); i++ )
1358 {
1359 if ( parameters.length () > 0)
1360 parameters += " ";
1361 InvokeFile& invokeFile = *output[i];
1362 if ( invokeFile.switches.length () > 0 )
1363 {
1364 parameters += invokeFile.switches + " ";
1365 }
1366 parameters += invokeFile.name;
1367 }
1368
1369 for ( i = 0; i < input.size (); i++ )
1370 {
1371 if ( parameters.length () > 0 )
1372 parameters += " ";
1373 InvokeFile& invokeFile = *input[i];
1374 if ( invokeFile.switches.length () > 0 )
1375 {
1376 parameters += invokeFile.switches;
1377 parameters += " ";
1378 }
1379 parameters += invokeFile.name ;
1380 }
1381
1382 return parameters;
1383 }
1384
1385
1386 InvokeFile::InvokeFile ( const XMLElement& _node,
1387 const string& _name )
1388 : node (_node),
1389 name (_name)
1390 {
1391 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
1392 if (att != NULL)
1393 switches = att->value;
1394 else
1395 switches = "";
1396 }
1397
1398 void
1399 InvokeFile::ProcessXML()
1400 {
1401 }
1402
1403
1404 Dependency::Dependency ( const XMLElement& _node,
1405 const Module& _module )
1406 : node (_node),
1407 module (_module),
1408 dependencyModule (NULL)
1409 {
1410 }
1411
1412 void
1413 Dependency::ProcessXML()
1414 {
1415 dependencyModule = module.project.LocateModule ( node.value );
1416 if ( dependencyModule == NULL )
1417 {
1418 throw XMLInvalidBuildFileException (
1419 node.location,
1420 "module '%s' depend on non-existant module '%s'",
1421 module.name.c_str(),
1422 node.value.c_str() );
1423 }
1424 }
1425
1426
1427 ImportLibrary::ImportLibrary ( const XMLElement& _node,
1428 const Module& _module )
1429 : node (_node),
1430 module (_module)
1431 {
1432 const XMLAttribute* att = _node.GetAttribute ( "basename", false );
1433 if (att != NULL)
1434 basename = att->value;
1435 else
1436 basename = module.name;
1437
1438 att = _node.GetAttribute ( "dllname", false );
1439 if (att != NULL)
1440 dllname = att->value;
1441 else
1442 {
1443 if ( _module.type == StaticLibrary )
1444 {
1445 throw XMLInvalidBuildFileException (
1446 node.location,
1447 "<importlibrary> dllname attribute required." );
1448 }
1449
1450 dllname = "";
1451 }
1452
1453 att = _node.GetAttribute ( "definition", true );
1454 assert (att);
1455 definition = FixSeparator(att->value);
1456 }
1457
1458
1459 If::If ( const XMLElement& node_,
1460 const Project& project_,
1461 const Module* module_,
1462 const bool negated_ )
1463 : node(node_), project(project_), module(module_), negated(negated_)
1464 {
1465 const XMLAttribute* att;
1466
1467 att = node.GetAttribute ( "property", true );
1468 assert(att);
1469 property = att->value;
1470
1471 att = node.GetAttribute ( "value", true );
1472 assert(att);
1473 value = att->value;
1474 }
1475
1476 If::~If ()
1477 {
1478 }
1479
1480 void
1481 If::ProcessXML()
1482 {
1483
1484 }
1485
1486
1487 Property::Property ( const XMLElement& node_,
1488 const Project& project_,
1489 const Module* module_ )
1490 : node(node_), project(project_), module(module_)
1491 {
1492 const XMLAttribute* att;
1493
1494 att = node.GetAttribute ( "name", true );
1495 assert(att);
1496 name = att->value;
1497
1498 att = node.GetAttribute ( "value", true );
1499 assert(att);
1500 value = att->value;
1501 }
1502
1503 void
1504 Property::ProcessXML()
1505 {
1506 }
1507
1508
1509 PchFile::PchFile (
1510 const XMLElement& node_,
1511 const Module& module_,
1512 const File file_ )
1513 : node(node_), module(module_), file(file_)
1514 {
1515 }
1516
1517 void
1518 PchFile::ProcessXML()
1519 {
1520 }
1521
1522
1523 AutoRegister::AutoRegister ( const Project& project_,
1524 const Module* module_,
1525 const XMLElement& node_ )
1526 : project(project_),
1527 module(module_),
1528 node(node_)
1529 {
1530 Initialize();
1531 }
1532
1533 AutoRegister::~AutoRegister ()
1534 {
1535 }
1536
1537 bool
1538 AutoRegister::IsSupportedModuleType ( ModuleType type )
1539 {
1540 switch ( type )
1541 {
1542 case Win32DLL:
1543 case Win32OCX:
1544 return true;
1545 case Kernel:
1546 case KernelModeDLL:
1547 case NativeDLL:
1548 case NativeCUI:
1549 case Win32CUI:
1550 case Win32GUI:
1551 case Win32SCR:
1552 case KernelModeDriver:
1553 case BootSector:
1554 case BootLoader:
1555 case BootProgram:
1556 case BuildTool:
1557 case StaticLibrary:
1558 case ObjectLibrary:
1559 case Iso:
1560 case LiveIso:
1561 case IsoRegTest:
1562 case LiveIsoRegTest:
1563 case Test:
1564 case RpcServer:
1565 case RpcClient:
1566 case Alias:
1567 case IdlHeader:
1568 case EmbeddedTypeLib:
1569 return false;
1570 }
1571 throw InvalidOperationException ( __FILE__,
1572 __LINE__ );
1573 }
1574
1575 AutoRegisterType
1576 AutoRegister::GetAutoRegisterType( string type )
1577 {
1578 if ( type == "DllRegisterServer" )
1579 return DllRegisterServer;
1580 if ( type == "DllInstall" )
1581 return DllInstall;
1582 if ( type == "Both" )
1583 return Both;
1584 throw XMLInvalidBuildFileException (
1585 node.location,
1586 "<autoregister> type attribute must be DllRegisterServer, DllInstall or Both." );
1587 }
1588
1589 void
1590 AutoRegister::Initialize ()
1591 {
1592 if ( !IsSupportedModuleType ( module->type ) )
1593 {
1594 throw XMLInvalidBuildFileException (
1595 node.location,
1596 "<autoregister> is not applicable for this module type." );
1597 }
1598
1599 const XMLAttribute* att = node.GetAttribute ( "infsection", true );
1600 infSection = att->value;
1601
1602 att = node.GetAttribute ( "type", true );
1603 type = GetAutoRegisterType ( att->value );
1604 }
1605
1606 void
1607 AutoRegister::ProcessXML()
1608 {
1609 }