4 # Package that generates build files for msvc build
6 # $PostgreSQL: pgsql/src/tools/msvc/Mkvcbuild.pm,v 1.35 2008/12/20 22:04:02 mha Exp $
16 our (@ISA, @EXPORT_OK);
18 @EXPORT_OK = qw(Mkvcbuild);
25 my $contrib_defines = {'refint' => 'REFINT_VERBOSE'};
26 my @contrib_uselibpq = ('dblink', 'oid2name', 'pgbench', 'vacuumlo');
27 my @contrib_uselibpgport = ('oid2name', 'pgbench', 'pg_standby', 'vacuumlo');
28 my $contrib_extralibs = {'pgbench' => ['wsock32.lib']};
29 my $contrib_extraincludes = {'tsearch2' => ['contrib/tsearch2']};
30 my $contrib_extrasource = {
31 'cube' => ['cubescan.l','cubeparse.y'],
32 'seg' => ['segscan.l','segparse.y']
34 my @contrib_excludes = ('pgcrypto','intagg');
40 chdir('..\..\..') if (-d '..\msvc' && -d '..\..\..\src');
41 die 'Must run from root or msvc directory' unless (-d 'src\tools\msvc' && -d 'src');
43 $solution = new Solution($config);
45 our @pgportfiles = qw(
46 chklocale.c crypt.c fseeko.c getrusage.c inet_aton.c random.c srandom.c
47 unsetenv.c getaddrinfo.c gettimeofday.c kill.c open.c rand.c
48 snprintf.c strlcat.c strlcpy.c copydir.c dirmod.c exec.c noblock.c path.c pipe.c
49 pgsleep.c pgstrcasecmp.c qsort.c qsort_arg.c sprompt.c thread.c
50 getopt.c getopt_long.c dirent.c rint.c win32error.c);
52 $libpgport = $solution->AddProject('libpgport','lib','misc');
53 $libpgport->AddDefine('FRONTEND');
54 $libpgport->AddFiles('src\port',@pgportfiles);
56 $postgres = $solution->AddProject('postgres','exe','','src\backend');
57 $postgres->AddIncludeDir('src\backend');
58 $postgres->AddDir('src\backend\port\win32');
59 $postgres->AddFile('src\backend\utils\fmgrtab.c');
60 $postgres->ReplaceFile('src\backend\port\dynloader.c','src\backend\port\dynloader\win32.c');
61 $postgres->ReplaceFile('src\backend\port\pg_sema.c','src\backend\port\win32_sema.c');
62 $postgres->ReplaceFile('src\backend\port\pg_shmem.c','src\backend\port\win32_shmem.c');
63 $postgres->AddFiles('src\port',@pgportfiles);
64 $postgres->AddDir('src\timezone');
65 $postgres->AddFiles('src\backend\parser','scan.l','gram.y');
66 $postgres->AddFiles('src\backend\bootstrap','bootscanner.l','bootparse.y');
67 $postgres->AddFiles('src\backend\utils\misc','guc-file.l');
68 $postgres->AddDefine('BUILDING_DLL');
69 $postgres->AddLibrary('wsock32.lib');
70 $postgres->AddLibrary('ws2_32.lib');
71 $postgres->AddLibrary('secur32.lib');
72 $postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
73 $postgres->FullExportDLL('postgres.lib');
75 my $snowball = $solution->AddProject('dict_snowball','dll','','src\backend\snowball');
76 $snowball->RelocateFiles('src\backend\snowball\libstemmer', sub {
77 return shift !~ /dict_snowball.c$/;
79 $snowball->AddIncludeDir('src\include\snowball');
80 $snowball->AddReference($postgres);
82 my $plpgsql = $solution->AddProject('plpgsql','dll','PLs','src\pl\plpgsql\src');
83 $plpgsql->AddFiles('src\pl\plpgsql\src','scan.l','gram.y');
84 $plpgsql->AddReference($postgres);
86 if ($solution->{options}->{perl})
88 my $plperl = $solution->AddProject('plperl','dll','PLs','src\pl\plperl');
89 $plperl->AddIncludeDir($solution->{options}->{perl} . '/lib/CORE');
90 $plperl->AddDefine('PLPERL_HAVE_UID_GID');
91 if (Solution::IsNewer('src\pl\plperl\SPI.c','src\pl\plperl\SPI.xs'))
93 print 'Building src\pl\plperl\SPI.c...' . "\n";
94 system( $solution->{options}->{perl}
96 . $solution->{options}->{perl}
97 . '/lib/ExtUtils/xsubpp -typemap '
98 . $solution->{options}->{perl}
99 . '/lib/ExtUtils/typemap src\pl\plperl\SPI.xs >src\pl\plperl\SPI.c');
100 if ((!(-f 'src\pl\plperl\SPI.c')) || -z 'src\pl\plperl\SPI.c')
102 unlink('src\pl\plperl\SPI.c'); # if zero size
103 die 'Failed to create SPI.c' . "\n";
106 $plperl->AddReference($postgres);
107 $plperl->AddLibrary($solution->{options}->{perl} . '\lib\CORE\perl58.lib');
110 if ($solution->{options}->{python})
112 my $plpython = $solution->AddProject('plpython','dll','PLs','src\pl\plpython');
113 $plpython->AddIncludeDir($solution->{options}->{python} . '\include');
114 $solution->{options}->{python} =~ /\\Python(\d{2})/i
115 || croak "Could not determine python version from path";
116 $plpython->AddLibrary($solution->{options}->{python} . "\\Libs\\python$1.lib");
117 $plpython->AddReference($postgres);
120 if ($solution->{options}->{tcl})
122 my $pltcl = $solution->AddProject('pltcl','dll','PLs','src\pl\tcl');
123 $pltcl->AddIncludeDir($solution->{options}->{tcl} . '\include');
124 $pltcl->AddReference($postgres);
125 $pltcl->AddLibrary($solution->{options}->{tcl} . '\lib\tcl84.lib');
128 $libpq = $solution->AddProject('libpq','dll','interfaces','src\interfaces\libpq');
129 $libpq->AddDefine('FRONTEND');
130 $libpq->AddDefine('UNSAFE_STAT_OK');
131 $libpq->AddIncludeDir('src\port');
132 $libpq->AddLibrary('wsock32.lib');
133 $libpq->AddLibrary('secur32.lib');
134 $libpq->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
135 $libpq->UseDef('src\interfaces\libpq\libpqdll.def');
136 $libpq->ReplaceFile('src\interfaces\libpq\libpqrc.c','src\interfaces\libpq\libpq.rc');
137 $libpq->AddReference($libpgport);
140 $solution->AddProject('libpgtypes','dll','interfaces','src\interfaces\ecpg\pgtypeslib');
141 $pgtypes->AddDefine('FRONTEND');
142 $pgtypes->AddReference($libpgport);
143 $pgtypes->UseDef('src\interfaces\ecpg\pgtypeslib\pgtypeslib.def');
144 $pgtypes->AddIncludeDir('src\interfaces\ecpg\include');
146 my $libecpg =$solution->AddProject('libecpg','dll','interfaces','src\interfaces\ecpg\ecpglib');
147 $libecpg->AddDefine('FRONTEND');
148 $libecpg->AddIncludeDir('src\interfaces\ecpg\include');
149 $libecpg->AddIncludeDir('src\interfaces\libpq');
150 $libecpg->AddIncludeDir('src\port');
151 $libecpg->UseDef('src\interfaces\ecpg\ecpglib\ecpglib.def');
152 $libecpg->AddLibrary('wsock32.lib');
153 $libecpg->AddReference($libpq,$pgtypes,$libpgport);
156 $solution->AddProject('libecpg_compat','dll','interfaces','src\interfaces\ecpg\compatlib');
157 $libecpgcompat->AddIncludeDir('src\interfaces\ecpg\include');
158 $libecpgcompat->AddIncludeDir('src\interfaces\libpq');
159 $libecpgcompat->UseDef('src\interfaces\ecpg\compatlib\compatlib.def');
160 $libecpgcompat->AddReference($pgtypes,$libecpg,$libpgport);
162 my $ecpg = $solution->AddProject('ecpg','exe','interfaces','src\interfaces\ecpg\preproc');
163 $ecpg->AddIncludeDir('src\interfaces\ecpg\include');
164 $ecpg->AddIncludeDir('src\interfaces\libpq');
165 $ecpg->AddPrefixInclude('src\interfaces\ecpg\preproc');
166 $ecpg->AddFiles('src\interfaces\ecpg\preproc','pgc.l','preproc.y');
167 $ecpg->AddDefine('MAJOR_VERSION=4');
168 $ecpg->AddDefine('MINOR_VERSION=2');
169 $ecpg->AddDefine('PATCHLEVEL=1');
170 $ecpg->AddDefine('ECPG_COMPILE');
171 $ecpg->AddReference($libpgport);
173 my $pgregress_ecpg = $solution->AddProject('pg_regress_ecpg','exe','misc');
174 $pgregress_ecpg->AddFile('src\interfaces\ecpg\test\pg_regress_ecpg.c');
175 $pgregress_ecpg->AddFile('src\test\regress\pg_regress.c');
176 $pgregress_ecpg->AddIncludeDir('src\port');
177 $pgregress_ecpg->AddIncludeDir('src\test\regress');
178 $pgregress_ecpg->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
179 $pgregress_ecpg->AddDefine('FRONTEND');
180 $pgregress_ecpg->AddReference($libpgport);
183 my $initdb = AddSimpleFrontend('initdb');
184 $initdb->AddIncludeDir('src\interfaces\libpq');
185 $initdb->AddDefine('FRONTEND');
186 $initdb->AddLibrary('wsock32.lib');
187 $initdb->AddLibrary('ws2_32.lib');
189 my $pgconfig = AddSimpleFrontend('pg_config');
191 my $pgcontrol = AddSimpleFrontend('pg_controldata');
193 my $pgctl = AddSimpleFrontend('pg_ctl', 1);
195 my $pgreset = AddSimpleFrontend('pg_resetxlog');
197 my $pgevent = $solution->AddProject('pgevent','dll','bin');
198 $pgevent->AddFiles('src\bin\pgevent','pgevent.c','pgmsgevent.rc');
199 $pgevent->AddResourceFile('src\bin\pgevent','Eventlog message formatter');
200 $pgevent->RemoveFile('src\bin\pgevent\win32ver.rc');
201 $pgevent->UseDef('src\bin\pgevent\pgevent.def');
202 $pgevent->DisableLinkerWarnings('4104');
204 my $psql = AddSimpleFrontend('psql', 1);
205 $psql->AddIncludeDir('src\bin\pg_dump');
206 $psql->AddIncludeDir('src\backend');
207 $psql->AddFile('src\bin\psql\psqlscan.l');
209 my $pgdump = AddSimpleFrontend('pg_dump', 1);
210 $pgdump->AddIncludeDir('src\backend');
211 $pgdump->AddFile('src\bin\pg_dump\pg_dump.c');
212 $pgdump->AddFile('src\bin\pg_dump\common.c');
213 $pgdump->AddFile('src\bin\pg_dump\pg_dump_sort.c');
215 my $pgdumpall = AddSimpleFrontend('pg_dump', 1);
216 $pgdumpall->{name} = 'pg_dumpall';
217 $pgdumpall->AddIncludeDir('src\backend');
218 $pgdumpall->AddFile('src\bin\pg_dump\pg_dumpall.c');
220 my $pgrestore = AddSimpleFrontend('pg_dump', 1);
221 $pgrestore->{name} = 'pg_restore';
222 $pgrestore->AddIncludeDir('src\backend');
223 $pgrestore->AddFile('src\bin\pg_dump\pg_restore.c');
225 my $zic = $solution->AddProject('zic','exe','utils');
226 $zic->AddFiles('src\timezone','zic.c','ialloc.c','scheck.c','localtime.c');
227 $zic->AddReference($libpgport);
229 if ($solution->{options}->{xml})
231 $contrib_extraincludes->{'pgxml'} = [
232 $solution->{options}->{xml} . '\include',
233 $solution->{options}->{xslt} . '\include',
234 $solution->{options}->{iconv} . '\include'
237 $contrib_extralibs->{'pgxml'} = [
238 $solution->{options}->{xml} . '\lib\libxml2.lib',
239 $solution->{options}->{xslt} . '\lib\libxslt.lib'
244 push @contrib_excludes,'xml2';
247 if (!$solution->{options}->{openssl})
249 push @contrib_excludes,'sslinfo';
252 if ($solution->{options}->{uuid})
254 $contrib_extraincludes->{'uuid-ossp'} = [ $solution->{options}->{uuid} . '\include' ];
255 $contrib_extralibs->{'uuid-ossp'} = [ $solution->{options}->{uuid} . '\lib\uuid.lib' ];
259 push @contrib_excludes,'uuid-ossp';
262 # Pgcrypto makefile too complex to parse....
263 my $pgcrypto = $solution->AddProject('pgcrypto','dll','crypto');
265 'contrib\pgcrypto','pgcrypto.c','px.c','px-hmac.c',
266 'px-crypt.c','crypt-gensalt.c','crypt-blowfish.c','crypt-des.c',
267 'crypt-md5.c','mbuf.c','pgp.c','pgp-armor.c',
268 'pgp-cfb.c','pgp-compress.c','pgp-decrypt.c','pgp-encrypt.c',
269 'pgp-info.c','pgp-mpi.c','pgp-pubdec.c','pgp-pubenc.c',
270 'pgp-pubkey.c','pgp-s2k.c','pgp-pgsql.c'
272 if ($solution->{options}->{openssl})
274 $pgcrypto->AddFiles('contrib\pgcrypto', 'openssl.c','pgp-mpi-openssl.c');
279 'contrib\pgcrypto', 'md5.c','sha1.c','sha2.c',
280 'internal.c','internal-sha2.c','blf.c','rijndael.c',
281 'fortuna.c','random.c','pgp-mpi-internal.c','imath.c'
284 $pgcrypto->AddReference($postgres);
285 $pgcrypto->AddLibrary('wsock32.lib');
286 my $mf = Project::read_file('contrib/pgcrypto/Makefile');
287 GenerateContribSqlFiles('pgcrypto', $mf);
290 opendir($D, 'contrib') || croak "Could not opendir on contrib!\n";
291 while (my $d = readdir($D))
293 next if ($d =~ /^\./);
294 next unless (-f "contrib/$d/Makefile");
295 next if (grep {/^$d$/} @contrib_excludes);
300 $mf = Project::read_file('src\backend\utils\mb\conversion_procs\Makefile');
301 $mf =~ s{\\s*[\r\n]+}{}mg;
302 $mf =~ m{DIRS\s*=\s*(.*)$}m || die 'Could not match in conversion makefile' . "\n";
303 foreach my $sub (split /\s+/,$1)
305 my $mf = Project::read_file('src\backend\utils\mb\conversion_procs\\' . $sub . '\Makefile');
306 my $p = $solution->AddProject($sub, 'dll', 'conversion procs');
307 $p->AddFile('src\backend\utils\mb\conversion_procs\\' . $sub . '\\' . $sub . '.c');
308 if ($mf =~ m{^SRCS\s*\+=\s*(.*)$}m)
310 $p->AddFile('src\backend\utils\mb\conversion_procs\\' . $sub . '\\' . $1);
312 $p->AddReference($postgres);
315 $mf = Project::read_file('src\backend\foreign\Makefile');
316 $mf =~ s{\\s*[\r\n]+}{}mg;
317 $mf =~ m{FDW\s*=\s*(.*)$}m || die 'Could not match in foreign makefile' . "\n";
318 foreach my $foreign (split /\s+/,$1)
320 my $proj = $solution->AddProject($foreign . '_fdw', 'dll', 'foreign', 'src\backend\foreign\\' . $foreign);
321 $proj->AddReference($postgres);
324 $mf = Project::read_file('src\bin\scripts\Makefile');
325 $mf =~ s{\\s*[\r\n]+}{}mg;
326 $mf =~ m{PROGRAMS\s*=\s*(.*)$}m || die 'Could not match in bin\scripts\Makefile' . "\n";
327 foreach my $prg (split /\s+/,$1)
329 my $proj = $solution->AddProject($prg,'exe','bin');
330 $mf =~ m{$prg\s*:\s*(.*)$}m || die 'Could not find script define for $prg' . "\n";
331 my @files = split /\s+/,$1;
332 foreach my $f (@files)
334 if ($f =~ /\/keywords\.o$/)
336 $proj->AddFile('src\backend\parser\keywords.c');
337 $proj->AddIncludeDir('src\backend');
342 if ($f eq 'dumputils.c')
344 $proj->AddFile('src\bin\pg_dump\dumputils.c');
346 elsif ($f =~ /print\.c$/)
347 { # Also catches mbprint.c
348 $proj->AddFile('src\bin\psql\\' . $f);
352 $proj->AddFile('src\bin\scripts\\' . $f);
356 $proj->AddIncludeDir('src\interfaces\libpq');
357 $proj->AddIncludeDir('src\bin\pg_dump');
358 $proj->AddIncludeDir('src\bin\psql');
359 $proj->AddReference($libpq,$libpgport);
360 $proj->AddResourceFile('src\bin\scripts','PostgreSQL Utility');
363 # Regression DLL and EXE
364 my $regress = $solution->AddProject('regress','dll','misc');
365 $regress->AddFile('src\test\regress\regress.c');
366 $regress->AddReference($postgres);
368 my $pgregress = $solution->AddProject('pg_regress','exe','misc');
369 $pgregress->AddFile('src\test\regress\pg_regress.c');
370 $pgregress->AddFile('src\test\regress\pg_regress_main.c');
371 $pgregress->AddIncludeDir('src\port');
372 $pgregress->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
373 $pgregress->AddReference($libpgport);
378 #####################
379 # Utility functions #
380 #####################
382 # Add a simple frontend project (exe)
383 sub AddSimpleFrontend
388 my $p = $solution->AddProject($n,'exe','bin');
389 $p->AddDir('src\bin\\' . $n);
390 $p->AddReference($libpgport);
393 $p->AddIncludeDir('src\interfaces\libpq');
394 $p->AddReference($libpq);
399 # Add a simple contrib project
403 my $mf = Project::read_file('contrib\\' . $n . '\Makefile');
405 if ($mf =~ /^MODULE_big\s*=\s*(.*)$/mg)
408 $mf =~ s{\\\s*[\r\n]+}{}mg;
409 my $proj = $solution->AddProject($dn, 'dll', 'contrib');
410 $mf =~ /^OBJS\s*=\s*(.*)$/gm || croak "Could not find objects in MODULE_big for $n\n";
412 while ($objs =~ /\b([\w-]+\.o)\b/g)
416 $proj->AddFile('contrib\\' . $n . '\\' . $o);
418 $proj->AddReference($postgres);
419 if ($mf =~ /^SUBDIRS\s*:?=\s*(.*)$/mg)
421 foreach my $d (split /\s+/, $1)
423 my $mf2 = Project::read_file('contrib\\' . $n . '\\' . $d . '\Makefile');
424 $mf2 =~ s{\\\s*[\r\n]+}{}mg;
425 $mf2 =~ /^SUBOBJS\s*=\s*(.*)$/gm
426 || croak "Could not find objects in MODULE_big for $n, subdir $d\n";
428 while ($objs =~ /\b([\w-]+\.o)\b/g)
432 $proj->AddFile('contrib\\' . $n . '\\' . $d . '\\' . $o);
436 AdjustContribProj($proj);
438 elsif ($mf =~ /^MODULES\s*=\s*(.*)$/mg)
440 foreach my $mod (split /\s+/, $1)
442 my $proj = $solution->AddProject($mod, 'dll', 'contrib');
443 $proj->AddFile('contrib\\' . $n . '\\' . $mod . '.c');
444 $proj->AddReference($postgres);
445 AdjustContribProj($proj);
448 elsif ($mf =~ /^PROGRAM\s*=\s*(.*)$/mg)
450 my $proj = $solution->AddProject($1, 'exe', 'contrib');
451 $mf =~ /^OBJS\s*=\s*(.*)$/gm || croak "Could not find objects in MODULE_big for $n\n";
453 while ($objs =~ /\b([\w-]+\.o)\b/g)
457 $proj->AddFile('contrib\\' . $n . '\\' . $o);
459 AdjustContribProj($proj);
463 croak "Could not determine contrib module type for $n\n";
466 # Are there any output data files to build?
467 GenerateContribSqlFiles($n, $mf);
470 sub GenerateContribSqlFiles
474 if ($mf =~ /^DATA_built\s*=\s*(.*)$/mg)
478 # Strip out $(addsuffix) rules
479 if (index($l, '$(addsuffix ') >= 0)
483 for ($i = index($l, '$(addsuffix ') + 12; $i < length($l); $i++)
485 $pcount++ if (substr($l, $i, 1) eq '(');
486 $pcount-- if (substr($l, $i, 1) eq ')');
487 last if ($pcount < 0);
489 $l = substr($l, 0, index($l, '$(addsuffix ')) . substr($l, $i+1);
492 # Special case for contrib/spi
493 $l = "autoinc.sql insert_username.sql moddatetime.sql refint.sql timetravel.sql"
496 foreach my $d (split /\s+/, $l)
501 if (Solution::IsNewer("contrib/$n/$out", "contrib/$n/$in"))
503 print "Building $out from $in (contrib/$n)...\n";
504 my $cont = Project::read_file("contrib/$n/$in");
507 if ($mf =~ /^MODULE_big\s*=\s*(.*)$/m) { $dn = $1 }
508 $cont =~ s/MODULE_PATHNAME/\$libdir\/$dn/g;
510 open($o,">contrib/$n/$out") || croak "Could not write to contrib/$n/$d";
518 sub AdjustContribProj
521 my $n = $proj->{name};
523 if ($contrib_defines->{$n})
525 foreach my $d ($contrib_defines->{$n})
527 $proj->AddDefine($d);
530 if (grep {/^$n$/} @contrib_uselibpq)
532 $proj->AddIncludeDir('src\interfaces\libpq');
533 $proj->AddReference($libpq);
535 if (grep {/^$n$/} @contrib_uselibpgport)
537 $proj->AddReference($libpgport);
539 if ($contrib_extralibs->{$n})
541 foreach my $l (@{$contrib_extralibs->{$n}})
543 $proj->AddLibrary($l);
546 if ($contrib_extraincludes->{$n})
548 foreach my $i (@{$contrib_extraincludes->{$n}})
550 $proj->AddIncludeDir($i);
553 if ($contrib_extrasource->{$n})
555 $proj->AddFiles('contrib\\' . $n, @{$contrib_extrasource->{$n}});