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 // TODO FIXME wine hack?
87 bool only_msvc_headers
= false;
89 while ( m_configurations
.size () > 0 )
91 const MSVCConfiguration
* cfg
= m_configurations
.back();
92 m_configurations
.pop_back();
96 m_configurations
.push_back ( new MSVCConfiguration( Debug
));
97 m_configurations
.push_back ( new MSVCConfiguration( Release
));
98 m_configurations
.push_back ( new MSVCConfiguration( Speed
));
99 m_configurations
.push_back ( new MSVCConfiguration( RosBuild
));
101 if (!only_msvc_headers
)
103 m_configurations
.push_back ( new MSVCConfiguration( Debug
, ReactOSHeaders
));
104 m_configurations
.push_back ( new MSVCConfiguration( Release
, ReactOSHeaders
));
105 m_configurations
.push_back ( new MSVCConfiguration( Speed
, ReactOSHeaders
));
108 if ( configuration
.CleanAsYouGo
) {
109 _clean_project_files();
112 if ( configuration
.InstallFiles
) {
113 _install_files( _get_vc_dir(), configuration
.VSConfigurationType
);
116 string
filename_sln ( ProjectNode
.name
);
118 filename_sln
+= "_auto.sln";
119 printf ( "Creating MSVC workspace: %s\n", filename_sln
.c_str() );
121 // Write out the project files
124 // Write the solution file
125 SlnMaker
slnMaker( configuration
, ProjectNode
, m_configurations
, filename_sln
);
126 slnMaker
._generate_sln ( _get_solution_version(), _get_studio_version() );
128 printf ( "Done.\n" );
131 void MSVCBackend::ProcessModules()
133 for(std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin(); p
!= ProjectNode
.modules
.end(); ++ p
)
135 Module
&module
= *p
->second
;
137 module
.guid
= _gen_guid();
139 ProjMaker
*projMaker
;
141 if (configuration
.VSProjectVersion
== "10.00")
143 string vcxproj_file
= VcxprojFileName(module
);
144 projMaker
= new VCXProjMaker( configuration
, m_configurations
, vcxproj_file
);
148 string vcproj_file
= VcprojFileName(module
);
149 projMaker
= new VCProjMaker( configuration
, m_configurations
, vcproj_file
);
152 projMaker
->_generate_proj_file ( module
);
157 static bool FileExists(string
&filename
)
159 ifstream
file(filename
.c_str());
168 void MSVCBackend::ProcessFile(string
&filepath
)
170 // Remove the .\ at the start of the filenames
171 if ( filepath
[0] == '.' && strchr ( "/\\", filepath
[1] ) )
172 filepath
.erase(0, 2);
174 if(!FileExists(filepath
))
178 for(size_t i
= 0; i
< filepath
.length(); i
++)
180 if(filepath
[i
] == '\\')
184 // Remove the filename from the path
187 size_t pos
= filepath
.rfind(string("/"), filepath
.length() - 1);
189 if(pos
!= string::npos
)
192 folder
.erase(pos
, folder
.length() - pos
);
196 fileUnit
.filename
= filepath
;
197 fileUnit
.folder
= folder
;
199 m_fileUnits
.push_back(fileUnit
);
207 bool MSVCBackend::CheckFolderAdded(string
&folder
)
209 for(size_t i
= 0; i
< m_folders
.size(); i
++)
211 if(m_folders
[i
] == folder
)
218 void MSVCBackend::AddFolders(string
&folder
)
220 // Check if this folder was already added. true if it was, false otherwise.
221 if(CheckFolderAdded(folder
))
224 m_folders
.push_back(folder
);
226 size_t pos
= folder
.rfind(string("/"), folder
.length() - 1);
228 if(pos
== string::npos
)
231 folder
.erase(pos
, folder
.length() - pos
);
235 void MSVCBackend::OutputFolders()
238 m_devFile
<< "Folders=";
240 for(size_t i
= 0; i
< m_folders
.size(); i
++)
245 m_devFile
<< m_folders
[i
];
251 MSVCBackend::SuoFileName ( const Module
& module
) const
253 return FixSeparatorForSystemCommand(
254 ReplaceExtension ( module
.output
->relative_path
+ "\\" + module
.output
->name
, "_" + _get_vc_dir() + "_auto.suo" )
259 MSVCBackend::SlnFileName ( const Module
& module
) const
261 return FixSeparatorForSystemCommand(
262 ReplaceExtension ( module
.output
->relative_path
+ "\\" + module
.output
->name
, "_" + _get_vc_dir() + "_auto.sln" )
267 MSVCBackend::NcbFileName ( const Module
& module
) const
269 return FixSeparatorForSystemCommand(
270 ReplaceExtension ( module
.output
->relative_path
+ "\\" + module
.output
->name
, "_" + _get_vc_dir() + "_auto.ncb" )
275 MSVCBackend::VcprojFileName ( const Module
& module
) const
277 return FixSeparatorForSystemCommand(
278 ReplaceExtension ( module
.output
->relative_path
+ "\\" + module
.name
, "_" + _get_vc_dir() + "_auto.vcproj" )
283 MSVCBackend::VcxprojFileName ( const Module
& module
) const
285 return FixSeparatorForSystemCommand(
286 ReplaceExtension ( module
.output
->relative_path
+ "\\" + module
.name
, "_" + _get_vc_dir() + "_auto.vcxproj" )
290 std::string
MSVCBackend::_get_vc_dir ( void ) const
292 if ( configuration
.VSProjectVersion
== "8.00" )
294 else if ( configuration
.VSProjectVersion
== "10.00" )
296 else /* default to VS2008 */
301 MSVCBackend::_get_object_files ( const Module
& module
, vector
<string
>& out
) const
303 string basepath
= module
.output
->relative_path
;
304 string vcdir
= _get_vc_dir ();
306 string intenv
= Environment::GetIntermediatePath () + DEF_SSEP
+ basepath
+ DEF_SSEP
;
307 string outenv
= Environment::GetOutputPath () + DEF_SSEP
+ basepath
+ DEF_SSEP
;
309 if ( configuration
.UseVSVersionInPath
)
311 intenv
+= vcdir
+ DEF_SSEP
;
312 outenv
+= vcdir
+ DEF_SSEP
;
315 string dbg
= vcdir
.substr ( 0, 3 );
319 if ( configuration
.UseConfigurationInPath
)
321 cfgs
.push_back ( intenv
+ "Debug" );
322 cfgs
.push_back ( intenv
+ "Release" );
323 cfgs
.push_back ( intenv
+ "Speed" );
324 cfgs
.push_back ( outenv
+ "Debug" );
325 cfgs
.push_back ( outenv
+ "Release" );
326 cfgs
.push_back ( outenv
+ "Speed" );
330 cfgs
.push_back ( intenv
);
331 cfgs
.push_back ( outenv
);
334 vector
<const IfableData
*> ifs_list
;
335 ifs_list
.push_back ( &module
.project
.non_if_data
);
336 ifs_list
.push_back ( &module
.non_if_data
);
337 while ( ifs_list
.size () )
339 const IfableData
& data
= *ifs_list
.back();
341 const vector
<File
*>& files
= data
.files
;
342 for ( i
= 0; i
< files
.size (); i
++ )
344 string file
= files
[i
]->file
.relative_path
+ sSep
+ files
[i
]->file
.name
;
345 string::size_type pos
= file
.find_last_of (DEF_SSEP
);
346 if ( pos
!= string::npos
)
347 file
.erase ( 0, pos
+1 );
348 if ( !stricmp ( Right(file
,3).c_str(), ".rc" ) )
349 file
= ReplaceExtension ( file
, ".res" );
351 file
= ReplaceExtension ( file
, ".obj" );
352 for ( size_t j
= 0; j
< cfgs
.size () / 2; j
++ )
353 out
.push_back ( cfgs
[j
] + file
);
357 //common files in intermediate dir
358 for ( i
= 0; i
< cfgs
.size () / 2; i
++)
360 out
.push_back ( cfgs
[i
] + "BuildLog.htm" );
361 out
.push_back ( cfgs
[i
] + dbg
+ "0.pdb" );
362 out
.push_back ( cfgs
[i
] + dbg
+ "0.idb" );
363 out
.push_back ( cfgs
[i
] + module
.name
+ ".pch" );
365 //files in the output dir
366 for ( i
= cfgs
.size () / 2; i
< cfgs
.size (); i
++ )
368 out
.push_back ( cfgs
[i
] + module
.output
->name
);
369 out
.push_back ( cfgs
[i
] + module
.name
+ ".pdb" );
370 out
.push_back ( cfgs
[i
] + module
.name
+ ".lib" );
371 out
.push_back ( cfgs
[i
] + module
.name
+ ".exp" );
372 out
.push_back ( cfgs
[i
] + module
.name
+ ".ilk" );
377 MSVCBackend::_get_def_files ( const Module
& module
, vector
<string
>& out
) const
379 if (module
.HasImportLibrary ())
382 string modulename
= module
.GetBasePath ();
383 string file
= module
.importLibrary
->definition
;
384 size_t pos
= file
.find (".def");
385 if (pos
!= string::npos
)
387 file
.insert (pos
, "_msvc");
389 modulename
+= DEF_SSEP
+ file
;
390 out
.push_back (modulename
);
396 MSVCBackend::_clean_project_files ( void )
398 for( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin(); p
!= ProjectNode
.modules
.end(); ++ p
)
400 Module
& module
= *p
->second
;
402 printf("Cleaning project %s %s %s\n", module
.name
.c_str (), module
.output
->relative_path
.c_str (), NcbFileName ( module
).c_str () );
404 string basepath
= module
.output
->relative_path
;
405 remove ( NcbFileName ( module
).c_str () );
406 remove ( SlnFileName ( module
).c_str () );
407 remove ( SuoFileName ( module
).c_str () );
408 remove ( VcprojFileName ( module
).c_str () );
410 string username
= getenv ( "USERNAME" );
411 string computername
= getenv ( "COMPUTERNAME" );
412 string vcproj_file_user
= "";
414 if ((computername
!= "") && (username
!= ""))
415 vcproj_file_user
= VcprojFileName ( module
) + "." + computername
+ "." + username
+ ".user";
417 remove ( vcproj_file_user
.c_str () );
419 _get_object_files ( module
, out
);
420 _get_def_files ( module
, out
);
421 for ( size_t j
= 0; j
< out
.size (); j
++)
423 printf("Cleaning file %s\n", out
[j
].c_str () );
424 remove ( out
[j
].c_str () );
428 string filename_sln
= ProjectNode
.name
+ ".sln";
430 remove ( filename_sln
.c_str () );
434 MSVCBackend::_copy_file ( const std::string
& inputname
, const std::string
& targetname
) const
436 FILE * input
= fopen ( inputname
.c_str (), "rb" );
440 FILE * output
= fopen ( targetname
.c_str (), "wb+" );
449 while ( (num_read
= fread( buffer
, sizeof(char), 256, input
) ) || !feof( input
) )
450 fwrite( buffer
, sizeof(char), num_read
, output
);
458 MSVCBackend::_install_files (const std::string
& vcdir
, const::string
& config
)
460 for( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin(); p
!= ProjectNode
.modules
.end(); ++ p
)
462 Module
& module
= *p
->second
;
463 if ( !module
.install
)
466 string inputname
= Environment::GetOutputPath () + DEF_SSEP
+ module
.output
->relative_path
+ DEF_SSEP
+ vcdir
+ DEF_SSEP
+ config
+ DEF_SSEP
+ module
.output
->name
;
467 string installdir
= Environment::GetInstallPath () + DEF_SSEP
+ module
.install
->relative_path
+ DEF_SSEP
+ module
.install
->name
;
468 if ( _copy_file( inputname
, installdir
) )
469 printf ("Installed File :'%s'\n",installdir
.c_str () );
474 MSVCBackend::_get_solution_version ( void )
478 if (configuration
.VSProjectVersion
.empty())
479 configuration
.VSProjectVersion
= MS_VS_DEF_VERSION
;
481 else if (configuration
.VSProjectVersion
== "8.00")
484 else if (configuration
.VSProjectVersion
== "9.00")
487 else if (configuration
.VSProjectVersion
== "10.00")
494 MSVCBackend::_get_studio_version ( void )
498 if (configuration
.VSProjectVersion
.empty())
499 configuration
.VSProjectVersion
= MS_VS_DEF_VERSION
;
501 else if (configuration
.VSProjectVersion
== "8.00")
504 else if (configuration
.VSProjectVersion
== "9.00")
507 else if (configuration
.VSProjectVersion
== "10.00")
514 MSVCBackend::_lookup_property ( const Module
& module
, const std::string
& name
) const
516 std::map
<std::string
, Property
*>::const_iterator p
;
518 /* Check local values */
519 p
= module
.non_if_data
.properties
.find(name
);
521 if ( p
!= module
.non_if_data
.properties
.end() )
524 // TODO FIXME - should we check local if-ed properties?
525 p
= module
.project
.non_if_data
.properties
.find(name
);
527 if ( p
!= module
.project
.non_if_data
.properties
.end() )
530 // TODO FIXME - should we check global if-ed properties?