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