]> granicus.if.org Git - postgresql/blob - src/tools/msvc/Solution.pm
Turn most vc build scripts into modules instead of scripts, and just have
[postgresql] / src / tools / msvc / Solution.pm
1 package Solution;
2 use Carp;
3 use strict;
4 use warnings;
5
6 use Genbki;
7
8 sub new
9 {
10     my $junk = shift;
11     my $options = shift;
12     my $self = {
13         projects => {},
14         options  => $options,
15         numver   => '',
16         strver   => '',
17     };
18     bless $self;
19     if ($options->{xml})
20     {
21         if (!($options->{xslt} && $options->{iconv}))
22         {
23             die "XML requires both XSLT and ICONV\n";
24         }
25     }
26     return $self;
27 }
28
29 # Return 1 if $oldfile is newer than $newfile, or if $newfile doesn't exist.
30 # Special case - if config.pl has changed, always return 1
31 sub IsNewer
32 {
33     my ($newfile, $oldfile) = @_;
34     if ($oldfile ne 'src\tools\msvc\config.pl')
35     {
36         return 1 if IsNewer($newfile, 'src\tools\msvc\config.pl');
37     }
38     return 1 if (!(-e $newfile));
39     my @nstat = stat($newfile);
40     my @ostat = stat($oldfile);
41     return 1 if ($nstat[9] < $ostat[9]);
42     return 0;
43 }
44
45 # Copy a file, *not* preserving date. Only works for text files.
46 sub copyFile
47 {
48     my ($src, $dest) = @_;
49     open(I,$src) || croak "Could not open $src";
50     open(O,">$dest") || croak "Could not open $dest";
51     while (<I>)
52     {
53         print O;
54     }
55     close(I);
56     close(O);
57 }
58
59 sub GenerateFiles
60 {
61     my $self = shift;
62
63     # Parse configure.in to get version numbers
64     open(C,"configure.in") || confess("Could not open configure.in for reading\n");
65     while (<C>)
66     {
67         if (/^AC_INIT\(\[PostgreSQL\], \[([^\]]+)\]/)
68         {
69             $self->{strver} = $1;
70             if ($self->{strver} !~ /^(\d+)\.(\d+)(?:\.(\d+))?/)
71             {
72                 confess "Bad format of version: $self->{strver}\n";
73             }
74             $self->{numver} = sprintf("%d%02d%02d", $1, $2, $3?$3:0);
75             $self->{majorver} = sprintf("%d.%d", $1, $2);
76         }
77     }
78     close(C);
79     confess "Unable to parse configure.in for all variables!"
80       if ($self->{strver} eq '' || $self->{numver} eq '');
81
82     if (IsNewer("src\\include\\pg_config_os.h","src\\include\\port\\win32.h"))
83     {
84         print "Copying pg_config_os.h...\n";
85         copyFile("src\\include\\port\\win32.h","src\\include\\pg_config_os.h");
86     }
87
88     if (IsNewer("src\\include\\pg_config.h","src\\include\\pg_config.h.win32"))
89     {
90         print "Generating pg_config.h...\n";
91         open(I,"src\\include\\pg_config.h.win32") || confess "Could not open pg_config.h.win32\n";
92         open(O,">src\\include\\pg_config.h") || confess "Could not write to pg_config.h\n";
93         while (<I>)
94         {
95             s{PG_VERSION "[^"]+"}{PG_VERSION "$self->{strver}"};
96             s{PG_VERSION_NUM \d+}{PG_VERSION_NUM $self->{numver}};
97 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)};
98             print O;
99         }
100         print O "/* defines added by config steps */\n";
101         print O "#define USE_ASSERT_CHECKING 1\n" if ($self->{options}->{asserts});
102         print O "#define USE_INTEGER_DATETIMES 1\n" if ($self->{options}->{integer_datetimes});
103         print O "#define USE_LDAP 1\n" if ($self->{options}->{ldap});
104         print O "#define HAVE_LIBZ 1\n" if ($self->{options}->{zlib});
105         print O "#define USE_SSL 1\n" if ($self->{options}->{openssl});
106         print O "#define ENABLE_NLS 1\n" if ($self->{options}->{nls});
107         print O "#define LOCALEDIR \"/share/locale\"\n" if ($self->{options}->{nls});
108
109         if ($self->{options}->{xml})
110         {
111             print O "#define HAVE_LIBXML2\n";
112             print O "#define USE_LIBXML\n";
113         }
114         if ($self->{options}->{krb5})
115         {
116             print O "#define KRB5 1\n";
117             print O "#define HAVE_KRB5_ERROR_TEXT_DATA 1\n";
118             print O "#define HAVE_KRB5_TICKET_ENC_PART2 1\n";
119             print O "#define PG_KRB_SRVNAM \"postgres\"\n";
120         }
121         close(O);
122         close(I);
123     }
124
125     if (IsNewer("src\\interfaces\\libpq\\libpqdll.def","src\\interfaces\\libpq\\exports.txt"))
126     {
127         print "Generating libpqdll.def...\n";
128         open(I,"src\\interfaces\\libpq\\exports.txt") || confess("Could not open exports.txt\n");
129         open(O,">src\\interfaces\\libpq\\libpqdll.def") || confess("Could not open libpqdll.def\n");
130         print O "LIBRARY LIBPQ\nEXPORTS\n";
131         while (<I>)
132         {
133             next if (/^#/);
134             my ($f, $o) = split;
135             print O " $f @ $o\n";
136         }
137         close(O);
138         close(I);
139     }
140
141     if (IsNewer("src\\backend\\utils\\fmgrtab.c","src\\include\\catalog\\pg_proc.h"))
142     {
143         print "Generating fmgrtab.c and fmgroids.h...\n";
144         open(I,"src\\include\\catalog\\pg_proc.h") || confess "Could not open pg_proc.h";
145         my @fmgr = ();
146         my %seenit;
147         while (<I>)
148         {
149             next unless (/^DATA/);
150             s/^.*OID[^=]*=[^0-9]*//;
151             s/\(//g;
152             s/[ \t]*\).*$//;
153             my @p = split;
154             next if ($p[4] ne "12");
155             push @fmgr,
156               {
157                 oid     => $p[0],
158                 proname => $p[1],
159                 prosrc  => $p[$#p-2],
160                 nargs   => $p[12],
161                 strict  => $p[9],
162                 retset  => $p[10],
163               };
164         }
165         close(I);
166
167         open(H,'>', 'src\include\utils\fmgroids.h')
168           ||confess "Could not open fmgroids.h";
169         print H
170           "/* fmgroids.h generated for Visual C++ */\n#ifndef FMGROIDS_H\n#define FMGROIDS_H\n\n";
171         open(T,">src\\backend\\utils\\fmgrtab.c") || confess "Could not open fmgrtab.c";
172         print T
173 "/* fmgrtab.c generated for Visual C++ */\n#include \"postgres.h\"\n#include \"utils/fmgrtab.h\"\n\n";
174         foreach my $s (sort {$a->{oid} <=> $b->{oid}} @fmgr)
175         {
176             next if $seenit{$s->{prosrc}};
177             $seenit{$s->{prosrc}} = 1;
178             print H "#define F_" . uc $s->{prosrc} . " $s->{oid}\n";
179             print T "extern Datum $s->{prosrc} (PG_FUNCTION_ARGS);\n";
180         }
181         print H "\n#endif\n /* FMGROIDS_H */\n";
182         close(H);
183         print T "const FmgrBuiltin fmgr_builtins[] = {\n";
184         my %bmap;
185         $bmap{'t'} = 'true';
186         $bmap{'f'} = 'false';
187         foreach my $s (sort {$a->{oid} <=> $b->{oid}} @fmgr)
188         {
189             print T
190 "  { $s->{oid}, \"$s->{prosrc}\", $s->{nargs}, $bmap{$s->{strict}}, $bmap{$s->{retset}}, $s->{prosrc} },\n";
191         }
192
193         print T
194 " { 0, NULL, 0, false, false, NULL }\n};\n\nconst int fmgr_nbuiltins = (sizeof(fmgr_builtins) / sizeof(FmgrBuiltin)) - 1;\n";
195         close(T);
196     }
197
198     if (IsNewer('src\interfaces\libpq\libpq.rc','src\interfaces\libpq\libpq.rc.in'))
199     {
200         print "Generating libpq.rc...\n";
201         my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
202         my $d = ($year - 100) . "$yday";
203         open(I,'<', 'src\interfaces\libpq\libpq.rc.in') || confess "Could not open libpq.rc.in";
204         open(O,'>', 'src\interfaces\libpq\libpq.rc') || confess "Could not open libpq.rc";
205         while (<I>)
206         {
207             s/(VERSION.*),0/$1,$d/;
208             print O;
209         }
210         close(I);
211         close(O);
212     }
213
214     if (IsNewer('src\bin\psql\sql_help.h','src\bin\psql\create_help.pl'))
215     {
216         print "Generating sql_help.h...\n";
217         chdir('src\bin\psql');
218         system("perl create_help.pl ../../../doc/src/sgml/ref sql_help.h");
219         chdir('..\..\..');
220     }
221
222     if (
223         IsNewer(
224             'src\interfaces\ecpg\include\ecpg_config.h',
225             'src\interfaces\ecpg\include\ecpg_config.h.in'
226         )
227       )
228     {
229         print "Generating ecpg_config.h...\n";
230         open(O,'>','src\interfaces\ecpg\include\ecpg_config.h')
231           || confess "Could not open ecpg_config.h";
232         print O <<EOF;
233 #if (_MSC_VER > 1200)
234 #define HAVE_LONG_LONG_INT_64
235 #endif
236 EOF
237         close(O);
238     }
239
240     unless (-f "src\\port\\pg_config_paths.h")
241     {
242         print "Generating pg_config_paths.h...\n";
243         open(O,'>', 'src\port\pg_config_paths.h') || confess "Could not open pg_config_paths.h";
244         print O  <<EOF;
245 #define PGBINDIR "/bin"
246 #define PGSHAREDIR "/share"
247 #define SYSCONFDIR "/etc"
248 #define INCLUDEDIR "/include"
249 #define PKGINCLUDEDIR "/include"
250 #define INCLUDEDIRSERVER "/include/server"
251 #define LIBDIR "/lib"
252 #define PKGLIBDIR "/lib"
253 #define LOCALEDIR "/share/locale"
254 #define DOCDIR "/doc"
255 #define MANDIR "/man"
256 EOF
257         close(O);
258     }
259
260     my $mf = Project::read_file('src\backend\catalog\Makefile');
261     $mf =~ s{\\s*[\r\n]+}{}mg;
262     $mf =~ /^POSTGRES_BKI_SRCS\s*:?=[^,]+,(.*)\)$/gm
263       || croak "Could not find POSTGRES_BKI_SRCS in Makefile\n";
264     my @allbki = split /\s+/, $1;
265     foreach my $bki (@allbki)
266     {
267         next if $bki eq "";
268         if (IsNewer('src/backend/catalog/postgres.bki', "src/include/catalog/$bki"))
269         {
270             print "Generating postgres.bki...\n";
271             Genbki::genbki(
272                 $self->{majorver},
273                 "src/backend/catalog/postgres",
274                 split(/ /,join(' src/include/catalog/',@allbki))
275             );
276             last;
277         }
278     }
279
280     open(O, ">doc/src/sgml/version.sgml") || croak "Could not write to version.sgml\n";
281     print O <<EOF;
282 <!entity version "$self->{strver}">
283 <!entity majorversion "$self->{majorver}">
284 EOF
285     close(O);
286 }
287
288 sub AddProject
289 {
290     my ($self, $name, $type, $folder, $initialdir) = @_;
291
292     my $proj = new Project($name, $type, $self);
293     push @{$self->{projects}->{$folder}}, $proj;
294     $proj->AddDir($initialdir) if ($initialdir);
295     if ($self->{options}->{zlib})
296     {
297         $proj->AddIncludeDir($self->{options}->{zlib} . '\include');
298         $proj->AddLibrary($self->{options}->{zlib} . '\lib\zdll.lib');
299     }
300     if ($self->{options}->{openssl})
301     {
302         $proj->AddIncludeDir($self->{options}->{openssl} . '\include');
303         $proj->AddLibrary($self->{options}->{openssl} . '\lib\VC\ssleay32.lib', 1);
304         $proj->AddLibrary($self->{options}->{openssl} . '\lib\VC\libeay32.lib', 1);
305     }
306     if ($self->{options}->{nls})
307     {
308         $proj->AddIncludeDir($self->{options}->{nls} . '\include');
309         $proj->AddLibrary($self->{options}->{nls} . '\lib\intl.lib');
310     }
311     if ($self->{options}->{krb5})
312     {
313         $proj->AddIncludeDir($self->{options}->{krb5} . '\inc\krb5');
314         $proj->AddLibrary($self->{options}->{krb5} . '\lib\i386\krb5_32.lib');
315         $proj->AddLibrary($self->{options}->{krb5} . '\lib\i386\comerr32.lib');
316     }
317     if ($self->{options}->{xml})
318     {
319         $proj->AddIncludeDir($self->{options}->{xml} . '\include');
320         $proj->AddIncludeDir($self->{options}->{iconv} . '\include');
321         $proj->AddLibrary($self->{options}->{xml} . '\lib\libxml2.lib');
322     }
323     return $proj;
324 }
325
326 sub Save
327 {
328     my ($self) = @_;
329     my %flduid;
330
331     $self->GenerateFiles();
332     foreach my $fld (keys %{$self->{projects}})
333     {
334         foreach my $proj (@{$self->{projects}->{$fld}})
335         {
336             $proj->Save();
337         }
338     }
339
340     open(SLN,">pgsql.sln") || croak "Could not write to pgsql.sln\n";
341     print SLN <<EOF;
342 Microsoft Visual Studio Solution File, Format Version 9.00
343 # Visual Studio 2005
344 EOF
345
346     foreach my $fld (keys %{$self->{projects}})
347     {
348         foreach my $proj (@{$self->{projects}->{$fld}})
349         {
350             print SLN <<EOF;
351 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "$proj->{name}", "$proj->{name}.vcproj", "$proj->{guid}"
352 EndProject
353 EOF
354         }
355         if ($fld ne "")
356         {
357             $flduid{$fld} = Win32::GuidGen();
358             print SLN <<EOF;
359 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "$fld", "$fld", "$flduid{$fld}"
360 EndProject
361 EOF
362         }
363     }
364
365     print SLN <<EOF;
366 Global
367         GlobalSection(SolutionConfigurationPlatforms) = preSolution
368                 Debug|Win32 = Debug|Win32
369                 Release|Win32 = Release|Win32
370         EndGlobalSection
371         GlobalSection(ProjectConfigurationPlatforms) = postSolution
372 EOF
373
374     foreach my $fld (keys %{$self->{projects}})
375     {
376         foreach my $proj (@{$self->{projects}->{$fld}})
377         {
378             print SLN <<EOF;
379                 $proj->{guid}.Debug|Win32.ActiveCfg = Debug|Win32
380                 $proj->{guid}.Debug|Win32.Build.0  = Debug|Win32        
381                 $proj->{guid}.Release|Win32.ActiveCfg = Release|Win32
382                 $proj->{guid}.Release|Win32.Build.0 = Release|Win32
383 EOF
384         }
385     }
386
387     print SLN <<EOF;
388         EndGlobalSection
389         GlobalSection(SolutionProperties) = preSolution
390                 HideSolutionNode = FALSE
391         EndGlobalSection
392         GlobalSection(NestedProjects) = preSolution
393 EOF
394
395     foreach my $fld (keys %{$self->{projects}})
396     {
397         next if ($fld eq "");
398         foreach my $proj (@{$self->{projects}->{$fld}})
399         {
400             print SLN "\t\t$proj->{guid} = $flduid{$fld}\n";
401         }
402     }
403
404     print SLN <<EOF;
405         EndGlobalSection
406 EndGlobal
407 EOF
408     close(SLN);
409 }
410
411 1;