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