Generate hooks and stubs for tests
[reactos.git] / reactos / tools / rbuild / project.cpp
1
2 #include "pch.h"
3 #include <assert.h>
4
5 #include "rbuild.h"
6
7 using std::string;
8 using std::vector;
9
10 /* static */ string
11 Environment::GetVariable ( const string& name )
12 {
13 char* value = getenv ( name.c_str () );
14 if ( value != NULL && strlen ( value ) > 0 )
15 return ssprintf ( "%s",
16 value );
17 else
18 return "";
19 }
20
21 /* static */ string
22 Environment::GetEnvironmentVariablePathOrDefault ( const string& name,
23 const string& defaultValue )
24 {
25 const string& environmentVariableValue = Environment::GetVariable ( name );
26 if ( environmentVariableValue.length () > 0 )
27 return NormalizeFilename ( environmentVariableValue );
28 else
29 return defaultValue;
30 }
31
32 /* static */ string
33 Environment::GetIntermediatePath ()
34 {
35 return GetEnvironmentVariablePathOrDefault ( "ROS_INTERMEDIATE",
36 "obj-i386" );
37 }
38
39 /* static */ string
40 Environment::GetOutputPath ()
41 {
42 return GetEnvironmentVariablePathOrDefault ( "ROS_OUTPUT",
43 "output-i386" );
44 }
45
46 /* static */ string
47 Environment::GetInstallPath ()
48 {
49 return GetEnvironmentVariablePathOrDefault ( "ROS_INSTALL",
50 "reactos" );
51 }
52
53
54 Project::Project ( const string& filename )
55 : xmlfile (filename),
56 node (NULL),
57 head (NULL)
58 {
59 ReadXml();
60 }
61
62 Project::~Project ()
63 {
64 size_t i;
65 for ( i = 0; i < modules.size (); i++ )
66 delete modules[i];
67 for ( i = 0; i < linkerFlags.size (); i++ )
68 delete linkerFlags[i];
69 for ( i = 0; i < cdfiles.size (); i++ )
70 delete cdfiles[i];
71 for ( i = 0; i < installfiles.size (); i++ )
72 delete installfiles[i];
73 delete head;
74 }
75
76 const Property*
77 Project::LookupProperty ( const string& name ) const
78 {
79 for ( size_t i = 0; i < non_if_data.properties.size (); i++ )
80 {
81 const Property* property = non_if_data.properties[i];
82 if ( property->name == name )
83 return property;
84 }
85 return NULL;
86 }
87
88 void
89 Project::SetConfigurationOption ( char* s,
90 string name,
91 string* alternativeName )
92 {
93 const Property* property = LookupProperty ( name );
94 if ( property != NULL && property->value.length () > 0 )
95 {
96 s = s + sprintf ( s,
97 "#define %s=%s\n",
98 property->name.c_str (),
99 property->value.c_str () );
100 }
101 else if ( property != NULL )
102 {
103 s = s + sprintf ( s,
104 "#define %s\n",
105 property->name.c_str () );
106 }
107 else if ( alternativeName != NULL )
108 {
109 s = s + sprintf ( s,
110 "#define %s\n",
111 alternativeName->c_str () );
112 }
113 }
114
115 void
116 Project::SetConfigurationOption ( char* s,
117 string name )
118 {
119 SetConfigurationOption ( s, name, NULL );
120 }
121
122 void
123 Project::WriteConfigurationFile ()
124 {
125 char* buf;
126 char* s;
127
128 buf = (char*) malloc ( 10*1024 );
129 if ( buf == NULL )
130 throw OutOfMemoryException ();
131
132 s = buf;
133 s = s + sprintf ( s, "/* Automatically generated. " );
134 s = s + sprintf ( s, "Edit config.xml to change configuration */\n" );
135 s = s + sprintf ( s, "#ifndef __INCLUDE_CONFIG_H\n" );
136 s = s + sprintf ( s, "#define __INCLUDE_CONFIG_H\n" );
137
138 SetConfigurationOption ( s, "ARCH" );
139 SetConfigurationOption ( s, "OPTIMIZED" );
140 SetConfigurationOption ( s, "MP", new string ( "UP" ) );
141 SetConfigurationOption ( s, "ACPI" );
142 SetConfigurationOption ( s, "_3GB" );
143
144 s = s + sprintf ( s, "#endif /* __INCLUDE_CONFIG_H */\n" );
145
146 FileSupportCode::WriteIfChanged ( buf, "include" SSEP "roscfg.h" );
147
148 free ( buf );
149 }
150
151 void
152 Project::ExecuteInvocations ()
153 {
154 for ( size_t i = 0; i < modules.size (); i++ )
155 modules[i]->InvokeModule ();
156 }
157
158 void
159 Project::ReadXml ()
160 {
161 Path path;
162 head = XMLLoadFile ( xmlfile, path, xmlbuildfiles );
163 node = NULL;
164 for ( size_t i = 0; i < head->subElements.size (); i++ )
165 {
166 if ( head->subElements[i]->name == "project" )
167 {
168 node = head->subElements[i];
169 string path;
170 this->ProcessXML ( path );
171 return;
172 }
173 }
174
175 throw InvalidBuildFileException (
176 node->location,
177 "Document contains no 'project' tag." );
178 }
179
180 void
181 Project::ProcessXML ( const string& path )
182 {
183 const XMLAttribute *att;
184 if ( node->name != "project" )
185 throw Exception ( "internal tool error: Project::ProcessXML() called with non-<project> node" );
186
187 att = node->GetAttribute ( "name", false );
188 if ( !att )
189 name = "Unnamed";
190 else
191 name = att->value;
192
193 att = node->GetAttribute ( "makefile", true );
194 assert(att);
195 makefile = att->value;
196
197 size_t i;
198 for ( i = 0; i < node->subElements.size (); i++ )
199 ProcessXMLSubElement ( *node->subElements[i], path );
200 for ( i = 0; i < modules.size (); i++ )
201 modules[i]->ProcessXML ();
202 for ( i = 0; i < linkerFlags.size (); i++ )
203 linkerFlags[i]->ProcessXML ();
204 non_if_data.ProcessXML ();
205 for ( i = 0; i < cdfiles.size (); i++ )
206 cdfiles[i]->ProcessXML ();
207 for ( i = 0; i < installfiles.size (); i++ )
208 installfiles[i]->ProcessXML ();
209 }
210
211 void
212 Project::ProcessXMLSubElement ( const XMLElement& e,
213 const string& path,
214 If* pIf )
215 {
216 bool subs_invalid = false;
217 string subpath(path);
218 if ( e.name == "module" )
219 {
220 if ( pIf )
221 throw InvalidBuildFileException (
222 e.location,
223 "<module> is not a valid sub-element of <if>" );
224 Module* module = new Module ( *this, e, path );
225 if ( LocateModule ( module->name ) )
226 throw InvalidBuildFileException (
227 node->location,
228 "module name conflict: '%s' (originally defined at %s)",
229 module->name.c_str(),
230 module->node.location.c_str() );
231 modules.push_back ( module );
232 return; // defer processing until later
233 }
234 else if ( e.name == "cdfile" )
235 {
236 CDFile* cdfile = new CDFile ( *this, e, path );
237 cdfiles.push_back ( cdfile );
238 subs_invalid = true;
239 }
240 else if ( e.name == "installfile" )
241 {
242 InstallFile* installfile = new InstallFile ( *this, e, path );
243 installfiles.push_back ( installfile );
244 subs_invalid = true;
245 }
246 else if ( e.name == "directory" )
247 {
248 const XMLAttribute* att = e.GetAttribute ( "name", true );
249 assert(att);
250 subpath = GetSubPath ( e.location, path, att->value );
251 }
252 else if ( e.name == "include" )
253 {
254 Include* include = new Include ( *this, e );
255 if ( pIf )
256 pIf->data.includes.push_back ( include );
257 else
258 non_if_data.includes.push_back ( include );
259 subs_invalid = true;
260 }
261 else if ( e.name == "define" )
262 {
263 Define* define = new Define ( *this, e );
264 if ( pIf )
265 pIf->data.defines.push_back ( define );
266 else
267 non_if_data.defines.push_back ( define );
268 subs_invalid = true;
269 }
270 else if ( e.name == "compilerflag" )
271 {
272 CompilerFlag* pCompilerFlag = new CompilerFlag ( *this, e );
273 if ( pIf )
274 pIf->data.compilerFlags.push_back ( pCompilerFlag );
275 else
276 non_if_data.compilerFlags.push_back ( pCompilerFlag );
277 subs_invalid = true;
278 }
279 else if ( e.name == "linkerflag" )
280 {
281 linkerFlags.push_back ( new LinkerFlag ( *this, e ) );
282 subs_invalid = true;
283 }
284 else if ( e.name == "if" )
285 {
286 If* pOldIf = pIf;
287 pIf = new If ( e, *this, NULL );
288 if ( pOldIf )
289 pOldIf->data.ifs.push_back ( pIf );
290 else
291 non_if_data.ifs.push_back ( pIf );
292 subs_invalid = false;
293 }
294 else if ( e.name == "property" )
295 {
296 Property* property = new Property ( e, *this, NULL );
297 if ( pIf )
298 pIf->data.properties.push_back ( property );
299 else
300 non_if_data.properties.push_back ( property );
301 }
302 if ( subs_invalid && e.subElements.size() )
303 throw InvalidBuildFileException (
304 e.location,
305 "<%s> cannot have sub-elements",
306 e.name.c_str() );
307 for ( size_t i = 0; i < e.subElements.size (); i++ )
308 ProcessXMLSubElement ( *e.subElements[i], subpath, pIf );
309 }
310
311 Module*
312 Project::LocateModule ( const string& name )
313 {
314 for ( size_t i = 0; i < modules.size (); i++ )
315 {
316 if (modules[i]->name == name)
317 return modules[i];
318 }
319
320 return NULL;
321 }
322
323 const Module*
324 Project::LocateModule ( const string& name ) const
325 {
326 for ( size_t i = 0; i < modules.size (); i++ )
327 {
328 if ( modules[i]->name == name )
329 return modules[i];
330 }
331
332 return NULL;
333 }
334
335 std::string
336 Project::GetProjectFilename () const
337 {
338 return xmlfile;
339 }
340
341