10 FixSeparator ( const string
& s
)
13 char* p
= strchr ( &s2
[0], CBAD_SEP
);
17 p
= strchr ( p
, CBAD_SEP
);
24 const string
& filename
,
25 const string
& newExtension
)
27 size_t index
= filename
.find_last_of ( '/' );
28 if ( index
== string::npos
)
30 size_t index2
= filename
.find_last_of ( '\\' );
31 if ( index2
!= string::npos
&& index2
> index
)
33 string tmp
= filename
.substr( index
/*, filename.size() - index*/ );
34 size_t ext_index
= tmp
.find_last_of( '.' );
35 if ( ext_index
!= string::npos
)
36 return filename
.substr ( 0, index
+ ext_index
) + newExtension
;
37 return filename
+ newExtension
;
42 const string
& location
,
44 const string
& att_value
)
46 if ( !att_value
.size() )
47 throw InvalidBuildFileException (
49 "<directory> tag has empty 'name' attribute" );
50 if ( strpbrk ( att_value
.c_str (), "/\\?*:<>|" ) )
51 throw InvalidBuildFileException (
53 "<directory> tag has invalid characters in 'name' attribute" );
56 return FixSeparator(path
+ CSEP
+ att_value
);
60 GetExtension ( const string
& filename
)
62 size_t index
= filename
.find_last_of ( '/' );
63 if (index
== string::npos
) index
= 0;
64 string tmp
= filename
.substr( index
, filename
.size() - index
);
65 size_t ext_index
= tmp
.find_last_of( '.' );
66 if (ext_index
!= string::npos
)
67 return filename
.substr ( index
+ ext_index
, filename
.size() );
72 GetDirectory ( const string
& filename
)
74 size_t index
= filename
.find_last_of ( CSEP
);
75 if ( index
== string::npos
)
78 return filename
.substr ( 0, index
);
82 NormalizeFilename ( const string
& filename
)
85 string normalizedPath
= path
.Fixup ( filename
, true );
86 string relativeNormalizedPath
= path
.RelativeFromWorkingDirectory ( normalizedPath
);
87 return FixSeparator ( relativeNormalizedPath
);
90 IfableData::~IfableData()
93 for ( i
= 0; i
< files
.size(); i
++ )
95 for ( i
= 0; i
< includes
.size(); i
++ )
97 for ( i
= 0; i
< defines
.size(); i
++ )
99 for ( i
= 0; i
< libraries
.size(); i
++ )
101 for ( i
= 0; i
< properties
.size(); i
++ )
102 delete properties
[i
];
103 for ( i
= 0; i
< ifs
.size(); i
++ )
107 void IfableData::ProcessXML ()
110 for ( i
= 0; i
< files
.size (); i
++ )
111 files
[i
]->ProcessXML ();
112 for ( i
= 0; i
< includes
.size (); i
++ )
113 includes
[i
]->ProcessXML ();
114 for ( i
= 0; i
< defines
.size (); i
++ )
115 defines
[i
]->ProcessXML ();
116 for ( i
= 0; i
< libraries
.size (); i
++ )
117 libraries
[i
]->ProcessXML ();
118 for ( i
= 0; i
< properties
.size(); i
++ )
119 properties
[i
]->ProcessXML ();
120 for ( i
= 0; i
< ifs
.size (); i
++ )
121 ifs
[i
]->ProcessXML ();
124 Module::Module ( const Project
& project
,
125 const XMLElement
& moduleNode
,
126 const string
& modulePath
)
129 importLibrary (NULL
),
135 if ( node
.name
!= "module" )
136 throw InvalidOperationException ( __FILE__
,
138 "Module created with non-<module> node" );
140 xmlbuildFile
= Path::RelativeFromWorkingDirectory ( moduleNode
.xmlFile
->filename() );
142 path
= FixSeparator ( modulePath
);
144 const XMLAttribute
* att
= moduleNode
.GetAttribute ( "name", true );
148 att
= moduleNode
.GetAttribute ( "type", true );
150 type
= GetModuleType ( node
.location
, *att
);
152 att
= moduleNode
.GetAttribute ( "extension", false );
154 extension
= att
->value
;
156 extension
= GetDefaultModuleExtension ();
158 att
= moduleNode
.GetAttribute ( "entrypoint", false );
160 entrypoint
= att
->value
;
162 entrypoint
= GetDefaultModuleEntrypoint ();
164 att
= moduleNode
.GetAttribute ( "baseaddress", false );
166 baseaddress
= att
->value
;
168 baseaddress
= GetDefaultModuleBaseaddress ();
170 att
= moduleNode
.GetAttribute ( "mangledsymbols", false );
173 const char* p
= att
->value
.c_str();
174 if ( !stricmp ( p
, "true" ) || !stricmp ( p
, "yes" ) )
175 mangledSymbols
= true;
176 else if ( !stricmp ( p
, "false" ) || !stricmp ( p
, "no" ) )
177 mangledSymbols
= false;
180 throw InvalidAttributeValueException (
187 mangledSymbols
= false;
189 att
= moduleNode
.GetAttribute ( "host", false );
192 const char* p
= att
->value
.c_str();
193 if ( !stricmp ( p
, "true" ) || !stricmp ( p
, "yes" ) )
195 else if ( !stricmp ( p
, "false" ) || !stricmp ( p
, "no" ) )
199 throw InvalidAttributeValueException (
206 att
= moduleNode
.GetAttribute ( "prefix", false );
210 att
= moduleNode
.GetAttribute ( "installbase", false );
212 installBase
= att
->value
;
216 att
= moduleNode
.GetAttribute ( "installname", false );
218 installName
= att
->value
;
222 att
= moduleNode
.GetAttribute ( "usewrc", false );
224 useWRC
= att
->value
== "true";
228 att
= moduleNode
.GetAttribute ( "warnings", false );
230 enableWarnings
= att
->value
== "true";
232 enableWarnings
= false;
238 for ( i
= 0; i
< invocations
.size(); i
++ )
239 delete invocations
[i
];
240 for ( i
= 0; i
< dependencies
.size(); i
++ )
241 delete dependencies
[i
];
242 for ( i
= 0; i
< compilerFlags
.size(); i
++ )
243 delete compilerFlags
[i
];
244 for ( i
= 0; i
< linkerFlags
.size(); i
++ )
245 delete linkerFlags
[i
];
246 for ( i
= 0; i
< stubbedComponents
.size(); i
++ )
247 delete stubbedComponents
[i
];
256 for ( i
= 0; i
< node
.subElements
.size(); i
++ )
257 ProcessXMLSubElement ( *node
.subElements
[i
], path
);
258 for ( i
= 0; i
< invocations
.size(); i
++ )
259 invocations
[i
]->ProcessXML ();
260 for ( i
= 0; i
< dependencies
.size(); i
++ )
261 dependencies
[i
]->ProcessXML ();
262 for ( i
= 0; i
< compilerFlags
.size(); i
++ )
263 compilerFlags
[i
]->ProcessXML();
264 for ( i
= 0; i
< linkerFlags
.size(); i
++ )
265 linkerFlags
[i
]->ProcessXML();
266 for ( i
= 0; i
< stubbedComponents
.size(); i
++ )
267 stubbedComponents
[i
]->ProcessXML();
268 non_if_data
.ProcessXML();
274 Module::ProcessXMLSubElement ( const XMLElement
& e
,
278 bool subs_invalid
= false;
279 string
subpath ( path
);
280 if ( e
.name
== "file" && e
.value
.size () > 0 )
283 const XMLAttribute
* att
= e
.GetAttribute ( "first", false );
286 if ( !stricmp ( att
->value
.c_str(), "true" ) )
288 else if ( stricmp ( att
->value
.c_str(), "false" ) )
289 throw InvalidBuildFileException (
291 "attribute 'first' of <file> element can only be 'true' or 'false'" );
293 string switches
= "";
294 att
= e
.GetAttribute ( "switches", false );
296 switches
= att
->value
;
299 // check for c++ file
300 string ext
= GetExtension ( e
.value
);
301 if ( !stricmp ( ext
.c_str(), ".cpp" ) )
303 else if ( !stricmp ( ext
.c_str(), ".cc" ) )
305 else if ( !stricmp ( ext
.c_str(), ".cxx" ) )
308 File
* pFile
= new File ( FixSeparator ( path
+ CSEP
+ e
.value
),
312 pIf
->data
.files
.push_back ( pFile
);
314 non_if_data
.files
.push_back ( pFile
);
317 else if ( e
.name
== "library" && e
.value
.size () )
319 Library
* pLibrary
= new Library ( e
, *this, e
.value
);
321 pIf
->data
.libraries
.push_back ( pLibrary
);
323 non_if_data
.libraries
.push_back ( pLibrary
);
326 else if ( e
.name
== "directory" )
328 const XMLAttribute
* att
= e
.GetAttribute ( "name", true );
330 subpath
= GetSubPath ( e
.location
, path
, att
->value
);
332 else if ( e
.name
== "include" )
334 Include
* include
= new Include ( project
, this, e
);
336 pIf
->data
.includes
.push_back ( include
);
338 non_if_data
.includes
.push_back ( include
);
341 else if ( e
.name
== "define" )
343 Define
* pDefine
= new Define ( project
, this, e
);
345 pIf
->data
.defines
.push_back ( pDefine
);
347 non_if_data
.defines
.push_back ( pDefine
);
350 else if ( e
.name
== "invoke" )
353 throw InvalidBuildFileException (
355 "<invoke> is not a valid sub-element of <if>" );
356 invocations
.push_back ( new Invoke ( e
, *this ) );
357 subs_invalid
= false;
359 else if ( e
.name
== "dependency" )
362 throw InvalidBuildFileException (
364 "<dependency> is not a valid sub-element of <if>" );
365 dependencies
.push_back ( new Dependency ( e
, *this ) );
368 else if ( e
.name
== "importlibrary" )
371 throw InvalidBuildFileException (
373 "<importlibrary> is not a valid sub-element of <if>" );
375 throw InvalidBuildFileException (
377 "Only one <importlibrary> is valid per module" );
378 importLibrary
= new ImportLibrary ( e
, *this );
381 else if ( e
.name
== "if" )
384 pIf
= new If ( e
, project
, this );
386 pOldIf
->data
.ifs
.push_back ( pIf
);
388 non_if_data
.ifs
.push_back ( pIf
);
389 subs_invalid
= false;
391 else if ( e
.name
== "compilerflag" )
393 compilerFlags
.push_back ( new CompilerFlag ( project
, this, e
) );
396 else if ( e
.name
== "linkerflag" )
398 linkerFlags
.push_back ( new LinkerFlag ( project
, this, e
) );
401 else if ( e
.name
== "component" )
403 stubbedComponents
.push_back ( new StubbedComponent ( this, e
) );
404 subs_invalid
= false;
406 else if ( e
.name
== "property" )
408 throw InvalidBuildFileException (
410 "<property> is not a valid sub-element of <module>" );
412 else if ( e
.name
== "bootstrap" )
414 bootstrap
= new Bootstrap ( project
, this, e
);
417 else if ( e
.name
== "pch" )
420 throw InvalidBuildFileException (
422 "<pch> is not a valid sub-element of <if>" );
424 throw InvalidBuildFileException (
426 "Only one <pch> is valid per module" );
428 e
, *this, FixSeparator ( path
+ CSEP
+ e
.value
) );
431 if ( subs_invalid
&& e
.subElements
.size() > 0 )
432 throw InvalidBuildFileException (
434 "<%s> cannot have sub-elements",
436 for ( size_t i
= 0; i
< e
.subElements
.size (); i
++ )
437 ProcessXMLSubElement ( *e
.subElements
[i
], subpath
, pIf
);
441 Module::GetModuleType ( const string
& location
, const XMLAttribute
& attribute
)
443 if ( attribute
.value
== "buildtool" )
445 if ( attribute
.value
== "staticlibrary" )
446 return StaticLibrary
;
447 if ( attribute
.value
== "objectlibrary" )
448 return ObjectLibrary
;
449 if ( attribute
.value
== "kernel" )
451 if ( attribute
.value
== "kernelmodedll" )
452 return KernelModeDLL
;
453 if ( attribute
.value
== "kernelmodedriver" )
454 return KernelModeDriver
;
455 if ( attribute
.value
== "nativedll" )
457 if ( attribute
.value
== "nativecui" )
459 if ( attribute
.value
== "win32dll" )
461 if ( attribute
.value
== "win32cui" )
463 if ( attribute
.value
== "win32gui" )
465 if ( attribute
.value
== "bootloader" )
467 if ( attribute
.value
== "bootsector" )
469 if ( attribute
.value
== "iso" )
471 if ( attribute
.value
== "liveiso" )
473 if ( attribute
.value
== "test" )
475 if ( attribute
.value
== "rpcserver" )
477 if ( attribute
.value
== "rpcclient" )
479 throw InvalidAttributeValueException ( location
,
485 Module::GetDefaultModuleExtension () const
504 case KernelModeDriver
:
519 throw InvalidOperationException ( __FILE__
,
524 Module::GetDefaultModuleEntrypoint () const
529 return "_NtProcessStartup";
531 return "_DriverEntry@8";
533 return "_DllMainCRTStartup@12";
535 return "_NtProcessStartup@4";
537 return "_DllMain@12";
540 return "_mainCRTStartup";
542 return "_WinMainCRTStartup";
543 case KernelModeDriver
:
544 return "_DriverEntry@8";
556 throw InvalidOperationException ( __FILE__
,
561 Module::GetDefaultModuleBaseaddress () const
580 case KernelModeDriver
:
593 throw InvalidOperationException ( __FILE__
,
598 Module::HasImportLibrary () const
600 return importLibrary
!= NULL
;
604 Module::GetTargetName () const
606 return name
+ extension
;
610 Module::GetDependencyPath () const
612 if ( HasImportLibrary () )
614 return ReplaceExtension ( GetPath(), ".a" );
621 Module::GetBasePath () const
627 Module::GetPath () const
629 if ( path
.length() > 0 )
630 return path
+ CSEP
+ GetTargetName ();
632 return GetTargetName ();
636 Module::GetPathWithPrefix ( const string
& prefix
) const
638 return path
+ CSEP
+ prefix
+ GetTargetName ();
642 Module::GetInvocationTarget ( const int index
) const
644 return ssprintf ( "%s_invoke_%d",
650 Module::HasFileWithExtension (
651 const IfableData
& data
,
652 const std::string
& extension
) const
655 for ( i
= 0; i
< data
.files
.size (); i
++ )
657 File
& file
= *data
.files
[i
];
658 string file_ext
= GetExtension ( file
.name
);
659 if ( !stricmp ( file_ext
.c_str (), extension
.c_str () ) )
662 for ( i
= 0; i
< data
.ifs
.size (); i
++ )
664 if ( HasFileWithExtension ( data
.ifs
[i
]->data
, extension
) )
671 Module::InvokeModule () const
673 for ( size_t i
= 0; i
< invocations
.size (); i
++ )
675 Invoke
& invoke
= *invocations
[i
];
676 string command
= invoke
.invokeModule
->GetPath () + " " + invoke
.GetParameters ();
677 printf ( "Executing '%s'\n\n", command
.c_str () );
678 int exitcode
= system ( command
.c_str () );
680 throw InvocationFailedException ( command
,
686 File::File ( const string
& _name
, bool _first
,
687 std::string _switches
)
700 Library::Library ( const XMLElement
& _node
,
701 const Module
& _module
,
702 const string
& _name
)
706 imported_module(_module
.project
.LocateModule(_name
))
708 if ( module
.name
== name
)
709 throw InvalidBuildFileException (
711 "module '%s' cannot link against itself",
713 if ( !imported_module
)
714 throw InvalidBuildFileException (
716 "module '%s' trying to import non-existant module '%s'",
722 Library::ProcessXML()
724 if ( !module
.project
.LocateModule ( name
) )
725 throw InvalidBuildFileException (
727 "module '%s' is trying to link against non-existant module '%s'",
733 Invoke::Invoke ( const XMLElement
& _node
,
734 const Module
& _module
)
743 const XMLAttribute
* att
= node
.GetAttribute ( "module", false );
745 invokeModule
= &module
;
748 invokeModule
= module
.project
.LocateModule ( att
->value
);
749 if ( invokeModule
== NULL
)
750 throw InvalidBuildFileException (
752 "module '%s' is trying to invoke non-existant module '%s'",
754 att
->value
.c_str() );
757 for ( size_t i
= 0; i
< node
.subElements
.size (); i
++ )
758 ProcessXMLSubElement ( *node
.subElements
[i
] );
762 Invoke::ProcessXMLSubElement ( const XMLElement
& e
)
764 bool subs_invalid
= false;
765 if ( e
.name
== "input" )
767 for ( size_t i
= 0; i
< e
.subElements
.size (); i
++ )
768 ProcessXMLSubElementInput ( *e
.subElements
[i
] );
770 else if ( e
.name
== "output" )
772 for ( size_t i
= 0; i
< e
.subElements
.size (); i
++ )
773 ProcessXMLSubElementOutput ( *e
.subElements
[i
] );
775 if ( subs_invalid
&& e
.subElements
.size() > 0 )
776 throw InvalidBuildFileException ( e
.location
,
777 "<%s> cannot have sub-elements",
782 Invoke::ProcessXMLSubElementInput ( const XMLElement
& e
)
784 bool subs_invalid
= false;
785 if ( e
.name
== "inputfile" && e
.value
.size () > 0 )
787 input
.push_back ( new InvokeFile ( e
, FixSeparator ( module
.path
+ CSEP
+ e
.value
) ) );
790 if ( subs_invalid
&& e
.subElements
.size() > 0 )
791 throw InvalidBuildFileException ( e
.location
,
792 "<%s> cannot have sub-elements",
797 Invoke::ProcessXMLSubElementOutput ( const XMLElement
& e
)
799 bool subs_invalid
= false;
800 if ( e
.name
== "outputfile" && e
.value
.size () > 0 )
802 output
.push_back ( new InvokeFile ( e
, FixSeparator ( module
.path
+ CSEP
+ e
.value
) ) );
805 if ( subs_invalid
&& e
.subElements
.size() > 0 )
806 throw InvalidBuildFileException (
808 "<%s> cannot have sub-elements",
813 Invoke::GetTargets ( string_list
& targets
) const
815 for ( size_t i
= 0; i
< output
.size (); i
++ )
817 InvokeFile
& file
= *output
[i
];
818 targets
.push_back ( NormalizeFilename ( file
.name
) );
823 Invoke::GetParameters () const
825 string
parameters ( "" );
827 for ( i
= 0; i
< output
.size (); i
++ )
829 if ( parameters
.length () > 0)
831 InvokeFile
& invokeFile
= *output
[i
];
832 if ( invokeFile
.switches
.length () > 0 )
834 parameters
+= invokeFile
.switches
+ " ";
836 parameters
+= invokeFile
.name
;
839 for ( i
= 0; i
< input
.size (); i
++ )
841 if ( parameters
.length () > 0 )
843 InvokeFile
& invokeFile
= *input
[i
];
844 if ( invokeFile
.switches
.length () > 0 )
846 parameters
+= invokeFile
.switches
;
849 parameters
+= invokeFile
.name
;
856 InvokeFile::InvokeFile ( const XMLElement
& _node
,
857 const string
& _name
)
861 const XMLAttribute
* att
= _node
.GetAttribute ( "switches", false );
863 switches
= att
->value
;
869 InvokeFile::ProcessXML()
874 Dependency::Dependency ( const XMLElement
& _node
,
875 const Module
& _module
)
878 dependencyModule (NULL
)
883 Dependency::ProcessXML()
885 dependencyModule
= module
.project
.LocateModule ( node
.value
);
886 if ( dependencyModule
== NULL
)
887 throw InvalidBuildFileException ( node
.location
,
888 "module '%s' depend on non-existant module '%s'",
890 node
.value
.c_str() );
894 ImportLibrary::ImportLibrary ( const XMLElement
& _node
,
895 const Module
& _module
)
899 const XMLAttribute
* att
= _node
.GetAttribute ( "basename", false );
901 basename
= att
->value
;
903 basename
= module
.name
;
905 att
= _node
.GetAttribute ( "definition", true );
907 definition
= FixSeparator(att
->value
);
911 If::If ( const XMLElement
& node_
,
912 const Project
& project_
,
913 const Module
* module_
)
914 : node(node_
), project(project_
), module(module_
)
916 const XMLAttribute
* att
;
918 att
= node
.GetAttribute ( "property", true );
920 property
= att
->value
;
922 att
= node
.GetAttribute ( "value", true );
937 Property::Property ( const XMLElement
& node_
,
938 const Project
& project_
,
939 const Module
* module_
)
940 : node(node_
), project(project_
), module(module_
)
942 const XMLAttribute
* att
;
944 att
= node
.GetAttribute ( "name", true );
948 att
= node
.GetAttribute ( "value", true );
954 Property::ProcessXML()
960 const XMLElement
& node_
,
961 const Module
& module_
,
962 const string
& header_
)
963 : node(node_
), module(module_
), header(header_
)
968 PchFile::ProcessXML()