OSDN Git Service

Add missing library and include dir for XSLT in MSVC builds
[pg-rex/syncrep.git] / src / tools / msvc / Solution.pm
1 package Solution;
2
3 #
4 # Package that encapsulates a Visual C++ solution file generation
5 #
6 # $PostgreSQL: pgsql/src/tools/msvc/Solution.pm,v 1.55 2010/03/02 22:02:31 adunstan Exp $
7 #
8 use Carp;
9 use strict;
10 use warnings;
11
12 sub new
13 {
14     my $junk = shift;
15     my $options = shift;
16     my $self = {
17         projects => {},
18         options  => $options,
19         numver   => '',
20         strver   => '',
21         vcver    => undef,
22         platform => undef,
23     };
24     bless $self;
25         # integer_datetimes is now the default
26         $options->{integer_datetimes} = 1 
27                 unless exists $options->{integer_datetimes};
28     $options->{float4byval} = 1
29         unless exists $options->{float4byval};
30     if ($options->{xml})
31     {
32         if (!($options->{xslt} && $options->{iconv}))
33         {
34             die "XML requires both XSLT and ICONV\n";
35         }
36     }
37         $options->{blocksize} = 8
38                 unless $options->{blocksize}; # undef or 0 means default
39         die "Bad blocksize $options->{blocksize}"
40                 unless grep {$_ == $options->{blocksize}} (1,2,4,8,16,32);
41         $options->{segsize} = 1
42                 unless $options->{segsize}; # undef or 0 means default
43         # only allow segsize 1 for now, as we can't do large files yet in windows
44         die "Bad segsize $options->{segsize}"
45                 unless $options->{segsize} == 1;
46         $options->{wal_blocksize} = 8
47                 unless $options->{wal_blocksize}; # undef or 0 means default
48         die "Bad wal_blocksize $options->{wal_blocksize}"
49                 unless grep {$_ == $options->{wal_blocksize}} (1,2,4,8,16,32,64);
50         $options->{wal_segsize} = 16
51                 unless $options->{wal_segsize}; # undef or 0 means default
52         die "Bad wal_segsize $options->{wal_segsize}"
53                 unless grep {$_ == $options->{wal_segsize}} (1,2,4,8,16,32,64);
54
55     $self->DetermineToolVersions();
56
57     return $self;
58 }
59
60 sub DetermineToolVersions
61 {
62     my $self = shift;
63
64 # Determine version of vcbuild command, to set proper verison of visual studio
65     open(P,"vcbuild /? |") || die "vcbuild command not found";
66     my $line = <P>;
67     close(P);
68     if ($line !~ /^Microsoft\s*\(R\) Visual C\+\+ Project Builder - \D+(\d+)\.00\.\d+/) {
69        die "Unable to determine vcbuild version from first line of output!";
70     }
71     if ($1 == 8) { $self->{vcver} = '8.00' }
72     elsif ($1 == 9) { $self->{vcver} = '9.00' }
73     else { die "Unsupported version of Visual Studio: $1" }
74     print "Detected Visual Studio version $self->{vcver}\n";
75
76 # Determine if we are in 32 or 64-bit mode. Do this by seeing if CL has
77 # 64-bit only parameters.
78         $self->{platform} = 'Win32';
79         open(P,"cl /? 2>NUL|") || die "cl command not found";
80         while (<P>) {
81                 if (/^\/favor:</) {
82                         $self->{platform} = 'x64';
83                         last;
84                 }
85         }
86         close(P);
87         print "Detected hardware platform: $self->{platform}\n";
88 }
89
90
91 # Return 1 if $oldfile is newer than $newfile, or if $newfile doesn't exist.
92 # Special case - if config.pl has changed, always return 1
93 sub IsNewer
94 {
95     my ($newfile, $oldfile) = @_;
96     if ($oldfile ne 'src\tools\msvc\config.pl' && $oldfile ne 'src\tools\msvc\config_default.pl')
97     {
98         return 1 if (-f 'src\tools\msvc\config.pl') && IsNewer($newfile, 'src\tools\msvc\config.pl');
99         return 1 if (-f 'src\tools\msvc\config_default.pl') && IsNewer($newfile, 'src\tools\msvc\config_default.pl');
100     }
101     return 1 if (!(-e $newfile));
102     my @nstat = stat($newfile);
103     my @ostat = stat($oldfile);
104     return 1 if ($nstat[9] < $ostat[9]);
105     return 0;
106 }
107
108 # Copy a file, *not* preserving date. Only works for text files.
109 sub copyFile
110 {
111     my ($src, $dest) = @_;
112     open(I,$src) || croak "Could not open $src";
113     open(O,">$dest") || croak "Could not open $dest";
114     while (<I>)
115     {
116         print O;
117     }
118     close(I);
119     close(O);
120 }
121
122 sub GenerateFiles
123 {
124     my $self = shift;
125     my $bits = $self->{platform} eq 'Win32' ? 32 : 64;
126
127     # Parse configure.in to get version numbers
128     open(C,"configure.in") || confess("Could not open configure.in for reading\n");
129     while (<C>)
130     {
131         if (/^AC_INIT\(\[PostgreSQL\], \[([^\]]+)\]/)
132         {
133             $self->{strver} = $1;
134             if ($self->{strver} !~ /^(\d+)\.(\d+)(?:\.(\d+))?/)
135             {
136                 confess "Bad format of version: $self->{strver}\n";
137             }
138             $self->{numver} = sprintf("%d%02d%02d", $1, $2, $3?$3:0);
139             $self->{majorver} = sprintf("%d.%d", $1, $2);
140         }
141     }
142     close(C);
143     confess "Unable to parse configure.in for all variables!"
144       if ($self->{strver} eq '' || $self->{numver} eq '');
145
146     if (IsNewer("src\\include\\pg_config_os.h","src\\include\\port\\win32.h"))
147     {
148         print "Copying pg_config_os.h...\n";
149         copyFile("src\\include\\port\\win32.h","src\\include\\pg_config_os.h");
150     }
151
152     if (IsNewer("src\\include\\pg_config.h","src\\include\\pg_config.h.win32"))
153     {
154         print "Generating pg_config.h...\n";
155         open(I,"src\\include\\pg_config.h.win32") || confess "Could not open pg_config.h.win32\n";
156         open(O,">src\\include\\pg_config.h") || confess "Could not write to pg_config.h\n";
157         while (<I>)
158         {
159             s{PG_VERSION "[^"]+"}{PG_VERSION "$self->{strver}"};
160             s{PG_VERSION_NUM \d+}{PG_VERSION_NUM $self->{numver}};
161 s{PG_VERSION_STR "[^"]+"}{__STRINGIFY(x) #x\n#define __STRINGIFY2(z) __STRINGIFY(z)\n#define PG_VERSION_STR "PostgreSQL $self->{strver}, compiled by Visual C++ build " __STRINGIFY2(_MSC_VER) ", $bits-bit"};
162             print O;
163         }
164                 print O "#define PG_MAJORVERSION \"$self->{majorver}\"\n";
165         print O "#define LOCALEDIR \"/share/locale\"\n" if ($self->{options}->{nls});
166         print O "/* defines added by config steps */\n";
167         print O "#ifndef IGNORE_CONFIGURED_SETTINGS\n";
168         print O "#define USE_ASSERT_CHECKING 1\n" if ($self->{options}->{asserts});
169         print O "#define USE_INTEGER_DATETIMES 1\n" if ($self->{options}->{integer_datetimes});
170         print O "#define USE_LDAP 1\n" if ($self->{options}->{ldap});
171         print O "#define HAVE_LIBZ 1\n" if ($self->{options}->{zlib});
172         print O "#define USE_SSL 1\n" if ($self->{options}->{openssl});
173                 print O "#define ENABLE_NLS 1\n" if ($self->{options}->{nls});
174
175                 print O "#define BLCKSZ ",1024 * $self->{options}->{blocksize},"\n";
176                 print O "#define RELSEG_SIZE ",
177                         (1024 / $self->{options}->{blocksize}) * 
178                                 $self->{options}->{segsize} * 1024, "\n";
179                 print O "#define XLOG_BLCKSZ ",
180                         1024 * $self->{options}->{wal_blocksize},"\n";
181                 print O "#define XLOG_SEG_SIZE (",
182                         $self->{options}->{wal_segsize}," * 1024 * 1024)\n";
183         
184         if ($self->{options}->{float4byval}) 
185         {
186             print O "#define USE_FLOAT4_BYVAL 1\n";
187             print O "#define FLOAT4PASSBYVAL true\n";
188         }
189         else
190         {
191             print O "#define FLOAT4PASSBYVAL false\n";
192         }
193         if ($self->{options}->{float8byval})
194         {
195             print O "#define USE_FLOAT8_BYVAL 1\n";
196             print O "#define FLOAT8PASSBYVAL true\n";
197         }
198         else
199         {
200             print O "#define FLOAT8PASSBYVAL false\n";
201         }
202
203         if ($self->{options}->{uuid})
204         {
205             print O "#define HAVE_UUID_H\n";
206         }
207         if ($self->{options}->{xml})
208         {
209             print O "#define HAVE_LIBXML2\n";
210             print O "#define USE_LIBXML\n";
211         }
212         if ($self->{options}->{xslt})
213         {
214             print O "#define HAVE_LIBXSLT\n";
215             print O "#define USE_LIBXSLT\n";
216         }
217         if ($self->{options}->{krb5})
218         {
219             print O "#define KRB5 1\n";
220             print O "#define HAVE_KRB5_ERROR_TEXT_DATA 1\n";
221             print O "#define HAVE_KRB5_TICKET_ENC_PART2 1\n";
222             print O "#define HAVE_KRB5_FREE_UNPARSED_NAME 1\n";
223             print O "#define ENABLE_GSS 1\n";
224         }
225         if (my $port = $self->{options}->{"--with-pgport"})
226         {
227             print O "#undef DEF_PGPORT\n";
228             print O "#undef DEF_PGPORT_STR\n";
229             print O "#define DEF_PGPORT $port\n";
230             print O "#define DEF_PGPORT_STR \"$port\"\n";
231         }
232         print O "#define VAL_CONFIGURE \"" . $self->GetFakeConfigure() . "\"\n";
233         print O "#endif /* IGNORE_CONFIGURED_SETTINGS */\n";
234         close(O);
235         close(I);
236     }
237
238     $self->GenerateDefFile("src\\interfaces\\libpq\\libpqdll.def","src\\interfaces\\libpq\\exports.txt","LIBPQ");
239     $self->GenerateDefFile("src\\interfaces\\ecpg\\ecpglib\\ecpglib.def","src\\interfaces\\ecpg\\ecpglib\\exports.txt","LIBECPG");
240     $self->GenerateDefFile("src\\interfaces\\ecpg\\compatlib\\compatlib.def","src\\interfaces\\ecpg\\compatlib\\exports.txt","LIBECPG_COMPAT");
241     $self->GenerateDefFile("src\\interfaces\\ecpg\\pgtypeslib\\pgtypeslib.def","src\\interfaces\\ecpg\\pgtypeslib\\exports.txt","LIBPGTYPES");
242
243     if (IsNewer('src\backend\utils\fmgrtab.c','src\include\catalog\pg_proc.h'))
244     {
245         print "Generating fmgrtab.c and fmgroids.h...\n";
246         chdir('src\backend\utils');
247         system("perl -I ../catalog Gen_fmgrtab.pl ../../../src/include/catalog/pg_proc.h");
248         chdir('..\..\..');
249         copyFile('src\backend\utils\fmgroids.h','src\include\utils\fmgroids.h');
250     }
251
252     if (IsNewer('src\include\utils\probes.h','src\backend\utils\probes.d'))
253     {
254                 print "Generating probes.h...\n";
255                 system('psed -f src\backend\utils\Gen_dummy_probes.sed src\backend\utils\probes.d > src\include\utils\probes.h'); 
256         }
257
258     if (IsNewer('src\interfaces\libpq\libpq.rc','src\interfaces\libpq\libpq.rc.in'))
259     {
260         print "Generating libpq.rc...\n";
261         my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
262         my $d = ($year - 100) . "$yday";
263         open(I,'<', 'src\interfaces\libpq\libpq.rc.in') || confess "Could not open libpq.rc.in";
264         open(O,'>', 'src\interfaces\libpq\libpq.rc') || confess "Could not open libpq.rc";
265         while (<I>)
266         {
267             s/(VERSION.*),0/$1,$d/;
268             print O;
269         }
270         close(I);
271         close(O);
272     }
273
274     if (IsNewer('src\bin\psql\sql_help.h','src\bin\psql\create_help.pl'))
275     {
276         print "Generating sql_help.h...\n";
277         chdir('src\bin\psql');
278         system("perl create_help.pl ../../../doc/src/sgml/ref sql_help");
279         chdir('..\..\..');
280     }
281
282     if (
283         IsNewer(
284             'src\interfaces\ecpg\preproc\preproc.y',
285             'src\backend\parser\gram.y'
286         )
287       )
288     {
289         print "Generating preproc.y...\n";
290         chdir('src\interfaces\ecpg\preproc');
291         system('perl parse.pl < ..\..\..\backend\parser\gram.y > preproc.y');
292         chdir('..\..\..\..');
293     }
294
295     if (
296         IsNewer(
297             'src\interfaces\ecpg\include\ecpg_config.h',
298             'src\interfaces\ecpg\include\ecpg_config.h.in'
299         )
300       )
301     {
302         print "Generating ecpg_config.h...\n";
303         open(O,'>','src\interfaces\ecpg\include\ecpg_config.h')
304           || confess "Could not open ecpg_config.h";
305         print O <<EOF;
306 #if (_MSC_VER > 1200)
307 #define HAVE_LONG_LONG_INT_64
308 #define ENABLE_THREAD_SAFETY 1
309 EOF
310         print O "#define USE_INTEGER_DATETIMES 1\n" if ($self->{options}->{integer_datetimes});
311         print O "#endif\n";
312         close(O);
313     }
314
315     unless (-f "src\\port\\pg_config_paths.h")
316     {
317         print "Generating pg_config_paths.h...\n";
318         open(O,'>', 'src\port\pg_config_paths.h') || confess "Could not open pg_config_paths.h";
319         print O  <<EOF;
320 #define PGBINDIR "/bin"
321 #define PGSHAREDIR "/share"
322 #define SYSCONFDIR "/etc"
323 #define INCLUDEDIR "/include"
324 #define PKGINCLUDEDIR "/include"
325 #define INCLUDEDIRSERVER "/include/server"
326 #define LIBDIR "/lib"
327 #define PKGLIBDIR "/lib"
328 #define LOCALEDIR "/share/locale"
329 #define DOCDIR "/doc"
330 #define HTMLDIR "/doc"
331 #define MANDIR "/man"
332 EOF
333         close(O);
334     }
335
336     my $mf = Project::read_file('src\backend\catalog\Makefile');
337     $mf =~ s{\\s*[\r\n]+}{}mg;
338     $mf =~ /^POSTGRES_BKI_SRCS\s*:?=[^,]+,(.*)\)$/gm
339       || croak "Could not find POSTGRES_BKI_SRCS in Makefile\n";
340     my @allbki = split /\s+/, $1;
341     foreach my $bki (@allbki)
342     {
343         next if $bki eq "";
344         if (IsNewer('src/backend/catalog/postgres.bki', "src/include/catalog/$bki"))
345         {
346             print "Generating postgres.bki and schemapg.h...\n";
347             chdir('src\backend\catalog');
348             my $bki_srcs = join(' ../../../src/include/catalog/', @allbki);
349             system("perl genbki.pl -I../../../src/include/catalog --set-version=$self->{majorver} $bki_srcs");
350             chdir('..\..\..');
351             copyFile('src\backend\catalog\schemapg.h', 'src\include\catalog\schemapg.h');
352             last;
353         }
354     }
355
356     open(O, ">doc/src/sgml/version.sgml") || croak "Could not write to version.sgml\n";
357     print O <<EOF;
358 <!entity version "$self->{strver}">
359 <!entity majorversion "$self->{majorver}">
360 EOF
361     close(O);
362 }
363
364 sub GenerateDefFile
365 {
366     my ($self, $deffile, $txtfile, $libname)  = @_;
367
368     if (IsNewer($deffile,$txtfile))
369     {
370         print "Generating $deffile...\n";
371         open(I,$txtfile) || confess("Could not open $txtfile\n");
372         open(O,">$deffile") || confess("Could not open $deffile\n");
373         print O "LIBRARY $libname\nEXPORTS\n";
374         while (<I>)
375         {
376             next if (/^#/);
377             next if (/^\s*$/);
378             my ($f, $o) = split;
379             print O " $f @ $o\n";
380         }
381         close(O);
382         close(I);
383     }
384 }
385
386 sub AddProject
387 {
388     my ($self, $name, $type, $folder, $initialdir) = @_;
389
390     my $proj = new Project($name, $type, $self);
391     push @{$self->{projects}->{$folder}}, $proj;
392     $proj->AddDir($initialdir) if ($initialdir);
393     if ($self->{options}->{zlib})
394     {
395         $proj->AddIncludeDir($self->{options}->{zlib} . '\include');
396         $proj->AddLibrary($self->{options}->{zlib} . '\lib\zdll.lib');
397     }
398     if ($self->{options}->{openssl})
399     {
400         $proj->AddIncludeDir($self->{options}->{openssl} . '\include');
401         $proj->AddLibrary($self->{options}->{openssl} . '\lib\VC\ssleay32.lib', 1);
402         $proj->AddLibrary($self->{options}->{openssl} . '\lib\VC\libeay32.lib', 1);
403     }
404     if ($self->{options}->{nls})
405     {
406         $proj->AddIncludeDir($self->{options}->{nls} . '\include');
407         $proj->AddLibrary($self->{options}->{nls} . '\lib\libintl.lib');
408     }
409     if ($self->{options}->{krb5})
410     {
411         $proj->AddIncludeDir($self->{options}->{krb5} . '\inc\krb5');
412         $proj->AddLibrary($self->{options}->{krb5} . '\lib\i386\krb5_32.lib');
413         $proj->AddLibrary($self->{options}->{krb5} . '\lib\i386\comerr32.lib');
414         $proj->AddLibrary($self->{options}->{krb5} . '\lib\i386\gssapi32.lib');
415     }
416     if ($self->{options}->{xml})
417     {
418         $proj->AddIncludeDir($self->{options}->{xml} . '\include');
419         $proj->AddIncludeDir($self->{options}->{iconv} . '\include');
420         $proj->AddLibrary($self->{options}->{xml} . '\lib\libxml2.lib');
421     }
422     if ($self->{options}->{xslt})
423     {
424         $proj->AddIncludeDir($self->{options}->{xslt} . '\include');
425         $proj->AddLibrary($self->{options}->{xslt} . '\lib\libxslt.lib');
426     }
427     return $proj;
428 }
429
430 sub Save
431 {
432     my ($self) = @_;
433     my %flduid;
434
435     $self->GenerateFiles();
436     foreach my $fld (keys %{$self->{projects}})
437     {
438         foreach my $proj (@{$self->{projects}->{$fld}})
439         {
440             $proj->Save();
441         }
442     }
443
444     open(SLN,">pgsql.sln") || croak "Could not write to pgsql.sln\n";
445     print SLN <<EOF;
446 Microsoft Visual Studio Solution File, Format Version 9.00
447 # Visual Studio 2005
448 EOF
449
450     foreach my $fld (keys %{$self->{projects}})
451     {
452         foreach my $proj (@{$self->{projects}->{$fld}})
453         {
454             print SLN <<EOF;
455 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "$proj->{name}", "$proj->{name}.vcproj", "$proj->{guid}"
456 EndProject
457 EOF
458         }
459         if ($fld ne "")
460         {
461             $flduid{$fld} = Win32::GuidGen();
462             print SLN <<EOF;
463 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "$fld", "$fld", "$flduid{$fld}"
464 EndProject
465 EOF
466         }
467     }
468
469     print SLN <<EOF;
470 Global
471         GlobalSection(SolutionConfigurationPlatforms) = preSolution
472                 Debug|$self->{platform}= Debug|$self->{platform}
473                 Release|$self->{platform} = Release|$self->{platform}
474         EndGlobalSection
475         GlobalSection(ProjectConfigurationPlatforms) = postSolution
476 EOF
477
478     foreach my $fld (keys %{$self->{projects}})
479     {
480         foreach my $proj (@{$self->{projects}->{$fld}})
481         {
482             print SLN <<EOF;
483                 $proj->{guid}.Debug|$self->{platform}.ActiveCfg = Debug|$self->{platform}
484                 $proj->{guid}.Debug|$self->{platform}.Build.0  = Debug|$self->{platform}
485                 $proj->{guid}.Release|$self->{platform}.ActiveCfg = Release|$self->{platform}
486                 $proj->{guid}.Release|$self->{platform}.Build.0 = Release|$self->{platform}
487 EOF
488         }
489     }
490
491     print SLN <<EOF;
492         EndGlobalSection
493         GlobalSection(SolutionProperties) = preSolution
494                 HideSolutionNode = FALSE
495         EndGlobalSection
496         GlobalSection(NestedProjects) = preSolution
497 EOF
498
499     foreach my $fld (keys %{$self->{projects}})
500     {
501         next if ($fld eq "");
502         foreach my $proj (@{$self->{projects}->{$fld}})
503         {
504             print SLN "\t\t$proj->{guid} = $flduid{$fld}\n";
505         }
506     }
507
508     print SLN <<EOF;
509         EndGlobalSection
510 EndGlobal
511 EOF
512     close(SLN);
513 }
514
515 sub GetFakeConfigure
516 {
517     my $self = shift;
518
519     my $cfg = '--enable-thread-safety';
520     $cfg .= ' --enable-cassert' if ($self->{options}->{asserts});
521     $cfg .= ' --enable-integer-datetimes' if ($self->{options}->{integer_datetimes});
522     $cfg .= ' --enable-nls' if ($self->{options}->{nls});
523     $cfg .= ' --with-ldap' if ($self->{options}->{ldap});
524     $cfg .= ' --without-zlib' unless ($self->{options}->{zlib});
525     $cfg .= ' --with-openssl' if ($self->{options}->{ssl});
526     $cfg .= ' --with-ossp-uuid' if ($self->{options}->{uuid});
527     $cfg .= ' --with-libxml' if ($self->{options}->{xml});
528     $cfg .= ' --with-libxslt' if ($self->{options}->{xslt});
529     $cfg .= ' --with-krb5' if ($self->{options}->{krb5});
530     $cfg .= ' --with-tcl' if ($self->{options}->{tcl});
531     $cfg .= ' --with-perl' if ($self->{options}->{perl});
532     $cfg .= ' --with-python' if ($self->{options}->{python});
533
534     return $cfg;
535 }
536
537 1;