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 * Copyright (C) 2006 Christoph von Wittich
7 * Copyright (C) 2009 Ged Murphy
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #pragma warning ( disable : 4786 )
25 #pragma warning ( disable : 4996 )
39 static class MSVCFactory
: public Backend::Factory
43 MSVCFactory() : Factory("MSVC", "Microsoft Visual C") {}
44 Backend
*operator() (Project
&project
,
45 Configuration
& configuration
)
47 return new MSVCBackend(project
, configuration
);
52 MSVCConfiguration::MSVCConfiguration ( const OptimizationType optimization
, const HeadersType headers
, const std::string
&name
)
54 this->optimization
= optimization
;
55 this->headers
= headers
;
60 std::string headers_name
;
61 if ( headers
== MSVCHeaders
)
64 headers_name
= " - ReactOS headers";
65 if ( optimization
== Debug
)
66 this->name
= "Debug" + headers_name
;
67 else if ( optimization
== Release
)
68 this->name
= "Release" + headers_name
;
69 else if ( optimization
== Speed
)
70 this->name
= "Speed" + headers_name
;
71 else if ( optimization
== RosBuild
)
72 this->name
= "RosBuild";
74 this->name
= "Unknown" + headers_name
;
78 MSVCBackend::MSVCBackend(Project
&project
,
79 Configuration
& configuration
) : Backend(project
, configuration
)
84 void MSVCBackend::Process()
86 bool only_msvc_headers
= false;
88 while ( m_configurations
.size () > 0 )
90 const MSVCConfiguration
* cfg
= m_configurations
.back();
91 m_configurations
.pop_back();
95 m_configurations
.push_back ( new MSVCConfiguration( Debug
));
96 m_configurations
.push_back ( new MSVCConfiguration( Release
));
97 // m_configurations.push_back ( new MSVCConfiguration( Speed ));
98 m_configurations
.push_back ( new MSVCConfiguration( RosBuild
));
100 if (!only_msvc_headers
)
102 m_configurations
.push_back ( new MSVCConfiguration( Debug
, ReactOSHeaders
));
103 m_configurations
.push_back ( new MSVCConfiguration( Release
, ReactOSHeaders
));
104 // m_configurations.push_back ( new MSVCConfiguration( Speed, ReactOSHeaders ));
107 if ( configuration
.CleanAsYouGo
) {
108 _clean_project_files();
111 if ( configuration
.InstallFiles
) {
112 _install_files( _get_vc_dir(), configuration
.VSConfigurationType
);
115 string
filename_sln ( ProjectNode
.name
);
117 filename_sln
+= "_auto.sln";
118 printf ( "Creating MSVC workspace: %s\n", filename_sln
.c_str() );
120 //Write a property page for each configuration
121 for ( size_t icfg
= 0; icfg
< m_configurations
.size(); icfg
++ )
123 MSVCConfiguration
* cfg
= m_configurations
[icfg
];
125 //RosBuild doesn't need a property page
126 if(cfg
->optimization
== RosBuild
)
129 string
filename_props( cfg
->name
);
130 filename_props
+= ".vsprops";
131 //Write the propery pages files
132 PropsMaker
propsMaker( configuration
, &ProjectNode
, filename_props
, cfg
);
133 propsMaker
._generate_props( _get_solution_version(), _get_studio_version() );
136 // Write out the project files
139 // Write the solution file
140 SlnMaker
slnMaker( configuration
, ProjectNode
, m_configurations
, filename_sln
);
141 slnMaker
._generate_sln ( _get_solution_version(), _get_studio_version() );
143 printf ( "Done.\n" );
146 void MSVCBackend::ProcessModules()
148 for(std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin(); p
!= ProjectNode
.modules
.end(); ++ p
)
150 Module
&module
= *p
->second
;
152 module
.guid
= _gen_guid();
154 ProjMaker
*projMaker
;
156 if (configuration
.VSProjectVersion
== "10.00")
158 string vcxproj_file
= VcxprojFileName(module
);
159 projMaker
= new VCXProjMaker( configuration
, m_configurations
, vcxproj_file
);
163 string vcproj_file
= VcprojFileName(module
);
164 projMaker
= new VCProjMaker( configuration
, m_configurations
, vcproj_file
);
167 projMaker
->_generate_proj_file ( module
);
172 static bool FileExists(string
&filename
)
174 ifstream
file(filename
.c_str());
183 void MSVCBackend::ProcessFile(string
&filepath
)
185 // Remove the .\ at the start of the filenames
186 if ( filepath
[0] == '.' && strchr ( "/\\", filepath
[1] ) )
187 filepath
.erase(0, 2);
189 if(!FileExists(filepath
))
193 for(size_t i
= 0; i
< filepath
.length(); i
++)
195 if(filepath
[i
] == '\\')
199 // Remove the filename from the path
202 size_t pos
= filepath
.rfind(string("/"), filepath
.length() - 1);
204 if(pos
!= string::npos
)
207 folder
.erase(pos
, folder
.length() - pos
);
211 fileUnit
.filename
= filepath
;
212 fileUnit
.folder
= folder
;
214 m_fileUnits
.push_back(fileUnit
);
222 bool MSVCBackend::CheckFolderAdded(string
&folder
)
224 for(size_t i
= 0; i
< m_folders
.size(); i
++)
226 if(m_folders
[i
] == folder
)
233 void MSVCBackend::AddFolders(string
&folder
)
235 // Check if this folder was already added. true if it was, false otherwise.
236 if(CheckFolderAdded(folder
))
239 m_folders
.push_back(folder
);
241 size_t pos
= folder
.rfind(string("/"), folder
.length() - 1);
243 if(pos
== string::npos
)
246 folder
.erase(pos
, folder
.length() - pos
);
250 void MSVCBackend::OutputFolders()
253 m_devFile
<< "Folders=";
255 for(size_t i
= 0; i
< m_folders
.size(); i
++)
260 m_devFile
<< m_folders
[i
];
266 MSVCBackend::SuoFileName ( const Module
& module
) const
268 return FixSeparatorForSystemCommand(
269 ReplaceExtension ( module
.output
->relative_path
+ "\\" + module
.output
->name
, "_" + _get_vc_dir() + "_auto.suo" )
274 MSVCBackend::SlnFileName ( const Module
& module
) const
276 return FixSeparatorForSystemCommand(
277 ReplaceExtension ( module
.output
->relative_path
+ "\\" + module
.output
->name
, "_" + _get_vc_dir() + "_auto.sln" )
282 MSVCBackend::NcbFileName ( const Module
& module
) const
284 return FixSeparatorForSystemCommand(
285 ReplaceExtension ( module
.output
->relative_path
+ "\\" + module
.output
->name
, "_" + _get_vc_dir() + "_auto.ncb" )
290 MSVCBackend::VcprojFileName ( const Module
& module
) const
292 return FixSeparatorForSystemCommand(
293 ReplaceExtension ( module
.output
->relative_path
+ "\\" + module
.name
, "_" + _get_vc_dir() + "_auto.vcproj" )
298 MSVCBackend::VcxprojFileName ( const Module
& module
) const
300 return FixSeparatorForSystemCommand(
301 ReplaceExtension ( module
.output
->relative_path
+ "\\" + module
.name
, "_" + _get_vc_dir() + "_auto.vcxproj" )
305 std::string
MSVCBackend::_get_vc_dir ( void ) const
307 if ( configuration
.VSProjectVersion
== "8.00" )
309 else if ( configuration
.VSProjectVersion
== "10.00" )
311 else /* default to VS2008 */
316 MSVCBackend::_get_object_files ( const Module
& module
, vector
<string
>& out
) const
318 string basepath
= module
.output
->relative_path
;
319 string vcdir
= _get_vc_dir ();
321 string intenv
= Environment::GetIntermediatePath () + DEF_SSEP
+ basepath
+ DEF_SSEP
;
322 string outenv
= Environment::GetOutputPath () + DEF_SSEP
+ basepath
+ DEF_SSEP
;
324 if ( configuration
.UseVSVersionInPath
)
326 intenv
+= vcdir
+ DEF_SSEP
;
327 outenv
+= vcdir
+ DEF_SSEP
;
330 string dbg
= vcdir
.substr ( 0, 3 );
334 if ( configuration
.UseConfigurationInPath
)
336 cfgs
.push_back ( intenv
+ "Debug" );
337 cfgs
.push_back ( intenv
+ "Release" );
338 cfgs
.push_back ( intenv
+ "Speed" );
339 cfgs
.push_back ( outenv
+ "Debug" );
340 cfgs
.push_back ( outenv
+ "Release" );
341 cfgs
.push_back ( outenv
+ "Speed" );
345 cfgs
.push_back ( intenv
);
346 cfgs
.push_back ( outenv
);
349 vector
<const IfableData
*> ifs_list
;
350 ifs_list
.push_back ( &module
.project
.non_if_data
);
351 ifs_list
.push_back ( &module
.non_if_data
);
352 while ( ifs_list
.size () )
354 const IfableData
& data
= *ifs_list
.back();
356 const vector
<File
*>& files
= data
.files
;
357 for ( i
= 0; i
< files
.size (); i
++ )
359 string file
= files
[i
]->file
.relative_path
+ sSep
+ files
[i
]->file
.name
;
360 string::size_type pos
= file
.find_last_of (DEF_SSEP
);
361 if ( pos
!= string::npos
)
362 file
.erase ( 0, pos
+1 );
363 if ( !stricmp ( Right(file
,3).c_str(), ".rc" ) )
364 file
= ReplaceExtension ( file
, ".res" );
366 file
= ReplaceExtension ( file
, ".obj" );
367 for ( size_t j
= 0; j
< cfgs
.size () / 2; j
++ )
368 out
.push_back ( cfgs
[j
] + file
);
372 //common files in intermediate dir
373 for ( i
= 0; i
< cfgs
.size () / 2; i
++)
375 out
.push_back ( cfgs
[i
] + "BuildLog.htm" );
376 out
.push_back ( cfgs
[i
] + dbg
+ "0.pdb" );
377 out
.push_back ( cfgs
[i
] + dbg
+ "0.idb" );
378 out
.push_back ( cfgs
[i
] + module
.name
+ ".pch" );
380 //files in the output dir
381 for ( i
= cfgs
.size () / 2; i
< cfgs
.size (); i
++ )
383 out
.push_back ( cfgs
[i
] + module
.output
->name
);
384 out
.push_back ( cfgs
[i
] + module
.name
+ ".pdb" );
385 out
.push_back ( cfgs
[i
] + module
.name
+ ".lib" );
386 out
.push_back ( cfgs
[i
] + module
.name
+ ".exp" );
387 out
.push_back ( cfgs
[i
] + module
.name
+ ".ilk" );
392 MSVCBackend::_get_def_files ( const Module
& module
, vector
<string
>& out
) const
394 if (module
.HasImportLibrary())
397 string modulename
= module
.GetBasePath ();
398 string file
= module
.importLibrary
->definition
;
399 size_t pos
= file
.find (".def");
400 if (pos
!= string::npos
)
402 file
.insert (pos
, "_msvc");
404 modulename
+= DEF_SSEP
+ file
;
405 out
.push_back (modulename
);
411 MSVCBackend::_clean_project_files ( void )
413 for( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin(); p
!= ProjectNode
.modules
.end(); ++ p
)
415 Module
& module
= *p
->second
;
417 printf("Cleaning project %s %s %s\n", module
.name
.c_str (), module
.output
->relative_path
.c_str (), NcbFileName ( module
).c_str () );
419 string basepath
= module
.output
->relative_path
;
420 remove ( NcbFileName ( module
).c_str () );
421 remove ( SlnFileName ( module
).c_str () );
422 remove ( SuoFileName ( module
).c_str () );
423 remove ( VcprojFileName ( module
).c_str () );
425 string username
= getenv ( "USERNAME" );
426 string computername
= getenv ( "COMPUTERNAME" );
427 string vcproj_file_user
= "";
429 if ((computername
!= "") && (username
!= ""))
430 vcproj_file_user
= VcprojFileName ( module
) + "." + computername
+ "." + username
+ ".user";
432 remove ( vcproj_file_user
.c_str () );
434 _get_object_files ( module
, out
);
435 _get_def_files ( module
, out
);
436 for ( size_t j
= 0; j
< out
.size (); j
++)
438 printf("Cleaning file %s\n", out
[j
].c_str () );
439 remove ( out
[j
].c_str () );
443 string filename_sln
= ProjectNode
.name
+ ".sln";
445 remove ( filename_sln
.c_str () );
449 MSVCBackend::_copy_file ( const std::string
& inputname
, const std::string
& targetname
) const
451 FILE * input
= fopen ( inputname
.c_str (), "rb" );
455 FILE * output
= fopen ( targetname
.c_str (), "wb+" );
464 while ( (num_read
= fread( buffer
, sizeof(char), 256, input
) ) || !feof( input
) )
465 fwrite( buffer
, sizeof(char), num_read
, output
);
473 MSVCBackend::_install_files (const std::string
& vcdir
, const::string
& config
)
475 for( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin(); p
!= ProjectNode
.modules
.end(); ++ p
)
477 Module
& module
= *p
->second
;
478 if ( !module
.install
)
481 string inputname
= Environment::GetOutputPath () + DEF_SSEP
+ module
.output
->relative_path
+ DEF_SSEP
+ vcdir
+ DEF_SSEP
+ config
+ DEF_SSEP
+ module
.output
->name
;
482 string installdir
= Environment::GetInstallPath () + DEF_SSEP
+ module
.install
->relative_path
+ DEF_SSEP
+ module
.install
->name
;
483 if ( _copy_file( inputname
, installdir
) )
484 printf ("Installed File :'%s'\n",installdir
.c_str () );
489 MSVCBackend::_get_solution_version ( void )
493 if (configuration
.VSProjectVersion
.empty())
494 configuration
.VSProjectVersion
= MS_VS_DEF_VERSION
;
496 else if (configuration
.VSProjectVersion
== "8.00")
499 else if (configuration
.VSProjectVersion
== "9.00")
502 else if (configuration
.VSProjectVersion
== "10.00")
509 MSVCBackend::_get_studio_version ( void )
513 if (configuration
.VSProjectVersion
.empty())
514 configuration
.VSProjectVersion
= MS_VS_DEF_VERSION
;
516 else if (configuration
.VSProjectVersion
== "8.00")
519 else if (configuration
.VSProjectVersion
== "9.00")
522 else if (configuration
.VSProjectVersion
== "10.00")
529 MSVCBackend::_lookup_property ( const Module
& module
, const std::string
& name
) const
531 std::map
<std::string
, Property
*>::const_iterator p
;
533 /* Check local values */
534 p
= module
.non_if_data
.properties
.find(name
);
536 if ( p
!= module
.non_if_data
.properties
.end() )
539 // TODO FIXME - should we check local if-ed properties?
540 p
= module
.project
.non_if_data
.properties
.find(name
);
542 if ( p
!= module
.project
.non_if_data
.properties
.end() )
545 // TODO FIXME - should we check global if-ed properties?