af30e8c5962997b59dba07f1cc552395634bf20f
[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, "rsym = " TOOL_PREFIX "rsym" EXEPOSTFIX "\n" );
180 fprintf ( fMakefile, "wrc = " TOOL_PREFIX "wrc" SSEP "wrc" EXEPOSTFIX "\n" );
181 fprintf ( fMakefile, "\n" );
182 GenerateGlobalCFlagsAndProperties (
183 "=",
184 ProjectNode.non_if_data );
185 fprintf ( fMakefile, "PROJECT_RCFLAGS = $(PROJECT_CFLAGS)\n" );
186 fprintf ( fMakefile, "PROJECT_LFLAGS = %s\n",
187 GenerateProjectLFLAGS ().c_str () );
188 fprintf ( fMakefile, "\n" );
189 }
190
191 bool
192 MingwBackend::IncludeInAllTarget ( const Module& module ) const
193 {
194 if ( module.type == ObjectLibrary )
195 return false;
196 if ( module.type == BootSector )
197 return false;
198 if ( module.type == Iso )
199 return false;
200 return true;
201 }
202
203 void
204 MingwBackend::GenerateAllTarget () const
205 {
206 fprintf ( fMakefile, "all:" );
207 int wrap_count = 0;
208 for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
209 {
210 Module& module = *ProjectNode.modules[i];
211 if ( IncludeInAllTarget ( module ) )
212 {
213 if ( wrap_count++ == 5 )
214 fprintf ( fMakefile, " \\\n\t\t" ), wrap_count = 0;
215 fprintf ( fMakefile,
216 " %s",
217 FixupTargetFilename ( module.GetPath () ).c_str () );
218 }
219 }
220 fprintf ( fMakefile, "\n\t\n\n" );
221 }
222
223 string
224 MingwBackend::GetBuildToolDependencies () const
225 {
226 string dependencies;
227 for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
228 {
229 Module& module = *ProjectNode.modules[i];
230 if ( module.type == BuildTool )
231 {
232 if ( dependencies.length () > 0 )
233 dependencies += " ";
234 dependencies += module.GetDependencyPath ();
235 }
236 }
237 return dependencies;
238 }
239
240 void
241 MingwBackend::GenerateInitTarget () const
242 {
243 fprintf ( fMakefile,
244 "INIT = %s\n",
245 GetBuildToolDependencies ().c_str () );
246 fprintf ( fMakefile,
247 "\n" );
248 }
249
250 void
251 MingwBackend::GenerateXmlBuildFilesMacro() const
252 {
253 fprintf ( fMakefile,
254 "XMLBUILDFILES = %s \\\n",
255 ProjectNode.GetProjectFilename ().c_str () );
256 string xmlbuildFilenames;
257 int numberOfExistingFiles = 0;
258 for ( size_t i = 0; i < ProjectNode.xmlbuildfiles.size (); i++ )
259 {
260 XMLInclude& xmlbuildfile = *ProjectNode.xmlbuildfiles[i];
261 if ( !xmlbuildfile.fileExists )
262 continue;
263 numberOfExistingFiles++;
264 if ( xmlbuildFilenames.length () > 0 )
265 xmlbuildFilenames += " ";
266 xmlbuildFilenames += NormalizeFilename ( xmlbuildfile.topIncludeFilename );
267 if ( numberOfExistingFiles % 5 == 4 || i == ProjectNode.xmlbuildfiles.size () - 1 )
268 {
269 fprintf ( fMakefile,
270 "\t%s",
271 xmlbuildFilenames.c_str ());
272 if ( i == ProjectNode.xmlbuildfiles.size () - 1 )
273 {
274 fprintf ( fMakefile,
275 "\n" );
276 }
277 else
278 {
279 fprintf ( fMakefile,
280 " \\\n",
281 xmlbuildFilenames.c_str () );
282 }
283 xmlbuildFilenames.resize ( 0 );
284 }
285 numberOfExistingFiles++;
286 }
287 fprintf ( fMakefile,
288 "\n" );
289 }
290
291 void
292 MingwBackend::CheckAutomaticDependencies ()
293 {
294 AutomaticDependency automaticDependency ( ProjectNode );
295 automaticDependency.Process ();
296 automaticDependency.CheckAutomaticDependencies ();
297 }
298
299 void
300 MingwBackend::ProcessModule ( Module& module )
301 {
302 MingwModuleHandler* h = MingwModuleHandler::InstanciateHandler (
303 module.node.location,
304 module.type,
305 this );
306 MingwModuleHandler::string_list clean_files;
307 if ( module.host == HostDefault )
308 {
309 module.host = h->DefaultHost();
310 assert ( module.host != HostDefault );
311 }
312 h->Process ( module, clean_files );
313 h->GenerateCleanTarget ( module, clean_files );
314 }
315
316 bool
317 MingwBackend::IncludeDirectoryTarget ( const string& directory ) const
318 {
319 if ( directory == "$(INTERMEDIATE)tools")
320 return false;
321 else
322 return true;
323 }
324
325 void
326 MingwBackend::GenerateDirectoryTargets ()
327 {
328 if ( directories.size () == 0 )
329 return;
330
331 set_string::iterator i;
332 for ( i = directories.begin ();
333 i != directories.end ();
334 i++ )
335 {
336 if ( IncludeDirectoryTarget ( *i ) )
337 {
338 fprintf ( fMakefile,
339 "%s:\n",
340 i->c_str () );
341 fprintf ( fMakefile,
342 "\t${mkdir} %s\n\n",
343 i->c_str () );
344 }
345 }
346
347 directories.clear ();
348 }
349
350 string
351 FixupTargetFilename ( const string& targetFilename )
352 {
353 return string("$(INTERMEDIATE)") + NormalizeFilename ( targetFilename );
354 }
355
356 void
357 MingwBackend::DetectPCHSupport()
358 {
359 #ifdef WIN32
360 string sNUL = "NUL";
361 #else
362 string sNUL = "/dev/null";
363 #endif
364 string path = "tools" SSEP "rbuild" SSEP "backend" SSEP "mingw" SSEP "pch_detection.h";
365 string cmd = ssprintf(
366 "gcc -c %s 2>%s",
367 path.c_str (),
368 sNUL.c_str () );
369 system ( cmd.c_str() );
370 path += ".gch";
371
372 FILE* f = fopen ( path.c_str(), "rb" );
373 if ( f )
374 {
375 use_pch = true;
376 fclose(f);
377 unlink ( path.c_str() );
378 }
379 else
380 use_pch = false;
381
382 // TODO FIXME - eventually check for ROS_USE_PCH env var and
383 // allow that to override use_pch if true
384 }