4 # Package that generates build files for msvc build
6 # src/tools/msvc/Mkvcbuild.pm
18 use List::Util qw(first);
21 our (@ISA, @EXPORT_OK);
23 @EXPORT_OK = qw(Mkvcbuild);
30 my $contrib_defines = { 'refint' => 'REFINT_VERBOSE' };
31 my @contrib_uselibpq =
32 ('dblink', 'oid2name', 'pgbench', 'pg_upgrade', 'vacuumlo');
33 my @contrib_uselibpgport = (
34 'oid2name', 'pgbench',
35 'pg_standby', 'pg_archivecleanup',
36 'pg_test_fsync', 'pg_test_timing',
37 'pg_upgrade', 'vacuumlo');
38 my $contrib_extralibs = { 'pgbench' => ['wsock32.lib'] };
39 my $contrib_extraincludes =
40 { 'tsearch2' => ['contrib/tsearch2'], 'dblink' => ['src/backend'] };
41 my $contrib_extrasource = {
42 'cube' => [ 'cubescan.l', 'cubeparse.y' ],
43 'seg' => [ 'segscan.l', 'segparse.y' ] };
44 my @contrib_excludes = ('pgcrypto', 'intagg', 'sepgsql');
50 chdir('..\..\..') if (-d '..\msvc' && -d '..\..\..\src');
51 die 'Must run from root or msvc directory'
52 unless (-d 'src\tools\msvc' && -d 'src');
54 my $vsVersion = DetermineVisualStudioVersion();
56 $solution = CreateSolution($vsVersion, $config);
58 our @pgportfiles = qw(
59 chklocale.c crypt.c fls.c fseeko.c getrusage.c inet_aton.c random.c
60 srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c
61 erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c exec.c noblock.c path.c
62 pgcheckdir.c pg_crc.c pgmkdirp.c pgsleep.c pgstrcasecmp.c qsort.c qsort_arg.c quotes.c
63 sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c rint.c win32env.c
64 win32error.c win32setlocale.c);
66 $libpgport = $solution->AddProject('libpgport', 'lib', 'misc');
67 $libpgport->AddDefine('FRONTEND');
68 $libpgport->AddFiles('src\port', @pgportfiles);
70 $postgres = $solution->AddProject('postgres', 'exe', '', 'src\backend');
71 $postgres->AddIncludeDir('src\backend');
72 $postgres->AddDir('src\backend\port\win32');
73 $postgres->AddFile('src\backend\utils\fmgrtab.c');
74 $postgres->ReplaceFile(
75 'src\backend\port\dynloader.c',
76 'src\backend\port\dynloader\win32.c');
77 $postgres->ReplaceFile('src\backend\port\pg_sema.c',
78 'src\backend\port\win32_sema.c');
79 $postgres->ReplaceFile('src\backend\port\pg_shmem.c',
80 'src\backend\port\win32_shmem.c');
81 $postgres->ReplaceFile('src\backend\port\pg_latch.c',
82 'src\backend\port\win32_latch.c');
83 $postgres->AddFiles('src\port', @pgportfiles);
84 $postgres->AddDir('src\timezone');
85 $postgres->AddFiles('src\backend\parser', 'scan.l', 'gram.y');
86 $postgres->AddFiles('src\backend\bootstrap', 'bootscanner.l',
88 $postgres->AddFiles('src\backend\utils\misc', 'guc-file.l');
89 $postgres->AddFiles('src\backend\replication', 'repl_scanner.l',
91 $postgres->AddDefine('BUILDING_DLL');
92 $postgres->AddLibrary('wsock32.lib');
93 $postgres->AddLibrary('ws2_32.lib');
94 $postgres->AddLibrary('secur32.lib');
95 $postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
96 $postgres->FullExportDLL('postgres.lib');
98 my $snowball = $solution->AddProject('dict_snowball', 'dll', '',
99 'src\backend\snowball');
100 $snowball->RelocateFiles(
101 'src\backend\snowball\libstemmer',
103 return shift !~ /dict_snowball.c$/;
105 $snowball->AddIncludeDir('src\include\snowball');
106 $snowball->AddReference($postgres);
109 $solution->AddProject('plpgsql', 'dll', 'PLs', 'src\pl\plpgsql\src');
110 $plpgsql->AddFiles('src\pl\plpgsql\src', 'pl_gram.y');
111 $plpgsql->AddReference($postgres);
113 if ($solution->{options}->{perl})
115 my $plperlsrc = "src\\pl\\plperl\\";
117 $solution->AddProject('plperl', 'dll', 'PLs', 'src\pl\plperl');
118 $plperl->AddIncludeDir($solution->{options}->{perl} . '/lib/CORE');
119 $plperl->AddDefine('PLPERL_HAVE_UID_GID');
120 foreach my $xs ('SPI.xs', 'Util.xs')
122 (my $xsc = $xs) =~ s/\.xs/.c/;
123 if (Solution::IsNewer("$plperlsrc$xsc", "$plperlsrc$xs"))
125 my $xsubppdir = first { -e "$_\\ExtUtils\\xsubpp" } @INC;
126 print "Building $plperlsrc$xsc...\n";
127 system( $solution->{options}->{perl}
129 . "$xsubppdir/ExtUtils/xsubpp -typemap "
130 . $solution->{options}->{perl}
131 . '/lib/ExtUtils/typemap '
133 . ">$plperlsrc$xsc");
134 if ((!(-f "$plperlsrc$xsc")) || -z "$plperlsrc$xsc")
136 unlink("$plperlsrc$xsc"); # if zero size
137 die "Failed to create $xsc.\n";
141 if (Solution::IsNewer(
142 'src\pl\plperl\perlchunks.h',
143 'src\pl\plperl\plc_perlboot.pl')
144 || Solution::IsNewer(
145 'src\pl\plperl\perlchunks.h',
146 'src\pl\plperl\plc_trusted.pl'))
148 print 'Building src\pl\plperl\perlchunks.h ...' . "\n";
149 my $basedir = getcwd;
150 chdir 'src\pl\plperl';
151 system( $solution->{options}->{perl}
154 . '--strip="^(\#.*|\s*)$$" '
155 . 'plc_perlboot.pl plc_trusted.pl '
158 if ((!(-f 'src\pl\plperl\perlchunks.h'))
159 || -z 'src\pl\plperl\perlchunks.h')
161 unlink('src\pl\plperl\perlchunks.h'); # if zero size
162 die 'Failed to create perlchunks.h' . "\n";
165 if (Solution::IsNewer(
166 'src\pl\plperl\plperl_opmask.h',
167 'src\pl\plperl\plperl_opmask.pl'))
169 print 'Building src\pl\plperl\plperl_opmask.h ...' . "\n";
170 my $basedir = getcwd;
171 chdir 'src\pl\plperl';
172 system( $solution->{options}->{perl}
174 . 'plperl_opmask.pl '
175 . 'plperl_opmask.h');
177 if ((!(-f 'src\pl\plperl\plperl_opmask.h'))
178 || -z 'src\pl\plperl\plperl_opmask.h')
180 unlink('src\pl\plperl\plperl_opmask.h'); # if zero size
181 die 'Failed to create plperl_opmask.h' . "\n";
184 $plperl->AddReference($postgres);
186 grep { /perl\d+.lib$/ }
187 glob($solution->{options}->{perl} . '\lib\CORE\perl*.lib');
190 $plperl->AddLibrary($perl_libs[0]);
194 die "could not identify perl library version";
198 if ($solution->{options}->{python})
201 # Attempt to get python version and location.
202 # Assume python.exe in specified dir.
204 $solution->{options}->{python}
205 . "\\python -c \"import sys;print(sys.prefix);print(str(sys.version_info[0])+str(sys.version_info[1]))\" |"
206 ) || die "Could not query for python version!\n";
213 # Sometimes (always?) if python is not present, the execution
214 # appears to work, but gives no data...
215 die "Failed to query python for version information\n"
216 if (!(defined($pyprefix) && defined($pyver)));
218 my $pymajorver = substr($pyver, 0, 1);
219 my $plpython = $solution->AddProject('plpython' . $pymajorver,
220 'dll', 'PLs', 'src\pl\plpython');
221 $plpython->AddIncludeDir($pyprefix . '\include');
222 $plpython->AddLibrary($pyprefix . "\\Libs\\python$pyver.lib");
223 $plpython->AddReference($postgres);
226 if ($solution->{options}->{tcl})
229 $solution->AddProject('pltcl', 'dll', 'PLs', 'src\pl\tcl');
230 $pltcl->AddIncludeDir($solution->{options}->{tcl} . '\include');
231 $pltcl->AddReference($postgres);
232 if (-e $solution->{options}->{tcl} . '\lib\tcl85.lib')
235 $solution->{options}->{tcl} . '\lib\tcl85.lib');
240 $solution->{options}->{tcl} . '\lib\tcl84.lib');
244 $libpq = $solution->AddProject('libpq', 'dll', 'interfaces',
245 'src\interfaces\libpq');
246 $libpq->AddDefine('FRONTEND');
247 $libpq->AddDefine('UNSAFE_STAT_OK');
248 $libpq->AddIncludeDir('src\port');
249 $libpq->AddLibrary('wsock32.lib');
250 $libpq->AddLibrary('secur32.lib');
251 $libpq->AddLibrary('ws2_32.lib');
252 $libpq->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
253 $libpq->UseDef('src\interfaces\libpq\libpqdll.def');
254 $libpq->ReplaceFile('src\interfaces\libpq\libpqrc.c',
255 'src\interfaces\libpq\libpq.rc');
256 $libpq->AddReference($libpgport);
258 my $libpqwalreceiver =
259 $solution->AddProject('libpqwalreceiver', 'dll', '',
260 'src\backend\replication\libpqwalreceiver');
261 $libpqwalreceiver->AddIncludeDir('src\interfaces\libpq');
262 $libpqwalreceiver->AddReference($postgres, $libpq);
264 my $pgtypes = $solution->AddProject(
266 'interfaces', 'src\interfaces\ecpg\pgtypeslib');
267 $pgtypes->AddDefine('FRONTEND');
268 $pgtypes->AddReference($libpgport);
269 $pgtypes->UseDef('src\interfaces\ecpg\pgtypeslib\pgtypeslib.def');
270 $pgtypes->AddIncludeDir('src\interfaces\ecpg\include');
272 my $libecpg = $solution->AddProject('libecpg', 'dll', 'interfaces',
273 'src\interfaces\ecpg\ecpglib');
274 $libecpg->AddDefine('FRONTEND');
275 $libecpg->AddIncludeDir('src\interfaces\ecpg\include');
276 $libecpg->AddIncludeDir('src\interfaces\libpq');
277 $libecpg->AddIncludeDir('src\port');
278 $libecpg->UseDef('src\interfaces\ecpg\ecpglib\ecpglib.def');
279 $libecpg->AddLibrary('wsock32.lib');
280 $libecpg->AddReference($libpq, $pgtypes, $libpgport);
282 my $libecpgcompat = $solution->AddProject(
283 'libecpg_compat', 'dll',
284 'interfaces', 'src\interfaces\ecpg\compatlib');
285 $libecpgcompat->AddIncludeDir('src\interfaces\ecpg\include');
286 $libecpgcompat->AddIncludeDir('src\interfaces\libpq');
287 $libecpgcompat->UseDef('src\interfaces\ecpg\compatlib\compatlib.def');
288 $libecpgcompat->AddReference($pgtypes, $libecpg, $libpgport);
290 my $ecpg = $solution->AddProject('ecpg', 'exe', 'interfaces',
291 'src\interfaces\ecpg\preproc');
292 $ecpg->AddIncludeDir('src\interfaces\ecpg\include');
293 $ecpg->AddIncludeDir('src\interfaces\libpq');
294 $ecpg->AddPrefixInclude('src\interfaces\ecpg\preproc');
295 $ecpg->AddFiles('src\interfaces\ecpg\preproc', 'pgc.l', 'preproc.y');
296 $ecpg->AddDefine('MAJOR_VERSION=4');
297 $ecpg->AddDefine('MINOR_VERSION=9');
298 $ecpg->AddDefine('PATCHLEVEL=0');
299 $ecpg->AddDefine('ECPG_COMPILE');
300 $ecpg->AddReference($libpgport);
303 $solution->AddProject('pg_regress_ecpg', 'exe', 'misc');
304 $pgregress_ecpg->AddFile('src\interfaces\ecpg\test\pg_regress_ecpg.c');
305 $pgregress_ecpg->AddFile('src\test\regress\pg_regress.c');
306 $pgregress_ecpg->AddIncludeDir('src\port');
307 $pgregress_ecpg->AddIncludeDir('src\test\regress');
308 $pgregress_ecpg->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
309 $pgregress_ecpg->AddDefine('FRONTEND');
310 $pgregress_ecpg->AddReference($libpgport);
312 my $isolation_tester =
313 $solution->AddProject('isolationtester', 'exe', 'misc');
314 $isolation_tester->AddFile('src\test\isolation\isolationtester.c');
315 $isolation_tester->AddFile('src\test\isolation\specparse.y');
316 $isolation_tester->AddFile('src\test\isolation\specscanner.l');
317 $isolation_tester->AddFile('src\test\isolation\specparse.c');
318 $isolation_tester->AddIncludeDir('src\test\isolation');
319 $isolation_tester->AddIncludeDir('src\port');
320 $isolation_tester->AddIncludeDir('src\test\regress');
321 $isolation_tester->AddIncludeDir('src\interfaces\libpq');
322 $isolation_tester->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
323 $isolation_tester->AddDefine('FRONTEND');
324 $isolation_tester->AddLibrary('wsock32.lib');
325 $isolation_tester->AddReference($libpq, $libpgport);
327 my $pgregress_isolation =
328 $solution->AddProject('pg_isolation_regress', 'exe', 'misc');
329 $pgregress_isolation->AddFile('src\test\isolation\isolation_main.c');
330 $pgregress_isolation->AddFile('src\test\regress\pg_regress.c');
331 $pgregress_isolation->AddIncludeDir('src\port');
332 $pgregress_isolation->AddIncludeDir('src\test\regress');
333 $pgregress_isolation->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
334 $pgregress_isolation->AddDefine('FRONTEND');
335 $pgregress_isolation->AddReference($libpgport);
338 my $initdb = AddSimpleFrontend('initdb');
339 $initdb->AddIncludeDir('src\interfaces\libpq');
340 $initdb->AddIncludeDir('src\timezone');
341 $initdb->AddDefine('FRONTEND');
342 $initdb->AddLibrary('wsock32.lib');
343 $initdb->AddLibrary('ws2_32.lib');
345 my $pgbasebackup = AddSimpleFrontend('pg_basebackup', 1);
346 $pgbasebackup->AddFile('src\bin\pg_basebackup\pg_basebackup.c');
347 $pgbasebackup->AddLibrary('ws2_32.lib');
349 my $pgreceivexlog = AddSimpleFrontend('pg_basebackup', 1);
350 $pgreceivexlog->{name} = 'pg_receivexlog';
351 $pgreceivexlog->AddFile('src\bin\pg_basebackup\pg_receivexlog.c');
352 $pgreceivexlog->AddLibrary('ws2_32.lib');
354 my $pgconfig = AddSimpleFrontend('pg_config');
356 my $pgcontrol = AddSimpleFrontend('pg_controldata');
358 my $pgctl = AddSimpleFrontend('pg_ctl', 1);
360 my $pgreset = AddSimpleFrontend('pg_resetxlog');
362 my $pgevent = $solution->AddProject('pgevent', 'dll', 'bin');
363 $pgevent->AddFiles('src\bin\pgevent', 'pgevent.c', 'pgmsgevent.rc');
364 $pgevent->AddResourceFile('src\bin\pgevent',
365 'Eventlog message formatter');
366 $pgevent->RemoveFile('src\bin\pgevent\win32ver.rc');
367 $pgevent->UseDef('src\bin\pgevent\pgevent.def');
368 $pgevent->DisableLinkerWarnings('4104');
370 my $psql = AddSimpleFrontend('psql', 1);
371 $psql->AddIncludeDir('src\bin\pg_dump');
372 $psql->AddIncludeDir('src\backend');
373 $psql->AddFile('src\bin\psql\psqlscan.l');
375 my $pgdump = AddSimpleFrontend('pg_dump', 1);
376 $pgdump->AddIncludeDir('src\backend');
377 $pgdump->AddFile('src\bin\pg_dump\pg_dump.c');
378 $pgdump->AddFile('src\bin\pg_dump\common.c');
379 $pgdump->AddFile('src\bin\pg_dump\pg_dump_sort.c');
380 $pgdump->AddFile('src\bin\pg_dump\keywords.c');
381 $pgdump->AddFile('src\backend\parser\kwlookup.c');
383 my $pgdumpall = AddSimpleFrontend('pg_dump', 1);
385 # pg_dumpall doesn't use the files in the Makefile's $(OBJS), unlike
386 # pg_dump and pg_restore.
387 # So remove their sources from the object, keeping the other setup that
388 # AddSimpleFrontend() has done.
389 my @nodumpall = grep { m/src\\bin\\pg_dump\\.*\.c$/ }
390 keys %{ $pgdumpall->{files} };
391 delete @{ $pgdumpall->{files} }{@nodumpall};
392 $pgdumpall->{name} = 'pg_dumpall';
393 $pgdumpall->AddIncludeDir('src\backend');
394 $pgdumpall->AddFile('src\bin\pg_dump\pg_dumpall.c');
395 $pgdumpall->AddFile('src\bin\pg_dump\dumputils.c');
396 $pgdumpall->AddFile('src\bin\pg_dump\dumpmem.c');
397 $pgdumpall->AddFile('src\bin\pg_dump\keywords.c');
398 $pgdumpall->AddFile('src\backend\parser\kwlookup.c');
400 my $pgrestore = AddSimpleFrontend('pg_dump', 1);
401 $pgrestore->{name} = 'pg_restore';
402 $pgrestore->AddIncludeDir('src\backend');
403 $pgrestore->AddFile('src\bin\pg_dump\pg_restore.c');
404 $pgrestore->AddFile('src\bin\pg_dump\keywords.c');
405 $pgrestore->AddFile('src\backend\parser\kwlookup.c');
407 my $zic = $solution->AddProject('zic', 'exe', 'utils');
408 $zic->AddFiles('src\timezone', 'zic.c', 'ialloc.c', 'scheck.c',
410 $zic->AddReference($libpgport);
412 if ($solution->{options}->{xml})
414 $contrib_extraincludes->{'pgxml'} = [
415 $solution->{options}->{xml} . '\include',
416 $solution->{options}->{xslt} . '\include',
417 $solution->{options}->{iconv} . '\include' ];
419 $contrib_extralibs->{'pgxml'} = [
420 $solution->{options}->{xml} . '\lib\libxml2.lib',
421 $solution->{options}->{xslt} . '\lib\libxslt.lib' ];
425 push @contrib_excludes, 'xml2';
428 if (!$solution->{options}->{openssl})
430 push @contrib_excludes, 'sslinfo';
433 if ($solution->{options}->{uuid})
435 $contrib_extraincludes->{'uuid-ossp'} =
436 [ $solution->{options}->{uuid} . '\include' ];
437 $contrib_extralibs->{'uuid-ossp'} =
438 [ $solution->{options}->{uuid} . '\lib\uuid.lib' ];
442 push @contrib_excludes, 'uuid-ossp';
445 # Pgcrypto makefile too complex to parse....
446 my $pgcrypto = $solution->AddProject('pgcrypto', 'dll', 'crypto');
448 'contrib\pgcrypto', 'pgcrypto.c',
450 'px-crypt.c', 'crypt-gensalt.c',
451 'crypt-blowfish.c', 'crypt-des.c',
452 'crypt-md5.c', 'mbuf.c',
453 'pgp.c', 'pgp-armor.c',
454 'pgp-cfb.c', 'pgp-compress.c',
455 'pgp-decrypt.c', 'pgp-encrypt.c',
456 'pgp-info.c', 'pgp-mpi.c',
457 'pgp-pubdec.c', 'pgp-pubenc.c',
458 'pgp-pubkey.c', 'pgp-s2k.c',
460 if ($solution->{options}->{openssl})
462 $pgcrypto->AddFiles('contrib\pgcrypto', 'openssl.c',
463 'pgp-mpi-openssl.c');
468 'contrib\pgcrypto', 'md5.c',
470 'internal.c', 'internal-sha2.c',
471 'blf.c', 'rijndael.c',
472 'fortuna.c', 'random.c',
473 'pgp-mpi-internal.c', 'imath.c');
475 $pgcrypto->AddReference($postgres);
476 $pgcrypto->AddLibrary('wsock32.lib');
477 my $mf = Project::read_file('contrib/pgcrypto/Makefile');
478 GenerateContribSqlFiles('pgcrypto', $mf);
481 opendir($D, 'contrib') || croak "Could not opendir on contrib!\n";
482 while (my $d = readdir($D))
484 next if ($d =~ /^\./);
485 next unless (-f "contrib/$d/Makefile");
486 next if (grep { /^$d$/ } @contrib_excludes);
492 Project::read_file('src\backend\utils\mb\conversion_procs\Makefile');
493 $mf =~ s{\\s*[\r\n]+}{}mg;
494 $mf =~ m{SUBDIRS\s*=\s*(.*)$}m
495 || die 'Could not match in conversion makefile' . "\n";
496 foreach my $sub (split /\s+/, $1)
498 my $mf = Project::read_file(
499 'src\backend\utils\mb\conversion_procs\\' . $sub . '\Makefile');
500 my $p = $solution->AddProject($sub, 'dll', 'conversion procs');
501 $p->AddFile('src\backend\utils\mb\conversion_procs\\'
505 if ($mf =~ m{^SRCS\s*\+=\s*(.*)$}m)
508 'src\backend\utils\mb\conversion_procs\\' . $sub . '\\' . $1);
510 $p->AddReference($postgres);
513 $mf = Project::read_file('src\bin\scripts\Makefile');
514 $mf =~ s{\\s*[\r\n]+}{}mg;
515 $mf =~ m{PROGRAMS\s*=\s*(.*)$}m
516 || die 'Could not match in bin\scripts\Makefile' . "\n";
517 foreach my $prg (split /\s+/, $1)
519 my $proj = $solution->AddProject($prg, 'exe', 'bin');
520 $mf =~ m{$prg\s*:\s*(.*)$}m
521 || die 'Could not find script define for $prg' . "\n";
522 my @files = split /\s+/, $1;
523 foreach my $f (@files)
526 if ($f eq 'keywords.c')
528 $proj->AddFile('src\bin\pg_dump\keywords.c');
530 elsif ($f eq 'kwlookup.c')
532 $proj->AddFile('src\backend\parser\kwlookup.c');
534 elsif ($f eq 'dumputils.c')
536 $proj->AddFile('src\bin\pg_dump\dumputils.c');
538 elsif ($f =~ /print\.c$/)
539 { # Also catches mbprint.c
540 $proj->AddFile('src\bin\psql\\' . $f);
544 $proj->AddFile('src\bin\scripts\\' . $f);
547 $proj->AddIncludeDir('src\interfaces\libpq');
548 $proj->AddIncludeDir('src\bin\pg_dump');
549 $proj->AddIncludeDir('src\bin\psql');
550 $proj->AddReference($libpq, $libpgport);
551 $proj->AddResourceFile('src\bin\scripts', 'PostgreSQL Utility');
554 # Regression DLL and EXE
555 my $regress = $solution->AddProject('regress', 'dll', 'misc');
556 $regress->AddFile('src\test\regress\regress.c');
557 $regress->AddReference($postgres);
559 my $pgregress = $solution->AddProject('pg_regress', 'exe', 'misc');
560 $pgregress->AddFile('src\test\regress\pg_regress.c');
561 $pgregress->AddFile('src\test\regress\pg_regress_main.c');
562 $pgregress->AddIncludeDir('src\port');
563 $pgregress->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
564 $pgregress->AddReference($libpgport);
567 return $solution->{vcver};
570 #####################
571 # Utility functions #
572 #####################
574 # Add a simple frontend project (exe)
575 sub AddSimpleFrontend
578 my $uselibpq = shift;
580 my $p = $solution->AddProject($n, 'exe', 'bin');
581 $p->AddDir('src\bin\\' . $n);
582 $p->AddReference($libpgport);
585 $p->AddIncludeDir('src\interfaces\libpq');
586 $p->AddReference($libpq);
591 # Add a simple contrib project
595 my $mf = Project::read_file('contrib\\' . $n . '\Makefile');
597 if ($mf =~ /^MODULE_big\s*=\s*(.*)$/mg)
600 $mf =~ s{\\\s*[\r\n]+}{}mg;
601 my $proj = $solution->AddProject($dn, 'dll', 'contrib');
602 $mf =~ /^OBJS\s*=\s*(.*)$/gm
603 || croak "Could not find objects in MODULE_big for $n\n";
605 while ($objs =~ /\b([\w-]+\.o)\b/g)
609 $proj->AddFile('contrib\\' . $n . '\\' . $o);
611 $proj->AddReference($postgres);
612 if ($mf =~ /^SUBDIRS\s*:?=\s*(.*)$/mg)
614 foreach my $d (split /\s+/, $1)
616 my $mf2 = Project::read_file(
617 'contrib\\' . $n . '\\' . $d . '\Makefile');
618 $mf2 =~ s{\\\s*[\r\n]+}{}mg;
619 $mf2 =~ /^SUBOBJS\s*=\s*(.*)$/gm
621 "Could not find objects in MODULE_big for $n, subdir $d\n";
623 while ($objs =~ /\b([\w-]+\.o)\b/g)
627 $proj->AddFile('contrib\\' . $n . '\\' . $d . '\\' . $o);
631 AdjustContribProj($proj);
633 elsif ($mf =~ /^MODULES\s*=\s*(.*)$/mg)
635 foreach my $mod (split /\s+/, $1)
637 my $proj = $solution->AddProject($mod, 'dll', 'contrib');
638 $proj->AddFile('contrib\\' . $n . '\\' . $mod . '.c');
639 $proj->AddReference($postgres);
640 AdjustContribProj($proj);
643 elsif ($mf =~ /^PROGRAM\s*=\s*(.*)$/mg)
645 my $proj = $solution->AddProject($1, 'exe', 'contrib');
646 $mf =~ s{\\\s*[\r\n]+}{}mg;
647 $mf =~ /^OBJS\s*=\s*(.*)$/gm
648 || croak "Could not find objects in PROGRAM for $n\n";
650 while ($objs =~ /\b([\w-]+\.o)\b/g)
654 $proj->AddFile('contrib\\' . $n . '\\' . $o);
656 AdjustContribProj($proj);
660 croak "Could not determine contrib module type for $n\n";
663 # Are there any output data files to build?
664 GenerateContribSqlFiles($n, $mf);
667 sub GenerateContribSqlFiles
671 if ($mf =~ /^DATA_built\s*=\s*(.*)$/mg)
675 # Strip out $(addsuffix) rules
676 if (index($l, '$(addsuffix ') >= 0)
680 for ($i = index($l, '$(addsuffix ') + 12; $i < length($l); $i++)
682 $pcount++ if (substr($l, $i, 1) eq '(');
683 $pcount-- if (substr($l, $i, 1) eq ')');
684 last if ($pcount < 0);
687 substr($l, 0, index($l, '$(addsuffix ')) . substr($l, $i + 1);
690 foreach my $d (split /\s+/, $l)
695 if (Solution::IsNewer("contrib/$n/$out", "contrib/$n/$in"))
697 print "Building $out from $in (contrib/$n)...\n";
698 my $cont = Project::read_file("contrib/$n/$in");
701 $cont =~ s/MODULE_PATHNAME/\$libdir\/$dn/g;
703 open($o, ">contrib/$n/$out")
704 || croak "Could not write to contrib/$n/$d";
712 sub AdjustContribProj
715 my $n = $proj->{name};
717 if ($contrib_defines->{$n})
719 foreach my $d ($contrib_defines->{$n})
721 $proj->AddDefine($d);
724 if (grep { /^$n$/ } @contrib_uselibpq)
726 $proj->AddIncludeDir('src\interfaces\libpq');
727 $proj->AddReference($libpq);
729 if (grep { /^$n$/ } @contrib_uselibpgport)
731 $proj->AddReference($libpgport);
733 if ($contrib_extralibs->{$n})
735 foreach my $l (@{ $contrib_extralibs->{$n} })
737 $proj->AddLibrary($l);
740 if ($contrib_extraincludes->{$n})
742 foreach my $i (@{ $contrib_extraincludes->{$n} })
744 $proj->AddIncludeDir($i);
747 if ($contrib_extrasource->{$n})
749 $proj->AddFiles('contrib\\' . $n, @{ $contrib_extrasource->{$n} });