]> granicus.if.org Git - postgresql/blob - src/tools/msvc/Mkvcbuild.pm
Move psql's print.c and mbprint.c into src/fe_utils.
[postgresql] / src / tools / msvc / Mkvcbuild.pm
1 package Mkvcbuild;
2
3 #
4 # Package that generates build files for msvc build
5 #
6 # src/tools/msvc/Mkvcbuild.pm
7 #
8 use Carp;
9 use Win32;
10 use strict;
11 use warnings;
12 use Project;
13 use Solution;
14 use Cwd;
15 use File::Copy;
16 use Config;
17 use VSObjectFactory;
18 use List::Util qw(first);
19
20 use Exporter;
21 our (@ISA, @EXPORT_OK);
22 @ISA       = qw(Exporter);
23 @EXPORT_OK = qw(Mkvcbuild);
24
25 my $solution;
26 my $libpgport;
27 my $libpgcommon;
28 my $libpgfeutils;
29 my $postgres;
30 my $libpq;
31
32 # Set of variables for modules in contrib/ and src/test/modules/
33 my $contrib_defines = { 'refint' => 'REFINT_VERBOSE' };
34 my @contrib_uselibpq = ('dblink', 'oid2name', 'postgres_fdw', 'vacuumlo');
35 my @contrib_uselibpgport   = ('oid2name', 'pg_standby', 'vacuumlo');
36 my @contrib_uselibpgcommon = ('oid2name', 'pg_standby', 'vacuumlo');
37 my $contrib_extralibs      = undef;
38 my $contrib_extraincludes =
39   { 'tsearch2' => ['contrib/tsearch2'], 'dblink' => ['src/backend'] };
40 my $contrib_extrasource = {
41         'cube' => [ 'contrib/cube/cubescan.l', 'contrib/cube/cubeparse.y' ],
42         'seg'  => [ 'contrib/seg/segscan.l',   'contrib/seg/segparse.y' ], };
43 my @contrib_excludes = (
44         'commit_ts',      'hstore_plperl', 'hstore_plpython', 'intagg',
45         'ltree_plpython', 'pgcrypto',      'sepgsql',         'brin',
46         'test_extensions');
47
48 # Set of variables for frontend modules
49 my $frontend_defines = { 'initdb' => 'FRONTEND' };
50 my @frontend_uselibpq = ('pg_ctl', 'pg_upgrade', 'pgbench', 'psql');
51 my @frontend_uselibpgport = (
52         'pg_archivecleanup', 'pg_test_fsync',
53         'pg_test_timing',    'pg_upgrade',
54         'pg_xlogdump',       'pgbench');
55 my @frontend_uselibpgcommon = (
56         'pg_archivecleanup', 'pg_test_fsync',
57         'pg_test_timing',    'pg_upgrade',
58         'pg_xlogdump',       'pgbench');
59 my $frontend_extralibs = {
60         'initdb'     => ['ws2_32.lib'],
61         'pg_restore' => ['ws2_32.lib'],
62         'pgbench'    => ['ws2_32.lib'],
63         'psql'       => ['ws2_32.lib'] };
64 my $frontend_extraincludes = {
65         'initdb' => ['src/timezone'],
66         'psql'   => [ 'src/backend' ],
67         'pgbench' => [ 'src/bin/psql' ] };
68 my $frontend_extrasource = {
69         'psql' => ['src/bin/psql/psqlscan.l', 'src/bin/psql/psqlscanslash.l'],
70         'pgbench' =>
71           [ 'src/bin/pgbench/exprscan.l', 'src/bin/pgbench/exprparse.y',
72             'src/bin/psql/psqlscan.l' ] };
73 my @frontend_excludes = (
74         'pgevent',     'pg_basebackup', 'pg_rewind', 'pg_dump',
75         'pg_xlogdump', 'scripts',       'pgbench');
76
77 sub mkvcbuild
78 {
79         our $config = shift;
80
81         chdir('../../..') if (-d '../msvc' && -d '../../../src');
82         die 'Must run from root or msvc directory'
83           unless (-d 'src/tools/msvc' && -d 'src');
84
85         my $vsVersion = DetermineVisualStudioVersion();
86
87         $solution = CreateSolution($vsVersion, $config);
88
89         our @pgportfiles = qw(
90           chklocale.c crypt.c fls.c fseeko.c getrusage.c inet_aton.c random.c
91           srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c
92           erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
93           pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c
94           mkdtemp.c qsort.c qsort_arg.c quotes.c system.c
95           sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c
96           win32env.c win32error.c win32security.c win32setlocale.c);
97
98         push(@pgportfiles, 'rint.c') if ($vsVersion < '12.00');
99
100         if ($vsVersion >= '9.00')
101         {
102                 push(@pgportfiles, 'pg_crc32c_choose.c');
103                 push(@pgportfiles, 'pg_crc32c_sse42.c');
104                 push(@pgportfiles, 'pg_crc32c_sb8.c');
105         }
106         else
107         {
108                 push(@pgportfiles, 'pg_crc32c_sb8.c');
109         }
110
111         our @pgcommonallfiles = qw(
112           config_info.c controldata_utils.c exec.c keywords.c
113           pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c
114           string.c username.c wait_error.c);
115
116         our @pgcommonfrontendfiles = (
117                 @pgcommonallfiles, qw(fe_memutils.c
118                   restricted_token.c));
119
120         our @pgcommonbkndfiles = @pgcommonallfiles;
121
122         our @pgfeutilsfiles = qw(
123           mbprint.c print.c simple_list.c string_utils.c);
124
125         $libpgport = $solution->AddProject('libpgport', 'lib', 'misc');
126         $libpgport->AddDefine('FRONTEND');
127         $libpgport->AddFiles('src/port', @pgportfiles);
128
129         $libpgcommon = $solution->AddProject('libpgcommon', 'lib', 'misc');
130         $libpgcommon->AddDefine('FRONTEND');
131         $libpgcommon->AddFiles('src/common', @pgcommonfrontendfiles);
132
133         $libpgfeutils = $solution->AddProject('libpgfeutils', 'lib', 'misc');
134         $libpgfeutils->AddDefine('FRONTEND');
135         $libpgfeutils->AddIncludeDir('src/interfaces/libpq');
136         $libpgfeutils->AddFiles('src/fe_utils', @pgfeutilsfiles);
137
138         $postgres = $solution->AddProject('postgres', 'exe', '', 'src/backend');
139         $postgres->AddIncludeDir('src/backend');
140         $postgres->AddDir('src/backend/port/win32');
141         $postgres->AddFile('src/backend/utils/fmgrtab.c');
142         $postgres->ReplaceFile(
143                 'src/backend/port/dynloader.c',
144                 'src/backend/port/dynloader/win32.c');
145         $postgres->ReplaceFile('src/backend/port/pg_sema.c',
146                 'src/backend/port/win32_sema.c');
147         $postgres->ReplaceFile('src/backend/port/pg_shmem.c',
148                 'src/backend/port/win32_shmem.c');
149         $postgres->AddFiles('src/port',   @pgportfiles);
150         $postgres->AddFiles('src/common', @pgcommonbkndfiles);
151         $postgres->AddDir('src/timezone');
152
153         # We need source files from src/timezone, but that directory's resource
154         # file pertains to "zic", not to the backend.
155         $postgres->RemoveFile('src/timezone/win32ver.rc');
156         $postgres->AddFiles('src/backend/parser', 'scan.l', 'gram.y');
157         $postgres->AddFiles('src/backend/bootstrap', 'bootscanner.l',
158                 'bootparse.y');
159         $postgres->AddFiles('src/backend/utils/misc', 'guc-file.l');
160         $postgres->AddFiles('src/backend/replication', 'repl_scanner.l',
161                 'repl_gram.y');
162         $postgres->AddDefine('BUILDING_DLL');
163         $postgres->AddLibrary('secur32.lib');
164         $postgres->AddLibrary('ws2_32.lib');
165         $postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
166         $postgres->FullExportDLL('postgres.lib');
167
168    # The OBJS scraper doesn't know about ifdefs, so remove be-secure-openssl.c
169    # if building without OpenSSL
170         if (!$solution->{options}->{openssl})
171         {
172                 $postgres->RemoveFile('src/backend/libpq/be-secure-openssl.c');
173         }
174
175         my $snowball = $solution->AddProject('dict_snowball', 'dll', '',
176                 'src/backend/snowball');
177
178         # This Makefile uses VPATH to find most source files in a subdirectory.
179         $snowball->RelocateFiles(
180                 'src/backend/snowball/libstemmer',
181                 sub {
182                         return shift !~ /(dict_snowball.c|win32ver.rc)$/;
183                 });
184         $snowball->AddIncludeDir('src/include/snowball');
185         $snowball->AddReference($postgres);
186
187         my $plpgsql =
188           $solution->AddProject('plpgsql', 'dll', 'PLs', 'src/pl/plpgsql/src');
189         $plpgsql->AddFiles('src/pl/plpgsql/src', 'pl_gram.y');
190         $plpgsql->AddReference($postgres);
191
192         if ($solution->{options}->{tcl})
193         {
194                 my $pltcl =
195                   $solution->AddProject('pltcl', 'dll', 'PLs', 'src/pl/tcl');
196                 $pltcl->AddIncludeDir($solution->{options}->{tcl} . '/include');
197                 $pltcl->AddReference($postgres);
198                 if (-e $solution->{options}->{tcl} . '/lib/tcl85.lib')
199                 {
200                         $pltcl->AddLibrary(
201                                 $solution->{options}->{tcl} . '/lib/tcl85.lib');
202                 }
203                 else
204                 {
205                         $pltcl->AddLibrary(
206                                 $solution->{options}->{tcl} . '/lib/tcl84.lib');
207                 }
208         }
209
210         $libpq = $solution->AddProject('libpq', 'dll', 'interfaces',
211                 'src/interfaces/libpq');
212         $libpq->AddDefine('FRONTEND');
213         $libpq->AddDefine('UNSAFE_STAT_OK');
214         $libpq->AddIncludeDir('src/port');
215         $libpq->AddLibrary('secur32.lib');
216         $libpq->AddLibrary('ws2_32.lib');
217         $libpq->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
218         $libpq->UseDef('src/interfaces/libpq/libpqdll.def');
219         $libpq->ReplaceFile('src/interfaces/libpq/libpqrc.c',
220                 'src/interfaces/libpq/libpq.rc');
221         $libpq->AddReference($libpgport);
222
223    # The OBJS scraper doesn't know about ifdefs, so remove fe-secure-openssl.c
224    # if building without OpenSSL
225         if (!$solution->{options}->{openssl})
226         {
227                 $libpq->RemoveFile('src/interfaces/libpq/fe-secure-openssl.c');
228         }
229
230         my $libpqwalreceiver =
231           $solution->AddProject('libpqwalreceiver', 'dll', '',
232                 'src/backend/replication/libpqwalreceiver');
233         $libpqwalreceiver->AddIncludeDir('src/interfaces/libpq');
234         $libpqwalreceiver->AddReference($postgres, $libpq);
235
236         my $pgtypes = $solution->AddProject(
237                 'libpgtypes', 'dll',
238                 'interfaces', 'src/interfaces/ecpg/pgtypeslib');
239         $pgtypes->AddDefine('FRONTEND');
240         $pgtypes->AddReference($libpgport);
241         $pgtypes->UseDef('src/interfaces/ecpg/pgtypeslib/pgtypeslib.def');
242         $pgtypes->AddIncludeDir('src/interfaces/ecpg/include');
243
244         my $libecpg = $solution->AddProject('libecpg', 'dll', 'interfaces',
245                 'src/interfaces/ecpg/ecpglib');
246         $libecpg->AddDefine('FRONTEND');
247         $libecpg->AddIncludeDir('src/interfaces/ecpg/include');
248         $libecpg->AddIncludeDir('src/interfaces/libpq');
249         $libecpg->AddIncludeDir('src/port');
250         $libecpg->UseDef('src/interfaces/ecpg/ecpglib/ecpglib.def');
251         $libecpg->AddLibrary('ws2_32.lib');
252         $libecpg->AddReference($libpq, $pgtypes, $libpgport);
253
254         my $libecpgcompat = $solution->AddProject(
255                 'libecpg_compat', 'dll',
256                 'interfaces',     'src/interfaces/ecpg/compatlib');
257         $libecpgcompat->AddDefine('FRONTEND');
258         $libecpgcompat->AddIncludeDir('src/interfaces/ecpg/include');
259         $libecpgcompat->AddIncludeDir('src/interfaces/libpq');
260         $libecpgcompat->UseDef('src/interfaces/ecpg/compatlib/compatlib.def');
261         $libecpgcompat->AddReference($pgtypes, $libecpg, $libpgport);
262
263         my $ecpg = $solution->AddProject('ecpg', 'exe', 'interfaces',
264                 'src/interfaces/ecpg/preproc');
265         $ecpg->AddIncludeDir('src/interfaces/ecpg/include');
266         $ecpg->AddIncludeDir('src/interfaces/libpq');
267         $ecpg->AddPrefixInclude('src/interfaces/ecpg/preproc');
268         $ecpg->AddFiles('src/interfaces/ecpg/preproc', 'pgc.l', 'preproc.y');
269         $ecpg->AddDefine('MAJOR_VERSION=4');
270         $ecpg->AddDefine('MINOR_VERSION=12');
271         $ecpg->AddDefine('PATCHLEVEL=0');
272         $ecpg->AddDefine('ECPG_COMPILE');
273         $ecpg->AddReference($libpgcommon, $libpgport);
274
275         my $pgregress_ecpg =
276           $solution->AddProject('pg_regress_ecpg', 'exe', 'misc');
277         $pgregress_ecpg->AddFile('src/interfaces/ecpg/test/pg_regress_ecpg.c');
278         $pgregress_ecpg->AddFile('src/test/regress/pg_regress.c');
279         $pgregress_ecpg->AddIncludeDir('src/port');
280         $pgregress_ecpg->AddIncludeDir('src/test/regress');
281         $pgregress_ecpg->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
282         $pgregress_ecpg->AddLibrary('ws2_32.lib');
283         $pgregress_ecpg->AddDirResourceFile('src/interfaces/ecpg/test');
284         $pgregress_ecpg->AddReference($libpgcommon, $libpgport);
285
286         my $isolation_tester =
287           $solution->AddProject('isolationtester', 'exe', 'misc');
288         $isolation_tester->AddFile('src/test/isolation/isolationtester.c');
289         $isolation_tester->AddFile('src/test/isolation/specparse.y');
290         $isolation_tester->AddFile('src/test/isolation/specscanner.l');
291         $isolation_tester->AddFile('src/test/isolation/specparse.c');
292         $isolation_tester->AddIncludeDir('src/test/isolation');
293         $isolation_tester->AddIncludeDir('src/port');
294         $isolation_tester->AddIncludeDir('src/test/regress');
295         $isolation_tester->AddIncludeDir('src/interfaces/libpq');
296         $isolation_tester->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
297         $isolation_tester->AddLibrary('ws2_32.lib');
298         $isolation_tester->AddDirResourceFile('src/test/isolation');
299         $isolation_tester->AddReference($libpq, $libpgcommon, $libpgport);
300
301         my $pgregress_isolation =
302           $solution->AddProject('pg_isolation_regress', 'exe', 'misc');
303         $pgregress_isolation->AddFile('src/test/isolation/isolation_main.c');
304         $pgregress_isolation->AddFile('src/test/regress/pg_regress.c');
305         $pgregress_isolation->AddIncludeDir('src/port');
306         $pgregress_isolation->AddIncludeDir('src/test/regress');
307         $pgregress_isolation->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
308         $pgregress_isolation->AddLibrary('ws2_32.lib');
309         $pgregress_isolation->AddDirResourceFile('src/test/isolation');
310         $pgregress_isolation->AddReference($libpgcommon, $libpgport);
311
312         # src/bin
313         my $D;
314         opendir($D, 'src/bin') || croak "Could not opendir on src/bin!\n";
315         while (my $d = readdir($D))
316         {
317                 next if ($d =~ /^\./);
318                 next unless (-f "src/bin/$d/Makefile");
319                 next if (grep { /^$d$/ } @frontend_excludes);
320                 AddSimpleFrontend($d);
321         }
322
323         my $pgbasebackup = AddSimpleFrontend('pg_basebackup', 1);
324         $pgbasebackup->AddFile('src/bin/pg_basebackup/pg_basebackup.c');
325         $pgbasebackup->AddLibrary('ws2_32.lib');
326
327         my $pgreceivexlog = AddSimpleFrontend('pg_basebackup', 1);
328         $pgreceivexlog->{name} = 'pg_receivexlog';
329         $pgreceivexlog->AddFile('src/bin/pg_basebackup/pg_receivexlog.c');
330         $pgreceivexlog->AddLibrary('ws2_32.lib');
331
332         my $pgrecvlogical = AddSimpleFrontend('pg_basebackup', 1);
333         $pgrecvlogical->{name} = 'pg_recvlogical';
334         $pgrecvlogical->AddFile('src/bin/pg_basebackup/pg_recvlogical.c');
335         $pgrecvlogical->AddLibrary('ws2_32.lib');
336
337         my $pgrewind = AddSimpleFrontend('pg_rewind', 1);
338         $pgrewind->{name} = 'pg_rewind';
339         $pgrewind->AddFile('src/backend/access/transam/xlogreader.c');
340         $pgrewind->AddLibrary('ws2_32.lib');
341         $pgrewind->AddDefine('FRONTEND');
342
343         my $pgevent = $solution->AddProject('pgevent', 'dll', 'bin');
344         $pgevent->AddFiles('src/bin/pgevent', 'pgevent.c', 'pgmsgevent.rc');
345         $pgevent->AddResourceFile('src/bin/pgevent', 'Eventlog message formatter',
346                 'win32');
347         $pgevent->RemoveFile('src/bin/pgevent/win32ver.rc');
348         $pgevent->UseDef('src/bin/pgevent/pgevent.def');
349         $pgevent->DisableLinkerWarnings('4104');
350
351         my $pgdump = AddSimpleFrontend('pg_dump', 1);
352         $pgdump->AddIncludeDir('src/backend');
353         $pgdump->AddFile('src/bin/pg_dump/pg_dump.c');
354         $pgdump->AddFile('src/bin/pg_dump/common.c');
355         $pgdump->AddFile('src/bin/pg_dump/pg_dump_sort.c');
356         $pgdump->AddLibrary('ws2_32.lib');
357
358         my $pgdumpall = AddSimpleFrontend('pg_dump', 1);
359
360         # pg_dumpall doesn't use the files in the Makefile's $(OBJS), unlike
361         # pg_dump and pg_restore.
362         # So remove their sources from the object, keeping the other setup that
363         # AddSimpleFrontend() has done.
364         my @nodumpall = grep { m!src/bin/pg_dump/.*\.c$! }
365           keys %{ $pgdumpall->{files} };
366         delete @{ $pgdumpall->{files} }{@nodumpall};
367         $pgdumpall->{name} = 'pg_dumpall';
368         $pgdumpall->AddIncludeDir('src/backend');
369         $pgdumpall->AddFile('src/bin/pg_dump/pg_dumpall.c');
370         $pgdumpall->AddFile('src/bin/pg_dump/dumputils.c');
371         $pgdumpall->AddLibrary('ws2_32.lib');
372
373         my $pgrestore = AddSimpleFrontend('pg_dump', 1);
374         $pgrestore->{name} = 'pg_restore';
375         $pgrestore->AddIncludeDir('src/backend');
376         $pgrestore->AddFile('src/bin/pg_dump/pg_restore.c');
377         $pgrestore->AddLibrary('ws2_32.lib');
378
379         my $zic = $solution->AddProject('zic', 'exe', 'utils');
380         $zic->AddFiles('src/timezone', 'zic.c', 'ialloc.c', 'scheck.c',
381                 'localtime.c');
382         $zic->AddDirResourceFile('src/timezone');
383         $zic->AddReference($libpgcommon, $libpgport);
384
385         if ($solution->{options}->{xml})
386         {
387                 $contrib_extraincludes->{'pgxml'} = [
388                         $solution->{options}->{xml} . '/include',
389                         $solution->{options}->{xslt} . '/include',
390                         $solution->{options}->{iconv} . '/include' ];
391
392                 $contrib_extralibs->{'pgxml'} = [
393                         $solution->{options}->{xml} . '/lib/libxml2.lib',
394                         $solution->{options}->{xslt} . '/lib/libxslt.lib' ];
395         }
396         else
397         {
398                 push @contrib_excludes, 'xml2';
399         }
400
401         if (!$solution->{options}->{openssl})
402         {
403                 push @contrib_excludes, 'sslinfo';
404         }
405
406         if ($solution->{options}->{uuid})
407         {
408                 $contrib_extraincludes->{'uuid-ossp'} =
409                   [ $solution->{options}->{uuid} . '/include' ];
410                 $contrib_extralibs->{'uuid-ossp'} =
411                   [ $solution->{options}->{uuid} . '/lib/uuid.lib' ];
412         }
413         else
414         {
415                 push @contrib_excludes, 'uuid-ossp';
416         }
417
418         # AddProject() does not recognize the constructs used to populate OBJS in
419         # the pgcrypto Makefile, so it will discover no files.
420         my $pgcrypto =
421           $solution->AddProject('pgcrypto', 'dll', 'crypto', 'contrib/pgcrypto');
422         $pgcrypto->AddFiles(
423                 'contrib/pgcrypto', 'pgcrypto.c',
424                 'px.c',             'px-hmac.c',
425                 'px-crypt.c',       'crypt-gensalt.c',
426                 'crypt-blowfish.c', 'crypt-des.c',
427                 'crypt-md5.c',      'mbuf.c',
428                 'pgp.c',            'pgp-armor.c',
429                 'pgp-cfb.c',        'pgp-compress.c',
430                 'pgp-decrypt.c',    'pgp-encrypt.c',
431                 'pgp-info.c',       'pgp-mpi.c',
432                 'pgp-pubdec.c',     'pgp-pubenc.c',
433                 'pgp-pubkey.c',     'pgp-s2k.c',
434                 'pgp-pgsql.c');
435         if ($solution->{options}->{openssl})
436         {
437                 $pgcrypto->AddFiles('contrib/pgcrypto', 'openssl.c',
438                         'pgp-mpi-openssl.c');
439         }
440         else
441         {
442                 $pgcrypto->AddFiles(
443                         'contrib/pgcrypto',   'md5.c',
444                         'sha1.c',             'sha2.c',
445                         'internal.c',         'internal-sha2.c',
446                         'blf.c',              'rijndael.c',
447                         'fortuna.c',          'random.c',
448                         'pgp-mpi-internal.c', 'imath.c');
449         }
450         $pgcrypto->AddReference($postgres);
451         $pgcrypto->AddLibrary('ws2_32.lib');
452         my $mf = Project::read_file('contrib/pgcrypto/Makefile');
453         GenerateContribSqlFiles('pgcrypto', $mf);
454
455         foreach my $subdir ('contrib', 'src/test/modules')
456         {
457                 opendir($D, $subdir) || croak "Could not opendir on $subdir!\n";
458                 while (my $d = readdir($D))
459                 {
460                         next if ($d =~ /^\./);
461                         next unless (-f "$subdir/$d/Makefile");
462                         next if (grep { /^$d$/ } @contrib_excludes);
463                         AddContrib($subdir, $d);
464                 }
465                 closedir($D);
466         }
467
468         # Build Perl and Python modules after contrib/ modules to satisfy some
469         # dependencies with transform contrib modules, like hstore_plpython
470         # ltree_plpython and hstore_plperl.
471         if ($solution->{options}->{python})
472         {
473
474                 # Attempt to get python version and location.
475                 # Assume python.exe in specified dir.
476                 my $pythonprog = "import sys;print(sys.prefix);"
477                   . "print(str(sys.version_info[0])+str(sys.version_info[1]))";
478                 my $prefixcmd =
479                   $solution->{options}->{python} . "\\python -c \"$pythonprog\"";
480                 my $pyout = `$prefixcmd`;
481                 die "Could not query for python version!\n" if $?;
482                 my ($pyprefix, $pyver) = split(/\r?\n/, $pyout);
483
484                 # Sometimes (always?) if python is not present, the execution
485                 # appears to work, but gives no data...
486                 die "Failed to query python for version information\n"
487                   if (!(defined($pyprefix) && defined($pyver)));
488
489                 my $pymajorver = substr($pyver, 0, 1);
490                 my $plpython = $solution->AddProject('plpython' . $pymajorver,
491                         'dll', 'PLs', 'src/pl/plpython');
492                 $plpython->AddIncludeDir($pyprefix . '/include');
493                 $plpython->AddLibrary($pyprefix . "/Libs/python$pyver.lib");
494                 $plpython->AddReference($postgres);
495
496                 # Add transform modules dependent on plpython
497                 AddTransformModule(
498                         'hstore_plpython' . $pymajorver, 'contrib/hstore_plpython',
499                         'plpython' . $pymajorver,        'src/pl/plpython',
500                         'hstore',                        'contrib/hstore');
501                 AddTransformModule(
502                         'ltree_plpython' . $pymajorver, 'contrib/ltree_plpython',
503                         'plpython' . $pymajorver,       'src/pl/plpython',
504                         'ltree',                        'contrib/ltree');
505         }
506
507         if ($solution->{options}->{perl})
508         {
509                 my $plperlsrc = "src/pl/plperl/";
510                 my $plperl =
511                   $solution->AddProject('plperl', 'dll', 'PLs', 'src/pl/plperl');
512                 $plperl->AddIncludeDir($solution->{options}->{perl} . '/lib/CORE');
513                 $plperl->AddDefine('PLPERL_HAVE_UID_GID');
514                 foreach my $xs ('SPI.xs', 'Util.xs')
515                 {
516                         (my $xsc = $xs) =~ s/\.xs/.c/;
517                         if (Solution::IsNewer("$plperlsrc$xsc", "$plperlsrc$xs"))
518                         {
519                                 my $xsubppdir = first { -e "$_/ExtUtils/xsubpp" } @INC;
520                                 print "Building $plperlsrc$xsc...\n";
521                                 system( $solution->{options}->{perl}
522                                           . '/bin/perl '
523                                           . "$xsubppdir/ExtUtils/xsubpp -typemap "
524                                           . $solution->{options}->{perl}
525                                           . '/lib/ExtUtils/typemap '
526                                           . "$plperlsrc$xs "
527                                           . ">$plperlsrc$xsc");
528                                 if ((!(-f "$plperlsrc$xsc")) || -z "$plperlsrc$xsc")
529                                 {
530                                         unlink("$plperlsrc$xsc");    # if zero size
531                                         die "Failed to create $xsc.\n";
532                                 }
533                         }
534                 }
535                 if (Solution::IsNewer(
536                                 'src/pl/plperl/perlchunks.h',
537                                 'src/pl/plperl/plc_perlboot.pl')
538                         || Solution::IsNewer(
539                                 'src/pl/plperl/perlchunks.h',
540                                 'src/pl/plperl/plc_trusted.pl'))
541                 {
542                         print 'Building src/pl/plperl/perlchunks.h ...' . "\n";
543                         my $basedir = getcwd;
544                         chdir 'src/pl/plperl';
545                         system( $solution->{options}->{perl}
546                                   . '/bin/perl '
547                                   . 'text2macro.pl '
548                                   . '--strip="^(\#.*|\s*)$$" '
549                                   . 'plc_perlboot.pl plc_trusted.pl '
550                                   . '>perlchunks.h');
551                         chdir $basedir;
552                         if ((!(-f 'src/pl/plperl/perlchunks.h'))
553                                 || -z 'src/pl/plperl/perlchunks.h')
554                         {
555                                 unlink('src/pl/plperl/perlchunks.h');    # if zero size
556                                 die 'Failed to create perlchunks.h' . "\n";
557                         }
558                 }
559                 if (Solution::IsNewer(
560                                 'src/pl/plperl/plperl_opmask.h',
561                                 'src/pl/plperl/plperl_opmask.pl'))
562                 {
563                         print 'Building src/pl/plperl/plperl_opmask.h ...' . "\n";
564                         my $basedir = getcwd;
565                         chdir 'src/pl/plperl';
566                         system( $solution->{options}->{perl}
567                                   . '/bin/perl '
568                                   . 'plperl_opmask.pl '
569                                   . 'plperl_opmask.h');
570                         chdir $basedir;
571                         if ((!(-f 'src/pl/plperl/plperl_opmask.h'))
572                                 || -z 'src/pl/plperl/plperl_opmask.h')
573                         {
574                                 unlink('src/pl/plperl/plperl_opmask.h');    # if zero size
575                                 die 'Failed to create plperl_opmask.h' . "\n";
576                         }
577                 }
578                 $plperl->AddReference($postgres);
579                 my @perl_libs =
580                   grep { /perl\d+.lib$/ }
581                   glob($solution->{options}->{perl} . '\lib\CORE\perl*.lib');
582                 if (@perl_libs == 1)
583                 {
584                         $plperl->AddLibrary($perl_libs[0]);
585                 }
586                 else
587                 {
588                         die "could not identify perl library version";
589                 }
590
591                 # Add transform module dependent on plperl
592                 my $hstore_plperl = AddTransformModule(
593                         'hstore_plperl', 'contrib/hstore_plperl',
594                         'plperl',        'src/pl/plperl',
595                         'hstore',        'contrib/hstore');
596                 $hstore_plperl->AddDefine('PLPERL_HAVE_UID_GID');
597         }
598
599         $mf =
600           Project::read_file('src/backend/utils/mb/conversion_procs/Makefile');
601         $mf =~ s{\\\r?\n}{}g;
602         $mf =~ m{SUBDIRS\s*=\s*(.*)$}m
603           || die 'Could not match in conversion makefile' . "\n";
604         foreach my $sub (split /\s+/, $1)
605         {
606                 my $dir = 'src/backend/utils/mb/conversion_procs/' . $sub;
607                 my $p = $solution->AddProject($sub, 'dll', 'conversion procs', $dir);
608                 $p->AddFile("$dir/$sub.c");    # implicit source file
609                 $p->AddReference($postgres);
610         }
611
612         $mf = Project::read_file('src/bin/scripts/Makefile');
613         $mf =~ s{\\\r?\n}{}g;
614         $mf =~ m{PROGRAMS\s*=\s*(.*)$}m
615           || die 'Could not match in bin/scripts/Makefile' . "\n";
616         foreach my $prg (split /\s+/, $1)
617         {
618                 my $proj = $solution->AddProject($prg, 'exe', 'bin');
619                 $mf =~ m{$prg\s*:\s*(.*)$}m
620                   || die 'Could not find script define for $prg' . "\n";
621                 my @files = split /\s+/, $1;
622                 foreach my $f (@files)
623                 {
624                         $f =~ s/\.o$/\.c/;
625                         if ($f =~ /\.c$/)
626                         {
627                                 $proj->AddFile('src/bin/scripts/' . $f);
628                         }
629                 }
630                 $proj->AddIncludeDir('src/interfaces/libpq');
631                 $proj->AddReference($libpq, $libpgfeutils, $libpgcommon,
632                                     $libpgport);
633                 $proj->AddDirResourceFile('src/bin/scripts');
634                 $proj->AddLibrary('ws2_32.lib');
635         }
636
637         # Regression DLL and EXE
638         my $regress = $solution->AddProject('regress', 'dll', 'misc');
639         $regress->AddFile('src/test/regress/regress.c');
640         $regress->AddDirResourceFile('src/test/regress');
641         $regress->AddReference($postgres);
642
643         my $pgregress = $solution->AddProject('pg_regress', 'exe', 'misc');
644         $pgregress->AddFile('src/test/regress/pg_regress.c');
645         $pgregress->AddFile('src/test/regress/pg_regress_main.c');
646         $pgregress->AddIncludeDir('src/port');
647         $pgregress->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
648         $pgregress->AddLibrary('ws2_32.lib');
649         $pgregress->AddDirResourceFile('src/test/regress');
650         $pgregress->AddReference($libpgcommon, $libpgport);
651
652         # fix up pg_xlogdump once it's been set up
653         # files symlinked on Unix are copied on windows
654         my $pg_xlogdump = AddSimpleFrontend('pg_xlogdump');
655         $pg_xlogdump->AddDefine('FRONTEND');
656         foreach my $xf (glob('src/backend/access/rmgrdesc/*desc.c'))
657         {
658                 $pg_xlogdump->AddFile($xf);
659         }
660         $pg_xlogdump->AddFile('src/backend/access/transam/xlogreader.c');
661
662         # fix up pgbench once it's been set up
663         # we're borrowing psqlscan.c from psql, so grab it from the correct place
664         my $pgbench = AddSimpleFrontend('pgbench');
665         $pgbench->ReplaceFile('src/bin/pgbench/psqlscan.c', 'src/bin/psql/psqlscan.c');
666
667         $solution->Save();
668         return $solution->{vcver};
669 }
670
671 #####################
672 # Utility functions #
673 #####################
674
675 # Add a simple frontend project (exe)
676 sub AddSimpleFrontend
677 {
678         my $n        = shift;
679         my $uselibpq = shift;
680
681         my $p = $solution->AddProject($n, 'exe', 'bin');
682         $p->AddDir('src/bin/' . $n);
683         $p->AddReference($libpgfeutils, $libpgcommon, $libpgport);
684         if ($uselibpq)
685         {
686                 $p->AddIncludeDir('src/interfaces/libpq');
687                 $p->AddReference($libpq);
688         }
689
690         # Adjust module definition using frontend variables
691         AdjustFrontendProj($p);
692
693         return $p;
694 }
695
696 # Add a simple transform module
697 sub AddTransformModule
698 {
699         my $n              = shift;
700         my $n_src          = shift;
701         my $pl_proj_name   = shift;
702         my $pl_src         = shift;
703         my $transform_name = shift;
704         my $transform_src  = shift;
705
706         my $transform_proj = undef;
707         foreach my $proj (@{ $solution->{projects}->{'contrib'} })
708         {
709                 if ($proj->{name} eq $transform_name)
710                 {
711                         $transform_proj = $proj;
712                         last;
713                 }
714         }
715         die "could not find base module $transform_name for transform module $n"
716           if (!defined($transform_proj));
717
718         my $pl_proj = undef;
719         foreach my $proj (@{ $solution->{projects}->{'PLs'} })
720         {
721                 if ($proj->{name} eq $pl_proj_name)
722                 {
723                         $pl_proj = $proj;
724                         last;
725                 }
726         }
727         die "could not find PL $pl_proj_name for transform module $n"
728           if (!defined($pl_proj));
729
730         my $p = $solution->AddProject($n, 'dll', 'contrib', $n_src);
731         for my $file (glob("$n_src/*.c"))
732         {
733                 $p->AddFile($file);
734         }
735         $p->AddReference($postgres);
736
737         # Add PL dependencies
738         $p->AddIncludeDir($pl_src);
739         $p->AddReference($pl_proj);
740         $p->AddIncludeDir($pl_proj->{includes});
741         foreach my $pl_lib (@{ $pl_proj->{libraries} })
742         {
743                 $p->AddLibrary($pl_lib);
744         }
745
746         # Add base module dependencies
747         $p->AddIncludeDir($transform_src);
748         $p->AddIncludeDir($transform_proj->{includes});
749         foreach my $trans_lib (@{ $transform_proj->{libraries} })
750         {
751                 $p->AddLibrary($trans_lib);
752         }
753         $p->AddReference($transform_proj);
754
755         return $p;
756 }
757
758 # Add a simple contrib project
759 sub AddContrib
760 {
761         my $subdir = shift;
762         my $n      = shift;
763         my $mf     = Project::read_file("$subdir/$n/Makefile");
764
765         if ($mf =~ /^MODULE_big\s*=\s*(.*)$/mg)
766         {
767                 my $dn = $1;
768                 my $proj = $solution->AddProject($dn, 'dll', 'contrib', "$subdir/$n");
769                 $proj->AddReference($postgres);
770                 AdjustContribProj($proj);
771         }
772         elsif ($mf =~ /^MODULES\s*=\s*(.*)$/mg)
773         {
774                 foreach my $mod (split /\s+/, $1)
775                 {
776                         my $proj =
777                           $solution->AddProject($mod, 'dll', 'contrib', "$subdir/$n");
778                         my $filename = $mod . '.c';
779                         $proj->AddFile("$subdir/$n/$filename");
780                         $proj->AddReference($postgres);
781                         AdjustContribProj($proj);
782                 }
783         }
784         elsif ($mf =~ /^PROGRAM\s*=\s*(.*)$/mg)
785         {
786                 my $proj = $solution->AddProject($1, 'exe', 'contrib', "$subdir/$n");
787                 AdjustContribProj($proj);
788         }
789         else
790         {
791                 croak "Could not determine contrib module type for $n\n";
792         }
793
794         # Are there any output data files to build?
795         GenerateContribSqlFiles($n, $mf);
796 }
797
798 sub GenerateContribSqlFiles
799 {
800         my $n  = shift;
801         my $mf = shift;
802         $mf =~ s{\\\r?\n}{}g;
803         if ($mf =~ /^DATA_built\s*=\s*(.*)$/mg)
804         {
805                 my $l = $1;
806
807                 # Strip out $(addsuffix) rules
808                 if (index($l, '$(addsuffix ') >= 0)
809                 {
810                         my $pcount = 0;
811                         my $i;
812                         for ($i = index($l, '$(addsuffix ') + 12; $i < length($l); $i++)
813                         {
814                                 $pcount++ if (substr($l, $i, 1) eq '(');
815                                 $pcount-- if (substr($l, $i, 1) eq ')');
816                                 last      if ($pcount < 0);
817                         }
818                         $l =
819                           substr($l, 0, index($l, '$(addsuffix ')) . substr($l, $i + 1);
820                 }
821
822                 foreach my $d (split /\s+/, $l)
823                 {
824                         my $in  = "$d.in";
825                         my $out = "$d";
826
827                         if (Solution::IsNewer("contrib/$n/$out", "contrib/$n/$in"))
828                         {
829                                 print "Building $out from $in (contrib/$n)...\n";
830                                 my $cont = Project::read_file("contrib/$n/$in");
831                                 my $dn   = $out;
832                                 $dn   =~ s/\.sql$//;
833                                 $cont =~ s/MODULE_PATHNAME/\$libdir\/$dn/g;
834                                 my $o;
835                                 open($o, ">contrib/$n/$out")
836                                   || croak "Could not write to contrib/$n/$d";
837                                 print $o $cont;
838                                 close($o);
839                         }
840                 }
841         }
842 }
843
844 sub AdjustContribProj
845 {
846         my $proj = shift;
847         AdjustModule(
848                 $proj,                    $contrib_defines,
849                 \@contrib_uselibpq,       \@contrib_uselibpgport,
850                 \@contrib_uselibpgcommon, $contrib_extralibs,
851                 $contrib_extrasource,     $contrib_extraincludes);
852 }
853
854 sub AdjustFrontendProj
855 {
856         my $proj = shift;
857         AdjustModule(
858                 $proj,                     $frontend_defines,
859                 \@frontend_uselibpq,       \@frontend_uselibpgport,
860                 \@frontend_uselibpgcommon, $frontend_extralibs,
861                 $frontend_extrasource,     $frontend_extraincludes);
862 }
863
864 sub AdjustModule
865 {
866         my $proj                  = shift;
867         my $module_defines        = shift;
868         my $module_uselibpq       = shift;
869         my $module_uselibpgport   = shift;
870         my $module_uselibpgcommon = shift;
871         my $module_extralibs      = shift;
872         my $module_extrasource    = shift;
873         my $module_extraincludes  = shift;
874         my $n                     = $proj->{name};
875
876         if ($module_defines->{$n})
877         {
878                 foreach my $d ($module_defines->{$n})
879                 {
880                         $proj->AddDefine($d);
881                 }
882         }
883         if (grep { /^$n$/ } @{$module_uselibpq})
884         {
885                 $proj->AddIncludeDir('src\interfaces\libpq');
886                 $proj->AddReference($libpq);
887         }
888         if (grep { /^$n$/ } @{$module_uselibpgport})
889         {
890                 $proj->AddReference($libpgport);
891         }
892         if (grep { /^$n$/ } @{$module_uselibpgcommon})
893         {
894                 $proj->AddReference($libpgcommon);
895         }
896         if ($module_extralibs->{$n})
897         {
898                 foreach my $l (@{ $module_extralibs->{$n} })
899                 {
900                         $proj->AddLibrary($l);
901                 }
902         }
903         if ($module_extraincludes->{$n})
904         {
905                 foreach my $i (@{ $module_extraincludes->{$n} })
906                 {
907                         $proj->AddIncludeDir($i);
908                 }
909         }
910         if ($module_extrasource->{$n})
911         {
912                 foreach my $i (@{ $module_extrasource->{$n} })
913                 {
914                         print "Files $i\n";
915                         $proj->AddFile($i);
916                 }
917         }
918 }
919
920 1;