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