Test module type support
[reactos.git] / reactos / tools / rbuild / backend / mingw / mingw.cpp
1
2 #include "../../pch.h"
3
4 #include "mingw.h"
5 #include <assert.h>
6
7 using std::string;
8 using std::vector;
9 using std::set;
10
11 typedef set<string> set_string;
12
13 static class MingwFactory : public Backend::Factory
14 {
15 public:
16 MingwFactory() : Factory ( "mingw" ) {}
17 Backend* operator() ( Project& project )
18 {
19 return new MingwBackend ( project );
20 }
21 } factory;
22
23
24 MingwBackend::MingwBackend ( Project& project )
25 : Backend ( project )
26 {
27 }
28
29 void
30 MingwBackend::CreateDirectoryTargetIfNotYetCreated ( const string& directory )
31 {
32 directories.insert ( directory );
33 }
34
35
36 void
37 MingwBackend::Process ()
38 {
39 DetectPCHSupport();
40
41 CreateMakefile ();
42 GenerateHeader ();
43 GenerateGlobalVariables ();
44 GenerateAllTarget ();
45 GenerateInitTarget ();
46 GenerateXmlBuildFilesMacro();
47 for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
48 {
49 Module& module = *ProjectNode.modules[i];
50 ProcessModule ( module );
51 }
52 GenerateDirectoryTargets ();
53 CheckAutomaticDependencies ();
54 CloseMakefile ();
55 }
56
57 void
58 MingwBackend::CreateMakefile ()
59 {
60 fMakefile = fopen ( ProjectNode.makefile.c_str (), "w" );
61 if ( !fMakefile )
62 throw AccessDeniedException ( ProjectNode.makefile );
63 MingwModuleHandler::SetMakefile ( fMakefile );
64 MingwModuleHandler::SetUsePch ( use_pch );
65 }
66
67 void
68 MingwBackend::CloseMakefile () const
69 {
70 if (fMakefile)
71 fclose ( fMakefile );
72 }
73
74 void
75 MingwBackend::GenerateHeader () const
76 {
77 fprintf ( fMakefile, "# THIS FILE IS AUTOMATICALLY GENERATED, EDIT 'ReactOS.xml' INSTEAD\n\n" );
78 }
79
80 void
81 MingwBackend::GenerateProjectCFlagsMacro ( const char* assignmentOperation,
82 IfableData& data ) const
83 {
84 size_t i;
85
86 fprintf (
87 fMakefile,
88 "PROJECT_CFLAGS %s",
89 assignmentOperation );
90 for ( i = 0; i < data.includes.size(); i++ )
91 {
92 fprintf (
93 fMakefile,
94 " -I%s",
95 data.includes[i]->directory.c_str() );
96 }
97
98 for ( i = 0; i < data.defines.size(); i++ )
99 {
100 Define& d = *data.defines[i];
101 fprintf (
102 fMakefile,
103 " -D%s",
104 d.name.c_str() );
105 if ( d.value.size() )
106 fprintf (
107 fMakefile,
108 "=%s",
109 d.value.c_str() );
110 }
111 fprintf ( fMakefile, "\n" );
112 }
113
114 void
115 MingwBackend::GenerateGlobalCFlagsAndProperties (
116 const char* assignmentOperation,
117 IfableData& data ) const
118 {
119 size_t i;
120
121 for ( i = 0; i < data.properties.size(); i++ )
122 {
123 Property& prop = *data.properties[i];
124 fprintf ( fMakefile, "%s := %s\n",
125 prop.name.c_str(),
126 prop.value.c_str() );
127 }
128
129 if ( data.includes.size() || data.defines.size() )
130 {
131 GenerateProjectCFlagsMacro ( assignmentOperation,
132 data );
133 }
134
135 for ( i = 0; i < data.ifs.size(); i++ )
136 {
137 If& rIf = *data.ifs[i];
138 if ( rIf.data.defines.size()
139 || rIf.data.includes.size()
140 || rIf.data.ifs.size() )
141 {
142 fprintf (
143 fMakefile,
144 "ifeq (\"$(%s)\",\"%s\")\n",
145 rIf.property.c_str(),
146 rIf.value.c_str() );
147 GenerateGlobalCFlagsAndProperties (
148 "+=",
149 rIf.data );
150 fprintf (
151 fMakefile,
152 "endif\n\n" );
153 }
154 }
155 }
156
157 string
158 MingwBackend::GenerateProjectLFLAGS () const
159 {
160 string lflags;
161 for ( size_t i = 0; i < ProjectNode.linkerFlags.size (); i++ )
162 {
163 LinkerFlag& linkerFlag = *ProjectNode.linkerFlags[i];
164 if ( lflags.length () > 0 )
165 lflags += " ";
166 lflags += linkerFlag.flag;
167 }
168 return lflags;
169 }
170
171 void
172 MingwBackend::GenerateGlobalVariables () const
173 {
174 #define TOOL_PREFIX "$(Q)$(INTERMEDIATE)tools" SSEP
175 fprintf ( fMakefile, "winebuild = " TOOL_PREFIX "winebuild" SSEP "winebuild" EXEPOSTFIX "\n" );
176 fprintf ( fMakefile, "bin2res = " TOOL_PREFIX "bin2res" SSEP "bin2res" EXEPOSTFIX "\n" );
177 fprintf ( fMakefile, "cabman = " TOOL_PREFIX "cabman" SSEP "cabman" EXEPOSTFIX "\n" );
178 fprintf ( fMakefile, "cdmake = " TOOL_PREFIX "cdmake" SSEP "cdmake" EXEPOSTFIX "\n" );
179 fprintf ( fMakefile, "regtests = " TOOL_PREFIX "regtests" EXEPOSTFIX "\n" );
180 fprintf ( fMakefile, "rsym = " TOOL_PREFIX "rsym" EXEPOSTFIX "\n" );
181 fprintf ( fMakefile, "wrc = " TOOL_PREFIX "wrc" SSEP "wrc" EXEPOSTFIX "\n" );
182 fprintf ( fMakefile, "\n" );
183 GenerateGlobalCFlagsAndProperties (
184 "=",
185 ProjectNode.non_if_data );
186 fprintf ( fMakefile, "PROJECT_RCFLAGS = $(PROJECT_CFLAGS)\n" );
187 fprintf ( fMakefile, "PROJECT_LFLAGS = %s\n",
188 GenerateProjectLFLAGS ().c_str () );
189 fprintf ( fMakefile, "\n" );
190 }
191
192 bool
193 MingwBackend::IncludeInAllTarget ( const Module& module ) const
194 {
195 if ( module.type == ObjectLibrary )
196 return false;
197 if ( module.type == BootSector )
198 return false;
199 if ( module.type == Iso )
200 return false;
201 return true;
202 }
203
204 void
205 MingwBackend::GenerateAllTarget () const
206 {
207 fprintf ( fMakefile, "all:" );
208 int wrap_count = 0;
209 for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
210 {
211 Module& module = *ProjectNode.modules[i];
212 if ( IncludeInAllTarget ( module ) )
213 {
214 if ( wrap_count++ == 5 )
215 fprintf ( fMakefile, " \\\n\t\t" ), wrap_count = 0;
216 fprintf ( fMakefile,
217 " %s",
218 FixupTargetFilename ( module.GetPath () ).c_str () );
219 }
220 }
221 fprintf ( fMakefile, "\n\t\n\n" );
222 }
223
224 string
225 MingwBackend::GetBuildToolDependencies () const
226 {
227 string dependencies;
228 for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
229 {
230 Module& module = *ProjectNode.modules[i];
231 if ( module.type == BuildTool )
232 {
233 if ( dependencies.length () > 0 )
234 dependencies += " ";
235 dependencies += module.GetDependencyPath ();
236 }
237 }
238 return dependencies;
239 }
240
241 void
242 MingwBackend::GenerateInitTarget () const
243 {
244 fprintf ( fMakefile,
245 "INIT = %s\n",
246 GetBuildToolDependencies ().c_str () );
247 fprintf ( fMakefile,
248 "\n" );
249 }
250
251 void
252 MingwBackend::GenerateXmlBuildFilesMacro() const
253 {
254 fprintf ( fMakefile,
255 "XMLBUILDFILES = %s \\\n",
256 ProjectNode.GetProjectFilename ().c_str () );
257 string xmlbuildFilenames;
258 int numberOfExistingFiles = 0;
259 for ( size_t i = 0; i < ProjectNode.xmlbuildfiles.size (); i++ )
260 {
261 XMLInclude& xmlbuildfile = *ProjectNode.xmlbuildfiles[i];
262 if ( !xmlbuildfile.fileExists )
263 continue;
264 numberOfExistingFiles++;
265 if ( xmlbuildFilenames.length () > 0 )
266 xmlbuildFilenames += " ";
267 xmlbuildFilenames += NormalizeFilename ( xmlbuildfile.topIncludeFilename );
268 if ( numberOfExistingFiles % 5 == 4 || i == ProjectNode.xmlbuildfiles.size () - 1 )
269 {
270 fprintf ( fMakefile,
271 "\t%s",
272 xmlbuildFilenames.c_str ());
273 if ( i == ProjectNode.xmlbuildfiles.size () - 1 )
274 {
275 fprintf ( fMakefile,
276 "\n" );
277 }
278 else
279 {
280 fprintf ( fMakefile,
281 " \\\n",
282 xmlbuildFilenames.c_str () );
283 }
284 xmlbuildFilenames.resize ( 0 );
285 }
286 numberOfExistingFiles++;
287 }
288 fprintf ( fMakefile,
289 "\n" );
290 }
291
292 void
293 MingwBackend::CheckAutomaticDependencies ()
294 {
295 AutomaticDependency automaticDependency ( ProjectNode );
296 automaticDependency.Process ();
297 automaticDependency.CheckAutomaticDependencies ();
298 }
299
300 void
301 MingwBackend::ProcessModule ( Module& module )
302 {
303 MingwModuleHandler* h = MingwModuleHandler::InstanciateHandler (
304 module.node.location,
305 module.type,
306 this );
307 MingwModuleHandler::string_list clean_files;
308 if ( module.host == HostDefault )
309 {
310 module.host = h->DefaultHost();
311 assert ( module.host != HostDefault );
312 }
313 h->Process ( module, clean_files );
314 h->GenerateCleanTarget ( module, clean_files );
315 }
316
317 bool
318 MingwBackend::IncludeDirectoryTarget ( const string& directory ) const
319 {
320 if ( directory == "$(INTERMEDIATE)tools")
321 return false;
322 else
323 return true;
324 }
325
326 void
327 MingwBackend::GenerateDirectoryTargets ()
328 {
329 if ( directories.size () == 0 )
330 return;
331
332 set_string::iterator i;
333 for ( i = directories.begin ();
334 i != directories.end ();
335 i++ )
336 {
337 if ( IncludeDirectoryTarget ( *i ) )
338 {
339 fprintf ( fMakefile,
340 "%s: $(RMKDIR_TARGET)\n",
341 i->c_str () );
342 fprintf ( fMakefile,
343 "\t${mkdir} %s\n\n",
344 i->c_str () );
345 }
346 }
347
348 directories.clear ();
349 }
350
351 string
352 FixupTargetFilename ( const string& targetFilename )
353 {
354 return string("$(INTERMEDIATE)") + NormalizeFilename ( targetFilename );
355 }
356
357 void
358 MingwBackend::DetectPCHSupport()
359 {
360 #ifdef WIN32
361 string sNUL = "NUL";
362 #else
363 string sNUL = "/dev/null";
364 #endif
365 string path = "tools" SSEP "rbuild" SSEP "backend" SSEP "mingw" SSEP "pch_detection.h";
366 string cmd = ssprintf(
367 "gcc -c %s 2>%s",
368 path.c_str (),
369 sNUL.c_str () );
370 system ( cmd.c_str() );
371 path += ".gch";
372
373 FILE* f = fopen ( path.c_str(), "rb" );
374 if ( f )
375 {
376 use_pch = true;
377 fclose(f);
378 unlink ( path.c_str() );
379 }
380 else
381 use_pch = false;
382
383 // TODO FIXME - eventually check for ROS_USE_PCH env var and
384 // allow that to override use_pch if true
385 }