1package MSBuildProject; 2 3# 4# Package that encapsulates a MSBuild project file (Visual C++ 2013 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 <PlatformToolset>$self->{PlatformToolset}</PlatformToolset> 274 </PropertyGroup> 275EOF 276 return; 277} 278 279sub WritePropertySheetsPropertyGroup 280{ 281 my ($self, $f, $cfgname) = @_; 282 print $f <<EOF; 283 <ImportGroup Condition="'\$(Configuration)|\$(Platform)'=='$cfgname|$self->{platform}'" Label="PropertySheets"> 284 <Import Project="\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props" Condition="exists('\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props')" Label="LocalAppDataPlatform" /> 285 </ImportGroup> 286EOF 287 return; 288} 289 290sub WriteAdditionalProperties 291{ 292 my ($self, $f, $cfgname) = @_; 293 print $f <<EOF; 294 <OutDir Condition="'\$(Configuration)|\$(Platform)'=='$cfgname|$self->{platform}'">.\\$cfgname\\$self->{name}\\</OutDir> 295 <IntDir Condition="'\$(Configuration)|\$(Platform)'=='$cfgname|$self->{platform}'">.\\$cfgname\\$self->{name}\\</IntDir> 296 <LinkIncremental Condition="'\$(Configuration)|\$(Platform)'=='$cfgname|$self->{platform}'">false</LinkIncremental> 297EOF 298 return; 299} 300 301sub WriteItemDefinitionGroup 302{ 303 my ($self, $f, $cfgname, $p) = @_; 304 my $cfgtype = 305 ($self->{type} eq "exe") 306 ? 'Application' 307 : ($self->{type} eq "dll" ? 'DynamicLibrary' : 'StaticLibrary'); 308 my $libs = $self->GetAdditionalLinkerDependencies($cfgname, ';'); 309 310 my $targetmachine = 311 $self->{platform} eq 'Win32' ? 'MachineX86' : 'MachineX64'; 312 313 my $includes = $self->{includes}; 314 unless ($includes eq '' or $includes =~ /;$/) 315 { 316 $includes .= ';'; 317 } 318 print $f <<EOF; 319 <ItemDefinitionGroup Condition="'\$(Configuration)|\$(Platform)'=='$cfgname|$self->{platform}'"> 320 <ClCompile> 321 <Optimization>$p->{opt}</Optimization> 322 <AdditionalIncludeDirectories>$self->{prefixincludes}src/include;src/include/port/win32;src/include/port/win32_msvc;$includes\%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 323 <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> 324 <StringPooling>$p->{strpool}</StringPooling> 325 <RuntimeLibrary>$p->{runtime}</RuntimeLibrary> 326 <DisableSpecificWarnings>$self->{disablewarnings};\%(DisableSpecificWarnings)</DisableSpecificWarnings> 327 <AdditionalOptions>/MP \%(AdditionalOptions)</AdditionalOptions> 328 <AssemblerOutput> 329 </AssemblerOutput> 330 <AssemblerListingLocation>.\\$cfgname\\$self->{name}\\</AssemblerListingLocation> 331 <ObjectFileName>.\\$cfgname\\$self->{name}\\</ObjectFileName> 332 <ProgramDataBaseFileName>.\\$cfgname\\$self->{name}\\</ProgramDataBaseFileName> 333 <BrowseInformation>false</BrowseInformation> 334 <WarningLevel>Level3</WarningLevel> 335 <SuppressStartupBanner>true</SuppressStartupBanner> 336 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 337 <CompileAs>Default</CompileAs> 338 </ClCompile> 339 <Link> 340 <OutputFile>.\\$cfgname\\$self->{name}\\$self->{name}.$self->{type}</OutputFile> 341 <AdditionalDependencies>$libs;\%(AdditionalDependencies)</AdditionalDependencies> 342 <SuppressStartupBanner>true</SuppressStartupBanner> 343 <AdditionalLibraryDirectories>\%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> 344 <IgnoreSpecificDefaultLibraries>libc;\%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries> 345 <StackReserveSize>4194304</StackReserveSize> 346 <GenerateDebugInformation>true</GenerateDebugInformation> 347 <ProgramDatabaseFile>.\\$cfgname\\$self->{name}\\$self->{name}.pdb</ProgramDatabaseFile> 348 <GenerateMapFile>false</GenerateMapFile> 349 <MapFileName>.\\$cfgname\\$self->{name}\\$self->{name}.map</MapFileName> 350 <RandomizedBaseAddress>false</RandomizedBaseAddress> 351 <!-- Permit links to MinGW-built, 32-bit DLLs (default before VS2012). --> 352 <ImageHasSafeExceptionHandlers/> 353 <SubSystem>Console</SubSystem> 354 <TargetMachine>$targetmachine</TargetMachine> 355EOF 356 if ($self->{disablelinkerwarnings}) 357 { 358 print $f 359 " <AdditionalOptions>/ignore:$self->{disablelinkerwarnings} \%(AdditionalOptions)</AdditionalOptions>\n"; 360 } 361 if ($self->{implib}) 362 { 363 my $l = $self->{implib}; 364 $l =~ s/__CFGNAME__/$cfgname/g; 365 print $f " <ImportLibrary>$l</ImportLibrary>\n"; 366 } 367 if ($self->{def}) 368 { 369 my $d = $self->{def}; 370 $d =~ s/__CFGNAME__/$cfgname/g; 371 print $f " <ModuleDefinitionFile>$d</ModuleDefinitionFile>\n"; 372 } 373 print $f <<EOF; 374 </Link> 375 <ResourceCompile> 376 <AdditionalIncludeDirectories>src\\include;\%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 377 </ResourceCompile> 378EOF 379 if ($self->{builddef}) 380 { 381 print $f <<EOF; 382 <PreLinkEvent> 383 <Message>Generate DEF file</Message> 384 <Command>perl src\\tools\\msvc\\gendef.pl $cfgname\\$self->{name} $self->{platform}</Command> 385 </PreLinkEvent> 386EOF 387 } 388 print $f <<EOF; 389 </ItemDefinitionGroup> 390EOF 391 return; 392} 393 394sub Footer 395{ 396 my ($self, $f) = @_; 397 $self->WriteReferences($f); 398 399 print $f <<EOF; 400 <Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.targets" /> 401 <ImportGroup Label="ExtensionTargets"> 402 </ImportGroup> 403</Project> 404EOF 405 return; 406} 407 408package VC2013Project; 409 410# 411# Package that encapsulates a Visual C++ 2013 project file 412# 413 414use strict; 415use warnings; 416use base qw(MSBuildProject); 417 418no warnings qw(redefine); ## no critic 419 420sub new 421{ 422 my $classname = shift; 423 my $self = $classname->SUPER::_new(@_); 424 bless($self, $classname); 425 426 $self->{vcver} = '12.00'; 427 $self->{PlatformToolset} = 'v120'; 428 $self->{ToolsVersion} = '12.0'; 429 430 return $self; 431} 432 433package VC2015Project; 434 435# 436# Package that encapsulates a Visual C++ 2015 project file 437# 438 439use strict; 440use warnings; 441use base qw(MSBuildProject); 442 443no warnings qw(redefine); ## no critic 444 445sub new 446{ 447 my $classname = shift; 448 my $self = $classname->SUPER::_new(@_); 449 bless($self, $classname); 450 451 $self->{vcver} = '14.00'; 452 $self->{PlatformToolset} = 'v140'; 453 $self->{ToolsVersion} = '14.0'; 454 455 return $self; 456} 457 458package VC2017Project; 459 460# 461# Package that encapsulates a Visual C++ 2017 project file 462# 463 464use strict; 465use warnings; 466use base qw(MSBuildProject); 467 468no warnings qw(redefine); ## no critic 469 470sub new 471{ 472 my $classname = shift; 473 my $self = $classname->SUPER::_new(@_); 474 bless($self, $classname); 475 476 $self->{vcver} = '15.00'; 477 $self->{PlatformToolset} = 'v141'; 478 $self->{ToolsVersion} = '15.0'; 479 480 return $self; 481} 482 483package VC2019Project; 484 485# 486# Package that encapsulates a Visual C++ 2019 project file 487# 488 489use strict; 490use warnings; 491use base qw(MSBuildProject); 492 493no warnings qw(redefine); ## no critic 494 495sub new 496{ 497 my $classname = shift; 498 my $self = $classname->SUPER::_new(@_); 499 bless($self, $classname); 500 501 $self->{vcver} = '16.00'; 502 $self->{PlatformToolset} = 'v142'; 503 $self->{ToolsVersion} = '16.0'; 504 505 return $self; 506} 507 5081; 509