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