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 GetFilename ( const string
& filename
)
84 size_t index
= filename
.find_last_of ( CSEP
);
85 if ( index
== string::npos
)
88 return filename
.substr ( index
+ 1, filename
.length () - index
);
92 NormalizeFilename ( const string
& filename
)
97 string normalizedPath
= path
.Fixup ( filename
, true );
98 string relativeNormalizedPath
= path
.RelativeFromWorkingDirectory ( normalizedPath
);
99 return FixSeparator ( relativeNormalizedPath
);
103 GetBooleanValue ( const string
& value
)
111 IfableData::~IfableData()
114 for ( i
= 0; i
< files
.size(); i
++ )
116 for ( i
= 0; i
< includes
.size(); i
++ )
118 for ( i
= 0; i
< defines
.size(); i
++ )
120 for ( i
= 0; i
< libraries
.size(); i
++ )
122 for ( i
= 0; i
< properties
.size(); i
++ )
123 delete properties
[i
];
124 for ( i
= 0; i
< compilerFlags
.size(); i
++ )
125 delete compilerFlags
[i
];
126 for ( i
= 0; i
< ifs
.size(); i
++ )
130 void IfableData::ProcessXML ()
133 for ( i
= 0; i
< files
.size (); i
++ )
134 files
[i
]->ProcessXML ();
135 for ( i
= 0; i
< includes
.size (); i
++ )
136 includes
[i
]->ProcessXML ();
137 for ( i
= 0; i
< defines
.size (); i
++ )
138 defines
[i
]->ProcessXML ();
139 for ( i
= 0; i
< libraries
.size (); i
++ )
140 libraries
[i
]->ProcessXML ();
141 for ( i
= 0; i
< properties
.size(); i
++ )
142 properties
[i
]->ProcessXML ();
143 for ( i
= 0; i
< compilerFlags
.size(); i
++ )
144 compilerFlags
[i
]->ProcessXML ();
145 for ( i
= 0; i
< ifs
.size (); i
++ )
146 ifs
[i
]->ProcessXML ();
149 Module::Module ( const Project
& project
,
150 const XMLElement
& moduleNode
,
151 const string
& modulePath
)
154 importLibrary (NULL
),
160 if ( node
.name
!= "module" )
161 throw InvalidOperationException ( __FILE__
,
163 "Module created with non-<module> node" );
165 xmlbuildFile
= Path::RelativeFromWorkingDirectory ( moduleNode
.xmlFile
->filename () );
167 path
= FixSeparator ( modulePath
);
171 const XMLAttribute
* att
= moduleNode
.GetAttribute ( "if", false );
173 enabled
= GetBooleanValue ( project
.ResolveProperties ( att
->value
) );
175 att
= moduleNode
.GetAttribute ( "ifnot", false );
177 enabled
= !GetBooleanValue ( project
.ResolveProperties ( att
->value
) );
179 att
= moduleNode
.GetAttribute ( "name", true );
183 att
= moduleNode
.GetAttribute ( "type", true );
185 type
= GetModuleType ( node
.location
, *att
);
187 att
= moduleNode
.GetAttribute ( "extension", false );
189 extension
= att
->value
;
191 extension
= GetDefaultModuleExtension ();
193 att
= moduleNode
.GetAttribute ( "entrypoint", false );
195 entrypoint
= att
->value
;
197 entrypoint
= GetDefaultModuleEntrypoint ();
199 att
= moduleNode
.GetAttribute ( "baseaddress", false );
201 baseaddress
= att
->value
;
203 baseaddress
= GetDefaultModuleBaseaddress ();
205 att
= moduleNode
.GetAttribute ( "mangledsymbols", false );
208 const char* p
= att
->value
.c_str();
209 if ( !stricmp ( p
, "true" ) || !stricmp ( p
, "yes" ) )
210 mangledSymbols
= true;
211 else if ( !stricmp ( p
, "false" ) || !stricmp ( p
, "no" ) )
212 mangledSymbols
= false;
215 throw InvalidAttributeValueException (
222 mangledSymbols
= false;
224 att
= moduleNode
.GetAttribute ( "host", false );
227 const char* p
= att
->value
.c_str();
228 if ( !stricmp ( p
, "true" ) || !stricmp ( p
, "yes" ) )
230 else if ( !stricmp ( p
, "false" ) || !stricmp ( p
, "no" ) )
234 throw InvalidAttributeValueException (
241 att
= moduleNode
.GetAttribute ( "prefix", false );
245 att
= moduleNode
.GetAttribute ( "installbase", false );
247 installBase
= att
->value
;
251 att
= moduleNode
.GetAttribute ( "installname", false );
253 installName
= att
->value
;
257 att
= moduleNode
.GetAttribute ( "usewrc", false );
259 useWRC
= att
->value
== "true";
263 att
= moduleNode
.GetAttribute ( "warnings", false );
265 enableWarnings
= att
->value
== "true";
267 enableWarnings
= false;
273 for ( i
= 0; i
< invocations
.size(); i
++ )
274 delete invocations
[i
];
275 for ( i
= 0; i
< dependencies
.size(); i
++ )
276 delete dependencies
[i
];
277 for ( i
= 0; i
< compilerFlags
.size(); i
++ )
278 delete compilerFlags
[i
];
279 for ( i
= 0; i
< linkerFlags
.size(); i
++ )
280 delete linkerFlags
[i
];
281 for ( i
= 0; i
< stubbedComponents
.size(); i
++ )
282 delete stubbedComponents
[i
];
291 for ( i
= 0; i
< node
.subElements
.size(); i
++ )
292 ProcessXMLSubElement ( *node
.subElements
[i
], path
);
293 for ( i
= 0; i
< invocations
.size(); i
++ )
294 invocations
[i
]->ProcessXML ();
295 for ( i
= 0; i
< dependencies
.size(); i
++ )
296 dependencies
[i
]->ProcessXML ();
297 for ( i
= 0; i
< compilerFlags
.size(); i
++ )
298 compilerFlags
[i
]->ProcessXML();
299 for ( i
= 0; i
< linkerFlags
.size(); i
++ )
300 linkerFlags
[i
]->ProcessXML();
301 for ( i
= 0; i
< stubbedComponents
.size(); i
++ )
302 stubbedComponents
[i
]->ProcessXML();
303 non_if_data
.ProcessXML();
309 Module::ProcessXMLSubElement ( const XMLElement
& e
,
313 bool subs_invalid
= false;
314 string
subpath ( path
);
315 if ( e
.name
== "file" && e
.value
.size () > 0 )
318 const XMLAttribute
* att
= e
.GetAttribute ( "first", false );
321 if ( !stricmp ( att
->value
.c_str(), "true" ) )
323 else if ( stricmp ( att
->value
.c_str(), "false" ) )
324 throw InvalidBuildFileException (
326 "attribute 'first' of <file> element can only be 'true' or 'false'" );
328 string switches
= "";
329 att
= e
.GetAttribute ( "switches", false );
331 switches
= att
->value
;
334 // check for c++ file
335 string ext
= GetExtension ( e
.value
);
336 if ( !stricmp ( ext
.c_str(), ".cpp" ) )
338 else if ( !stricmp ( ext
.c_str(), ".cc" ) )
340 else if ( !stricmp ( ext
.c_str(), ".cxx" ) )
343 File
* pFile
= new File ( FixSeparator ( path
+ CSEP
+ e
.value
),
348 pIf
->data
.files
.push_back ( pFile
);
350 non_if_data
.files
.push_back ( pFile
);
353 else if ( e
.name
== "library" && e
.value
.size () )
355 Library
* pLibrary
= new Library ( e
, *this, e
.value
);
357 pIf
->data
.libraries
.push_back ( pLibrary
);
359 non_if_data
.libraries
.push_back ( pLibrary
);
362 else if ( e
.name
== "directory" )
364 const XMLAttribute
* att
= e
.GetAttribute ( "name", true );
366 subpath
= GetSubPath ( e
.location
, path
, att
->value
);
368 else if ( e
.name
== "include" )
370 Include
* include
= new Include ( project
, this, &e
);
372 pIf
->data
.includes
.push_back ( include
);
374 non_if_data
.includes
.push_back ( include
);
377 else if ( e
.name
== "define" )
379 Define
* pDefine
= new Define ( project
, this, e
);
381 pIf
->data
.defines
.push_back ( pDefine
);
383 non_if_data
.defines
.push_back ( pDefine
);
386 else if ( e
.name
== "invoke" )
389 throw InvalidBuildFileException (
391 "<invoke> is not a valid sub-element of <if>" );
392 invocations
.push_back ( new Invoke ( e
, *this ) );
393 subs_invalid
= false;
395 else if ( e
.name
== "dependency" )
398 throw InvalidBuildFileException (
400 "<dependency> is not a valid sub-element of <if>" );
401 dependencies
.push_back ( new Dependency ( e
, *this ) );
404 else if ( e
.name
== "importlibrary" )
407 throw InvalidBuildFileException (
409 "<importlibrary> is not a valid sub-element of <if>" );
411 throw InvalidBuildFileException (
413 "Only one <importlibrary> is valid per module" );
414 importLibrary
= new ImportLibrary ( e
, *this );
417 else if ( e
.name
== "if" )
420 pIf
= new If ( e
, project
, this );
422 pOldIf
->data
.ifs
.push_back ( pIf
);
424 non_if_data
.ifs
.push_back ( pIf
);
425 subs_invalid
= false;
427 else if ( e
.name
== "ifnot" )
430 pIf
= new If ( e
, project
, this, true );
432 pOldIf
->data
.ifs
.push_back ( pIf
);
434 non_if_data
.ifs
.push_back ( pIf
);
435 subs_invalid
= false;
437 else if ( e
.name
== "compilerflag" )
439 CompilerFlag
* pCompilerFlag
= new CompilerFlag ( project
, this, e
);
441 pIf
->data
.compilerFlags
.push_back ( pCompilerFlag
);
443 non_if_data
.compilerFlags
.push_back ( pCompilerFlag
);
446 else if ( e
.name
== "linkerflag" )
448 linkerFlags
.push_back ( new LinkerFlag ( project
, this, e
) );
451 else if ( e
.name
== "component" )
453 stubbedComponents
.push_back ( new StubbedComponent ( this, e
) );
454 subs_invalid
= false;
456 else if ( e
.name
== "property" )
458 throw InvalidBuildFileException (
460 "<property> is not a valid sub-element of <module>" );
462 else if ( e
.name
== "bootstrap" )
464 bootstrap
= new Bootstrap ( project
, this, e
);
467 else if ( e
.name
== "pch" )
470 throw InvalidBuildFileException (
472 "<pch> is not a valid sub-element of <if>" );
474 throw InvalidBuildFileException (
476 "Only one <pch> is valid per module" );
478 e
, *this, File ( FixSeparator ( path
+ CSEP
+ e
.value
), false, "", true ) );
481 if ( subs_invalid
&& e
.subElements
.size() > 0 )
482 throw InvalidBuildFileException (
484 "<%s> cannot have sub-elements",
486 for ( size_t i
= 0; i
< e
.subElements
.size (); i
++ )
487 ProcessXMLSubElement ( *e
.subElements
[i
], subpath
, pIf
);
491 Module::GetModuleType ( const string
& location
, const XMLAttribute
& attribute
)
493 if ( attribute
.value
== "buildtool" )
495 if ( attribute
.value
== "staticlibrary" )
496 return StaticLibrary
;
497 if ( attribute
.value
== "objectlibrary" )
498 return ObjectLibrary
;
499 if ( attribute
.value
== "kernel" )
501 if ( attribute
.value
== "kernelmodedll" )
502 return KernelModeDLL
;
503 if ( attribute
.value
== "kernelmodedriver" )
504 return KernelModeDriver
;
505 if ( attribute
.value
== "nativedll" )
507 if ( attribute
.value
== "nativecui" )
509 if ( attribute
.value
== "win32dll" )
511 if ( attribute
.value
== "win32cui" )
513 if ( attribute
.value
== "win32gui" )
515 if ( attribute
.value
== "bootloader" )
517 if ( attribute
.value
== "bootsector" )
519 if ( attribute
.value
== "iso" )
521 if ( attribute
.value
== "liveiso" )
523 if ( attribute
.value
== "test" )
525 if ( attribute
.value
== "rpcserver" )
527 if ( attribute
.value
== "rpcclient" )
529 throw InvalidAttributeValueException ( location
,
535 Module::GetDefaultModuleExtension () const
554 case KernelModeDriver
:
569 throw InvalidOperationException ( __FILE__
,
574 Module::GetDefaultModuleEntrypoint () const
579 return "_NtProcessStartup";
581 return "_DriverEntry@8";
583 return "_DllMainCRTStartup@12";
585 return "_NtProcessStartup@4";
587 return "_DllMain@12";
590 return "_mainCRTStartup";
592 return "_WinMainCRTStartup";
593 case KernelModeDriver
:
594 return "_DriverEntry@8";
606 throw InvalidOperationException ( __FILE__
,
611 Module::GetDefaultModuleBaseaddress () const
627 case KernelModeDriver
:
640 throw InvalidOperationException ( __FILE__
,
645 Module::HasImportLibrary () const
647 return importLibrary
!= NULL
;
651 Module::IsDLL () const
659 case KernelModeDriver
:
676 throw InvalidOperationException ( __FILE__
,
681 Module::GenerateInOutputTree () const
689 case KernelModeDriver
:
706 throw InvalidOperationException ( __FILE__
,
711 Module::GetTargetName () const
713 return name
+ extension
;
717 Module::GetDependencyPath () const
719 if ( HasImportLibrary () )
720 return ReplaceExtension ( GetPathWithPrefix ( "lib" ), ".a" );
726 Module::GetBasePath () const
732 Module::GetPath () const
734 if ( path
.length() > 0 )
735 return path
+ CSEP
+ GetTargetName ();
737 return GetTargetName ();
741 Module::GetPathWithPrefix ( const string
& prefix
) const
743 return path
+ CSEP
+ prefix
+ GetTargetName ();
747 Module::GetInvocationTarget ( const int index
) const
749 return ssprintf ( "%s_invoke_%d",
755 Module::HasFileWithExtension (
756 const IfableData
& data
,
757 const std::string
& extension
) const
760 for ( i
= 0; i
< data
.files
.size (); i
++ )
762 File
& file
= *data
.files
[i
];
763 string file_ext
= GetExtension ( file
.name
);
764 if ( !stricmp ( file_ext
.c_str (), extension
.c_str () ) )
767 for ( i
= 0; i
< data
.ifs
.size (); i
++ )
769 if ( HasFileWithExtension ( data
.ifs
[i
]->data
, extension
) )
776 Module::InvokeModule () const
778 for ( size_t i
= 0; i
< invocations
.size (); i
++ )
780 Invoke
& invoke
= *invocations
[i
];
781 string command
= invoke
.invokeModule
->GetPath () + " " + invoke
.GetParameters ();
782 printf ( "Executing '%s'\n\n", command
.c_str () );
783 int exitcode
= system ( command
.c_str () );
785 throw InvocationFailedException ( command
,
791 File::File ( const string
& _name
, bool _first
,
792 std::string _switches
,
793 bool _isPreCompiledHeader
)
797 isPreCompiledHeader(_isPreCompiledHeader
)
807 File::IsGeneratedFile () const
809 string extension
= GetExtension ( name
);
810 return ( extension
== ".spec" || extension
== ".SPEC" );
814 Library::Library ( const XMLElement
& _node
,
815 const Module
& _module
,
816 const string
& _name
)
820 imported_module(_module
.project
.LocateModule(_name
))
822 if ( module
.name
== name
)
823 throw InvalidBuildFileException (
825 "module '%s' cannot link against itself",
827 if ( !imported_module
)
828 throw InvalidBuildFileException (
830 "module '%s' trying to import non-existant module '%s'",
836 Library::ProcessXML()
838 if ( !module
.project
.LocateModule ( name
) )
839 throw InvalidBuildFileException (
841 "module '%s' is trying to link against non-existant module '%s'",
847 Invoke::Invoke ( const XMLElement
& _node
,
848 const Module
& _module
)
857 const XMLAttribute
* att
= node
.GetAttribute ( "module", false );
859 invokeModule
= &module
;
862 invokeModule
= module
.project
.LocateModule ( att
->value
);
863 if ( invokeModule
== NULL
)
864 throw InvalidBuildFileException (
866 "module '%s' is trying to invoke non-existant module '%s'",
868 att
->value
.c_str() );
871 for ( size_t i
= 0; i
< node
.subElements
.size (); i
++ )
872 ProcessXMLSubElement ( *node
.subElements
[i
] );
876 Invoke::ProcessXMLSubElement ( const XMLElement
& e
)
878 bool subs_invalid
= false;
879 if ( e
.name
== "input" )
881 for ( size_t i
= 0; i
< e
.subElements
.size (); i
++ )
882 ProcessXMLSubElementInput ( *e
.subElements
[i
] );
884 else if ( e
.name
== "output" )
886 for ( size_t i
= 0; i
< e
.subElements
.size (); i
++ )
887 ProcessXMLSubElementOutput ( *e
.subElements
[i
] );
889 if ( subs_invalid
&& e
.subElements
.size() > 0 )
890 throw InvalidBuildFileException ( e
.location
,
891 "<%s> cannot have sub-elements",
896 Invoke::ProcessXMLSubElementInput ( const XMLElement
& e
)
898 bool subs_invalid
= false;
899 if ( e
.name
== "inputfile" && e
.value
.size () > 0 )
901 input
.push_back ( new InvokeFile ( e
, FixSeparator ( module
.path
+ CSEP
+ e
.value
) ) );
904 if ( subs_invalid
&& e
.subElements
.size() > 0 )
905 throw InvalidBuildFileException ( e
.location
,
906 "<%s> cannot have sub-elements",
911 Invoke::ProcessXMLSubElementOutput ( const XMLElement
& e
)
913 bool subs_invalid
= false;
914 if ( e
.name
== "outputfile" && e
.value
.size () > 0 )
916 output
.push_back ( new InvokeFile ( e
, FixSeparator ( module
.path
+ CSEP
+ e
.value
) ) );
919 if ( subs_invalid
&& e
.subElements
.size() > 0 )
920 throw InvalidBuildFileException (
922 "<%s> cannot have sub-elements",
927 Invoke::GetTargets ( string_list
& targets
) const
929 for ( size_t i
= 0; i
< output
.size (); i
++ )
931 InvokeFile
& file
= *output
[i
];
932 targets
.push_back ( NormalizeFilename ( file
.name
) );
937 Invoke::GetParameters () const
939 string
parameters ( "" );
941 for ( i
= 0; i
< output
.size (); i
++ )
943 if ( parameters
.length () > 0)
945 InvokeFile
& invokeFile
= *output
[i
];
946 if ( invokeFile
.switches
.length () > 0 )
948 parameters
+= invokeFile
.switches
+ " ";
950 parameters
+= invokeFile
.name
;
953 for ( i
= 0; i
< input
.size (); i
++ )
955 if ( parameters
.length () > 0 )
957 InvokeFile
& invokeFile
= *input
[i
];
958 if ( invokeFile
.switches
.length () > 0 )
960 parameters
+= invokeFile
.switches
;
963 parameters
+= invokeFile
.name
;
970 InvokeFile::InvokeFile ( const XMLElement
& _node
,
971 const string
& _name
)
975 const XMLAttribute
* att
= _node
.GetAttribute ( "switches", false );
977 switches
= att
->value
;
983 InvokeFile::ProcessXML()
988 Dependency::Dependency ( const XMLElement
& _node
,
989 const Module
& _module
)
992 dependencyModule (NULL
)
997 Dependency::ProcessXML()
999 dependencyModule
= module
.project
.LocateModule ( node
.value
);
1000 if ( dependencyModule
== NULL
)
1001 throw InvalidBuildFileException ( node
.location
,
1002 "module '%s' depend on non-existant module '%s'",
1003 module
.name
.c_str(),
1004 node
.value
.c_str() );
1008 ImportLibrary::ImportLibrary ( const XMLElement
& _node
,
1009 const Module
& _module
)
1013 const XMLAttribute
* att
= _node
.GetAttribute ( "basename", false );
1015 basename
= att
->value
;
1017 basename
= module
.name
;
1019 att
= _node
.GetAttribute ( "definition", true );
1021 definition
= FixSeparator(att
->value
);
1025 If::If ( const XMLElement
& node_
,
1026 const Project
& project_
,
1027 const Module
* module_
,
1028 const bool negated_
)
1029 : node(node_
), project(project_
), module(module_
), negated(negated_
)
1031 const XMLAttribute
* att
;
1033 att
= node
.GetAttribute ( "property", true );
1035 property
= att
->value
;
1037 att
= node
.GetAttribute ( "value", true );
1052 Property::Property ( const XMLElement
& node_
,
1053 const Project
& project_
,
1054 const Module
* module_
)
1055 : node(node_
), project(project_
), module(module_
)
1057 const XMLAttribute
* att
;
1059 att
= node
.GetAttribute ( "name", true );
1063 att
= node
.GetAttribute ( "value", true );
1069 Property::ProcessXML()
1075 const XMLElement
& node_
,
1076 const Module
& module_
,
1078 : node(node_
), module(module_
), file(file_
)
1083 PchFile::ProcessXML()