4 # Package that generates build files for msvc build
6 # $PostgreSQL: pgsql/src/tools/msvc/Mkvcbuild.pm,v 1.49 2010/01/20 04:14:06 adunstan Exp $
18 our (@ISA, @EXPORT_OK);
20 @EXPORT_OK = qw(Mkvcbuild);
27 my $contrib_defines = {'refint' => 'REFINT_VERBOSE'};
28 my @contrib_uselibpq = ('dblink', 'oid2name', 'pgbench', 'vacuumlo');
29 my @contrib_uselibpgport = ('oid2name', 'pgbench', 'pg_standby', 'vacuumlo');
30 my $contrib_extralibs = {'pgbench' => ['wsock32.lib']};
31 my $contrib_extraincludes = {'tsearch2' => ['contrib/tsearch2'], 'dblink' => ['src/backend']};
32 my $contrib_extrasource = {
33 'cube' => ['cubescan.l','cubeparse.y'],
34 'seg' => ['segscan.l','segparse.y']
36 my @contrib_excludes = ('pgcrypto','intagg');
42 chdir('..\..\..') if (-d '..\msvc' && -d '..\..\..\src');
43 die 'Must run from root or msvc directory' unless (-d 'src\tools\msvc' && -d 'src');
45 $solution = new Solution($config);
47 our @pgportfiles = qw(
48 chklocale.c crypt.c fseeko.c getrusage.c inet_aton.c random.c srandom.c
49 getaddrinfo.c gettimeofday.c kill.c open.c erand48.c
50 snprintf.c strlcat.c strlcpy.c copydir.c dirmod.c exec.c noblock.c path.c pipe.c
51 pgsleep.c pgstrcasecmp.c qsort.c qsort_arg.c sprompt.c thread.c
52 getopt.c getopt_long.c dirent.c rint.c win32env.c win32error.c);
54 $libpgport = $solution->AddProject('libpgport','lib','misc');
55 $libpgport->AddDefine('FRONTEND');
56 $libpgport->AddFiles('src\port',@pgportfiles);
58 $postgres = $solution->AddProject('postgres','exe','','src\backend');
59 $postgres->AddIncludeDir('src\backend');
60 $postgres->AddDir('src\backend\port\win32');
61 $postgres->AddFile('src\backend\utils\fmgrtab.c');
62 $postgres->ReplaceFile('src\backend\port\dynloader.c','src\backend\port\dynloader\win32.c');
63 $postgres->ReplaceFile('src\backend\port\pg_sema.c','src\backend\port\win32_sema.c');
64 $postgres->ReplaceFile('src\backend\port\pg_shmem.c','src\backend\port\win32_shmem.c');
65 $postgres->AddFiles('src\port',@pgportfiles);
66 $postgres->AddDir('src\timezone');
67 $postgres->AddFiles('src\backend\parser','scan.l','gram.y');
68 $postgres->AddFiles('src\backend\bootstrap','bootscanner.l','bootparse.y');
69 $postgres->AddFiles('src\backend\utils\misc','guc-file.l');
70 $postgres->AddDefine('BUILDING_DLL');
71 $postgres->AddLibrary('wsock32.lib');
72 $postgres->AddLibrary('ws2_32.lib');
73 $postgres->AddLibrary('secur32.lib');
74 $postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
75 $postgres->FullExportDLL('postgres.lib');
77 my $snowball = $solution->AddProject('dict_snowball','dll','','src\backend\snowball');
78 $snowball->RelocateFiles('src\backend\snowball\libstemmer', sub {
79 return shift !~ /dict_snowball.c$/;
81 $snowball->AddIncludeDir('src\include\snowball');
82 $snowball->AddReference($postgres);
84 my $plpgsql = $solution->AddProject('plpgsql','dll','PLs','src\pl\plpgsql\src');
85 $plpgsql->AddFiles('src\pl\plpgsql\src', 'gram.y');
86 $plpgsql->AddReference($postgres);
88 if ($solution->{options}->{perl})
90 my $plperlsrc = "src\\pl\\plperl\\";
91 my $plperl = $solution->AddProject('plperl','dll','PLs','src\pl\plperl');
92 $plperl->AddIncludeDir($solution->{options}->{perl} . '/lib/CORE');
93 $plperl->AddDefine('PLPERL_HAVE_UID_GID');
94 foreach my $xs ('SPI.xs', 'Util.xs')
96 (my $xsc = $xs) =~ s/\.xs/.c/;
97 if (Solution::IsNewer("$plperlsrc$xsc","$plperlsrc$xs"))
99 print "Building $plperlsrc$xsc...\n";
100 system( $solution->{options}->{perl}
102 . $solution->{options}->{perl}
103 . '/lib/ExtUtils/xsubpp -typemap '
104 . $solution->{options}->{perl}
105 . '/lib/ExtUtils/typemap '
108 if ((!(-f "$plperlsrc$xsc")) || -z "$plperlsrc$xsc")
110 unlink("$plperlsrc$xsc"); # if zero size
111 die "Failed to create $xsc.\n";
115 if ( Solution::IsNewer('src\pl\plperl\perlchunks.h','src\pl\plperl\plc_perlboot.pl')
116 ||Solution::IsNewer('src\pl\plperl\perlchunks.h','src\pl\plperl\plc_safe_bad.pl')
117 ||Solution::IsNewer('src\pl\plperl\perlchunks.h','src\pl\plperl\plc_safe_ok.pl'))
119 print 'Building src\pl\plperl\perlchunks.h ...' . "\n";
120 my $basedir = getcwd;
121 chdir 'src\pl\plperl';
122 system( $solution->{options}->{perl}
125 . '--strip="^(\#.*|\s*)$$" '
126 . 'plc_perlboot.pl plc_safe_bad.pl plc_safe_ok.pl '
129 if ((!(-f 'src\pl\plperl\perlchunks.h')) || -z 'src\pl\plperl\perlchunks.h')
131 unlink('src\pl\plperl\perlchunks.h'); # if zero size
132 die 'Failed to create perlchunks.h' . "\n";
135 $plperl->AddReference($postgres);
136 my @perl_libs = grep {/perl\d+.lib$/ }
137 glob($solution->{options}->{perl} . '\lib\CORE\perl*.lib');
140 $plperl->AddLibrary($perl_libs[0]);
144 die "could not identify perl library version";
148 if ($solution->{options}->{python})
150 my $plpython = $solution->AddProject('plpython','dll','PLs','src\pl\plpython');
151 $plpython->AddIncludeDir($solution->{options}->{python} . '\include');
152 $solution->{options}->{python} =~ /\\Python(\d{2})/i
153 || croak "Could not determine python version from path";
154 $plpython->AddLibrary($solution->{options}->{python} . "\\Libs\\python$1.lib");
155 $plpython->AddReference($postgres);
158 if ($solution->{options}->{tcl})
160 my $pltcl = $solution->AddProject('pltcl','dll','PLs','src\pl\tcl');
161 $pltcl->AddIncludeDir($solution->{options}->{tcl} . '\include');
162 $pltcl->AddReference($postgres);
163 if (-e $solution->{options}->{tcl} . '\lib\tcl85.lib')
165 $pltcl->AddLibrary($solution->{options}->{tcl} . '\lib\tcl85.lib');
169 $pltcl->AddLibrary($solution->{options}->{tcl} . '\lib\tcl84.lib');
173 $libpq = $solution->AddProject('libpq','dll','interfaces','src\interfaces\libpq');
174 $libpq->AddDefine('FRONTEND');
175 $libpq->AddDefine('UNSAFE_STAT_OK');
176 $libpq->AddIncludeDir('src\port');
177 $libpq->AddLibrary('wsock32.lib');
178 $libpq->AddLibrary('secur32.lib');
179 $libpq->AddLibrary('ws2_32.lib');
180 $libpq->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
181 $libpq->UseDef('src\interfaces\libpq\libpqdll.def');
182 $libpq->ReplaceFile('src\interfaces\libpq\libpqrc.c','src\interfaces\libpq\libpq.rc');
183 $libpq->AddReference($libpgport);
185 my $walreceiver = $solution->AddProject('walreceiver', 'dll', '', 'src\backend\replication\walreceiver');
186 $walreceiver->AddIncludeDir('src\interfaces\libpq');
187 $walreceiver->AddReference($postgres,$libpq);
190 $solution->AddProject('libpgtypes','dll','interfaces','src\interfaces\ecpg\pgtypeslib');
191 $pgtypes->AddDefine('FRONTEND');
192 $pgtypes->AddReference($libpgport);
193 $pgtypes->UseDef('src\interfaces\ecpg\pgtypeslib\pgtypeslib.def');
194 $pgtypes->AddIncludeDir('src\interfaces\ecpg\include');
196 my $libecpg =$solution->AddProject('libecpg','dll','interfaces','src\interfaces\ecpg\ecpglib');
197 $libecpg->AddDefine('FRONTEND');
198 $libecpg->AddIncludeDir('src\interfaces\ecpg\include');
199 $libecpg->AddIncludeDir('src\interfaces\libpq');
200 $libecpg->AddIncludeDir('src\port');
201 $libecpg->UseDef('src\interfaces\ecpg\ecpglib\ecpglib.def');
202 $libecpg->AddLibrary('wsock32.lib');
203 $libecpg->AddReference($libpq,$pgtypes,$libpgport);
206 $solution->AddProject('libecpg_compat','dll','interfaces','src\interfaces\ecpg\compatlib');
207 $libecpgcompat->AddIncludeDir('src\interfaces\ecpg\include');
208 $libecpgcompat->AddIncludeDir('src\interfaces\libpq');
209 $libecpgcompat->UseDef('src\interfaces\ecpg\compatlib\compatlib.def');
210 $libecpgcompat->AddReference($pgtypes,$libecpg,$libpgport);
212 my $ecpg = $solution->AddProject('ecpg','exe','interfaces','src\interfaces\ecpg\preproc');
213 $ecpg->AddIncludeDir('src\interfaces\ecpg\include');
214 $ecpg->AddIncludeDir('src\interfaces\libpq');
215 $ecpg->AddPrefixInclude('src\interfaces\ecpg\preproc');
216 $ecpg->AddFiles('src\interfaces\ecpg\preproc','pgc.l','preproc.y');
217 $ecpg->AddDefine('MAJOR_VERSION=4');
218 $ecpg->AddDefine('MINOR_VERSION=2');
219 $ecpg->AddDefine('PATCHLEVEL=1');
220 $ecpg->AddDefine('ECPG_COMPILE');
221 $ecpg->AddReference($libpgport);
223 my $pgregress_ecpg = $solution->AddProject('pg_regress_ecpg','exe','misc');
224 $pgregress_ecpg->AddFile('src\interfaces\ecpg\test\pg_regress_ecpg.c');
225 $pgregress_ecpg->AddFile('src\test\regress\pg_regress.c');
226 $pgregress_ecpg->AddIncludeDir('src\port');
227 $pgregress_ecpg->AddIncludeDir('src\test\regress');
228 $pgregress_ecpg->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
229 $pgregress_ecpg->AddDefine('FRONTEND');
230 $pgregress_ecpg->AddReference($libpgport);
233 my $initdb = AddSimpleFrontend('initdb');
234 $initdb->AddIncludeDir('src\interfaces\libpq');
235 $initdb->AddDefine('FRONTEND');
236 $initdb->AddLibrary('wsock32.lib');
237 $initdb->AddLibrary('ws2_32.lib');
239 my $pgconfig = AddSimpleFrontend('pg_config');
241 my $pgcontrol = AddSimpleFrontend('pg_controldata');
243 my $pgctl = AddSimpleFrontend('pg_ctl', 1);
245 my $pgreset = AddSimpleFrontend('pg_resetxlog');
247 my $pgevent = $solution->AddProject('pgevent','dll','bin');
248 $pgevent->AddFiles('src\bin\pgevent','pgevent.c','pgmsgevent.rc');
249 $pgevent->AddResourceFile('src\bin\pgevent','Eventlog message formatter');
250 $pgevent->RemoveFile('src\bin\pgevent\win32ver.rc');
251 $pgevent->UseDef('src\bin\pgevent\pgevent.def');
252 $pgevent->DisableLinkerWarnings('4104');
254 my $psql = AddSimpleFrontend('psql', 1);
255 $psql->AddIncludeDir('src\bin\pg_dump');
256 $psql->AddIncludeDir('src\backend');
257 $psql->AddFile('src\bin\psql\psqlscan.l');
259 my $pgdump = AddSimpleFrontend('pg_dump', 1);
260 $pgdump->AddIncludeDir('src\backend');
261 $pgdump->AddFile('src\bin\pg_dump\pg_dump.c');
262 $pgdump->AddFile('src\bin\pg_dump\common.c');
263 $pgdump->AddFile('src\bin\pg_dump\pg_dump_sort.c');
264 $pgdump->AddFile('src\bin\pg_dump\keywords.c');
265 $pgdump->AddFile('src\backend\parser\kwlookup.c');
267 my $pgdumpall = AddSimpleFrontend('pg_dump', 1);
268 $pgdumpall->{name} = 'pg_dumpall';
269 $pgdumpall->AddIncludeDir('src\backend');
270 $pgdumpall->AddFile('src\bin\pg_dump\pg_dumpall.c');
271 $pgdumpall->AddFile('src\bin\pg_dump\keywords.c');
272 $pgdumpall->AddFile('src\backend\parser\kwlookup.c');
274 my $pgrestore = AddSimpleFrontend('pg_dump', 1);
275 $pgrestore->{name} = 'pg_restore';
276 $pgrestore->AddIncludeDir('src\backend');
277 $pgrestore->AddFile('src\bin\pg_dump\pg_restore.c');
278 $pgrestore->AddFile('src\bin\pg_dump\keywords.c');
279 $pgrestore->AddFile('src\backend\parser\kwlookup.c');
281 my $zic = $solution->AddProject('zic','exe','utils');
282 $zic->AddFiles('src\timezone','zic.c','ialloc.c','scheck.c','localtime.c');
283 $zic->AddReference($libpgport);
285 if ($solution->{options}->{xml})
287 $contrib_extraincludes->{'pgxml'} = [
288 $solution->{options}->{xml} . '\include',
289 $solution->{options}->{xslt} . '\include',
290 $solution->{options}->{iconv} . '\include'
293 $contrib_extralibs->{'pgxml'} = [
294 $solution->{options}->{xml} . '\lib\libxml2.lib',
295 $solution->{options}->{xslt} . '\lib\libxslt.lib'
300 push @contrib_excludes,'xml2';
303 if (!$solution->{options}->{openssl})
305 push @contrib_excludes,'sslinfo';
308 if ($solution->{options}->{uuid})
310 $contrib_extraincludes->{'uuid-ossp'} = [ $solution->{options}->{uuid} . '\include' ];
311 $contrib_extralibs->{'uuid-ossp'} = [ $solution->{options}->{uuid} . '\lib\uuid.lib' ];
315 push @contrib_excludes,'uuid-ossp';
318 # Pgcrypto makefile too complex to parse....
319 my $pgcrypto = $solution->AddProject('pgcrypto','dll','crypto');
321 'contrib\pgcrypto','pgcrypto.c','px.c','px-hmac.c',
322 'px-crypt.c','crypt-gensalt.c','crypt-blowfish.c','crypt-des.c',
323 'crypt-md5.c','mbuf.c','pgp.c','pgp-armor.c',
324 'pgp-cfb.c','pgp-compress.c','pgp-decrypt.c','pgp-encrypt.c',
325 'pgp-info.c','pgp-mpi.c','pgp-pubdec.c','pgp-pubenc.c',
326 'pgp-pubkey.c','pgp-s2k.c','pgp-pgsql.c'
328 if ($solution->{options}->{openssl})
330 $pgcrypto->AddFiles('contrib\pgcrypto', 'openssl.c','pgp-mpi-openssl.c');
335 'contrib\pgcrypto', 'md5.c','sha1.c','sha2.c',
336 'internal.c','internal-sha2.c','blf.c','rijndael.c',
337 'fortuna.c','random.c','pgp-mpi-internal.c','imath.c'
340 $pgcrypto->AddReference($postgres);
341 $pgcrypto->AddLibrary('wsock32.lib');
342 my $mf = Project::read_file('contrib/pgcrypto/Makefile');
343 GenerateContribSqlFiles('pgcrypto', $mf);
346 opendir($D, 'contrib') || croak "Could not opendir on contrib!\n";
347 while (my $d = readdir($D))
349 next if ($d =~ /^\./);
350 next unless (-f "contrib/$d/Makefile");
351 next if (grep {/^$d$/} @contrib_excludes);
356 $mf = Project::read_file('src\backend\utils\mb\conversion_procs\Makefile');
357 $mf =~ s{\\s*[\r\n]+}{}mg;
358 $mf =~ m{SUBDIRS\s*=\s*(.*)$}m || die 'Could not match in conversion makefile' . "\n";
359 foreach my $sub (split /\s+/,$1)
361 my $mf = Project::read_file('src\backend\utils\mb\conversion_procs\\' . $sub . '\Makefile');
362 my $p = $solution->AddProject($sub, 'dll', 'conversion procs');
363 $p->AddFile('src\backend\utils\mb\conversion_procs\\' . $sub . '\\' . $sub . '.c');
364 if ($mf =~ m{^SRCS\s*\+=\s*(.*)$}m)
366 $p->AddFile('src\backend\utils\mb\conversion_procs\\' . $sub . '\\' . $1);
368 $p->AddReference($postgres);
371 $mf = Project::read_file('src\bin\scripts\Makefile');
372 $mf =~ s{\\s*[\r\n]+}{}mg;
373 $mf =~ m{PROGRAMS\s*=\s*(.*)$}m || die 'Could not match in bin\scripts\Makefile' . "\n";
374 foreach my $prg (split /\s+/,$1)
376 my $proj = $solution->AddProject($prg,'exe','bin');
377 $mf =~ m{$prg\s*:\s*(.*)$}m || die 'Could not find script define for $prg' . "\n";
378 my @files = split /\s+/,$1;
379 foreach my $f (@files)
382 if ($f eq 'keywords.c')
384 $proj->AddFile('src\bin\pg_dump\keywords.c');
386 elsif ($f eq 'kwlookup.c')
388 $proj->AddFile('src\backend\parser\kwlookup.c');
390 elsif ($f eq 'dumputils.c')
392 $proj->AddFile('src\bin\pg_dump\dumputils.c');
394 elsif ($f =~ /print\.c$/)
395 { # Also catches mbprint.c
396 $proj->AddFile('src\bin\psql\\' . $f);
400 $proj->AddFile('src\bin\scripts\\' . $f);
403 $proj->AddIncludeDir('src\interfaces\libpq');
404 $proj->AddIncludeDir('src\bin\pg_dump');
405 $proj->AddIncludeDir('src\bin\psql');
406 $proj->AddReference($libpq,$libpgport);
407 $proj->AddResourceFile('src\bin\scripts','PostgreSQL Utility');
410 # Regression DLL and EXE
411 my $regress = $solution->AddProject('regress','dll','misc');
412 $regress->AddFile('src\test\regress\regress.c');
413 $regress->AddReference($postgres);
415 my $pgregress = $solution->AddProject('pg_regress','exe','misc');
416 $pgregress->AddFile('src\test\regress\pg_regress.c');
417 $pgregress->AddFile('src\test\regress\pg_regress_main.c');
418 $pgregress->AddIncludeDir('src\port');
419 $pgregress->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
420 $pgregress->AddReference($libpgport);
425 #####################
426 # Utility functions #
427 #####################
429 # Add a simple frontend project (exe)
430 sub AddSimpleFrontend
435 my $p = $solution->AddProject($n,'exe','bin');
436 $p->AddDir('src\bin\\' . $n);
437 $p->AddReference($libpgport);
440 $p->AddIncludeDir('src\interfaces\libpq');
441 $p->AddReference($libpq);
446 # Add a simple contrib project
450 my $mf = Project::read_file('contrib\\' . $n . '\Makefile');
452 if ($mf =~ /^MODULE_big\s*=\s*(.*)$/mg)
455 $mf =~ s{\\\s*[\r\n]+}{}mg;
456 my $proj = $solution->AddProject($dn, 'dll', 'contrib');
457 $mf =~ /^OBJS\s*=\s*(.*)$/gm || croak "Could not find objects in MODULE_big for $n\n";
459 while ($objs =~ /\b([\w-]+\.o)\b/g)
463 $proj->AddFile('contrib\\' . $n . '\\' . $o);
465 $proj->AddReference($postgres);
466 if ($mf =~ /^SUBDIRS\s*:?=\s*(.*)$/mg)
468 foreach my $d (split /\s+/, $1)
470 my $mf2 = Project::read_file('contrib\\' . $n . '\\' . $d . '\Makefile');
471 $mf2 =~ s{\\\s*[\r\n]+}{}mg;
472 $mf2 =~ /^SUBOBJS\s*=\s*(.*)$/gm
473 || croak "Could not find objects in MODULE_big for $n, subdir $d\n";
475 while ($objs =~ /\b([\w-]+\.o)\b/g)
479 $proj->AddFile('contrib\\' . $n . '\\' . $d . '\\' . $o);
483 AdjustContribProj($proj);
485 elsif ($mf =~ /^MODULES\s*=\s*(.*)$/mg)
487 foreach my $mod (split /\s+/, $1)
489 my $proj = $solution->AddProject($mod, 'dll', 'contrib');
490 $proj->AddFile('contrib\\' . $n . '\\' . $mod . '.c');
491 $proj->AddReference($postgres);
492 AdjustContribProj($proj);
495 elsif ($mf =~ /^PROGRAM\s*=\s*(.*)$/mg)
497 my $proj = $solution->AddProject($1, 'exe', 'contrib');
498 $mf =~ /^OBJS\s*=\s*(.*)$/gm || croak "Could not find objects in MODULE_big for $n\n";
500 while ($objs =~ /\b([\w-]+\.o)\b/g)
504 $proj->AddFile('contrib\\' . $n . '\\' . $o);
506 AdjustContribProj($proj);
510 croak "Could not determine contrib module type for $n\n";
513 # Are there any output data files to build?
514 GenerateContribSqlFiles($n, $mf);
517 sub GenerateContribSqlFiles
521 if ($mf =~ /^DATA_built\s*=\s*(.*)$/mg)
525 # Strip out $(addsuffix) rules
526 if (index($l, '$(addsuffix ') >= 0)
530 for ($i = index($l, '$(addsuffix ') + 12; $i < length($l); $i++)
532 $pcount++ if (substr($l, $i, 1) eq '(');
533 $pcount-- if (substr($l, $i, 1) eq ')');
534 last if ($pcount < 0);
536 $l = substr($l, 0, index($l, '$(addsuffix ')) . substr($l, $i+1);
539 # Special case for contrib/spi
540 $l = "autoinc.sql insert_username.sql moddatetime.sql refint.sql timetravel.sql"
543 foreach my $d (split /\s+/, $l)
548 if (Solution::IsNewer("contrib/$n/$out", "contrib/$n/$in"))
550 print "Building $out from $in (contrib/$n)...\n";
551 my $cont = Project::read_file("contrib/$n/$in");
554 if ($mf =~ /^MODULE_big\s*=\s*(.*)$/m) { $dn = $1 }
555 $cont =~ s/MODULE_PATHNAME/\$libdir\/$dn/g;
557 open($o,">contrib/$n/$out") || croak "Could not write to contrib/$n/$d";
565 sub AdjustContribProj
568 my $n = $proj->{name};
570 if ($contrib_defines->{$n})
572 foreach my $d ($contrib_defines->{$n})
574 $proj->AddDefine($d);
577 if (grep {/^$n$/} @contrib_uselibpq)
579 $proj->AddIncludeDir('src\interfaces\libpq');
580 $proj->AddReference($libpq);
582 if (grep {/^$n$/} @contrib_uselibpgport)
584 $proj->AddReference($libpgport);
586 if ($contrib_extralibs->{$n})
588 foreach my $l (@{$contrib_extralibs->{$n}})
590 $proj->AddLibrary($l);
593 if ($contrib_extraincludes->{$n})
595 foreach my $i (@{$contrib_extraincludes->{$n}})
597 $proj->AddIncludeDir($i);
600 if ($contrib_extrasource->{$n})
602 $proj->AddFiles('contrib\\' . $n, @{$contrib_extrasource->{$n}});