30ec36e75325b7dc3478201e20823857fbe0198f
[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 FixSeparator ( const string& s )
56 {
57 string s2(s);
58 char* p = strchr ( &s2[0], CBAD_SEP );
59 while ( p )
60 {
61 *p++ = CSEP;
62 p = strchr ( p, CBAD_SEP );
63 }
64 return s2;
65 }
66
67 string
68 DosSeparator ( const string& s )
69 {
70 string s2(s);
71 char* p = strchr ( &s2[0], '/' );
72 while ( p )
73 {
74 *p++ = '\\';
75 p = strchr ( p, '/' );
76 }
77 return s2;
78 }
79
80 string
81 ReplaceExtension (
82 const string& filename,
83 const string& newExtension )
84 {
85 size_t index = filename.find_last_of ( '/' );
86 if ( index == string::npos )
87 index = 0;
88 size_t index2 = filename.find_last_of ( '\\' );
89 if ( index2 != string::npos && index2 > index )
90 index = index2;
91 string tmp = filename.substr( index /*, filename.size() - index*/ );
92 size_t ext_index = tmp.find_last_of( '.' );
93 if ( ext_index != string::npos )
94 return filename.substr ( 0, index + ext_index ) + newExtension;
95 return filename + newExtension;
96 }
97
98 string
99 GetSubPath (
100 const string& location,
101 const string& path,
102 const string& att_value )
103 {
104 if ( !att_value.size() )
105 throw InvalidBuildFileException (
106 location,
107 "<directory> tag has empty 'name' attribute" );
108 if ( strpbrk ( att_value.c_str (), "/\\?*:<>|" ) )
109 throw InvalidBuildFileException (
110 location,
111 "<directory> tag has invalid characters in 'name' attribute" );
112 if ( !path.size() )
113 return att_value;
114 return FixSeparator(path + CSEP + att_value);
115 }
116
117 string
118 GetExtension ( const string& filename )
119 {
120 size_t index = filename.find_last_of ( '/' );
121 if (index == string::npos) index = 0;
122 string tmp = filename.substr( index, filename.size() - index );
123 size_t ext_index = tmp.find_last_of( '.' );
124 if (ext_index != string::npos)
125 return filename.substr ( index + ext_index, filename.size() );
126 return "";
127 }
128
129 string
130 GetDirectory ( const string& filename )
131 {
132 size_t index = filename.find_last_of ( CSEP );
133 if ( index == string::npos )
134 return "";
135 else
136 return filename.substr ( 0, index );
137 }
138
139 string
140 GetFilename ( const string& filename )
141 {
142 size_t index = filename.find_last_of ( CSEP );
143 if ( index == string::npos )
144 return filename;
145 else
146 return filename.substr ( index + 1, filename.length () - index );
147 }
148
149 string
150 NormalizeFilename ( const string& filename )
151 {
152 if ( filename == "" )
153 return "";
154 Path path;
155 string normalizedPath = path.Fixup ( filename, true );
156 string relativeNormalizedPath = path.RelativeFromWorkingDirectory ( normalizedPath );
157 return FixSeparator ( relativeNormalizedPath );
158 }
159
160 bool
161 GetBooleanValue ( const string& value )
162 {
163 if ( value == "1" )
164 return true;
165 else
166 return false;
167 }
168
169 IfableData::~IfableData()
170 {
171 size_t i;
172 for ( i = 0; i < files.size(); i++ )
173 delete files[i];
174 for ( i = 0; i < includes.size(); i++ )
175 delete includes[i];
176 for ( i = 0; i < defines.size(); i++ )
177 delete defines[i];
178 for ( i = 0; i < libraries.size(); i++ )
179 delete libraries[i];
180 for ( i = 0; i < properties.size(); i++ )
181 delete properties[i];
182 for ( i = 0; i < compilerFlags.size(); i++ )
183 delete compilerFlags[i];
184 for ( i = 0; i < ifs.size(); i++ )
185 delete ifs[i];
186 }
187
188 void IfableData::ProcessXML ()
189 {
190 size_t i;
191 for ( i = 0; i < files.size (); i++ )
192 files[i]->ProcessXML ();
193 for ( i = 0; i < includes.size (); i++ )
194 includes[i]->ProcessXML ();
195 for ( i = 0; i < defines.size (); i++ )
196 defines[i]->ProcessXML ();
197 for ( i = 0; i < libraries.size (); i++ )
198 libraries[i]->ProcessXML ();
199 for ( i = 0; i < properties.size(); i++ )
200 properties[i]->ProcessXML ();
201 for ( i = 0; i < compilerFlags.size(); i++ )
202 compilerFlags[i]->ProcessXML ();
203 for ( i = 0; i < ifs.size (); i++ )
204 ifs[i]->ProcessXML ();
205 }
206
207 Module::Module ( const Project& project,
208 const XMLElement& moduleNode,
209 const string& modulePath )
210 : project (project),
211 node (moduleNode),
212 importLibrary (NULL),
213 bootstrap (NULL),
214 pch (NULL),
215 cplusplus (false),
216 host (HostDefault)
217 {
218 if ( node.name != "module" )
219 throw InvalidOperationException ( __FILE__,
220 __LINE__,
221 "Module created with non-<module> node" );
222
223 xmlbuildFile = Path::RelativeFromWorkingDirectory ( moduleNode.xmlFile->filename () );
224
225 path = FixSeparator ( modulePath );
226
227 enabled = true;
228
229 const XMLAttribute* att = moduleNode.GetAttribute ( "if", false );
230 if ( att != NULL )
231 enabled = GetBooleanValue ( project.ResolveProperties ( att->value ) );
232
233 att = moduleNode.GetAttribute ( "ifnot", false );
234 if ( att != NULL )
235 enabled = !GetBooleanValue ( project.ResolveProperties ( att->value ) );
236
237 att = moduleNode.GetAttribute ( "name", true );
238 assert(att);
239 name = att->value;
240
241 att = moduleNode.GetAttribute ( "type", true );
242 assert(att);
243 type = GetModuleType ( node.location, *att );
244
245 att = moduleNode.GetAttribute ( "extension", false );
246 if ( att != NULL )
247 extension = att->value;
248 else
249 extension = GetDefaultModuleExtension ();
250
251 att = moduleNode.GetAttribute ( "entrypoint", false );
252 if ( att != NULL )
253 entrypoint = att->value;
254 else
255 entrypoint = GetDefaultModuleEntrypoint ();
256
257 att = moduleNode.GetAttribute ( "baseaddress", false );
258 if ( att != NULL )
259 baseaddress = att->value;
260 else
261 baseaddress = GetDefaultModuleBaseaddress ();
262
263 att = moduleNode.GetAttribute ( "mangledsymbols", false );
264 if ( att != NULL )
265 {
266 const char* p = att->value.c_str();
267 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
268 mangledSymbols = true;
269 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
270 mangledSymbols = false;
271 else
272 {
273 throw InvalidAttributeValueException (
274 moduleNode.location,
275 "mangledsymbols",
276 att->value );
277 }
278 }
279 else
280 mangledSymbols = false;
281
282 att = moduleNode.GetAttribute ( "host", false );
283 if ( att != NULL )
284 {
285 const char* p = att->value.c_str();
286 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
287 host = HostTrue;
288 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
289 host = HostFalse;
290 else
291 {
292 throw InvalidAttributeValueException (
293 moduleNode.location,
294 "host",
295 att->value );
296 }
297 }
298
299 att = moduleNode.GetAttribute ( "prefix", false );
300 if ( att != NULL )
301 prefix = att->value;
302
303 att = moduleNode.GetAttribute ( "installbase", false );
304 if ( att != NULL )
305 installBase = att->value;
306 else
307 installBase = "";
308
309 att = moduleNode.GetAttribute ( "installname", false );
310 if ( att != NULL )
311 installName = att->value;
312 else
313 installName = "";
314
315 att = moduleNode.GetAttribute ( "usewrc", false );
316 if ( att != NULL )
317 useWRC = att->value == "true";
318 else
319 useWRC = true;
320
321 att = moduleNode.GetAttribute ( "allowwarnings", false );
322 if ( att == NULL )
323 {
324 att = moduleNode.GetAttribute ( "warnings", false );
325 if ( att != NULL )
326 {
327 printf ( "%s: WARNING: 'warnings' attribute of <module> is deprecated, use 'allowwarnings' instead\n",
328 moduleNode.location.c_str() );
329 }
330 }
331 if ( att != NULL )
332 allowWarnings = att->value == "true";
333 else
334 allowWarnings = false;
335
336 att = moduleNode.GetAttribute ( "aliasof", false );
337 if ( type == Alias && att != NULL )
338 aliasedModuleName = att->value;
339 else
340 aliasedModuleName = "";
341 }
342
343 Module::~Module ()
344 {
345 size_t i;
346 for ( i = 0; i < invocations.size(); i++ )
347 delete invocations[i];
348 for ( i = 0; i < dependencies.size(); i++ )
349 delete dependencies[i];
350 for ( i = 0; i < compilerFlags.size(); i++ )
351 delete compilerFlags[i];
352 for ( i = 0; i < linkerFlags.size(); i++ )
353 delete linkerFlags[i];
354 for ( i = 0; i < stubbedComponents.size(); i++ )
355 delete stubbedComponents[i];
356 if ( pch )
357 delete pch;
358 }
359
360 void
361 Module::ProcessXML()
362 {
363 if ( type == Alias )
364 {
365 if ( aliasedModuleName == name )
366 throw InvalidBuildFileException (
367 node.location,
368 "module '%s' cannot link against itself",
369 name.c_str() );
370 const Module* m = project.LocateModule ( aliasedModuleName );
371 if ( !m )
372 throw InvalidBuildFileException (
373 node.location,
374 "module '%s' trying to alias non-existant module '%s'",
375 name.c_str(),
376 aliasedModuleName.c_str() );
377 }
378
379 size_t i;
380 for ( i = 0; i < node.subElements.size(); i++ )
381 ProcessXMLSubElement ( *node.subElements[i], path );
382 for ( i = 0; i < invocations.size(); i++ )
383 invocations[i]->ProcessXML ();
384 for ( i = 0; i < dependencies.size(); i++ )
385 dependencies[i]->ProcessXML ();
386 for ( i = 0; i < compilerFlags.size(); i++ )
387 compilerFlags[i]->ProcessXML();
388 for ( i = 0; i < linkerFlags.size(); i++ )
389 linkerFlags[i]->ProcessXML();
390 for ( i = 0; i < stubbedComponents.size(); i++ )
391 stubbedComponents[i]->ProcessXML();
392 non_if_data.ProcessXML();
393 if ( pch )
394 pch->ProcessXML();
395 }
396
397 void
398 Module::ProcessXMLSubElement ( const XMLElement& e,
399 const string& path,
400 If* pIf /*= NULL*/ )
401 {
402 bool subs_invalid = false;
403 string subpath ( path );
404 if ( e.name == "file" && e.value.size () > 0 )
405 {
406 bool first = false;
407 const XMLAttribute* att = e.GetAttribute ( "first", false );
408 if ( att != NULL )
409 {
410 if ( !stricmp ( att->value.c_str(), "true" ) )
411 first = true;
412 else if ( stricmp ( att->value.c_str(), "false" ) )
413 throw InvalidBuildFileException (
414 e.location,
415 "attribute 'first' of <file> element can only be 'true' or 'false'" );
416 }
417 string switches = "";
418 att = e.GetAttribute ( "switches", false );
419 if ( att != NULL )
420 switches = att->value;
421 if ( !cplusplus )
422 {
423 // check for c++ file
424 string ext = GetExtension ( e.value );
425 if ( !stricmp ( ext.c_str(), ".cpp" ) )
426 cplusplus = true;
427 else if ( !stricmp ( ext.c_str(), ".cc" ) )
428 cplusplus = true;
429 else if ( !stricmp ( ext.c_str(), ".cxx" ) )
430 cplusplus = true;
431 }
432 File* pFile = new File ( FixSeparator ( path + CSEP + e.value ),
433 first,
434 switches,
435 false );
436 if ( pIf )
437 pIf->data.files.push_back ( pFile );
438 else
439 non_if_data.files.push_back ( pFile );
440 subs_invalid = true;
441 }
442 else if ( e.name == "library" && e.value.size () )
443 {
444 Library* pLibrary = new Library ( e, *this, e.value );
445 if ( pIf )
446 pIf->data.libraries.push_back ( pLibrary );
447 else
448 non_if_data.libraries.push_back ( pLibrary );
449 subs_invalid = true;
450 }
451 else if ( e.name == "directory" )
452 {
453 const XMLAttribute* att = e.GetAttribute ( "name", true );
454 assert(att);
455 subpath = GetSubPath ( e.location, path, att->value );
456 }
457 else if ( e.name == "include" )
458 {
459 Include* include = new Include ( project, this, &e );
460 if ( pIf )
461 pIf->data.includes.push_back ( include );
462 else
463 non_if_data.includes.push_back ( include );
464 subs_invalid = true;
465 }
466 else if ( e.name == "define" )
467 {
468 Define* pDefine = new Define ( project, this, e );
469 if ( pIf )
470 pIf->data.defines.push_back ( pDefine );
471 else
472 non_if_data.defines.push_back ( pDefine );
473 subs_invalid = true;
474 }
475 else if ( e.name == "invoke" )
476 {
477 if ( pIf )
478 throw InvalidBuildFileException (
479 e.location,
480 "<invoke> is not a valid sub-element of <if>" );
481 invocations.push_back ( new Invoke ( e, *this ) );
482 subs_invalid = false;
483 }
484 else if ( e.name == "dependency" )
485 {
486 if ( pIf )
487 throw InvalidBuildFileException (
488 e.location,
489 "<dependency> is not a valid sub-element of <if>" );
490 dependencies.push_back ( new Dependency ( e, *this ) );
491 subs_invalid = true;
492 }
493 else if ( e.name == "importlibrary" )
494 {
495 if ( pIf )
496 throw InvalidBuildFileException (
497 e.location,
498 "<importlibrary> is not a valid sub-element of <if>" );
499 if ( importLibrary )
500 throw InvalidBuildFileException (
501 e.location,
502 "Only one <importlibrary> is valid per module" );
503 importLibrary = new ImportLibrary ( e, *this );
504 subs_invalid = true;
505 }
506 else if ( e.name == "if" )
507 {
508 If* pOldIf = pIf;
509 pIf = new If ( e, project, this );
510 if ( pOldIf )
511 pOldIf->data.ifs.push_back ( pIf );
512 else
513 non_if_data.ifs.push_back ( pIf );
514 subs_invalid = false;
515 }
516 else if ( e.name == "ifnot" )
517 {
518 If* pOldIf = pIf;
519 pIf = new If ( e, project, this, true );
520 if ( pOldIf )
521 pOldIf->data.ifs.push_back ( pIf );
522 else
523 non_if_data.ifs.push_back ( pIf );
524 subs_invalid = false;
525 }
526 else if ( e.name == "compilerflag" )
527 {
528 CompilerFlag* pCompilerFlag = new CompilerFlag ( project, this, e );
529 if ( pIf )
530 pIf->data.compilerFlags.push_back ( pCompilerFlag );
531 else
532 non_if_data.compilerFlags.push_back ( pCompilerFlag );
533 subs_invalid = true;
534 }
535 else if ( e.name == "linkerflag" )
536 {
537 linkerFlags.push_back ( new LinkerFlag ( project, this, e ) );
538 subs_invalid = true;
539 }
540 else if ( e.name == "component" )
541 {
542 stubbedComponents.push_back ( new StubbedComponent ( this, e ) );
543 subs_invalid = false;
544 }
545 else if ( e.name == "property" )
546 {
547 throw InvalidBuildFileException (
548 e.location,
549 "<property> is not a valid sub-element of <module>" );
550 }
551 else if ( e.name == "bootstrap" )
552 {
553 bootstrap = new Bootstrap ( project, this, e );
554 subs_invalid = true;
555 }
556 else if ( e.name == "pch" )
557 {
558 if ( pIf )
559 throw InvalidBuildFileException (
560 e.location,
561 "<pch> is not a valid sub-element of <if>" );
562 if ( pch )
563 throw InvalidBuildFileException (
564 e.location,
565 "Only one <pch> is valid per module" );
566 pch = new PchFile (
567 e, *this, File ( FixSeparator ( path + CSEP + e.value ), false, "", true ) );
568 subs_invalid = true;
569 }
570 if ( subs_invalid && e.subElements.size() > 0 )
571 throw InvalidBuildFileException (
572 e.location,
573 "<%s> cannot have sub-elements",
574 e.name.c_str() );
575 for ( size_t i = 0; i < e.subElements.size (); i++ )
576 ProcessXMLSubElement ( *e.subElements[i], subpath, pIf );
577 }
578
579 ModuleType
580 Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
581 {
582 if ( attribute.value == "buildtool" )
583 return BuildTool;
584 if ( attribute.value == "staticlibrary" )
585 return StaticLibrary;
586 if ( attribute.value == "objectlibrary" )
587 return ObjectLibrary;
588 if ( attribute.value == "kernel" )
589 return Kernel;
590 if ( attribute.value == "kernelmodedll" )
591 return KernelModeDLL;
592 if ( attribute.value == "kernelmodedriver" )
593 return KernelModeDriver;
594 if ( attribute.value == "nativedll" )
595 return NativeDLL;
596 if ( attribute.value == "nativecui" )
597 return NativeCUI;
598 if ( attribute.value == "win32dll" )
599 return Win32DLL;
600 if ( attribute.value == "win32cui" )
601 return Win32CUI;
602 if ( attribute.value == "win32gui" )
603 return Win32GUI;
604 if ( attribute.value == "bootloader" )
605 return BootLoader;
606 if ( attribute.value == "bootsector" )
607 return BootSector;
608 if ( attribute.value == "iso" )
609 return Iso;
610 if ( attribute.value == "liveiso" )
611 return LiveIso;
612 if ( attribute.value == "test" )
613 return Test;
614 if ( attribute.value == "rpcserver" )
615 return RpcServer;
616 if ( attribute.value == "rpcclient" )
617 return RpcClient;
618 if ( attribute.value == "alias" )
619 return Alias;
620 throw InvalidAttributeValueException ( location,
621 attribute.name,
622 attribute.value );
623 }
624
625 string
626 Module::GetDefaultModuleExtension () const
627 {
628 switch (type)
629 {
630 case BuildTool:
631 return EXEPOSTFIX;
632 case StaticLibrary:
633 return ".a";
634 case ObjectLibrary:
635 return ".o";
636 case Kernel:
637 case NativeCUI:
638 case Win32CUI:
639 case Win32GUI:
640 return ".exe";
641 case KernelModeDLL:
642 case NativeDLL:
643 case Win32DLL:
644 return ".dll";
645 case KernelModeDriver:
646 case BootLoader:
647 return ".sys";
648 case BootSector:
649 return ".o";
650 case Iso:
651 case LiveIso:
652 return ".iso";
653 case Test:
654 return ".exe";
655 case RpcServer:
656 return ".o";
657 case RpcClient:
658 return ".o";
659 case Alias:
660 return "";
661 }
662 throw InvalidOperationException ( __FILE__,
663 __LINE__ );
664 }
665
666 string
667 Module::GetDefaultModuleEntrypoint () const
668 {
669 switch ( type )
670 {
671 case Kernel:
672 return "_NtProcessStartup";
673 case KernelModeDLL:
674 return "_DriverEntry@8";
675 case NativeDLL:
676 return "_DllMainCRTStartup@12";
677 case NativeCUI:
678 return "_NtProcessStartup@4";
679 case Win32DLL:
680 return "_DllMain@12";
681 case Win32CUI:
682 case Test:
683 return "_mainCRTStartup";
684 case Win32GUI:
685 return "_WinMainCRTStartup";
686 case KernelModeDriver:
687 return "_DriverEntry@8";
688 case BuildTool:
689 case StaticLibrary:
690 case ObjectLibrary:
691 case BootLoader:
692 case BootSector:
693 case Iso:
694 case LiveIso:
695 case RpcServer:
696 case RpcClient:
697 case Alias:
698 return "";
699 }
700 throw InvalidOperationException ( __FILE__,
701 __LINE__ );
702 }
703
704 string
705 Module::GetDefaultModuleBaseaddress () const
706 {
707 switch ( type )
708 {
709 case Kernel:
710 return "0x80000000";
711 case Win32DLL:
712 return "0x10000000";
713 case NativeDLL:
714 case NativeCUI:
715 case Win32CUI:
716 case Test:
717 return "0x00400000";
718 case Win32GUI:
719 return "0x00400000";
720 case KernelModeDLL:
721 case KernelModeDriver:
722 return "0x00010000";
723 case BuildTool:
724 case StaticLibrary:
725 case ObjectLibrary:
726 case BootLoader:
727 case BootSector:
728 case Iso:
729 case LiveIso:
730 case RpcServer:
731 case RpcClient:
732 case Alias:
733 return "";
734 }
735 throw InvalidOperationException ( __FILE__,
736 __LINE__ );
737 }
738
739 bool
740 Module::HasImportLibrary () const
741 {
742 return importLibrary != NULL;
743 }
744
745 bool
746 Module::IsDLL () const
747 {
748 switch ( type )
749 {
750 case Kernel:
751 case KernelModeDLL:
752 case NativeDLL:
753 case Win32DLL:
754 case KernelModeDriver:
755 return true;
756 case NativeCUI:
757 case Win32CUI:
758 case Test:
759 case Win32GUI:
760 case BuildTool:
761 case StaticLibrary:
762 case ObjectLibrary:
763 case BootLoader:
764 case BootSector:
765 case Iso:
766 case LiveIso:
767 case RpcServer:
768 case RpcClient:
769 case Alias:
770 return false;
771 }
772 throw InvalidOperationException ( __FILE__,
773 __LINE__ );
774 }
775
776 bool
777 Module::GenerateInOutputTree () const
778 {
779 switch ( type )
780 {
781 case Kernel:
782 case KernelModeDLL:
783 case NativeDLL:
784 case Win32DLL:
785 case KernelModeDriver:
786 case NativeCUI:
787 case Win32CUI:
788 case Test:
789 case Win32GUI:
790 case BuildTool:
791 case BootLoader:
792 case BootSector:
793 case Iso:
794 case LiveIso:
795 return true;
796 case StaticLibrary:
797 case ObjectLibrary:
798 case RpcServer:
799 case RpcClient:
800 case Alias:
801 return false;
802 }
803 throw InvalidOperationException ( __FILE__,
804 __LINE__ );
805 }
806
807 string
808 Module::GetTargetName () const
809 {
810 return name + extension;
811 }
812
813 string
814 Module::GetDependencyPath () const
815 {
816 if ( HasImportLibrary () )
817 return ReplaceExtension ( GetPathWithPrefix ( "lib" ), ".a" );
818 else
819 return GetPath();
820 }
821
822 string
823 Module::GetBasePath () const
824 {
825 return path;
826 }
827
828 string
829 Module::GetPath () const
830 {
831 if ( path.length() > 0 )
832 return path + CSEP + GetTargetName ();
833 else
834 return GetTargetName ();
835 }
836
837 string
838 Module::GetPathWithPrefix ( const string& prefix ) const
839 {
840 return path + CSEP + prefix + GetTargetName ();
841 }
842
843 string
844 Module::GetInvocationTarget ( const int index ) const
845 {
846 return ssprintf ( "%s_invoke_%d",
847 name.c_str (),
848 index );
849 }
850
851 bool
852 Module::HasFileWithExtension (
853 const IfableData& data,
854 const std::string& extension ) const
855 {
856 size_t i;
857 for ( i = 0; i < data.files.size (); i++ )
858 {
859 File& file = *data.files[i];
860 string file_ext = GetExtension ( file.name );
861 if ( !stricmp ( file_ext.c_str (), extension.c_str () ) )
862 return true;
863 }
864 for ( i = 0; i < data.ifs.size (); i++ )
865 {
866 if ( HasFileWithExtension ( data.ifs[i]->data, extension ) )
867 return true;
868 }
869 return false;
870 }
871
872 void
873 Module::InvokeModule () const
874 {
875 for ( size_t i = 0; i < invocations.size (); i++ )
876 {
877 Invoke& invoke = *invocations[i];
878 string command = invoke.invokeModule->GetPath () + " " + invoke.GetParameters ();
879 printf ( "Executing '%s'\n\n", command.c_str () );
880 int exitcode = system ( command.c_str () );
881 if ( exitcode != 0 )
882 throw InvocationFailedException ( command,
883 exitcode );
884 }
885 }
886
887
888 File::File ( const string& _name, bool _first,
889 std::string _switches,
890 bool _isPreCompiledHeader )
891 : name(_name),
892 first(_first),
893 switches(_switches),
894 isPreCompiledHeader(_isPreCompiledHeader)
895 {
896 }
897
898 void
899 File::ProcessXML()
900 {
901 }
902
903 bool
904 File::IsGeneratedFile () const
905 {
906 string extension = GetExtension ( name );
907 return ( extension == ".spec" || extension == ".SPEC" );
908 }
909
910
911 Library::Library ( const XMLElement& _node,
912 const Module& _module,
913 const string& _name )
914 : node(_node),
915 module(_module),
916 name(_name),
917 importedModule(_module.project.LocateModule(_name))
918 {
919 if ( module.name == name )
920 throw InvalidBuildFileException (
921 node.location,
922 "module '%s' cannot link against itself",
923 name.c_str() );
924 if ( !importedModule )
925 throw InvalidBuildFileException (
926 node.location,
927 "module '%s' trying to import non-existant module '%s'",
928 module.name.c_str(),
929 name.c_str() );
930 }
931
932 void
933 Library::ProcessXML()
934 {
935 if ( !module.project.LocateModule ( name ) )
936 throw InvalidBuildFileException (
937 node.location,
938 "module '%s' is trying to link against non-existant module '%s'",
939 module.name.c_str(),
940 name.c_str() );
941 }
942
943
944 Invoke::Invoke ( const XMLElement& _node,
945 const Module& _module )
946 : node (_node),
947 module (_module)
948 {
949 }
950
951 void
952 Invoke::ProcessXML()
953 {
954 const XMLAttribute* att = node.GetAttribute ( "module", false );
955 if (att == NULL)
956 invokeModule = &module;
957 else
958 {
959 invokeModule = module.project.LocateModule ( att->value );
960 if ( invokeModule == NULL )
961 throw InvalidBuildFileException (
962 node.location,
963 "module '%s' is trying to invoke non-existant module '%s'",
964 module.name.c_str(),
965 att->value.c_str() );
966 }
967
968 for ( size_t i = 0; i < node.subElements.size (); i++ )
969 ProcessXMLSubElement ( *node.subElements[i] );
970 }
971
972 void
973 Invoke::ProcessXMLSubElement ( const XMLElement& e )
974 {
975 bool subs_invalid = false;
976 if ( e.name == "input" )
977 {
978 for ( size_t i = 0; i < e.subElements.size (); i++ )
979 ProcessXMLSubElementInput ( *e.subElements[i] );
980 }
981 else if ( e.name == "output" )
982 {
983 for ( size_t i = 0; i < e.subElements.size (); i++ )
984 ProcessXMLSubElementOutput ( *e.subElements[i] );
985 }
986 if ( subs_invalid && e.subElements.size() > 0 )
987 throw InvalidBuildFileException ( e.location,
988 "<%s> cannot have sub-elements",
989 e.name.c_str() );
990 }
991
992 void
993 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
994 {
995 bool subs_invalid = false;
996 if ( e.name == "inputfile" && e.value.size () > 0 )
997 {
998 input.push_back ( new InvokeFile ( e, FixSeparator ( module.path + CSEP + e.value ) ) );
999 subs_invalid = true;
1000 }
1001 if ( subs_invalid && e.subElements.size() > 0 )
1002 throw InvalidBuildFileException ( e.location,
1003 "<%s> cannot have sub-elements",
1004 e.name.c_str() );
1005 }
1006
1007 void
1008 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
1009 {
1010 bool subs_invalid = false;
1011 if ( e.name == "outputfile" && e.value.size () > 0 )
1012 {
1013 output.push_back ( new InvokeFile ( e, FixSeparator ( module.path + CSEP + e.value ) ) );
1014 subs_invalid = true;
1015 }
1016 if ( subs_invalid && e.subElements.size() > 0 )
1017 throw InvalidBuildFileException (
1018 e.location,
1019 "<%s> cannot have sub-elements",
1020 e.name.c_str() );
1021 }
1022
1023 void
1024 Invoke::GetTargets ( string_list& targets ) const
1025 {
1026 for ( size_t i = 0; i < output.size (); i++ )
1027 {
1028 InvokeFile& file = *output[i];
1029 targets.push_back ( NormalizeFilename ( file.name ) );
1030 }
1031 }
1032
1033 string
1034 Invoke::GetParameters () const
1035 {
1036 string parameters ( "" );
1037 size_t i;
1038 for ( i = 0; i < output.size (); i++ )
1039 {
1040 if ( parameters.length () > 0)
1041 parameters += " ";
1042 InvokeFile& invokeFile = *output[i];
1043 if ( invokeFile.switches.length () > 0 )
1044 {
1045 parameters += invokeFile.switches + " ";
1046 }
1047 parameters += invokeFile.name;
1048 }
1049
1050 for ( i = 0; i < input.size (); i++ )
1051 {
1052 if ( parameters.length () > 0 )
1053 parameters += " ";
1054 InvokeFile& invokeFile = *input[i];
1055 if ( invokeFile.switches.length () > 0 )
1056 {
1057 parameters += invokeFile.switches;
1058 parameters += " ";
1059 }
1060 parameters += invokeFile.name ;
1061 }
1062
1063 return parameters;
1064 }
1065
1066
1067 InvokeFile::InvokeFile ( const XMLElement& _node,
1068 const string& _name )
1069 : node (_node),
1070 name (_name)
1071 {
1072 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
1073 if (att != NULL)
1074 switches = att->value;
1075 else
1076 switches = "";
1077 }
1078
1079 void
1080 InvokeFile::ProcessXML()
1081 {
1082 }
1083
1084
1085 Dependency::Dependency ( const XMLElement& _node,
1086 const Module& _module )
1087 : node (_node),
1088 module (_module),
1089 dependencyModule (NULL)
1090 {
1091 }
1092
1093 void
1094 Dependency::ProcessXML()
1095 {
1096 dependencyModule = module.project.LocateModule ( node.value );
1097 if ( dependencyModule == NULL )
1098 throw InvalidBuildFileException ( node.location,
1099 "module '%s' depend on non-existant module '%s'",
1100 module.name.c_str(),
1101 node.value.c_str() );
1102 }
1103
1104
1105 ImportLibrary::ImportLibrary ( const XMLElement& _node,
1106 const Module& _module )
1107 : node (_node),
1108 module (_module)
1109 {
1110 const XMLAttribute* att = _node.GetAttribute ( "basename", false );
1111 if (att != NULL)
1112 basename = att->value;
1113 else
1114 basename = module.name;
1115
1116 att = _node.GetAttribute ( "definition", true );
1117 assert (att);
1118 definition = FixSeparator(att->value);
1119 }
1120
1121
1122 If::If ( const XMLElement& node_,
1123 const Project& project_,
1124 const Module* module_,
1125 const bool negated_ )
1126 : node(node_), project(project_), module(module_), negated(negated_)
1127 {
1128 const XMLAttribute* att;
1129
1130 att = node.GetAttribute ( "property", true );
1131 assert(att);
1132 property = att->value;
1133
1134 att = node.GetAttribute ( "value", true );
1135 assert(att);
1136 value = att->value;
1137 }
1138
1139 If::~If ()
1140 {
1141 }
1142
1143 void
1144 If::ProcessXML()
1145 {
1146 }
1147
1148
1149 Property::Property ( const XMLElement& node_,
1150 const Project& project_,
1151 const Module* module_ )
1152 : node(node_), project(project_), module(module_)
1153 {
1154 const XMLAttribute* att;
1155
1156 att = node.GetAttribute ( "name", true );
1157 assert(att);
1158 name = att->value;
1159
1160 att = node.GetAttribute ( "value", true );
1161 assert(att);
1162 value = att->value;
1163 }
1164
1165 void
1166 Property::ProcessXML()
1167 {
1168 }
1169
1170
1171 PchFile::PchFile (
1172 const XMLElement& node_,
1173 const Module& module_,
1174 const File file_ )
1175 : node(node_), module(module_), file(file_)
1176 {
1177 }
1178
1179 void
1180 PchFile::ProcessXML()
1181 {
1182 }