package Mkvcbuild; use Carp; use Win32; use strict; use warnings; use Project; use Solution; use Exporter; our (@ISA, @EXPORT_OK); @ISA = qw(Exporter); @EXPORT_OK = qw(Mkvcbuild); my $solution; my $libpgport; my $postgres; my $libpq; my $contrib_defines = {'refint' => 'REFINT_VERBOSE'}; my @contrib_uselibpq = ('dblink', 'oid2name', 'pgbench', 'vacuumlo'); my @contrib_uselibpgport = ('oid2name', 'pgbench', 'pg_standby', 'vacuumlo'); my $contrib_extralibs = {'pgbench' => ['wsock32.lib']}; my $contrib_extraincludes = {'tsearch2' => ['contrib/tsearch2']}; my $contrib_extrasource = { 'cube' => ['cubescan.l','cubeparse.y'], 'seg' => ['segscan.l','segparse.y'] }; my @contrib_excludes = ('pgcrypto'); sub mkvcbuild { our $config = shift; chdir('..\..\..') if (-d '..\msvc' && -d '..\..\..\src'); die 'Must run from root or msvc directory' unless (-d 'src\tools\msvc' && -d 'src'); $solution = new Solution($config); our @pgportfiles = qw( crypt.c fseeko.c getrusage.c inet_aton.c random.c srandom.c unsetenv.c getaddrinfo.c gettimeofday.c kill.c open.c rand.c snprintf.c strlcat.c strlcpy.c copydir.c dirmod.c exec.c noblock.c path.c pipe.c pgsleep.c pgstrcasecmp.c qsort.c qsort_arg.c sprompt.c thread.c getopt.c getopt_long.c dirent.c rint.c win32error.c); $libpgport = $solution->AddProject('libpgport','lib','misc'); $libpgport->AddDefine('FRONTEND'); $libpgport->AddFiles('src\port',@pgportfiles); $postgres = $solution->AddProject('postgres','exe','','src\backend'); $postgres->AddIncludeDir('src\backend'); $postgres->AddDir('src\backend\port\win32'); $postgres->AddFile('src\backend\utils\fmgrtab.c'); $postgres->ReplaceFile('src\backend\port\dynloader.c','src\backend\port\dynloader\win32.c'); $postgres->ReplaceFile('src\backend\port\pg_sema.c','src\backend\port\win32_sema.c'); $postgres->ReplaceFile('src\backend\port\pg_shmem.c','src\backend\port\sysv_shmem.c'); $postgres->AddFiles('src\port',@pgportfiles); $postgres->AddDir('src\timezone'); $postgres->AddFiles('src\backend\parser','scan.l','gram.y'); $postgres->AddFiles('src\backend\bootstrap','bootscanner.l','bootparse.y'); $postgres->AddFiles('src\backend\utils\misc','guc-file.l'); $postgres->AddDefine('BUILDING_DLL'); $postgres->AddLibrary('wsock32.lib ws2_32.lib'); $postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap}); $postgres->FullExportDLL('postgres.lib'); my $plpgsql = $solution->AddProject('plpgsql','dll','PLs','src\pl\plpgsql\src'); $plpgsql->AddFiles('src\pl\plpgsql\src','scan.l','gram.y'); $plpgsql->AddReference($postgres); if ($solution->{options}->{perl}) { my $plperl = $solution->AddProject('plperl','dll','PLs','src\pl\plperl'); $plperl->AddIncludeDir($solution->{options}->{perl} . '/lib/CORE'); $plperl->AddDefine('PLPERL_HAVE_UID_GID'); if (Solution::IsNewer('src\pl\plperl\SPI.c','src\pl\plperl\SPI.xs')) { print 'Building src\pl\plperl\SPI.c...' . "\n"; system( $solution->{options}->{perl} . '/bin/perl ' . $solution->{options}->{perl} . '/lib/ExtUtils/xsubpp -typemap ' . $solution->{options}->{perl} . '/lib/ExtUtils/typemap src\pl\plperl\SPI.xs >src\pl\plperl\SPI.c'); if ((!(-f 'src\pl\plperl\SPI.c')) || -z 'src\pl\plperl\SPI.c') { unlink('src\pl\plperl\SPI.c'); # if zero size die 'Failed to create SPI.c' . "\n"; } } $plperl->AddReference($postgres); $plperl->AddLibrary($solution->{options}->{perl} . '\lib\CORE\perl58.lib'); } if ($solution->{options}->{python}) { my $plpython = $solution->AddProject('plpython','dll','PLs','src\pl\plpython'); $plpython->AddIncludeDir($solution->{options}->{python} . '\include'); $solution->{options}->{python} =~ /\\Python(\d{2})/i || croak "Could not determine python version from path"; $plpython->AddLibrary($solution->{options}->{python} . "\\Libs\\python$1.lib"); $plpython->AddReference($postgres); } if ($solution->{options}->{tcl}) { my $pltcl = $solution->AddProject('pltcl','dll','PLs','src\pl\tcl'); $pltcl->AddIncludeDir($solution->{options}->{tcl} . '\include'); $pltcl->AddReference($postgres); $pltcl->AddLibrary($solution->{options}->{tcl} . '\lib\tcl84.lib'); } $libpq = $solution->AddProject('libpq','dll','interfaces','src\interfaces\libpq'); $libpq->AddDefine('FRONTEND'); $libpq->AddIncludeDir('src\port'); $libpq->AddLibrary('wsock32.lib'); $libpq->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap}); $libpq->UseDef('src\interfaces\libpq\libpqdll.def'); $libpq->ReplaceFile('src\interfaces\libpq\libpqrc.c','src\interfaces\libpq\libpq.rc'); $libpq->AddReference($libpgport); my $pgtypes = $solution->AddProject('libpgtypes','dll','interfaces','src\interfaces\ecpg\pgtypeslib'); $pgtypes->AddDefine('FRONTEND'); $pgtypes->AddReference($postgres,$libpgport); $pgtypes->AddIncludeDir('src\interfaces\ecpg\include'); if ($config->{pthread}) { my $libecpg = $solution->AddProject('libecpg','dll','interfaces','src\interfaces\ecpg\ecpglib'); $libecpg->AddDefine('FRONTEND'); $libecpg->AddIncludeDir('src\interfaces\ecpg\include'); $libecpg->AddIncludeDir('src\interfaces\libpq'); $libecpg->AddIncludeDir('src\port'); $libecpg->AddLibrary('wsock32.lib'); $libecpg->AddLibrary($config->{'pthread'} . '\pthreadVC2.lib'); $libecpg->AddReference($libpq,$pgtypes); my $libecpgcompat = $solution->AddProject('libecpg_compat','dll','interfaces', 'src\interfaces\ecpg\compatlib'); $libecpgcompat->AddIncludeDir('src\interfaces\ecpg\include'); $libecpgcompat->AddIncludeDir('src\interfaces\libpq'); $libecpgcompat->AddReference($pgtypes,$libecpg); my $ecpg = $solution->AddProject('ecpg','exe','interfaces','src\interfaces\ecpg\preproc'); $ecpg->AddIncludeDir('src\interfaces\ecpg\include'); $ecpg->AddIncludeDir('src\interfaces\libpq'); $ecpg->AddFiles('src\interfaces\ecpg\preproc','pgc.l','preproc.y'); $ecpg->AddDefine('MAJOR_VERSION=4'); $ecpg->AddDefine('MINOR_VERSION=2'); $ecpg->AddDefine('PATCHLEVEL=1'); $ecpg->AddReference($libpgport); } else { print "Not building ecpg due to lack of pthreads.\n"; } # src/bin my $initdb = AddSimpleFrontend('initdb', 1); my $pgconfig = AddSimpleFrontend('pg_config'); my $pgcontrol = AddSimpleFrontend('pg_controldata'); my $pgctl = AddSimpleFrontend('pg_ctl', 1); my $pgreset = AddSimpleFrontend('pg_resetxlog'); my $pgevent = $solution->AddProject('pgevent','dll','bin'); $pgevent->AddFiles('src\bin\pgevent','pgevent.c','pgmsgevent.rc'); $pgevent->AddResourceFile('src\bin\pgevent','Eventlog message formatter'); $pgevent->RemoveFile('src\bin\pgevent\win32ver.rc'); $pgevent->UseDef('src\bin\pgevent\pgevent.def'); $pgevent->DisableLinkerWarnings('4104'); my $psql = AddSimpleFrontend('psql', 1); $psql->AddIncludeDir('src\bin\pg_dump'); $psql->AddFile('src\bin\psql\psqlscan.l'); my $pgdump = AddSimpleFrontend('pg_dump', 1); $pgdump->AddFile('src\bin\pg_dump\pg_dump.c'); $pgdump->AddFile('src\bin\pg_dump\common.c'); $pgdump->AddFile('src\bin\pg_dump\pg_dump_sort.c'); my $pgdumpall = AddSimpleFrontend('pg_dump', 1); $pgdumpall->{name} = 'pg_dumpall'; $pgdumpall->AddFile('src\bin\pg_dump\pg_dumpall.c'); my $pgrestore = AddSimpleFrontend('pg_dump', 1); $pgrestore->{name} = 'pg_restore'; $pgrestore->AddFile('src\bin\pg_dump\pg_restore.c'); my $zic = $solution->AddProject('zic','exe','utils'); $zic->AddFiles('src\timezone','zic.c','ialloc.c','scheck.c','localtime.c'); $zic->AddReference($libpgport); if ($solution->{options}->{xml}) { $contrib_extraincludes->{'xml2'} = [ $solution->{options}->{xml} . '\include', $solution->{options}->{xslt} . '\include', $solution->{options}->{iconv} . '\include' ]; $contrib_extralibs->{'xml2'} = [ $solution->{options}->{xml} . '\lib\libxml2.lib', $solution->{options}->{xslt} . '\lib\libxslt.lib' ]; } else { push @contrib_excludes,'xml2'; } if (!$solution->{options}->{openssl}) { push @contrib_excludes,'sslinfo'; } # Pgcrypto makefile too complex to parse.... my $pgcrypto = $solution->AddProject('pgcrypto','dll','crypto'); $pgcrypto->AddFiles( 'contrib\pgcrypto','pgcrypto.c','px.c','px-hmac.c', 'px-crypt.c','crypt-gensalt.c','crypt-blowfish.c','crypt-des.c', 'crypt-md5.c','mbuf.c','pgp.c','pgp-armor.c', 'pgp-cfb.c','pgp-compress.c','pgp-decrypt.c','pgp-encrypt.c', 'pgp-info.c','pgp-mpi.c','pgp-pubdec.c','pgp-pubenc.c', 'pgp-pubkey.c','pgp-s2k.c','pgp-pgsql.c' ); if ($solution->{options}->{openssl}) { $pgcrypto->AddFiles('contrib\pgcrypto', 'openssl.c','pgp-mpi-openssl.c'); } else { $pgcrypto->AddFiles( 'contrib\pgcrypto', 'md5.c','sha1.c','sha2.c', 'internal.c','internal-sha2.c','blf.c','rijndael.c', 'fortuna.c','random.c','pgp-mpi-internal.c','imath.c' ); } $pgcrypto->AddReference($postgres); $pgcrypto->AddLibrary('wsock32.lib'); my $D; opendir($D, 'contrib') || croak "Could not opendir on contrib!\n"; while (my $d = readdir($D)) { next if ($d =~ /^\./); next unless (-f "contrib/$d/Makefile"); next if (grep {/^$d$/} @contrib_excludes); AddContrib($d); } closedir($D); my $mf = Project::read_file('src\backend\utils\mb\conversion_procs\Makefile'); $mf =~ s{\\s*[\r\n]+}{}mg; $mf =~ m{DIRS\s*=\s*(.*)$}m || die 'Could not match in conversion makefile' . "\n"; foreach my $sub (split /\s+/,$1) { my $mf = Project::read_file('src\backend\utils\mb\conversion_procs\\' . $sub . '\Makefile'); my $p = $solution->AddProject($sub, 'dll', 'conversion procs'); $p->AddFile('src\backend\utils\mb\conversion_procs\\' . $sub . '\\' . $sub . '.c'); if ($mf =~ m{^SRCS\s*\+=\s*(.*)$}m) { $p->AddFile('src\backend\utils\mb\conversion_procs\\' . $sub . '\\' . $1); } $p->AddReference($postgres); } $mf = Project::read_file('src\bin\scripts\Makefile'); $mf =~ s{\\s*[\r\n]+}{}mg; $mf =~ m{PROGRAMS\s*=\s*(.*)$}m || die 'Could not match in bin\scripts\Makefile' . "\n"; foreach my $prg (split /\s+/,$1) { my $proj = $solution->AddProject($prg,'exe','bin'); $mf =~ m{$prg\s*:\s*(.*)$}m || die 'Could not find script define for $prg' . "\n"; my @files = split /\s+/,$1; foreach my $f (@files) { if ($f =~ /\/keywords\.o$/) { $proj->AddFile('src\backend\parser\keywords.c'); } else { $f =~ s/\.o$/\.c/; if ($f eq 'dumputils.c') { $proj->AddFile('src\bin\pg_dump\dumputils.c'); } elsif ($f =~ /print\.c$/) { # Also catches mbprint.c $proj->AddFile('src\bin\psql\\' . $f); } else { $proj->AddFile('src\bin\scripts\\' . $f); } } } $proj->AddIncludeDir('src\interfaces\libpq'); $proj->AddIncludeDir('src\bin\pg_dump'); $proj->AddIncludeDir('src\bin\psql'); $proj->AddReference($libpq,$libpgport); $proj->AddResourceFile('src\bin\scripts','PostgreSQL Utility'); } # Regression DLL and EXE my $regress = $solution->AddProject('regress','dll','misc'); $regress->AddFile('src\test\regress\regress.c'); $regress->AddReference($postgres); my $pgregress = $solution->AddProject('pg_regress','exe','misc'); $pgregress->AddFile('src\test\regress\pg_regress.c'); $pgregress->AddIncludeDir('src\port'); $pgregress->AddDefine('HOST_TUPLE="i686-pc-win32vc"'); $pgregress->AddDefine('FRONTEND'); $pgregress->AddReference($libpgport); $solution->Save(); } ##################### # Utility functions # ##################### # Add a simple frontend project (exe) sub AddSimpleFrontend { my $n = shift; my $uselibpq= shift; my $p = $solution->AddProject($n,'exe','bin'); $p->AddDir('src\bin\\' . $n); $p->AddDefine('FRONTEND'); $p->AddReference($libpgport); if ($uselibpq) { $p->AddIncludeDir('src\interfaces\libpq'); $p->AddReference($libpq); } return $p; } # Add a simple contrib project sub AddContrib { my $n = shift; my $mf = Project::read_file('contrib\\' . $n . '\Makefile'); if ($mf =~ /^MODULE_big/mg) { $mf =~ s{\\\s*[\r\n]+}{}mg; my $proj = $solution->AddProject($n, 'dll', 'contrib'); $mf =~ /^OBJS\s*=\s*(.*)$/gm || croak "Could not find objects in MODULE_big for $n\n"; foreach my $o (split /\s+/, $1) { $o =~ s/\.o$/.c/; $proj->AddFile('contrib\\' . $n . '\\' . $o); } $proj->AddReference($postgres); if ($mf =~ /^SUBDIRS\s*:?=\s*(.*)$/mg) { foreach my $d (split /\s+/, $1) { my $mf2 = Project::read_file('contrib\\' . $n . '\\' . $d . '\Makefile'); $mf2 =~ s{\\\s*[\r\n]+}{}mg; $mf2 =~ /^SUBOBJS\s*=\s*(.*)$/gm || croak "Could not find objects in MODULE_big for $n, subdir $d\n"; foreach my $o (split /\s+/, $1) { $o =~ s/\.o$/.c/; $proj->AddFile('contrib\\' . $n . '\\' . $d . '\\' . $o); } } } AdjustContribProj($proj); return $proj; } elsif ($mf =~ /^MODULES\s*=\s*(.*)$/mg) { foreach my $mod (split /\s+/, $1) { my $proj = $solution->AddProject($mod, 'dll', 'contrib'); $proj->AddFile('contrib\\' . $n . '\\' . $mod . '.c'); $proj->AddReference($postgres); AdjustContribProj($proj); } return undef; } elsif ($mf =~ /^PROGRAM\s*=\s*(.*)$/mg) { my $proj = $solution->AddProject($1, 'exe', 'contrib'); $mf =~ /^OBJS\s*=\s*(.*)$/gm || croak "Could not find objects in MODULE_big for $n\n"; foreach my $o (split /\s+/, $1) { $o =~ s/\.o$/.c/; $proj->AddFile('contrib\\' . $n . '\\' . $o); } AdjustContribProj($proj); return $proj; } else { croak "Could not determine contrib module type for $n\n"; } } sub AdjustContribProj { my $proj = shift; my $n = $proj->{name}; if ($contrib_defines->{$n}) { foreach my $d ($contrib_defines->{$n}) { $proj->AddDefine($d); } } if (grep {/^$n$/} @contrib_uselibpq) { $proj->AddIncludeDir('src\interfaces\libpq'); $proj->AddReference($libpq); } if (grep {/^$n$/} @contrib_uselibpgport) { $proj->AddReference($libpgport); } if ($contrib_extralibs->{$n}) { foreach my $l (@{$contrib_extralibs->{$n}}) { $proj->AddLibrary($l); } } if ($contrib_extraincludes->{$n}) { foreach my $i (@{$contrib_extraincludes->{$n}}) { $proj->AddIncludeDir($i); } } if ($contrib_extrasource->{$n}) { $proj->AddFiles('contrib\\' . $n, @{$contrib_extrasource->{$n}}); } } 1;