use enum instead of string in more places
[reactos.git] / reactos / tools / rbuild / module.cpp
1 // module.cpp
2
3 #include "pch.h"
4 #include <assert.h>
5
6 #include "rbuild.h"
7
8 using std::string;
9 using std::vector;
10
11 string
12 FixSeparator ( const string& s )
13 {
14 string s2(s);
15 char* p = strchr ( &s2[0], CBAD_SEP );
16 while ( p )
17 {
18 *p++ = CSEP;
19 p = strchr ( p, CBAD_SEP );
20 }
21 return s2;
22 }
23
24 Module::Module ( const Project& project,
25 const XMLElement& moduleNode,
26 const string& modulePath )
27 : project(project),
28 node(moduleNode)
29 {
30 if ( node.name != "module" )
31 throw Exception ( "internal tool error: Module created with non-<module> node" );
32
33 path = FixSeparator ( modulePath );
34
35 const XMLAttribute* att = moduleNode.GetAttribute ( "name", true );
36 assert(att);
37 name = att->value;
38
39 att = moduleNode.GetAttribute ( "type", true );
40 assert(att);
41 type = GetModuleType ( node.location, *att );
42
43 att = moduleNode.GetAttribute ( "extension", false );
44 if (att != NULL)
45 extension = att->value;
46 else
47 extension = GetDefaultModuleExtension ();
48 }
49
50 Module::~Module ()
51 {
52 size_t i;
53 for ( i = 0; i < files.size(); i++ )
54 delete files[i];
55 for ( i = 0; i < libraries.size(); i++ )
56 delete libraries[i];
57 for ( i = 0; i < includes.size(); i++ )
58 delete includes[i];
59 for ( i = 0; i < defines.size(); i++ )
60 delete defines[i];
61 for ( i = 0; i < invocations.size(); i++ )
62 delete invocations[i];
63 for ( i = 0; i < dependencies.size(); i++ )
64 delete dependencies[i];
65 }
66
67 void
68 Module::ProcessXML()
69 {
70 size_t i;
71 for ( i = 0; i < node.subElements.size(); i++ )
72 ProcessXMLSubElement ( *node.subElements[i], path );
73 for ( i = 0; i < files.size (); i++ )
74 files[i]->ProcessXML ();
75 for ( i = 0; i < libraries.size(); i++ )
76 libraries[i]->ProcessXML ();
77 for ( i = 0; i < includes.size(); i++ )
78 includes[i]->ProcessXML ();
79 for ( i = 0; i < defines.size(); i++ )
80 defines[i]->ProcessXML ();
81 for ( i = 0; i < invocations.size(); i++ )
82 invocations[i]->ProcessXML ();
83 for ( i = 0; i < dependencies.size(); i++ )
84 dependencies[i]->ProcessXML ();
85 }
86
87 void
88 Module::ProcessXMLSubElement ( const XMLElement& e,
89 const string& path )
90 {
91 bool subs_invalid = false;
92 string subpath ( path );
93 if ( e.name == "file" && e.value.size () > 0 )
94 {
95 files.push_back ( new File ( FixSeparator ( path + CSEP + e.value ) ) );
96 subs_invalid = true;
97 }
98 else if ( e.name == "library" && e.value.size () )
99 {
100 libraries.push_back ( new Library ( e, *this, e.value ) );
101 subs_invalid = true;
102 }
103 else if ( e.name == "directory" )
104 {
105 const XMLAttribute* att = e.GetAttribute ( "name", true );
106 assert(att);
107 subpath = FixSeparator ( path + CSEP + att->value );
108 }
109 else if ( e.name == "include" )
110 {
111 includes.push_back ( new Include ( project, this, e ) );
112 subs_invalid = true;
113 }
114 else if ( e.name == "define" )
115 {
116 defines.push_back ( new Define ( project, this, e ) );
117 subs_invalid = true;
118 }
119 else if ( e.name == "invoke" )
120 {
121 invocations.push_back ( new Invoke ( e, *this ) );
122 subs_invalid = false;
123 }
124 else if ( e.name == "dependency" )
125 {
126 dependencies.push_back ( new Dependency ( e, *this ) );
127 subs_invalid = true;
128 }
129 if ( subs_invalid && e.subElements.size() > 0 )
130 throw InvalidBuildFileException (
131 e.location,
132 "<%s> cannot have sub-elements",
133 e.name.c_str() );
134 for ( size_t i = 0; i < e.subElements.size (); i++ )
135 ProcessXMLSubElement ( *e.subElements[i], subpath );
136 }
137
138 ModuleType
139 Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
140 {
141 if ( attribute.value == "buildtool" )
142 return BuildTool;
143 if ( attribute.value == "staticlibrary" )
144 return StaticLibrary;
145 if ( attribute.value == "kernelmodedll" )
146 return KernelModeDLL;
147 throw InvalidAttributeValueException ( location,
148 attribute.name,
149 attribute.value );
150 }
151
152 string
153 Module::GetDefaultModuleExtension () const
154 {
155 switch (type)
156 {
157 case BuildTool:
158 return EXEPOSTFIX;
159 case StaticLibrary:
160 return ".a";
161 case KernelModeDLL:
162 return ".dll";
163 }
164 throw InvalidOperationException (__FILE__,
165 __LINE__);
166 }
167
168 string
169 Module::GetBasePath() const
170 {
171 return path;
172 }
173
174 string
175 Module::GetPath () const
176 {
177 return path + CSEP + name + extension;
178 }
179
180 string
181 Module::GetTargets () const
182 {
183 if ( invocations.size () > 0 )
184 {
185 string targets ( "" );
186 for ( size_t i = 0; i < invocations.size (); i++ )
187 {
188 Invoke& invoke = *invocations[i];
189 if ( targets.length () > 0 )
190 targets += " ";
191 targets += invoke.GetTargets ();
192 }
193 return targets;
194 }
195 else
196 return GetPath ();
197 }
198
199 string
200 Module::GetInvocationTarget ( const int index ) const
201 {
202 return ssprintf ( "%s_invoke_%d",
203 name.c_str (),
204 index );
205 }
206
207
208 File::File ( const string& _name )
209 : name(_name)
210 {
211 }
212
213 void
214 File::ProcessXML()
215 {
216 }
217
218
219 Library::Library ( const XMLElement& _node,
220 const Module& _module,
221 const string& _name )
222 : node(_node),
223 module(_module),
224 name(_name)
225 {
226 if ( module.name == name )
227 throw InvalidBuildFileException (
228 node.location,
229 "module '%s' cannot link against itself",
230 name.c_str() );
231 }
232
233 void
234 Library::ProcessXML()
235 {
236 if ( !module.project.LocateModule ( name ) )
237 throw InvalidBuildFileException (
238 node.location,
239 "module '%s' is trying to link against non-existant module '%s'",
240 module.name.c_str(),
241 name.c_str() );
242 }
243
244
245 Invoke::Invoke ( const XMLElement& _node,
246 const Module& _module )
247 : node (_node),
248 module (_module)
249 {
250 }
251
252 void
253 Invoke::ProcessXML()
254 {
255 const XMLAttribute* att = node.GetAttribute ( "module", false );
256 if (att == NULL)
257 invokeModule = &module;
258 else
259 {
260 invokeModule = module.project.LocateModule ( att->value );
261 if ( invokeModule == NULL )
262 throw InvalidBuildFileException (
263 node.location,
264 "module '%s' is trying to invoke non-existant module '%s'",
265 module.name.c_str(),
266 att->value.c_str() );
267 }
268
269 for ( size_t i = 0; i < node.subElements.size (); i++ )
270 ProcessXMLSubElement ( *node.subElements[i] );
271 }
272
273 void
274 Invoke::ProcessXMLSubElement ( const XMLElement& e )
275 {
276 bool subs_invalid = false;
277 if ( e.name == "input" )
278 {
279 for ( size_t i = 0; i < e.subElements.size (); i++ )
280 ProcessXMLSubElementInput ( *e.subElements[i] );
281 }
282 else if ( e.name == "output" )
283 {
284 for ( size_t i = 0; i < e.subElements.size (); i++ )
285 ProcessXMLSubElementOutput ( *e.subElements[i] );
286 }
287 if ( subs_invalid && e.subElements.size() > 0 )
288 throw InvalidBuildFileException ( e.location,
289 "<%s> cannot have sub-elements",
290 e.name.c_str() );
291 }
292
293 void
294 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
295 {
296 bool subs_invalid = false;
297 if ( e.name == "inputfile" && e.value.size () > 0 )
298 {
299 input.push_back ( new InvokeFile ( e, FixSeparator ( module.path + CSEP + e.value ) ) );
300 subs_invalid = true;
301 }
302 if ( subs_invalid && e.subElements.size() > 0 )
303 throw InvalidBuildFileException ( e.location,
304 "<%s> cannot have sub-elements",
305 e.name.c_str() );
306 }
307
308 void
309 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
310 {
311 bool subs_invalid = false;
312 if ( e.name == "outputfile" && e.value.size () > 0 )
313 {
314 output.push_back ( new InvokeFile ( e, FixSeparator ( module.path + CSEP + e.value ) ) );
315 subs_invalid = true;
316 }
317 if ( subs_invalid && e.subElements.size() > 0 )
318 throw InvalidBuildFileException ( e.location,
319 "<%s> cannot have sub-elements",
320 e.name.c_str() );
321 }
322
323 string
324 Invoke::GetTargets () const
325 {
326 string targets ( "" );
327 for ( size_t i = 0; i < output.size (); i++ )
328 {
329 InvokeFile& file = *output[i];
330 if ( targets.length () > 0 )
331 targets += " ";
332 targets += file.name;
333 }
334 return targets;
335 }
336
337
338 InvokeFile::InvokeFile ( const XMLElement& _node,
339 const string& _name )
340 : node (_node),
341 name (_name)
342 {
343 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
344 if (att != NULL)
345 switches = att->value;
346 else
347 switches = "";
348 }
349
350 void
351 InvokeFile::ProcessXML()
352 {
353 }
354
355
356 Dependency::Dependency ( const XMLElement& _node,
357 const Module& _module )
358 : node (_node),
359 module (_module),
360 dependencyModule (NULL)
361 {
362 }
363
364 void
365 Dependency::ProcessXML()
366 {
367 dependencyModule = module.project.LocateModule ( node.value );
368 if ( dependencyModule == NULL )
369 throw InvalidBuildFileException ( node.location,
370 "module '%s' depend on non-existant module '%s'",
371 module.name.c_str(),
372 node.value.c_str() );
373 }