]> granicus.if.org Git - postgresql/blob - src/tools/msvc/Mkvcbuild.pm
Use the preferred version of xsubpp, not necessarily the one that came with the
[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 List::Util qw(first);
18
19 use Exporter;
20 our (@ISA, @EXPORT_OK);
21 @ISA = qw(Exporter);
22 @EXPORT_OK = qw(Mkvcbuild);
23
24 my $solution;
25 my $libpgport;
26 my $postgres;
27 my $libpq;
28
29 my $contrib_defines = {'refint' => 'REFINT_VERBOSE'};
30 my @contrib_uselibpq = ('dblink', 'oid2name', 'pgbench', 'pg_upgrade','vacuumlo');
31 my @contrib_uselibpgport =(
32     'oid2name', 'pgbench', 'pg_standby','pg_archivecleanup',
33     'pg_test_fsync', 'pg_upgrade', 'vacuumlo'
34 );
35 my $contrib_extralibs = {'pgbench' => ['wsock32.lib']};
36 my $contrib_extraincludes = {'tsearch2' => ['contrib/tsearch2'], 'dblink' => ['src/backend']};
37 my $contrib_extrasource = {
38     'cube' => ['cubescan.l','cubeparse.y'],
39     'seg' => ['segscan.l','segparse.y']
40 };
41 my @contrib_excludes = ('pgcrypto','intagg','sepgsql');
42
43 sub mkvcbuild
44 {
45     our $config = shift;
46
47     chdir('..\..\..') if (-d '..\msvc' && -d '..\..\..\src');
48     die 'Must run from root or msvc directory' unless (-d 'src\tools\msvc' && -d 'src');
49
50     $solution = new Solution($config);
51
52     our @pgportfiles = qw(
53       chklocale.c crypt.c fseeko.c getrusage.c inet_aton.c random.c srandom.c
54       getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c erand48.c
55       snprintf.c strlcat.c strlcpy.c dirmod.c exec.c noblock.c path.c
56       pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c qsort.c qsort_arg.c
57       sprompt.c thread.c getopt.c getopt_long.c dirent.c rint.c win32env.c
58       win32error.c win32setlocale.c);
59
60     $libpgport = $solution->AddProject('libpgport','lib','misc');
61     $libpgport->AddDefine('FRONTEND');
62     $libpgport->AddFiles('src\port',@pgportfiles);
63
64     $postgres = $solution->AddProject('postgres','exe','','src\backend');
65     $postgres->AddIncludeDir('src\backend');
66     $postgres->AddDir('src\backend\port\win32');
67     $postgres->AddFile('src\backend\utils\fmgrtab.c');
68     $postgres->ReplaceFile('src\backend\port\dynloader.c','src\backend\port\dynloader\win32.c');
69     $postgres->ReplaceFile('src\backend\port\pg_sema.c','src\backend\port\win32_sema.c');
70     $postgres->ReplaceFile('src\backend\port\pg_shmem.c','src\backend\port\win32_shmem.c');
71     $postgres->ReplaceFile('src\backend\port\pg_latch.c','src\backend\port\win32_latch.c');
72     $postgres->AddFiles('src\port',@pgportfiles);
73     $postgres->AddFile('src\backend\port\pipe.c');
74     $postgres->AddDir('src\timezone');
75     $postgres->AddFiles('src\backend\parser','scan.l','gram.y');
76     $postgres->AddFiles('src\backend\bootstrap','bootscanner.l','bootparse.y');
77     $postgres->AddFiles('src\backend\utils\misc','guc-file.l');
78     $postgres->AddFiles('src\backend\replication', 'repl_scanner.l', 'repl_gram.y');
79     $postgres->AddDefine('BUILDING_DLL');
80     $postgres->AddLibrary('wsock32.lib');
81     $postgres->AddLibrary('ws2_32.lib');
82     $postgres->AddLibrary('secur32.lib');
83     $postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
84     $postgres->FullExportDLL('postgres.lib');
85
86     my $snowball = $solution->AddProject('dict_snowball','dll','','src\backend\snowball');
87     $snowball->RelocateFiles(
88         'src\backend\snowball\libstemmer',
89         sub {
90             return shift !~ /dict_snowball.c$/;
91         }
92     );
93     $snowball->AddIncludeDir('src\include\snowball');
94     $snowball->AddReference($postgres);
95
96     my $plpgsql = $solution->AddProject('plpgsql','dll','PLs','src\pl\plpgsql\src');
97     $plpgsql->AddFiles('src\pl\plpgsql\src', 'gram.y');
98     $plpgsql->AddReference($postgres);
99
100     if ($solution->{options}->{perl})
101     {
102         my $plperlsrc = "src\\pl\\plperl\\";
103         my $plperl = $solution->AddProject('plperl','dll','PLs','src\pl\plperl');
104         $plperl->AddIncludeDir($solution->{options}->{perl} . '/lib/CORE');
105         $plperl->AddDefine('PLPERL_HAVE_UID_GID');
106         foreach my $xs ('SPI.xs', 'Util.xs')
107         {
108             (my $xsc = $xs) =~ s/\.xs/.c/;
109             if (Solution::IsNewer("$plperlsrc$xsc","$plperlsrc$xs"))
110             {
111                 my $xsubppdir = first { -e "$_\\ExtUtils\\xsubpp.BAT" } @INC;
112                 print "Building $plperlsrc$xsc...\n";
113                 system( $solution->{options}->{perl}
114                       . '/bin/perl '
115                       . $solution->{options}->{perl}
116                       . "$xsubppdir/ExtUtils/xsubpp -typemap "
117                       . $solution->{options}->{perl}
118                       . '/lib/ExtUtils/typemap '
119                       . "$plperlsrc$xs "
120                       . ">$plperlsrc$xsc");
121                 if ((!(-f "$plperlsrc$xsc")) || -z "$plperlsrc$xsc")
122                 {
123                     unlink("$plperlsrc$xsc"); # if zero size
124                     die "Failed to create $xsc.\n";
125                 }
126             }
127         }
128         if (  Solution::IsNewer('src\pl\plperl\perlchunks.h','src\pl\plperl\plc_perlboot.pl')
129             ||Solution::IsNewer('src\pl\plperl\perlchunks.h','src\pl\plperl\plc_trusted.pl'))
130         {
131             print 'Building src\pl\plperl\perlchunks.h ...' . "\n";
132             my $basedir = getcwd;
133             chdir 'src\pl\plperl';
134             system( $solution->{options}->{perl}
135                   . '/bin/perl '
136                   . 'text2macro.pl '
137                   . '--strip="^(\#.*|\s*)$$" '
138                   . 'plc_perlboot.pl plc_trusted.pl '
139                   .     '>perlchunks.h');
140             chdir $basedir;
141             if ((!(-f 'src\pl\plperl\perlchunks.h')) || -z 'src\pl\plperl\perlchunks.h')
142             {
143                 unlink('src\pl\plperl\perlchunks.h'); # if zero size
144                 die 'Failed to create perlchunks.h' . "\n";
145             }
146         }
147         if (  Solution::IsNewer('src\pl\plperl\plperl_opmask.h','src\pl\plperl\plperl_opmask.pl'))
148         {
149             print 'Building src\pl\plperl\plperl_opmask.h ...' . "\n";
150             my $basedir = getcwd;
151             chdir 'src\pl\plperl';
152             system( $solution->{options}->{perl}
153                   . '/bin/perl '
154                   . 'plperl_opmask.pl '
155                   .     'plperl_opmask.h');
156             chdir $basedir;
157             if ((!(-f 'src\pl\plperl\plperl_opmask.h')) || -z 'src\pl\plperl\plperl_opmask.h')
158             {
159                 unlink('src\pl\plperl\plperl_opmask.h'); # if zero size
160                 die 'Failed to create plperl_opmask.h' . "\n";
161             }
162         }
163         $plperl->AddReference($postgres);
164         my @perl_libs =
165           grep {/perl\d+.lib$/ }glob($solution->{options}->{perl} . '\lib\CORE\perl*.lib');
166         if (@perl_libs == 1)
167         {
168             $plperl->AddLibrary($perl_libs[0]);
169         }
170         else
171         {
172             die "could not identify perl library version";
173         }
174     }
175
176     if ($solution->{options}->{python})
177     {
178
179         # Attempt to get python version and location.
180         # Assume python.exe in specified dir.
181         open(P,
182             $solution->{options}->{python}
183               . "\\python -c \"import sys;print(sys.prefix);print(str(sys.version_info[0])+str(sys.version_info[1]))\" |"
184         ) || die "Could not query for python version!\n";
185         my $pyprefix = <P>;
186         chomp($pyprefix);
187         my $pyver = <P>;
188         chomp($pyver);
189         close(P);
190
191         # Sometimes (always?) if python is not present, the execution
192         # appears to work, but gives no data...
193         die "Failed to query python for version information\n"
194           if (!(defined($pyprefix) && defined($pyver)));
195
196         my $pymajorver = substr($pyver, 0, 1);
197         my $plpython =
198           $solution->AddProject('plpython' . $pymajorver, 'dll','PLs', 'src\pl\plpython');
199         $plpython->AddIncludeDir($pyprefix . '\include');
200         $plpython->AddLibrary($pyprefix . "\\Libs\\python$pyver.lib");
201         $plpython->AddReference($postgres);
202     }
203
204     if ($solution->{options}->{tcl})
205     {
206         my $pltcl = $solution->AddProject('pltcl','dll','PLs','src\pl\tcl');
207         $pltcl->AddIncludeDir($solution->{options}->{tcl} . '\include');
208         $pltcl->AddReference($postgres);
209         if (-e $solution->{options}->{tcl} . '\lib\tcl85.lib')
210         {
211             $pltcl->AddLibrary($solution->{options}->{tcl} . '\lib\tcl85.lib');
212         }
213         else
214         {
215             $pltcl->AddLibrary($solution->{options}->{tcl} . '\lib\tcl84.lib');
216         }
217     }
218
219     $libpq = $solution->AddProject('libpq','dll','interfaces','src\interfaces\libpq');
220     $libpq->AddDefine('FRONTEND');
221     $libpq->AddDefine('UNSAFE_STAT_OK');
222     $libpq->AddIncludeDir('src\port');
223     $libpq->AddLibrary('wsock32.lib');
224     $libpq->AddLibrary('secur32.lib');
225     $libpq->AddLibrary('ws2_32.lib');
226     $libpq->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
227     $libpq->UseDef('src\interfaces\libpq\libpqdll.def');
228     $libpq->ReplaceFile('src\interfaces\libpq\libpqrc.c','src\interfaces\libpq\libpq.rc');
229     $libpq->AddReference($libpgport);
230
231     my $libpqwalreceiver = $solution->AddProject('libpqwalreceiver', 'dll', '',
232         'src\backend\replication\libpqwalreceiver');
233     $libpqwalreceiver->AddIncludeDir('src\interfaces\libpq');
234     $libpqwalreceiver->AddReference($postgres,$libpq);
235
236     my $pgtypes =
237       $solution->AddProject('libpgtypes','dll','interfaces','src\interfaces\ecpg\pgtypeslib');
238     $pgtypes->AddDefine('FRONTEND');
239     $pgtypes->AddReference($libpgport);
240     $pgtypes->UseDef('src\interfaces\ecpg\pgtypeslib\pgtypeslib.def');
241     $pgtypes->AddIncludeDir('src\interfaces\ecpg\include');
242
243     my $libecpg =$solution->AddProject('libecpg','dll','interfaces','src\interfaces\ecpg\ecpglib');
244     $libecpg->AddDefine('FRONTEND');
245     $libecpg->AddIncludeDir('src\interfaces\ecpg\include');
246     $libecpg->AddIncludeDir('src\interfaces\libpq');
247     $libecpg->AddIncludeDir('src\port');
248     $libecpg->UseDef('src\interfaces\ecpg\ecpglib\ecpglib.def');
249     $libecpg->AddLibrary('wsock32.lib');
250     $libecpg->AddReference($libpq,$pgtypes,$libpgport);
251
252     my $libecpgcompat =
253       $solution->AddProject('libecpg_compat','dll','interfaces','src\interfaces\ecpg\compatlib');
254     $libecpgcompat->AddIncludeDir('src\interfaces\ecpg\include');
255     $libecpgcompat->AddIncludeDir('src\interfaces\libpq');
256     $libecpgcompat->UseDef('src\interfaces\ecpg\compatlib\compatlib.def');
257     $libecpgcompat->AddReference($pgtypes,$libecpg,$libpgport);
258
259     my $ecpg = $solution->AddProject('ecpg','exe','interfaces','src\interfaces\ecpg\preproc');
260     $ecpg->AddIncludeDir('src\interfaces\ecpg\include');
261     $ecpg->AddIncludeDir('src\interfaces\libpq');
262     $ecpg->AddPrefixInclude('src\interfaces\ecpg\preproc');
263     $ecpg->AddFiles('src\interfaces\ecpg\preproc','pgc.l','preproc.y');
264     $ecpg->AddDefine('MAJOR_VERSION=4');
265     $ecpg->AddDefine('MINOR_VERSION=2');
266     $ecpg->AddDefine('PATCHLEVEL=1');
267     $ecpg->AddDefine('ECPG_COMPILE');
268     $ecpg->AddReference($libpgport);
269
270     my $pgregress_ecpg = $solution->AddProject('pg_regress_ecpg','exe','misc');
271     $pgregress_ecpg->AddFile('src\interfaces\ecpg\test\pg_regress_ecpg.c');
272     $pgregress_ecpg->AddFile('src\test\regress\pg_regress.c');
273     $pgregress_ecpg->AddIncludeDir('src\port');
274     $pgregress_ecpg->AddIncludeDir('src\test\regress');
275     $pgregress_ecpg->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
276     $pgregress_ecpg->AddDefine('FRONTEND');
277     $pgregress_ecpg->AddReference($libpgport);
278
279     my $isolation_tester = $solution->AddProject('isolationtester','exe','misc');
280     $isolation_tester->AddFile('src\test\isolation\isolationtester.c');
281     $isolation_tester->AddFile('src\test\isolation\specparse.y');
282     $isolation_tester->AddFile('src\test\isolation\specscanner.l');
283     $isolation_tester->AddFile('src\test\isolation\specparse.c');
284     $isolation_tester->AddIncludeDir('src\test\isolation');
285     $isolation_tester->AddIncludeDir('src\port');
286     $isolation_tester->AddIncludeDir('src\test\regress');
287     $isolation_tester->AddIncludeDir('src\interfaces\libpq');
288     $isolation_tester->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
289     $isolation_tester->AddDefine('FRONTEND');
290     $isolation_tester->AddLibrary('wsock32.lib');
291     $isolation_tester->AddReference($libpq, $libpgport);
292
293     my $pgregress_isolation = $solution->AddProject('pg_isolation_regress','exe','misc');
294     $pgregress_isolation->AddFile('src\test\isolation\isolation_main.c');
295     $pgregress_isolation->AddFile('src\test\regress\pg_regress.c');
296     $pgregress_isolation->AddIncludeDir('src\port');
297     $pgregress_isolation->AddIncludeDir('src\test\regress');
298     $pgregress_isolation->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
299     $pgregress_isolation->AddDefine('FRONTEND');
300     $pgregress_isolation->AddReference($libpgport);
301
302     # src/bin
303     my $initdb = AddSimpleFrontend('initdb');
304     $initdb->AddIncludeDir('src\interfaces\libpq');
305     $initdb->AddIncludeDir('src\timezone');
306     $initdb->AddDefine('FRONTEND');
307     $initdb->AddLibrary('wsock32.lib');
308     $initdb->AddLibrary('ws2_32.lib');
309
310     my $pgbasebackup = AddSimpleFrontend('pg_basebackup', 1);
311     $pgbasebackup->AddFile('src\bin\pg_basebackup\pg_basebackup.c');
312     $pgbasebackup->AddLibrary('ws2_32.lib');
313
314     my $pgreceivexlog = AddSimpleFrontend('pg_basebackup', 1);
315     $pgreceivexlog->{name} = 'pg_receivexlog';
316     $pgreceivexlog->AddFile('src\bin\pg_basebackup\pg_receivexlog.c');
317     $pgreceivexlog->AddLibrary('ws2_32.lib');
318
319     my $pgconfig = AddSimpleFrontend('pg_config');
320
321     my $pgcontrol = AddSimpleFrontend('pg_controldata');
322
323     my $pgctl = AddSimpleFrontend('pg_ctl', 1);
324
325     my $pgreset = AddSimpleFrontend('pg_resetxlog');
326
327     my $pgevent = $solution->AddProject('pgevent','dll','bin');
328     $pgevent->AddFiles('src\bin\pgevent','pgevent.c','pgmsgevent.rc');
329     $pgevent->AddResourceFile('src\bin\pgevent','Eventlog message formatter');
330     $pgevent->RemoveFile('src\bin\pgevent\win32ver.rc');
331     $pgevent->UseDef('src\bin\pgevent\pgevent.def');
332     $pgevent->DisableLinkerWarnings('4104');
333
334     my $psql = AddSimpleFrontend('psql', 1);
335     $psql->AddIncludeDir('src\bin\pg_dump');
336     $psql->AddIncludeDir('src\backend');
337     $psql->AddFile('src\bin\psql\psqlscan.l');
338
339     my $pgdump = AddSimpleFrontend('pg_dump', 1);
340     $pgdump->AddIncludeDir('src\backend');
341     $pgdump->AddFile('src\bin\pg_dump\pg_dump.c');
342     $pgdump->AddFile('src\bin\pg_dump\common.c');
343     $pgdump->AddFile('src\bin\pg_dump\pg_dump_sort.c');
344     $pgdump->AddFile('src\bin\pg_dump\keywords.c');
345     $pgdump->AddFile('src\backend\parser\kwlookup.c');
346
347     my $pgdumpall = AddSimpleFrontend('pg_dump', 1);
348     $pgdumpall->{name} = 'pg_dumpall';
349     $pgdumpall->AddIncludeDir('src\backend');
350     $pgdumpall->AddFile('src\bin\pg_dump\pg_dumpall.c');
351     $pgdumpall->AddFile('src\bin\pg_dump\keywords.c');
352     $pgdumpall->AddFile('src\backend\parser\kwlookup.c');
353
354     my $pgrestore = AddSimpleFrontend('pg_dump', 1);
355     $pgrestore->{name} = 'pg_restore';
356     $pgrestore->AddIncludeDir('src\backend');
357     $pgrestore->AddFile('src\bin\pg_dump\pg_restore.c');
358     $pgrestore->AddFile('src\bin\pg_dump\keywords.c');
359     $pgrestore->AddFile('src\backend\parser\kwlookup.c');
360
361     my $zic = $solution->AddProject('zic','exe','utils');
362     $zic->AddFiles('src\timezone','zic.c','ialloc.c','scheck.c','localtime.c');
363     $zic->AddReference($libpgport);
364
365     if ($solution->{options}->{xml})
366     {
367         $contrib_extraincludes->{'pgxml'} = [
368             $solution->{options}->{xml} . '\include',
369             $solution->{options}->{xslt} . '\include',
370             $solution->{options}->{iconv} . '\include'
371         ];
372
373         $contrib_extralibs->{'pgxml'} = [
374             $solution->{options}->{xml} . '\lib\libxml2.lib',
375             $solution->{options}->{xslt} . '\lib\libxslt.lib'
376         ];
377     }
378     else
379     {
380         push @contrib_excludes,'xml2';
381     }
382
383     if (!$solution->{options}->{openssl})
384     {
385         push @contrib_excludes,'sslinfo';
386     }
387
388     if ($solution->{options}->{uuid})
389     {
390         $contrib_extraincludes->{'uuid-ossp'} = [ $solution->{options}->{uuid} . '\include' ];
391         $contrib_extralibs->{'uuid-ossp'} = [ $solution->{options}->{uuid} . '\lib\uuid.lib' ];
392     }
393     else
394     {
395         push @contrib_excludes,'uuid-ossp';
396     }
397
398     # Pgcrypto makefile too complex to parse....
399     my $pgcrypto = $solution->AddProject('pgcrypto','dll','crypto');
400     $pgcrypto->AddFiles(
401         'contrib\pgcrypto','pgcrypto.c','px.c','px-hmac.c',
402         'px-crypt.c','crypt-gensalt.c','crypt-blowfish.c','crypt-des.c',
403         'crypt-md5.c','mbuf.c','pgp.c','pgp-armor.c',
404         'pgp-cfb.c','pgp-compress.c','pgp-decrypt.c','pgp-encrypt.c',
405         'pgp-info.c','pgp-mpi.c','pgp-pubdec.c','pgp-pubenc.c',
406         'pgp-pubkey.c','pgp-s2k.c','pgp-pgsql.c'
407     );
408     if ($solution->{options}->{openssl})
409     {
410         $pgcrypto->AddFiles('contrib\pgcrypto', 'openssl.c','pgp-mpi-openssl.c');
411     }
412     else
413     {
414         $pgcrypto->AddFiles(
415             'contrib\pgcrypto', 'md5.c','sha1.c','sha2.c',
416             'internal.c','internal-sha2.c','blf.c','rijndael.c',
417             'fortuna.c','random.c','pgp-mpi-internal.c','imath.c'
418         );
419     }
420     $pgcrypto->AddReference($postgres);
421     $pgcrypto->AddLibrary('wsock32.lib');
422     my $mf = Project::read_file('contrib/pgcrypto/Makefile');
423     GenerateContribSqlFiles('pgcrypto', $mf);
424
425     my $D;
426     opendir($D, 'contrib') || croak "Could not opendir on contrib!\n";
427     while (my $d = readdir($D))
428     {
429         next if ($d =~ /^\./);
430         next unless (-f "contrib/$d/Makefile");
431         next if (grep {/^$d$/} @contrib_excludes);
432         AddContrib($d);
433     }
434     closedir($D);
435
436     $mf = Project::read_file('src\backend\utils\mb\conversion_procs\Makefile');
437     $mf =~ s{\\s*[\r\n]+}{}mg;
438     $mf =~ m{SUBDIRS\s*=\s*(.*)$}m || die 'Could not match in conversion makefile' . "\n";
439     foreach my $sub (split /\s+/,$1)
440     {
441         my $mf = Project::read_file('src\backend\utils\mb\conversion_procs\\' . $sub . '\Makefile');
442         my $p = $solution->AddProject($sub, 'dll', 'conversion procs');
443         $p->AddFile('src\backend\utils\mb\conversion_procs\\' . $sub . '\\' . $sub . '.c');
444         if ($mf =~ m{^SRCS\s*\+=\s*(.*)$}m)
445         {
446             $p->AddFile('src\backend\utils\mb\conversion_procs\\' . $sub . '\\' . $1);
447         }
448         $p->AddReference($postgres);
449     }
450
451     $mf = Project::read_file('src\bin\scripts\Makefile');
452     $mf =~ s{\\s*[\r\n]+}{}mg;
453     $mf =~ m{PROGRAMS\s*=\s*(.*)$}m || die 'Could not match in bin\scripts\Makefile' . "\n";
454     foreach my $prg (split /\s+/,$1)
455     {
456         my $proj = $solution->AddProject($prg,'exe','bin');
457         $mf =~ m{$prg\s*:\s*(.*)$}m || die 'Could not find script define for $prg' . "\n";
458         my @files = split /\s+/,$1;
459         foreach my $f (@files)
460         {
461             $f =~ s/\.o$/\.c/;
462             if ($f eq 'keywords.c')
463             {
464                 $proj->AddFile('src\bin\pg_dump\keywords.c');
465             }
466             elsif ($f eq 'kwlookup.c')
467             {
468                 $proj->AddFile('src\backend\parser\kwlookup.c');
469             }
470             elsif ($f eq 'dumputils.c')
471             {
472                 $proj->AddFile('src\bin\pg_dump\dumputils.c');
473             }
474             elsif ($f =~ /print\.c$/)
475             { # Also catches mbprint.c
476                 $proj->AddFile('src\bin\psql\\' . $f);
477             }
478             elsif ($f =~ /\.c$/)
479             {
480                 $proj->AddFile('src\bin\scripts\\' . $f);
481             }
482         }
483         $proj->AddIncludeDir('src\interfaces\libpq');
484         $proj->AddIncludeDir('src\bin\pg_dump');
485         $proj->AddIncludeDir('src\bin\psql');
486         $proj->AddReference($libpq,$libpgport);
487         $proj->AddResourceFile('src\bin\scripts','PostgreSQL Utility');
488     }
489
490     # Regression DLL and EXE
491     my $regress = $solution->AddProject('regress','dll','misc');
492     $regress->AddFile('src\test\regress\regress.c');
493     $regress->AddReference($postgres);
494
495     my $pgregress = $solution->AddProject('pg_regress','exe','misc');
496     $pgregress->AddFile('src\test\regress\pg_regress.c');
497     $pgregress->AddFile('src\test\regress\pg_regress_main.c');
498     $pgregress->AddIncludeDir('src\port');
499     $pgregress->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
500     $pgregress->AddReference($libpgport);
501
502     $solution->Save();
503 }
504
505 #####################
506 # Utility functions #
507 #####################
508
509 # Add a simple frontend project (exe)
510 sub AddSimpleFrontend
511 {
512     my $n = shift;
513     my $uselibpq= shift;
514
515     my $p = $solution->AddProject($n,'exe','bin');
516     $p->AddDir('src\bin\\' . $n);
517     $p->AddReference($libpgport);
518     if ($uselibpq)
519     {
520         $p->AddIncludeDir('src\interfaces\libpq');
521         $p->AddReference($libpq);
522     }
523     return $p;
524 }
525
526 # Add a simple contrib project
527 sub AddContrib
528 {
529     my $n = shift;
530     my $mf = Project::read_file('contrib\\' . $n . '\Makefile');
531
532     if ($mf =~ /^MODULE_big\s*=\s*(.*)$/mg)
533     {
534         my $dn = $1;
535         $mf =~ s{\\\s*[\r\n]+}{}mg;
536         my $proj = $solution->AddProject($dn, 'dll', 'contrib');
537         $mf =~ /^OBJS\s*=\s*(.*)$/gm || croak "Could not find objects in MODULE_big for $n\n";
538         my $objs = $1;
539         while ($objs =~ /\b([\w-]+\.o)\b/g)
540         {
541             my $o = $1;
542             $o =~ s/\.o$/.c/;
543             $proj->AddFile('contrib\\' . $n . '\\' . $o);
544         }
545         $proj->AddReference($postgres);
546         if ($mf =~ /^SUBDIRS\s*:?=\s*(.*)$/mg)
547         {
548             foreach my $d (split /\s+/, $1)
549             {
550                 my $mf2 = Project::read_file('contrib\\' . $n . '\\' . $d . '\Makefile');
551                 $mf2 =~ s{\\\s*[\r\n]+}{}mg;
552                 $mf2 =~ /^SUBOBJS\s*=\s*(.*)$/gm
553                   || croak "Could not find objects in MODULE_big for $n, subdir $d\n";
554                 $objs = $1;
555                 while ($objs =~ /\b([\w-]+\.o)\b/g)
556                 {
557                     my $o = $1;
558                     $o =~ s/\.o$/.c/;
559                     $proj->AddFile('contrib\\' . $n . '\\' . $d . '\\' . $o);
560                 }
561             }
562         }
563         AdjustContribProj($proj);
564     }
565     elsif ($mf =~ /^MODULES\s*=\s*(.*)$/mg)
566     {
567         foreach my $mod (split /\s+/, $1)
568         {
569             my $proj = $solution->AddProject($mod, 'dll', 'contrib');
570             $proj->AddFile('contrib\\' . $n . '\\' . $mod . '.c');
571             $proj->AddReference($postgres);
572             AdjustContribProj($proj);
573         }
574     }
575     elsif ($mf =~ /^PROGRAM\s*=\s*(.*)$/mg)
576     {
577         my $proj = $solution->AddProject($1, 'exe', 'contrib');
578         $mf =~ s{\\\s*[\r\n]+}{}mg;
579         $mf =~ /^OBJS\s*=\s*(.*)$/gm || croak "Could not find objects in PROGRAM for $n\n";
580         my $objs = $1;
581         while ($objs =~ /\b([\w-]+\.o)\b/g)
582         {
583             my $o = $1;
584             $o =~ s/\.o$/.c/;
585             $proj->AddFile('contrib\\' . $n . '\\' . $o);
586         }
587         AdjustContribProj($proj);
588     }
589     else
590     {
591         croak "Could not determine contrib module type for $n\n";
592     }
593
594     # Are there any output data files to build?
595     GenerateContribSqlFiles($n, $mf);
596 }
597
598 sub GenerateContribSqlFiles
599 {
600     my $n = shift;
601     my $mf = shift;
602     if ($mf =~ /^DATA_built\s*=\s*(.*)$/mg)
603     {
604         my $l = $1;
605
606         # Strip out $(addsuffix) rules
607         if (index($l, '$(addsuffix ') >= 0)
608         {
609             my $pcount = 0;
610             my $i;
611             for ($i = index($l, '$(addsuffix ') + 12; $i < length($l); $i++)
612             {
613                 $pcount++ if (substr($l, $i, 1) eq '(');
614                 $pcount-- if (substr($l, $i, 1) eq ')');
615                 last if ($pcount < 0);
616             }
617             $l = substr($l, 0, index($l, '$(addsuffix ')) . substr($l, $i+1);
618         }
619
620         foreach my $d (split /\s+/, $l)
621         {
622             my $in = "$d.in";
623             my $out = "$d";
624
625             if (Solution::IsNewer("contrib/$n/$out", "contrib/$n/$in"))
626             {
627                 print "Building $out from $in (contrib/$n)...\n";
628                 my $cont = Project::read_file("contrib/$n/$in");
629                 my $dn = $out;
630                 $dn =~ s/\.sql$//;
631                 $cont =~ s/MODULE_PATHNAME/\$libdir\/$dn/g;
632                 my $o;
633                 open($o,">contrib/$n/$out") || croak "Could not write to contrib/$n/$d";
634                 print $o $cont;
635                 close($o);
636             }
637         }
638     }
639 }
640
641 sub AdjustContribProj
642 {
643     my $proj = shift;
644     my $n = $proj->{name};
645
646     if ($contrib_defines->{$n})
647     {
648         foreach my $d ($contrib_defines->{$n})
649         {
650             $proj->AddDefine($d);
651         }
652     }
653     if (grep {/^$n$/} @contrib_uselibpq)
654     {
655         $proj->AddIncludeDir('src\interfaces\libpq');
656         $proj->AddReference($libpq);
657     }
658     if (grep {/^$n$/} @contrib_uselibpgport)
659     {
660         $proj->AddReference($libpgport);
661     }
662     if ($contrib_extralibs->{$n})
663     {
664         foreach my $l (@{$contrib_extralibs->{$n}})
665         {
666             $proj->AddLibrary($l);
667         }
668     }
669     if ($contrib_extraincludes->{$n})
670     {
671         foreach my $i (@{$contrib_extraincludes->{$n}})
672         {
673             $proj->AddIncludeDir($i);
674         }
675     }
676     if ($contrib_extrasource->{$n})
677     {
678         $proj->AddFiles('contrib\\' . $n, @{$contrib_extrasource->{$n}});
679     }
680 }
681
682 1;