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 while ( m_configurations
.size () > 0 )
88 const MSVCConfiguration
* cfg
= m_configurations
.back();
89 m_configurations
.pop_back();
93 //Don't generate configurations that require WDK if it can't be found
94 if(getenv ( "BASEDIR" ) != NULL
)
96 m_configurations
.push_back ( new MSVCConfiguration( Debug
));
97 m_configurations
.push_back ( new MSVCConfiguration( Release
));
99 m_configurations
.push_back ( new MSVCConfiguration( RosBuild
));
100 m_configurations
.push_back ( new MSVCConfiguration( Debug
, ReactOSHeaders
));
101 m_configurations
.push_back ( new MSVCConfiguration( Release
, ReactOSHeaders
));
102 // m_configurations.push_back ( new MSVCConfiguration( Speed ));
103 // m_configurations.push_back ( new MSVCConfiguration( Speed, ReactOSHeaders ));
105 if ( configuration
.CleanAsYouGo
) {
106 _clean_project_files();
109 if ( configuration
.InstallFiles
) {
110 _install_files( _get_vc_dir(), configuration
.VSConfigurationType
);
113 string
filename_sln ( ProjectNode
.name
);
115 filename_sln
+= "_auto.sln";
116 printf ( "Creating MSVC workspace: %s\n", filename_sln
.c_str() );
118 if (configuration
.VSProjectVersion
== "10.00")
120 PropsMaker
propsMaker( &ProjectNode
, "reactos.props", m_configurations
);
121 propsMaker
._generate_props( _get_solution_version(), _get_studio_version() );
125 //Write a property page for each configuration
126 for ( size_t icfg
= 0; icfg
< m_configurations
.size(); icfg
++ )
128 MSVCConfiguration
* cfg
= m_configurations
[icfg
];
130 //RosBuild doesn't need a property page
131 if(cfg
->optimization
== RosBuild
)
134 //Write the propery pages files
135 string
filename_props( cfg
->name
);
137 filename_props
= filename_props
+ ".vsprops";
138 VSPropsMaker
propsMaker( configuration
, &ProjectNode
, filename_props
, cfg
);
139 propsMaker
._generate_props( _get_solution_version(), _get_studio_version() );
142 // Write out the project files
145 printf ( "Done.\n" );
148 void MSVCBackend::ProcessModules()
150 string
filename_sln ( ProjectNode
.name
);
152 filename_sln
+= "_auto.sln";
154 // Write the solution file
155 SlnMaker
slnMaker( configuration
, m_configurations
, filename_sln
, _get_solution_version(), _get_studio_version() );
157 for(std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin(); p
!= ProjectNode
.modules
.end(); ++ p
)
159 Module
&module
= *p
->second
;
161 module
.guid
= _gen_guid();
163 ProjMaker
*projMaker
;
165 if (configuration
.VSProjectVersion
== "10.00")
167 string vcxproj_file
= VcxprojFileName(module
);
168 projMaker
= new VCXProjMaker( configuration
, m_configurations
, vcxproj_file
, module
);
172 string vcproj_file
= VcprojFileName(module
);
173 projMaker
= new VCProjMaker( configuration
, m_configurations
, vcproj_file
, module
);
176 projMaker
->_generate_proj_file ( module
);
178 slnMaker
._add_project(*projMaker
, module
);
185 static bool FileExists(string
&filename
)
187 ifstream
file(filename
.c_str());
196 void MSVCBackend::ProcessFile(string
&filepath
)
198 // Remove the .\ at the start of the filenames
199 if ( filepath
[0] == '.' && strchr ( "/\\", filepath
[1] ) )
200 filepath
.erase(0, 2);
202 if(!FileExists(filepath
))
206 for(size_t i
= 0; i
< filepath
.length(); i
++)
208 if(filepath
[i
] == '\\')
212 // Remove the filename from the path
215 size_t pos
= filepath
.rfind(string("/"), filepath
.length() - 1);
217 if(pos
!= string::npos
)
220 folder
.erase(pos
, folder
.length() - pos
);
224 fileUnit
.filename
= filepath
;
225 fileUnit
.folder
= folder
;
227 m_fileUnits
.push_back(fileUnit
);
235 bool MSVCBackend::CheckFolderAdded(string
&folder
)
237 for(size_t i
= 0; i
< m_folders
.size(); i
++)
239 if(m_folders
[i
] == folder
)
246 void MSVCBackend::AddFolders(string
&folder
)
248 // Check if this folder was already added. true if it was, false otherwise.
249 if(CheckFolderAdded(folder
))
252 m_folders
.push_back(folder
);
254 size_t pos
= folder
.rfind(string("/"), folder
.length() - 1);
256 if(pos
== string::npos
)
259 folder
.erase(pos
, folder
.length() - pos
);
263 void MSVCBackend::OutputFolders()
266 m_devFile
<< "Folders=";
268 for(size_t i
= 0; i
< m_folders
.size(); i
++)
273 m_devFile
<< m_folders
[i
];
279 MSVCBackend::UserFileName ( const Module
& module
, std::string vcproj_file
) const
284 if (getenv ( "USERNAME" ) != NULL
)
285 username
= getenv ( "USERNAME" );
286 if (getenv ( "COMPUTERNAME" ) != NULL
)
287 computername
= getenv ( "COMPUTERNAME" );
288 else if (getenv ( "HOSTNAME" ) != NULL
)
289 computername
= getenv ( "HOSTNAME" );
291 if ((computername
!= "") && (username
!= ""))
292 return vcproj_file
+ "." + computername
+ "." + username
+ ".user";
298 MSVCBackend::SuoFileName ( const Module
& module
) const
300 return FixSeparatorForSystemCommand(
301 ReplaceExtension ( module
.output
->relative_path
+ "\\" + module
.output
->name
, "_" + _get_vc_dir() + "_auto.suo" )
306 MSVCBackend::SlnFileName ( const Module
& module
) const
308 return FixSeparatorForSystemCommand(
309 ReplaceExtension ( module
.output
->relative_path
+ "\\" + module
.output
->name
, "_" + _get_vc_dir() + "_auto.sln" )
314 MSVCBackend::NcbFileName ( const Module
& module
) const
316 return FixSeparatorForSystemCommand(
317 ReplaceExtension ( module
.output
->relative_path
+ "\\" + module
.output
->name
, "_" + _get_vc_dir() + "_auto.ncb" )
322 MSVCBackend::VcprojFileName ( const Module
& module
) const
324 return FixSeparatorForSystemCommand(
325 ReplaceExtension ( module
.output
->relative_path
+ "\\" + module
.name
, "_" + _get_vc_dir() + "_auto.vcproj" )
330 MSVCBackend::VcxprojFileName ( const Module
& module
) const
332 return FixSeparatorForSystemCommand(
333 ReplaceExtension ( module
.output
->relative_path
+ "\\" + module
.name
, "_" + _get_vc_dir() + "_auto.vcxproj" )
337 std::string
MSVCBackend::_get_vc_dir ( void ) const
339 if ( configuration
.VSProjectVersion
== "8.00" )
341 else if ( configuration
.VSProjectVersion
== "10.00" )
343 else /* default to VS2008 */
348 MSVCBackend::_get_object_files ( const Module
& module
, vector
<string
>& out
) const
350 string basepath
= module
.output
->relative_path
;
351 string vcdir
= _get_vc_dir ();
353 string intenv
= Environment::GetIntermediatePath () + DEF_SSEP
+ basepath
+ DEF_SSEP
;
354 string outenv
= Environment::GetOutputPath () + DEF_SSEP
+ basepath
+ DEF_SSEP
;
356 if ( configuration
.UseVSVersionInPath
)
358 intenv
+= vcdir
+ DEF_SSEP
;
359 outenv
+= vcdir
+ DEF_SSEP
;
362 string dbg
= vcdir
.substr ( 0, 3 );
366 if ( configuration
.UseConfigurationInPath
)
368 cfgs
.push_back ( intenv
+ "Debug" );
369 cfgs
.push_back ( intenv
+ "Release" );
370 cfgs
.push_back ( intenv
+ "Speed" );
371 cfgs
.push_back ( outenv
+ "Debug" );
372 cfgs
.push_back ( outenv
+ "Release" );
373 cfgs
.push_back ( outenv
+ "Speed" );
377 cfgs
.push_back ( intenv
);
378 cfgs
.push_back ( outenv
);
381 vector
<const IfableData
*> ifs_list
;
382 ifs_list
.push_back ( &module
.project
.non_if_data
);
383 ifs_list
.push_back ( &module
.non_if_data
);
384 while ( ifs_list
.size () )
386 const IfableData
& data
= *ifs_list
.back();
388 const vector
<File
*>& files
= data
.files
;
389 for ( i
= 0; i
< files
.size (); i
++ )
391 string file
= files
[i
]->file
.relative_path
+ sSep
+ files
[i
]->file
.name
;
392 string::size_type pos
= file
.find_last_of (DEF_SSEP
);
393 if ( pos
!= string::npos
)
394 file
.erase ( 0, pos
+1 );
395 if ( !stricmp ( Right(file
,3).c_str(), ".rc" ) )
396 file
= ReplaceExtension ( file
, ".res" );
398 file
= ReplaceExtension ( file
, ".obj" );
399 for ( size_t j
= 0; j
< cfgs
.size () / 2; j
++ )
400 out
.push_back ( cfgs
[j
] + file
);
404 //common files in intermediate dir
405 for ( i
= 0; i
< cfgs
.size () / 2; i
++)
407 out
.push_back ( cfgs
[i
] + "BuildLog.htm" );
408 out
.push_back ( cfgs
[i
] + dbg
+ "0.pdb" );
409 out
.push_back ( cfgs
[i
] + dbg
+ "0.idb" );
410 out
.push_back ( cfgs
[i
] + module
.name
+ ".pch" );
412 //files in the output dir
413 for ( i
= cfgs
.size () / 2; i
< cfgs
.size (); i
++ )
415 out
.push_back ( cfgs
[i
] + module
.output
->name
);
416 out
.push_back ( cfgs
[i
] + module
.name
+ ".pdb" );
417 out
.push_back ( cfgs
[i
] + module
.name
+ ".lib" );
418 out
.push_back ( cfgs
[i
] + module
.name
+ ".exp" );
419 out
.push_back ( cfgs
[i
] + module
.name
+ ".ilk" );
424 MSVCBackend::_get_def_files ( const Module
& module
, vector
<string
>& out
) const
426 if (module
.HasImportLibrary())
429 string modulename
= module
.GetBasePath ();
430 string file
= module
.importLibrary
->definition
;
431 size_t pos
= file
.find (".def");
432 if (pos
!= string::npos
)
434 file
.insert (pos
, "_msvc");
436 modulename
+= DEF_SSEP
+ file
;
437 out
.push_back (modulename
);
443 MSVCBackend::_clean_project_files ( void )
445 for( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin(); p
!= ProjectNode
.modules
.end(); ++ p
)
447 Module
& module
= *p
->second
;
449 printf("Cleaning project %s %s %s\n", module
.name
.c_str (), module
.output
->relative_path
.c_str (), NcbFileName ( module
).c_str () );
451 string vcproj_file_user
= UserFileName(module
, VcprojFileName ( module
));
452 if(vcproj_file_user
!= "")
453 remove ( vcproj_file_user
.c_str () );
455 _get_object_files ( module
, out
);
456 _get_def_files ( module
, out
);
457 for ( size_t j
= 0; j
< out
.size (); j
++)
459 printf("Cleaning file %s\n", out
[j
].c_str () );
460 remove ( out
[j
].c_str () );
464 string filename_sln
= ProjectNode
.name
+ ".sln";
466 remove ( filename_sln
.c_str () );
470 MSVCBackend::_copy_file ( const std::string
& inputname
, const std::string
& targetname
) const
472 FILE * input
= fopen ( inputname
.c_str (), "rb" );
476 FILE * output
= fopen ( targetname
.c_str (), "wb+" );
485 while ( (num_read
= fread( buffer
, sizeof(char), 256, input
) ) || !feof( input
) )
486 fwrite( buffer
, sizeof(char), num_read
, output
);
494 MSVCBackend::_install_files (const std::string
& vcdir
, const::string
& config
)
496 for( std::map
<std::string
, Module
*>::const_iterator p
= ProjectNode
.modules
.begin(); p
!= ProjectNode
.modules
.end(); ++ p
)
498 Module
& module
= *p
->second
;
499 if ( !module
.install
)
502 string inputname
= Environment::GetOutputPath () + DEF_SSEP
+ module
.output
->relative_path
+ DEF_SSEP
+ vcdir
+ DEF_SSEP
+ config
+ DEF_SSEP
+ module
.output
->name
;
503 string installdir
= Environment::GetInstallPath () + DEF_SSEP
+ module
.install
->relative_path
+ DEF_SSEP
+ module
.install
->name
;
504 if ( _copy_file( inputname
, installdir
) )
505 printf ("Installed File :'%s'\n",installdir
.c_str () );
510 MSVCBackend::_get_solution_version ( void )
514 if (configuration
.VSProjectVersion
.empty())
515 configuration
.VSProjectVersion
= MS_VS_DEF_VERSION
;
517 else if (configuration
.VSProjectVersion
== "8.00")
520 else if (configuration
.VSProjectVersion
== "9.00")
523 else if (configuration
.VSProjectVersion
== "10.00")
530 MSVCBackend::_get_studio_version ( void )
534 if (configuration
.VSProjectVersion
.empty())
535 configuration
.VSProjectVersion
= MS_VS_DEF_VERSION
;
537 else if (configuration
.VSProjectVersion
== "8.00")
540 else if (configuration
.VSProjectVersion
== "9.00")
543 else if (configuration
.VSProjectVersion
== "10.00")
550 MSVCBackend::_lookup_property ( const Module
& module
, const std::string
& name
) const
552 std::map
<std::string
, Property
*>::const_iterator p
;
554 /* Check local values */
555 p
= module
.non_if_data
.properties
.find(name
);
557 if ( p
!= module
.non_if_data
.properties
.end() )
560 // TODO FIXME - should we check local if-ed properties?
561 p
= module
.project
.non_if_data
.properties
.find(name
);
563 if ( p
!= module
.project
.non_if_data
.properties
.end() )
566 // TODO FIXME - should we check global if-ed properties?