package Solution; # # Package that encapsulates a Visual C++ solution file generation # # $PostgreSQL: pgsql/src/tools/msvc/Solution.pm,v 1.56 2010/03/03 03:29:37 adunstan Exp $ # use Carp; use strict; use warnings; sub new { my $junk = shift; my $options = shift; my $self = { projects => {}, options => $options, numver => '', strver => '', vcver => undef, platform => undef, }; bless $self; # integer_datetimes is now the default $options->{integer_datetimes} = 1 unless exists $options->{integer_datetimes}; $options->{float4byval} = 1 unless exists $options->{float4byval}; if ($options->{xml}) { if (!($options->{xslt} && $options->{iconv})) { die "XML requires both XSLT and ICONV\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); $options->{wal_segsize} = 16 unless $options->{wal_segsize}; # undef or 0 means default die "Bad wal_segsize $options->{wal_segsize}" unless grep {$_ == $options->{wal_segsize}} (1,2,4,8,16,32,64); $self->DetermineToolVersions(); return $self; } sub DetermineToolVersions { my $self = shift; # Determine version of vcbuild command, to set proper verison of visual studio open(P,"vcbuild /? |") || die "vcbuild command not found"; my $line =

; close(P); if ($line !~ /^Microsoft\s*\(R\) Visual C\+\+ Project Builder - \D+(\d+)\.00\.\d+/) { die "Unable to determine vcbuild version from first line of output!"; } if ($1 == 8) { $self->{vcver} = '8.00' } elsif ($1 == 9) { $self->{vcver} = '9.00' } else { die "Unsupported version of Visual Studio: $1" } print "Detected Visual Studio version $self->{vcver}\n"; # Determine if we are in 32 or 64-bit mode. Do this by seeing if CL has # 64-bit only parameters. $self->{platform} = 'Win32'; open(P,"cl /? 2>NUL|") || die "cl command not found"; while (

) { if (/^\/favor:{platform} = 'x64'; last; } } close(P); print "Detected hardware platform: $self->{platform}\n"; } # 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) = @_; 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(I,$src) || croak "Could not open $src"; open(O,">$dest") || croak "Could not open $dest"; while () { print O; } close(I); close(O); } sub GenerateFiles { my $self = shift; my $bits = $self->{platform} eq 'Win32' ? 32 : 64; # Parse configure.in to get version numbers open(C,"configure.in") || confess("Could not open configure.in for reading\n"); while () { if (/^AC_INIT\(\[PostgreSQL\], \[([^\]]+)\]/) { $self->{strver} = $1; if ($self->{strver} !~ /^(\d+)\.(\d+)(?:\.(\d+))?/) { confess "Bad format of version: $self->{strver}\n"; } $self->{numver} = sprintf("%d%02d%02d", $1, $2, $3?$3:0); $self->{majorver} = sprintf("%d.%d", $1, $2); } } close(C); confess "Unable to parse configure.in for all variables!" if ($self->{strver} eq '' || $self->{numver} eq ''); 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"); } if (IsNewer("src\\include\\pg_config.h","src\\include\\pg_config.h.win32")) { print "Generating pg_config.h...\n"; open(I,"src\\include\\pg_config.h.win32") || confess "Could not open pg_config.h.win32\n"; open(O,">src\\include\\pg_config.h") || confess "Could not write to pg_config.h\n"; while () { s{PG_VERSION "[^"]+"}{PG_VERSION "$self->{strver}"}; s{PG_VERSION_NUM \d+}{PG_VERSION_NUM $self->{numver}}; s{PG_VERSION_STR "[^"]+"}{__STRINGIFY(x) #x\n#define __STRINGIFY2(z) __STRINGIFY(z)\n#define PG_VERSION_STR "PostgreSQL $self->{strver}, compiled by Visual C++ build " __STRINGIFY2(_MSC_VER) ", $bits-bit"}; print O; } print O "#define PG_MAJORVERSION \"$self->{majorver}\"\n"; print O "#define LOCALEDIR \"/share/locale\"\n" if ($self->{options}->{nls}); print O "/* defines added by config steps */\n"; print O "#ifndef IGNORE_CONFIGURED_SETTINGS\n"; print O "#define USE_ASSERT_CHECKING 1\n" if ($self->{options}->{asserts}); print O "#define USE_INTEGER_DATETIMES 1\n" if ($self->{options}->{integer_datetimes}); print O "#define USE_LDAP 1\n" if ($self->{options}->{ldap}); print O "#define HAVE_LIBZ 1\n" if ($self->{options}->{zlib}); print O "#define USE_SSL 1\n" if ($self->{options}->{openssl}); print O "#define ENABLE_NLS 1\n" if ($self->{options}->{nls}); print O "#define BLCKSZ ",1024 * $self->{options}->{blocksize},"\n"; print O "#define RELSEG_SIZE ", (1024 / $self->{options}->{blocksize}) * $self->{options}->{segsize} * 1024, "\n"; print O "#define XLOG_BLCKSZ ", 1024 * $self->{options}->{wal_blocksize},"\n"; print O "#define XLOG_SEG_SIZE (", $self->{options}->{wal_segsize}," * 1024 * 1024)\n"; if ($self->{options}->{float4byval}) { print O "#define USE_FLOAT4_BYVAL 1\n"; print O "#define FLOAT4PASSBYVAL true\n"; } else { print O "#define FLOAT4PASSBYVAL false\n"; } if ($self->{options}->{float8byval}) { print O "#define USE_FLOAT8_BYVAL 1\n"; print O "#define FLOAT8PASSBYVAL true\n"; } else { print O "#define FLOAT8PASSBYVAL false\n"; } if ($self->{options}->{uuid}) { print O "#define HAVE_UUID_H\n"; } if ($self->{options}->{xml}) { print O "#define HAVE_LIBXML2\n"; print O "#define USE_LIBXML\n"; } if ($self->{options}->{xslt}) { print O "#define HAVE_LIBXSLT\n"; print O "#define USE_LIBXSLT\n"; } if ($self->{options}->{krb5}) { print O "#define KRB5 1\n"; print O "#define HAVE_KRB5_ERROR_TEXT_DATA 1\n"; print O "#define HAVE_KRB5_TICKET_ENC_PART2 1\n"; print O "#define HAVE_KRB5_FREE_UNPARSED_NAME 1\n"; print O "#define ENABLE_GSS 1\n"; } if (my $port = $self->{options}->{"--with-pgport"}) { print O "#undef DEF_PGPORT\n"; print O "#undef DEF_PGPORT_STR\n"; print O "#define DEF_PGPORT $port\n"; print O "#define DEF_PGPORT_STR \"$port\"\n"; } print O "#define VAL_CONFIGURE \"" . $self->GetFakeConfigure() . "\"\n"; print O "#endif /* IGNORE_CONFIGURED_SETTINGS */\n"; close(O); close(I); } $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"); if (IsNewer('src\backend\utils\fmgrtab.c','src\include\catalog\pg_proc.h')) { print "Generating fmgrtab.c and fmgroids.h...\n"; chdir('src\backend\utils'); system("perl -I ../catalog Gen_fmgrtab.pl ../../../src/include/catalog/pg_proc.h"); chdir('..\..\..'); copyFile('src\backend\utils\fmgroids.h','src\include\utils\fmgroids.h'); } if (IsNewer('src\include\utils\probes.h','src\backend\utils\probes.d')) { print "Generating probes.h...\n"; system('psed -f src\backend\utils\Gen_dummy_probes.sed src\backend\utils\probes.d > src\include\utils\probes.h'); } if (IsNewer('src\interfaces\libpq\libpq.rc','src\interfaces\libpq\libpq.rc.in')) { print "Generating libpq.rc...\n"; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); my $d = ($year - 100) . "$yday"; open(I,'<', 'src\interfaces\libpq\libpq.rc.in') || confess "Could not open libpq.rc.in"; open(O,'>', 'src\interfaces\libpq\libpq.rc') || confess "Could not open libpq.rc"; while () { s/(VERSION.*),0/$1,$d/; print O; } close(I); close(O); } 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\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('..\..\..\..'); } if ( IsNewer( 'src\interfaces\ecpg\include\ecpg_config.h', 'src\interfaces\ecpg\include\ecpg_config.h.in' ) ) { print "Generating ecpg_config.h...\n"; open(O,'>','src\interfaces\ecpg\include\ecpg_config.h') || confess "Could not open ecpg_config.h"; print O < 1200) #define HAVE_LONG_LONG_INT_64 #define ENABLE_THREAD_SAFETY 1 EOF print O "#define USE_INTEGER_DATETIMES 1\n" if ($self->{options}->{integer_datetimes}); print O "#endif\n"; close(O); } unless (-f "src\\port\\pg_config_paths.h") { print "Generating pg_config_paths.h...\n"; open(O,'>', 'src\port\pg_config_paths.h') || confess "Could not open pg_config_paths.h"; print O <{majorver} $bki_srcs"); chdir('..\..\..'); copyFile('src\backend\catalog\schemapg.h', 'src\include\catalog\schemapg.h'); last; } } open(O, ">doc/src/sgml/version.sgml") || croak "Could not write to version.sgml\n"; print O <{strver}"> {majorver}"> EOF close(O); } sub GenerateDefFile { my ($self, $deffile, $txtfile, $libname) = @_; if (IsNewer($deffile,$txtfile)) { print "Generating $deffile...\n"; open(I,$txtfile) || confess("Could not open $txtfile\n"); open(O,">$deffile") || confess("Could not open $deffile\n"); print O "LIBRARY $libname\nEXPORTS\n"; while () { next if (/^#/); next if (/^\s*$/); my ($f, $o) = split; print O " $f @ $o\n"; } close(O); close(I); } } sub AddProject { my ($self, $name, $type, $folder, $initialdir) = @_; my $proj = new Project($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'); $proj->AddLibrary($self->{options}->{openssl} . '\lib\VC\ssleay32.lib', 1); $proj->AddLibrary($self->{options}->{openssl} . '\lib\VC\libeay32.lib', 1); } if ($self->{options}->{nls}) { $proj->AddIncludeDir($self->{options}->{nls} . '\include'); $proj->AddLibrary($self->{options}->{nls} . '\lib\libintl.lib'); } if ($self->{options}->{krb5}) { $proj->AddIncludeDir($self->{options}->{krb5} . '\inc\krb5'); $proj->AddLibrary($self->{options}->{krb5} . '\lib\i386\krb5_32.lib'); $proj->AddLibrary($self->{options}->{krb5} . '\lib\i386\comerr32.lib'); $proj->AddLibrary($self->{options}->{krb5} . '\lib\i386\gssapi32.lib'); } if ($self->{options}->{iconv}) { $proj->AddIncludeDir($self->{options}->{iconv} . '\include'); $proj->AddLibrary($self->{options}->{iconv} . '\lib\iconv.lib'); } if ($self->{options}->{xml}) { $proj->AddIncludeDir($self->{options}->{xml} . '\include'); $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'); } 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(SLN,">pgsql.sln") || croak "Could not write to pgsql.sln\n"; print SLN <{projects}}) { foreach my $proj (@{$self->{projects}->{$fld}}) { print SLN <{name}.vcproj", "$proj->{guid}" EndProject EOF } if ($fld ne "") { $flduid{$fld} = Win32::GuidGen(); print SLN <{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 <{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 <{projects}}) { next if ($fld eq ""); foreach my $proj (@{$self->{projects}->{$fld}}) { print SLN "\t\t$proj->{guid} = $flduid{$fld}\n"; } } print SLN <{options}->{asserts}); $cfg .= ' --enable-integer-datetimes' if ($self->{options}->{integer_datetimes}); $cfg .= ' --enable-nls' if ($self->{options}->{nls}); $cfg .= ' --with-ldap' if ($self->{options}->{ldap}); $cfg .= ' --without-zlib' unless ($self->{options}->{zlib}); $cfg .= ' --with-openssl' if ($self->{options}->{ssl}); $cfg .= ' --with-ossp-uuid' if ($self->{options}->{uuid}); $cfg .= ' --with-libxml' if ($self->{options}->{xml}); $cfg .= ' --with-libxslt' if ($self->{options}->{xslt}); $cfg .= ' --with-krb5' if ($self->{options}->{krb5}); $cfg .= ' --with-tcl' if ($self->{options}->{tcl}); $cfg .= ' --with-perl' if ($self->{options}->{perl}); $cfg .= ' --with-python' if ($self->{options}->{python}); return $cfg; } 1;