make_msvcX_install_[config] patch by Brezenbak
[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 if ( configuration.InstallFiles ) {
64 _install_files( _get_vc_dir(), configuration.VSConfigurationType );
65 return;
66 }
67 string filename_sln ( ProjectNode.name );
68 //string filename_rules = "gccasm.rules";
69
70 if ( configuration.VSProjectVersion == "6.00" )
71 filename_sln += ".dsw";
72 else {
73 filename_sln += ".sln";
74
75 //m_rulesFile = fopen ( filename_rules.c_str(), "wb" );
76 //if ( m_rulesFile )
77 //{
78 // _generate_rules_file ( m_rulesFile );
79 //}
80 //fclose ( m_rulesFile );
81 }
82
83 printf ( "Creating MSVC workspace: %s\n", filename_sln.c_str() );
84
85 ProcessModules();
86 m_slnFile = fopen ( filename_sln.c_str(), "wb" );
87
88 if ( !m_slnFile )
89 {
90 printf ( "Could not create file '%s'.\n", filename_sln.c_str() );
91 return;
92 }
93
94 if ( configuration.VSProjectVersion == "6.00" )
95 _generate_wine_dsw ( m_slnFile );
96 else
97 _generate_sln ( m_slnFile );
98
99 fclose ( m_slnFile );
100 printf ( "Done.\n" );
101 }
102
103 void MSVCBackend::ProcessModules()
104 {
105 for(size_t i = 0; i < ProjectNode.modules.size(); i++)
106 {
107 Module &module = *ProjectNode.modules[i];
108
109 module.guid = _gen_guid();
110
111 if (configuration.VSProjectVersion == "6.00")
112 this->_generate_dsp ( module );
113 else
114 this->_generate_vcproj ( module );
115
116
117 /*for(size_t k = 0; k < module.non_if_data.files.size(); k++)
118 {
119 File &file = *module.non_if_data.files[k];
120
121 ProcessFile(file.name);
122 }*/
123 }
124 }
125
126 static bool FileExists(string &filename)
127 {
128 ifstream file(filename.c_str());
129
130 if(!file.is_open())
131 return false;
132
133 file.close();
134 return true;
135 }
136
137 void MSVCBackend::ProcessFile(string &filepath)
138 {
139 // Remove the .\ at the start of the filenames
140 if ( filepath[0] == '.' && strchr ( "/\\", filepath[1] ) )
141 filepath.erase(0, 2);
142
143 if(!FileExists(filepath))
144 return;
145
146 // Change the \ to /
147 for(size_t i = 0; i < filepath.length(); i++)
148 {
149 if(filepath[i] == '\\')
150 filepath[i] = '/';
151 }
152
153 // Remove the filename from the path
154 string folder = "";
155
156 size_t pos = filepath.rfind(string("/"), filepath.length() - 1);
157
158 if(pos != string::npos)
159 {
160 folder = filepath;
161 folder.erase(pos, folder.length() - pos);
162 }
163
164 FileUnit fileUnit;
165 fileUnit.filename = filepath;
166 fileUnit.folder = folder;
167
168 m_fileUnits.push_back(fileUnit);
169
170 if(folder != "")
171 AddFolders(folder);
172
173 m_unitCount++;
174 }
175
176 bool MSVCBackend::CheckFolderAdded(string &folder)
177 {
178 for(size_t i = 0; i < m_folders.size(); i++)
179 {
180 if(m_folders[i] == folder)
181 return true;
182 }
183
184 return false;
185 }
186
187 void MSVCBackend::AddFolders(string &folder)
188 {
189 // Check if this folder was already added. true if it was, false otherwise.
190 if(CheckFolderAdded(folder))
191 return;
192
193 m_folders.push_back(folder);
194
195 size_t pos = folder.rfind(string("/"), folder.length() - 1);
196
197 if(pos == string::npos)
198 return;
199
200 folder.erase(pos, folder.length() - pos);
201 AddFolders(folder);
202 }
203
204 void MSVCBackend::OutputFolders()
205 {
206 #if 0
207 m_devFile << "Folders=";
208
209 for(size_t i = 0; i < m_folders.size(); i++)
210 {
211 if(i > 0)
212 m_devFile << ",";
213
214 m_devFile << m_folders[i];
215 }
216 #endif
217 }
218
219 std::string
220 MSVCBackend::OptFileName ( const Module& module ) const
221 {
222 return DosSeparator(
223 ReplaceExtension ( module.GetPath(), "_" + _get_vc_dir() + "_auto.opt" )
224 );
225 }
226
227 std::string
228 MSVCBackend::SuoFileName ( const Module& module ) const
229 {
230 return DosSeparator(
231 ReplaceExtension ( module.GetPath(), "_" + _get_vc_dir() + "_auto.suo" )
232 );
233 }
234
235 std::string
236 MSVCBackend::DswFileName ( const Module& module ) const
237 {
238 return DosSeparator(
239 ReplaceExtension ( module.GetPath(), "_auto.dsw" )
240 );
241 }
242
243 std::string
244 MSVCBackend::SlnFileName ( const Module& module ) const
245 {
246 return DosSeparator(
247 ReplaceExtension ( module.GetPath(), "_" + _get_vc_dir() + "_auto.sln" )
248 );
249 }
250
251 std::string
252 MSVCBackend::NcbFileName ( const Module& module ) const
253 {
254 return DosSeparator(
255 ReplaceExtension ( module.GetPath(), "_" + _get_vc_dir() + "_auto.ncb" )
256 );
257 }
258
259 std::string
260 MSVCBackend::DspFileName ( const Module& module ) const
261 {
262 return DosSeparator(
263 ReplaceExtension ( module.GetPath(), "_auto.dsp" )
264 );
265 }
266
267 std::string
268 MSVCBackend::VcprojFileName ( const Module& module ) const
269 {
270 return DosSeparator(
271 ReplaceExtension ( module.GetPath(), "_" + _get_vc_dir() + "_auto.vcproj" )
272 );
273 }
274
275 std::string MSVCBackend::_get_vc_dir ( void ) const
276 {
277 if ( configuration.VSProjectVersion == "6.00" )
278 return "vc6";
279 else if ( configuration.VSProjectVersion == "7.00" )
280 return "vc70";
281 else if ( configuration.VSProjectVersion == "7.10" )
282 return "vc71";
283 else /* must be VS2005 */
284 return "vc8";
285
286
287 }
288
289 void
290 MSVCBackend::_get_object_files ( const Module& module, vector<string>& out) const
291 {
292 string basepath = module.GetBasePath ();
293 string vcdir = _get_vc_dir ();
294 size_t i;
295 string intenv = Environment::GetIntermediatePath () + "\\" + basepath + "\\" + vcdir + "\\";
296 string outenv = Environment::GetOutputPath () + "\\" + basepath + "\\" + vcdir + "\\";
297 string dbg = vcdir.substr ( 0, 3 );
298
299 vector<string> cfgs;
300 cfgs.push_back ( intenv + "Debug" );
301 cfgs.push_back ( intenv + "Release" );
302 cfgs.push_back ( intenv + "Speed" );
303 cfgs.push_back ( outenv + "Debug" );
304 cfgs.push_back ( outenv + "Release" );
305 cfgs.push_back ( outenv + "Speed" );
306
307
308 vector<const IfableData*> ifs_list;
309 ifs_list.push_back ( &module.project.non_if_data );
310 ifs_list.push_back ( &module.non_if_data );
311 while ( ifs_list.size () )
312 {
313 const IfableData& data = *ifs_list.back();
314 ifs_list.pop_back();
315 const vector<File*>& files = data.files;
316 for ( i = 0; i < files.size (); i++ )
317 {
318 string file = files[i]->name;
319 string::size_type pos = file.find_last_of ("\\");
320 if ( pos != string::npos )
321 file.erase ( 0, pos+1 );
322 if ( !stricmp ( Right(file,3).c_str(), ".rc" ) )
323 file = ReplaceExtension ( file, ".res" );
324 else
325 file = ReplaceExtension ( file, ".obj" );
326 for ( size_t j = 0; j < cfgs.size () / 2; j++ )
327 out.push_back ( cfgs[j] + "\\" + file );
328 }
329
330 }
331 //common files in intermediate dir
332 for ( i = 0; i < cfgs.size () / 2; i++)
333 {
334 out.push_back ( cfgs[i] + "\\" + "BuildLog.htm" );
335 out.push_back ( cfgs[i] + "\\" + dbg + "0.pdb" );
336 out.push_back ( cfgs[i] + "\\" + dbg + "0.idb" );
337 out.push_back ( cfgs[i] + "\\" + module.name + ".pch" );
338 }
339 //files in the output dir
340 for ( i = cfgs.size () / 2; i < cfgs.size (); i++ )
341 {
342 out.push_back ( cfgs[i] + "\\" + module.GetTargetName () );
343 out.push_back ( cfgs[i] + "\\" + module.name + ".pdb" );
344 out.push_back ( cfgs[i] + "\\" + module.name + ".lib" );
345 out.push_back ( cfgs[i] + "\\" + module.name + ".exp" );
346 out.push_back ( cfgs[i] + "\\" + module.name + ".ilk" );
347 out.push_back ( cfgs[i] + "\\" + "(InputName).obj" ); //MSVC2003 build bug
348 }
349 }
350
351 void
352 MSVCBackend::_clean_project_files ( void )
353 {
354 for ( size_t i = 0; i < ProjectNode.modules.size(); i++ )
355 {
356 Module& module = *ProjectNode.modules[i];
357 vector<string> out;
358 printf("Cleaning project %s %s %s\n", module.name.c_str (), module.GetBasePath ().c_str (), NcbFileName ( module ).c_str () );
359
360 string basepath = module.GetBasePath ();
361 remove ( NcbFileName ( module ).c_str () );
362 remove ( DspFileName ( module ).c_str () );
363 remove ( DswFileName ( module ).c_str () );
364 remove ( OptFileName ( module ).c_str () );
365 remove ( SlnFileName ( module ).c_str () );
366 remove ( SuoFileName ( module ).c_str () );
367 remove ( VcprojFileName ( module ).c_str () );
368
369 _get_object_files ( module, out );
370 for ( size_t j = 0; j < out.size (); j++)
371 remove ( out[j].c_str () );
372 }
373 string filename_sln = ProjectNode.name + ".sln";
374 string filename_dsw = ProjectNode.name + ".dsw";
375
376 remove ( filename_sln.c_str () );
377 remove ( filename_dsw.c_str () );
378 }
379
380 bool
381 MSVCBackend::_copy_file ( const std::string& inputname, const std::string& targetname ) const
382 {
383 FILE * input = fopen ( inputname.c_str (), "rb" );
384 if ( !input )
385 return false;
386
387 FILE * output = fopen ( targetname.c_str (), "wb+" );
388 if ( !output )
389 {
390 fclose ( input );
391 return false;
392 }
393
394 char buffer[256];
395 int num_read;
396 while ( (num_read = fread( buffer, sizeof(char), 256, input) ) || !feof( input ) )
397 fwrite( buffer, sizeof(char), num_read, output );
398
399 fclose ( input );
400 fclose ( output );
401 return true;
402 }
403
404 void
405 MSVCBackend::_install_files (const std::string& vcdir, const::string& config)
406 {
407 for ( size_t i = 0; i < ProjectNode.modules.size(); i++ )
408 {
409 Module& module = *ProjectNode.modules[i];
410 if ( module.installBase == "" || module.installName == "" )
411 continue;
412
413 string inputname = Environment::GetOutputPath () + "\\" + module.GetBasePath () + "\\" + vcdir + "\\" + config + "\\" + module.GetTargetName ();
414 string installdir = Environment::GetInstallPath () + "\\" + module.installBase + "\\" + module.installName;
415 if ( _copy_file( inputname, installdir ) )
416 printf ("Installed File :'%s'\n",installdir.c_str () );
417 }
418 }