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