Process .idl files before source files
[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 entrypoint = att->value;
343 isDefaultEntryPoint = false;
344 }
345 else
346 {
347 entrypoint = GetDefaultModuleEntrypoint ();
348 isDefaultEntryPoint = true;
349 }
350
351 att = moduleNode.GetAttribute ( "baseaddress", false );
352 if ( att != NULL )
353 baseaddress = att->value;
354 else
355 baseaddress = GetDefaultModuleBaseaddress ();
356
357 att = moduleNode.GetAttribute ( "mangledsymbols", false );
358 if ( att != NULL )
359 {
360 const char* p = att->value.c_str();
361 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
362 mangledSymbols = true;
363 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
364 mangledSymbols = false;
365 else
366 {
367 throw InvalidAttributeValueException (
368 moduleNode.location,
369 "mangledsymbols",
370 att->value );
371 }
372 }
373 else
374 mangledSymbols = false;
375
376 att = moduleNode.GetAttribute ( "underscoresymbols", false );
377 if ( att != NULL )
378 underscoreSymbols = att->value == "true";
379 else
380 underscoreSymbols = false;
381
382 att = moduleNode.GetAttribute ( "host", false );
383 if ( att != NULL )
384 {
385 const char* p = att->value.c_str();
386 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
387 host = HostTrue;
388 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
389 host = HostFalse;
390 else
391 {
392 throw InvalidAttributeValueException (
393 moduleNode.location,
394 "host",
395 att->value );
396 }
397 }
398
399 att = moduleNode.GetAttribute ( "isstartuplib", false );
400 if ( att != NULL )
401 {
402 const char* p = att->value.c_str();
403 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
404 isStartupLib = true;
405 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
406 isStartupLib = false;
407 else
408 {
409 throw InvalidAttributeValueException (
410 moduleNode.location,
411 "host",
412 att->value );
413 }
414 }
415 else
416 isStartupLib = false;
417
418 att = moduleNode.GetAttribute ( "prefix", false );
419 if ( att != NULL )
420 prefix = att->value;
421
422 att = moduleNode.GetAttribute ( "installbase", false );
423 if ( att != NULL )
424 installBase = att->value;
425 else
426 installBase = "";
427
428 att = moduleNode.GetAttribute ( "installname", false );
429 if ( att != NULL )
430 installName = att->value;
431 else
432 installName = "";
433
434 att = moduleNode.GetAttribute ( "usewrc", false );
435 if ( att != NULL )
436 useWRC = att->value == "true";
437 else
438 useWRC = true;
439
440 att = moduleNode.GetAttribute ( "allowwarnings", false );
441 if ( att == NULL )
442 {
443 att = moduleNode.GetAttribute ( "warnings", false );
444 if ( att != NULL )
445 {
446 printf ( "%s: WARNING: 'warnings' attribute of <module> is deprecated, use 'allowwarnings' instead\n",
447 moduleNode.location.c_str() );
448 }
449 }
450 if ( att != NULL )
451 allowWarnings = att->value == "true";
452 else
453 allowWarnings = false;
454
455 att = moduleNode.GetAttribute ( "aliasof", false );
456 if ( type == Alias && att != NULL )
457 aliasedModuleName = att->value;
458 else
459 aliasedModuleName = "";
460
461 if ( type == BootProgram )
462 {
463 att = moduleNode.GetAttribute ( "payload", true );
464 payload = att->value;
465 }
466 }
467
468 Module::~Module ()
469 {
470 size_t i;
471 for ( i = 0; i < invocations.size(); i++ )
472 delete invocations[i];
473 for ( i = 0; i < dependencies.size(); i++ )
474 delete dependencies[i];
475 for ( i = 0; i < compilerFlags.size(); i++ )
476 delete compilerFlags[i];
477 for ( i = 0; i < linkerFlags.size(); i++ )
478 delete linkerFlags[i];
479 for ( i = 0; i < stubbedComponents.size(); i++ )
480 delete stubbedComponents[i];
481 if ( linkerScript )
482 delete linkerScript;
483 if ( pch )
484 delete pch;
485 }
486
487 void
488 Module::ProcessXML()
489 {
490 if ( type == Alias )
491 {
492 if ( aliasedModuleName == name )
493 {
494 throw XMLInvalidBuildFileException (
495 node.location,
496 "module '%s' cannot link against itself",
497 name.c_str() );
498 }
499 const Module* m = project.LocateModule ( aliasedModuleName );
500 if ( !m )
501 {
502 throw XMLInvalidBuildFileException (
503 node.location,
504 "module '%s' trying to alias non-existant module '%s'",
505 name.c_str(),
506 aliasedModuleName.c_str() );
507 }
508 }
509
510 size_t i;
511 for ( i = 0; i < node.subElements.size(); i++ )
512 {
513 ParseContext parseContext;
514 ProcessXMLSubElement ( *node.subElements[i], path, parseContext );
515 }
516 for ( i = 0; i < invocations.size(); i++ )
517 invocations[i]->ProcessXML ();
518 for ( i = 0; i < dependencies.size(); i++ )
519 dependencies[i]->ProcessXML ();
520 for ( i = 0; i < compilerFlags.size(); i++ )
521 compilerFlags[i]->ProcessXML();
522 for ( i = 0; i < linkerFlags.size(); i++ )
523 linkerFlags[i]->ProcessXML();
524 for ( i = 0; i < stubbedComponents.size(); i++ )
525 stubbedComponents[i]->ProcessXML();
526 non_if_data.ProcessXML();
527 if ( linkerScript )
528 linkerScript->ProcessXML();
529 if ( pch )
530 pch->ProcessXML();
531 if ( autoRegister )
532 autoRegister->ProcessXML();
533 }
534
535 void
536 Module::ProcessXMLSubElement ( const XMLElement& e,
537 const string& path,
538 ParseContext& parseContext )
539 {
540 If* pOldIf = parseContext.ifData;
541 CompilationUnit* pOldCompilationUnit = parseContext.compilationUnit;
542 bool subs_invalid = false;
543 string subpath ( path );
544 if ( e.name == "file" && e.value.size () > 0 )
545 {
546 bool first = false;
547 const XMLAttribute* att = e.GetAttribute ( "first", false );
548 if ( att != NULL )
549 {
550 if ( !stricmp ( att->value.c_str(), "true" ) )
551 first = true;
552 else if ( stricmp ( att->value.c_str(), "false" ) )
553 {
554 throw XMLInvalidBuildFileException (
555 e.location,
556 "attribute 'first' of <file> element can only be 'true' or 'false'" );
557 }
558 }
559 string switches = "";
560 att = e.GetAttribute ( "switches", false );
561 if ( att != NULL )
562 switches = att->value;
563 if ( !cplusplus )
564 {
565 // check for c++ file
566 string ext = GetExtension ( e.value );
567 if ( !stricmp ( ext.c_str(), ".cpp" ) )
568 cplusplus = true;
569 else if ( !stricmp ( ext.c_str(), ".cc" ) )
570 cplusplus = true;
571 else if ( !stricmp ( ext.c_str(), ".cxx" ) )
572 cplusplus = true;
573 }
574 File* pFile = new File ( FixSeparator ( path + cSep + e.value ),
575 first,
576 switches,
577 false );
578 if ( parseContext.compilationUnit )
579 parseContext.compilationUnit->files.push_back ( pFile );
580 else
581 {
582 CompilationUnit* pCompilationUnit = new CompilationUnit ( pFile );
583 if ( parseContext.ifData )
584 parseContext.ifData->data.compilationUnits.push_back ( pCompilationUnit );
585 else
586 {
587 string ext = GetExtension ( e.value );
588 if ( !stricmp ( ext.c_str(), ".idl" ) )
589 non_if_data.compilationUnits.insert ( non_if_data.compilationUnits.begin(), pCompilationUnit );
590 else
591 non_if_data.compilationUnits.push_back ( pCompilationUnit );
592 }
593 }
594 if ( parseContext.ifData )
595 parseContext.ifData->data.files.push_back ( pFile );
596 else
597 non_if_data.files.push_back ( pFile );
598 subs_invalid = true;
599 }
600 else if ( e.name == "library" && e.value.size () )
601 {
602 Library* pLibrary = new Library ( e, *this, e.value );
603 if ( parseContext.ifData )
604 parseContext.ifData->data.libraries.push_back ( pLibrary );
605 else
606 non_if_data.libraries.push_back ( pLibrary );
607 subs_invalid = true;
608 }
609 else if ( e.name == "directory" )
610 {
611 const XMLAttribute* att = e.GetAttribute ( "name", true );
612 assert(att);
613 subpath = GetSubPath ( e.location, path, att->value );
614 }
615 else if ( e.name == "include" )
616 {
617 Include* include = new Include ( project, this, &e );
618 if ( parseContext.ifData )
619 parseContext.ifData->data.includes.push_back ( include );
620 else
621 non_if_data.includes.push_back ( include );
622 subs_invalid = true;
623 }
624 else if ( e.name == "define" )
625 {
626 Define* pDefine = new Define ( project, this, e );
627 if ( parseContext.ifData )
628 parseContext.ifData->data.defines.push_back ( pDefine );
629 else
630 non_if_data.defines.push_back ( pDefine );
631 subs_invalid = true;
632 }
633 else if ( e.name == "invoke" )
634 {
635 if ( parseContext.ifData )
636 {
637 throw XMLInvalidBuildFileException (
638 e.location,
639 "<invoke> is not a valid sub-element of <if>" );
640 }
641 invocations.push_back ( new Invoke ( e, *this ) );
642 subs_invalid = false;
643 }
644 else if ( e.name == "dependency" )
645 {
646 if ( parseContext.ifData )
647 {
648 throw XMLInvalidBuildFileException (
649 e.location,
650 "<dependency> is not a valid sub-element of <if>" );
651 }
652 dependencies.push_back ( new Dependency ( e, *this ) );
653 subs_invalid = true;
654 }
655 else if ( e.name == "importlibrary" )
656 {
657 if ( parseContext.ifData )
658 {
659 throw XMLInvalidBuildFileException (
660 e.location,
661 "<importlibrary> is not a valid sub-element of <if>" );
662 }
663 if ( importLibrary )
664 {
665 throw XMLInvalidBuildFileException (
666 e.location,
667 "Only one <importlibrary> is valid per module" );
668 }
669 importLibrary = new ImportLibrary ( e, *this );
670 subs_invalid = true;
671 }
672 else if ( e.name == "if" )
673 {
674 parseContext.ifData = new If ( e, project, this );
675 if ( pOldIf )
676 pOldIf->data.ifs.push_back ( parseContext.ifData );
677 else
678 non_if_data.ifs.push_back ( parseContext.ifData );
679 subs_invalid = false;
680 }
681 else if ( e.name == "ifnot" )
682 {
683 parseContext.ifData = new If ( e, project, this, true );
684 if ( pOldIf )
685 pOldIf->data.ifs.push_back ( parseContext.ifData );
686 else
687 non_if_data.ifs.push_back ( parseContext.ifData );
688 subs_invalid = false;
689 }
690 else if ( e.name == "compilerflag" )
691 {
692 CompilerFlag* pCompilerFlag = new CompilerFlag ( project, this, e );
693 if ( parseContext.ifData )
694 parseContext.ifData->data.compilerFlags.push_back ( pCompilerFlag );
695 else
696 non_if_data.compilerFlags.push_back ( pCompilerFlag );
697 subs_invalid = true;
698 }
699 else if ( e.name == "linkerflag" )
700 {
701 linkerFlags.push_back ( new LinkerFlag ( project, this, e ) );
702 subs_invalid = true;
703 }
704 else if ( e.name == "linkerscript" )
705 {
706 if ( linkerScript )
707 {
708 throw XMLInvalidBuildFileException (
709 e.location,
710 "Only one <linkerscript> is valid per module" );
711 }
712 linkerScript = new LinkerScript ( project, this, e );
713 subs_invalid = true;
714 }
715 else if ( e.name == "component" )
716 {
717 stubbedComponents.push_back ( new StubbedComponent ( this, e ) );
718 subs_invalid = false;
719 }
720 else if ( e.name == "property" )
721 {
722 throw XMLInvalidBuildFileException (
723 e.location,
724 "<property> is not a valid sub-element of <module>" );
725 }
726 else if ( e.name == "bootstrap" )
727 {
728 bootstrap = new Bootstrap ( project, this, e );
729 subs_invalid = true;
730 }
731 else if ( e.name == "pch" )
732 {
733 if ( parseContext.ifData )
734 {
735 throw XMLInvalidBuildFileException (
736 e.location,
737 "<pch> is not a valid sub-element of <if>" );
738 }
739 if ( pch )
740 {
741 throw XMLInvalidBuildFileException (
742 e.location,
743 "Only one <pch> is valid per module" );
744 }
745 pch = new PchFile (
746 e, *this, File ( FixSeparator ( path + cSep + e.value ), false, "", true ) );
747 subs_invalid = true;
748 }
749 else if ( e.name == "compilationunit" )
750 {
751 if ( project.configuration.CompilationUnitsEnabled )
752 {
753 CompilationUnit* pCompilationUnit = new CompilationUnit ( &project, this, &e );
754 if ( parseContext.ifData )
755 parseContext.ifData->data.compilationUnits.push_back ( pCompilationUnit );
756 else
757 non_if_data.compilationUnits.push_back ( pCompilationUnit );
758 parseContext.compilationUnit = pCompilationUnit;
759 }
760 subs_invalid = false;
761 }
762 else if ( e.name == "autoregister" )
763 {
764 if ( autoRegister != NULL)
765 {
766 throw XMLInvalidBuildFileException (
767 e.location,
768 "there can be only one <%s> element for a module",
769 e.name.c_str() );
770 }
771 autoRegister = new AutoRegister ( project, this, e );
772 subs_invalid = true;
773 }
774 if ( subs_invalid && e.subElements.size() > 0 )
775 {
776 throw XMLInvalidBuildFileException (
777 e.location,
778 "<%s> cannot have sub-elements",
779 e.name.c_str() );
780 }
781 for ( size_t i = 0; i < e.subElements.size (); i++ )
782 ProcessXMLSubElement ( *e.subElements[i], subpath, parseContext );
783 parseContext.ifData = pOldIf;
784 parseContext.compilationUnit = pOldCompilationUnit;
785 }
786
787 ModuleType
788 Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
789 {
790 if ( attribute.value == "buildtool" )
791 return BuildTool;
792 if ( attribute.value == "staticlibrary" )
793 return StaticLibrary;
794 if ( attribute.value == "objectlibrary" )
795 return ObjectLibrary;
796 if ( attribute.value == "kernel" )
797 return Kernel;
798 if ( attribute.value == "kernelmodedll" )
799 return KernelModeDLL;
800 if ( attribute.value == "exportdriver" )
801 return ExportDriver;
802 if ( attribute.value == "kernelmodedriver" )
803 return KernelModeDriver;
804 if ( attribute.value == "nativedll" )
805 return NativeDLL;
806 if ( attribute.value == "nativecui" )
807 return NativeCUI;
808 if ( attribute.value == "win32dll" )
809 return Win32DLL;
810 if ( attribute.value == "win32cui" )
811 return Win32CUI;
812 if ( attribute.value == "win32gui" )
813 return Win32GUI;
814 if ( attribute.value == "win32scr" )
815 return Win32SCR;
816 if ( attribute.value == "bootloader" )
817 return BootLoader;
818 if ( attribute.value == "bootsector" )
819 return BootSector;
820 if ( attribute.value == "bootprogram" )
821 return BootProgram;
822 if ( attribute.value == "iso" )
823 return Iso;
824 if ( attribute.value == "liveiso" )
825 return LiveIso;
826 if ( attribute.value == "isoregtest" )
827 return IsoRegTest;
828 if ( attribute.value == "liveisoregtest" )
829 return LiveIsoRegTest;
830 if ( attribute.value == "test" )
831 return Test;
832 if ( attribute.value == "rpcserver" )
833 return RpcServer;
834 if ( attribute.value == "rpcclient" )
835 return RpcClient;
836 if ( attribute.value == "alias" )
837 return Alias;
838 if ( attribute.value == "idlheader" )
839 return IdlHeader;
840 throw InvalidAttributeValueException ( location,
841 attribute.name,
842 attribute.value );
843 }
844
845 string
846 Module::GetDefaultModuleExtension () const
847 {
848 switch (type)
849 {
850 case BuildTool:
851 return ExePostfix;
852 case StaticLibrary:
853 return ".a";
854 case ObjectLibrary:
855 return ".o";
856 case Kernel:
857 case NativeCUI:
858 case Win32CUI:
859 case Win32GUI:
860 return ".exe";
861 case Win32SCR:
862 return ".scr";
863
864 case KernelModeDLL:
865 case NativeDLL:
866 case Win32DLL:
867 return ".dll";
868 case KernelModeDriver:
869 case BootLoader:
870 case ExportDriver:
871 return ".sys";
872 case BootSector:
873 return ".o";
874 case Iso:
875 case LiveIso:
876 case IsoRegTest:
877 case LiveIsoRegTest:
878 return ".iso";
879 case Test:
880 return ".exe";
881 case RpcServer:
882 return ".o";
883 case RpcClient:
884 return ".o";
885 case Alias:
886 case BootProgram:
887 case IdlHeader:
888 return "";
889 }
890 throw InvalidOperationException ( __FILE__,
891 __LINE__ );
892 }
893
894 string
895 Module::GetDefaultModuleEntrypoint () const
896 {
897 switch ( type )
898 {
899 case Kernel:
900 return "NtProcessStartup";
901 case KernelModeDLL:
902 case KernelModeDriver:
903 case ExportDriver:
904 return "DriverEntry@8";
905 case NativeDLL:
906 return "DllMainCRTStartup@12";
907 case NativeCUI:
908 return "NtProcessStartup@4";
909 case Win32DLL:
910 return "DllMain@12";
911 case Win32CUI:
912 case Test:
913 if ( isUnicode )
914 return "wmainCRTStartup";
915 else
916 return "mainCRTStartup";
917 case Win32SCR:
918 case Win32GUI:
919 if ( isUnicode )
920 return "wWinMainCRTStartup";
921 else
922 return "WinMainCRTStartup";
923 case BuildTool:
924 case StaticLibrary:
925 case ObjectLibrary:
926 case BootLoader:
927 case BootSector:
928 case Iso:
929 case LiveIso:
930 case IsoRegTest:
931 case LiveIsoRegTest:
932 case RpcServer:
933 case RpcClient:
934 case Alias:
935 case BootProgram:
936 case IdlHeader:
937 return "";
938 }
939 throw InvalidOperationException ( __FILE__,
940 __LINE__ );
941 }
942
943 string
944 Module::GetDefaultModuleBaseaddress () const
945 {
946 switch ( type )
947 {
948 case Kernel:
949 return "0x80000000";
950 case Win32DLL:
951 return "0x10000000";
952 case NativeDLL:
953 case NativeCUI:
954 case Win32CUI:
955 case Test:
956 return "0x00400000";
957 case Win32SCR:
958 case Win32GUI:
959 return "0x00400000";
960 case KernelModeDLL:
961 case KernelModeDriver:
962 case ExportDriver:
963 return "0x00010000";
964 case BuildTool:
965 case StaticLibrary:
966 case ObjectLibrary:
967 case BootLoader:
968 case BootSector:
969 case Iso:
970 case LiveIso:
971 case IsoRegTest:
972 case LiveIsoRegTest:
973 case RpcServer:
974 case RpcClient:
975 case Alias:
976 case BootProgram:
977 case IdlHeader:
978 return "";
979 }
980 throw InvalidOperationException ( __FILE__,
981 __LINE__ );
982 }
983
984 bool
985 Module::HasImportLibrary () const
986 {
987 return importLibrary != NULL && type != StaticLibrary;
988 }
989
990 bool
991 Module::IsDLL () const
992 {
993 switch ( type )
994 {
995 case Kernel:
996 case KernelModeDLL:
997 case ExportDriver:
998 case NativeDLL:
999 case Win32DLL:
1000 return true;
1001 case KernelModeDriver:
1002 case NativeCUI:
1003 case Win32CUI:
1004 case Test:
1005 case Win32SCR:
1006 case Win32GUI:
1007 case BuildTool:
1008 case StaticLibrary:
1009 case ObjectLibrary:
1010 case BootLoader:
1011 case BootSector:
1012 case BootProgram:
1013 case Iso:
1014 case LiveIso:
1015 case IsoRegTest:
1016 case LiveIsoRegTest:
1017 case RpcServer:
1018 case RpcClient:
1019 case Alias:
1020 case IdlHeader:
1021 return false;
1022 }
1023 throw InvalidOperationException ( __FILE__,
1024 __LINE__ );
1025 }
1026
1027 bool
1028 Module::GenerateInOutputTree () const
1029 {
1030 switch ( type )
1031 {
1032 case Kernel:
1033 case KernelModeDLL:
1034 case ExportDriver:
1035 case NativeDLL:
1036 case Win32DLL:
1037 case KernelModeDriver:
1038 case NativeCUI:
1039 case Win32CUI:
1040 case Test:
1041 case Win32SCR:
1042 case Win32GUI:
1043 case BuildTool:
1044 case BootLoader:
1045 case BootSector:
1046 case BootProgram:
1047 case Iso:
1048 case LiveIso:
1049 case IsoRegTest:
1050 case LiveIsoRegTest:
1051 return true;
1052 case StaticLibrary:
1053 case ObjectLibrary:
1054 case RpcServer:
1055 case RpcClient:
1056 case Alias:
1057 case IdlHeader:
1058 return false;
1059 }
1060 throw InvalidOperationException ( __FILE__,
1061 __LINE__ );
1062 }
1063
1064 string
1065 Module::GetTargetName () const
1066 {
1067 return name + extension;
1068 }
1069
1070 string
1071 Module::GetDependencyPath () const
1072 {
1073 if ( HasImportLibrary () )
1074 return ReplaceExtension ( GetPathWithPrefix ( "lib" ), ".a" );
1075 else
1076 return GetPath();
1077 }
1078
1079 string
1080 Module::GetBasePath () const
1081 {
1082 return path;
1083 }
1084
1085 string
1086 Module::GetPath () const
1087 {
1088 if ( path.length() > 0 )
1089 return path + cSep + GetTargetName ();
1090 else
1091 return GetTargetName ();
1092 }
1093
1094 string
1095 Module::GetPathWithPrefix ( const string& prefix ) const
1096 {
1097 return path + cSep + prefix + GetTargetName ();
1098 }
1099
1100 string
1101 Module::GetPathToBaseDir () const
1102 {
1103 string temp_path = path;
1104 string result = "..\\";
1105 while(temp_path.find ('\\') != string::npos)
1106 {
1107 temp_path.erase (0, temp_path.find('\\')+1);
1108 result += "..\\";
1109 }
1110 return result;
1111 }
1112
1113 string
1114 Module::GetInvocationTarget ( const int index ) const
1115 {
1116 return ssprintf ( "%s_invoke_%d",
1117 name.c_str (),
1118 index );
1119 }
1120
1121 string
1122 Module::GetEntryPoint(bool leadingUnderscore) const
1123 {
1124 string result = "";
1125 if (entrypoint == "0" || entrypoint == "0x0")
1126 return "0";
1127 if (leadingUnderscore)
1128 result = "_";
1129
1130 result += entrypoint;
1131 return result;
1132 }
1133
1134 bool
1135 Module::HasFileWithExtension (
1136 const IfableData& data,
1137 const std::string& extension ) const
1138 {
1139 size_t i;
1140 for ( i = 0; i < data.compilationUnits.size (); i++ )
1141 {
1142 CompilationUnit* compilationUnit = data.compilationUnits[i];
1143 if ( compilationUnit->HasFileWithExtension ( extension ) )
1144 return true;
1145 }
1146 for ( i = 0; i < data.ifs.size (); i++ )
1147 {
1148 if ( HasFileWithExtension ( data.ifs[i]->data, extension ) )
1149 return true;
1150 }
1151 return false;
1152 }
1153
1154 void
1155 Module::InvokeModule () const
1156 {
1157 for ( size_t i = 0; i < invocations.size (); i++ )
1158 {
1159 Invoke& invoke = *invocations[i];
1160 string command = FixSeparatorForSystemCommand(invoke.invokeModule->GetPath ()) + " " + invoke.GetParameters ();
1161 printf ( "Executing '%s'\n\n", command.c_str () );
1162 int exitcode = system ( command.c_str () );
1163 if ( exitcode != 0 )
1164 throw InvocationFailedException ( command,
1165 exitcode );
1166 }
1167 }
1168
1169
1170 File::File ( const string& _name, bool _first,
1171 std::string _switches,
1172 bool _isPreCompiledHeader )
1173 : name(_name),
1174 first(_first),
1175 switches(_switches),
1176 isPreCompiledHeader(_isPreCompiledHeader)
1177 {
1178 }
1179
1180 void
1181 File::ProcessXML()
1182 {
1183 }
1184
1185
1186 Library::Library ( const XMLElement& _node,
1187 const Module& _module,
1188 const string& _name )
1189 : node(&_node),
1190 module(_module),
1191 name(_name),
1192 importedModule(_module.project.LocateModule(_name))
1193 {
1194 if ( module.name == name )
1195 {
1196 throw XMLInvalidBuildFileException (
1197 node->location,
1198 "module '%s' cannot link against itself",
1199 name.c_str() );
1200 }
1201 if ( !importedModule )
1202 {
1203 throw XMLInvalidBuildFileException (
1204 node->location,
1205 "module '%s' trying to import non-existant module '%s'",
1206 module.name.c_str(),
1207 name.c_str() );
1208 }
1209 }
1210
1211 Library::Library ( const Module& _module,
1212 const string& _name )
1213 : node(NULL),
1214 module(_module),
1215 name(_name),
1216 importedModule(_module.project.LocateModule(_name))
1217 {
1218 }
1219
1220 void
1221 Library::ProcessXML()
1222 {
1223 if ( node && !module.project.LocateModule ( name ) )
1224 {
1225 throw XMLInvalidBuildFileException (
1226 node->location,
1227 "module '%s' is trying to link against non-existant module '%s'",
1228 module.name.c_str(),
1229 name.c_str() );
1230 }
1231 }
1232
1233
1234 Invoke::Invoke ( const XMLElement& _node,
1235 const Module& _module )
1236 : node (_node),
1237 module (_module)
1238 {
1239 }
1240
1241 void
1242 Invoke::ProcessXML()
1243 {
1244 const XMLAttribute* att = node.GetAttribute ( "module", false );
1245 if (att == NULL)
1246 invokeModule = &module;
1247 else
1248 {
1249 invokeModule = module.project.LocateModule ( att->value );
1250 if ( invokeModule == NULL )
1251 {
1252 throw XMLInvalidBuildFileException (
1253 node.location,
1254 "module '%s' is trying to invoke non-existant module '%s'",
1255 module.name.c_str(),
1256 att->value.c_str() );
1257 }
1258 }
1259
1260 for ( size_t i = 0; i < node.subElements.size (); i++ )
1261 ProcessXMLSubElement ( *node.subElements[i] );
1262 }
1263
1264 void
1265 Invoke::ProcessXMLSubElement ( const XMLElement& e )
1266 {
1267 bool subs_invalid = false;
1268 if ( e.name == "input" )
1269 {
1270 for ( size_t i = 0; i < e.subElements.size (); i++ )
1271 ProcessXMLSubElementInput ( *e.subElements[i] );
1272 }
1273 else if ( e.name == "output" )
1274 {
1275 for ( size_t i = 0; i < e.subElements.size (); i++ )
1276 ProcessXMLSubElementOutput ( *e.subElements[i] );
1277 }
1278 if ( subs_invalid && e.subElements.size() > 0 )
1279 {
1280 throw XMLInvalidBuildFileException (
1281 e.location,
1282 "<%s> cannot have sub-elements",
1283 e.name.c_str() );
1284 }
1285 }
1286
1287 void
1288 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
1289 {
1290 bool subs_invalid = false;
1291 if ( e.name == "inputfile" && e.value.size () > 0 )
1292 {
1293 input.push_back ( new InvokeFile (
1294 e, FixSeparator ( module.path + cSep + e.value ) ) );
1295 subs_invalid = true;
1296 }
1297 if ( subs_invalid && e.subElements.size() > 0 )
1298 {
1299 throw XMLInvalidBuildFileException (
1300 e.location,
1301 "<%s> cannot have sub-elements",
1302 e.name.c_str() );
1303 }
1304 }
1305
1306 void
1307 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
1308 {
1309 bool subs_invalid = false;
1310 if ( e.name == "outputfile" && e.value.size () > 0 )
1311 {
1312 output.push_back ( new InvokeFile (
1313 e, FixSeparator ( module.path + cSep + e.value ) ) );
1314 subs_invalid = true;
1315 }
1316 if ( subs_invalid && e.subElements.size() > 0 )
1317 {
1318 throw XMLInvalidBuildFileException (
1319 e.location,
1320 "<%s> cannot have sub-elements",
1321 e.name.c_str() );
1322 }
1323 }
1324
1325 void
1326 Invoke::GetTargets ( string_list& targets ) const
1327 {
1328 for ( size_t i = 0; i < output.size (); i++ )
1329 {
1330 InvokeFile& file = *output[i];
1331 targets.push_back ( NormalizeFilename ( file.name ) );
1332 }
1333 }
1334
1335 string
1336 Invoke::GetParameters () const
1337 {
1338 string parameters ( "" );
1339 size_t i;
1340 for ( i = 0; i < output.size (); i++ )
1341 {
1342 if ( parameters.length () > 0)
1343 parameters += " ";
1344 InvokeFile& invokeFile = *output[i];
1345 if ( invokeFile.switches.length () > 0 )
1346 {
1347 parameters += invokeFile.switches + " ";
1348 }
1349 parameters += invokeFile.name;
1350 }
1351
1352 for ( i = 0; i < input.size (); i++ )
1353 {
1354 if ( parameters.length () > 0 )
1355 parameters += " ";
1356 InvokeFile& invokeFile = *input[i];
1357 if ( invokeFile.switches.length () > 0 )
1358 {
1359 parameters += invokeFile.switches;
1360 parameters += " ";
1361 }
1362 parameters += invokeFile.name ;
1363 }
1364
1365 return parameters;
1366 }
1367
1368
1369 InvokeFile::InvokeFile ( const XMLElement& _node,
1370 const string& _name )
1371 : node (_node),
1372 name (_name)
1373 {
1374 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
1375 if (att != NULL)
1376 switches = att->value;
1377 else
1378 switches = "";
1379 }
1380
1381 void
1382 InvokeFile::ProcessXML()
1383 {
1384 }
1385
1386
1387 Dependency::Dependency ( const XMLElement& _node,
1388 const Module& _module )
1389 : node (_node),
1390 module (_module),
1391 dependencyModule (NULL)
1392 {
1393 }
1394
1395 void
1396 Dependency::ProcessXML()
1397 {
1398 dependencyModule = module.project.LocateModule ( node.value );
1399 if ( dependencyModule == NULL )
1400 {
1401 throw XMLInvalidBuildFileException (
1402 node.location,
1403 "module '%s' depend on non-existant module '%s'",
1404 module.name.c_str(),
1405 node.value.c_str() );
1406 }
1407 }
1408
1409
1410 ImportLibrary::ImportLibrary ( const XMLElement& _node,
1411 const Module& _module )
1412 : node (_node),
1413 module (_module)
1414 {
1415 const XMLAttribute* att = _node.GetAttribute ( "basename", false );
1416 if (att != NULL)
1417 basename = att->value;
1418 else
1419 basename = module.name;
1420
1421 att = _node.GetAttribute ( "dllname", false );
1422 if (att != NULL)
1423 dllname = att->value;
1424 else
1425 {
1426 if ( _module.type == StaticLibrary )
1427 {
1428 throw XMLInvalidBuildFileException (
1429 node.location,
1430 "<importlibrary> dllname attribute required." );
1431 }
1432
1433 dllname = "";
1434 }
1435
1436 att = _node.GetAttribute ( "definition", true );
1437 assert (att);
1438 definition = FixSeparator(att->value);
1439 }
1440
1441
1442 If::If ( const XMLElement& node_,
1443 const Project& project_,
1444 const Module* module_,
1445 const bool negated_ )
1446 : node(node_), project(project_), module(module_), negated(negated_)
1447 {
1448 const XMLAttribute* att;
1449
1450 att = node.GetAttribute ( "property", true );
1451 assert(att);
1452 property = att->value;
1453
1454 att = node.GetAttribute ( "value", true );
1455 assert(att);
1456 value = att->value;
1457 }
1458
1459 If::~If ()
1460 {
1461 }
1462
1463 void
1464 If::ProcessXML()
1465 {
1466
1467 }
1468
1469
1470 Property::Property ( const XMLElement& node_,
1471 const Project& project_,
1472 const Module* module_ )
1473 : node(node_), project(project_), module(module_)
1474 {
1475 const XMLAttribute* att;
1476
1477 att = node.GetAttribute ( "name", true );
1478 assert(att);
1479 name = att->value;
1480
1481 att = node.GetAttribute ( "value", true );
1482 assert(att);
1483 value = att->value;
1484 }
1485
1486 void
1487 Property::ProcessXML()
1488 {
1489 }
1490
1491
1492 PchFile::PchFile (
1493 const XMLElement& node_,
1494 const Module& module_,
1495 const File file_ )
1496 : node(node_), module(module_), file(file_)
1497 {
1498 }
1499
1500 void
1501 PchFile::ProcessXML()
1502 {
1503 }
1504
1505
1506 AutoRegister::AutoRegister ( const Project& project_,
1507 const Module* module_,
1508 const XMLElement& node_ )
1509 : project(project_),
1510 module(module_),
1511 node(node_)
1512 {
1513 Initialize();
1514 }
1515
1516 AutoRegister::~AutoRegister ()
1517 {
1518 }
1519
1520 bool
1521 AutoRegister::IsSupportedModuleType ( ModuleType type )
1522 {
1523 switch ( type )
1524 {
1525 case Win32DLL:
1526 return true;
1527 case Kernel:
1528 case KernelModeDLL:
1529 case ExportDriver:
1530 case NativeDLL:
1531 case NativeCUI:
1532 case Win32CUI:
1533 case Win32GUI:
1534 case Win32SCR:
1535 case KernelModeDriver:
1536 case BootSector:
1537 case BootLoader:
1538 case BootProgram:
1539 case BuildTool:
1540 case StaticLibrary:
1541 case ObjectLibrary:
1542 case Iso:
1543 case LiveIso:
1544 case IsoRegTest:
1545 case LiveIsoRegTest:
1546 case Test:
1547 case RpcServer:
1548 case RpcClient:
1549 case Alias:
1550 case IdlHeader:
1551 return false;
1552 }
1553 throw InvalidOperationException ( __FILE__,
1554 __LINE__ );
1555 }
1556
1557 AutoRegisterType
1558 AutoRegister::GetAutoRegisterType( string type )
1559 {
1560 if ( type == "DllRegisterServer" )
1561 return DllRegisterServer;
1562 if ( type == "DllInstall" )
1563 return DllInstall;
1564 if ( type == "Both" )
1565 return Both;
1566 throw XMLInvalidBuildFileException (
1567 node.location,
1568 "<autoregister> type attribute must be DllRegisterServer, DllInstall or Both." );
1569 }
1570
1571 void
1572 AutoRegister::Initialize ()
1573 {
1574 if ( !IsSupportedModuleType ( module->type ) )
1575 {
1576 throw XMLInvalidBuildFileException (
1577 node.location,
1578 "<autoregister> is not applicable for this module type." );
1579 }
1580
1581 const XMLAttribute* att = node.GetAttribute ( "infsection", true );
1582 infSection = att->value;
1583
1584 att = node.GetAttribute ( "type", true );
1585 type = GetAutoRegisterType ( att->value );
1586 }
1587
1588 void
1589 AutoRegister::ProcessXML()
1590 {
1591 }