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