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