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