25adae1cdb4dd72b6535949518c5e71d7e94daa5
[reactos.git] / reactos / tools / rbuild / backend / msvc / msvc.cpp
1 /*
2 * Copyright (C) 2005 Trevor McCort
3 * Copyright (C) 2005 Casper S. Hornstrup
4 * Copyright (C) 2005 Steven Edwards
5 * Copyright (C) 2005 Royce Mitchell
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 #ifdef _MSC_VER
22 #pragma warning ( disable : 4786 )
23 #endif//_MSC_VER
24
25 #include <iostream>
26 #include <fstream>
27 #include <string>
28 #include <vector>
29
30 #include "msvc.h"
31 #include "../mingw/mingw.h"
32
33 using std::string;
34 using std::vector;
35 using std::ifstream;
36
37 static class MSVCFactory : public Backend::Factory
38 {
39 public:
40
41 MSVCFactory() : Factory("MSVC") {}
42 Backend *operator() (Project &project,
43 Configuration& configuration)
44 {
45 return new MSVCBackend(project, configuration);
46 }
47
48 } factory;
49
50
51 MSVCBackend::MSVCBackend(Project &project,
52 Configuration& configuration) : Backend(project, configuration)
53 {
54 m_unitCount = 0;
55 }
56
57 void MSVCBackend::Process()
58 {
59 if ( configuration.CleanAsYouGo ) {
60 _clean_project_files();
61 return;
62 }
63
64 string filename_sln ( ProjectNode.name );
65 //string filename_rules = "gccasm.rules";
66
67 if ( configuration.VSProjectVersion == "6.00" )
68 filename_sln += ".dsw";
69 else {
70 filename_sln += ".sln";
71
72 //m_rulesFile = fopen ( filename_rules.c_str(), "wb" );
73 //if ( m_rulesFile )
74 //{
75 // _generate_rules_file ( m_rulesFile );
76 //}
77 //fclose ( m_rulesFile );
78 }
79
80 printf ( "Creating MSVC workspace: %s\n", filename_sln.c_str() );
81
82 ProcessModules();
83 m_slnFile = fopen ( filename_sln.c_str(), "wb" );
84
85 if ( !m_slnFile )
86 {
87 printf ( "Could not create file '%s'.\n", filename_sln.c_str() );
88 return;
89 }
90
91 if ( configuration.VSProjectVersion == "6.00" )
92 _generate_wine_dsw ( m_slnFile );
93 else
94 _generate_sln ( m_slnFile );
95
96 fclose ( m_slnFile );
97 printf ( "Done.\n" );
98 }
99
100 void MSVCBackend::ProcessModules()
101 {
102 for(size_t i = 0; i < ProjectNode.modules.size(); i++)
103 {
104 Module &module = *ProjectNode.modules[i];
105
106 module.guid = _gen_guid();
107
108 if (configuration.VSProjectVersion == "6.00")
109 this->_generate_dsp ( module );
110 else
111 this->_generate_vcproj ( module );
112
113
114 /*for(size_t k = 0; k < module.non_if_data.files.size(); k++)
115 {
116 File &file = *module.non_if_data.files[k];
117
118 ProcessFile(file.name);
119 }*/
120 }
121 }
122
123 static bool FileExists(string &filename)
124 {
125 ifstream file(filename.c_str());
126
127 if(!file.is_open())
128 return false;
129
130 file.close();
131 return true;
132 }
133
134 void MSVCBackend::ProcessFile(string &filepath)
135 {
136 // Remove the .\ at the start of the filenames
137 if ( filepath[0] == '.' && strchr ( "/\\", filepath[1] ) )
138 filepath.erase(0, 2);
139
140 if(!FileExists(filepath))
141 return;
142
143 // Change the \ to /
144 for(size_t i = 0; i < filepath.length(); i++)
145 {
146 if(filepath[i] == '\\')
147 filepath[i] = '/';
148 }
149
150 // Remove the filename from the path
151 string folder = "";
152
153 size_t pos = filepath.rfind(string("/"), filepath.length() - 1);
154
155 if(pos != string::npos)
156 {
157 folder = filepath;
158 folder.erase(pos, folder.length() - pos);
159 }
160
161 FileUnit fileUnit;
162 fileUnit.filename = filepath;
163 fileUnit.folder = folder;
164
165 m_fileUnits.push_back(fileUnit);
166
167 if(folder != "")
168 AddFolders(folder);
169
170 m_unitCount++;
171 }
172
173 bool MSVCBackend::CheckFolderAdded(string &folder)
174 {
175 for(size_t i = 0; i < m_folders.size(); i++)
176 {
177 if(m_folders[i] == folder)
178 return true;
179 }
180
181 return false;
182 }
183
184 void MSVCBackend::AddFolders(string &folder)
185 {
186 // Check if this folder was already added. true if it was, false otherwise.
187 if(CheckFolderAdded(folder))
188 return;
189
190 m_folders.push_back(folder);
191
192 size_t pos = folder.rfind(string("/"), folder.length() - 1);
193
194 if(pos == string::npos)
195 return;
196
197 folder.erase(pos, folder.length() - pos);
198 AddFolders(folder);
199 }
200
201 void MSVCBackend::OutputFolders()
202 {
203 #if 0
204 m_devFile << "Folders=";
205
206 for(size_t i = 0; i < m_folders.size(); i++)
207 {
208 if(i > 0)
209 m_devFile << ",";
210
211 m_devFile << m_folders[i];
212 }
213 #endif
214 }
215
216 std::string
217 MSVCBackend::OptFileName ( const Module& module ) const
218 {
219 return DosSeparator(
220 ReplaceExtension ( module.GetPath(), "_" + _get_vc_dir() + "_auto.opt" )
221 );
222 }
223
224 std::string
225 MSVCBackend::SuoFileName ( const Module& module ) const
226 {
227 return DosSeparator(
228 ReplaceExtension ( module.GetPath(), "_" + _get_vc_dir() + "_auto.suo" )
229 );
230 }
231
232 std::string
233 MSVCBackend::DswFileName ( const Module& module ) const
234 {
235 return DosSeparator(
236 ReplaceExtension ( module.GetPath(), "_auto.dsw" )
237 );
238 }
239
240 std::string
241 MSVCBackend::SlnFileName ( const Module& module ) const
242 {
243 return DosSeparator(
244 ReplaceExtension ( module.GetPath(), "_" + _get_vc_dir() + "_auto.sln" )
245 );
246 }
247
248 std::string
249 MSVCBackend::NcbFileName ( const Module& module ) const
250 {
251 return DosSeparator(
252 ReplaceExtension ( module.GetPath(), "_" + _get_vc_dir() + "_auto.ncb" )
253 );
254 }
255
256 std::string
257 MSVCBackend::DspFileName ( const Module& module ) const
258 {
259 return DosSeparator(
260 ReplaceExtension ( module.GetPath(), "_auto.dsp" )
261 );
262 }
263
264 std::string
265 MSVCBackend::VcprojFileName ( const Module& module ) const
266 {
267 return DosSeparator(
268 ReplaceExtension ( module.GetPath(), "_" + _get_vc_dir() + "_auto.vcproj" )
269 );
270 }
271
272 std::string MSVCBackend::_get_vc_dir ( void ) const
273 {
274 if ( configuration.VSProjectVersion == "6.00" )
275 return "vc6";
276 else if ( configuration.VSProjectVersion == "7.00" )
277 return "vc70";
278 else if ( configuration.VSProjectVersion == "7.10" )
279 return "vc71";
280 else /* must be VS2005 */
281 return "vc8";
282
283
284 }
285
286 void
287 MSVCBackend::_get_object_files ( const Module& module, vector<string>& out) const
288 {
289 string basepath = module.GetBasePath ();
290 string vcdir = _get_vc_dir ();
291 size_t i;
292 string intenv = Environment::GetIntermediatePath () + "\\" + basepath + "\\" + vcdir + "\\";
293 string outenv = Environment::GetOutputPath () + "\\" + basepath + "\\" + vcdir + "\\";
294 string dbg = vcdir.substr ( 0, 3 );
295
296 vector<string> cfgs;
297 cfgs.push_back ( intenv + "Debug" );
298 cfgs.push_back ( intenv + "Release" );
299 cfgs.push_back ( intenv + "Speed" );
300 cfgs.push_back ( outenv + "Debug" );
301 cfgs.push_back ( outenv + "Release" );
302 cfgs.push_back ( outenv + "Speed" );
303
304
305 vector<const IfableData*> ifs_list;
306 ifs_list.push_back ( &module.project.non_if_data );
307 ifs_list.push_back ( &module.non_if_data );
308 while ( ifs_list.size () )
309 {
310 const IfableData& data = *ifs_list.back();
311 ifs_list.pop_back();
312 const vector<File*>& files = data.files;
313 for ( i = 0; i < files.size (); i++ )
314 {
315 string file = files[i]->name;
316 string::size_type pos = file.find_last_of ("\\");
317 if ( pos != string::npos )
318 file.erase ( 0, pos+1 );
319 if ( !stricmp ( Right(file,3).c_str(), ".rc" ) )
320 file = ReplaceExtension ( file, ".res" );
321 else
322 file = ReplaceExtension ( file, ".obj" );
323 for ( size_t j = 0; j < cfgs.size () / 2; j++ )
324 out.push_back ( cfgs[j] + "\\" + file );
325 }
326
327 }
328 //common files in intermediate dir
329 for ( i = 0; i < cfgs.size () / 2; i++)
330 {
331 out.push_back ( cfgs[i] + "\\" + "BuildLog.htm" );
332 out.push_back ( cfgs[i] + "\\" + dbg + "0.pdb" );
333 out.push_back ( cfgs[i] + "\\" + dbg + "0.idb" );
334 out.push_back ( cfgs[i] + "\\" + module.name + ".pch" );
335 }
336 //files in the output dir
337 for ( i = cfgs.size () / 2; i < cfgs.size (); i++ )
338 {
339 out.push_back ( cfgs[i] + "\\" + module.GetTargetName () );
340 out.push_back ( cfgs[i] + "\\" + module.name + ".pdb" );
341 out.push_back ( cfgs[i] + "\\" + module.name + ".lib" );
342 out.push_back ( cfgs[i] + "\\" + module.name + ".exp" );
343 out.push_back ( cfgs[i] + "\\" + module.name + ".ilk" );
344 out.push_back ( cfgs[i] + "\\" + "(InputName).obj" ); //MSVC2003 build bug
345 }
346 }
347
348 void
349 MSVCBackend::_clean_project_files ( void )
350 {
351 for ( size_t i = 0; i < ProjectNode.modules.size(); i++ )
352 {
353 Module& module = *ProjectNode.modules[i];
354 vector<string> out;
355 printf("Cleaning project %s %s %s\n", module.name.c_str (), module.GetBasePath ().c_str (), NcbFileName ( module ).c_str () );
356
357 string basepath = module.GetBasePath ();
358 remove ( NcbFileName ( module ).c_str () );
359 remove ( DspFileName ( module ).c_str () );
360 remove ( DswFileName ( module ).c_str () );
361 remove ( OptFileName ( module ).c_str () );
362 remove ( SlnFileName ( module ).c_str () );
363 remove ( SuoFileName ( module ).c_str () );
364 remove ( VcprojFileName ( module ).c_str () );
365
366 _get_object_files ( module, out );
367 for ( size_t j = 0; j < out.size (); j++)
368 remove ( out[j].c_str () );
369 }
370 string filename_sln = ProjectNode.name + ".sln";
371 string filename_dsw = ProjectNode.name + ".dsw";
372
373 remove ( filename_sln.c_str () );
374 remove ( filename_dsw.c_str () );
375 }
376