1package VCBuildProject;
2
3#
4# Package that encapsulates a VCBuild (Visual C++ 2005/2008) project file
5#
6# src/tools/msvc/VCBuildProject.pm
7#
8
9use Carp;
10use strict;
11use warnings;
12use base qw(Project);
13
14no warnings qw(redefine);    ## no critic
15
16sub _new
17{
18	my $classname = shift;
19	my $self      = $classname->SUPER::_new(@_);
20	bless($self, $classname);
21
22	$self->{filenameExtension} = '.vcproj';
23
24	return $self;
25}
26
27sub WriteHeader
28{
29	my ($self, $f) = @_;
30
31	print $f <<EOF;
32<?xml version="1.0" encoding="Windows-1252"?>
33<VisualStudioProject ProjectType="Visual C++" Version="$self->{vcver}" Name="$self->{name}" ProjectGUID="$self->{guid}">
34 <Platforms><Platform Name="$self->{platform}"/></Platforms>
35 <Configurations>
36EOF
37
38	$self->WriteConfiguration(
39		$f, 'Debug',
40		{
41			defs     => "_DEBUG;DEBUG=1",
42			wholeopt => 0,
43			opt      => 0,
44			strpool  => 'false',
45			runtime  => 3
46		});
47	$self->WriteConfiguration(
48		$f,
49		'Release',
50		{
51			defs     => "",
52			wholeopt => 0,
53			opt      => 3,
54			strpool  => 'true',
55			runtime  => 2
56		});
57	print $f <<EOF;
58 </Configurations>
59EOF
60	$self->WriteReferences($f);
61	return;
62}
63
64sub WriteFiles
65{
66	my ($self, $f) = @_;
67	print $f <<EOF;
68 <Files>
69EOF
70	my @dirstack = ();
71	my %uniquefiles;
72	foreach my $fileNameWithPath (sort keys %{ $self->{files} })
73	{
74		confess "Bad format filename '$fileNameWithPath'\n"
75		  unless ($fileNameWithPath =~ m!^(.*)/([^/]+)\.(c|cpp|y|l|rc)$!);
76		my $dir  = $1;
77		my $file = $2;
78
79		# Walk backwards down the directory stack and close any dirs
80		# we're done with.
81		while ($#dirstack >= 0)
82		{
83			if (join('/', @dirstack) eq
84				substr($dir, 0, length(join('/', @dirstack))))
85			{
86				last if (length($dir) == length(join('/', @dirstack)));
87				last
88				  if (substr($dir, length(join('/', @dirstack)), 1) eq '/');
89			}
90			print $f ' ' x $#dirstack . "  </Filter>\n";
91			pop @dirstack;
92		}
93
94		# Now walk forwards and create whatever directories are needed
95		while (join('/', @dirstack) ne $dir)
96		{
97			my $left = substr($dir, length(join('/', @dirstack)));
98			$left =~ s/^\///;
99			my @pieces = split /\//, $left;
100			push @dirstack, $pieces[0];
101			print $f ' ' x $#dirstack
102			  . "  <Filter Name=\"$pieces[0]\" Filter=\"\">\n";
103		}
104
105		# VC builds do not like file paths with forward slashes.
106		my $fileNameWithPathFormatted = $fileNameWithPath;
107		$fileNameWithPathFormatted =~ s/\//\\/g;
108
109		print $f ' ' x $#dirstack
110		  . "   <File RelativePath=\"$fileNameWithPathFormatted\"";
111		if ($fileNameWithPath =~ /\.y$/)
112		{
113			my $of = $fileNameWithPath;
114			$of =~ s/\.y$/.c/;
115			$of =~
116			  s{^src/pl/plpgsql/src/gram.c$}{src/pl/plpgsql/src/pl_gram.c};
117			print $f '>'
118			  . $self->GenerateCustomTool(
119				'Running bison on ' . $fileNameWithPath,
120				"perl src/tools/msvc/pgbison.pl $fileNameWithPath", $of)
121			  . '</File>' . "\n";
122		}
123		elsif ($fileNameWithPath =~ /\.l$/)
124		{
125			my $of = $fileNameWithPath;
126			$of =~ s/\.l$/.c/;
127			print $f '>'
128			  . $self->GenerateCustomTool(
129				'Running flex on ' . $fileNameWithPath,
130				"perl src/tools/msvc/pgflex.pl $fileNameWithPath", $of)
131			  . '</File>' . "\n";
132		}
133		elsif (defined($uniquefiles{$file}))
134		{
135
136			# File already exists, so fake a new name
137			my $obj = $dir;
138			$obj =~ s!/!_!g;
139			print $f
140			  "><FileConfiguration Name=\"Debug|$self->{platform}\"><Tool Name=\"VCCLCompilerTool\" ObjectFile=\".\\debug\\$self->{name}\\$obj"
141			  . "_$file.obj\" /></FileConfiguration><FileConfiguration Name=\"Release|$self->{platform}\"><Tool Name=\"VCCLCompilerTool\" ObjectFile=\".\\release\\$self->{name}\\$obj"
142			  . "_$file.obj\" /></FileConfiguration></File>\n";
143		}
144		else
145		{
146			$uniquefiles{$file} = 1;
147			print $f " />\n";
148		}
149	}
150	while ($#dirstack >= 0)
151	{
152		print $f ' ' x $#dirstack . "  </Filter>\n";
153		pop @dirstack;
154	}
155	print $f <<EOF;
156 </Files>
157EOF
158	return;
159}
160
161sub Footer
162{
163	my ($self, $f) = @_;
164
165	print $f <<EOF;
166 <Globals/>
167</VisualStudioProject>
168EOF
169	return;
170}
171
172sub WriteConfiguration
173{
174	my ($self, $f, $cfgname, $p) = @_;
175	my $cfgtype =
176	  ($self->{type} eq "exe") ? 1 : ($self->{type} eq "dll" ? 2 : 4);
177	my $libs = $self->GetAdditionalLinkerDependencies($cfgname, ' ');
178
179	my $targetmachine = $self->{platform} eq 'Win32' ? 1 : 17;
180
181	print $f <<EOF;
182  <Configuration Name="$cfgname|$self->{platform}" OutputDirectory=".\\$cfgname\\$self->{name}" IntermediateDirectory=".\\$cfgname\\$self->{name}"
183	ConfigurationType="$cfgtype" UseOfMFC="0" ATLMinimizesCRunTimeLibraryUsage="FALSE" CharacterSet="2" WholeProgramOptimization="$p->{wholeopt}">
184	<Tool Name="VCCLCompilerTool" Optimization="$p->{opt}"
185		AdditionalIncludeDirectories="$self->{prefixincludes}src/include;src/include/port/win32;src/include/port/win32_msvc;$self->{includes}"
186		PreprocessorDefinitions="WIN32;_WINDOWS;__WINDOWS__;__WIN32__;EXEC_BACKEND;WIN32_STACK_RLIMIT=4194304;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE$self->{defines}$p->{defs}"
187		StringPooling="$p->{strpool}"
188		RuntimeLibrary="$p->{runtime}" DisableSpecificWarnings="$self->{disablewarnings}"
189		AdditionalOptions="/MP"
190EOF
191	print $f <<EOF;
192		AssemblerOutput="0" AssemblerListingLocation=".\\$cfgname\\$self->{name}\\" ObjectFile=".\\$cfgname\\$self->{name}\\"
193		ProgramDataBaseFileName=".\\$cfgname\\$self->{name}\\" BrowseInformation="0"
194		WarningLevel="3" SuppressStartupBanner="TRUE" DebugInformationFormat="3" CompileAs="0"/>
195	<Tool Name="VCLinkerTool" OutputFile=".\\$cfgname\\$self->{name}\\$self->{name}.$self->{type}"
196		AdditionalDependencies="$libs"
197		LinkIncremental="0" SuppressStartupBanner="TRUE" AdditionalLibraryDirectories="" IgnoreDefaultLibraryNames="libc"
198		StackReserveSize="4194304" DisableSpecificWarnings="$self->{disablewarnings}"
199		GenerateDebugInformation="TRUE" ProgramDatabaseFile=".\\$cfgname\\$self->{name}\\$self->{name}.pdb"
200		GenerateMapFile="FALSE" MapFileName=".\\$cfgname\\$self->{name}\\$self->{name}.map"
201		RandomizedBaseAddress="FALSE"
202		SubSystem="1" TargetMachine="$targetmachine"
203EOF
204	if ($self->{disablelinkerwarnings})
205	{
206		print $f
207		  "\t\tAdditionalOptions=\"/ignore:$self->{disablelinkerwarnings}\"\n";
208	}
209	if ($self->{implib})
210	{
211		my $l = $self->{implib};
212		$l =~ s/__CFGNAME__/$cfgname/g;
213		print $f "\t\tImportLibrary=\"$l\"\n";
214	}
215	if ($self->{def})
216	{
217		my $d = $self->{def};
218		$d =~ s/__CFGNAME__/$cfgname/g;
219		print $f "\t\tModuleDefinitionFile=\"$d\"\n";
220	}
221
222	print $f "\t/>\n";
223	print $f
224	  "\t<Tool Name=\"VCLibrarianTool\" OutputFile=\".\\$cfgname\\$self->{name}\\$self->{name}.lib\" IgnoreDefaultLibraryNames=\"libc\" />\n";
225	print $f
226	  "\t<Tool Name=\"VCResourceCompilerTool\" AdditionalIncludeDirectories=\"src\\include\" />\n";
227	if ($self->{builddef})
228	{
229		print $f
230		  "\t<Tool Name=\"VCPreLinkEventTool\" Description=\"Generate DEF file\" CommandLine=\"perl src\\tools\\msvc\\gendef.pl $cfgname\\$self->{name} $self->{platform}\" />\n";
231	}
232	print $f <<EOF;
233  </Configuration>
234EOF
235	return;
236}
237
238sub WriteReferences
239{
240	my ($self, $f) = @_;
241	print $f " <References>\n";
242	foreach my $ref (@{ $self->{references} })
243	{
244		print $f
245		  "  <ProjectReference ReferencedProjectIdentifier=\"$ref->{guid}\" Name=\"$ref->{name}\" />\n";
246	}
247	print $f " </References>\n";
248	return;
249}
250
251sub GenerateCustomTool
252{
253	my ($self, $desc, $tool, $output, $cfg) = @_;
254	if (!defined($cfg))
255	{
256		return $self->GenerateCustomTool($desc, $tool, $output, 'Debug')
257		  . $self->GenerateCustomTool($desc, $tool, $output, 'Release');
258	}
259	return
260	  "<FileConfiguration Name=\"$cfg|$self->{platform}\"><Tool Name=\"VCCustomBuildTool\" Description=\"$desc\" CommandLine=\"$tool\" AdditionalDependencies=\"\" Outputs=\"$output\" /></FileConfiguration>";
261}
262
263package VC2005Project;
264
265#
266# Package that encapsulates a Visual C++ 2005 project file
267#
268
269use strict;
270use warnings;
271use base qw(VCBuildProject);
272
273no warnings qw(redefine);    ## no critic
274
275sub new
276{
277	my $classname = shift;
278	my $self      = $classname->SUPER::_new(@_);
279	bless($self, $classname);
280
281	$self->{vcver} = '8.00';
282
283	return $self;
284}
285
286package VC2008Project;
287
288#
289# Package that encapsulates a Visual C++ 2008 project file
290#
291
292use strict;
293use warnings;
294use base qw(VCBuildProject);
295
296no warnings qw(redefine);    ## no critic
297
298sub new
299{
300	my $classname = shift;
301	my $self      = $classname->SUPER::_new(@_);
302	bless($self, $classname);
303
304	$self->{vcver} = '9.00';
305
306	return $self;
307}
308
3091;
310