Didnt mean to commit this in the last one.
[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 == "kernelmodedriver" )
735 return KernelModeDriver;
736 if ( attribute.value == "nativedll" )
737 return NativeDLL;
738 if ( attribute.value == "nativecui" )
739 return NativeCUI;
740 if ( attribute.value == "win32dll" )
741 return Win32DLL;
742 if ( attribute.value == "win32cui" )
743 return Win32CUI;
744 if ( attribute.value == "win32gui" )
745 return Win32GUI;
746 if ( attribute.value == "bootloader" )
747 return BootLoader;
748 if ( attribute.value == "bootsector" )
749 return BootSector;
750 if ( attribute.value == "bootprogram" )
751 return BootProgram;
752 if ( attribute.value == "iso" )
753 return Iso;
754 if ( attribute.value == "liveiso" )
755 return LiveIso;
756 if ( attribute.value == "test" )
757 return Test;
758 if ( attribute.value == "rpcserver" )
759 return RpcServer;
760 if ( attribute.value == "rpcclient" )
761 return RpcClient;
762 if ( attribute.value == "alias" )
763 return Alias;
764 throw InvalidAttributeValueException ( location,
765 attribute.name,
766 attribute.value );
767 }
768
769 string
770 Module::GetDefaultModuleExtension () const
771 {
772 switch (type)
773 {
774 case BuildTool:
775 return ExePostfix;
776 case StaticLibrary:
777 return ".a";
778 case ObjectLibrary:
779 return ".o";
780 case Kernel:
781 case NativeCUI:
782 case Win32CUI:
783 case Win32GUI:
784 return ".exe";
785 case KernelModeDLL:
786 case NativeDLL:
787 case Win32DLL:
788 return ".dll";
789 case KernelModeDriver:
790 case BootLoader:
791 return ".sys";
792 case BootSector:
793 return ".o";
794 case Iso:
795 case LiveIso:
796 return ".iso";
797 case Test:
798 return ".exe";
799 case RpcServer:
800 return ".o";
801 case RpcClient:
802 return ".o";
803 case Alias:
804 return "";
805 case BootProgram:
806 return "";
807 }
808 throw InvalidOperationException ( __FILE__,
809 __LINE__ );
810 }
811
812 string
813 Module::GetDefaultModuleEntrypoint () const
814 {
815 switch ( type )
816 {
817 case Kernel:
818 return "_NtProcessStartup";
819 case KernelModeDLL:
820 return "_DriverEntry@8";
821 case NativeDLL:
822 return "_DllMainCRTStartup@12";
823 case NativeCUI:
824 return "_NtProcessStartup@4";
825 case Win32DLL:
826 return "_DllMain@12";
827 case Win32CUI:
828 case Test:
829 if ( isUnicode )
830 return "_wmainCRTStartup";
831 else
832 return "_mainCRTStartup";
833 case Win32GUI:
834 if ( isUnicode )
835 return "_wWinMainCRTStartup";
836 else
837 return "_WinMainCRTStartup";
838 case KernelModeDriver:
839 return "_DriverEntry@8";
840 case BuildTool:
841 case StaticLibrary:
842 case ObjectLibrary:
843 case BootLoader:
844 case BootSector:
845 case Iso:
846 case LiveIso:
847 case RpcServer:
848 case RpcClient:
849 case Alias:
850 case BootProgram:
851 return "";
852 }
853 throw InvalidOperationException ( __FILE__,
854 __LINE__ );
855 }
856
857 string
858 Module::GetDefaultModuleBaseaddress () const
859 {
860 switch ( type )
861 {
862 case Kernel:
863 return "0x80000000";
864 case Win32DLL:
865 return "0x10000000";
866 case NativeDLL:
867 case NativeCUI:
868 case Win32CUI:
869 case Test:
870 return "0x00400000";
871 case Win32GUI:
872 return "0x00400000";
873 case KernelModeDLL:
874 case KernelModeDriver:
875 return "0x00010000";
876 case BuildTool:
877 case StaticLibrary:
878 case ObjectLibrary:
879 case BootLoader:
880 case BootSector:
881 case Iso:
882 case LiveIso:
883 case RpcServer:
884 case RpcClient:
885 case Alias:
886 case BootProgram:
887 return "";
888 }
889 throw InvalidOperationException ( __FILE__,
890 __LINE__ );
891 }
892
893 bool
894 Module::HasImportLibrary () const
895 {
896 return importLibrary != NULL;
897 }
898
899 bool
900 Module::IsDLL () const
901 {
902 switch ( type )
903 {
904 case Kernel:
905 case KernelModeDLL:
906 case NativeDLL:
907 case Win32DLL:
908 case KernelModeDriver:
909 return true;
910 case NativeCUI:
911 case Win32CUI:
912 case Test:
913 case Win32GUI:
914 case BuildTool:
915 case StaticLibrary:
916 case ObjectLibrary:
917 case BootLoader:
918 case BootSector:
919 case BootProgram:
920 case Iso:
921 case LiveIso:
922 case RpcServer:
923 case RpcClient:
924 case Alias:
925 return false;
926 }
927 throw InvalidOperationException ( __FILE__,
928 __LINE__ );
929 }
930
931 bool
932 Module::GenerateInOutputTree () const
933 {
934 switch ( type )
935 {
936 case Kernel:
937 case KernelModeDLL:
938 case NativeDLL:
939 case Win32DLL:
940 case KernelModeDriver:
941 case NativeCUI:
942 case Win32CUI:
943 case Test:
944 case Win32GUI:
945 case BuildTool:
946 case BootLoader:
947 case BootSector:
948 case BootProgram:
949 case Iso:
950 case LiveIso:
951 return true;
952 case StaticLibrary:
953 case ObjectLibrary:
954 case RpcServer:
955 case RpcClient:
956 case Alias:
957 return false;
958 }
959 throw InvalidOperationException ( __FILE__,
960 __LINE__ );
961 }
962
963 string
964 Module::GetTargetName () const
965 {
966 return name + extension;
967 }
968
969 string
970 Module::GetDependencyPath () const
971 {
972 if ( HasImportLibrary () )
973 return ReplaceExtension ( GetPathWithPrefix ( "lib" ), ".a" );
974 else
975 return GetPath();
976 }
977
978 string
979 Module::GetBasePath () const
980 {
981 return path;
982 }
983
984 string
985 Module::GetPath () const
986 {
987 if ( path.length() > 0 )
988 return path + cSep + GetTargetName ();
989 else
990 return GetTargetName ();
991 }
992
993 string
994 Module::GetPathWithPrefix ( const string& prefix ) const
995 {
996 return path + cSep + prefix + GetTargetName ();
997 }
998
999 string
1000 Module::GetPathToBaseDir () const
1001 {
1002 string temp_path = path;
1003 string result = "..\\";
1004 while(temp_path.find ('\\') != string::npos)
1005 {
1006 temp_path.erase (0, temp_path.find('\\')+1);
1007 result += "..\\";
1008 }
1009 return result;
1010 }
1011
1012 string
1013 Module::GetInvocationTarget ( const int index ) const
1014 {
1015 return ssprintf ( "%s_invoke_%d",
1016 name.c_str (),
1017 index );
1018 }
1019
1020 bool
1021 Module::HasFileWithExtension (
1022 const IfableData& data,
1023 const std::string& extension ) const
1024 {
1025 size_t i;
1026 for ( i = 0; i < data.compilationUnits.size (); i++ )
1027 {
1028 CompilationUnit* compilationUnit = data.compilationUnits[i];
1029 if ( compilationUnit->HasFileWithExtension ( extension ) )
1030 return true;
1031 }
1032 for ( i = 0; i < data.ifs.size (); i++ )
1033 {
1034 if ( HasFileWithExtension ( data.ifs[i]->data, extension ) )
1035 return true;
1036 }
1037 return false;
1038 }
1039
1040 void
1041 Module::InvokeModule () const
1042 {
1043 for ( size_t i = 0; i < invocations.size (); i++ )
1044 {
1045 Invoke& invoke = *invocations[i];
1046 string command = FixSeparatorForSystemCommand(invoke.invokeModule->GetPath ()) + " " + invoke.GetParameters ();
1047 printf ( "Executing '%s'\n\n", command.c_str () );
1048 int exitcode = system ( command.c_str () );
1049 if ( exitcode != 0 )
1050 throw InvocationFailedException ( command,
1051 exitcode );
1052 }
1053 }
1054
1055
1056 File::File ( const string& _name, bool _first,
1057 std::string _switches,
1058 bool _isPreCompiledHeader )
1059 : name(_name),
1060 first(_first),
1061 switches(_switches),
1062 isPreCompiledHeader(_isPreCompiledHeader)
1063 {
1064 }
1065
1066 void
1067 File::ProcessXML()
1068 {
1069 }
1070
1071
1072 Library::Library ( const XMLElement& _node,
1073 const Module& _module,
1074 const string& _name )
1075 : node(_node),
1076 module(_module),
1077 name(_name),
1078 importedModule(_module.project.LocateModule(_name))
1079 {
1080 if ( module.name == name )
1081 {
1082 throw XMLInvalidBuildFileException (
1083 node.location,
1084 "module '%s' cannot link against itself",
1085 name.c_str() );
1086 }
1087 if ( !importedModule )
1088 {
1089 throw XMLInvalidBuildFileException (
1090 node.location,
1091 "module '%s' trying to import non-existant module '%s'",
1092 module.name.c_str(),
1093 name.c_str() );
1094 }
1095 }
1096
1097 void
1098 Library::ProcessXML()
1099 {
1100 if ( !module.project.LocateModule ( name ) )
1101 {
1102 throw XMLInvalidBuildFileException (
1103 node.location,
1104 "module '%s' is trying to link against non-existant module '%s'",
1105 module.name.c_str(),
1106 name.c_str() );
1107 }
1108 }
1109
1110
1111 Invoke::Invoke ( const XMLElement& _node,
1112 const Module& _module )
1113 : node (_node),
1114 module (_module)
1115 {
1116 }
1117
1118 void
1119 Invoke::ProcessXML()
1120 {
1121 const XMLAttribute* att = node.GetAttribute ( "module", false );
1122 if (att == NULL)
1123 invokeModule = &module;
1124 else
1125 {
1126 invokeModule = module.project.LocateModule ( att->value );
1127 if ( invokeModule == NULL )
1128 {
1129 throw XMLInvalidBuildFileException (
1130 node.location,
1131 "module '%s' is trying to invoke non-existant module '%s'",
1132 module.name.c_str(),
1133 att->value.c_str() );
1134 }
1135 }
1136
1137 for ( size_t i = 0; i < node.subElements.size (); i++ )
1138 ProcessXMLSubElement ( *node.subElements[i] );
1139 }
1140
1141 void
1142 Invoke::ProcessXMLSubElement ( const XMLElement& e )
1143 {
1144 bool subs_invalid = false;
1145 if ( e.name == "input" )
1146 {
1147 for ( size_t i = 0; i < e.subElements.size (); i++ )
1148 ProcessXMLSubElementInput ( *e.subElements[i] );
1149 }
1150 else if ( e.name == "output" )
1151 {
1152 for ( size_t i = 0; i < e.subElements.size (); i++ )
1153 ProcessXMLSubElementOutput ( *e.subElements[i] );
1154 }
1155 if ( subs_invalid && e.subElements.size() > 0 )
1156 {
1157 throw XMLInvalidBuildFileException (
1158 e.location,
1159 "<%s> cannot have sub-elements",
1160 e.name.c_str() );
1161 }
1162 }
1163
1164 void
1165 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
1166 {
1167 bool subs_invalid = false;
1168 if ( e.name == "inputfile" && e.value.size () > 0 )
1169 {
1170 input.push_back ( new InvokeFile (
1171 e, FixSeparator ( module.path + cSep + e.value ) ) );
1172 subs_invalid = true;
1173 }
1174 if ( subs_invalid && e.subElements.size() > 0 )
1175 {
1176 throw XMLInvalidBuildFileException (
1177 e.location,
1178 "<%s> cannot have sub-elements",
1179 e.name.c_str() );
1180 }
1181 }
1182
1183 void
1184 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
1185 {
1186 bool subs_invalid = false;
1187 if ( e.name == "outputfile" && e.value.size () > 0 )
1188 {
1189 output.push_back ( new InvokeFile (
1190 e, FixSeparator ( module.path + cSep + e.value ) ) );
1191 subs_invalid = true;
1192 }
1193 if ( subs_invalid && e.subElements.size() > 0 )
1194 {
1195 throw XMLInvalidBuildFileException (
1196 e.location,
1197 "<%s> cannot have sub-elements",
1198 e.name.c_str() );
1199 }
1200 }
1201
1202 void
1203 Invoke::GetTargets ( string_list& targets ) const
1204 {
1205 for ( size_t i = 0; i < output.size (); i++ )
1206 {
1207 InvokeFile& file = *output[i];
1208 targets.push_back ( NormalizeFilename ( file.name ) );
1209 }
1210 }
1211
1212 string
1213 Invoke::GetParameters () const
1214 {
1215 string parameters ( "" );
1216 size_t i;
1217 for ( i = 0; i < output.size (); i++ )
1218 {
1219 if ( parameters.length () > 0)
1220 parameters += " ";
1221 InvokeFile& invokeFile = *output[i];
1222 if ( invokeFile.switches.length () > 0 )
1223 {
1224 parameters += invokeFile.switches + " ";
1225 }
1226 parameters += invokeFile.name;
1227 }
1228
1229 for ( i = 0; i < input.size (); i++ )
1230 {
1231 if ( parameters.length () > 0 )
1232 parameters += " ";
1233 InvokeFile& invokeFile = *input[i];
1234 if ( invokeFile.switches.length () > 0 )
1235 {
1236 parameters += invokeFile.switches;
1237 parameters += " ";
1238 }
1239 parameters += invokeFile.name ;
1240 }
1241
1242 return parameters;
1243 }
1244
1245
1246 InvokeFile::InvokeFile ( const XMLElement& _node,
1247 const string& _name )
1248 : node (_node),
1249 name (_name)
1250 {
1251 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
1252 if (att != NULL)
1253 switches = att->value;
1254 else
1255 switches = "";
1256 }
1257
1258 void
1259 InvokeFile::ProcessXML()
1260 {
1261 }
1262
1263
1264 Dependency::Dependency ( const XMLElement& _node,
1265 const Module& _module )
1266 : node (_node),
1267 module (_module),
1268 dependencyModule (NULL)
1269 {
1270 }
1271
1272 void
1273 Dependency::ProcessXML()
1274 {
1275 dependencyModule = module.project.LocateModule ( node.value );
1276 if ( dependencyModule == NULL )
1277 {
1278 throw XMLInvalidBuildFileException (
1279 node.location,
1280 "module '%s' depend on non-existant module '%s'",
1281 module.name.c_str(),
1282 node.value.c_str() );
1283 }
1284 }
1285
1286
1287 ImportLibrary::ImportLibrary ( const XMLElement& _node,
1288 const Module& _module )
1289 : node (_node),
1290 module (_module)
1291 {
1292 const XMLAttribute* att = _node.GetAttribute ( "basename", false );
1293 if (att != NULL)
1294 basename = att->value;
1295 else
1296 basename = module.name;
1297
1298 att = _node.GetAttribute ( "definition", true );
1299 assert (att);
1300 definition = FixSeparator(att->value);
1301 }
1302
1303
1304 If::If ( const XMLElement& node_,
1305 const Project& project_,
1306 const Module* module_,
1307 const bool negated_ )
1308 : node(node_), project(project_), module(module_), negated(negated_)
1309 {
1310 const XMLAttribute* att;
1311
1312 att = node.GetAttribute ( "property", true );
1313 assert(att);
1314 property = att->value;
1315
1316 att = node.GetAttribute ( "value", true );
1317 assert(att);
1318 value = att->value;
1319 }
1320
1321 If::~If ()
1322 {
1323 }
1324
1325 void
1326 If::ProcessXML()
1327 {
1328
1329 }
1330
1331
1332 Property::Property ( const XMLElement& node_,
1333 const Project& project_,
1334 const Module* module_ )
1335 : node(node_), project(project_), module(module_)
1336 {
1337 const XMLAttribute* att;
1338
1339 att = node.GetAttribute ( "name", true );
1340 assert(att);
1341 name = att->value;
1342
1343 att = node.GetAttribute ( "value", true );
1344 assert(att);
1345 value = att->value;
1346 }
1347
1348 void
1349 Property::ProcessXML()
1350 {
1351 }
1352
1353
1354 PchFile::PchFile (
1355 const XMLElement& node_,
1356 const Module& module_,
1357 const File file_ )
1358 : node(node_), module(module_), file(file_)
1359 {
1360 }
1361
1362 void
1363 PchFile::ProcessXML()
1364 {
1365 }
1366
1367
1368 AutoRegister::AutoRegister ( const Project& project_,
1369 const Module* module_,
1370 const XMLElement& node_ )
1371 : project(project_),
1372 module(module_),
1373 node(node_)
1374 {
1375 Initialize();
1376 }
1377
1378 AutoRegister::~AutoRegister ()
1379 {
1380 }
1381
1382 bool
1383 AutoRegister::IsSupportedModuleType ( ModuleType type )
1384 {
1385 switch ( type )
1386 {
1387 case Win32DLL:
1388 return true;
1389 case Kernel:
1390 case KernelModeDLL:
1391 case NativeDLL:
1392 case NativeCUI:
1393 case Win32CUI:
1394 case Win32GUI:
1395 case KernelModeDriver:
1396 case BootSector:
1397 case BootLoader:
1398 case BootProgram:
1399 case BuildTool:
1400 case StaticLibrary:
1401 case ObjectLibrary:
1402 case Iso:
1403 case LiveIso:
1404 case Test:
1405 case RpcServer:
1406 case RpcClient:
1407 case Alias:
1408 return false;
1409 }
1410 throw InvalidOperationException ( __FILE__,
1411 __LINE__ );
1412 }
1413
1414 AutoRegisterType
1415 AutoRegister::GetAutoRegisterType( string type )
1416 {
1417 if ( type == "DllRegisterServer" )
1418 return DllRegisterServer;
1419 if ( type == "DllInstall" )
1420 return DllInstall;
1421 if ( type == "Both" )
1422 return Both;
1423 throw XMLInvalidBuildFileException (
1424 node.location,
1425 "<autoregister> type attribute must be DllRegisterServer, DllInstall or Both." );
1426 }
1427
1428 void
1429 AutoRegister::Initialize ()
1430 {
1431 if ( !IsSupportedModuleType ( module->type ) )
1432 {
1433 throw XMLInvalidBuildFileException (
1434 node.location,
1435 "<autoregister> is not applicable for this module type." );
1436 }
1437
1438 const XMLAttribute* att = node.GetAttribute ( "infsection", true );
1439 infSection = att->value;
1440
1441 att = node.GetAttribute ( "type", true );
1442 type = GetAutoRegisterType ( att->value );
1443 }
1444
1445 void
1446 AutoRegister::ProcessXML()
1447 {
1448 }