]> granicus.if.org Git - postgresql/blob - src/tools/msvc/Mkvcbuild.pm
Centralize single quote escaping in src/port/quotes.c
[postgresql] / src / tools / msvc / Mkvcbuild.pm
1 package Mkvcbuild;
2
3 #
4 # Package that generates build files for msvc build
5 #
6 # src/tools/msvc/Mkvcbuild.pm
7 #
8 use Carp;
9 use Win32;
10 use strict;
11 use warnings;
12 use Project;
13 use Solution;
14 use Cwd;
15 use File::Copy;
16 use Config;
17 use VSObjectFactory;
18 use List::Util qw(first);
19
20 use Exporter;
21 our (@ISA, @EXPORT_OK);
22 @ISA       = qw(Exporter);
23 @EXPORT_OK = qw(Mkvcbuild);
24
25 my $solution;
26 my $libpgport;
27 my $postgres;
28 my $libpq;
29
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');
45
46 sub mkvcbuild
47 {
48         our $config = shift;
49
50         chdir('..\..\..') if (-d '..\msvc' && -d '..\..\..\src');
51         die 'Must run from root or msvc directory'
52           unless (-d 'src\tools\msvc' && -d 'src');
53
54         my $vsVersion = DetermineVisualStudioVersion();
55
56         $solution = CreateSolution($vsVersion, $config);
57
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);
65
66         $libpgport = $solution->AddProject('libpgport', 'lib', 'misc');
67         $libpgport->AddDefine('FRONTEND');
68         $libpgport->AddFiles('src\port', @pgportfiles);
69
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',
87                 'bootparse.y');
88         $postgres->AddFiles('src\backend\utils\misc', 'guc-file.l');
89         $postgres->AddFiles('src\backend\replication', 'repl_scanner.l',
90                 'repl_gram.y');
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');
97
98         my $snowball = $solution->AddProject('dict_snowball', 'dll', '',
99                 'src\backend\snowball');
100         $snowball->RelocateFiles(
101                 'src\backend\snowball\libstemmer',
102                 sub {
103                         return shift !~ /dict_snowball.c$/;
104                 });
105         $snowball->AddIncludeDir('src\include\snowball');
106         $snowball->AddReference($postgres);
107
108         my $plpgsql =
109           $solution->AddProject('plpgsql', 'dll', 'PLs', 'src\pl\plpgsql\src');
110         $plpgsql->AddFiles('src\pl\plpgsql\src', 'pl_gram.y');
111         $plpgsql->AddReference($postgres);
112
113         if ($solution->{options}->{perl})
114         {
115                 my $plperlsrc = "src\\pl\\plperl\\";
116                 my $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')
121                 {
122                         (my $xsc = $xs) =~ s/\.xs/.c/;
123                         if (Solution::IsNewer("$plperlsrc$xsc", "$plperlsrc$xs"))
124                         {
125                                 my $xsubppdir = first { -e "$_\\ExtUtils\\xsubpp" } @INC;
126                                 print "Building $plperlsrc$xsc...\n";
127                                 system( $solution->{options}->{perl}
128                                           . '/bin/perl '
129                                           . "$xsubppdir/ExtUtils/xsubpp -typemap "
130                                           . $solution->{options}->{perl}
131                                           . '/lib/ExtUtils/typemap '
132                                           . "$plperlsrc$xs "
133                                           . ">$plperlsrc$xsc");
134                                 if ((!(-f "$plperlsrc$xsc")) || -z "$plperlsrc$xsc")
135                                 {
136                                         unlink("$plperlsrc$xsc");    # if zero size
137                                         die "Failed to create $xsc.\n";
138                                 }
139                         }
140                 }
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'))
147                 {
148                         print 'Building src\pl\plperl\perlchunks.h ...' . "\n";
149                         my $basedir = getcwd;
150                         chdir 'src\pl\plperl';
151                         system( $solution->{options}->{perl}
152                                   . '/bin/perl '
153                                   . 'text2macro.pl '
154                                   . '--strip="^(\#.*|\s*)$$" '
155                                   . 'plc_perlboot.pl plc_trusted.pl '
156                                   . '>perlchunks.h');
157                         chdir $basedir;
158                         if ((!(-f 'src\pl\plperl\perlchunks.h'))
159                                 || -z 'src\pl\plperl\perlchunks.h')
160                         {
161                                 unlink('src\pl\plperl\perlchunks.h');    # if zero size
162                                 die 'Failed to create perlchunks.h' . "\n";
163                         }
164                 }
165                 if (Solution::IsNewer(
166                                 'src\pl\plperl\plperl_opmask.h',
167                                 'src\pl\plperl\plperl_opmask.pl'))
168                 {
169                         print 'Building src\pl\plperl\plperl_opmask.h ...' . "\n";
170                         my $basedir = getcwd;
171                         chdir 'src\pl\plperl';
172                         system( $solution->{options}->{perl}
173                                   . '/bin/perl '
174                                   . 'plperl_opmask.pl '
175                                   . 'plperl_opmask.h');
176                         chdir $basedir;
177                         if ((!(-f 'src\pl\plperl\plperl_opmask.h'))
178                                 || -z 'src\pl\plperl\plperl_opmask.h')
179                         {
180                                 unlink('src\pl\plperl\plperl_opmask.h');    # if zero size
181                                 die 'Failed to create plperl_opmask.h' . "\n";
182                         }
183                 }
184                 $plperl->AddReference($postgres);
185                 my @perl_libs =
186                   grep { /perl\d+.lib$/ }
187                   glob($solution->{options}->{perl} . '\lib\CORE\perl*.lib');
188                 if (@perl_libs == 1)
189                 {
190                         $plperl->AddLibrary($perl_libs[0]);
191                 }
192                 else
193                 {
194                         die "could not identify perl library version";
195                 }
196         }
197
198         if ($solution->{options}->{python})
199         {
200
201                 # Attempt to get python version and location.
202                 # Assume python.exe in specified dir.
203                 open(P,
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";
207                 my $pyprefix = <P>;
208                 chomp($pyprefix);
209                 my $pyver = <P>;
210                 chomp($pyver);
211                 close(P);
212
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)));
217
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);
224         }
225
226         if ($solution->{options}->{tcl})
227         {
228                 my $pltcl =
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')
233                 {
234                         $pltcl->AddLibrary(
235                                 $solution->{options}->{tcl} . '\lib\tcl85.lib');
236                 }
237                 else
238                 {
239                         $pltcl->AddLibrary(
240                                 $solution->{options}->{tcl} . '\lib\tcl84.lib');
241                 }
242         }
243
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);
257
258         my $libpqwalreceiver =
259           $solution->AddProject('libpqwalreceiver', 'dll', '',
260                 'src\backend\replication\libpqwalreceiver');
261         $libpqwalreceiver->AddIncludeDir('src\interfaces\libpq');
262         $libpqwalreceiver->AddReference($postgres, $libpq);
263
264         my $pgtypes = $solution->AddProject(
265                 'libpgtypes', 'dll',
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');
271
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);
281
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);
289
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);
301
302         my $pgregress_ecpg =
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);
311
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);
326
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);
336
337         # src/bin
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');
344
345         my $pgbasebackup = AddSimpleFrontend('pg_basebackup', 1);
346         $pgbasebackup->AddFile('src\bin\pg_basebackup\pg_basebackup.c');
347         $pgbasebackup->AddLibrary('ws2_32.lib');
348
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');
353
354         my $pgconfig = AddSimpleFrontend('pg_config');
355
356         my $pgcontrol = AddSimpleFrontend('pg_controldata');
357
358         my $pgctl = AddSimpleFrontend('pg_ctl', 1);
359
360         my $pgreset = AddSimpleFrontend('pg_resetxlog');
361
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');
369
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');
374
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');
382
383         my $pgdumpall = AddSimpleFrontend('pg_dump', 1);
384
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');
399
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');
406
407         my $zic = $solution->AddProject('zic', 'exe', 'utils');
408         $zic->AddFiles('src\timezone', 'zic.c', 'ialloc.c', 'scheck.c',
409                 'localtime.c');
410         $zic->AddReference($libpgport);
411
412         if ($solution->{options}->{xml})
413         {
414                 $contrib_extraincludes->{'pgxml'} = [
415                         $solution->{options}->{xml} . '\include',
416                         $solution->{options}->{xslt} . '\include',
417                         $solution->{options}->{iconv} . '\include' ];
418
419                 $contrib_extralibs->{'pgxml'} = [
420                         $solution->{options}->{xml} . '\lib\libxml2.lib',
421                         $solution->{options}->{xslt} . '\lib\libxslt.lib' ];
422         }
423         else
424         {
425                 push @contrib_excludes, 'xml2';
426         }
427
428         if (!$solution->{options}->{openssl})
429         {
430                 push @contrib_excludes, 'sslinfo';
431         }
432
433         if ($solution->{options}->{uuid})
434         {
435                 $contrib_extraincludes->{'uuid-ossp'} =
436                   [ $solution->{options}->{uuid} . '\include' ];
437                 $contrib_extralibs->{'uuid-ossp'} =
438                   [ $solution->{options}->{uuid} . '\lib\uuid.lib' ];
439         }
440         else
441         {
442                 push @contrib_excludes, 'uuid-ossp';
443         }
444
445         # Pgcrypto makefile too complex to parse....
446         my $pgcrypto = $solution->AddProject('pgcrypto', 'dll', 'crypto');
447         $pgcrypto->AddFiles(
448                 'contrib\pgcrypto', 'pgcrypto.c',
449                 'px.c',             'px-hmac.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',
459                 'pgp-pgsql.c');
460         if ($solution->{options}->{openssl})
461         {
462                 $pgcrypto->AddFiles('contrib\pgcrypto', 'openssl.c',
463                         'pgp-mpi-openssl.c');
464         }
465         else
466         {
467                 $pgcrypto->AddFiles(
468                         'contrib\pgcrypto',   'md5.c',
469                         'sha1.c',             'sha2.c',
470                         'internal.c',         'internal-sha2.c',
471                         'blf.c',              'rijndael.c',
472                         'fortuna.c',          'random.c',
473                         'pgp-mpi-internal.c', 'imath.c');
474         }
475         $pgcrypto->AddReference($postgres);
476         $pgcrypto->AddLibrary('wsock32.lib');
477         my $mf = Project::read_file('contrib/pgcrypto/Makefile');
478         GenerateContribSqlFiles('pgcrypto', $mf);
479
480         my $D;
481         opendir($D, 'contrib') || croak "Could not opendir on contrib!\n";
482         while (my $d = readdir($D))
483         {
484                 next if ($d =~ /^\./);
485                 next unless (-f "contrib/$d/Makefile");
486                 next if (grep { /^$d$/ } @contrib_excludes);
487                 AddContrib($d);
488         }
489         closedir($D);
490
491         $mf =
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)
497         {
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\\' 
502                           . $sub . '\\' 
503                           . $sub
504                           . '.c');
505                 if ($mf =~ m{^SRCS\s*\+=\s*(.*)$}m)
506                 {
507                         $p->AddFile(
508                                 'src\backend\utils\mb\conversion_procs\\' . $sub . '\\' . $1);
509                 }
510                 $p->AddReference($postgres);
511         }
512
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)
518         {
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)
524                 {
525                         $f =~ s/\.o$/\.c/;
526                         if ($f eq 'keywords.c')
527                         {
528                                 $proj->AddFile('src\bin\pg_dump\keywords.c');
529                         }
530                         elsif ($f eq 'kwlookup.c')
531                         {
532                                 $proj->AddFile('src\backend\parser\kwlookup.c');
533                         }
534                         elsif ($f eq 'dumputils.c')
535                         {
536                                 $proj->AddFile('src\bin\pg_dump\dumputils.c');
537                         }
538                         elsif ($f =~ /print\.c$/)
539                         {    # Also catches mbprint.c
540                                 $proj->AddFile('src\bin\psql\\' . $f);
541                         }
542                         elsif ($f =~ /\.c$/)
543                         {
544                                 $proj->AddFile('src\bin\scripts\\' . $f);
545                         }
546                 }
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');
552         }
553
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);
558
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);
565
566         $solution->Save();
567         return $solution->{vcver};
568 }
569
570 #####################
571 # Utility functions #
572 #####################
573
574 # Add a simple frontend project (exe)
575 sub AddSimpleFrontend
576 {
577         my $n        = shift;
578         my $uselibpq = shift;
579
580         my $p = $solution->AddProject($n, 'exe', 'bin');
581         $p->AddDir('src\bin\\' . $n);
582         $p->AddReference($libpgport);
583         if ($uselibpq)
584         {
585                 $p->AddIncludeDir('src\interfaces\libpq');
586                 $p->AddReference($libpq);
587         }
588         return $p;
589 }
590
591 # Add a simple contrib project
592 sub AddContrib
593 {
594         my $n  = shift;
595         my $mf = Project::read_file('contrib\\' . $n . '\Makefile');
596
597         if ($mf =~ /^MODULE_big\s*=\s*(.*)$/mg)
598         {
599                 my $dn = $1;
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";
604                 my $objs = $1;
605                 while ($objs =~ /\b([\w-]+\.o)\b/g)
606                 {
607                         my $o = $1;
608                         $o =~ s/\.o$/.c/;
609                         $proj->AddFile('contrib\\' . $n . '\\' . $o);
610                 }
611                 $proj->AddReference($postgres);
612                 if ($mf =~ /^SUBDIRS\s*:?=\s*(.*)$/mg)
613                 {
614                         foreach my $d (split /\s+/, $1)
615                         {
616                                 my $mf2 = Project::read_file(
617                                         'contrib\\' . $n . '\\' . $d . '\Makefile');
618                                 $mf2 =~ s{\\\s*[\r\n]+}{}mg;
619                                 $mf2 =~ /^SUBOBJS\s*=\s*(.*)$/gm
620                                   || croak
621                                   "Could not find objects in MODULE_big for $n, subdir $d\n";
622                                 $objs = $1;
623                                 while ($objs =~ /\b([\w-]+\.o)\b/g)
624                                 {
625                                         my $o = $1;
626                                         $o =~ s/\.o$/.c/;
627                                         $proj->AddFile('contrib\\' . $n . '\\' . $d . '\\' . $o);
628                                 }
629                         }
630                 }
631                 AdjustContribProj($proj);
632         }
633         elsif ($mf =~ /^MODULES\s*=\s*(.*)$/mg)
634         {
635                 foreach my $mod (split /\s+/, $1)
636                 {
637                         my $proj = $solution->AddProject($mod, 'dll', 'contrib');
638                         $proj->AddFile('contrib\\' . $n . '\\' . $mod . '.c');
639                         $proj->AddReference($postgres);
640                         AdjustContribProj($proj);
641                 }
642         }
643         elsif ($mf =~ /^PROGRAM\s*=\s*(.*)$/mg)
644         {
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";
649                 my $objs = $1;
650                 while ($objs =~ /\b([\w-]+\.o)\b/g)
651                 {
652                         my $o = $1;
653                         $o =~ s/\.o$/.c/;
654                         $proj->AddFile('contrib\\' . $n . '\\' . $o);
655                 }
656                 AdjustContribProj($proj);
657         }
658         else
659         {
660                 croak "Could not determine contrib module type for $n\n";
661         }
662
663         # Are there any output data files to build?
664         GenerateContribSqlFiles($n, $mf);
665 }
666
667 sub GenerateContribSqlFiles
668 {
669         my $n  = shift;
670         my $mf = shift;
671         if ($mf =~ /^DATA_built\s*=\s*(.*)$/mg)
672         {
673                 my $l = $1;
674
675                 # Strip out $(addsuffix) rules
676                 if (index($l, '$(addsuffix ') >= 0)
677                 {
678                         my $pcount = 0;
679                         my $i;
680                         for ($i = index($l, '$(addsuffix ') + 12; $i < length($l); $i++)
681                         {
682                                 $pcount++ if (substr($l, $i, 1) eq '(');
683                                 $pcount-- if (substr($l, $i, 1) eq ')');
684                                 last      if ($pcount < 0);
685                         }
686                         $l =
687                           substr($l, 0, index($l, '$(addsuffix ')) . substr($l, $i + 1);
688                 }
689
690                 foreach my $d (split /\s+/, $l)
691                 {
692                         my $in  = "$d.in";
693                         my $out = "$d";
694
695                         if (Solution::IsNewer("contrib/$n/$out", "contrib/$n/$in"))
696                         {
697                                 print "Building $out from $in (contrib/$n)...\n";
698                                 my $cont = Project::read_file("contrib/$n/$in");
699                                 my $dn   = $out;
700                                 $dn   =~ s/\.sql$//;
701                                 $cont =~ s/MODULE_PATHNAME/\$libdir\/$dn/g;
702                                 my $o;
703                                 open($o, ">contrib/$n/$out")
704                                   || croak "Could not write to contrib/$n/$d";
705                                 print $o $cont;
706                                 close($o);
707                         }
708                 }
709         }
710 }
711
712 sub AdjustContribProj
713 {
714         my $proj = shift;
715         my $n    = $proj->{name};
716
717         if ($contrib_defines->{$n})
718         {
719                 foreach my $d ($contrib_defines->{$n})
720                 {
721                         $proj->AddDefine($d);
722                 }
723         }
724         if (grep { /^$n$/ } @contrib_uselibpq)
725         {
726                 $proj->AddIncludeDir('src\interfaces\libpq');
727                 $proj->AddReference($libpq);
728         }
729         if (grep { /^$n$/ } @contrib_uselibpgport)
730         {
731                 $proj->AddReference($libpgport);
732         }
733         if ($contrib_extralibs->{$n})
734         {
735                 foreach my $l (@{ $contrib_extralibs->{$n} })
736                 {
737                         $proj->AddLibrary($l);
738                 }
739         }
740         if ($contrib_extraincludes->{$n})
741         {
742                 foreach my $i (@{ $contrib_extraincludes->{$n} })
743                 {
744                         $proj->AddIncludeDir($i);
745                 }
746         }
747         if ($contrib_extrasource->{$n})
748         {
749                 $proj->AddFiles('contrib\\' . $n, @{ $contrib_extrasource->{$n} });
750         }
751 }
752
753 1;