4c6e34abbfd2f2ae6832a790006683b5d612a3bd
[reactos.git] / reactos / tools / rbuild / backend / mingw / modulehandler.cpp
1
2 #include "../../pch.h"
3 #include <assert.h>
4
5 #include "../../rbuild.h"
6 #include "mingw.h"
7 #include "modulehandler.h"
8
9 using std::string;
10 using std::vector;
11 using std::map;
12
13 map<ModuleType,MingwModuleHandler*>*
14 MingwModuleHandler::handler_map = NULL;
15
16 FILE*
17 MingwModuleHandler::fMakefile = NULL;
18
19 MingwModuleHandler::MingwModuleHandler ( ModuleType moduletype )
20 {
21 if ( !handler_map )
22 handler_map = new map<ModuleType,MingwModuleHandler*>;
23 (*handler_map)[moduletype] = this;
24 }
25
26 /*static*/ void
27 MingwModuleHandler::SetMakefile ( FILE* f )
28 {
29 fMakefile = f;
30 }
31
32 /*static*/ MingwModuleHandler*
33 MingwModuleHandler::LookupHandler ( const string& location,
34 ModuleType moduletype )
35 {
36 if ( !handler_map )
37 throw Exception ( "internal tool error: no registered module handlers" );
38 MingwModuleHandler* h = (*handler_map)[moduletype];
39 if ( !h )
40 {
41 throw UnknownModuleTypeException ( location, moduletype );
42 return NULL;
43 }
44 return h;
45 }
46
47 string
48 MingwModuleHandler::GetWorkingDirectory () const
49 {
50 return ".";
51 }
52
53 string
54 MingwModuleHandler::GetExtension ( const string& filename ) const
55 {
56 size_t index = filename.find_last_of ( '.' );
57 if (index != string::npos)
58 return filename.substr ( index );
59 return "";
60 }
61
62 string
63 MingwModuleHandler::ReplaceExtension ( const string& filename,
64 const string& newExtension ) const
65 {
66 size_t index = filename.find_last_of ( '.' );
67 if (index != string::npos)
68 return filename.substr ( 0, index ) + newExtension;
69 return filename;
70 }
71
72 string
73 MingwModuleHandler::GetModuleArchiveFilename ( const Module& module ) const
74 {
75 return ReplaceExtension ( FixupTargetFilename ( module.GetPath () ).c_str (),
76 ".a" );
77 }
78
79 string
80 MingwModuleHandler::GetImportLibraryDependencies ( const Module& module ) const
81 {
82 if ( module.libraries.size () == 0 )
83 return "";
84
85 string dependencies ( "" );
86 for ( size_t i = 0; i < module.libraries.size (); i++ )
87 {
88 if ( dependencies.size () > 0 )
89 dependencies += " ";
90 const Module* importedModule = module.project.LocateModule ( module.libraries[i]->name );
91 assert ( importedModule != NULL );
92 dependencies += FixupTargetFilename ( importedModule->GetPath () ).c_str ();
93 }
94 return dependencies;
95 }
96
97 string
98 MingwModuleHandler::GetModuleDependencies ( const Module& module ) const
99 {
100 if ( module.dependencies.size () == 0 )
101 return "";
102
103 string dependencies ( "" );
104 for ( size_t i = 0; i < module.dependencies.size (); i++ )
105 {
106 if ( dependencies.size () > 0 )
107 dependencies += " ";
108 const Dependency* dependency = module.dependencies[i];
109 const Module* dependencyModule = dependency->dependencyModule;
110 dependencies += dependencyModule->GetTargets ();
111 }
112 return dependencies;
113 }
114
115 string
116 MingwModuleHandler::GetAllDependencies ( const Module& module ) const
117 {
118 string dependencies = GetImportLibraryDependencies ( module );
119 string s = GetModuleDependencies ( module );
120 if (s.length () > 0)
121 {
122 dependencies += " ";
123 dependencies += s;
124 }
125 return dependencies;
126 }
127
128 string
129 MingwModuleHandler::GetSourceFilenames ( const Module& module ) const
130 {
131 if ( module.files.size () == 0 )
132 return "";
133
134 string sourceFilenames ( "" );
135 for ( size_t i = 0; i < module.files.size (); i++ )
136 {
137 if ( sourceFilenames.size () > 0 )
138 sourceFilenames += " ";
139 sourceFilenames += module.files[i]->name;
140 }
141 return sourceFilenames;
142 }
143
144 string
145 MingwModuleHandler::GetObjectFilename ( const string& sourceFilename ) const
146 {
147 return FixupTargetFilename ( ReplaceExtension ( sourceFilename,
148 ".o" ) );
149 }
150
151 string
152 MingwModuleHandler::GetObjectFilenames ( const Module& module ) const
153 {
154 if ( module.files.size () == 0 )
155 return "";
156
157 string objectFilenames ( "" );
158 for ( size_t i = 0; i < module.files.size (); i++ )
159 {
160 if ( objectFilenames.size () > 0 )
161 objectFilenames += " ";
162 objectFilenames += GetObjectFilename ( module.files[i]->name );
163 }
164 return objectFilenames;
165 }
166
167 string
168 MingwModuleHandler::GenerateGccDefineParametersFromVector ( const vector<Define*>& defines ) const
169 {
170 string parameters;
171 for (size_t i = 0; i < defines.size (); i++)
172 {
173 Define& define = *defines[i];
174 if (parameters.length () > 0)
175 parameters += " ";
176 parameters += "-D";
177 parameters += define.name;
178 if (define.value.length () > 0)
179 {
180 parameters += "=";
181 parameters += define.value;
182 }
183 }
184 return parameters;
185 }
186
187 string
188 MingwModuleHandler::GenerateGccDefineParameters ( const Module& module ) const
189 {
190 string parameters = GenerateGccDefineParametersFromVector ( module.project.defines );
191 string s = GenerateGccDefineParametersFromVector ( module.defines );
192 if (s.length () > 0)
193 {
194 parameters += " ";
195 parameters += s;
196 }
197 return parameters;
198 }
199
200 string
201 MingwModuleHandler::ConcatenatePaths ( const string& path1,
202 const string& path2 ) const
203 {
204 if ( ( path1.length () == 0 ) || ( path1 == "." ) || ( path1 == "./" ) )
205 return path2;
206 if ( path1[path1.length ()] == CSEP )
207 return path1 + path2;
208 else
209 return path1 + CSEP + path2;
210 }
211
212 string
213 MingwModuleHandler::GenerateGccIncludeParametersFromVector ( const vector<Include*>& includes ) const
214 {
215 string parameters;
216 for ( size_t i = 0; i < includes.size (); i++ )
217 {
218 Include& include = *includes[i];
219 if (parameters.length () > 0)
220 parameters += " ";
221 parameters += "-I" + include.directory;
222 }
223 return parameters;
224 }
225
226 void
227 MingwModuleHandler::GenerateGccModuleIncludeVariable ( const Module& module ) const
228 {
229 string name ( module.name + "_INCLUDES" );
230 fprintf ( fMakefile,
231 "%s := %s\n",
232 name.c_str(),
233 GenerateGccIncludeParameters(module).c_str() );
234 }
235
236 string
237 MingwModuleHandler::GenerateGccIncludeParameters ( const Module& module ) const
238 {
239 string parameters = GenerateGccIncludeParametersFromVector ( module.includes );
240 string s = GenerateGccIncludeParametersFromVector ( module.project.includes );
241 if ( s.length () > 0 )
242 {
243 parameters += " ";
244 parameters += s;
245 }
246 return parameters;
247 }
248
249 string
250 MingwModuleHandler::GenerateGccParameters ( const Module& module ) const
251 {
252 string parameters = GenerateGccDefineParameters ( module );
253 parameters += ssprintf(" $(%s_INCLUDES)",module.name.c_str());
254 return parameters;
255 }
256
257 string
258 MingwModuleHandler::GenerateGccCommand ( const Module& module,
259 const string& sourceFilename,
260 const string& cc ) const
261 {
262 string objectFilename = GetObjectFilename ( sourceFilename );
263 return ssprintf ( "%s -c %s -o %s %s\n",
264 cc.c_str (),
265 sourceFilename.c_str (),
266 objectFilename.c_str (),
267 GenerateGccParameters ( module ).c_str () );
268 }
269
270 string
271 MingwModuleHandler::GenerateGccAssemblerCommand ( const Module& module,
272 const string& sourceFilename,
273 const string& cc ) const
274 {
275 string objectFilename = GetObjectFilename ( sourceFilename );
276 return ssprintf ( "%s -x assembler-with-cpp -c %s -o %s -D__ASM__ %s\n",
277 cc.c_str (),
278 sourceFilename.c_str (),
279 objectFilename.c_str (),
280 GenerateGccParameters ( module ).c_str () );
281 }
282
283 string
284 MingwModuleHandler::GenerateCommand ( const Module& module,
285 const string& sourceFilename,
286 const string& cc ) const
287 {
288 string extension = GetExtension ( sourceFilename );
289 if ( extension == ".c" || extension == ".C" )
290 return GenerateGccCommand ( module,
291 sourceFilename,
292 cc );
293 else if ( extension == ".s" || extension == ".S" )
294 return GenerateGccAssemblerCommand ( module,
295 sourceFilename,
296 cc );
297
298 throw InvalidOperationException ( __FILE__,
299 __LINE__,
300 "Unsupported filename extension '%s' in file '%s'",
301 extension.c_str (),
302 sourceFilename.c_str () );
303 }
304
305 void
306 MingwModuleHandler::GenerateObjectFileTargets ( const Module& module,
307 const string& cc) const
308 {
309 if ( module.files.size () == 0 )
310 return;
311
312 GenerateGccModuleIncludeVariable ( module );
313
314 for ( size_t i = 0; i < module.files.size (); i++ )
315 {
316 string sourceFilename = module.files[i]->name;
317 string objectFilename = GetObjectFilename ( sourceFilename );
318 fprintf ( fMakefile,
319 "%s: %s\n",
320 objectFilename.c_str (),
321 sourceFilename.c_str () );
322 fprintf ( fMakefile,
323 "\t%s\n",
324 GenerateCommand ( module,
325 sourceFilename,
326 cc ).c_str () );
327 }
328
329 fprintf ( fMakefile, "\n" );
330 }
331
332 void
333 MingwModuleHandler::GenerateObjectFileTargetsHost ( const Module& module ) const
334 {
335 GenerateObjectFileTargets ( module,
336 "${host_gcc}" );
337 }
338
339 void
340 MingwModuleHandler::GenerateObjectFileTargetsTarget ( const Module& module ) const
341 {
342 GenerateObjectFileTargets ( module,
343 "${gcc}" );
344 }
345
346 void
347 MingwModuleHandler::GenerateArchiveTarget ( const Module& module,
348 const string& ar ) const
349 {
350 string archiveFilename = GetModuleArchiveFilename ( module );
351 string sourceFilenames = GetSourceFilenames ( module );
352 string objectFilenames = GetObjectFilenames ( module );
353
354 fprintf ( fMakefile,
355 "%s: %s\n",
356 archiveFilename.c_str (),
357 objectFilenames.c_str ());
358
359 fprintf ( fMakefile,
360 "\t%s -rc %s %s\n\n",
361 ar.c_str (),
362 archiveFilename.c_str (),
363 objectFilenames.c_str ());
364 }
365
366 void
367 MingwModuleHandler::GenerateArchiveTargetHost ( const Module& module ) const
368 {
369 GenerateArchiveTarget ( module,
370 "${host_ar}" );
371 }
372
373 void
374 MingwModuleHandler::GenerateArchiveTargetTarget ( const Module& module ) const
375 {
376 GenerateArchiveTarget ( module,
377 "${ar}" );
378 }
379
380 string
381 MingwModuleHandler::GetInvocationDependencies ( const Module& module ) const
382 {
383 string dependencies;
384 for ( size_t i = 0; i < module.invocations.size (); i++ )
385 {
386 Invoke& invoke = *module.invocations[i];
387 if (invoke.invokeModule == &module)
388 /* Protect against circular dependencies */
389 continue;
390 if ( dependencies.length () > 0 )
391 dependencies += " ";
392 dependencies += invoke.GetTargets ();
393 }
394 return dependencies;
395 }
396
397 string
398 MingwModuleHandler::GetInvocationParameters ( const Invoke& invoke ) const
399 {
400 string parameters ( "" );
401 size_t i;
402 for (i = 0; i < invoke.output.size (); i++)
403 {
404 if (parameters.length () > 0)
405 parameters += " ";
406 InvokeFile& invokeFile = *invoke.output[i];
407 if (invokeFile.switches.length () > 0)
408 {
409 parameters += invokeFile.switches;
410 parameters += " ";
411 }
412 parameters += invokeFile.name;
413 }
414
415 for (i = 0; i < invoke.input.size (); i++)
416 {
417 if (parameters.length () > 0)
418 parameters += " ";
419 InvokeFile& invokeFile = *invoke.input[i];
420 if (invokeFile.switches.length () > 0)
421 {
422 parameters += invokeFile.switches;
423 parameters += " ";
424 }
425 parameters += invokeFile.name;
426 }
427
428 return parameters;
429 }
430
431 void
432 MingwModuleHandler::GenerateInvocations ( const Module& module ) const
433 {
434 if ( module.invocations.size () == 0 )
435 return;
436
437 for ( size_t i = 0; i < module.invocations.size (); i++ )
438 {
439 const Invoke& invoke = *module.invocations[i];
440
441 if ( invoke.invokeModule->type != BuildTool )
442 throw InvalidBuildFileException ( module.node.location,
443 "Only modules of type buildtool can be invoked." );
444
445 string invokeTarget = module.GetInvocationTarget ( i );
446 fprintf ( fMakefile,
447 "%s: %s\n\n",
448 invoke.GetTargets ().c_str (),
449 invokeTarget.c_str () );
450 fprintf ( fMakefile,
451 "%s: %s\n",
452 invokeTarget.c_str (),
453 FixupTargetFilename ( invoke.invokeModule->GetPath () ).c_str () );
454 fprintf ( fMakefile,
455 "\t%s %s\n\n",
456 FixupTargetFilename ( invoke.invokeModule->GetPath () ).c_str (),
457 GetInvocationParameters ( invoke ).c_str () );
458 fprintf ( fMakefile,
459 ".PNONY: %s\n\n",
460 invokeTarget.c_str () );
461 }
462 }
463
464 string
465 MingwModuleHandler::GetPreconditionDependenciesName ( const Module& module ) const
466 {
467 return ssprintf ( "%s_precondition",
468 module.name.c_str () );
469 }
470
471 void
472 MingwModuleHandler::GeneratePreconditionDependencies ( const Module& module ) const
473 {
474 string preconditionDependenciesName = GetPreconditionDependenciesName ( module );
475 string sourceFilenames = GetSourceFilenames ( module );
476 string dependencies = GetModuleDependencies ( module );
477 string s = GetInvocationDependencies ( module );
478 if ( s.length () > 0 )
479 {
480 if ( dependencies.length () > 0 )
481 dependencies += " ";
482 dependencies += s;
483 }
484
485 fprintf ( fMakefile,
486 "%s: %s\n\n",
487 preconditionDependenciesName.c_str (),
488 dependencies.c_str () );
489 fprintf ( fMakefile,
490 "%s: %s\n\n",
491 sourceFilenames.c_str (),
492 preconditionDependenciesName.c_str ());
493 fprintf ( fMakefile,
494 ".PHONY: %s\n\n",
495 preconditionDependenciesName.c_str () );
496 }
497
498 static MingwBuildToolModuleHandler buildtool_handler;
499
500 MingwBuildToolModuleHandler::MingwBuildToolModuleHandler()
501 : MingwModuleHandler ( BuildTool )
502 {
503 }
504
505 void
506 MingwBuildToolModuleHandler::Process ( const Module& module )
507 {
508 GeneratePreconditionDependencies ( module );
509 GenerateBuildToolModuleTarget ( module );
510 GenerateInvocations ( module );
511 }
512
513 void
514 MingwBuildToolModuleHandler::GenerateBuildToolModuleTarget ( const Module& module )
515 {
516 string target ( FixupTargetFilename ( module.GetPath () ) );
517 string archiveFilename = GetModuleArchiveFilename ( module );
518 fprintf ( fMakefile, "%s: %s\n",
519 target.c_str (),
520 archiveFilename.c_str () );
521 fprintf ( fMakefile,
522 "\t${host_gcc} -o %s %s\n",
523 target.c_str (),
524 archiveFilename.c_str () );
525 GenerateArchiveTargetHost ( module );
526 GenerateObjectFileTargetsHost ( module );
527 }
528
529 static MingwKernelModuleHandler kernelmodule_handler;
530
531 MingwKernelModuleHandler::MingwKernelModuleHandler ()
532 : MingwModuleHandler ( KernelModeDLL )
533 {
534 }
535
536 void
537 MingwKernelModuleHandler::Process ( const Module& module )
538 {
539 GeneratePreconditionDependencies ( module );
540 GenerateKernelModuleTarget ( module );
541 GenerateInvocations ( module );
542 }
543
544 void
545 MingwKernelModuleHandler::GenerateKernelModuleTarget ( const Module& module )
546 {
547 static string ros_junk ( "$(ROS_TEMPORARY)" );
548 //static string ros_output ( "$(ROS_INTERMEDIATE)" );
549 string target ( FixupTargetFilename(module.GetPath()) );
550 string workingDirectory = GetWorkingDirectory ( );
551 string archiveFilename = GetModuleArchiveFilename ( module );
552 string importLibraryDependencies = GetImportLibraryDependencies ( module );
553 string base_tmp = ros_junk + module.name + ".base.tmp";
554 string junk_tmp = ros_junk + module.name + ".junk.tmp";
555 string temp_exp = ros_junk + module.name + ".temp.exp";
556 fprintf ( fMakefile, "%s: %s %s\n",
557 target.c_str (),
558 archiveFilename.c_str (),
559 importLibraryDependencies.c_str () );
560 fprintf ( fMakefile,
561 "\t${gcc} -Wl,--entry,_NtProcessStartup -Wl,-T,%s" SSEP "ntoskrnl.lnk -Wl,--subsystem,native -Wl,--image-base,0xC0000000 -Wl,--file-alignment,0x1000 -Wl,--section-alignment,0x1000 -Wl,--base-file,%s -nostartfiles -o %s %s %s\n",
562 module.GetBasePath ().c_str (),
563 base_tmp.c_str (),
564 junk_tmp.c_str (),
565 archiveFilename.c_str (),
566 importLibraryDependencies.c_str () );
567 fprintf ( fMakefile,
568 "\t${rm} %s\n",
569 junk_tmp.c_str () );
570 fprintf ( fMakefile,
571 "\t${dlltool} --dllname %s --base-file %s --output-exp %s --kill-at\n",
572 target.c_str (),
573 base_tmp.c_str (),
574 temp_exp.c_str ());
575 fprintf ( fMakefile,
576 "\t${rm} %s\n",
577 base_tmp.c_str () );
578 fprintf ( fMakefile,
579 "\t${ld} -Wl,%s -o %s %s %s\n",
580 temp_exp.c_str (),
581 target.c_str (),
582 archiveFilename.c_str (),
583 importLibraryDependencies.c_str () );
584 fprintf ( fMakefile,
585 "\t${rm} %s\n",
586 temp_exp.c_str () );
587
588 GenerateArchiveTargetTarget ( module );
589 GenerateObjectFileTargetsTarget ( module );
590 }
591
592 static MingwStaticLibraryModuleHandler staticlibrary_handler;
593
594 MingwStaticLibraryModuleHandler::MingwStaticLibraryModuleHandler ()
595 : MingwModuleHandler ( StaticLibrary )
596 {
597 }
598
599 void
600 MingwStaticLibraryModuleHandler::Process ( const Module& module )
601 {
602 GeneratePreconditionDependencies ( module );
603 GenerateStaticLibraryModuleTarget ( module );
604 GenerateInvocations ( module );
605 }
606
607 void
608 MingwStaticLibraryModuleHandler::GenerateStaticLibraryModuleTarget ( const Module& module )
609 {
610 GenerateArchiveTargetTarget ( module );
611 GenerateObjectFileTargetsTarget ( module );
612 }