cc8cedf367c73c725a1e26ccb4e96c089eb775e6
[reactos.git] / reactos / tools / rbuild / backend / msvc / vcxprojmaker.cpp
1 /*
2 * Copyright (C) 2002 Patrik Stridvall
3 * Copyright (C) 2005 Royce Mitchell III
4 * Copyright (C) 2006 Hervé Poussineau
5 * Copyright (C) 2006 Christoph von Wittich
6 * Copyright (C) 2009 Ged Murphy
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23 #ifdef _MSC_VER
24 #pragma warning ( disable : 4786 )
25 #endif//_MSC_VER
26
27 #include <string>
28 #include <vector>
29 #include <set>
30 #include <algorithm>
31 #include <fstream>
32 #include <iostream>
33
34 #include <stdio.h>
35
36 #include "msvc.h"
37
38 using std::string;
39 using std::vector;
40 using std::set;
41
42 typedef set<string> StringSet;
43
44 #ifdef OUT
45 #undef OUT
46 #endif//OUT
47
48
49 VCXProjMaker::VCXProjMaker ( )
50 {
51 vcproj_file = "";
52 }
53
54 VCXProjMaker::VCXProjMaker ( Configuration& buildConfig,
55 const std::vector<MSVCConfiguration*>& msvc_configs,
56 std::string filename )
57 {
58 configuration = buildConfig;
59 m_configurations = msvc_configs;
60 vcproj_file = filename;
61
62 OUT = fopen ( vcproj_file.c_str(), "wb" );
63
64 if ( !OUT )
65 {
66 printf ( "Could not create file '%s'.\n", vcproj_file.c_str() );
67 }
68 }
69
70 VCXProjMaker::~VCXProjMaker()
71 {
72 fclose ( OUT );
73 }
74
75 void
76 VCXProjMaker::_generate_proj_file ( const Module& module )
77 {
78 size_t i;
79
80 string computername;
81 string username;
82
83 // make sure the containers are empty
84 header_files.clear();
85 includes.clear();
86 includes_ros.clear();
87 libraries.clear();
88 common_defines.clear();
89
90 if (getenv ( "USERNAME" ) != NULL)
91 username = getenv ( "USERNAME" );
92 if (getenv ( "COMPUTERNAME" ) != NULL)
93 computername = getenv ( "COMPUTERNAME" );
94 else if (getenv ( "HOSTNAME" ) != NULL)
95 computername = getenv ( "HOSTNAME" );
96
97 string vcproj_file_user = "";
98
99 if ((computername != "") && (username != ""))
100 vcproj_file_user = vcproj_file + "." + computername + "." + username + ".user";
101
102 printf ( "Creating MSVC project: '%s'\n", vcproj_file.c_str() );
103
104 string path_basedir = module.GetPathToBaseDir ();
105 string intenv = Environment::GetIntermediatePath ();
106 string outenv = Environment::GetOutputPath ();
107 string outdir;
108 string intdir;
109 string vcdir;
110
111 if ( intenv == "obj-i386" )
112 intdir = path_basedir + "obj-i386"; /* append relative dir from project dir */
113 else
114 intdir = intenv;
115
116 if ( outenv == "output-i386" )
117 outdir = path_basedir + "output-i386";
118 else
119 outdir = outenv;
120
121 if ( configuration.UseVSVersionInPath )
122 {
123 vcdir = DEF_SSEP + _get_vc_dir();
124 }
125
126 bool include_idl = false;
127
128 vector<string> source_files, resource_files;
129 vector<const IfableData*> ifs_list;
130 ifs_list.push_back ( &module.project.non_if_data );
131 ifs_list.push_back ( &module.non_if_data );
132
133 while ( ifs_list.size() )
134 {
135 const IfableData& data = *ifs_list.back();
136 ifs_list.pop_back();
137 const vector<File*>& files = data.files;
138 for ( i = 0; i < files.size(); i++ )
139 {
140 if (files[i]->file.directory != SourceDirectory)
141 continue;
142
143 // We want the full path here for directory support later on
144 string path = Path::RelativeFromDirectory (
145 files[i]->file.relative_path,
146 module.output->relative_path );
147 string file = path + std::string("\\") + files[i]->file.name;
148
149 if ( !stricmp ( Right(file,3).c_str(), ".rc" ) )
150 resource_files.push_back ( file );
151 else if ( !stricmp ( Right(file,2).c_str(), ".h" ) )
152 header_files.push_back ( file );
153 else
154 source_files.push_back ( file );
155 }
156 const vector<Include*>& incs = data.includes;
157 for ( i = 0; i < incs.size(); i++ )
158 {
159 string path = Path::RelativeFromDirectory (
160 incs[i]->directory->relative_path,
161 module.output->relative_path );
162 if ( module.type != RpcServer && module.type != RpcClient )
163 {
164 if ( path.find ("/include/reactos/idl") != string::npos)
165 {
166 include_idl = true;
167 continue;
168 }
169 }
170 // switch between general headers and ros headers
171 if ( !strncmp(incs[i]->directory->relative_path.c_str(), "include\\crt", 11 ) ||
172 !strncmp(incs[i]->directory->relative_path.c_str(), "include\\ddk", 11 ) ||
173 !strncmp(incs[i]->directory->relative_path.c_str(), "include\\GL", 10 ) ||
174 !strncmp(incs[i]->directory->relative_path.c_str(), "include\\psdk", 12 ) ||
175 !strncmp(incs[i]->directory->relative_path.c_str(), "include\\reactos\\wine", 20 ) )
176 {
177 if (strncmp(incs[i]->directory->relative_path.c_str(), "include\\crt", 11 ))
178 // not crt include
179 includes_ros.push_back ( path );
180 }
181 else
182 {
183 includes.push_back ( path );
184 }
185 }
186 const vector<Library*>& libs = data.libraries;
187 for ( i = 0; i < libs.size(); i++ )
188 {
189 string libpath = outdir + "\\" + libs[i]->importedModule->output->relative_path + "\\" + _get_vc_dir() + "\\---\\" + libs[i]->name + ".lib";
190 libraries.push_back ( libpath );
191 }
192 const vector<Define*>& defs = data.defines;
193 for ( i = 0; i < defs.size(); i++ )
194 {
195 if ( defs[i]->backend != "" && defs[i]->backend != "msvc" )
196 continue;
197
198 if ( defs[i]->value[0] )
199 common_defines.insert( defs[i]->name + "=" + defs[i]->value );
200 else
201 common_defines.insert( defs[i]->name );
202 }
203 for ( std::map<std::string, Property*>::const_iterator p = data.properties.begin(); p != data.properties.end(); ++ p )
204 {
205 Property& prop = *p->second;
206 if ( strstr ( module.baseaddress.c_str(), prop.name.c_str() ) )
207 baseaddr = prop.value;
208 }
209 }
210 /* include intermediate path for reactos.rc */
211 string version = intdir + "\\include";
212 includes.push_back (version);
213 version += "\\reactos";
214 includes.push_back (version);
215
216 // Set the binary type
217 string module_type = GetExtension(*module.output);
218 BinaryType binaryType;
219 if ((module.type == ObjectLibrary) || (module.type == RpcClient) ||(module.type == RpcServer) || (module_type == ".lib") || (module_type == ".a"))
220 binaryType = Lib;
221 else if ((module_type == ".dll") || (module_type == ".cpl"))
222 binaryType = Dll;
223 else if ((module_type == ".exe") || (module_type == ".scr"))
224 binaryType = Exe;
225 else if (module_type == ".sys")
226 binaryType = Sys;
227 else
228 binaryType = BinUnknown;
229
230 string include_string;
231
232 fprintf ( OUT, "<?xml version=\"1.0\" encoding = \"utf-8\"?>\r\n" );
233 fprintf ( OUT, "<Project " );
234 fprintf ( OUT, "DefaultTargets=\"Build\" " ); //FIXME: what's Build??
235 fprintf ( OUT, "ToolsVersion=\"4.0\" " ); //FIXME: Is it always 4.0??
236 fprintf ( OUT, "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n" );
237
238 if (configuration.VSProjectVersion.empty())
239 configuration.VSProjectVersion = "10.00";
240
241 // Write out the configurations
242 fprintf ( OUT, "\t<ItemGroup Label=\"ProjectConfigurations\">\r\n" );
243 for ( size_t icfg = 0; icfg < m_configurations.size(); icfg++ )
244 {
245 const MSVCConfiguration& cfg = *m_configurations[icfg];
246
247 if ( cfg.optimization == RosBuild )
248 {
249 _generate_makefile_configuration( module, cfg );
250 }
251 else
252 {
253 _generate_standard_configuration( module, cfg, binaryType );
254 }
255 }
256 fprintf ( OUT, "\t</ItemGroup>\r\n" );
257
258 // Write out the global info
259 fprintf ( OUT, "\t<PropertyGroup Label=\"Globals\">\r\n" );
260 fprintf ( OUT, "\t\t<ProjectGuid>{%s}</ProjectGuid>\r\n", module.guid.c_str() );
261 fprintf ( OUT, "\t\t<Keyword>%s</Keyword>\r\n", "Win32Proj" ); //FIXME: Win32Proj???
262 fprintf ( OUT, "\t\t<RootNamespace>%s</RootNamespace>\r\n", module.name.c_str() ); //FIXME: shouldn't this be the soltion name?
263 fprintf ( OUT, "\t</PropertyGroup>\r\n" );
264
265
266
267 }
268
269 void
270 VCXProjMaker::_generate_user_configuration ()
271 {
272 // Call base implementation
273 ProjMaker::_generate_user_configuration ();
274 }
275
276 void
277 VCXProjMaker::_generate_standard_configuration( const Module& module, const MSVCConfiguration& cfg, BinaryType binaryType )
278 {
279 fprintf ( OUT, "\t\t<ProjectConfiguration Include=\"%s|Win32\">\r\n", cfg.name.c_str() );
280 fprintf ( OUT, "\t\t<Configuration>%s</Configuration>\r\n", cfg.name.c_str() );
281 fprintf ( OUT, "\t\t<Platform>Win32</Platform>\r\n" );
282 fprintf ( OUT, "\t</ProjectConfiguration>\r\n" );
283 }
284
285 void
286 VCXProjMaker::_generate_makefile_configuration( const Module& module, const MSVCConfiguration& cfg )
287 {
288 // TODO: Implement me
289 ProjMaker::_generate_makefile_configuration ( module, cfg );
290 }