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