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