summaryrefslogtreecommitdiffstats
path: root/src/tools/msvc/Solution.pm
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/msvc/Solution.pm')
-rw-r--r--src/tools/msvc/Solution.pm1378
1 files changed, 1378 insertions, 0 deletions
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
new file mode 100644
index 0000000..790f03b
--- /dev/null
+++ b/src/tools/msvc/Solution.pm
@@ -0,0 +1,1378 @@
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+package Solution;
+
+#
+# Package that encapsulates a Visual C++ solution file generation
+#
+# src/tools/msvc/Solution.pm
+#
+use Carp;
+use strict;
+use warnings;
+use VSObjectFactory;
+
+no warnings qw(redefine); ## no critic
+
+sub _new
+{
+ my $classname = shift;
+ my $options = shift;
+ my $self = {
+ projects => {},
+ options => $options,
+ VisualStudioVersion => undef,
+ MinimumVisualStudioVersion => undef,
+ vcver => undef,
+ platform => undef,
+ };
+ bless($self, $classname);
+
+ $self->DeterminePlatform();
+
+ if ($options->{xslt} && !$options->{xml})
+ {
+ die "XSLT requires XML\n";
+ }
+ $options->{blocksize} = 8
+ unless $options->{blocksize}; # undef or 0 means default
+ die "Bad blocksize $options->{blocksize}"
+ unless grep { $_ == $options->{blocksize} } (1, 2, 4, 8, 16, 32);
+ $options->{segsize} = 1
+ unless $options->{segsize}; # undef or 0 means default
+ # only allow segsize 1 for now, as we can't do large files yet in windows
+ die "Bad segsize $options->{segsize}"
+ unless $options->{segsize} == 1;
+ $options->{wal_blocksize} = 8
+ unless $options->{wal_blocksize}; # undef or 0 means default
+ die "Bad wal_blocksize $options->{wal_blocksize}"
+ unless grep { $_ == $options->{wal_blocksize} }
+ (1, 2, 4, 8, 16, 32, 64);
+
+ return $self;
+}
+
+sub GetAdditionalHeaders
+{
+ return '';
+}
+
+sub DeterminePlatform
+{
+ my $self = shift;
+
+ if ($^O eq "MSWin32")
+ {
+ # Examine CL help output to determine if we are in 32 or 64-bit mode.
+ my $output = `cl /help 2>&1`;
+ $? >> 8 == 0 or die "cl command not found";
+ $self->{platform} =
+ ($output =~ /^\/favor:<.+AMD64/m) ? 'x64' : 'Win32';
+ }
+ else
+ {
+ $self->{platform} = 'FAKE';
+ }
+ print "Detected hardware platform: $self->{platform}\n";
+ return;
+}
+
+# Return 1 if $oldfile is newer than $newfile, or if $newfile doesn't exist.
+# Special case - if config.pl has changed, always return 1
+sub IsNewer
+{
+ my ($newfile, $oldfile) = @_;
+ -e $oldfile or warn "source file \"$oldfile\" does not exist";
+ if ( $oldfile ne 'src/tools/msvc/config.pl'
+ && $oldfile ne 'src/tools/msvc/config_default.pl')
+ {
+ return 1
+ if (-f 'src/tools/msvc/config.pl')
+ && IsNewer($newfile, 'src/tools/msvc/config.pl');
+ return 1
+ if (-f 'src/tools/msvc/config_default.pl')
+ && IsNewer($newfile, 'src/tools/msvc/config_default.pl');
+ }
+ return 1 if (!(-e $newfile));
+ my @nstat = stat($newfile);
+ my @ostat = stat($oldfile);
+ return 1 if ($nstat[9] < $ostat[9]);
+ return 0;
+}
+
+# Copy a file, *not* preserving date. Only works for text files.
+sub copyFile
+{
+ my ($src, $dest) = @_;
+ open(my $i, '<', $src) || croak "Could not open $src";
+ open(my $o, '>', $dest) || croak "Could not open $dest";
+ while (<$i>)
+ {
+ print $o $_;
+ }
+ close($i);
+ close($o);
+ return;
+}
+
+# Fetch version of OpenSSL based on a parsing of the command shipped with
+# the installer this build is linking to. This returns as result an array
+# made of the three first digits of the OpenSSL version, which is enough
+# to decide which options to apply depending on the version of OpenSSL
+# linking with.
+sub GetOpenSSLVersion
+{
+ my $self = shift;
+
+ # Attempt to get OpenSSL version and location. This assumes that
+ # openssl.exe is in the specified directory.
+ # Quote the .exe name in case it has spaces
+ my $opensslcmd =
+ qq("$self->{options}->{openssl}\\bin\\openssl.exe" version 2>&1);
+ my $sslout = `$opensslcmd`;
+
+ $? >> 8 == 0
+ or croak
+ "Unable to determine OpenSSL version: The openssl.exe command wasn't found.";
+
+ if ($sslout =~ /(\d+)\.(\d+)\.(\d+)(\D)/m)
+ {
+ return ($1, $2, $3);
+ }
+
+ croak
+ "Unable to determine OpenSSL version: The openssl.exe version could not be determined.";
+}
+
+sub GenerateFiles
+{
+ my $self = shift;
+ my $bits = $self->{platform} eq 'Win32' ? 32 : 64;
+ my $ac_init_found = 0;
+ my $package_name;
+ my $package_version;
+ my $package_bugreport;
+ my $package_url;
+ my ($majorver, $minorver);
+ my $ac_define_openssl_api_compat_found = 0;
+ my $openssl_api_compat;
+
+ # Parse configure.ac to get version numbers
+ open(my $c, '<', "configure.ac")
+ || confess("Could not open configure.ac for reading\n");
+ while (<$c>)
+ {
+ if (/^AC_INIT\(\[([^\]]+)\], \[([^\]]+)\], \[([^\]]+)\], \[([^\]]*)\], \[([^\]]+)\]/
+ )
+ {
+ $ac_init_found = 1;
+
+ $package_name = $1;
+ $package_version = $2;
+ $package_bugreport = $3;
+ #$package_tarname = $4;
+ $package_url = $5;
+
+ if ($package_version !~ /^(\d+)(?:\.(\d+))?/)
+ {
+ confess "Bad format of version: $package_version\n";
+ }
+ $majorver = sprintf("%d", $1);
+ $minorver = sprintf("%d", $2 ? $2 : 0);
+ }
+ elsif (/\bAC_DEFINE\(OPENSSL_API_COMPAT, \[([0-9xL]+)\]/)
+ {
+ $ac_define_openssl_api_compat_found = 1;
+ $openssl_api_compat = $1;
+ }
+ }
+ close($c);
+ confess "Unable to parse configure.ac for all variables!"
+ unless $ac_init_found && $ac_define_openssl_api_compat_found;
+
+ if (IsNewer("src/include/pg_config_os.h", "src/include/port/win32.h"))
+ {
+ print "Copying pg_config_os.h...\n";
+ copyFile("src/include/port/win32.h", "src/include/pg_config_os.h");
+ }
+
+ print "Generating configuration headers...\n";
+ my $extraver = $self->{options}->{extraver};
+ $extraver = '' unless defined $extraver;
+ my $port = $self->{options}->{"--with-pgport"} || 5432;
+
+ # Every symbol in pg_config.h.in must be accounted for here. Set
+ # to undef if the symbol should not be defined.
+ my %define = (
+ ALIGNOF_DOUBLE => 8,
+ ALIGNOF_INT => 4,
+ ALIGNOF_LONG => 4,
+ ALIGNOF_LONG_LONG_INT => 8,
+ ALIGNOF_PG_INT128_TYPE => undef,
+ ALIGNOF_SHORT => 2,
+ AC_APPLE_UNIVERSAL_BUILD => undef,
+ BLCKSZ => 1024 * $self->{options}->{blocksize},
+ CONFIGURE_ARGS => '"' . $self->GetFakeConfigure() . '"',
+ DEF_PGPORT => $port,
+ DEF_PGPORT_STR => qq{"$port"},
+ DLSUFFIX => '".dll"',
+ ENABLE_GSS => $self->{options}->{gss} ? 1 : undef,
+ ENABLE_NLS => $self->{options}->{nls} ? 1 : undef,
+ ENABLE_THREAD_SAFETY => 1,
+ GETTIMEOFDAY_1ARG => undef,
+ HAVE_APPEND_HISTORY => undef,
+ HAVE_ASN1_STRING_GET0_DATA => undef,
+ HAVE_ATOMICS => 1,
+ HAVE_ATOMIC_H => undef,
+ HAVE_BACKTRACE_SYMBOLS => undef,
+ HAVE_BIO_GET_DATA => undef,
+ HAVE_BIO_METH_NEW => undef,
+ HAVE_CLOCK_GETTIME => undef,
+ HAVE_COMPUTED_GOTO => undef,
+ HAVE_COPYFILE => undef,
+ HAVE_COPYFILE_H => undef,
+ HAVE_CRTDEFS_H => undef,
+ HAVE_CRYPTO_LOCK => undef,
+ HAVE_DECL_FDATASYNC => 0,
+ HAVE_DECL_F_FULLFSYNC => 0,
+ HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER => 0,
+ HAVE_DECL_LLVMCREATEPERFJITEVENTLISTENER => 0,
+ HAVE_DECL_LLVMGETHOSTCPUNAME => 0,
+ HAVE_DECL_LLVMGETHOSTCPUFEATURES => 0,
+ HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN => 0,
+ HAVE_DECL_POSIX_FADVISE => 0,
+ HAVE_DECL_PREADV => 0,
+ HAVE_DECL_PWRITEV => 0,
+ HAVE_DECL_RTLD_GLOBAL => 0,
+ HAVE_DECL_RTLD_NOW => 0,
+ HAVE_DECL_SIGWAIT => 0,
+ HAVE_DECL_STRLCAT => 0,
+ HAVE_DECL_STRLCPY => 0,
+ HAVE_DECL_STRNLEN => 1,
+ HAVE_DECL_STRTOLL => 1,
+ HAVE_DECL_STRTOULL => 1,
+ HAVE_DLOPEN => undef,
+ HAVE_EDITLINE_HISTORY_H => undef,
+ HAVE_EDITLINE_READLINE_H => undef,
+ HAVE_EXECINFO_H => undef,
+ HAVE_EXPLICIT_BZERO => undef,
+ HAVE_FDATASYNC => undef,
+ HAVE_FLS => undef,
+ HAVE_FSEEKO => 1,
+ HAVE_FUNCNAME__FUNC => undef,
+ HAVE_FUNCNAME__FUNCTION => 1,
+ HAVE_GCC__ATOMIC_INT32_CAS => undef,
+ HAVE_GCC__ATOMIC_INT64_CAS => undef,
+ HAVE_GCC__SYNC_CHAR_TAS => undef,
+ HAVE_GCC__SYNC_INT32_CAS => undef,
+ HAVE_GCC__SYNC_INT32_TAS => undef,
+ HAVE_GCC__SYNC_INT64_CAS => undef,
+ HAVE_GETADDRINFO => undef,
+ HAVE_GETHOSTBYNAME_R => undef,
+ HAVE_GETIFADDRS => undef,
+ HAVE_GETOPT => undef,
+ HAVE_GETOPT_H => undef,
+ HAVE_GETOPT_LONG => undef,
+ HAVE_GETPEEREID => undef,
+ HAVE_GETPEERUCRED => undef,
+ HAVE_GETPWUID_R => undef,
+ HAVE_GETRLIMIT => undef,
+ HAVE_GETRUSAGE => undef,
+ HAVE_GETTIMEOFDAY => undef,
+ HAVE_GSSAPI_GSSAPI_H => undef,
+ HAVE_GSSAPI_H => undef,
+ HAVE_HMAC_CTX_FREE => undef,
+ HAVE_HMAC_CTX_NEW => undef,
+ HAVE_HISTORY_H => undef,
+ HAVE_HISTORY_TRUNCATE_FILE => undef,
+ HAVE_IFADDRS_H => undef,
+ HAVE_INET_ATON => undef,
+ HAVE_INET_PTON => 1,
+ HAVE_INT_TIMEZONE => 1,
+ HAVE_INT64 => undef,
+ HAVE_INT8 => undef,
+ HAVE_INTTYPES_H => undef,
+ HAVE_INT_OPTERR => undef,
+ HAVE_INT_OPTRESET => undef,
+ HAVE_IPV6 => 1,
+ HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P => undef,
+ HAVE_KQUEUE => undef,
+ HAVE_LANGINFO_H => undef,
+ HAVE_LDAP_H => undef,
+ HAVE_LDAP_INITIALIZE => undef,
+ HAVE_LIBCRYPTO => undef,
+ HAVE_LIBLDAP => undef,
+ HAVE_LIBLZ4 => undef,
+ HAVE_LIBM => undef,
+ HAVE_LIBPAM => undef,
+ HAVE_LIBREADLINE => undef,
+ HAVE_LIBSELINUX => undef,
+ HAVE_LIBSSL => undef,
+ HAVE_LIBWLDAP32 => undef,
+ HAVE_LIBXML2 => undef,
+ HAVE_LIBXSLT => undef,
+ HAVE_LIBZ => $self->{options}->{zlib} ? 1 : undef,
+ HAVE_LIBZSTD => undef,
+ HAVE_LINK => undef,
+ HAVE_LOCALE_T => 1,
+ HAVE_LONG_INT_64 => undef,
+ HAVE_LONG_LONG_INT_64 => 1,
+ HAVE_MBARRIER_H => undef,
+ HAVE_MBSTOWCS_L => 1,
+ HAVE_MEMORY_H => 1,
+ HAVE_MEMSET_S => undef,
+ HAVE_MINIDUMP_TYPE => 1,
+ HAVE_MKDTEMP => undef,
+ HAVE_NETINET_TCP_H => undef,
+ HAVE_NET_IF_H => undef,
+ HAVE_OPENSSL_INIT_SSL => undef,
+ HAVE_OSSP_UUID_H => undef,
+ HAVE_PAM_PAM_APPL_H => undef,
+ HAVE_POLL => undef,
+ HAVE_POLL_H => undef,
+ HAVE_POSIX_DECL_SIGWAIT => undef,
+ HAVE_POSIX_FADVISE => undef,
+ HAVE_POSIX_FALLOCATE => undef,
+ HAVE_PPC_LWARX_MUTEX_HINT => undef,
+ HAVE_PPOLL => undef,
+ HAVE_PREAD => undef,
+ HAVE_PSTAT => undef,
+ HAVE_PS_STRINGS => undef,
+ HAVE_PTHREAD => undef,
+ HAVE_PTHREAD_BARRIER_WAIT => undef,
+ HAVE_PTHREAD_IS_THREADED_NP => undef,
+ HAVE_PTHREAD_PRIO_INHERIT => undef,
+ HAVE_PWRITE => undef,
+ HAVE_READLINE_H => undef,
+ HAVE_READLINE_HISTORY_H => undef,
+ HAVE_READLINE_READLINE_H => undef,
+ HAVE_READLINK => undef,
+ HAVE_READV => undef,
+ HAVE_RL_COMPLETION_MATCHES => undef,
+ HAVE_RL_COMPLETION_SUPPRESS_QUOTE => undef,
+ HAVE_RL_FILENAME_COMPLETION_FUNCTION => undef,
+ HAVE_RL_FILENAME_QUOTE_CHARACTERS => undef,
+ HAVE_RL_FILENAME_QUOTING_FUNCTION => undef,
+ HAVE_RL_RESET_SCREEN_SIZE => undef,
+ HAVE_RL_VARIABLE_BIND => undef,
+ HAVE_SECURITY_PAM_APPL_H => undef,
+ HAVE_SETENV => undef,
+ HAVE_SETPROCTITLE => undef,
+ HAVE_SETPROCTITLE_FAST => undef,
+ HAVE_SETSID => undef,
+ HAVE_SHM_OPEN => undef,
+ HAVE_SOCKLEN_T => 1,
+ HAVE_SPINLOCKS => 1,
+ HAVE_STDBOOL_H => 1,
+ HAVE_STDINT_H => 1,
+ HAVE_STDLIB_H => 1,
+ HAVE_STRCHRNUL => undef,
+ HAVE_STRERROR_R => undef,
+ HAVE_STRINGS_H => undef,
+ HAVE_STRING_H => 1,
+ HAVE_STRLCAT => undef,
+ HAVE_STRLCPY => undef,
+ HAVE_STRNLEN => 1,
+ HAVE_STRSIGNAL => undef,
+ HAVE_STRTOF => 1,
+ HAVE_STRTOLL => 1,
+ HAVE_STRTOQ => undef,
+ HAVE_STRTOULL => 1,
+ HAVE_STRTOUQ => undef,
+ HAVE_STRUCT_ADDRINFO => 1,
+ HAVE_STRUCT_CMSGCRED => undef,
+ HAVE_STRUCT_OPTION => undef,
+ HAVE_STRUCT_SOCKADDR_SA_LEN => undef,
+ HAVE_STRUCT_SOCKADDR_STORAGE => 1,
+ HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY => 1,
+ HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN => undef,
+ HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY => undef,
+ HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN => undef,
+ HAVE_STRUCT_SOCKADDR_UN => undef,
+ HAVE_STRUCT_TM_TM_ZONE => undef,
+ HAVE_SYNC_FILE_RANGE => undef,
+ HAVE_SYMLINK => 1,
+ HAVE_SYNCFS => undef,
+ HAVE_SYSLOG => undef,
+ HAVE_SYS_EPOLL_H => undef,
+ HAVE_SYS_EVENT_H => undef,
+ HAVE_SYS_IPC_H => undef,
+ HAVE_SYS_PERSONALITY_H => undef,
+ HAVE_SYS_PRCTL_H => undef,
+ HAVE_SYS_PROCCTL_H => undef,
+ HAVE_SYS_PSTAT_H => undef,
+ HAVE_SYS_RESOURCE_H => undef,
+ HAVE_SYS_SELECT_H => undef,
+ HAVE_SYS_SEM_H => undef,
+ HAVE_SYS_SHM_H => undef,
+ HAVE_SYS_SIGNALFD_H => undef,
+ HAVE_SYS_SOCKIO_H => undef,
+ HAVE_SYS_STAT_H => 1,
+ HAVE_SYS_TAS_H => undef,
+ HAVE_SYS_TYPES_H => 1,
+ HAVE_SYS_UCRED_H => undef,
+ HAVE_SYS_UIO_H => undef,
+ HAVE_SYS_UN_H => undef,
+ HAVE_TERMIOS_H => undef,
+ HAVE_TYPEOF => undef,
+ HAVE_UCRED_H => undef,
+ HAVE_UINT64 => undef,
+ HAVE_UINT8 => undef,
+ HAVE_UNION_SEMUN => undef,
+ HAVE_UNISTD_H => 1,
+ HAVE_UNSETENV => undef,
+ HAVE_USELOCALE => undef,
+ HAVE_UUID_BSD => undef,
+ HAVE_UUID_E2FS => undef,
+ HAVE_UUID_OSSP => undef,
+ HAVE_UUID_H => undef,
+ HAVE_UUID_UUID_H => undef,
+ HAVE_WINLDAP_H => undef,
+ HAVE_WCSTOMBS_L => 1,
+ HAVE_WCTYPE_H => 1,
+ HAVE_WRITEV => undef,
+ HAVE_X509_GET_SIGNATURE_NID => 1,
+ HAVE_X509_GET_SIGNATURE_INFO => undef,
+ HAVE_X86_64_POPCNTQ => undef,
+ HAVE__BOOL => undef,
+ HAVE__BUILTIN_BSWAP16 => undef,
+ HAVE__BUILTIN_BSWAP32 => undef,
+ HAVE__BUILTIN_BSWAP64 => undef,
+ HAVE__BUILTIN_CLZ => undef,
+ HAVE__BUILTIN_CONSTANT_P => undef,
+ HAVE__BUILTIN_CTZ => undef,
+ HAVE__BUILTIN_FRAME_ADDRESS => undef,
+ HAVE__BUILTIN_OP_OVERFLOW => undef,
+ HAVE__BUILTIN_POPCOUNT => undef,
+ HAVE__BUILTIN_TYPES_COMPATIBLE_P => undef,
+ HAVE__BUILTIN_UNREACHABLE => undef,
+ HAVE__CONFIGTHREADLOCALE => 1,
+ HAVE__CPUID => 1,
+ HAVE__GET_CPUID => undef,
+ HAVE__STATIC_ASSERT => undef,
+ HAVE___STRTOLL => undef,
+ HAVE___STRTOULL => undef,
+ INT64_MODIFIER => qq{"ll"},
+ LOCALE_T_IN_XLOCALE => undef,
+ MAXIMUM_ALIGNOF => 8,
+ MEMSET_LOOP_LIMIT => 1024,
+ OPENSSL_API_COMPAT => $openssl_api_compat,
+ PACKAGE_BUGREPORT => qq{"$package_bugreport"},
+ PACKAGE_NAME => qq{"$package_name"},
+ PACKAGE_STRING => qq{"$package_name $package_version"},
+ PACKAGE_TARNAME => lc qq{"$package_name"},
+ PACKAGE_URL => qq{"$package_url"},
+ PACKAGE_VERSION => qq{"$package_version"},
+ PG_INT128_TYPE => undef,
+ PG_INT64_TYPE => 'long long int',
+ PG_KRB_SRVNAM => qq{"postgres"},
+ PG_MAJORVERSION => qq{"$majorver"},
+ PG_MAJORVERSION_NUM => $majorver,
+ PG_MINORVERSION_NUM => $minorver,
+ PG_PRINTF_ATTRIBUTE => undef,
+ PG_USE_STDBOOL => 1,
+ PG_VERSION => qq{"$package_version$extraver"},
+ PG_VERSION_NUM => sprintf("%d%04d", $majorver, $minorver),
+ PG_VERSION_STR =>
+ qq{"PostgreSQL $package_version$extraver, compiled by Visual C++ build " CppAsString2(_MSC_VER) ", $bits-bit"},
+ PROFILE_PID_DIR => undef,
+ PTHREAD_CREATE_JOINABLE => undef,
+ RELSEG_SIZE => (1024 / $self->{options}->{blocksize}) *
+ $self->{options}->{segsize} * 1024,
+ SIZEOF_BOOL => 1,
+ SIZEOF_LONG => 4,
+ SIZEOF_OFF_T => undef,
+ SIZEOF_SIZE_T => $bits / 8,
+ SIZEOF_VOID_P => $bits / 8,
+ STDC_HEADERS => 1,
+ STRERROR_R_INT => undef,
+ USE_ARMV8_CRC32C => undef,
+ USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK => undef,
+ USE_ASSERT_CHECKING => $self->{options}->{asserts} ? 1 : undef,
+ USE_BONJOUR => undef,
+ USE_BSD_AUTH => undef,
+ USE_ICU => $self->{options}->{icu} ? 1 : undef,
+ USE_LIBXML => undef,
+ USE_LIBXSLT => undef,
+ USE_LZ4 => undef,
+ USE_LDAP => $self->{options}->{ldap} ? 1 : undef,
+ USE_LLVM => undef,
+ USE_NAMED_POSIX_SEMAPHORES => undef,
+ USE_OPENSSL => undef,
+ USE_PAM => undef,
+ USE_SLICING_BY_8_CRC32C => undef,
+ USE_SSE42_CRC32C => undef,
+ USE_SSE42_CRC32C_WITH_RUNTIME_CHECK => 1,
+ USE_SYSTEMD => undef,
+ USE_SYSV_SEMAPHORES => undef,
+ USE_SYSV_SHARED_MEMORY => undef,
+ USE_UNNAMED_POSIX_SEMAPHORES => undef,
+ USE_WIN32_SEMAPHORES => 1,
+ USE_WIN32_SHARED_MEMORY => 1,
+ USE_ZSTD => undef,
+ WCSTOMBS_L_IN_XLOCALE => undef,
+ WORDS_BIGENDIAN => undef,
+ XLOG_BLCKSZ => 1024 * $self->{options}->{wal_blocksize},
+ _FILE_OFFSET_BITS => undef,
+ _LARGEFILE_SOURCE => undef,
+ _LARGE_FILES => undef,
+ inline => '__inline',
+ pg_restrict => '__restrict',
+ # not defined, because it'd conflict with __declspec(restrict)
+ restrict => undef,
+ typeof => undef,);
+
+ if ($self->{options}->{uuid})
+ {
+ $define{HAVE_UUID_OSSP} = 1;
+ $define{HAVE_UUID_H} = 1;
+ }
+ if ($self->{options}->{xml})
+ {
+ $define{HAVE_LIBXML2} = 1;
+ $define{USE_LIBXML} = 1;
+ }
+ if ($self->{options}->{xslt})
+ {
+ $define{HAVE_LIBXSLT} = 1;
+ $define{USE_LIBXSLT} = 1;
+ }
+ if ($self->{options}->{lz4})
+ {
+ $define{HAVE_LIBLZ4} = 1;
+ $define{USE_LZ4} = 1;
+ }
+ if ($self->{options}->{zstd})
+ {
+ $define{HAVE_LIBZSTD} = 1;
+ $define{USE_ZSTD} = 1;
+ }
+ if ($self->{options}->{openssl})
+ {
+ $define{USE_OPENSSL} = 1;
+
+ my ($digit1, $digit2, $digit3) = $self->GetOpenSSLVersion();
+
+ # Symbols needed with OpenSSL 1.1.1 and above.
+ if ( ($digit1 >= '3' && $digit2 >= '0' && $digit3 >= '0')
+ || ($digit1 >= '1' && $digit2 >= '1' && $digit3 >= '1'))
+ {
+ $define{HAVE_X509_GET_SIGNATURE_INFO} = 1;
+ }
+
+ # Symbols needed with OpenSSL 1.1.0 and above.
+ if ( ($digit1 >= '3' && $digit2 >= '0' && $digit3 >= '0')
+ || ($digit1 >= '1' && $digit2 >= '1' && $digit3 >= '0'))
+ {
+ $define{HAVE_ASN1_STRING_GET0_DATA} = 1;
+ $define{HAVE_BIO_GET_DATA} = 1;
+ $define{HAVE_BIO_METH_NEW} = 1;
+ $define{HAVE_HMAC_CTX_FREE} = 1;
+ $define{HAVE_HMAC_CTX_NEW} = 1;
+ $define{HAVE_OPENSSL_INIT_SSL} = 1;
+ }
+ }
+
+ $self->GenerateConfigHeader('src/include/pg_config.h', \%define, 1);
+ $self->GenerateConfigHeader('src/include/pg_config_ext.h', \%define, 0);
+ $self->GenerateConfigHeader('src/interfaces/ecpg/include/ecpg_config.h',
+ \%define, 0);
+
+ $self->GenerateDefFile(
+ "src/interfaces/libpq/libpqdll.def",
+ "src/interfaces/libpq/exports.txt",
+ "LIBPQ");
+ $self->GenerateDefFile(
+ "src/interfaces/ecpg/ecpglib/ecpglib.def",
+ "src/interfaces/ecpg/ecpglib/exports.txt",
+ "LIBECPG");
+ $self->GenerateDefFile(
+ "src/interfaces/ecpg/compatlib/compatlib.def",
+ "src/interfaces/ecpg/compatlib/exports.txt",
+ "LIBECPG_COMPAT");
+ $self->GenerateDefFile(
+ "src/interfaces/ecpg/pgtypeslib/pgtypeslib.def",
+ "src/interfaces/ecpg/pgtypeslib/exports.txt",
+ "LIBPGTYPES");
+
+ chdir('src/backend/utils');
+ my $pg_proc_dat = '../../../src/include/catalog/pg_proc.dat';
+ if ( IsNewer('fmgr-stamp', 'Gen_fmgrtab.pl')
+ || IsNewer('fmgr-stamp', '../catalog/Catalog.pm')
+ || IsNewer('fmgr-stamp', $pg_proc_dat)
+ || IsNewer('fmgr-stamp', '../../../src/include/access/transam.h'))
+ {
+ system(
+ "perl -I ../catalog Gen_fmgrtab.pl --include-path ../../../src/include/ $pg_proc_dat"
+ );
+ open(my $f, '>', 'fmgr-stamp')
+ || confess "Could not touch fmgr-stamp";
+ close($f);
+ }
+ chdir('../../..');
+
+ if (IsNewer(
+ 'src/include/utils/fmgroids.h',
+ 'src/backend/utils/fmgroids.h'))
+ {
+ copyFile('src/backend/utils/fmgroids.h',
+ 'src/include/utils/fmgroids.h');
+ }
+
+ if (IsNewer(
+ 'src/include/utils/fmgrprotos.h',
+ 'src/backend/utils/fmgrprotos.h'))
+ {
+ copyFile(
+ 'src/backend/utils/fmgrprotos.h',
+ 'src/include/utils/fmgrprotos.h');
+ }
+
+ if (IsNewer(
+ 'src/include/storage/lwlocknames.h',
+ 'src/backend/storage/lmgr/lwlocknames.txt'))
+ {
+ print "Generating lwlocknames.c and lwlocknames.h...\n";
+ chdir('src/backend/storage/lmgr');
+ system('perl generate-lwlocknames.pl lwlocknames.txt');
+ chdir('../../../..');
+ }
+ if (IsNewer(
+ 'src/include/storage/lwlocknames.h',
+ 'src/backend/storage/lmgr/lwlocknames.h'))
+ {
+ copyFile(
+ 'src/backend/storage/lmgr/lwlocknames.h',
+ 'src/include/storage/lwlocknames.h');
+ }
+
+ if (IsNewer('src/include/utils/probes.h', 'src/backend/utils/probes.d'))
+ {
+ print "Generating probes.h...\n";
+ system(
+ 'perl src/backend/utils/Gen_dummy_probes.pl src/backend/utils/probes.d > src/include/utils/probes.h'
+ );
+ }
+
+ if ($self->{options}->{python}
+ && IsNewer(
+ 'src/pl/plpython/spiexceptions.h',
+ 'src/backend/utils/errcodes.txt'))
+ {
+ print "Generating spiexceptions.h...\n";
+ system(
+ 'perl src/pl/plpython/generate-spiexceptions.pl src/backend/utils/errcodes.txt > src/pl/plpython/spiexceptions.h'
+ );
+ }
+
+ if (IsNewer(
+ 'src/include/utils/errcodes.h',
+ 'src/backend/utils/errcodes.txt'))
+ {
+ print "Generating errcodes.h...\n";
+ system(
+ 'perl src/backend/utils/generate-errcodes.pl src/backend/utils/errcodes.txt > src/backend/utils/errcodes.h'
+ );
+ copyFile('src/backend/utils/errcodes.h',
+ 'src/include/utils/errcodes.h');
+ }
+
+ if (IsNewer(
+ 'src/pl/plpgsql/src/plerrcodes.h',
+ 'src/backend/utils/errcodes.txt'))
+ {
+ print "Generating plerrcodes.h...\n";
+ system(
+ 'perl src/pl/plpgsql/src/generate-plerrcodes.pl src/backend/utils/errcodes.txt > src/pl/plpgsql/src/plerrcodes.h'
+ );
+ }
+
+ if ($self->{options}->{tcl}
+ && IsNewer(
+ 'src/pl/tcl/pltclerrcodes.h', 'src/backend/utils/errcodes.txt'))
+ {
+ print "Generating pltclerrcodes.h...\n";
+ system(
+ 'perl src/pl/tcl/generate-pltclerrcodes.pl src/backend/utils/errcodes.txt > src/pl/tcl/pltclerrcodes.h'
+ );
+ }
+
+ if (IsNewer('src/bin/psql/sql_help.h', 'src/bin/psql/create_help.pl'))
+ {
+ print "Generating sql_help.h...\n";
+ chdir('src/bin/psql');
+ system("perl create_help.pl ../../../doc/src/sgml/ref sql_help");
+ chdir('../../..');
+ }
+
+ if (IsNewer('src/common/kwlist_d.h', 'src/include/parser/kwlist.h'))
+ {
+ print "Generating kwlist_d.h...\n";
+ system(
+ 'perl -I src/tools src/tools/gen_keywordlist.pl --extern -o src/common src/include/parser/kwlist.h'
+ );
+ }
+
+ if (IsNewer(
+ 'src/pl/plpgsql/src/pl_reserved_kwlist_d.h',
+ 'src/pl/plpgsql/src/pl_reserved_kwlist.h')
+ || IsNewer(
+ 'src/pl/plpgsql/src/pl_unreserved_kwlist_d.h',
+ 'src/pl/plpgsql/src/pl_unreserved_kwlist.h'))
+ {
+ print
+ "Generating pl_reserved_kwlist_d.h and pl_unreserved_kwlist_d.h...\n";
+ chdir('src/pl/plpgsql/src');
+ system(
+ 'perl -I ../../../tools ../../../tools/gen_keywordlist.pl --varname ReservedPLKeywords pl_reserved_kwlist.h'
+ );
+ system(
+ 'perl -I ../../../tools ../../../tools/gen_keywordlist.pl --varname UnreservedPLKeywords pl_unreserved_kwlist.h'
+ );
+ chdir('../../../..');
+ }
+
+ if (IsNewer(
+ 'src/interfaces/ecpg/preproc/c_kwlist_d.h',
+ 'src/interfaces/ecpg/preproc/c_kwlist.h')
+ || IsNewer(
+ 'src/interfaces/ecpg/preproc/ecpg_kwlist_d.h',
+ 'src/interfaces/ecpg/preproc/ecpg_kwlist.h'))
+ {
+ print "Generating c_kwlist_d.h and ecpg_kwlist_d.h...\n";
+ chdir('src/interfaces/ecpg/preproc');
+ system(
+ 'perl -I ../../../tools ../../../tools/gen_keywordlist.pl --varname ScanCKeywords --no-case-fold c_kwlist.h'
+ );
+ system(
+ 'perl -I ../../../tools ../../../tools/gen_keywordlist.pl --varname ScanECPGKeywords ecpg_kwlist.h'
+ );
+ chdir('../../../..');
+ }
+
+ if (IsNewer(
+ 'src/interfaces/ecpg/preproc/preproc.y',
+ 'src/backend/parser/gram.y'))
+ {
+ print "Generating preproc.y...\n";
+ chdir('src/interfaces/ecpg/preproc');
+ system('perl parse.pl < ../../../backend/parser/gram.y > preproc.y');
+ chdir('../../../..');
+ }
+
+ unless (-f "src/port/pg_config_paths.h")
+ {
+ print "Generating pg_config_paths.h...\n";
+ open(my $o, '>', 'src/port/pg_config_paths.h')
+ || confess "Could not open pg_config_paths.h";
+ print $o <<EOF;
+#define PGBINDIR "/bin"
+#define PGSHAREDIR "/share"
+#define SYSCONFDIR "/etc"
+#define INCLUDEDIR "/include"
+#define PKGINCLUDEDIR "/include"
+#define INCLUDEDIRSERVER "/include/server"
+#define LIBDIR "/lib"
+#define PKGLIBDIR "/lib"
+#define LOCALEDIR "/share/locale"
+#define DOCDIR "/doc"
+#define HTMLDIR "/doc"
+#define MANDIR "/man"
+EOF
+ close($o);
+ }
+
+ my $mf = Project::read_file('src/backend/catalog/Makefile');
+ $mf =~ s{\\\r?\n}{}g;
+ $mf =~ /^CATALOG_HEADERS\s*:?=(.*)$/gm
+ || croak "Could not find CATALOG_HEADERS in Makefile\n";
+ my @bki_srcs = split /\s+/, $1;
+ $mf =~ /^POSTGRES_BKI_DATA\s*:?=[^,]+,(.*)\)$/gm
+ || croak "Could not find POSTGRES_BKI_DATA in Makefile\n";
+ my @bki_data = split /\s+/, $1;
+
+ my $need_genbki = 0;
+ foreach my $bki (@bki_srcs, @bki_data)
+ {
+ next if $bki eq "";
+ if (IsNewer(
+ 'src/backend/catalog/bki-stamp',
+ "src/include/catalog/$bki"))
+ {
+ $need_genbki = 1;
+ last;
+ }
+ }
+ $need_genbki = 1
+ if IsNewer('src/backend/catalog/bki-stamp',
+ 'src/backend/catalog/genbki.pl');
+ $need_genbki = 1
+ if IsNewer('src/backend/catalog/bki-stamp',
+ 'src/backend/catalog/Catalog.pm');
+ if ($need_genbki)
+ {
+ chdir('src/backend/catalog');
+ my $bki_srcs = join(' ../../../src/include/catalog/', @bki_srcs);
+ system(
+ "perl genbki.pl --include-path ../../../src/include/ --set-version=$majorver $bki_srcs"
+ );
+ open(my $f, '>', 'bki-stamp')
+ || confess "Could not touch bki-stamp";
+ close($f);
+ chdir('../../..');
+ }
+
+ if (IsNewer(
+ 'src/include/catalog/header-stamp',
+ 'src/backend/catalog/bki-stamp'))
+ {
+ # Copy generated headers to include directory.
+ opendir(my $dh, 'src/backend/catalog/')
+ || die "Can't opendir src/backend/catalog/ $!";
+ my @def_headers = grep { /pg_\w+_d\.h$/ } readdir($dh);
+ closedir $dh;
+ foreach my $def_header (@def_headers)
+ {
+ copyFile(
+ "src/backend/catalog/$def_header",
+ "src/include/catalog/$def_header");
+ }
+ copyFile(
+ 'src/backend/catalog/schemapg.h',
+ 'src/include/catalog/schemapg.h');
+ copyFile(
+ 'src/backend/catalog/system_fk_info.h',
+ 'src/include/catalog/system_fk_info.h');
+ open(my $chs, '>', 'src/include/catalog/header-stamp')
+ || confess "Could not touch header-stamp";
+ close($chs);
+ }
+
+ open(my $o, '>', "doc/src/sgml/version.sgml")
+ || croak "Could not write to version.sgml\n";
+ print $o <<EOF;
+<!ENTITY version "$package_version">
+<!ENTITY majorversion "$majorver">
+EOF
+ close($o);
+ return;
+}
+
+# Read lines from input file and substitute symbols using the same
+# logic that config.status uses. There should be one call of this for
+# each AC_CONFIG_HEADERS call in configure.ac.
+#
+# If the "required" argument is true, we also keep track which of our
+# defines have been found and error out if any are left unused at the
+# end. That way we avoid accumulating defines in this file that are
+# no longer used by configure.
+sub GenerateConfigHeader
+{
+ my ($self, $config_header, $defines, $required) = @_;
+
+ my $config_header_in = $config_header . '.in';
+
+ if ( IsNewer($config_header, $config_header_in)
+ || IsNewer($config_header, __FILE__))
+ {
+ my %defines_copy = %$defines;
+
+ open(my $i, '<', $config_header_in)
+ || confess "Could not open $config_header_in\n";
+ open(my $o, '>', $config_header)
+ || confess "Could not write to $config_header\n";
+
+ print $o
+ "/* $config_header. Generated from $config_header_in by src/tools/msvc/Solution.pm. */\n";
+
+ while (<$i>)
+ {
+ if (m/^#(\s*)undef\s+(\w+)/)
+ {
+ my $ws = $1;
+ my $macro = $2;
+ if (exists $defines->{$macro})
+ {
+ if (defined $defines->{$macro})
+ {
+ print $o "#${ws}define $macro ", $defines->{$macro},
+ "\n";
+ }
+ else
+ {
+ print $o "/* #${ws}undef $macro */\n";
+ }
+ delete $defines_copy{$macro};
+ }
+ else
+ {
+ croak
+ "undefined symbol: $macro at $config_header line $.";
+ }
+ }
+ else
+ {
+ print $o $_;
+ }
+ }
+ close($o);
+ close($i);
+
+ if ($required && scalar(keys %defines_copy) > 0)
+ {
+ croak "unused defines: " . join(' ', keys %defines_copy);
+ }
+ }
+}
+
+sub GenerateDefFile
+{
+ my ($self, $deffile, $txtfile, $libname) = @_;
+
+ if (IsNewer($deffile, $txtfile))
+ {
+ print "Generating $deffile...\n";
+ open(my $if, '<', $txtfile) || confess("Could not open $txtfile\n");
+ open(my $of, '>', $deffile) || confess("Could not open $deffile\n");
+ print $of "LIBRARY $libname\nEXPORTS\n";
+ while (<$if>)
+ {
+ next if (/^#/);
+ next if (/^\s*$/);
+ my ($f, $o) = split;
+ print $of " $f @ $o\n";
+ }
+ close($of);
+ close($if);
+ }
+ return;
+}
+
+sub AddProject
+{
+ my ($self, $name, $type, $folder, $initialdir) = @_;
+
+ my $proj =
+ VSObjectFactory::CreateProject($self->{vcver}, $name, $type, $self);
+ push @{ $self->{projects}->{$folder} }, $proj;
+ $proj->AddDir($initialdir) if ($initialdir);
+ if ($self->{options}->{zlib})
+ {
+ $proj->AddIncludeDir($self->{options}->{zlib} . '\include');
+ $proj->AddLibrary($self->{options}->{zlib} . '\lib\zdll.lib');
+ }
+ if ($self->{options}->{openssl})
+ {
+ $proj->AddIncludeDir($self->{options}->{openssl} . '\include');
+ my ($digit1, $digit2, $digit3) = $self->GetOpenSSLVersion();
+
+ # Starting at version 1.1.0 the OpenSSL installers have
+ # changed their library names from:
+ # - libeay to libcrypto
+ # - ssleay to libssl
+ if ( ($digit1 >= '3' && $digit2 >= '0' && $digit3 >= '0')
+ || ($digit1 >= '1' && $digit2 >= '1' && $digit3 >= '0'))
+ {
+ my $dbgsuffix;
+ my $libsslpath;
+ my $libcryptopath;
+
+ # The format name of the libraries is slightly
+ # different between the Win32 and Win64 platform, so
+ # adapt.
+ if (-e "$self->{options}->{openssl}/lib/VC/sslcrypto32MD.lib")
+ {
+ # Win32 here, with a debugging library set.
+ $dbgsuffix = 1;
+ $libsslpath = '\lib\VC\libssl32.lib';
+ $libcryptopath = '\lib\VC\libcrypto32.lib';
+ }
+ elsif (-e "$self->{options}->{openssl}/lib/VC/sslcrypto64MD.lib")
+ {
+ # Win64 here, with a debugging library set.
+ $dbgsuffix = 1;
+ $libsslpath = '\lib\VC\libssl64.lib';
+ $libcryptopath = '\lib\VC\libcrypto64.lib';
+ }
+ else
+ {
+ # On both Win32 and Win64 the same library
+ # names are used without a debugging context.
+ $dbgsuffix = 0;
+ $libsslpath = '\lib\libssl.lib';
+ $libcryptopath = '\lib\libcrypto.lib';
+ }
+
+ $proj->AddLibrary($self->{options}->{openssl} . $libsslpath,
+ $dbgsuffix);
+ $proj->AddLibrary($self->{options}->{openssl} . $libcryptopath,
+ $dbgsuffix);
+ }
+ else
+ {
+ # Choose which set of libraries to use depending on if
+ # debugging libraries are in place in the installer.
+ if (-e "$self->{options}->{openssl}/lib/VC/ssleay32MD.lib")
+ {
+ $proj->AddLibrary(
+ $self->{options}->{openssl} . '\lib\VC\ssleay32.lib', 1);
+ $proj->AddLibrary(
+ $self->{options}->{openssl} . '\lib\VC\libeay32.lib', 1);
+ }
+ else
+ {
+ # We don't expect the config-specific library
+ # to be here, so don't ask for it in last
+ # parameter.
+ $proj->AddLibrary(
+ $self->{options}->{openssl} . '\lib\ssleay32.lib', 0);
+ $proj->AddLibrary(
+ $self->{options}->{openssl} . '\lib\libeay32.lib', 0);
+ }
+ }
+ }
+ if ($self->{options}->{nls})
+ {
+ $proj->AddIncludeDir($self->{options}->{nls} . '\include');
+ $proj->AddLibrary($self->{options}->{nls} . '\lib\libintl.lib');
+ }
+ if ($self->{options}->{gss})
+ {
+ $proj->AddIncludeDir($self->{options}->{gss} . '\include');
+ $proj->AddIncludeDir($self->{options}->{gss} . '\include\krb5');
+ if ($self->{platform} eq 'Win32')
+ {
+ $proj->AddLibrary(
+ $self->{options}->{gss} . '\lib\i386\krb5_32.lib');
+ $proj->AddLibrary(
+ $self->{options}->{gss} . '\lib\i386\comerr32.lib');
+ $proj->AddLibrary(
+ $self->{options}->{gss} . '\lib\i386\gssapi32.lib');
+ }
+ else
+ {
+ $proj->AddLibrary(
+ $self->{options}->{gss} . '\lib\amd64\krb5_64.lib');
+ $proj->AddLibrary(
+ $self->{options}->{gss} . '\lib\amd64\comerr64.lib');
+ $proj->AddLibrary(
+ $self->{options}->{gss} . '\lib\amd64\gssapi64.lib');
+ }
+ }
+ if ($self->{options}->{iconv})
+ {
+ $proj->AddIncludeDir($self->{options}->{iconv} . '\include');
+ $proj->AddLibrary($self->{options}->{iconv} . '\lib\iconv.lib');
+ }
+ if ($self->{options}->{icu})
+ {
+ $proj->AddIncludeDir($self->{options}->{icu} . '\include');
+ if ($self->{platform} eq 'Win32')
+ {
+ $proj->AddLibrary($self->{options}->{icu} . '\lib\icuin.lib');
+ $proj->AddLibrary($self->{options}->{icu} . '\lib\icuuc.lib');
+ $proj->AddLibrary($self->{options}->{icu} . '\lib\icudt.lib');
+ }
+ else
+ {
+ $proj->AddLibrary($self->{options}->{icu} . '\lib64\icuin.lib');
+ $proj->AddLibrary($self->{options}->{icu} . '\lib64\icuuc.lib');
+ $proj->AddLibrary($self->{options}->{icu} . '\lib64\icudt.lib');
+ }
+ }
+ if ($self->{options}->{xml})
+ {
+ $proj->AddIncludeDir($self->{options}->{xml} . '\include');
+ $proj->AddIncludeDir($self->{options}->{xml} . '\include\libxml2');
+ $proj->AddLibrary($self->{options}->{xml} . '\lib\libxml2.lib');
+ }
+ if ($self->{options}->{xslt})
+ {
+ $proj->AddIncludeDir($self->{options}->{xslt} . '\include');
+ $proj->AddLibrary($self->{options}->{xslt} . '\lib\libxslt.lib');
+ }
+ if ($self->{options}->{lz4})
+ {
+ $proj->AddIncludeDir($self->{options}->{lz4} . '\include');
+ $proj->AddLibrary($self->{options}->{lz4} . '\lib\liblz4.lib');
+ }
+ if ($self->{options}->{zstd})
+ {
+ $proj->AddIncludeDir($self->{options}->{zstd} . '\include');
+ $proj->AddLibrary($self->{options}->{zstd} . '\lib\libzstd.lib');
+ }
+ if ($self->{options}->{uuid})
+ {
+ $proj->AddIncludeDir($self->{options}->{uuid} . '\include');
+ $proj->AddLibrary($self->{options}->{uuid} . '\lib\uuid.lib');
+ }
+ return $proj;
+}
+
+sub Save
+{
+ my ($self) = @_;
+ my %flduid;
+
+ $self->GenerateFiles();
+ foreach my $fld (keys %{ $self->{projects} })
+ {
+ foreach my $proj (@{ $self->{projects}->{$fld} })
+ {
+ $proj->Save();
+ }
+ }
+
+ open(my $sln, '>', "pgsql.sln") || croak "Could not write to pgsql.sln\n";
+ print $sln <<EOF;
+Microsoft Visual Studio Solution File, Format Version $self->{solutionFileVersion}
+# $self->{visualStudioName}
+EOF
+
+ print $sln $self->GetAdditionalHeaders();
+
+ foreach my $fld (keys %{ $self->{projects} })
+ {
+ foreach my $proj (@{ $self->{projects}->{$fld} })
+ {
+ print $sln <<EOF;
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "$proj->{name}", "$proj->{name}$proj->{filenameExtension}", "$proj->{guid}"
+EndProject
+EOF
+ }
+ if ($fld ne "")
+ {
+ $flduid{$fld} = $^O eq "MSWin32" ? Win32::GuidGen() : 'FAKE';
+ print $sln <<EOF;
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "$fld", "$fld", "$flduid{$fld}"
+EndProject
+EOF
+ }
+ }
+
+ print $sln <<EOF;
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|$self->{platform}= Debug|$self->{platform}
+ Release|$self->{platform} = Release|$self->{platform}
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+EOF
+
+ foreach my $fld (keys %{ $self->{projects} })
+ {
+ foreach my $proj (@{ $self->{projects}->{$fld} })
+ {
+ print $sln <<EOF;
+ $proj->{guid}.Debug|$self->{platform}.ActiveCfg = Debug|$self->{platform}
+ $proj->{guid}.Debug|$self->{platform}.Build.0 = Debug|$self->{platform}
+ $proj->{guid}.Release|$self->{platform}.ActiveCfg = Release|$self->{platform}
+ $proj->{guid}.Release|$self->{platform}.Build.0 = Release|$self->{platform}
+EOF
+ }
+ }
+
+ print $sln <<EOF;
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+EOF
+
+ foreach my $fld (keys %{ $self->{projects} })
+ {
+ next if ($fld eq "");
+ foreach my $proj (@{ $self->{projects}->{$fld} })
+ {
+ print $sln "\t\t$proj->{guid} = $flduid{$fld}\n";
+ }
+ }
+
+ print $sln <<EOF;
+ EndGlobalSection
+EndGlobal
+EOF
+ close($sln);
+ return;
+}
+
+sub GetFakeConfigure
+{
+ my $self = shift;
+
+ my $cfg = '--enable-thread-safety';
+ $cfg .= ' --enable-cassert' if ($self->{options}->{asserts});
+ $cfg .= ' --enable-nls' if ($self->{options}->{nls});
+ $cfg .= ' --enable-tap-tests' if ($self->{options}->{tap_tests});
+ $cfg .= ' --with-ldap' if ($self->{options}->{ldap});
+ $cfg .= ' --without-zlib' unless ($self->{options}->{zlib});
+ $cfg .= ' --with-extra-version' if ($self->{options}->{extraver});
+ $cfg .= ' --with-ssl=openssl' if ($self->{options}->{openssl});
+ $cfg .= ' --with-uuid' if ($self->{options}->{uuid});
+ $cfg .= ' --with-libxml' if ($self->{options}->{xml});
+ $cfg .= ' --with-libxslt' if ($self->{options}->{xslt});
+ $cfg .= ' --with-lz4' if ($self->{options}->{lz4});
+ $cfg .= ' --with-zstd' if ($self->{options}->{zstd});
+ $cfg .= ' --with-gssapi' if ($self->{options}->{gss});
+ $cfg .= ' --with-icu' if ($self->{options}->{icu});
+ $cfg .= ' --with-tcl' if ($self->{options}->{tcl});
+ $cfg .= ' --with-perl' if ($self->{options}->{perl});
+ $cfg .= ' --with-python' if ($self->{options}->{python});
+ my $port = $self->{options}->{'--with-pgport'};
+ $cfg .= " --with-pgport=$port" if defined($port);
+
+ return $cfg;
+}
+
+package VS2013Solution;
+
+#
+# Package that encapsulates a Visual Studio 2013 solution file
+#
+
+use Carp;
+use strict;
+use warnings;
+use base qw(Solution);
+
+no warnings qw(redefine); ## no critic
+
+sub new
+{
+ my $classname = shift;
+ my $self = $classname->SUPER::_new(@_);
+ bless($self, $classname);
+
+ $self->{solutionFileVersion} = '12.00';
+ $self->{vcver} = '12.00';
+ $self->{visualStudioName} = 'Visual Studio 2013';
+ $self->{VisualStudioVersion} = '12.0.21005.1';
+ $self->{MinimumVisualStudioVersion} = '10.0.40219.1';
+
+ return $self;
+}
+
+package VS2015Solution;
+
+#
+# Package that encapsulates a Visual Studio 2015 solution file
+#
+
+use Carp;
+use strict;
+use warnings;
+use base qw(Solution);
+
+no warnings qw(redefine); ## no critic
+
+sub new
+{
+ my $classname = shift;
+ my $self = $classname->SUPER::_new(@_);
+ bless($self, $classname);
+
+ $self->{solutionFileVersion} = '12.00';
+ $self->{vcver} = '14.00';
+ $self->{visualStudioName} = 'Visual Studio 2015';
+ $self->{VisualStudioVersion} = '14.0.24730.2';
+ $self->{MinimumVisualStudioVersion} = '10.0.40219.1';
+
+ return $self;
+}
+
+package VS2017Solution;
+
+#
+# Package that encapsulates a Visual Studio 2017 solution file
+#
+
+use Carp;
+use strict;
+use warnings;
+use base qw(Solution);
+
+no warnings qw(redefine); ## no critic
+
+sub new
+{
+ my $classname = shift;
+ my $self = $classname->SUPER::_new(@_);
+ bless($self, $classname);
+
+ $self->{solutionFileVersion} = '12.00';
+ $self->{vcver} = '15.00';
+ $self->{visualStudioName} = 'Visual Studio 2017';
+ $self->{VisualStudioVersion} = '15.0.26730.3';
+ $self->{MinimumVisualStudioVersion} = '10.0.40219.1';
+
+ return $self;
+}
+
+package VS2019Solution;
+
+#
+# Package that encapsulates a Visual Studio 2019 solution file
+#
+
+use Carp;
+use strict;
+use warnings;
+use base qw(Solution);
+
+no warnings qw(redefine); ## no critic
+
+sub new
+{
+ my $classname = shift;
+ my $self = $classname->SUPER::_new(@_);
+ bless($self, $classname);
+
+ $self->{solutionFileVersion} = '12.00';
+ $self->{vcver} = '16.00';
+ $self->{visualStudioName} = 'Visual Studio 2019';
+ $self->{VisualStudioVersion} = '16.0.28729.10';
+ $self->{MinimumVisualStudioVersion} = '10.0.40219.1';
+
+ return $self;
+}
+
+package VS2022Solution;
+
+#
+# Package that encapsulates a Visual Studio 2022 solution file
+#
+
+use Carp;
+use strict;
+use warnings;
+use base qw(Solution);
+
+no warnings qw(redefine); ## no critic
+
+sub new
+{
+ my $classname = shift;
+ my $self = $classname->SUPER::_new(@_);
+ bless($self, $classname);
+
+ $self->{solutionFileVersion} = '12.00';
+ $self->{vcver} = '17.00';
+ $self->{visualStudioName} = 'Visual Studio 2022';
+ $self->{VisualStudioVersion} = '17.0.31903.59';
+ $self->{MinimumVisualStudioVersion} = '10.0.40219.1';
+
+ return $self;
+}
+
+sub GetAdditionalHeaders
+{
+ my ($self, $f) = @_;
+
+ return qq|VisualStudioVersion = $self->{VisualStudioVersion}
+MinimumVisualStudioVersion = $self->{MinimumVisualStudioVersion}
+|;
+}
+
+1;