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