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