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