OSDN Git Service

Build and run isolation test programs under MSVC.
[pg-rex/syncrep.git] / 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         # Attempt to get python version and location.
176         # Assume python.exe in specified dir.
177         open(P,
178             $solution->{options}->{python}
179               . "\\python -c \"import sys;print(sys.prefix);print(str(sys.version_info[0])+str(sys.version_info[1]))\" |"
180         ) || die "Could not query for python version!\n";
181         my $pyprefix = <P>;
182         chomp($pyprefix);
183         my $pyver = <P>;
184         chomp($pyver);
185         close(P);
186
187         # Sometimes (always?) if python is not present, the execution
188         # appears to work, but gives no data...
189         die "Failed to query python for version information\n"
190           if (!(defined($pyprefix) && defined($pyver)));
191
192         my $pymajorver = substr($pyver, 0, 1);
193         my $plpython = $solution->AddProject('plpython' . $pymajorver, 'dll',
194                                              'PLs', 'src\pl\plpython');
195         $plpython->AddIncludeDir($pyprefix . '\include');
196         $plpython->AddLibrary($pyprefix . "\\Libs\\python$pyver.lib");
197         $plpython->AddReference($postgres);
198     }
199
200     if ($solution->{options}->{tcl})
201     {
202         my $pltcl = $solution->AddProject('pltcl','dll','PLs','src\pl\tcl');
203         $pltcl->AddIncludeDir($solution->{options}->{tcl} . '\include');
204         $pltcl->AddReference($postgres);
205         if (-e $solution->{options}->{tcl} . '\lib\tcl85.lib')
206         {
207             $pltcl->AddLibrary($solution->{options}->{tcl} . '\lib\tcl85.lib');
208         }
209         else
210         {
211             $pltcl->AddLibrary($solution->{options}->{tcl} . '\lib\tcl84.lib');
212         }
213     }
214
215     $libpq = $solution->AddProject('libpq','dll','interfaces','src\interfaces\libpq');
216     $libpq->AddDefine('FRONTEND');
217     $libpq->AddDefine('UNSAFE_STAT_OK');
218     $libpq->AddIncludeDir('src\port');
219     $libpq->AddLibrary('wsock32.lib');
220     $libpq->AddLibrary('secur32.lib');
221     $libpq->AddLibrary('ws2_32.lib');
222     $libpq->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
223     $libpq->UseDef('src\interfaces\libpq\libpqdll.def');
224     $libpq->ReplaceFile('src\interfaces\libpq\libpqrc.c','src\interfaces\libpq\libpq.rc');
225     $libpq->AddReference($libpgport);
226
227     my $libpqwalreceiver = $solution->AddProject('libpqwalreceiver', 'dll', '',
228         'src\backend\replication\libpqwalreceiver');
229     $libpqwalreceiver->AddIncludeDir('src\interfaces\libpq');
230     $libpqwalreceiver->AddReference($postgres,$libpq);
231
232     my $pgtypes =
233       $solution->AddProject('libpgtypes','dll','interfaces','src\interfaces\ecpg\pgtypeslib');
234     $pgtypes->AddDefine('FRONTEND');
235     $pgtypes->AddReference($libpgport);
236     $pgtypes->UseDef('src\interfaces\ecpg\pgtypeslib\pgtypeslib.def');
237     $pgtypes->AddIncludeDir('src\interfaces\ecpg\include');
238
239     my $libecpg =$solution->AddProject('libecpg','dll','interfaces','src\interfaces\ecpg\ecpglib');
240     $libecpg->AddDefine('FRONTEND');
241     $libecpg->AddIncludeDir('src\interfaces\ecpg\include');
242     $libecpg->AddIncludeDir('src\interfaces\libpq');
243     $libecpg->AddIncludeDir('src\port');
244     $libecpg->UseDef('src\interfaces\ecpg\ecpglib\ecpglib.def');
245     $libecpg->AddLibrary('wsock32.lib');
246     $libecpg->AddReference($libpq,$pgtypes,$libpgport);
247
248     my $libecpgcompat =
249       $solution->AddProject('libecpg_compat','dll','interfaces','src\interfaces\ecpg\compatlib');
250     $libecpgcompat->AddIncludeDir('src\interfaces\ecpg\include');
251     $libecpgcompat->AddIncludeDir('src\interfaces\libpq');
252     $libecpgcompat->UseDef('src\interfaces\ecpg\compatlib\compatlib.def');
253     $libecpgcompat->AddReference($pgtypes,$libecpg,$libpgport);
254
255     my $ecpg = $solution->AddProject('ecpg','exe','interfaces','src\interfaces\ecpg\preproc');
256     $ecpg->AddIncludeDir('src\interfaces\ecpg\include');
257     $ecpg->AddIncludeDir('src\interfaces\libpq');
258     $ecpg->AddPrefixInclude('src\interfaces\ecpg\preproc');
259     $ecpg->AddFiles('src\interfaces\ecpg\preproc','pgc.l','preproc.y');
260     $ecpg->AddDefine('MAJOR_VERSION=4');
261     $ecpg->AddDefine('MINOR_VERSION=2');
262     $ecpg->AddDefine('PATCHLEVEL=1');
263     $ecpg->AddDefine('ECPG_COMPILE');
264     $ecpg->AddReference($libpgport);
265
266     my $pgregress_ecpg = $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->AddDefine('FRONTEND');
273     $pgregress_ecpg->AddReference($libpgport);
274
275     my $isolation_tester = $solution->AddProject('isolation_tester','exe','misc');
276     $isolation_tester->AddFile('src\test\isolation\isolationtester.c');
277     $isolation_tester->AddFile('src\test\isolation\specparse.y');
278     $isolation_tester->AddFile('src\test\isolation\specscanner.l');
279     $isolation_tester->AddFile('src\test\isolation\specparse.c');
280     $isolation_tester->AddIncludeDir('src\test\isolation');
281     $isolation_tester->AddIncludeDir('src\port');
282     $isolation_tester->AddIncludeDir('src\test\regress');
283     $isolation_tester->AddIncludeDir('src\interfaces\libpq');
284     $isolation_tester->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
285     $isolation_tester->AddDefine('FRONTEND');
286     $isolation_tester->AddReference($libpq, $libpgport);
287
288     my $pgregress_isolation = $solution->AddProject('pg_isolation_regress','exe','misc');
289     $pgregress_isolation->AddFile('src\test\isolation\isolation_main.c');
290     $pgregress_isolation->AddFile('src\test\regress\pg_regress.c');
291     $pgregress_isolation->AddIncludeDir('src\port');
292     $pgregress_isolation->AddIncludeDir('src\test\regress');
293     $pgregress_isolation->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
294     $pgregress_isolation->AddDefine('FRONTEND');
295     $pgregress_isolation->AddReference($libpgport);
296
297     # src/bin
298     my $initdb = AddSimpleFrontend('initdb');
299     $initdb->AddIncludeDir('src\interfaces\libpq');
300     $initdb->AddDefine('FRONTEND');
301     $initdb->AddLibrary('wsock32.lib');
302     $initdb->AddLibrary('ws2_32.lib');
303
304     my $pgbasebackup = AddSimpleFrontend('pg_basebackup', 1);
305
306     my $pgconfig = AddSimpleFrontend('pg_config');
307
308     my $pgcontrol = AddSimpleFrontend('pg_controldata');
309
310     my $pgctl = AddSimpleFrontend('pg_ctl', 1);
311
312     my $pgreset = AddSimpleFrontend('pg_resetxlog');
313
314     my $pgevent = $solution->AddProject('pgevent','dll','bin');
315     $pgevent->AddFiles('src\bin\pgevent','pgevent.c','pgmsgevent.rc');
316     $pgevent->AddResourceFile('src\bin\pgevent','Eventlog message formatter');
317     $pgevent->RemoveFile('src\bin\pgevent\win32ver.rc');
318     $pgevent->UseDef('src\bin\pgevent\pgevent.def');
319     $pgevent->DisableLinkerWarnings('4104');
320
321     my $psql = AddSimpleFrontend('psql', 1);
322     $psql->AddIncludeDir('src\bin\pg_dump');
323     $psql->AddIncludeDir('src\backend');
324     $psql->AddFile('src\bin\psql\psqlscan.l');
325
326     my $pgdump = AddSimpleFrontend('pg_dump', 1);
327     $pgdump->AddIncludeDir('src\backend');
328     $pgdump->AddFile('src\bin\pg_dump\pg_dump.c');
329     $pgdump->AddFile('src\bin\pg_dump\common.c');
330     $pgdump->AddFile('src\bin\pg_dump\pg_dump_sort.c');
331     $pgdump->AddFile('src\bin\pg_dump\keywords.c');
332     $pgdump->AddFile('src\backend\parser\kwlookup.c');
333
334     my $pgdumpall = AddSimpleFrontend('pg_dump', 1);
335     $pgdumpall->{name} = 'pg_dumpall';
336     $pgdumpall->AddIncludeDir('src\backend');
337     $pgdumpall->AddFile('src\bin\pg_dump\pg_dumpall.c');
338     $pgdumpall->AddFile('src\bin\pg_dump\keywords.c');
339     $pgdumpall->AddFile('src\backend\parser\kwlookup.c');
340
341     my $pgrestore = AddSimpleFrontend('pg_dump', 1);
342     $pgrestore->{name} = 'pg_restore';
343     $pgrestore->AddIncludeDir('src\backend');
344     $pgrestore->AddFile('src\bin\pg_dump\pg_restore.c');
345     $pgrestore->AddFile('src\bin\pg_dump\keywords.c');
346     $pgrestore->AddFile('src\backend\parser\kwlookup.c');
347
348     my $zic = $solution->AddProject('zic','exe','utils');
349     $zic->AddFiles('src\timezone','zic.c','ialloc.c','scheck.c','localtime.c');
350     $zic->AddReference($libpgport);
351
352     if ($solution->{options}->{xml})
353     {
354         $contrib_extraincludes->{'pgxml'} = [
355             $solution->{options}->{xml} . '\include',
356             $solution->{options}->{xslt} . '\include',
357             $solution->{options}->{iconv} . '\include'
358         ];
359
360         $contrib_extralibs->{'pgxml'} = [
361             $solution->{options}->{xml} . '\lib\libxml2.lib',
362             $solution->{options}->{xslt} . '\lib\libxslt.lib'
363         ];
364     }
365     else
366     {
367         push @contrib_excludes,'xml2';
368     }
369
370     if (!$solution->{options}->{openssl})
371     {
372         push @contrib_excludes,'sslinfo';
373     }
374
375     if ($solution->{options}->{uuid})
376     {
377         $contrib_extraincludes->{'uuid-ossp'} = [ $solution->{options}->{uuid} . '\include' ];
378         $contrib_extralibs->{'uuid-ossp'} = [ $solution->{options}->{uuid} . '\lib\uuid.lib' ];
379     }
380     else
381     {
382         push @contrib_excludes,'uuid-ossp';
383     }
384
385     # Pgcrypto makefile too complex to parse....
386     my $pgcrypto = $solution->AddProject('pgcrypto','dll','crypto');
387     $pgcrypto->AddFiles(
388         'contrib\pgcrypto','pgcrypto.c','px.c','px-hmac.c',
389         'px-crypt.c','crypt-gensalt.c','crypt-blowfish.c','crypt-des.c',
390         'crypt-md5.c','mbuf.c','pgp.c','pgp-armor.c',
391         'pgp-cfb.c','pgp-compress.c','pgp-decrypt.c','pgp-encrypt.c',
392         'pgp-info.c','pgp-mpi.c','pgp-pubdec.c','pgp-pubenc.c',
393         'pgp-pubkey.c','pgp-s2k.c','pgp-pgsql.c'
394     );
395     if ($solution->{options}->{openssl})
396     {
397         $pgcrypto->AddFiles('contrib\pgcrypto', 'openssl.c','pgp-mpi-openssl.c');
398     }
399     else
400     {
401         $pgcrypto->AddFiles(
402             'contrib\pgcrypto', 'md5.c','sha1.c','sha2.c',
403             'internal.c','internal-sha2.c','blf.c','rijndael.c',
404             'fortuna.c','random.c','pgp-mpi-internal.c','imath.c'
405         );
406     }
407     $pgcrypto->AddReference($postgres);
408     $pgcrypto->AddLibrary('wsock32.lib');
409     my $mf = Project::read_file('contrib/pgcrypto/Makefile');
410     GenerateContribSqlFiles('pgcrypto', $mf);
411
412     my $D;
413     opendir($D, 'contrib') || croak "Could not opendir on contrib!\n";
414     while (my $d = readdir($D))
415     {
416         next if ($d =~ /^\./);
417         next unless (-f "contrib/$d/Makefile");
418         next if (grep {/^$d$/} @contrib_excludes);
419         AddContrib($d);
420     }
421     closedir($D);
422
423     $mf = Project::read_file('src\backend\utils\mb\conversion_procs\Makefile');
424     $mf =~ s{\\s*[\r\n]+}{}mg;
425     $mf =~ m{SUBDIRS\s*=\s*(.*)$}m || die 'Could not match in conversion makefile' . "\n";
426     foreach my $sub (split /\s+/,$1)
427     {
428         my $mf = Project::read_file('src\backend\utils\mb\conversion_procs\\' . $sub . '\Makefile');
429         my $p = $solution->AddProject($sub, 'dll', 'conversion procs');
430         $p->AddFile('src\backend\utils\mb\conversion_procs\\' . $sub . '\\' . $sub . '.c');
431         if ($mf =~ m{^SRCS\s*\+=\s*(.*)$}m)
432         {
433             $p->AddFile('src\backend\utils\mb\conversion_procs\\' . $sub . '\\' . $1);
434         }
435         $p->AddReference($postgres);
436     }
437
438     $mf = Project::read_file('src\bin\scripts\Makefile');
439     $mf =~ s{\\s*[\r\n]+}{}mg;
440     $mf =~ m{PROGRAMS\s*=\s*(.*)$}m || die 'Could not match in bin\scripts\Makefile' . "\n";
441     foreach my $prg (split /\s+/,$1)
442     {
443         my $proj = $solution->AddProject($prg,'exe','bin');
444         $mf =~ m{$prg\s*:\s*(.*)$}m || die 'Could not find script define for $prg' . "\n";
445         my @files = split /\s+/,$1;
446         foreach my $f (@files)
447         {
448             $f =~ s/\.o$/\.c/;
449             if ($f eq 'keywords.c')
450             {
451                 $proj->AddFile('src\bin\pg_dump\keywords.c');
452             }
453             elsif ($f eq 'kwlookup.c')
454             {
455                 $proj->AddFile('src\backend\parser\kwlookup.c');
456             }
457             elsif ($f eq 'dumputils.c')
458             {
459                 $proj->AddFile('src\bin\pg_dump\dumputils.c');
460             }
461             elsif ($f =~ /print\.c$/)
462             { # Also catches mbprint.c
463                 $proj->AddFile('src\bin\psql\\' . $f);
464             }
465             elsif ($f =~ /\.c$/)
466             {
467                 $proj->AddFile('src\bin\scripts\\' . $f);
468             }
469         }
470         $proj->AddIncludeDir('src\interfaces\libpq');
471         $proj->AddIncludeDir('src\bin\pg_dump');
472         $proj->AddIncludeDir('src\bin\psql');
473         $proj->AddReference($libpq,$libpgport);
474         $proj->AddResourceFile('src\bin\scripts','PostgreSQL Utility');
475     }
476
477     # Regression DLL and EXE
478     my $regress = $solution->AddProject('regress','dll','misc');
479     $regress->AddFile('src\test\regress\regress.c');
480     $regress->AddReference($postgres);
481
482     my $pgregress = $solution->AddProject('pg_regress','exe','misc');
483     $pgregress->AddFile('src\test\regress\pg_regress.c');
484     $pgregress->AddFile('src\test\regress\pg_regress_main.c');
485     $pgregress->AddIncludeDir('src\port');
486     $pgregress->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
487     $pgregress->AddReference($libpgport);
488
489     $solution->Save();
490 }
491
492 #####################
493 # Utility functions #
494 #####################
495
496 # Add a simple frontend project (exe)
497 sub AddSimpleFrontend
498 {
499     my $n = shift;
500     my $uselibpq= shift;
501
502     my $p = $solution->AddProject($n,'exe','bin');
503     $p->AddDir('src\bin\\' . $n);
504     $p->AddReference($libpgport);
505     if ($uselibpq)
506     {
507         $p->AddIncludeDir('src\interfaces\libpq');
508         $p->AddReference($libpq);
509     }
510     return $p;
511 }
512
513 # Add a simple contrib project
514 sub AddContrib
515 {
516     my $n = shift;
517     my $mf = Project::read_file('contrib\\' . $n . '\Makefile');
518
519     if ($mf =~ /^MODULE_big\s*=\s*(.*)$/mg)
520     {
521         my $dn = $1;
522         $mf =~ s{\\\s*[\r\n]+}{}mg;
523         my $proj = $solution->AddProject($dn, 'dll', 'contrib');
524         $mf =~ /^OBJS\s*=\s*(.*)$/gm || croak "Could not find objects in MODULE_big for $n\n";
525         my $objs = $1;
526         while ($objs =~ /\b([\w-]+\.o)\b/g)
527         {
528             my $o = $1;
529             $o =~ s/\.o$/.c/;
530             $proj->AddFile('contrib\\' . $n . '\\' . $o);
531         }
532         $proj->AddReference($postgres);
533         if ($mf =~ /^SUBDIRS\s*:?=\s*(.*)$/mg)
534         {
535             foreach my $d (split /\s+/, $1)
536             {
537                 my $mf2 = Project::read_file('contrib\\' . $n . '\\' . $d . '\Makefile');
538                 $mf2 =~ s{\\\s*[\r\n]+}{}mg;
539                 $mf2 =~ /^SUBOBJS\s*=\s*(.*)$/gm
540                   || croak "Could not find objects in MODULE_big for $n, subdir $d\n";
541                 $objs = $1;
542                 while ($objs =~ /\b([\w-]+\.o)\b/g)
543                 {
544                     my $o = $1;
545                     $o =~ s/\.o$/.c/;
546                     $proj->AddFile('contrib\\' . $n . '\\' . $d . '\\' . $o);
547                 }
548             }
549         }
550         AdjustContribProj($proj);
551     }
552     elsif ($mf =~ /^MODULES\s*=\s*(.*)$/mg)
553     {
554         foreach my $mod (split /\s+/, $1)
555         {
556             my $proj = $solution->AddProject($mod, 'dll', 'contrib');
557             $proj->AddFile('contrib\\' . $n . '\\' . $mod . '.c');
558             $proj->AddReference($postgres);
559             AdjustContribProj($proj);
560         }
561     }
562     elsif ($mf =~ /^PROGRAM\s*=\s*(.*)$/mg)
563     {
564         my $proj = $solution->AddProject($1, 'exe', 'contrib');
565         $mf =~ s{\\\s*[\r\n]+}{}mg;
566         $mf =~ /^OBJS\s*=\s*(.*)$/gm || croak "Could not find objects in PROGRAM for $n\n";
567         my $objs = $1;
568         while ($objs =~ /\b([\w-]+\.o)\b/g)
569         {
570             my $o = $1;
571             $o =~ s/\.o$/.c/;
572             $proj->AddFile('contrib\\' . $n . '\\' . $o);
573         }
574         AdjustContribProj($proj);
575     }
576     else
577     {
578         croak "Could not determine contrib module type for $n\n";
579     }
580
581     # Are there any output data files to build?
582     GenerateContribSqlFiles($n, $mf);
583 }
584
585 sub GenerateContribSqlFiles
586 {
587     my $n = shift;
588     my $mf = shift;
589     if ($mf =~ /^DATA_built\s*=\s*(.*)$/mg)
590     {
591         my $l = $1;
592
593         # Strip out $(addsuffix) rules
594         if (index($l, '$(addsuffix ') >= 0)
595         {
596             my $pcount = 0;
597             my $i;
598             for ($i = index($l, '$(addsuffix ') + 12; $i < length($l); $i++)
599             {
600                 $pcount++ if (substr($l, $i, 1) eq '(');
601                 $pcount-- if (substr($l, $i, 1) eq ')');
602                 last if ($pcount < 0);
603             }
604             $l = substr($l, 0, index($l, '$(addsuffix ')) . substr($l, $i+1);
605         }
606
607         foreach my $d (split /\s+/, $l)
608         {
609             my $in = "$d.in";
610             my $out = "$d";
611
612             if (Solution::IsNewer("contrib/$n/$out", "contrib/$n/$in"))
613             {
614                 print "Building $out from $in (contrib/$n)...\n";
615                 my $cont = Project::read_file("contrib/$n/$in");
616                 my $dn = $out;
617                 $dn =~ s/\.sql$//;
618                 $cont =~ s/MODULE_PATHNAME/\$libdir\/$dn/g;
619                 my $o;
620                 open($o,">contrib/$n/$out") || croak "Could not write to contrib/$n/$d";
621                 print $o $cont;
622                 close($o);
623             }
624         }
625     }
626 }
627
628 sub AdjustContribProj
629 {
630     my $proj = shift;
631     my $n = $proj->{name};
632
633     if ($contrib_defines->{$n})
634     {
635         foreach my $d ($contrib_defines->{$n})
636         {
637             $proj->AddDefine($d);
638         }
639     }
640     if (grep {/^$n$/} @contrib_uselibpq)
641     {
642         $proj->AddIncludeDir('src\interfaces\libpq');
643         $proj->AddReference($libpq);
644     }
645     if (grep {/^$n$/} @contrib_uselibpgport)
646     {
647         $proj->AddReference($libpgport);
648     }
649     if ($contrib_extralibs->{$n})
650     {
651         foreach my $l (@{$contrib_extralibs->{$n}})
652         {
653             $proj->AddLibrary($l);
654         }
655     }
656     if ($contrib_extraincludes->{$n})
657     {
658         foreach my $i (@{$contrib_extraincludes->{$n}})
659         {
660             $proj->AddIncludeDir($i);
661         }
662     }
663     if ($contrib_extrasource->{$n})
664     {
665         $proj->AddFiles('contrib\\' . $n, @{$contrib_extrasource->{$n}});
666     }
667 }
668
669 1;