1package MSBuildProject;
2
3#
4# Package that encapsulates a MSBuild project file (Visual C++ 2010 or greater)
5#
6# src/tools/msvc/MSBuildProject.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} = '.vcxproj';
23	$self->{ToolsVersion}      = '4.0';
24
25	return $self;
26}
27
28sub WriteHeader
29{
30	my ($self, $f) = @_;
31
32	print $f <<EOF;
33<?xml version="1.0" encoding="Windows-1252"?>
34<Project DefaultTargets="Build" ToolsVersion="$self->{ToolsVersion}" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
35  <ItemGroup Label="ProjectConfigurations">
36EOF
37	$self->WriteConfigurationHeader($f, 'Debug');
38	$self->WriteConfigurationHeader($f, 'Release');
39	print $f <<EOF;
40  </ItemGroup>
41  <PropertyGroup Label="Globals">
42    <ProjectGuid>$self->{guid}</ProjectGuid>
43EOF
44	# Check whether WindowsSDKVersion env variable is present.
45	# Add WindowsTargetPlatformVersion node if so.
46	my $sdkVersion = $ENV{'WindowsSDKVersion'};
47	if (defined($sdkVersion))
48	{
49		# remove trailing backslash if necessary.
50		$sdkVersion =~ s/\\$//;
51		print $f <<EOF
52    <WindowsTargetPlatformVersion>$sdkVersion</WindowsTargetPlatformVersion>
53EOF
54	}
55	print $f <<EOF;
56  </PropertyGroup>
57  <Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.Default.props" />
58EOF
59	$self->WriteConfigurationPropertyGroup($f, 'Release',
60		{ wholeopt => 'false' });
61	$self->WriteConfigurationPropertyGroup($f, 'Debug',
62		{ wholeopt => 'false' });
63	print $f <<EOF;
64  <Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.props" />
65  <ImportGroup Label="ExtensionSettings">
66  </ImportGroup>
67EOF
68	$self->WritePropertySheetsPropertyGroup($f, 'Release');
69	$self->WritePropertySheetsPropertyGroup($f, 'Debug');
70	print $f <<EOF;
71  <PropertyGroup Label="UserMacros" />
72  <PropertyGroup>
73    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
74EOF
75	$self->WriteAdditionalProperties($f, 'Debug');
76	$self->WriteAdditionalProperties($f, 'Release');
77	print $f <<EOF;
78  </PropertyGroup>
79EOF
80
81	$self->WriteItemDefinitionGroup(
82		$f, 'Debug',
83		{
84			defs    => "_DEBUG;DEBUG=1",
85			opt     => 'Disabled',
86			strpool => 'false',
87			runtime => 'MultiThreadedDebugDLL'
88		});
89	$self->WriteItemDefinitionGroup(
90		$f,
91		'Release',
92		{
93			defs    => "",
94			opt     => 'Full',
95			strpool => 'true',
96			runtime => 'MultiThreadedDLL'
97		});
98	return;
99}
100
101sub AddDefine
102{
103	my ($self, $def) = @_;
104
105	$self->{defines} .= $def . ';';
106	return;
107}
108
109sub WriteReferences
110{
111	my ($self, $f) = @_;
112
113	my @references = @{ $self->{references} };
114
115	if (scalar(@references))
116	{
117		print $f <<EOF;
118  <ItemGroup>
119EOF
120		foreach my $ref (@references)
121		{
122			print $f <<EOF;
123    <ProjectReference Include="$ref->{name}$ref->{filenameExtension}">
124      <Project>$ref->{guid}</Project>
125    </ProjectReference>
126EOF
127		}
128		print $f <<EOF;
129  </ItemGroup>
130EOF
131	}
132	return;
133}
134
135sub WriteFiles
136{
137	my ($self, $f) = @_;
138	print $f <<EOF;
139  <ItemGroup>
140EOF
141	my @grammarFiles  = ();
142	my @resourceFiles = ();
143	my %uniquefiles;
144	foreach my $fileNameWithPath (sort keys %{ $self->{files} })
145	{
146		confess "Bad format filename '$fileNameWithPath'\n"
147		  unless ($fileNameWithPath =~ m!^(.*)/([^/]+)\.(c|cpp|y|l|rc)$!);
148		my $dir      = $1;
149		my $fileName = $2;
150		if ($fileNameWithPath =~ /\.y$/ or $fileNameWithPath =~ /\.l$/)
151		{
152			push @grammarFiles, $fileNameWithPath;
153		}
154		elsif ($fileNameWithPath =~ /\.rc$/)
155		{
156			push @resourceFiles, $fileNameWithPath;
157		}
158		elsif (defined($uniquefiles{$fileName}))
159		{
160
161			# File already exists, so fake a new name
162			my $obj = $dir;
163			$obj =~ s!/!_!g;
164
165			print $f <<EOF;
166    <ClCompile Include="$fileNameWithPath">
167      <ObjectFileName Condition="'\$(Configuration)|\$(Platform)'=='Debug|$self->{platform}'">.\\debug\\$self->{name}\\${obj}_$fileName.obj</ObjectFileName>
168      <ObjectFileName Condition="'\$(Configuration)|\$(Platform)'=='Release|$self->{platform}'">.\\release\\$self->{name}\\${obj}_$fileName.obj</ObjectFileName>
169    </ClCompile>
170EOF
171		}
172		else
173		{
174			$uniquefiles{$fileName} = 1;
175			print $f <<EOF;
176    <ClCompile Include="$fileNameWithPath" />
177EOF
178		}
179
180	}
181	print $f <<EOF;
182  </ItemGroup>
183EOF
184	if (scalar(@grammarFiles))
185	{
186		print $f <<EOF;
187  <ItemGroup>
188EOF
189		foreach my $grammarFile (@grammarFiles)
190		{
191			(my $outputFile = $grammarFile) =~ s/\.(y|l)$/.c/;
192			if ($grammarFile =~ /\.y$/)
193			{
194				$outputFile =~
195				  s{^src\\pl\\plpgsql\\src\\gram.c$}{src\\pl\\plpgsql\\src\\pl_gram.c};
196				print $f <<EOF;
197    <CustomBuild Include="$grammarFile">
198      <Message Condition="'\$(Configuration)|\$(Platform)'=='Debug|$self->{platform}'">Running bison on $grammarFile</Message>
199      <Command Condition="'\$(Configuration)|\$(Platform)'=='Debug|$self->{platform}'">perl "src\\tools\\msvc\\pgbison.pl" "$grammarFile"</Command>
200      <AdditionalInputs Condition="'\$(Configuration)|\$(Platform)'=='Debug|$self->{platform}'">%(AdditionalInputs)</AdditionalInputs>
201      <Outputs Condition="'\$(Configuration)|\$(Platform)'=='Debug|$self->{platform}'">$outputFile;%(Outputs)</Outputs>
202      <Message Condition="'\$(Configuration)|\$(Platform)'=='Release|$self->{platform}'">Running bison on $grammarFile</Message>
203      <Command Condition="'\$(Configuration)|\$(Platform)'=='Release|$self->{platform}'">perl "src\\tools\\msvc\\pgbison.pl" "$grammarFile"</Command>
204      <AdditionalInputs Condition="'\$(Configuration)|\$(Platform)'=='Release|$self->{platform}'">%(AdditionalInputs)</AdditionalInputs>
205      <Outputs Condition="'\$(Configuration)|\$(Platform)'=='Release|$self->{platform}'">$outputFile;%(Outputs)</Outputs>
206    </CustomBuild>
207EOF
208			}
209			else    #if ($grammarFile =~ /\.l$/)
210			{
211				print $f <<EOF;
212    <CustomBuild Include="$grammarFile">
213      <Message Condition="'\$(Configuration)|\$(Platform)'=='Debug|$self->{platform}'">Running flex on $grammarFile</Message>
214      <Command Condition="'\$(Configuration)|\$(Platform)'=='Debug|$self->{platform}'">perl "src\\tools\\msvc\\pgflex.pl" "$grammarFile"</Command>
215      <AdditionalInputs Condition="'\$(Configuration)|\$(Platform)'=='Debug|$self->{platform}'">%(AdditionalInputs)</AdditionalInputs>
216      <Outputs Condition="'\$(Configuration)|\$(Platform)'=='Debug|$self->{platform}'">$outputFile;%(Outputs)</Outputs>
217      <Message Condition="'\$(Configuration)|\$(Platform)'=='Release|$self->{platform}'">Running flex on $grammarFile</Message>
218      <Command Condition="'\$(Configuration)|\$(Platform)'=='Release|$self->{platform}'">perl "src\\tools\\msvc\\pgflex.pl" "$grammarFile"</Command>
219      <AdditionalInputs Condition="'\$(Configuration)|\$(Platform)'=='Release|$self->{platform}'">%(AdditionalInputs)</AdditionalInputs>
220      <Outputs Condition="'\$(Configuration)|\$(Platform)'=='Release|$self->{platform}'">$outputFile;%(Outputs)</Outputs>
221    </CustomBuild>
222EOF
223			}
224		}
225		print $f <<EOF;
226  </ItemGroup>
227EOF
228	}
229	if (scalar(@resourceFiles))
230	{
231		print $f <<EOF;
232  <ItemGroup>
233EOF
234		foreach my $rcFile (@resourceFiles)
235		{
236			print $f <<EOF;
237    <ResourceCompile Include="$rcFile" />
238EOF
239		}
240		print $f <<EOF;
241  </ItemGroup>
242EOF
243	}
244	return;
245}
246
247sub WriteConfigurationHeader
248{
249	my ($self, $f, $cfgname) = @_;
250	print $f <<EOF;
251    <ProjectConfiguration Include="$cfgname|$self->{platform}">
252      <Configuration>$cfgname</Configuration>
253      <Platform>$self->{platform}</Platform>
254    </ProjectConfiguration>
255EOF
256	return;
257}
258
259sub WriteConfigurationPropertyGroup
260{
261	my ($self, $f, $cfgname, $p) = @_;
262	my $cfgtype =
263	  ($self->{type} eq "exe")
264	  ? 'Application'
265	  : ($self->{type} eq "dll" ? 'DynamicLibrary' : 'StaticLibrary');
266
267	print $f <<EOF;
268  <PropertyGroup Condition="'\$(Configuration)|\$(Platform)'=='$cfgname|$self->{platform}'" Label="Configuration">
269    <ConfigurationType>$cfgtype</ConfigurationType>
270    <UseOfMfc>false</UseOfMfc>
271    <CharacterSet>MultiByte</CharacterSet>
272    <WholeProgramOptimization>$p->{wholeopt}</WholeProgramOptimization>
273  </PropertyGroup>
274EOF
275	return;
276}
277
278sub WritePropertySheetsPropertyGroup
279{
280	my ($self, $f, $cfgname) = @_;
281	print $f <<EOF;
282  <ImportGroup Condition="'\$(Configuration)|\$(Platform)'=='$cfgname|$self->{platform}'" Label="PropertySheets">
283    <Import Project="\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props" Condition="exists('\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props')" Label="LocalAppDataPlatform" />
284  </ImportGroup>
285EOF
286	return;
287}
288
289sub WriteAdditionalProperties
290{
291	my ($self, $f, $cfgname) = @_;
292	print $f <<EOF;
293    <OutDir Condition="'\$(Configuration)|\$(Platform)'=='$cfgname|$self->{platform}'">.\\$cfgname\\$self->{name}\\</OutDir>
294    <IntDir Condition="'\$(Configuration)|\$(Platform)'=='$cfgname|$self->{platform}'">.\\$cfgname\\$self->{name}\\</IntDir>
295    <LinkIncremental Condition="'\$(Configuration)|\$(Platform)'=='$cfgname|$self->{platform}'">false</LinkIncremental>
296EOF
297	return;
298}
299
300sub WriteItemDefinitionGroup
301{
302	my ($self, $f, $cfgname, $p) = @_;
303	my $cfgtype =
304	  ($self->{type} eq "exe")
305	  ? 'Application'
306	  : ($self->{type} eq "dll" ? 'DynamicLibrary' : 'StaticLibrary');
307	my $libs = $self->GetAdditionalLinkerDependencies($cfgname, ';');
308
309	my $targetmachine =
310	  $self->{platform} eq 'Win32' ? 'MachineX86' : 'MachineX64';
311
312	my $includes = $self->{includes};
313	unless ($includes eq '' or $includes =~ /;$/)
314	{
315		$includes .= ';';
316	}
317	print $f <<EOF;
318  <ItemDefinitionGroup Condition="'\$(Configuration)|\$(Platform)'=='$cfgname|$self->{platform}'">
319    <ClCompile>
320      <Optimization>$p->{opt}</Optimization>
321      <AdditionalIncludeDirectories>$self->{prefixincludes}src/include;src/include/port/win32;src/include/port/win32_msvc;$includes\%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
322      <PreprocessorDefinitions>WIN32;_WINDOWS;__WINDOWS__;__WIN32__;EXEC_BACKEND;WIN32_STACK_RLIMIT=4194304;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE$self->{defines}$p->{defs}\%(PreprocessorDefinitions)</PreprocessorDefinitions>
323      <StringPooling>$p->{strpool}</StringPooling>
324      <RuntimeLibrary>$p->{runtime}</RuntimeLibrary>
325      <DisableSpecificWarnings>$self->{disablewarnings};\%(DisableSpecificWarnings)</DisableSpecificWarnings>
326      <AdditionalOptions>/MP \%(AdditionalOptions)</AdditionalOptions>
327      <AssemblerOutput>
328      </AssemblerOutput>
329      <AssemblerListingLocation>.\\$cfgname\\$self->{name}\\</AssemblerListingLocation>
330      <ObjectFileName>.\\$cfgname\\$self->{name}\\</ObjectFileName>
331      <ProgramDataBaseFileName>.\\$cfgname\\$self->{name}\\</ProgramDataBaseFileName>
332      <BrowseInformation>false</BrowseInformation>
333      <WarningLevel>Level3</WarningLevel>
334      <SuppressStartupBanner>true</SuppressStartupBanner>
335      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
336      <CompileAs>Default</CompileAs>
337    </ClCompile>
338    <Link>
339      <OutputFile>.\\$cfgname\\$self->{name}\\$self->{name}.$self->{type}</OutputFile>
340      <AdditionalDependencies>$libs;\%(AdditionalDependencies)</AdditionalDependencies>
341      <SuppressStartupBanner>true</SuppressStartupBanner>
342      <AdditionalLibraryDirectories>\%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
343      <IgnoreSpecificDefaultLibraries>libc;\%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
344      <StackReserveSize>4194304</StackReserveSize>
345      <GenerateDebugInformation>true</GenerateDebugInformation>
346      <ProgramDatabaseFile>.\\$cfgname\\$self->{name}\\$self->{name}.pdb</ProgramDatabaseFile>
347      <GenerateMapFile>false</GenerateMapFile>
348      <MapFileName>.\\$cfgname\\$self->{name}\\$self->{name}.map</MapFileName>
349      <RandomizedBaseAddress>false</RandomizedBaseAddress>
350      <!-- Permit links to MinGW-built, 32-bit DLLs (default before VS2012). -->
351      <ImageHasSafeExceptionHandlers/>
352      <SubSystem>Console</SubSystem>
353      <TargetMachine>$targetmachine</TargetMachine>
354EOF
355	if ($self->{disablelinkerwarnings})
356	{
357		print $f
358		  "      <AdditionalOptions>/ignore:$self->{disablelinkerwarnings} \%(AdditionalOptions)</AdditionalOptions>\n";
359	}
360	if ($self->{implib})
361	{
362		my $l = $self->{implib};
363		$l =~ s/__CFGNAME__/$cfgname/g;
364		print $f "      <ImportLibrary>$l</ImportLibrary>\n";
365	}
366	if ($self->{def})
367	{
368		my $d = $self->{def};
369		$d =~ s/__CFGNAME__/$cfgname/g;
370		print $f "      <ModuleDefinitionFile>$d</ModuleDefinitionFile>\n";
371	}
372	print $f <<EOF;
373    </Link>
374    <ResourceCompile>
375      <AdditionalIncludeDirectories>src\\include;\%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
376    </ResourceCompile>
377EOF
378	if ($self->{builddef})
379	{
380		print $f <<EOF;
381    <PreLinkEvent>
382      <Message>Generate DEF file</Message>
383      <Command>perl src\\tools\\msvc\\gendef.pl $cfgname\\$self->{name} $self->{platform}</Command>
384    </PreLinkEvent>
385EOF
386	}
387	print $f <<EOF;
388  </ItemDefinitionGroup>
389EOF
390	return;
391}
392
393sub Footer
394{
395	my ($self, $f) = @_;
396	$self->WriteReferences($f);
397
398	print $f <<EOF;
399  <Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.targets" />
400  <ImportGroup Label="ExtensionTargets">
401  </ImportGroup>
402</Project>
403EOF
404	return;
405}
406
407package VC2010Project;
408
409#
410# Package that encapsulates a Visual C++ 2010 project file
411#
412
413use strict;
414use warnings;
415use base qw(MSBuildProject);
416
417no warnings qw(redefine);    ## no critic
418
419sub new
420{
421	my $classname = shift;
422	my $self      = $classname->SUPER::_new(@_);
423	bless($self, $classname);
424
425	$self->{vcver} = '10.00';
426
427	return $self;
428}
429
430package VC2012Project;
431
432#
433# Package that encapsulates a Visual C++ 2012 project file
434#
435
436use strict;
437use warnings;
438use base qw(MSBuildProject);
439
440no warnings qw(redefine);    ## no critic
441
442sub new
443{
444	my $classname = shift;
445	my $self      = $classname->SUPER::_new(@_);
446	bless($self, $classname);
447
448	$self->{vcver}           = '11.00';
449	$self->{PlatformToolset} = 'v110';
450
451	return $self;
452}
453
454# This override adds the <PlatformToolset> element
455# to the PropertyGroup labeled "Configuration"
456sub WriteConfigurationPropertyGroup
457{
458	my ($self, $f, $cfgname, $p) = @_;
459	my $cfgtype =
460	  ($self->{type} eq "exe")
461	  ? 'Application'
462	  : ($self->{type} eq "dll" ? 'DynamicLibrary' : 'StaticLibrary');
463
464	print $f <<EOF;
465  <PropertyGroup Condition="'\$(Configuration)|\$(Platform)'=='$cfgname|$self->{platform}'" Label="Configuration">
466    <ConfigurationType>$cfgtype</ConfigurationType>
467    <UseOfMfc>false</UseOfMfc>
468    <CharacterSet>MultiByte</CharacterSet>
469    <WholeProgramOptimization>$p->{wholeopt}</WholeProgramOptimization>
470    <PlatformToolset>$self->{PlatformToolset}</PlatformToolset>
471  </PropertyGroup>
472EOF
473	return;
474}
475
476package VC2013Project;
477
478#
479# Package that encapsulates a Visual C++ 2013 project file
480#
481
482use strict;
483use warnings;
484use base qw(VC2012Project);
485
486no warnings qw(redefine);    ## no critic
487
488sub new
489{
490	my $classname = shift;
491	my $self      = $classname->SUPER::_new(@_);
492	bless($self, $classname);
493
494	$self->{vcver}           = '12.00';
495	$self->{PlatformToolset} = 'v120';
496	$self->{ToolsVersion}    = '12.0';
497
498	return $self;
499}
500
501package VC2015Project;
502
503#
504# Package that encapsulates a Visual C++ 2015 project file
505#
506
507use strict;
508use warnings;
509use base qw(VC2012Project);
510
511no warnings qw(redefine);    ## no critic
512
513sub new
514{
515	my $classname = shift;
516	my $self      = $classname->SUPER::_new(@_);
517	bless($self, $classname);
518
519	$self->{vcver}           = '14.00';
520	$self->{PlatformToolset} = 'v140';
521	$self->{ToolsVersion}    = '14.0';
522
523	return $self;
524}
525
526package VC2017Project;
527
528#
529# Package that encapsulates a Visual C++ 2017 project file
530#
531
532use strict;
533use warnings;
534use base qw(VC2012Project);
535
536no warnings qw(redefine);    ## no critic
537
538sub new
539{
540	my $classname = shift;
541	my $self      = $classname->SUPER::_new(@_);
542	bless($self, $classname);
543
544	$self->{vcver}           = '15.00';
545	$self->{PlatformToolset} = 'v141';
546	$self->{ToolsVersion}    = '15.0';
547
548	return $self;
549}
550
551package VC2019Project;
552
553#
554# Package that encapsulates a Visual C++ 2019 project file
555#
556
557use strict;
558use warnings;
559use base qw(VC2012Project);
560
561no warnings qw(redefine);    ## no critic
562
563sub new
564{
565	my $classname = shift;
566	my $self      = $classname->SUPER::_new(@_);
567	bless($self, $classname);
568
569	$self->{vcver}           = '16.00';
570	$self->{PlatformToolset} = 'v142';
571	$self->{ToolsVersion}    = '16.0';
572
573	return $self;
574}
575
5761;
577