create a couple more variables to reduce makefile size
[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 + "_CFLAGS" );
241 fprintf ( fMakefile,
242 "%s := %s %s\n",
243 name.c_str(),
244 GenerateGccDefineParameters(module).c_str(),
245 GenerateGccIncludeParameters(module).c_str() );
246 }
247
248 string
249 MingwModuleHandler::GenerateGccIncludeParameters ( const Module& module ) const
250 {
251 string parameters = GenerateGccIncludeParametersFromVector ( module.includes );
252 string s = GenerateGccIncludeParametersFromVector ( module.project.includes );
253 if ( s.length () > 0 )
254 {
255 parameters += " ";
256 parameters += s;
257 }
258 return parameters;
259 }
260
261 string
262 MingwModuleHandler::GenerateGccParameters ( const Module& module ) const
263 {
264 return ssprintf(" $(%s_CFLAGS)", module.name.c_str());
265 }
266
267 string
268 MingwModuleHandler::GenerateNasmParameters ( const Module& module ) const
269 {
270 return "";
271 }
272
273 string
274 MingwModuleHandler::GenerateGccCommand ( const Module& module,
275 const string& sourceFilename,
276 const string& cc ) const
277 {
278 string objectFilename = GetObjectFilename ( sourceFilename );
279 return ssprintf ( "%s -c %s -o %s %s\n",
280 cc.c_str (),
281 sourceFilename.c_str (),
282 objectFilename.c_str (),
283 GenerateGccParameters ( module ).c_str () );
284 }
285
286 string
287 MingwModuleHandler::GenerateGccAssemblerCommand ( const Module& module,
288 const string& sourceFilename,
289 const string& cc ) const
290 {
291 string objectFilename = GetObjectFilename ( sourceFilename );
292 return ssprintf ( "%s -x assembler-with-cpp -c %s -o %s -D__ASM__ %s\n",
293 cc.c_str (),
294 sourceFilename.c_str (),
295 objectFilename.c_str (),
296 GenerateGccParameters ( module ).c_str () );
297 }
298
299 string
300 MingwModuleHandler::GenerateNasmCommand ( const Module& module,
301 const string& sourceFilename ) const
302 {
303 string objectFilename = GetObjectFilename ( sourceFilename );
304 return ssprintf ( "%s -f win32 %s -o %s %s\n",
305 "nasm",
306 sourceFilename.c_str (),
307 objectFilename.c_str (),
308 GenerateNasmParameters ( module ).c_str () );
309 }
310
311 string
312 MingwModuleHandler::GenerateCommand ( const Module& module,
313 const string& sourceFilename,
314 const string& cc ) const
315 {
316 string extension = GetExtension ( sourceFilename );
317 if ( extension == ".c" || extension == ".C" )
318 return GenerateGccCommand ( module,
319 sourceFilename,
320 cc );
321 else if ( extension == ".s" || extension == ".S" )
322 return GenerateGccAssemblerCommand ( module,
323 sourceFilename,
324 cc );
325 else if ( extension == ".asm" || extension == ".ASM" )
326 return GenerateNasmCommand ( module,
327 sourceFilename );
328
329 throw InvalidOperationException ( __FILE__,
330 __LINE__,
331 "Unsupported filename extension '%s' in file '%s'",
332 extension.c_str (),
333 sourceFilename.c_str () );
334 }
335
336 void
337 MingwModuleHandler::GenerateObjectFileTargets ( const Module& module,
338 const string& cc) const
339 {
340 if ( module.files.size () == 0 )
341 return;
342
343 GenerateGccModuleIncludeVariable ( module );
344
345 for ( size_t i = 0; i < module.files.size (); i++ )
346 {
347 string sourceFilename = module.files[i]->name;
348 string objectFilename = GetObjectFilename ( sourceFilename );
349 fprintf ( fMakefile,
350 "%s: %s\n",
351 objectFilename.c_str (),
352 sourceFilename.c_str () );
353 fprintf ( fMakefile,
354 "\t%s\n",
355 GenerateCommand ( module,
356 sourceFilename,
357 cc ).c_str () );
358 }
359
360 fprintf ( fMakefile, "\n" );
361 }
362
363 void
364 MingwModuleHandler::GenerateObjectFileTargetsHost ( const Module& module ) const
365 {
366 GenerateObjectFileTargets ( module,
367 "${host_gcc}" );
368 }
369
370 void
371 MingwModuleHandler::GenerateObjectFileTargetsTarget ( const Module& module ) const
372 {
373 GenerateObjectFileTargets ( module,
374 "${gcc}" );
375 }
376
377 void
378 MingwModuleHandler::GenerateArchiveTarget ( const Module& module,
379 const string& ar ) const
380 {
381 string archiveFilename = GetModuleArchiveFilename ( module );
382 string sourceFilenames = GetSourceFilenames ( module );
383 string objectsMacro = GenerateObjectList ( module );
384
385 fprintf ( fMakefile,
386 "%s: %s\n",
387 archiveFilename.c_str (),
388 objectsMacro.c_str ());
389
390 fprintf ( fMakefile,
391 "\t%s -rc %s %s\n\n",
392 ar.c_str (),
393 archiveFilename.c_str (),
394 objectsMacro.c_str ());
395 }
396
397 void
398 MingwModuleHandler::GenerateArchiveTargetHost ( const Module& module ) const
399 {
400 GenerateArchiveTarget ( module,
401 "${host_ar}" );
402 }
403
404 void
405 MingwModuleHandler::GenerateArchiveTargetTarget ( const Module& module ) const
406 {
407 GenerateArchiveTarget ( module,
408 "${ar}" );
409 }
410
411 string
412 MingwModuleHandler::GetInvocationDependencies ( const Module& module ) const
413 {
414 string dependencies;
415 for ( size_t i = 0; i < module.invocations.size (); i++ )
416 {
417 Invoke& invoke = *module.invocations[i];
418 if (invoke.invokeModule == &module)
419 /* Protect against circular dependencies */
420 continue;
421 if ( dependencies.length () > 0 )
422 dependencies += " ";
423 dependencies += invoke.GetTargets ();
424 }
425 return dependencies;
426 }
427
428 string
429 MingwModuleHandler::GetInvocationParameters ( const Invoke& invoke ) const
430 {
431 string parameters ( "" );
432 size_t i;
433 for (i = 0; i < invoke.output.size (); i++)
434 {
435 if (parameters.length () > 0)
436 parameters += " ";
437 InvokeFile& invokeFile = *invoke.output[i];
438 if (invokeFile.switches.length () > 0)
439 {
440 parameters += invokeFile.switches;
441 parameters += " ";
442 }
443 parameters += invokeFile.name;
444 }
445
446 for (i = 0; i < invoke.input.size (); i++)
447 {
448 if (parameters.length () > 0)
449 parameters += " ";
450 InvokeFile& invokeFile = *invoke.input[i];
451 if (invokeFile.switches.length () > 0)
452 {
453 parameters += invokeFile.switches;
454 parameters += " ";
455 }
456 parameters += invokeFile.name;
457 }
458
459 return parameters;
460 }
461
462 void
463 MingwModuleHandler::GenerateInvocations ( const Module& module ) const
464 {
465 if ( module.invocations.size () == 0 )
466 return;
467
468 for ( size_t i = 0; i < module.invocations.size (); i++ )
469 {
470 const Invoke& invoke = *module.invocations[i];
471
472 if ( invoke.invokeModule->type != BuildTool )
473 throw InvalidBuildFileException ( module.node.location,
474 "Only modules of type buildtool can be invoked." );
475
476 string invokeTarget = module.GetInvocationTarget ( i );
477 fprintf ( fMakefile,
478 "%s: %s\n\n",
479 invoke.GetTargets ().c_str (),
480 invokeTarget.c_str () );
481 fprintf ( fMakefile,
482 "%s: %s\n",
483 invokeTarget.c_str (),
484 FixupTargetFilename ( invoke.invokeModule->GetPath () ).c_str () );
485 fprintf ( fMakefile,
486 "\t%s %s\n\n",
487 FixupTargetFilename ( invoke.invokeModule->GetPath () ).c_str (),
488 GetInvocationParameters ( invoke ).c_str () );
489 fprintf ( fMakefile,
490 ".PNONY: %s\n\n",
491 invokeTarget.c_str () );
492 }
493 }
494
495 string
496 MingwModuleHandler::GetPreconditionDependenciesName ( const Module& module ) const
497 {
498 return ssprintf ( "%s_precondition",
499 module.name.c_str () );
500 }
501
502 void
503 MingwModuleHandler::GeneratePreconditionDependencies ( const Module& module ) const
504 {
505 string preconditionDependenciesName = GetPreconditionDependenciesName ( module );
506 string sourceFilenames = GetSourceFilenames ( module );
507 string dependencies = GetModuleDependencies ( module );
508 string s = GetInvocationDependencies ( module );
509 if ( s.length () > 0 )
510 {
511 if ( dependencies.length () > 0 )
512 dependencies += " ";
513 dependencies += s;
514 }
515
516 fprintf ( fMakefile,
517 "%s: %s\n\n",
518 preconditionDependenciesName.c_str (),
519 dependencies.c_str () );
520 fprintf ( fMakefile,
521 "%s: %s\n\n",
522 sourceFilenames.c_str (),
523 preconditionDependenciesName.c_str ());
524 fprintf ( fMakefile,
525 ".PHONY: %s\n\n",
526 preconditionDependenciesName.c_str () );
527 }
528
529 string MingwModuleHandler::GenerateObjectList ( const Module& module ) const
530 {
531 string macro ( ssprintf("%s_OBJS",module.name.c_str()) );
532 fprintf (
533 fMakefile,
534 "%s = %s\n",
535 macro.c_str(),
536 GetObjectFilenames(module).c_str() );
537 return ssprintf("$(%s)",macro.c_str());
538 }
539
540
541 static MingwBuildToolModuleHandler buildtool_handler;
542
543 MingwBuildToolModuleHandler::MingwBuildToolModuleHandler()
544 : MingwModuleHandler ( BuildTool )
545 {
546 }
547
548 void
549 MingwBuildToolModuleHandler::Process ( const Module& module )
550 {
551 GeneratePreconditionDependencies ( module );
552 GenerateBuildToolModuleTarget ( module );
553 GenerateInvocations ( module );
554 }
555
556 void
557 MingwBuildToolModuleHandler::GenerateBuildToolModuleTarget ( const Module& module )
558 {
559 string target ( FixupTargetFilename ( module.GetPath () ) );
560 string archiveFilename = GetModuleArchiveFilename ( module );
561 fprintf ( fMakefile, "%s: %s\n",
562 target.c_str (),
563 archiveFilename.c_str () );
564 fprintf ( fMakefile,
565 "\t${host_gcc} -o %s %s\n",
566 target.c_str (),
567 archiveFilename.c_str () );
568 GenerateArchiveTargetHost ( module );
569 GenerateObjectFileTargetsHost ( module );
570 }
571
572 static MingwKernelModuleHandler kernelmodule_handler;
573
574 MingwKernelModuleHandler::MingwKernelModuleHandler ()
575 : MingwModuleHandler ( Kernel )
576 {
577 }
578
579 void
580 MingwKernelModuleHandler::Process ( const Module& module )
581 {
582 GeneratePreconditionDependencies ( module );
583 GenerateKernelModuleTarget ( module );
584 GenerateInvocations ( module );
585 }
586
587 void
588 MingwKernelModuleHandler::GenerateKernelModuleTarget ( const Module& module )
589 {
590 static string ros_junk ( "$(ROS_TEMPORARY)" );
591 //static string ros_output ( "$(ROS_INTERMEDIATE)" );
592 string target ( FixupTargetFilename(module.GetPath()) );
593 string workingDirectory = GetWorkingDirectory ( );
594 string archiveFilename = GetModuleArchiveFilename ( module );
595 string importLibraryDependencies = GetImportLibraryDependencies ( module );
596 string base_tmp = ros_junk + module.name + ".base.tmp";
597 string junk_tmp = ros_junk + module.name + ".junk.tmp";
598 string temp_exp = ros_junk + module.name + ".temp.exp";
599 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",
600 module.GetBasePath ().c_str () );
601 fprintf ( fMakefile, "%s: %s %s\n",
602 target.c_str (),
603 archiveFilename.c_str (),
604 importLibraryDependencies.c_str () );
605 fprintf ( fMakefile,
606 "\t${gcc} %s -Wl,--base-file,%s -o %s %s %s\n",
607 gccOptions.c_str (),
608 base_tmp.c_str (),
609 junk_tmp.c_str (),
610 archiveFilename.c_str (),
611 importLibraryDependencies.c_str () );
612 fprintf ( fMakefile,
613 "\t${rm} %s\n",
614 junk_tmp.c_str () );
615 fprintf ( fMakefile,
616 "\t${dlltool} --dllname %s --base-file %s --output-exp %s --kill-at\n",
617 target.c_str (),
618 base_tmp.c_str (),
619 temp_exp.c_str ());
620 fprintf ( fMakefile,
621 "\t${rm} %s\n",
622 base_tmp.c_str () );
623 fprintf ( fMakefile,
624 "\t${gcc} %s -Wl,%s -o %s %s %s\n",
625 gccOptions.c_str (),
626 temp_exp.c_str (),
627 target.c_str (),
628 archiveFilename.c_str (),
629 importLibraryDependencies.c_str () );
630 fprintf ( fMakefile,
631 "\t${rm} %s\n",
632 temp_exp.c_str () );
633
634 GenerateArchiveTargetTarget ( module );
635 GenerateObjectFileTargetsTarget ( module );
636 }
637
638
639 static MingwStaticLibraryModuleHandler staticlibrary_handler;
640
641 MingwStaticLibraryModuleHandler::MingwStaticLibraryModuleHandler ()
642 : MingwModuleHandler ( StaticLibrary )
643 {
644 }
645
646 void
647 MingwStaticLibraryModuleHandler::Process ( const Module& module )
648 {
649 GeneratePreconditionDependencies ( module );
650 GenerateStaticLibraryModuleTarget ( module );
651 GenerateInvocations ( module );
652 }
653
654 void
655 MingwStaticLibraryModuleHandler::GenerateStaticLibraryModuleTarget ( const Module& module )
656 {
657 GenerateArchiveTargetTarget ( module );
658 GenerateObjectFileTargetsTarget ( module );
659 }
660
661
662 static MingwKernelModeDLLModuleHandler kernelmodedll_handler;
663
664 MingwKernelModeDLLModuleHandler::MingwKernelModeDLLModuleHandler ()
665 : MingwModuleHandler ( KernelModeDLL )
666 {
667 }
668
669 void
670 MingwKernelModeDLLModuleHandler::Process ( const Module& module )
671 {
672 GeneratePreconditionDependencies ( module );
673 GenerateKernelModeDLLModuleTarget ( module );
674 GenerateInvocations ( module );
675 }
676
677 void
678 MingwKernelModeDLLModuleHandler::GenerateKernelModeDLLModuleTarget ( const Module& module )
679 {
680 static string ros_junk ( "$(ROS_TEMPORARY)" );
681 string target ( FixupTargetFilename ( module.GetPath () ) );
682 string workingDirectory = GetWorkingDirectory ( );
683 string archiveFilename = GetModuleArchiveFilename ( module );
684 string importLibraryDependencies = GetImportLibraryDependencies ( module );
685
686 if (module.importLibrary != NULL)
687 {
688 fprintf ( fMakefile, "%s:\n",
689 module.GetDependencyPath ().c_str () );
690
691 fprintf ( fMakefile,
692 "\t${dlltool} --dllname %s --def %s --output-lib %s --kill-at\n\n",
693 module.GetTargetName ().c_str (),
694 FixupTargetFilename ( module.GetBasePath () + SSEP + module.importLibrary->definition ).c_str (),
695 FixupTargetFilename ( module.GetDependencyPath () ).c_str () );
696 }
697
698 if (module.files.size () > 0)
699 {
700 fprintf ( fMakefile, "%s: %s %s\n",
701 target.c_str (),
702 archiveFilename.c_str (),
703 importLibraryDependencies.c_str () );
704
705 fprintf ( fMakefile,
706 "\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",
707 target.c_str (),
708 archiveFilename.c_str (),
709 importLibraryDependencies.c_str () );
710
711 GenerateArchiveTargetTarget ( module );
712 GenerateObjectFileTargetsTarget ( module );
713 }
714 else
715 {
716 fprintf ( fMakefile, "%s:\n\n",
717 target.c_str ());
718 fprintf ( fMakefile, ".PHONY: %s\n\n",
719 target.c_str ());
720 }
721 }