fba4022ad922fa4b4dcd6e75725c779a973a915d
[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 importLibrary (NULL)
30 {
31 if ( node.name != "module" )
32 throw Exception ( "internal tool error: Module created with non-<module> node" );
33
34 path = FixSeparator ( modulePath );
35
36 const XMLAttribute* att = moduleNode.GetAttribute ( "name", true );
37 assert(att);
38 name = att->value;
39
40 att = moduleNode.GetAttribute ( "type", true );
41 assert(att);
42 type = GetModuleType ( node.location, *att );
43
44 att = moduleNode.GetAttribute ( "extension", false );
45 if (att != NULL)
46 extension = att->value;
47 else
48 extension = GetDefaultModuleExtension ();
49 }
50
51 Module::~Module ()
52 {
53 size_t i;
54 for ( i = 0; i < files.size(); i++ )
55 delete files[i];
56 for ( i = 0; i < libraries.size(); i++ )
57 delete libraries[i];
58 for ( i = 0; i < includes.size(); i++ )
59 delete includes[i];
60 for ( i = 0; i < defines.size(); i++ )
61 delete defines[i];
62 for ( i = 0; i < invocations.size(); i++ )
63 delete invocations[i];
64 for ( i = 0; i < dependencies.size(); i++ )
65 delete dependencies[i];
66 }
67
68 void
69 Module::ProcessXML()
70 {
71 size_t i;
72 for ( i = 0; i < node.subElements.size(); i++ )
73 ProcessXMLSubElement ( *node.subElements[i], path );
74 for ( i = 0; i < files.size (); i++ )
75 files[i]->ProcessXML ();
76 for ( i = 0; i < libraries.size(); i++ )
77 libraries[i]->ProcessXML ();
78 for ( i = 0; i < includes.size(); i++ )
79 includes[i]->ProcessXML ();
80 for ( i = 0; i < defines.size(); i++ )
81 defines[i]->ProcessXML ();
82 for ( i = 0; i < invocations.size(); i++ )
83 invocations[i]->ProcessXML ();
84 for ( i = 0; i < dependencies.size(); i++ )
85 dependencies[i]->ProcessXML ();
86 }
87
88 void
89 Module::ProcessXMLSubElement ( const XMLElement& e,
90 const string& path )
91 {
92 bool subs_invalid = false;
93 string subpath ( path );
94 if ( e.name == "file" && e.value.size () > 0 )
95 {
96 files.push_back ( new File ( FixSeparator ( path + CSEP + e.value ) ) );
97 subs_invalid = true;
98 }
99 else if ( e.name == "library" && e.value.size () )
100 {
101 libraries.push_back ( new Library ( e, *this, e.value ) );
102 subs_invalid = true;
103 }
104 else if ( e.name == "directory" )
105 {
106 const XMLAttribute* att = e.GetAttribute ( "name", true );
107 assert(att);
108 subpath = FixSeparator ( path + CSEP + att->value );
109 }
110 else if ( e.name == "include" )
111 {
112 includes.push_back ( new Include ( project, this, e ) );
113 subs_invalid = true;
114 }
115 else if ( e.name == "define" )
116 {
117 defines.push_back ( new Define ( project, this, e ) );
118 subs_invalid = true;
119 }
120 else if ( e.name == "invoke" )
121 {
122 invocations.push_back ( new Invoke ( e, *this ) );
123 subs_invalid = false;
124 }
125 else if ( e.name == "dependency" )
126 {
127 dependencies.push_back ( new Dependency ( e, *this ) );
128 subs_invalid = true;
129 }
130 else if ( e.name == "importlibrary" )
131 {
132 importLibrary = new ImportLibrary ( e, *this );
133 subs_invalid = true;
134 }
135 if ( subs_invalid && e.subElements.size() > 0 )
136 throw InvalidBuildFileException (
137 e.location,
138 "<%s> cannot have sub-elements",
139 e.name.c_str() );
140 for ( size_t i = 0; i < e.subElements.size (); i++ )
141 ProcessXMLSubElement ( *e.subElements[i], subpath );
142 }
143
144 ModuleType
145 Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
146 {
147 if ( attribute.value == "buildtool" )
148 return BuildTool;
149 if ( attribute.value == "staticlibrary" )
150 return StaticLibrary;
151 if ( attribute.value == "kernel" )
152 return Kernel;
153 if ( attribute.value == "kernelmodedll" )
154 return KernelModeDLL;
155 if ( attribute.value == "nativedll" )
156 return NativeDLL;
157 throw InvalidAttributeValueException ( location,
158 attribute.name,
159 attribute.value );
160 }
161
162 string
163 Module::GetDefaultModuleExtension () const
164 {
165 switch (type)
166 {
167 case BuildTool:
168 return EXEPOSTFIX;
169 case StaticLibrary:
170 return ".a";
171 case Kernel:
172 return ".exe";
173 case KernelModeDLL:
174 return ".dll";
175 case NativeDLL:
176 return ".dll";
177 }
178 throw InvalidOperationException (__FILE__,
179 __LINE__);
180 }
181
182 string
183 Module::GetTargetName () const
184 {
185 return name + extension;
186 }
187
188 string
189 Module::GetDependencyPath () const
190 {
191 if ( type == KernelModeDLL )
192 return ssprintf ( "dk%snkm%slib%slib%s.a",
193 SSEP,
194 SSEP,
195 SSEP,
196 name.c_str () );
197 else
198 return GetPath ();
199 }
200
201 string
202 Module::GetBasePath () const
203 {
204 return path;
205 }
206
207 string
208 Module::GetPath () const
209 {
210 return path + CSEP + GetTargetName ();
211 }
212
213 string
214 Module::GetPathWithPrefix ( const string& prefix ) const
215 {
216 return path + CSEP + prefix + GetTargetName ();
217 }
218
219 string
220 Module::GetTargets () const
221 {
222 if ( invocations.size () > 0 )
223 {
224 string targets ( "" );
225 for ( size_t i = 0; i < invocations.size (); i++ )
226 {
227 Invoke& invoke = *invocations[i];
228 if ( targets.length () > 0 )
229 targets += " ";
230 targets += invoke.GetTargets ();
231 }
232 return targets;
233 }
234 else
235 return GetPath ();
236 }
237
238 string
239 Module::GetInvocationTarget ( const int index ) const
240 {
241 return ssprintf ( "%s_invoke_%d",
242 name.c_str (),
243 index );
244 }
245
246
247 File::File ( const string& _name )
248 : name(_name)
249 {
250 }
251
252 void
253 File::ProcessXML()
254 {
255 }
256
257
258 Library::Library ( const XMLElement& _node,
259 const Module& _module,
260 const string& _name )
261 : node(_node),
262 module(_module),
263 name(_name)
264 {
265 if ( module.name == name )
266 throw InvalidBuildFileException (
267 node.location,
268 "module '%s' cannot link against itself",
269 name.c_str() );
270 }
271
272 void
273 Library::ProcessXML()
274 {
275 if ( !module.project.LocateModule ( name ) )
276 throw InvalidBuildFileException (
277 node.location,
278 "module '%s' is trying to link against non-existant module '%s'",
279 module.name.c_str(),
280 name.c_str() );
281 }
282
283
284 Invoke::Invoke ( const XMLElement& _node,
285 const Module& _module )
286 : node (_node),
287 module (_module)
288 {
289 }
290
291 void
292 Invoke::ProcessXML()
293 {
294 const XMLAttribute* att = node.GetAttribute ( "module", false );
295 if (att == NULL)
296 invokeModule = &module;
297 else
298 {
299 invokeModule = module.project.LocateModule ( att->value );
300 if ( invokeModule == NULL )
301 throw InvalidBuildFileException (
302 node.location,
303 "module '%s' is trying to invoke non-existant module '%s'",
304 module.name.c_str(),
305 att->value.c_str() );
306 }
307
308 for ( size_t i = 0; i < node.subElements.size (); i++ )
309 ProcessXMLSubElement ( *node.subElements[i] );
310 }
311
312 void
313 Invoke::ProcessXMLSubElement ( const XMLElement& e )
314 {
315 bool subs_invalid = false;
316 if ( e.name == "input" )
317 {
318 for ( size_t i = 0; i < e.subElements.size (); i++ )
319 ProcessXMLSubElementInput ( *e.subElements[i] );
320 }
321 else if ( e.name == "output" )
322 {
323 for ( size_t i = 0; i < e.subElements.size (); i++ )
324 ProcessXMLSubElementOutput ( *e.subElements[i] );
325 }
326 if ( subs_invalid && e.subElements.size() > 0 )
327 throw InvalidBuildFileException ( e.location,
328 "<%s> cannot have sub-elements",
329 e.name.c_str() );
330 }
331
332 void
333 Invoke::ProcessXMLSubElementInput ( const XMLElement& e )
334 {
335 bool subs_invalid = false;
336 if ( e.name == "inputfile" && e.value.size () > 0 )
337 {
338 input.push_back ( new InvokeFile ( e, FixSeparator ( module.path + CSEP + e.value ) ) );
339 subs_invalid = true;
340 }
341 if ( subs_invalid && e.subElements.size() > 0 )
342 throw InvalidBuildFileException ( e.location,
343 "<%s> cannot have sub-elements",
344 e.name.c_str() );
345 }
346
347 void
348 Invoke::ProcessXMLSubElementOutput ( const XMLElement& e )
349 {
350 bool subs_invalid = false;
351 if ( e.name == "outputfile" && e.value.size () > 0 )
352 {
353 output.push_back ( new InvokeFile ( e, FixSeparator ( module.path + CSEP + e.value ) ) );
354 subs_invalid = true;
355 }
356 if ( subs_invalid && e.subElements.size() > 0 )
357 throw InvalidBuildFileException ( e.location,
358 "<%s> cannot have sub-elements",
359 e.name.c_str() );
360 }
361
362 string
363 Invoke::GetTargets () const
364 {
365 string targets ( "" );
366 for ( size_t i = 0; i < output.size (); i++ )
367 {
368 InvokeFile& file = *output[i];
369 if ( targets.length () > 0 )
370 targets += " ";
371 targets += file.name;
372 }
373 return targets;
374 }
375
376
377 InvokeFile::InvokeFile ( const XMLElement& _node,
378 const string& _name )
379 : node (_node),
380 name (_name)
381 {
382 const XMLAttribute* att = _node.GetAttribute ( "switches", false );
383 if (att != NULL)
384 switches = att->value;
385 else
386 switches = "";
387 }
388
389 void
390 InvokeFile::ProcessXML()
391 {
392 }
393
394
395 Dependency::Dependency ( const XMLElement& _node,
396 const Module& _module )
397 : node (_node),
398 module (_module),
399 dependencyModule (NULL)
400 {
401 }
402
403 void
404 Dependency::ProcessXML()
405 {
406 dependencyModule = module.project.LocateModule ( node.value );
407 if ( dependencyModule == NULL )
408 throw InvalidBuildFileException ( node.location,
409 "module '%s' depend on non-existant module '%s'",
410 module.name.c_str(),
411 node.value.c_str() );
412 }
413
414
415 ImportLibrary::ImportLibrary ( const XMLElement& _node,
416 const Module& _module )
417 : node (_node),
418 module (_module)
419 {
420 const XMLAttribute* att = _node.GetAttribute ( "basename", false );
421 if (att != NULL)
422 basename = att->value;
423 else
424 basename = module.name;
425
426 att = _node.GetAttribute ( "definition", true );
427 assert (att);
428 definition = att->value;
429 }