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