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