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