Display a message when a module has been disabled
[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 Project& project,
122 const string& location,
123 const string& path,
124 const string& att_value )
125 {
126 if ( !att_value.size() )
127 throw XMLInvalidBuildFileException (
128 location,
129 "<directory> tag has empty 'name' attribute" );
130 if ( strpbrk ( att_value.c_str (), "/\\?*:<>|" ) )
131 throw XMLInvalidBuildFileException (
132 location,
133 "<directory> tag has invalid characters in 'name' attribute" );
134 if ( !path.size() )
135 return att_value;
136
137 return FixSeparator(path + cSep + att_value);
138 }
139
140 static string
141 GetExtension ( const string& filename )
142 {
143 size_t index = filename.find_last_of ( '/' );
144 if (index == string::npos) index = 0;
145 string tmp = filename.substr( index, filename.size() - index );
146 size_t ext_index = tmp.find_last_of( '.' );
147 if (ext_index != string::npos)
148 return filename.substr ( index + ext_index, filename.size() );
149 return "";
150 }
151
152 string
153 GetExtension ( const FileLocation& file )
154 {
155 return GetExtension ( file.name );
156 }
157
158 string
159 NormalizeFilename ( const string& filename )
160 {
161 if ( filename == "" )
162 return "";
163 Path path;
164 string normalizedPath = path.Fixup ( filename, true );
165 string relativeNormalizedPath = path.RelativeFromWorkingDirectory ( normalizedPath );
166 return FixSeparator ( relativeNormalizedPath );
167 }
168
169 bool
170 GetBooleanValue ( const string& value )
171 {
172 if ( value == "1" )
173 return true;
174 else
175 return false;
176 }
177
178 string
179 ToLower ( string filename )
180 {
181 for ( size_t i = 1; i < filename.length (); i++ )
182 filename[i] = tolower ( filename[i] );
183 return filename;
184 }
185
186 void IfableData::ExtractModules( std::vector<Module*> &modules )
187 {
188 size_t i;
189 for ( i = 0; i < this->modules.size (); i++ )
190 modules.push_back(this->modules[i]);
191 }
192
193 IfableData::~IfableData()
194 {
195 size_t i;
196 for ( i = 0; i < includes.size (); i++ )
197 delete includes[i];
198 for ( i = 0; i < defines.size (); i++ )
199 delete defines[i];
200 for ( i = 0; i < libraries.size (); i++ )
201 delete libraries[i];
202 for ( i = 0; i < properties.size (); i++ )
203 delete properties[i];
204 for ( i = 0; i < compilerFlags.size (); i++ )
205 delete compilerFlags[i];
206 for ( i = 0; i < modules.size(); i++ )
207 delete modules[i];
208 for ( i = 0; i < ifs.size (); i++ )
209 delete ifs[i];
210 for ( i = 0; i < compilationUnits.size (); i++ )
211 delete compilationUnits[i];
212 }
213
214 void IfableData::ProcessXML ()
215 {
216 size_t i;
217 for ( i = 0; i < includes.size (); i++ )
218 includes[i]->ProcessXML ();
219 for ( i = 0; i < defines.size (); i++ )
220 defines[i]->ProcessXML ();
221 for ( i = 0; i < libraries.size (); i++ )
222 libraries[i]->ProcessXML ();
223 for ( i = 0; i < properties.size(); i++ )
224 properties[i]->ProcessXML ();
225 for ( i = 0; i < compilerFlags.size(); i++ )
226 compilerFlags[i]->ProcessXML ();
227 for ( i = 0; i < ifs.size (); i++ )
228 ifs[i]->ProcessXML ();
229 for ( i = 0; i < compilationUnits.size (); i++ )
230 compilationUnits[i]->ProcessXML ();
231 }
232
233 Module::Module ( const Project& project,
234 const XMLElement& moduleNode,
235 const string& modulePath )
236 : project (project),
237 node (moduleNode),
238 importLibrary (NULL),
239 metadata (NULL),
240 bootstrap (NULL),
241 autoRegister(NULL),
242 linkerScript (NULL),
243 pch (NULL),
244 cplusplus (false),
245 host (HostDefault)
246 {
247 if ( node.name != "module" )
248 throw InvalidOperationException ( __FILE__,
249 __LINE__,
250 "Module created with non-<module> node" );
251
252 xmlbuildFile = Path::RelativeFromWorkingDirectory ( moduleNode.xmlFile->filename () );
253
254 const XMLAttribute* att = moduleNode.GetAttribute ( "name", true );
255 assert(att);
256 name = att->value;
257
258 enabled = true;
259
260 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 if ( !enabled && project.configuration.Verbose )
269 printf("Module '%s' has been disabled.\n", name.c_str () );
270
271 att = moduleNode.GetAttribute ( "type", true );
272 assert(att);
273 type = GetModuleType ( node.location, *att );
274
275 att = moduleNode.GetAttribute ( "extension", false );
276 if ( att != NULL )
277 extension = att->value;
278 else
279 extension = GetDefaultModuleExtension ();
280
281 output = new FileLocation ( GetTargetDirectoryTree (),
282 modulePath,
283 name + extension );
284
285 att = moduleNode.GetAttribute ( "unicode", false );
286 if ( att != NULL )
287 {
288 const char* p = att->value.c_str();
289 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
290 isUnicode = true;
291 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
292 isUnicode = false;
293 else
294 {
295 throw InvalidAttributeValueException (
296 moduleNode.location,
297 "unicode",
298 att->value );
299 }
300 }
301 else
302 isUnicode = false;
303
304 if (isUnicode)
305 {
306 // Always define UNICODE and _UNICODE
307 Define* pDefine = new Define ( project, this, "UNICODE" );
308 non_if_data.defines.push_back ( pDefine );
309
310 pDefine = new Define ( project, this, "_UNICODE" );
311 non_if_data.defines.push_back ( pDefine );
312 }
313
314 att = moduleNode.GetAttribute ( "entrypoint", false );
315 if ( att != NULL )
316 {
317 if ( att->value == "" )
318 {
319 throw InvalidAttributeValueException (
320 moduleNode.location,
321 "entrypoint",
322 att->value );
323 }
324
325 entrypoint = att->value;
326 isDefaultEntryPoint = false;
327 }
328 else
329 {
330 entrypoint = GetDefaultModuleEntrypoint ();
331 isDefaultEntryPoint = true;
332 }
333
334 att = moduleNode.GetAttribute ( "baseaddress", false );
335 if ( att != NULL )
336 baseaddress = att->value;
337 else
338 baseaddress = GetDefaultModuleBaseaddress ();
339
340 att = moduleNode.GetAttribute ( "mangledsymbols", false );
341 if ( att != NULL )
342 {
343 const char* p = att->value.c_str();
344 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
345 mangledSymbols = true;
346 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
347 mangledSymbols = false;
348 else
349 {
350 throw InvalidAttributeValueException (
351 moduleNode.location,
352 "mangledsymbols",
353 att->value );
354 }
355 }
356 else
357 mangledSymbols = false;
358
359 att = moduleNode.GetAttribute ( "underscoresymbols", false );
360 if ( att != NULL )
361 underscoreSymbols = att->value == "true";
362 else
363 underscoreSymbols = false;
364
365 att = moduleNode.GetAttribute ( "host", false );
366 if ( att != NULL )
367 {
368 const char* p = att->value.c_str();
369 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
370 host = HostTrue;
371 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
372 host = HostFalse;
373 else
374 {
375 throw InvalidAttributeValueException (
376 moduleNode.location,
377 "host",
378 att->value );
379 }
380 }
381
382 att = moduleNode.GetAttribute ( "isstartuplib", false );
383 if ( att != NULL )
384 {
385 const char* p = att->value.c_str();
386 if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
387 isStartupLib = true;
388 else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
389 isStartupLib = false;
390 else
391 {
392 throw InvalidAttributeValueException (
393 moduleNode.location,
394 "host",
395 att->value );
396 }
397 }
398 else
399 isStartupLib = false;
400
401 att = moduleNode.GetAttribute ( "prefix", false );
402 if ( att != NULL )
403 prefix = att->value;
404
405 att = moduleNode.GetAttribute ( "installname", false );
406 if ( att != NULL )
407 {
408 const XMLAttribute* installbase = moduleNode.GetAttribute ( "installbase", false );
409 install = new FileLocation ( InstallDirectory,
410 installbase ? installbase->value : "",
411 att->value );
412 }
413 else
414 install = NULL;
415
416 att = moduleNode.GetAttribute ( "usewrc", false );
417 if ( att != NULL )
418 useWRC = att->value == "true";
419 else
420 useWRC = true;
421
422 att = moduleNode.GetAttribute ( "allowwarnings", false );
423 if ( att == NULL )
424 {
425 att = moduleNode.GetAttribute ( "warnings", false );
426 if ( att != NULL )
427 {
428 printf ( "%s: WARNING: 'warnings' attribute of <module> is deprecated, use 'allowwarnings' instead\n",
429 moduleNode.location.c_str() );
430 }
431 }
432 if ( att != NULL )
433 allowWarnings = att->value == "true";
434 else
435 allowWarnings = false;
436
437 att = moduleNode.GetAttribute ( "aliasof", false );
438 if ( type == Alias && att != NULL )
439 aliasedModuleName = att->value;
440 else
441 aliasedModuleName = "";
442
443 if ( type == BootProgram )
444 {
445 att = moduleNode.GetAttribute ( "payload", true );
446 payload = att->value;
447 }
448
449 if ( type == BootProgram || type == ElfExecutable )
450 {
451 att = moduleNode.GetAttribute ( "buildtype", false );
452 if ( att != NULL )
453 {
454 buildtype = att->value;
455 }
456 else
457 {
458 buildtype = "BOOTPROG";
459 }
460 }
461
462 SetImportLibrary ( NULL );
463 }
464
465 Module::~Module ()
466 {
467 size_t i;
468 for ( i = 0; i < invocations.size(); i++ )
469 delete invocations[i];
470 for ( i = 0; i < dependencies.size(); i++ )
471 delete dependencies[i];
472 for ( i = 0; i < compilerFlags.size(); i++ )
473 delete compilerFlags[i];
474 for ( i = 0; i < linkerFlags.size(); i++ )
475 delete linkerFlags[i];
476 for ( i = 0; i < stubbedComponents.size(); i++ )
477 delete stubbedComponents[i];
478 if ( linkerScript )
479 delete linkerScript;
480 if ( pch )
481 delete pch;
482 }
483
484 void
485 Module::ProcessXML()
486 {
487 if ( type == Alias )
488 {
489 aliasedModuleName = project.ResolveProperties ( aliasedModuleName );
490 if ( aliasedModuleName == name )
491 {
492 throw XMLInvalidBuildFileException (
493 node.location,
494 "module '%s' cannot link against itself",
495 name.c_str() );
496 }
497 const Module* m = project.LocateModule ( aliasedModuleName );
498 if ( !m && enabled )
499 {
500 throw XMLInvalidBuildFileException (
501 node.location,
502 "module '%s' trying to alias non-existant module '%s'",
503 name.c_str(),
504 aliasedModuleName.c_str() );
505 }
506 }
507
508 size_t i;
509 for ( i = 0; i < node.subElements.size(); i++ )
510 {
511 ParseContext parseContext;
512 ProcessXMLSubElement ( *node.subElements[i], SourceDirectory, output->relative_path, parseContext );
513 }
514 for ( i = 0; i < invocations.size(); i++ )
515 invocations[i]->ProcessXML ();
516 for ( i = 0; i < dependencies.size(); i++ )
517 dependencies[i]->ProcessXML ();
518 for ( i = 0; i < compilerFlags.size(); i++ )
519 compilerFlags[i]->ProcessXML();
520 for ( i = 0; i < linkerFlags.size(); i++ )
521 linkerFlags[i]->ProcessXML();
522 for ( i = 0; i < stubbedComponents.size(); i++ )
523 stubbedComponents[i]->ProcessXML();
524 non_if_data.ProcessXML();
525 if ( linkerScript )
526 linkerScript->ProcessXML();
527 if ( pch )
528 pch->ProcessXML();
529 if ( autoRegister )
530 autoRegister->ProcessXML();
531 }
532
533 void
534 Module::ProcessXMLSubElement ( const XMLElement& e,
535 DirectoryLocation directory,
536 const string& relative_path,
537 ParseContext& parseContext )
538 {
539 If* pOldIf = parseContext.ifData;
540 CompilationUnit* pOldCompilationUnit = parseContext.compilationUnit;
541 bool subs_invalid = false;
542 string subpath ( relative_path );
543 DirectoryLocation subdirectory = SourceDirectory;
544 if ( e.name == "file" && e.value.size () > 0 )
545 {
546 bool first = false;
547 const XMLAttribute* att = e.GetAttribute ( "first", false );
548 if ( att != NULL )
549 {
550 if ( !stricmp ( att->value.c_str(), "true" ) )
551 first = true;
552 else if ( stricmp ( att->value.c_str(), "false" ) )
553 {
554 throw XMLInvalidBuildFileException (
555 e.location,
556 "attribute 'first' of <file> element can only be 'true' or 'false'" );
557 }
558 }
559 string switches = "";
560 att = e.GetAttribute ( "switches", false );
561 if ( att != NULL )
562 switches = att->value;
563 if ( !cplusplus )
564 {
565 // check for c++ file
566 string ext = GetExtension ( e.value );
567 if ( !stricmp ( ext.c_str(), ".cpp" ) )
568 cplusplus = true;
569 else if ( !stricmp ( ext.c_str(), ".cc" ) )
570 cplusplus = true;
571 else if ( !stricmp ( ext.c_str(), ".cxx" ) )
572 cplusplus = true;
573 }
574 File* pFile = new File ( directory,
575 relative_path,
576 e.value,
577 first,
578 switches,
579 false );
580 if ( parseContext.compilationUnit )
581 parseContext.compilationUnit->files.push_back ( pFile );
582 else
583 {
584 CompilationUnit* pCompilationUnit = new CompilationUnit ( pFile );
585 if ( parseContext.ifData )
586 parseContext.ifData->data.compilationUnits.push_back ( pCompilationUnit );
587 else
588 {
589 string ext = GetExtension ( e.value );
590 if ( !stricmp ( ext.c_str(), ".idl" ) )
591 non_if_data.compilationUnits.insert ( non_if_data.compilationUnits.begin(), pCompilationUnit );
592 else
593 non_if_data.compilationUnits.push_back ( pCompilationUnit );
594 }
595 }
596 if ( parseContext.ifData )
597 parseContext.ifData->data.files.push_back ( pFile );
598 else
599 non_if_data.files.push_back ( pFile );
600 subs_invalid = true;
601 }
602 else if ( e.name == "library" && e.value.size () )
603 {
604 Library* pLibrary = new Library ( e, *this, e.value );
605 if ( parseContext.ifData )
606 parseContext.ifData->data.libraries.push_back ( pLibrary );
607 else
608 non_if_data.libraries.push_back ( pLibrary );
609 subs_invalid = true;
610 }
611 else if ( e.name == "directory" )
612 {
613 const XMLAttribute* att = e.GetAttribute ( "name", true );
614 const XMLAttribute* root = e.GetAttribute ( "root", false );
615 assert(att);
616 if ( root )
617 {
618 if ( root->value == "intermediate" )
619 subdirectory = IntermediateDirectory;
620 else if ( root->value == "output" )
621 subdirectory = OutputDirectory;
622 else
623 {
624 throw InvalidAttributeValueException (
625 e.location,
626 "root",
627 root->value );
628 }
629 }
630 subpath = GetSubPath ( this->project, e.location, relative_path, att->value );
631 }
632 else if ( e.name == "include" )
633 {
634 Include* include = new Include ( project, &e, this );
635 if ( parseContext.ifData )
636 parseContext.ifData->data.includes.push_back ( include );
637 else
638 non_if_data.includes.push_back ( include );
639 subs_invalid = true;
640 }
641 else if ( e.name == "define" )
642 {
643 Define* pDefine = new Define ( project, this, e );
644 if ( parseContext.ifData )
645 parseContext.ifData->data.defines.push_back ( pDefine );
646 else
647 non_if_data.defines.push_back ( pDefine );
648 subs_invalid = true;
649 }
650 else if ( e.name == "metadata" )
651 {
652 if ( parseContext.ifData )
653 {
654 throw XMLInvalidBuildFileException (
655 e.location,
656 "<metadata> is not a valid sub-element of <if>" );
657 }
658 metadata = new Metadata ( e, *this );
659 subs_invalid = false;
660 }
661 else if ( e.name == "invoke" )
662 {
663 if ( parseContext.ifData )
664 {
665 throw XMLInvalidBuildFileException (
666 e.location,
667 "<invoke> is not a valid sub-element of <if>" );
668 }
669 invocations.push_back ( new Invoke ( e, *this ) );
670 subs_invalid = false;
671 }
672 else if ( e.name == "dependency" )
673 {
674 if ( parseContext.ifData )
675 {
676 throw XMLInvalidBuildFileException (
677 e.location,
678 "<dependency> is not a valid sub-element of <if>" );
679 }
680 dependencies.push_back ( new Dependency ( e, *this ) );
681 subs_invalid = true;
682 }
683 else if ( e.name == "importlibrary" )
684 {
685 if ( parseContext.ifData )
686 {
687 throw XMLInvalidBuildFileException (
688 e.location,
689 "<importlibrary> is not a valid sub-element of <if>" );
690 }
691 if ( importLibrary )
692 {
693 throw XMLInvalidBuildFileException (
694 e.location,
695 "Only one <importlibrary> is valid per module" );
696 }
697 SetImportLibrary ( new ImportLibrary ( project, e, *this ) );
698 subs_invalid = true;
699 }
700 else if ( e.name == "if" )
701 {
702 parseContext.ifData = new If ( e, project, this );
703 if ( pOldIf )
704 pOldIf->data.ifs.push_back ( parseContext.ifData );
705 else
706 non_if_data.ifs.push_back ( parseContext.ifData );
707 subs_invalid = false;
708 }
709 else if ( e.name == "ifnot" )
710 {
711 parseContext.ifData = new If ( e, project, this, true );
712 if ( pOldIf )
713 pOldIf->data.ifs.push_back ( parseContext.ifData );
714 else
715 non_if_data.ifs.push_back ( parseContext.ifData );
716 subs_invalid = false;
717 }
718 else if ( e.name == "compilerflag" )
719 {
720 CompilerFlag* pCompilerFlag = new CompilerFlag ( project, this, e );
721 if ( parseContext.ifData )
722 parseContext.ifData->data.compilerFlags.push_back ( pCompilerFlag );
723 else
724 non_if_data.compilerFlags.push_back ( pCompilerFlag );
725 subs_invalid = true;
726 }
727 else if ( e.name == "linkerflag" )
728 {
729 linkerFlags.push_back ( new LinkerFlag ( project, this, e ) );
730 subs_invalid = true;
731 }
732 else if ( e.name == "linkerscript" )
733 {
734 if ( linkerScript )
735 {
736 throw XMLInvalidBuildFileException (
737 e.location,
738 "Only one <linkerscript> is valid per module" );
739 }
740 linkerScript = new LinkerScript ( project, this, e );
741 subs_invalid = true;
742 }
743 else if ( e.name == "component" )
744 {
745 stubbedComponents.push_back ( new StubbedComponent ( this, e ) );
746 subs_invalid = false;
747 }
748 else if ( e.name == "property" )
749 {
750 throw XMLInvalidBuildFileException (
751 e.location,
752 "<property> is not a valid sub-element of <module>" );
753 }
754 else if ( e.name == "bootstrap" )
755 {
756 bootstrap = new Bootstrap ( project, this, e );
757 subs_invalid = true;
758 }
759 else if ( e.name == "pch" )
760 {
761 if ( parseContext.ifData )
762 {
763 throw XMLInvalidBuildFileException (
764 e.location,
765 "<pch> is not a valid sub-element of <if>" );
766 }
767 if ( pch )
768 {
769 throw XMLInvalidBuildFileException (
770 e.location,
771 "Only one <pch> is valid per module" );
772 }
773 size_t pos = e.value.find_last_of ( "/\\" );
774 if ( pos == string::npos )
775 {
776 pch = new PchFile (
777 e, *this, FileLocation ( SourceDirectory, relative_path, e.value ) );
778 }
779 else
780 {
781 string dir = e.value.substr ( 0, pos );
782 string name = e.value.substr ( pos + 1);
783 pch = new PchFile (
784 e, *this, FileLocation ( SourceDirectory, relative_path + sSep + dir, name ) );
785 }
786 subs_invalid = true;
787 }
788 else if ( e.name == "compilationunit" )
789 {
790 if ( project.configuration.CompilationUnitsEnabled )
791 {
792 CompilationUnit* pCompilationUnit = new CompilationUnit ( &project, this, &e );
793 if ( parseContext.ifData )
794 parseContext.ifData->data.compilationUnits.push_back ( pCompilationUnit );
795 else
796 non_if_data.compilationUnits.push_back ( pCompilationUnit );
797 parseContext.compilationUnit = pCompilationUnit;
798 }
799 subs_invalid = false;
800 }
801 else if ( e.name == "autoregister" )
802 {
803 if ( autoRegister != NULL)
804 {
805 throw XMLInvalidBuildFileException (
806 e.location,
807 "there can be only one <%s> element for a module",
808 e.name.c_str() );
809 }
810 autoRegister = new AutoRegister ( project, this, e );
811 subs_invalid = true;
812 }
813 if ( subs_invalid && e.subElements.size() > 0 )
814 {
815 throw XMLInvalidBuildFileException (
816 e.location,
817 "<%s> cannot have sub-elements",
818 e.name.c_str() );
819 }
820 for ( size_t i = 0; i < e.subElements.size (); i++ )
821 ProcessXMLSubElement ( *e.subElements[i], subdirectory, subpath, parseContext );
822 parseContext.ifData = pOldIf;
823 parseContext.compilationUnit = pOldCompilationUnit;
824 }
825
826 ModuleType
827 Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
828 {
829 if ( attribute.value == "buildtool" )
830 return BuildTool;
831 if ( attribute.value == "staticlibrary" )
832 return StaticLibrary;
833 if ( attribute.value == "objectlibrary" )
834 return ObjectLibrary;
835 if ( attribute.value == "kernel" )
836 return Kernel;
837 if ( attribute.value == "kernelmodedll" )
838 return KernelModeDLL;
839 if ( attribute.value == "kernelmodedriver" )
840 return KernelModeDriver;
841 if ( attribute.value == "nativedll" )
842 return NativeDLL;
843 if ( attribute.value == "nativecui" )
844 return NativeCUI;
845 if ( attribute.value == "win32dll" )
846 return Win32DLL;
847 if ( attribute.value == "win32ocx" )
848 return Win32OCX;
849 if ( attribute.value == "win32cui" )
850 return Win32CUI;
851 if ( attribute.value == "win32gui" )
852 return Win32GUI;
853 if ( attribute.value == "win32scr" )
854 return Win32SCR;
855 if ( attribute.value == "bootloader" )
856 return BootLoader;
857 if ( attribute.value == "bootsector" )
858 return BootSector;
859 if ( attribute.value == "bootprogram" )
860 return BootProgram;
861 if ( attribute.value == "iso" )
862 return Iso;
863 if ( attribute.value == "liveiso" )
864 return LiveIso;
865 if ( attribute.value == "isoregtest" )
866 return IsoRegTest;
867 if ( attribute.value == "liveisoregtest" )
868 return LiveIsoRegTest;
869 if ( attribute.value == "test" )
870 return Test;
871 if ( attribute.value == "rpcserver" )
872 return RpcServer;
873 if ( attribute.value == "rpcclient" )
874 return RpcClient;
875 if ( attribute.value == "alias" )
876 return Alias;
877 if ( attribute.value == "idlheader" )
878 return IdlHeader;
879 if ( attribute.value == "embeddedtypelib" )
880 return EmbeddedTypeLib;
881 if ( attribute.value == "elfexecutable" )
882 return ElfExecutable;
883 throw InvalidAttributeValueException ( location,
884 attribute.name,
885 attribute.value );
886 }
887
888 DirectoryLocation
889 Module::GetTargetDirectoryTree () const
890 {
891 switch ( type )
892 {
893 case Kernel:
894 case KernelModeDLL:
895 case NativeDLL:
896 case Win32DLL:
897 case Win32OCX:
898 case KernelModeDriver:
899 case NativeCUI:
900 case Win32CUI:
901 case Test:
902 case Win32SCR:
903 case Win32GUI:
904 case BuildTool:
905 case BootLoader:
906 case BootSector:
907 case BootProgram:
908 case Iso:
909 case LiveIso:
910 case IsoRegTest:
911 case LiveIsoRegTest:
912 case EmbeddedTypeLib:
913 case ElfExecutable:
914 return OutputDirectory;
915 case StaticLibrary:
916 case ObjectLibrary:
917 case RpcServer:
918 case RpcClient:
919 case Alias:
920 case IdlHeader:
921 return IntermediateDirectory;
922 }
923 throw InvalidOperationException ( __FILE__,
924 __LINE__,
925 "Invalid module type %d.",
926 type );
927 }
928
929 string
930 Module::GetDefaultModuleExtension () const
931 {
932 switch (type)
933 {
934 case BuildTool:
935 return ExePostfix;
936 case BootProgram:
937 case StaticLibrary:
938 return ".a";
939 case ObjectLibrary:
940 return ".o";
941 case Kernel:
942 case NativeCUI:
943 case Win32CUI:
944 case Win32GUI:
945 return ".exe";
946 case Win32SCR:
947 return ".scr";
948
949 case KernelModeDLL:
950 case NativeDLL:
951 case Win32DLL:
952 return ".dll";
953 case Win32OCX:
954 return ".ocx";
955 case KernelModeDriver:
956 case BootLoader:
957 return ".sys";
958 case BootSector:
959 return ".o";
960 case Iso:
961 case LiveIso:
962 case IsoRegTest:
963 case LiveIsoRegTest:
964 return ".iso";
965 case Test:
966 return ".exe";
967 case RpcServer:
968 return ".o";
969 case RpcClient:
970 return ".o";
971 case Alias:
972 case ElfExecutable:
973 case IdlHeader:
974 return "";
975 case EmbeddedTypeLib:
976 return ".tlb";
977 }
978 throw InvalidOperationException ( __FILE__,
979 __LINE__ );
980 }
981
982 string
983 Module::GetDefaultModuleEntrypoint () const
984 {
985 switch ( type )
986 {
987 case Kernel:
988 return "NtProcessStartup";
989 case KernelModeDLL:
990 case KernelModeDriver:
991 return "DriverEntry@8";
992 case NativeDLL:
993 return "DllMainCRTStartup@12";
994 case NativeCUI:
995 return "NtProcessStartup@4";
996 case Win32DLL:
997 case Win32OCX:
998 return "DllMain@12";
999 case Win32CUI:
1000 case Test:
1001 if ( isUnicode )
1002 return "wmainCRTStartup";
1003 else
1004 return "mainCRTStartup";
1005 case Win32SCR:
1006 case Win32GUI:
1007 if ( isUnicode )
1008 return "wWinMainCRTStartup";
1009 else
1010 return "WinMainCRTStartup";
1011 case BuildTool:
1012 case StaticLibrary:
1013 case ObjectLibrary:
1014 case BootLoader:
1015 case BootSector:
1016 case Iso:
1017 case LiveIso:
1018 case IsoRegTest:
1019 case LiveIsoRegTest:
1020 case RpcServer:
1021 case RpcClient:
1022 case Alias:
1023 case BootProgram:
1024 case IdlHeader:
1025 case ElfExecutable:
1026 case EmbeddedTypeLib:
1027 return "";
1028 }
1029 throw InvalidOperationException ( __FILE__,
1030 __LINE__ );
1031 }
1032
1033 string
1034 Module::GetDefaultModuleBaseaddress () const
1035 {
1036 switch ( type )
1037 {
1038 case Kernel:
1039 return "0x80800000";
1040 case Win32DLL:
1041 case Win32OCX:
1042 return "0x10000000";
1043 case NativeDLL:
1044 case NativeCUI:
1045 case Win32CUI:
1046 case Test:
1047 return "0x00400000";
1048 case Win32SCR:
1049 case Win32GUI:
1050 return "0x00400000";
1051 case KernelModeDLL:
1052 case KernelModeDriver:
1053 return "0x00010000";
1054 case ElfExecutable:
1055 return "0xe00000";
1056 case BuildTool:
1057 case StaticLibrary:
1058 case ObjectLibrary:
1059 case BootLoader:
1060 case BootSector:
1061 case Iso:
1062 case LiveIso:
1063 case IsoRegTest:
1064 case LiveIsoRegTest:
1065 case RpcServer:
1066 case RpcClient:
1067 case Alias:
1068 case BootProgram:
1069 case IdlHeader:
1070 case EmbeddedTypeLib:
1071 return "";
1072 }
1073 throw InvalidOperationException ( __FILE__,
1074 __LINE__ );
1075 }
1076
1077 bool
1078 Module::HasImportLibrary () const
1079 {
1080 return importLibrary != NULL && type != StaticLibrary;
1081 }
1082
1083 bool
1084 Module::IsDLL () const
1085 {
1086 switch ( type )
1087 {
1088 case Kernel:
1089 case KernelModeDLL:
1090 case NativeDLL:
1091 case Win32DLL:
1092 case Win32OCX:
1093 case KernelModeDriver:
1094 return true;
1095 case NativeCUI:
1096 case Win32CUI:
1097 case Test:
1098 case Win32SCR:
1099 case Win32GUI:
1100 case BuildTool:
1101 case StaticLibrary:
1102 case ObjectLibrary:
1103 case BootLoader:
1104 case BootSector:
1105 case BootProgram:
1106 case Iso:
1107 case LiveIso:
1108 case IsoRegTest:
1109 case LiveIsoRegTest:
1110 case RpcServer:
1111 case RpcClient:
1112 case Alias:
1113 case IdlHeader:
1114 case EmbeddedTypeLib:
1115 case ElfExecutable:
1116 return false;
1117 }
1118 throw InvalidOperationException ( __FILE__,
1119 __LINE__ );
1120 }
1121
1122 string
1123 Module::GetPathWithPrefix ( const string& prefix ) const
1124 {
1125 return output->relative_path + cSep + prefix + output->name;
1126 }
1127
1128 string
1129 Module::GetPathToBaseDir () const
1130 {
1131 string temp_path = output->relative_path;
1132 string result = "..\\";
1133 while(temp_path.find ('\\') != string::npos)
1134 {
1135 temp_path.erase (0, temp_path.find('\\')+1);
1136 result += "..\\";
1137 }
1138 return result;
1139 }
1140
1141 string
1142 Module::GetInvocationTarget ( const int index ) const
1143 {
1144 return ssprintf ( "%s_invoke_%d",
1145 name.c_str (),
1146 index );
1147 }
1148
1149 string
1150 Module::GetEntryPoint(bool leadingUnderscore) const
1151 {
1152 string result = "";
1153 if (entrypoint == "0" || entrypoint == "0x0")
1154 return "0";
1155 if (leadingUnderscore)
1156 result = "_";
1157
1158 result += entrypoint;
1159 return result;
1160 }
1161
1162 bool
1163 Module::HasFileWithExtension (
1164 const IfableData& data,
1165 const std::string& extension ) const
1166 {
1167 size_t i;
1168 for ( i = 0; i < data.compilationUnits.size (); i++ )
1169 {
1170 CompilationUnit* compilationUnit = data.compilationUnits[i];
1171 if ( compilationUnit->HasFileWithExtension ( extension ) )
1172 return true;
1173 }
1174 for ( i = 0; i < data.ifs.size (); i++ )
1175 {
1176 if ( HasFileWithExtension ( data.ifs[i]->data, extension ) )
1177 return true;
1178 }
1179 return false;
1180 }
1181
1182 void
1183 Module::InvokeModule () const
1184 {
1185 for ( size_t i = 0; i < invocations.size (); i++ )
1186 {
1187 Invoke& invoke = *invocations[i];
1188 string command = FixSeparatorForSystemCommand(invoke.invokeModule->output->relative_path + "/" + invoke.invokeModule->output->name ) + " " + invoke.GetParameters ();
1189 printf ( "Executing '%s'\n\n", command.c_str () );
1190 int exitcode = system ( command.c_str () );
1191 if ( exitcode != 0 )
1192 throw InvocationFailedException ( command,
1193 exitcode );
1194 }
1195 }
1196
1197
1198 void
1199 Module::SetImportLibrary ( ImportLibrary* importLibrary )
1200 {
1201 this->importLibrary = importLibrary;
1202 dependency = new FileLocation ( IntermediateDirectory,
1203 output->relative_path,
1204 HasImportLibrary () ? "lib" + name + ".a" : output->name );
1205 }
1206
1207
1208 File::File ( DirectoryLocation directory,
1209 const string& relative_path,
1210 const string& name,
1211 bool _first,
1212 const string& _switches,
1213 bool _isPreCompiledHeader )
1214 : file ( directory, relative_path, name ),
1215 first(_first),
1216 switches(_switches),
1217 isPreCompiledHeader(_isPreCompiledHeader)
1218 {
1219 }
1220
1221
1222 void
1223 File::ProcessXML()
1224 {
1225 }
1226
1227
1228 std::string File::GetFullPath () const
1229 {
1230 string directory ( "" );
1231 switch ( file.directory )
1232 {
1233 case SourceDirectory:
1234 break;
1235 case IntermediateDirectory:
1236 directory = Environment::GetIntermediatePath () + sSep;
1237 break;
1238 default:
1239 throw InvalidOperationException ( __FILE__,
1240 __LINE__,
1241 "Invalid directory %d.",
1242 file.directory );
1243 }
1244
1245 if ( file.relative_path.length () > 0 )
1246 directory += file.relative_path + sSep;
1247
1248
1249 return directory + file.name;
1250 }
1251
1252
1253 Library::Library ( const XMLElement& _node,
1254 const Module& _module,
1255 const string& _name )
1256 : node(&_node),
1257 module(_module),
1258 name(_name),
1259 importedModule(_module.project.LocateModule(_name))
1260 {
1261 if ( module.name == name )
1262 {
1263 throw XMLInvalidBuildFileException (
1264 node->location,
1265 "module '%s' cannot link against itself",
1266 name.c_str() );
1267 }
1268 if ( !importedModule )
1269 {
1270 throw XMLInvalidBuildFileException (
1271 node->location,
1272 "module '%s' trying to import non-existant module '%s'",
1273 module.name.c_str(),
1274 name.c_str() );
1275 }
1276 }
1277
1278 Library::Library ( const Module& _module,
1279 const string& _name )
1280 : node(NULL),
1281 module(_module),
1282 name(_name),
1283 importedModule(_module.project.LocateModule(_name))
1284 {
1285 }
1286
1287 void
1288 Library::ProcessXML()
1289 {
1290 if ( node && !module.project.LocateModule ( name ) )
1291 {
1292 throw XMLInvalidBuildFileException (
1293 node->location,
1294 "module '%s' is trying to link against non-existant module '%s'",
1295 module.name.c_str(),
1296 name.c_str() );
1297 }
1298 }
1299
1300
1301 Invoke::Invoke ( const XMLElement& _node,
1302 const Module& _module )
1303 : node (_node),
1304 module (_module)
1305 {
1306 }
1307
1308 void
1309 Invoke::ProcessXML()
1310 {
1311 const XMLAttribute* att = node.GetAttribute ( "module", false );
1312 if (att == NULL)
1313 invokeModule = &module;
1314 else
1315 {
1316 invokeModule = module.project.LocateModule ( att->value );
1317 if ( invokeModule == NULL )
1318 {
1319 throw XMLInvalidBuildFileException (
1320 node.location,
1321 "module '%s' is trying to invoke non-existant module '%s'",
1322 module.name.c_str(),
1323 att->value.c_str() );
1324 }
1325 }
1326
1327 for ( size_t i = 0; i < node.subElements.size (); i++ )
1328 ProcessXMLSubElement ( *node.subElements[i] );
1329 }
1330
1331 void
1332 Invoke::ProcessXMLSubElement ( const XMLElement& e )
1333 {
1334 bool subs_invalid = false;
1335 if ( e.name == "input" )
1336 {
1337 for ( size_t i = 0; i < e.subElements.size (); i++ )
1338 ProcessXMLSubElementInput ( *e.subElements[i] );
1339 }
1340 else if ( e.name == "output" )
1341 {
1342 for ( size_t i = 0; i < e.subElements.size (); i++ )
1343 ProcessXMLSubElementOutput ( *e.subElements[i] );
1344 }
1345 if ( subs_invalid && e.subElements.size() > 0 )
1346 {
1347 throw XMLInvalidBuildFileException (
1348 e.location,
1349 "<%s> cannot have sub-elements",
1350 e.name.c_str() );
1351 }
1352 }
1353
1354 void
1355 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
1356 {
1357 bool subs_invalid = false;
1358 if ( e.name == "inputfile" && e.value.size () > 0 )
1359 {
1360 input.push_back ( new InvokeFile (
1361 e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
1362 subs_invalid = true;
1363 }
1364 if ( subs_invalid && e.subElements.size() > 0 )
1365 {
1366 throw XMLInvalidBuildFileException (
1367 e.location,
1368 "<%s> cannot have sub-elements",
1369 e.name.c_str() );
1370 }
1371 }
1372
1373 void
1374 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
1375 {
1376 bool subs_invalid = false;
1377 if ( e.name == "outputfile" && e.value.size () > 0 )
1378 {
1379 output.push_back ( new InvokeFile (
1380 e, FixSeparator ( module.output->relative_path + cSep + e.value ) ) );
1381 subs_invalid = true;
1382 }
1383 if ( subs_invalid && e.subElements.size() > 0 )
1384 {
1385 throw XMLInvalidBuildFileException (
1386 e.location,
1387 "<%s> cannot have sub-elements",
1388 e.name.c_str() );
1389 }
1390 }
1391
1392 void
1393 Invoke::GetTargets ( string_list& targets ) const
1394 {
1395 for ( size_t i = 0; i < output.size (); i++ )
1396 {
1397 InvokeFile& file = *output[i];
1398 targets.push_back ( NormalizeFilename ( file.name ) );
1399 }
1400 }
1401
1402 string
1403 Invoke::GetParameters () const
1404 {
1405 string parameters ( "" );
1406 size_t i;
1407 for ( i = 0; i < output.size (); i++ )
1408 {
1409 if ( parameters.length () > 0)
1410 parameters += " ";
1411 InvokeFile& invokeFile = *output[i];
1412 if ( invokeFile.switches.length () > 0 )
1413 {
1414 parameters += invokeFile.switches + " ";
1415 }
1416 parameters += invokeFile.name;
1417 }
1418
1419 for ( i = 0; i < input.size (); i++ )
1420 {
1421 if ( parameters.length () > 0 )
1422 parameters += " ";
1423 InvokeFile& invokeFile = *input[i];
1424 if ( invokeFile.switches.length () > 0 )
1425 {
1426 parameters += invokeFile.switches;
1427 parameters += " ";
1428 }
1429 parameters += invokeFile.name ;
1430 }
1431
1432 return parameters;
1433 }
1434
1435
1436 InvokeFile::InvokeFile ( const XMLElement& _node,
1437 const string& _name )
1438 : node (_node),
1439 name (_name)
1440 {
1441 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
1442 if (att != NULL)
1443 switches = att->value;
1444 else
1445 switches = "";
1446 }
1447
1448 void
1449 InvokeFile::ProcessXML()
1450 {
1451 }
1452
1453
1454 Dependency::Dependency ( const XMLElement& _node,
1455 const Module& _module )
1456 : node (_node),
1457 module (_module),
1458 dependencyModule (NULL)
1459 {
1460 }
1461
1462 void
1463 Dependency::ProcessXML()
1464 {
1465 dependencyModule = module.project.LocateModule ( node.value );
1466 if ( dependencyModule == NULL )
1467 {
1468 throw XMLInvalidBuildFileException (
1469 node.location,
1470 "module '%s' depend on non-existant module '%s'",
1471 module.name.c_str(),
1472 node.value.c_str() );
1473 }
1474 }
1475
1476
1477 Metadata::Metadata ( const XMLElement& _node,
1478 const Module& _module )
1479 : node (_node),
1480 module (_module)
1481 {
1482 /* The module name */
1483 const XMLAttribute* att = _node.GetAttribute ( "name", false );
1484 if (att != NULL)
1485 name = att->value;
1486 else
1487 name = module.name;
1488
1489 /* The module description */
1490 att = _node.GetAttribute ( "description", false );
1491 if (att != NULL)
1492 description = att->value;
1493 else
1494 description = "";
1495
1496 /* The module version */
1497 att = _node.GetAttribute ( "version", false );
1498 if (att != NULL)
1499 version = att->value;
1500 else
1501 version = "";
1502
1503 /* The module copyright */
1504 att = _node.GetAttribute ( "copyright", false );
1505 if (att != NULL)
1506 copyright = att->value;
1507 else
1508 copyright = "";
1509
1510 att = _node.GetAttribute ( "url", false );
1511 if (att != NULL)
1512 url = att->value;
1513 else
1514 url = "";
1515
1516 /* When was this module updated */
1517 att = _node.GetAttribute ( "date", false );
1518 if (att != NULL)
1519 date = att->value;
1520 else
1521 date = "?";
1522
1523 /* When was this module updated */
1524 att = _node.GetAttribute ( "owner", false );
1525 if (att != NULL)
1526 owner = att->value;
1527 else
1528 owner = "ReactOS";
1529 }
1530
1531
1532 ImportLibrary::ImportLibrary ( const Project& project,
1533 const XMLElement& node,
1534 const Module& module )
1535 : XmlNode ( project, node ),
1536 module (module)
1537 {
1538 const XMLAttribute* dllname = node.GetAttribute ( "dllname", false );
1539 const XMLAttribute* definition = node.GetAttribute ( "definition", true );
1540 assert ( definition );
1541
1542 if ( dllname )
1543 this->dllname = dllname->value;
1544 else if ( module.type == StaticLibrary )
1545 throw XMLInvalidBuildFileException (
1546 node.location,
1547 "<importlibrary> dllname attribute required." );
1548
1549 DirectoryLocation directory = SourceDirectory;
1550 size_t index = definition->value.rfind ( ".spec.def" );
1551 if ( index != string::npos )
1552 directory = IntermediateDirectory;
1553
1554 index = definition->value.find_last_of ( "/\\" );
1555 if ( index == string::npos )
1556 {
1557 source = new FileLocation ( directory,
1558 module.output->relative_path,
1559 definition->value );
1560 }
1561 else
1562 {
1563 string dir = definition->value.substr ( 0, index );
1564 string name = definition->value.substr ( index + 1);
1565 source = new FileLocation ( directory,
1566 NormalizeFilename ( module.output->relative_path + sSep + dir ),
1567 name );
1568 }
1569 }
1570
1571
1572 If::If ( const XMLElement& node_,
1573 const Project& project_,
1574 const Module* module_,
1575 const bool negated_ )
1576 : node(node_), project(project_), module(module_), negated(negated_)
1577 {
1578 const XMLAttribute* att;
1579
1580 att = node.GetAttribute ( "property", true );
1581 assert(att);
1582 property = att->value;
1583
1584 att = node.GetAttribute ( "value", true );
1585 assert(att);
1586 value = att->value;
1587 }
1588
1589 If::~If ()
1590 {
1591 }
1592
1593 void
1594 If::ProcessXML()
1595 {
1596
1597 }
1598
1599
1600 Property::Property ( const XMLElement& node_,
1601 const Project& project_,
1602 const Module* module_ )
1603 : project(project_), module(module_)
1604 {
1605 const XMLAttribute* att;
1606
1607 att = node_.GetAttribute ( "name", true );
1608 assert(att);
1609 name = project.ResolveProperties ( att->value );
1610
1611 att = node_.GetAttribute ( "value", true );
1612 assert(att);
1613 value = att->value;
1614 }
1615
1616 Property::Property ( const Project& project_,
1617 const Module* module_,
1618 const std::string& name_,
1619 const std::string& value_ )
1620 : project(project_), module(module_), name(name_), value(value_)
1621 {
1622 }
1623
1624 void
1625 Property::ProcessXML()
1626 {
1627 }
1628
1629
1630 PchFile::PchFile (
1631 const XMLElement& node_,
1632 const Module& module_,
1633 const FileLocation& file_ )
1634 : node(node_), module(module_), file(file_)
1635 {
1636 }
1637
1638 void
1639 PchFile::ProcessXML()
1640 {
1641 }