adjust newlines around rsym command
[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 = tools" SSEP "rmkdir" EXEPOSTFIX "\n" );
169 fprintf ( fMakefile, "winebuild = tools" SSEP "winebuild" SSEP "winebuild" EXEPOSTFIX "\n" );
170 fprintf ( fMakefile, "bin2res = tools" SSEP "bin2res" SSEP "bin2res" EXEPOSTFIX "\n" );
171 fprintf ( fMakefile, "cabman = tools" SSEP "cabman" SSEP "cabman" EXEPOSTFIX "\n" );
172 fprintf ( fMakefile, "cdmake = tools" SSEP "cdmake" SSEP "cdmake" EXEPOSTFIX "\n" );
173 fprintf ( fMakefile, "rsym = tools" SSEP "rsym" EXEPOSTFIX "\n" );
174 fprintf ( fMakefile, "wrc = 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 for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
205 {
206 Module& module = *ProjectNode.modules[i];
207 if ( IncludeInAllTarget ( module ) )
208 {
209 fprintf ( fMakefile,
210 " %s",
211 FixupTargetFilename ( module.GetPath () ).c_str () );
212 }
213 }
214 fprintf ( fMakefile, "\n\t\n\n" );
215 }
216
217 string
218 MingwBackend::GetBuildToolDependencies () const
219 {
220 string dependencies;
221 for ( size_t i = 0; i < ProjectNode.modules.size (); i++ )
222 {
223 Module& module = *ProjectNode.modules[i];
224 if ( module.type == BuildTool )
225 {
226 if ( dependencies.length () > 0 )
227 dependencies += " ";
228 dependencies += module.GetDependencyPath ();
229 }
230 }
231 return dependencies;
232 }
233
234 void
235 MingwBackend::GenerateInitTarget () const
236 {
237 fprintf ( fMakefile,
238 "init:");
239 fprintf ( fMakefile,
240 " $(ROS_INTERMEDIATE)." SSEP "tools" );
241 fprintf ( fMakefile,
242 " %s",
243 GetBuildToolDependencies ().c_str () );
244 fprintf ( fMakefile,
245 " %s",
246 "include" SSEP "reactos" SSEP "buildno.h" );
247 fprintf ( fMakefile,
248 "\n\t\n\n" );
249
250 fprintf ( fMakefile,
251 "$(ROS_INTERMEDIATE)." SSEP "tools:\n" );
252 fprintf ( fMakefile,
253 "ifneq ($(ROS_INTERMEDIATE),)\n" );
254 fprintf ( fMakefile,
255 "\t${nmkdir} $(ROS_INTERMEDIATE)\n" );
256 fprintf ( fMakefile,
257 "endif\n" );
258 fprintf ( fMakefile,
259 "\t${nmkdir} $(ROS_INTERMEDIATE)." SSEP "tools\n" );
260 fprintf ( fMakefile,
261 "\n" );
262 }
263
264 void
265 MingwBackend::GenerateXmlBuildFilesMacro() const
266 {
267 fprintf ( fMakefile,
268 "XMLBUILDFILES = %s \\\n",
269 ProjectNode.GetProjectFilename ().c_str () );
270 string xmlbuildFilenames;
271 int numberOfExistingFiles = 0;
272 for ( size_t i = 0; i < ProjectNode.xmlbuildfiles.size (); i++ )
273 {
274 XMLInclude& xmlbuildfile = *ProjectNode.xmlbuildfiles[i];
275 if ( !xmlbuildfile.fileExists )
276 continue;
277 numberOfExistingFiles++;
278 if ( xmlbuildFilenames.length () > 0 )
279 xmlbuildFilenames += " ";
280 xmlbuildFilenames += NormalizeFilename ( xmlbuildfile.topIncludeFilename );
281 if ( numberOfExistingFiles % 5 == 4 || i == ProjectNode.xmlbuildfiles.size () - 1 )
282 {
283 fprintf ( fMakefile,
284 "\t%s",
285 xmlbuildFilenames.c_str ());
286 if ( i == ProjectNode.xmlbuildfiles.size () - 1 )
287 {
288 fprintf ( fMakefile,
289 "\n" );
290 }
291 else
292 {
293 fprintf ( fMakefile,
294 " \\\n",
295 xmlbuildFilenames.c_str () );
296 }
297 xmlbuildFilenames.resize ( 0 );
298 }
299 numberOfExistingFiles++;
300 }
301 fprintf ( fMakefile,
302 "\n" );
303 }
304
305 void
306 MingwBackend::CheckAutomaticDependencies ()
307 {
308 AutomaticDependency automaticDependency ( ProjectNode );
309 automaticDependency.Process ();
310 automaticDependency.CheckAutomaticDependencies ();
311 }
312
313 void
314 MingwBackend::ProcessModule ( Module& module ) const
315 {
316 MingwModuleHandler* h = MingwModuleHandler::LookupHandler (
317 module.node.location,
318 module.type );
319 h->Process ( module );
320 h->GenerateDirectoryTargets ();
321 }
322
323 string
324 FixupTargetFilename ( const string& targetFilename )
325 {
326 return string("$(ROS_INTERMEDIATE)") + NormalizeFilename ( targetFilename );
327 }
328
329 void
330 MingwBackend::DetectPCHSupport()
331 {
332 string path = "tools" SSEP "rbuild" SSEP "backend" SSEP "mingw" SSEP "pch_detection.h";
333 system ( ssprintf("gcc -c %s", path.c_str()).c_str() );
334 path += ".gch";
335
336 FILE* f = fopen ( path.c_str(), "rb" );
337 if ( f )
338 {
339 use_pch = true;
340 fclose(f);
341 unlink ( path.c_str() );
342 }
343 else
344 use_pch = false;
345
346 // TODO FIXME - eventually check for ROS_USE_PCH env var and
347 // allow that to override use_pch if true
348 }