Merge from amd64-branch:
[reactos.git] / reactos / tools / rbuild / backend / msvc / vcprojmaker.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 struct SortFilesAscending
49 {
50 bool operator()(const string& rhs, const string& lhs)
51 {
52 return rhs < lhs;
53 }
54 };
55
56
57 VCProjMaker::VCProjMaker ( )
58 {
59 vcproj_file = "";
60 }
61
62 VCProjMaker::VCProjMaker ( Configuration& buildConfig,
63 const std::vector<MSVCConfiguration*>& msvc_configs,
64 std::string filename )
65 {
66 configuration = buildConfig;
67 m_configurations = msvc_configs;
68 vcproj_file = filename;
69
70 OUT = fopen ( vcproj_file.c_str(), "wb" );
71
72 if ( !OUT )
73 {
74 printf ( "Could not create file '%s'.\n", vcproj_file.c_str() );
75 }
76 }
77
78 VCProjMaker::~VCProjMaker()
79 {
80 fclose ( OUT );
81 }
82
83 void
84 VCProjMaker::_generate_proj_file ( const Module& module )
85 {
86 size_t i;
87
88 string computername;
89 string username;
90
91 // make sure the containers are empty
92 header_files.clear();
93 includes.clear();
94 includes_ros.clear();
95 libraries.clear();
96 common_defines.clear();
97
98 if (getenv ( "USERNAME" ) != NULL)
99 username = getenv ( "USERNAME" );
100 if (getenv ( "COMPUTERNAME" ) != NULL)
101 computername = getenv ( "COMPUTERNAME" );
102 else if (getenv ( "HOSTNAME" ) != NULL)
103 computername = getenv ( "HOSTNAME" );
104
105 string vcproj_file_user = "";
106
107 if ((computername != "") && (username != ""))
108 vcproj_file_user = vcproj_file + "." + computername + "." + username + ".user";
109
110 printf ( "Creating MSVC project: '%s'\n", vcproj_file.c_str() );
111
112 string path_basedir = module.GetPathToBaseDir ();
113 string intenv = Environment::GetIntermediatePath ();
114 string outenv = Environment::GetOutputPath ();
115 string outdir;
116 string intdir;
117 string vcdir;
118
119 if ( intenv == "obj-i386" )
120 intdir = path_basedir + "obj-i386"; /* append relative dir from project dir */
121 else
122 intdir = intenv;
123
124 if ( outenv == "output-i386" )
125 outdir = path_basedir + "output-i386";
126 else
127 outdir = outenv;
128
129 if ( configuration.UseVSVersionInPath )
130 {
131 vcdir = DEF_SSEP + _get_vc_dir();
132 }
133
134 bool include_idl = false;
135
136 vector<string> source_files, resource_files;
137 vector<const IfableData*> ifs_list;
138 ifs_list.push_back ( &module.project.non_if_data );
139 ifs_list.push_back ( &module.non_if_data );
140
141 while ( ifs_list.size() )
142 {
143 const IfableData& data = *ifs_list.back();
144 ifs_list.pop_back();
145 const vector<File*>& files = data.files;
146 for ( i = 0; i < files.size(); i++ )
147 {
148 if (files[i]->file.directory != SourceDirectory)
149 continue;
150
151 // We want the full path here for directory support later on
152 string path = Path::RelativeFromDirectory (
153 files[i]->file.relative_path,
154 module.output->relative_path );
155 string file = path + std::string("\\") + files[i]->file.name;
156
157 if ( !stricmp ( Right(file,3).c_str(), ".rc" ) )
158 resource_files.push_back ( file );
159 else if ( !stricmp ( Right(file,2).c_str(), ".h" ) )
160 header_files.push_back ( file );
161 else
162 source_files.push_back ( file );
163 }
164 const vector<Include*>& incs = data.includes;
165 for ( i = 0; i < incs.size(); i++ )
166 {
167 string path = Path::RelativeFromDirectory (
168 incs[i]->directory->relative_path,
169 module.output->relative_path );
170 if ( module.type != RpcServer && module.type != RpcClient )
171 {
172 if ( path.find ("/include/reactos/idl") != string::npos)
173 {
174 include_idl = true;
175 continue;
176 }
177 }
178 // switch between general headers and ros headers
179 if ( !strncmp(incs[i]->directory->relative_path.c_str(), "include\\crt", 11 ) ||
180 !strncmp(incs[i]->directory->relative_path.c_str(), "include\\ddk", 11 ) ||
181 !strncmp(incs[i]->directory->relative_path.c_str(), "include\\GL", 10 ) ||
182 !strncmp(incs[i]->directory->relative_path.c_str(), "include\\psdk", 12 ) ||
183 !strncmp(incs[i]->directory->relative_path.c_str(), "include\\reactos\\wine", 20 ) )
184 {
185 if (strncmp(incs[i]->directory->relative_path.c_str(), "include\\crt", 11 ))
186 // not crt include
187 includes_ros.push_back ( path );
188 }
189 else
190 {
191 includes.push_back ( path );
192 }
193 }
194 const vector<Library*>& libs = data.libraries;
195 for ( i = 0; i < libs.size(); i++ )
196 {
197 string libpath = outdir + "\\" + libs[i]->importedModule->output->relative_path + "\\" + _get_vc_dir() + "\\---\\" + libs[i]->name + ".lib";
198 libraries.push_back ( libpath );
199 }
200 const vector<Define*>& defs = data.defines;
201 for ( i = 0; i < defs.size(); i++ )
202 {
203 if ( defs[i]->backend != "" && defs[i]->backend != "msvc" )
204 continue;
205
206 if ( defs[i]->value[0] )
207 common_defines.insert( defs[i]->name + "=" + defs[i]->value );
208 else
209 common_defines.insert( defs[i]->name );
210 }
211 for ( std::map<std::string, Property*>::const_iterator p = data.properties.begin(); p != data.properties.end(); ++ p )
212 {
213 Property& prop = *p->second;
214 if ( strstr ( module.baseaddress.c_str(), prop.name.c_str() ) )
215 baseaddr = prop.value;
216 }
217 }
218 /* include intermediate path for reactos.rc */
219 string version = intdir + "\\include";
220 includes.push_back (version);
221 version += "\\reactos";
222 includes.push_back (version);
223
224 string include_string;
225
226 fprintf ( OUT, "<?xml version=\"1.0\" encoding = \"Windows-1252\"?>\r\n" );
227 fprintf ( OUT, "<VisualStudioProject\r\n" );
228 fprintf ( OUT, "\tProjectType=\"Visual C++\"\r\n" );
229
230 if (configuration.VSProjectVersion.empty())
231 configuration.VSProjectVersion = MS_VS_DEF_VERSION;
232
233 fprintf ( OUT, "\tVersion=\"%s\"\r\n", configuration.VSProjectVersion.c_str() );
234 fprintf ( OUT, "\tName=\"%s\"\r\n", module.name.c_str() );
235 fprintf ( OUT, "\tProjectGUID=\"%s\"\r\n", module.guid.c_str() );
236 fprintf ( OUT, "\tKeyword=\"Win32Proj\">\r\n" );
237
238 fprintf ( OUT, "\t<Platforms>\r\n" );
239 fprintf ( OUT, "\t\t<Platform\r\n" );
240 fprintf ( OUT, "\t\t\tName=\"Win32\"/>\r\n" );
241 fprintf ( OUT, "\t</Platforms>\r\n" );
242
243 // Set the binary type
244 string module_type = GetExtension(*module.output);
245 BinaryType binaryType;
246 if ((module.type == ObjectLibrary) || (module.type == RpcClient) ||(module.type == RpcServer) || (module_type == ".lib") || (module_type == ".a"))
247 binaryType = Lib;
248 else if ((module_type == ".dll") || (module_type == ".cpl"))
249 binaryType = Dll;
250 else if ((module_type == ".exe") || (module_type == ".scr"))
251 binaryType = Exe;
252 else if (module_type == ".sys")
253 binaryType = Sys;
254 else
255 binaryType = BinUnknown;
256
257 // Write out all the configurations
258 fprintf ( OUT, "\t<Configurations>\r\n" );
259 for ( size_t icfg = 0; icfg < m_configurations.size(); icfg++ )
260 {
261 const MSVCConfiguration& cfg = *m_configurations[icfg];
262
263 if ( cfg.optimization == RosBuild )
264 {
265 _generate_makefile_configuration( module, cfg );
266 }
267 else
268 {
269 _generate_standard_configuration( module, cfg, binaryType );
270 }
271 }
272 fprintf ( OUT, "\t</Configurations>\r\n" );
273
274 // Write out the project files
275 fprintf ( OUT, "\t<Files>\r\n" );
276
277 // Source files
278 fprintf ( OUT, "\t\t<Filter\r\n" );
279 fprintf ( OUT, "\t\t\tName=\"Source Files\"\r\n" );
280 fprintf ( OUT, "\t\t\tFilter=\"cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;S\">\r\n" );
281
282 std::sort(source_files.begin(), source_files.end(), SortFilesAscending());
283 vector<string> last_folder;
284 vector<string> split_path;
285 string indent_tab("\t\t\t");
286
287 for ( size_t isrcfile = 0; isrcfile < source_files.size(); isrcfile++ )
288 {
289 string source_file = DosSeparator(source_files[isrcfile]);
290
291 Path::Split(split_path, source_file, false);
292 size_t same_folder_index = 0;
293 for ( size_t ifolder = 0; ifolder < last_folder.size(); ifolder++ )
294 {
295 if ( ifolder < split_path.size() && last_folder[ifolder] == split_path[ifolder] )
296 ++same_folder_index;
297 else
298 break;
299 }
300
301 if ( same_folder_index < split_path.size() || last_folder.size() > split_path.size() )
302 {
303 int tabStart = 1;
304 if ( split_path.size() > last_folder.size() )
305 {
306 for ( size_t ifolder = last_folder.size(); ifolder < split_path.size(); ifolder++ )
307 indent_tab.push_back('\t');
308 tabStart = split_path.size() - last_folder.size() + 1;
309 }
310 else if ( split_path.size() < last_folder.size() )
311 {
312 indent_tab.resize( split_path.size() + 3 );
313 tabStart = split_path.size() - last_folder.size() + 1;
314 }
315
316 for ( size_t ifolder = last_folder.size(), itab = tabStart; ifolder > same_folder_index; ifolder--, itab++ )
317 {
318 fprintf ( OUT, "%s</Filter>\r\n", indent_tab.substr(0, indent_tab.size() - itab).c_str() );
319 }
320
321 for ( size_t ifolder = same_folder_index, itab = split_path.size() - same_folder_index; ifolder < split_path.size(); ifolder++, itab-- )
322 {
323 const string tab = indent_tab.substr(0, indent_tab.size() - itab);
324 fprintf ( OUT, "%s<Filter\r\n", tab.c_str() );
325 fprintf ( OUT, "%s\tName=\"%s\">\r\n", tab.c_str(), split_path[ifolder].c_str() );
326 }
327
328 last_folder = split_path;
329 }
330
331 fprintf ( OUT, "%s<File\r\n", indent_tab.c_str() );
332 fprintf ( OUT, "%s\tRelativePath=\"%s\">\r\n", indent_tab.c_str(), source_file.c_str() );
333
334 for ( size_t iconfig = 0; iconfig < m_configurations.size(); iconfig++ )
335 {
336 const MSVCConfiguration& config = *m_configurations[iconfig];
337
338 if (( isrcfile == 0 ) && ( module.pch != NULL ))
339 {
340 /* little hack to speed up PCH */
341 fprintf ( OUT, "%s\t<FileConfiguration\r\n", indent_tab.c_str() );
342 fprintf ( OUT, "%s\t\tName=\"", indent_tab.c_str() );
343 fprintf ( OUT, config.name.c_str() );
344 fprintf ( OUT, "|Win32\">\r\n" );
345 fprintf ( OUT, "%s\t\t<Tool\r\n", indent_tab.c_str() );
346 fprintf ( OUT, "%s\t\t\tName=\"VCCLCompilerTool\"\r\n", indent_tab.c_str() );
347 fprintf ( OUT, "%s\t\t\tUsePrecompiledHeader=\"1\"/>\r\n", indent_tab.c_str() );
348 fprintf ( OUT, "%s\t</FileConfiguration>\r\n", indent_tab.c_str() );
349 }
350
351 //if (configuration.VSProjectVersion < "8.00") {
352 if ((source_file.find(".idl") != string::npos) || ((source_file.find(".asm") != string::npos || tolower(source_file.at(source_file.size() - 1)) == 's')))
353 {
354 fprintf ( OUT, "%s\t<FileConfiguration\r\n", indent_tab.c_str() );
355 fprintf ( OUT, "%s\t\tName=\"", indent_tab.c_str() );
356 fprintf ( OUT, config.name.c_str() );
357 fprintf ( OUT, "|Win32\">\r\n" );
358 fprintf ( OUT, "%s\t\t<Tool\r\n", indent_tab.c_str() );
359 if (source_file.find(".idl") != string::npos)
360 {
361 string src = source_file.substr (0, source_file.find(".idl"));
362
363 if ( src.find (".\\") != string::npos )
364 src.erase (0, 2);
365
366 fprintf ( OUT, "%s\t\t\tName=\"VCCustomBuildTool\"\r\n", indent_tab.c_str() );
367
368 if ( module.type == RpcClient )
369 {
370 fprintf ( OUT, "%s\t\t\tCommandLine=\"midl.exe /cstub %s_c.c /header %s_c.h /server none &quot;$(InputPath)&quot; /out &quot;$(IntDir)&quot;", indent_tab.c_str(), src.c_str (), src.c_str () );
371 fprintf ( OUT, "&#x0D;&#x0A;");
372 fprintf ( OUT, "cl.exe /Od /D &quot;WIN32&quot; /D &quot;_DEBUG&quot; /D &quot;_WINDOWS&quot; /D &quot;_WIN32_WINNT=0x502&quot; /D &quot;_UNICODE&quot; /D &quot;UNICODE&quot; /Gm /EHsc /RTC1 /MDd /Fo&quot;$(IntDir)\\%s.obj&quot; /W3 /c /Wp64 /ZI /TC &quot;$(IntDir)\\%s_c.c&quot; /nologo /errorReport:prompt", src.c_str (), src.c_str () );
373 }
374 else
375 {
376 fprintf ( OUT, "%s\t\t\tCommandLine=\"midl.exe /sstub %s_s.c /header %s_s.h /client none &quot;$(InputPath)&quot; /out &quot;$(IntDir)&quot;", indent_tab.c_str(), src.c_str (), src.c_str () );
377 fprintf ( OUT, "&#x0D;&#x0A;");
378 fprintf ( OUT, "cl.exe /Od /D &quot;WIN32&quot; /D &quot;_DEBUG&quot; /D &quot;_WINDOWS&quot; /D &quot;_WIN32_WINNT=0x502&quot; /D &quot;_UNICODE&quot; /D &quot;UNICODE&quot; /Gm /EHsc /RTC1 /MDd /Fo&quot;$(IntDir)\\%s.obj&quot; /W3 /c /Wp64 /ZI /TC &quot;$(IntDir)\\%s_s.c&quot; /nologo /errorReport:prompt", src.c_str (), src.c_str () );
379
380 }
381 fprintf ( OUT, "&#x0D;&#x0A;");
382 fprintf ( OUT, "lib.exe /OUT:&quot;$(OutDir)\\%s.lib&quot; &quot;$(IntDir)\\%s.obj&quot;&#x0D;&#x0A;\"\r\n", module.name.c_str (), src.c_str () );
383 fprintf ( OUT, "%s\t\t\tOutputs=\"$(IntDir)\\$(InputName).obj\"/>\r\n", indent_tab.c_str() );
384 }
385 else if ((source_file.find(".asm") != string::npos))
386 {
387 fprintf ( OUT, "%s\t\t\tName=\"VCCustomBuildTool\"\r\n", indent_tab.c_str() );
388 fprintf ( OUT, "%s\t\t\tCommandLine=\"nasmw $(InputPath) -f coff -o &quot;$(OutDir)\\$(InputName).obj&quot;\"\r\n", indent_tab.c_str() );
389 fprintf ( OUT, "%s\t\t\tOutputs=\"$(OutDir)\\$(InputName).obj\"/>\r\n", indent_tab.c_str() );
390 }
391 else if ((tolower(source_file.at(source_file.size() - 1)) == 's'))
392 {
393 fprintf ( OUT, "%s\t\t\tName=\"VCCustomBuildTool\"\r\n", indent_tab.c_str() );
394 fprintf ( OUT, "%s\t\t\tCommandLine=\"cl /E &quot;$(InputPath)&quot; %s /D__ASM__ | as -o &quot;$(OutDir)\\$(InputName).obj&quot;\"\r\n", indent_tab.c_str(), include_string.c_str() );
395 fprintf ( OUT, "%s\t\t\tOutputs=\"$(OutDir)\\$(InputName).obj\"/>\r\n", indent_tab.c_str() );
396 }
397 fprintf ( OUT, "%s\t</FileConfiguration>\r\n", indent_tab.c_str() );
398 }
399 //}
400 }
401 fprintf ( OUT, "%s</File>\r\n", indent_tab.c_str() );
402 }
403
404 for ( size_t ifolder = last_folder.size(); ifolder > 0; ifolder-- )
405 {
406 indent_tab.resize( ifolder + 2 );
407 fprintf ( OUT, "%s</Filter>\r\n", indent_tab.c_str() );
408 }
409
410 fprintf ( OUT, "\t\t</Filter>\r\n" );
411
412 // Header files
413 fprintf ( OUT, "\t\t<Filter\r\n" );
414 fprintf ( OUT, "\t\t\tName=\"Header Files\"\r\n" );
415 fprintf ( OUT, "\t\t\tFilter=\"h;hpp;hxx;hm;inl\">\r\n" );
416 for ( i = 0; i < header_files.size(); i++ )
417 {
418 const string& header_file = header_files[i];
419 fprintf ( OUT, "\t\t\t<File\r\n" );
420 fprintf ( OUT, "\t\t\t\tRelativePath=\"%s\">\r\n", header_file.c_str() );
421 fprintf ( OUT, "\t\t\t</File>\r\n" );
422 }
423 fprintf ( OUT, "\t\t</Filter>\r\n" );
424
425 // Resource files
426 fprintf ( OUT, "\t\t<Filter\r\n" );
427 fprintf ( OUT, "\t\t\tName=\"Resource Files\"\r\n" );
428 fprintf ( OUT, "\t\t\tFilter=\"ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe\">\r\n" );
429 for ( i = 0; i < resource_files.size(); i++ )
430 {
431 const string& resource_file = resource_files[i];
432 fprintf ( OUT, "\t\t\t<File\r\n" );
433 fprintf ( OUT, "\t\t\t\tRelativePath=\"%s\">\r\n", resource_file.c_str() );
434 fprintf ( OUT, "\t\t\t</File>\r\n" );
435 }
436 fprintf ( OUT, "\t\t</Filter>\r\n" );
437
438 fprintf ( OUT, "\t</Files>\r\n" );
439 fprintf ( OUT, "\t<Globals>\r\n" );
440 fprintf ( OUT, "\t</Globals>\r\n" );
441 fprintf ( OUT, "</VisualStudioProject>\r\n" );
442 }
443
444 void VCProjMaker::_generate_user_configuration ()
445 {
446 // Call base implementation
447 ProjMaker::_generate_user_configuration ();
448 }
449
450 void VCProjMaker::_generate_standard_configuration( const Module& module,
451 const MSVCConfiguration& cfg,
452 BinaryType binaryType )
453 {
454 string path_basedir = module.GetPathToBaseDir ();
455 string intenv = Environment::GetIntermediatePath ();
456 string outenv = Environment::GetOutputPath ();
457 string outdir;
458 string intdir;
459 string vcdir;
460
461 bool debug = ( cfg.optimization == Debug );
462 bool release = ( cfg.optimization == Release );
463 bool speed = ( cfg.optimization == Speed );
464
465 bool include_idl = false;
466 string include_string;
467
468 size_t i;
469 string intermediatedir = "";
470 string importLib;
471 // don't do the work m_configurations.size() times
472 if (module.importLibrary != NULL)
473 {
474 intermediatedir = module.output->relative_path + vcdir;
475 importLib = _strip_gcc_deffile(module.importLibrary->source->name, module.importLibrary->source->relative_path, intermediatedir);
476 importLib = Path::RelativeFromDirectory (
477 importLib,
478 module.output->relative_path );
479 }
480
481 string module_type = GetExtension(*module.output);
482
483 // Set the configuration type for this config
484 ConfigurationType CfgType;
485 if ( binaryType == Exe )
486 CfgType = ConfigApp;
487 else if ( binaryType == Lib )
488 CfgType = ConfigLib;
489 else if ( binaryType == Dll || binaryType == Sys )
490 CfgType = ConfigDll;
491 else
492 CfgType = ConfigUnknown;
493
494
495 if ( intenv == "obj-i386" )
496 intdir = path_basedir + "obj-i386"; /* append relative dir from project dir */
497 else
498 intdir = intenv;
499
500 if ( outenv == "output-i386" )
501 outdir = path_basedir + "output-i386";
502 else
503 outdir = outenv;
504
505 if ( configuration.UseVSVersionInPath )
506 {
507 vcdir = DEF_SSEP + _get_vc_dir();
508 }
509
510 fprintf ( OUT, "\t\t<Configuration\r\n" );
511 fprintf ( OUT, "\t\t\tName=\"%s|Win32\"\r\n", cfg.name.c_str() );
512
513 if ( configuration.UseConfigurationInPath )
514 {
515 fprintf ( OUT, "\t\t\tOutputDirectory=\"%s\\%s%s\\%s\"\r\n", outdir.c_str (), module.output->relative_path.c_str (), vcdir.c_str (), cfg.name.c_str() );
516 fprintf ( OUT, "\t\t\tIntermediateDirectory=\"%s\\%s%s\\%s\"\r\n", intdir.c_str (), module.output->relative_path.c_str (), vcdir.c_str (), cfg.name.c_str() );
517 }
518 else
519 {
520 fprintf ( OUT, "\t\t\tOutputDirectory=\"%s\\%s%s\"\r\n", outdir.c_str (), module.output->relative_path.c_str (), vcdir.c_str () );
521 fprintf ( OUT, "\t\t\tIntermediateDirectory=\"%s\\%s%s\"\r\n", intdir.c_str (), module.output->relative_path.c_str (), vcdir.c_str () );
522 }
523
524 fprintf ( OUT, "\t\t\tConfigurationType=\"%d\"\r\n", CfgType );
525 fprintf ( OUT, "\t\t\tCharacterSet=\"2\"\r\n" );
526 fprintf ( OUT, "\t\t\t>\r\n" );
527
528 fprintf ( OUT, "\t\t\t<Tool\r\n" );
529 fprintf ( OUT, "\t\t\t\tName=\"VCCLCompilerTool\"\r\n" );
530
531 fprintf ( OUT, "\t\t\t\tOptimization=\"%d\"\r\n", release ? 2 : 0 );
532
533 fprintf ( OUT, "\t\t\t\tAdditionalIncludeDirectories=\"" );
534 bool multiple_includes = false;
535 fprintf ( OUT, "./;" );
536 for ( i = 0; i < includes.size(); i++ )
537 {
538 const std::string& include = includes[i];
539 if ( strcmp ( include.c_str(), "." ) )
540 {
541 if ( multiple_includes )
542 fprintf ( OUT, ";" );
543 fprintf ( OUT, "%s", include.c_str() );
544 include_string += " /I " + include;
545 multiple_includes = true;
546 }
547 }
548 if ( include_idl )
549 {
550 if ( multiple_includes )
551 fprintf ( OUT, ";" );
552
553 if ( configuration.UseConfigurationInPath )
554 {
555 fprintf ( OUT, "%s\\include\\reactos\\idl%s\\%s\r\n", intdir.c_str (), vcdir.c_str (), cfg.name.c_str() );
556 }
557 else
558 {
559 fprintf ( OUT, "%s\\include\\reactos\\idl\r\n", intdir.c_str () );
560 }
561 }
562 if ( cfg.headers == ReactOSHeaders )
563 {
564 for ( i = 0; i < includes_ros.size(); i++ )
565 {
566 const std::string& include = includes_ros[i];
567 if ( multiple_includes )
568 fprintf ( OUT, ";" );
569 fprintf ( OUT, "%s", include.c_str() );
570 //include_string += " /I " + include;
571 multiple_includes = true;
572 }
573 }
574 else
575 {
576 // Add WDK or PSDK paths, if user provides them
577 if (getenv ( "BASEDIR" ) != NULL &&
578 (module.type == Kernel ||
579 module.type == KernelModeDLL ||
580 module.type == KernelModeDriver ||
581 module.type == KeyboardLayout))
582 {
583 string WdkBase, SdkPath, CrtPath, DdkPath;
584 WdkBase = getenv ( "BASEDIR" );
585 SdkPath = WdkBase + "\\inc\\api";
586 CrtPath = WdkBase + "\\inc\\crt";
587 DdkPath = WdkBase + "\\inc\\ddk";
588
589 if ( multiple_includes )
590 fprintf ( OUT, ";" );
591
592 fprintf ( OUT, "%s;", SdkPath.c_str() );
593 fprintf ( OUT, "%s;", CrtPath.c_str() );
594 fprintf ( OUT, "%s", DdkPath.c_str() );
595 multiple_includes = true;
596 }
597 }
598 fprintf ( OUT, "\"\r\n" );
599
600 StringSet defines = common_defines;
601
602 // Always add _CRT_SECURE_NO_WARNINGS to disable warnings about not
603 // using the safe functions introduced in MSVC8.
604 defines.insert ( "_CRT_SECURE_NO_WARNINGS" );
605
606 if ( debug )
607 {
608 defines.insert ( "_DEBUG" );
609 }
610
611 if ( cfg.headers == MSVCHeaders )
612 {
613 // this is a define in MinGW w32api, but not Microsoft's headers
614 defines.insert ( "STDCALL=__stdcall" );
615 }
616
617 if ( binaryType == Lib || binaryType == Exe )
618 {
619 defines.insert ( "_LIB" );
620 }
621 else
622 {
623 defines.insert ( "_WINDOWS" );
624 defines.insert ( "_USRDLL" );
625 }
626
627 fprintf ( OUT, "\t\t\t\tPreprocessorDefinitions=\"" );
628 for ( StringSet::iterator it1=defines.begin(); it1!=defines.end(); it1++ )
629 {
630 if ( i > 0 )
631 fprintf ( OUT, ";" );
632
633 string unescaped = *it1;
634 fprintf ( OUT, "%s", _replace_str(unescaped, "\"","").c_str() );
635 }
636 fprintf ( OUT, "\"\r\n" );
637 fprintf ( OUT, "\t\t\t\tForcedIncludeFiles=\"%s\"\r\n", "warning.h");
638 fprintf ( OUT, "\t\t\t\tMinimalRebuild=\"%s\"\r\n", speed ? "TRUE" : "FALSE" );
639 fprintf ( OUT, "\t\t\t\tBasicRuntimeChecks=\"0\"\r\n" );
640 fprintf ( OUT, "\t\t\t\tRuntimeLibrary=\"%d\"\r\n", debug ? 3 : 2 ); // 3=/MDd 2=/MD
641 fprintf ( OUT, "\t\t\t\tBufferSecurityCheck=\"FALSE\"\r\n" );
642 fprintf ( OUT, "\t\t\t\tEnableFunctionLevelLinking=\"FALSE\"\r\n" );
643
644 if ( module.pch != NULL )
645 {
646 fprintf ( OUT, "\t\t\t\tUsePrecompiledHeader=\"2\"\r\n" );
647 string pch_path = Path::RelativeFromDirectory (
648 module.pch->file->name,
649 module.output->relative_path );
650 string::size_type pos = pch_path.find_last_of ("/");
651 if ( pos != string::npos )
652 pch_path.erase(0, pos+1);
653 fprintf ( OUT, "\t\t\t\tPrecompiledHeaderThrough=\"%s\"\r\n", pch_path.c_str() );
654
655 // Only include from the same module
656 pos = pch_path.find("../");
657 if (pos == string::npos && std::find(header_files.begin(), header_files.end(), pch_path) == header_files.end())
658 header_files.push_back(pch_path);
659 }
660 else
661 {
662 fprintf ( OUT, "\t\t\t\tUsePrecompiledHeader=\"0\"\r\n" );
663 }
664
665 fprintf ( OUT, "\t\t\t\tWholeProgramOptimization=\"%s\"\r\n", release ? "FALSE" : "FALSE");
666 if ( release )
667 {
668 fprintf ( OUT, "\t\t\t\tFavorSizeOrSpeed=\"1\"\r\n" );
669 fprintf ( OUT, "\t\t\t\tStringPooling=\"true\"\r\n" );
670 }
671
672 fprintf ( OUT, "\t\t\t\tWarningLevel=\"%s\"\r\n", speed ? "0" : "3" );
673 fprintf ( OUT, "\t\t\t\tDetect64BitPortabilityProblems=\"%s\"\r\n", "FALSE");
674 if ( !module.cplusplus )
675 fprintf ( OUT, "\t\t\t\tCompileAs=\"1\"\r\n" );
676
677 if ( module.type == Win32CUI || module.type == Win32GUI )
678 {
679 fprintf ( OUT, "\t\t\t\tCallingConvention=\"%d\"\r\n", 0 ); // 0=__cdecl
680 }
681 else
682 {
683 fprintf ( OUT, "\t\t\t\tCallingConvention=\"%d\"\r\n", 2 ); // 2=__stdcall
684 }
685
686 fprintf ( OUT, "\t\t\t\tDebugInformationFormat=\"%s\"/>\r\n", speed ? "0" : release ? "3": "4"); // 3=/Zi 4=ZI
687
688 fprintf ( OUT, "\t\t\t<Tool\r\n" );
689 fprintf ( OUT, "\t\t\t\tName=\"VCCustomBuildTool\"/>\r\n" );
690
691 if ( binaryType == Lib )
692 {
693 fprintf ( OUT, "\t\t\t<Tool\r\n" );
694 fprintf ( OUT, "\t\t\t\tName=\"VCLibrarianTool\"\r\n" );
695 fprintf ( OUT, "\t\t\t\tOutputFile=\"$(OutDir)/%s.lib\"/>\r\n", module.name.c_str() );
696 }
697 else
698 {
699 fprintf ( OUT, "\t\t\t<Tool\r\n" );
700 fprintf ( OUT, "\t\t\t\tName=\"VCLinkerTool\"\r\n" );
701 if (module.GetEntryPoint() == "0" && binaryType != Sys )
702 fprintf ( OUT, "AdditionalOptions=\"/noentry\"" );
703
704 if (configuration.VSProjectVersion == "9.00")
705 {
706 fprintf ( OUT, "\t\t\t\tRandomizedBaseAddress=\"0\"\r\n" );
707 fprintf ( OUT, "\t\t\t\tDataExecutionPrevention=\"0\"\r\n" );
708 }
709
710 if (module.importLibrary != NULL)
711 fprintf ( OUT, "\t\t\t\tModuleDefinitionFile=\"%s\"\r\n", importLib.c_str());
712
713 fprintf ( OUT, "\t\t\t\tAdditionalDependencies=\"" );
714 bool use_msvcrt_lib = false;
715 for ( i = 0; i < libraries.size(); i++ )
716 {
717 if ( i > 0 )
718 fprintf ( OUT, " " );
719 string libpath = libraries[i].c_str();
720 libpath = libpath.erase (0, libpath.find_last_of ("\\") + 1 );
721 if ( libpath == "msvcrt.lib" )
722 {
723 use_msvcrt_lib = true;
724 }
725 fprintf ( OUT, "%s", libpath.c_str() );
726 }
727 fprintf ( OUT, "\"\r\n" );
728
729 fprintf ( OUT, "\t\t\t\tAdditionalLibraryDirectories=\"" );
730
731 // Add WDK libs paths, if needed
732 if (getenv ( "BASEDIR" ) != NULL &&
733 (module.type == Kernel ||
734 module.type == KernelModeDLL ||
735 module.type == KernelModeDriver ||
736 module.type == KeyboardLayout))
737 {
738 string WdkBase, CrtPath, DdkPath;
739 WdkBase = getenv ( "BASEDIR" );
740 CrtPath = WdkBase + "\\lib\\crt\\i386";
741 DdkPath = WdkBase + "\\lib\\wnet\\i386";
742
743 fprintf ( OUT, "%s;", CrtPath.c_str() );
744 fprintf ( OUT, "%s", DdkPath.c_str() );
745
746 if (libraries.size () > 0)
747 fprintf ( OUT, ";" );
748 }
749
750 // Add conventional libraries dirs
751 for (i = 0; i < libraries.size (); i++)
752 {
753 if ( i > 0 )
754 fprintf ( OUT, ";" );
755
756 string libpath = libraries[i].c_str();
757 libpath.replace (libpath.find("---"), 3, cfg.name);
758 libpath = libpath.substr (0, libpath.find_last_of ("\\") );
759 fprintf ( OUT, "%s", libpath.c_str() );
760 }
761
762 fprintf ( OUT, "\"\r\n" );
763
764 fprintf ( OUT, "\t\t\t\tOutputFile=\"$(OutDir)/%s%s\"\r\n", module.name.c_str(), module_type.c_str() );
765 fprintf ( OUT, "\t\t\t\tLinkIncremental=\"%d\"\r\n", debug ? 2 : 1 );
766 fprintf ( OUT, "\t\t\t\tGenerateDebugInformation=\"%s\"\r\n", speed ? "FALSE" : "TRUE" );
767 fprintf ( OUT, "\t\t\t\tLinkTimeCodeGeneration=\"%d\"\r\n", release? 0 : 0); // whole program optimization
768
769 if ( debug )
770 fprintf ( OUT, "\t\t\t\tProgramDatabaseFile=\"$(OutDir)/%s.pdb\"\r\n", module.name.c_str() );
771
772 if ( binaryType == Sys )
773 {
774 if (module.GetEntryPoint() == "0")
775 fprintf ( OUT, "\t\t\t\tAdditionalOptions=\" /noentry /ALIGN:0x20 /SECTION:INIT,D /IGNORE:4001,4037,4039,4065,4070,4078,4087,4089,4096\"\r\n" );
776 else
777 fprintf ( OUT, "\t\t\t\tAdditionalOptions=\" /ALIGN:0x20 /SECTION:INIT,D /IGNORE:4001,4037,4039,4065,4070,4078,4087,4089,4096\"\r\n" );
778 fprintf ( OUT, "\t\t\t\tIgnoreAllDefaultLibraries=\"TRUE\"\r\n" );
779 fprintf ( OUT, "\t\t\t\tGenerateManifest=\"FALSE\"\r\n" );
780 fprintf ( OUT, "\t\t\t\tSubSystem=\"%d\"\r\n", 3 );
781 fprintf ( OUT, "\t\t\t\tDriver=\"%d\"\r\n", 1 );
782 fprintf ( OUT, "\t\t\t\tEntryPointSymbol=\"%s\"\r\n", module.GetEntryPoint() == "" ? "DriverEntry" : module.GetEntryPoint().c_str ());
783 fprintf ( OUT, "\t\t\t\tBaseAddress=\"%s\"\r\n", baseaddr == "" ? "0x10000" : baseaddr.c_str ());
784 }
785 else if ( binaryType == Exe )
786 {
787 if ( module.type == Kernel )
788 {
789 fprintf ( OUT, "\t\t\t\tAdditionalOptions=\" /SECTION:INIT,D /ALIGN:0x80\"\r\n" );
790 fprintf ( OUT, "\t\t\t\tIgnoreAllDefaultLibraries=\"TRUE\"\r\n" );
791 fprintf ( OUT, "\t\t\t\tGenerateManifest=\"FALSE\"\r\n" );
792 fprintf ( OUT, "\t\t\t\tSubSystem=\"%d\"\r\n", 3 );
793 fprintf ( OUT, "\t\t\t\tDriver=\"%d\"\r\n", 1 );
794 fprintf ( OUT, "\t\t\t\tEntryPointSymbol=\"KiSystemStartup\"\r\n" );
795 fprintf ( OUT, "\t\t\t\tBaseAddress=\"%s\"\r\n", baseaddr.c_str ());
796 }
797 else if ( module.type == NativeCUI )
798 {
799 fprintf ( OUT, "\t\t\t\tAdditionalOptions=\" /ALIGN:0x20\"\r\n" );
800 fprintf ( OUT, "\t\t\t\tSubSystem=\"%d\"\r\n", 1 );
801 fprintf ( OUT, "\t\t\t\tGenerateManifest=\"FALSE\"\r\n" );
802 fprintf ( OUT, "\t\t\t\tIgnoreAllDefaultLibraries=\"TRUE\"\r\n" );
803 fprintf ( OUT, "\t\t\t\tEntryPointSymbol=\"NtProcessStartup\"\r\n" );
804 fprintf ( OUT, "\t\t\t\tBaseAddress=\"%s\"\r\n", baseaddr.c_str ());
805 }
806 else if ( module.type == Win32CUI || module.type == Win32GUI || module.type == Win32SCR)
807 {
808 if ( use_msvcrt_lib )
809 {
810 fprintf ( OUT, "\t\t\t\tIgnoreAllDefaultLibraries=\"TRUE\"\r\n" );
811 }
812 fprintf ( OUT, "\t\t\t\tSubSystem=\"%d\"\r\n", 2 );
813 }
814 }
815 else if ( binaryType == Dll )
816 {
817 if (module.GetEntryPoint() == "0")
818 fprintf ( OUT, "\t\t\t\tEntryPointSymbol=\"\"\r\n" );
819 else
820 {
821 // get rid of DllMain@12 because MSVC needs to link to _DllMainCRTStartup@12
822 // when using CRT
823 if (module.GetEntryPoint() == "DllMain@12")
824 fprintf ( OUT, "\t\t\t\tEntryPointSymbol=\"\"\r\n" );
825 else
826 fprintf ( OUT, "\t\t\t\tEntryPointSymbol=\"%s\"\r\n", module.GetEntryPoint().c_str ());
827 }
828 fprintf ( OUT, "\t\t\t\tBaseAddress=\"%s\"\r\n", baseaddr == "" ? "0x40000" : baseaddr.c_str ());
829 if ( use_msvcrt_lib )
830 {
831 fprintf ( OUT, "\t\t\t\tIgnoreAllDefaultLibraries=\"TRUE\"\r\n" );
832 }
833 }
834 fprintf ( OUT, "\t\t\t\tTargetMachine=\"%d\"/>\r\n", 1 );
835 }
836
837 fprintf ( OUT, "\t\t\t<Tool\r\n" );
838 fprintf ( OUT, "\t\t\t\tName=\"VCResourceCompilerTool\"\r\n" );
839 fprintf ( OUT, "\t\t\t\tAdditionalIncludeDirectories=\"" );
840 multiple_includes = false;
841 fprintf ( OUT, "./;" );
842 for ( i = 0; i < includes.size(); i++ )
843 {
844 const std::string& include = includes[i];
845 if ( strcmp ( include.c_str(), "." ) )
846 {
847 if ( multiple_includes )
848 fprintf ( OUT, ";" );
849 fprintf ( OUT, "%s", include.c_str() );
850 multiple_includes = true;
851 }
852 }
853 if ( cfg.headers == ReactOSHeaders )
854 {
855 for ( i = 0; i < includes_ros.size(); i++ )
856 {
857 const std::string& include = includes_ros[i];
858 if ( multiple_includes )
859 fprintf ( OUT, ";" );
860 fprintf ( OUT, "%s", include.c_str() );
861 multiple_includes = true;
862 }
863 }
864 fprintf ( OUT, "\"/>\r\n " );
865
866 fprintf ( OUT, "\t\t\t<Tool\r\n" );
867 fprintf ( OUT, "\t\t\t\tName=\"VCMIDLTool\"/>\r\n" );
868 if (configuration.VSProjectVersion == "8.00")
869 {
870 fprintf ( OUT, "\t\t\t<Tool\r\n" );
871 fprintf ( OUT, "\t\t\t\tName=\"VCManifestTool\"\r\n" );
872 fprintf ( OUT, "\t\t\t\tEmbedManifest=\"false\"/>\r\n" );
873 }
874 fprintf ( OUT, "\t\t\t<Tool\r\n" );
875 fprintf ( OUT, "\t\t\t\tName=\"VCPostBuildEventTool\"/>\r\n" );
876 fprintf ( OUT, "\t\t\t<Tool\r\n" );
877 fprintf ( OUT, "\t\t\t\tName=\"VCPreBuildEventTool\"/>\r\n" );
878 fprintf ( OUT, "\t\t\t<Tool\r\n" );
879 fprintf ( OUT, "\t\t\t\tName=\"VCPreLinkEventTool\"/>\r\n" );
880 fprintf ( OUT, "\t\t\t<Tool\r\n" );
881 fprintf ( OUT, "\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"/>\r\n" );
882 fprintf ( OUT, "\t\t\t<Tool\r\n" );
883 fprintf ( OUT, "\t\t\t\tName=\"VCWebDeploymentTool\"/>\r\n" );
884 fprintf ( OUT, "\t\t</Configuration>\r\n" );
885 }
886
887
888 void
889 VCProjMaker::_generate_makefile_configuration( const Module& module, const MSVCConfiguration& cfg )
890 {
891 string path_basedir = module.GetPathToBaseDir ();
892 string intenv = Environment::GetIntermediatePath ();
893 string outenv = Environment::GetOutputPath ();
894
895 string outdir;
896 string intdir;
897 string vcdir;
898
899
900 if ( intenv == "obj-i386" )
901 intdir = path_basedir + "obj-i386"; /* append relative dir from project dir */
902 else
903 intdir = intenv;
904
905 if ( outenv == "output-i386" )
906 outdir = path_basedir + "output-i386";
907 else
908 outdir = outenv;
909
910 if ( configuration.UseVSVersionInPath )
911 {
912 vcdir = DEF_SSEP + _get_vc_dir();
913 }
914
915 fprintf ( OUT, "\t\t<Configuration\r\n" );
916 fprintf ( OUT, "\t\t\tName=\"%s|Win32\"\r\n", cfg.name.c_str() );
917
918 if ( configuration.UseConfigurationInPath )
919 {
920 fprintf ( OUT, "\t\t\tOutputDirectory=\"%s\\%s\\%s\"\r\n", outdir.c_str (), module.output->relative_path.c_str (), cfg.name.c_str() );
921 fprintf ( OUT, "\t\t\tIntermediateDirectory=\"%s\\%s\\%s\"\r\n", intdir.c_str (), module.output->relative_path.c_str (), cfg.name.c_str() );
922 }
923 else
924 {
925 fprintf ( OUT, "\t\t\tOutputDirectory=\"%s\\%s\"\r\n", outdir.c_str (), module.output->relative_path.c_str () );
926 fprintf ( OUT, "\t\t\tIntermediateDirectory=\"%s\\%s\"\r\n", intdir.c_str (), module.output->relative_path.c_str () );
927 }
928
929 fprintf ( OUT, "\t\t\tConfigurationType=\"0\"\r\n");
930 fprintf ( OUT, "\t\t\t>\r\n" );
931
932 fprintf ( OUT, "\t\t\t<Tool\r\n" );
933
934 fprintf ( OUT, "\t\t\t\tName=\"VCNMakeTool\"\r\n" );
935 fprintf ( OUT, "\t\t\t\tBuildCommandLine=\"%srosbuild.bat build %s\"\r\n", path_basedir.c_str (), module.name.c_str ());
936 fprintf ( OUT, "\t\t\t\tReBuildCommandLine=\"%srosbuild.bat rebuild %s\"\r\n", path_basedir.c_str (), module.name.c_str ());
937 fprintf ( OUT, "\t\t\t\tCleanCommandLine=\"%srosbuild.bat clean %s\"\r\n", path_basedir.c_str (), module.name.c_str ());
938 fprintf ( OUT, "\t\t\t\tOutput=\"\"\r\n");
939 fprintf ( OUT, "\t\t\t\tPreprocessorDefinitions=\"\"\r\n");
940 fprintf ( OUT, "\t\t\t\tIncludeSearchPath=\"\"\r\n");
941 fprintf ( OUT, "\t\t\t\tForcedIncludes=\"\"\r\n");
942 fprintf ( OUT, "\t\t\t\tAssemblySearchPath=\"\"\r\n");
943 fprintf ( OUT, "\t\t\t\tForcedUsingAssemblies=\"\"\r\n");
944 fprintf ( OUT, "\t\t\t\tCompileAsManaged=\"\"\r\n");
945
946 fprintf ( OUT, "\t\t\t/>\r\n" );
947 fprintf ( OUT, "\t\t</Configuration>\r\n" );
948 }