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