| package Solution; |
| |
| # |
| # Package that encapsulates a Visual C++ solution file generation |
| # |
| # src/tools/msvc/Solution.pm |
| # |
| use Carp; |
| use strict; |
| use warnings; |
| |
| use Genbki; |
| |
| sub new |
| { |
| my $junk = shift; |
| my $options = shift; |
| die "Pthreads is required by Greenplum DB.\n" unless $options->{pthread}; |
| die "zlib is required by Greenplum DB.\n" unless $options->{zlib}; |
| die "b2zlib is required by Greenplum DB.\n" unless $options->{bzlib}; |
| 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}; |
| $options->{float8byval} = 1 |
| unless exists $options->{float8byval}; |
| |
| |
| if ($options->{xml}) |
| { |
| if (!($options->{xslt} && $options->{iconv})) |
| { |
| die "XML requires both XSLT and ICONV\n"; |
| } |
| } |
| $options->{blocksize} = 32 |
| 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 = <P>; |
| 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 (<P>) |
| { |
| if (/^\/favor:</) |
| { |
| $self->{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 (<I>) |
| { |
| 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 (<C>) |
| { |
| if (/^AC_INIT\(\[Greenplum Database\], \[([^\]]+)\]/) |
| { |
| $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 (<I>) |
| { |
| 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 GP_VERSION \"unknown\"\n"; |
| 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 (<I>) |
| { |
| 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.h"); |
| chdir('..\..\..'); |
| } |
| |
| if (IsNewer('src\include\catalog\gp_version.h','src\include\catalog\gp_version.in')) |
| { |
| print "Generating gp_versions.h...\n"; |
| copyFile("src\\include\\catalog\\gp_version.in","src\\include\\catalog\\gp_version.h"); |
| } |
| |
| if (IsNewer('src\backend\catalog\cdb_schema.sql','src\backend\catalog\cdb_schema.in')) |
| { |
| print "Generating cdb_schema.sql...\n"; |
| copyFile("src\\backend\\catalog\\cdb_schema.in","src\\backend\\catalog\\cdb_schema.sql"); |
| } |
| |
| if (IsNewer('src\interfaces\ecpg\preproc\preproc.y','src\backend\parser\gram.y')) |
| { |
| print "Generating preproc.y...\n"; |
| chdir('src\interfaces\ecpg\preproc'); |
| system('attrib -r preproc.y'); |
| 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 <<EOF; |
| #if (_MSC_VER > 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 <<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{\\s*[\r\n]+}{}mg; |
| $mf =~ /^POSTGRES_BKI_SRCS\s*:?=[^,]+,(.*)\)\s*$/gm |
| || croak "Could not find POSTGRES_BKI_SRCS in Makefile\n"; |
| my @allbki = split /\s+/, $1; |
| foreach my $bki (@allbki) |
| { |
| next if $bki eq ""; |
| if (IsNewer('src/backend/catalog/postgres.bki', "src/include/catalog/$bki")) |
| { |
| print "Generating postgres.bki...\n"; |
| Genbki::genbki( |
| $self->{majorver}, |
| "src/backend/catalog/postgres", |
| split(/ /,join(' src/include/catalog/',@allbki)) |
| ); |
| last; |
| } |
| } |
| |
| open(O, ">doc/src/sgml/version.sgml") || croak "Could not write to version.sgml\n"; |
| print O <<EOF; |
| <!entity version "$self->{strver}"> |
| <!entity majorversion "$self->{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 (<I>) |
| { |
| 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\zlib.lib'); |
| #$proj->AddLibrary($self->{options}->{zlib} . '\lib\zdll.lib'); |
| $proj->AddLibrary($self->{options}->{curl} . '\lib\libcurl.lib'); |
| } |
| if ($self->{options}->{bzlib}) |
| { |
| $proj->AddIncludeDir($self->{options}->{bzlib} . '\include'); |
| $proj->AddLibrary($self->{options}->{bzlib} . '\lib\libbz2.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 <<EOF; |
| Microsoft Visual Studio Solution File, Format Version 9.00 |
| # Visual Studio 2005 |
| EOF |
| |
| 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}.vcproj", "$proj->{guid}" |
| EndProject |
| EOF |
| } |
| if ($fld ne "") |
| { |
| $flduid{$fld} = Win32::GuidGen(); |
| 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); |
| } |
| |
| sub GetFakeConfigure |
| { |
| my $self = shift; |
| |
| my $cfg = '--enable-thread-safety'; |
| $cfg .= ' --enable-cassert' if ($self->{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; |