]> granicus.if.org Git - postgresql/blob - src/tools/msvc/Install.pm
Rename and slightly redefine the default text search parser's "word"
[postgresql] / src / tools / msvc / Install.pm
1 package Install;
2
3 #
4 # Package that provides 'make install' functionality for msvc builds
5 #
6 # $PostgreSQL: pgsql/src/tools/msvc/Install.pm,v 1.25 2007/10/23 20:46:12 tgl Exp $
7 #
8 use strict;
9 use warnings;
10 use Carp;
11 use File::Basename;
12 use File::Copy;
13 use File::Find ();
14
15 use Exporter;
16 our (@ISA,@EXPORT_OK);
17 @ISA = qw(Exporter);
18 @EXPORT_OK = qw(Install);
19
20 sub lcopy
21 {
22         my $src = shift;
23         my $target = shift;
24
25         if (-f $target)
26         {
27            unlink $target || confess "Could not delete $target\n";
28         }
29
30         copy($src,$target)
31           || confess "Could not copy $src to $target\n";
32
33 }
34
35 sub Install
36 {
37     $| = 1;
38
39     my $target = shift;
40     our $config;
41     require 'config.pl';
42
43     chdir("../../..") if (-f "../../../configure");
44     chdir("../../../..") if (-f "../../../../configure");
45     my $conf = "";
46     if (-d "debug")
47     {
48         $conf = "debug";
49     }
50     if (-d "release")
51     {
52         $conf = "release";
53     }
54     die "Could not find debug or release binaries" if ($conf eq "");
55     print "Installing for $conf in $target\n";
56
57     EnsureDirectories($target, 'bin','lib','share','share/timezonesets','share/contrib','doc',
58         'doc/contrib', 'symbols', 'share/tsearch_data');
59
60     CopySolutionOutput($conf, $target);
61     lcopy($target . '/lib/libpq.dll', $target . '/bin/libpq.dll');
62         my $sample_files = [];
63         File::Find::find({wanted => 
64                                                   sub { /^.*\.sample\z/s && 
65                                                                         push(@$sample_files, $File::Find::name); 
66                                                         } 
67                                   }, 
68                                          "src" );
69     CopySetOfFiles('config files', $sample_files , $target . '/share/');
70     CopyFiles(
71         'Import libraries',
72         $target .'/lib/',
73         "$conf\\", "postgres\\postgres.lib","libpq\\libpq.lib", "libecpg\\libecpg.lib", "libpgport\\libpgport.lib"
74     );
75     CopySetOfFiles('timezone names', 
76                                    [ glob('src\timezone\tznames\*.txt') ] ,
77                                    $target . '/share/timezonesets/');
78     CopyFiles(
79         'timezone sets',
80         $target . '/share/timezonesets/',
81         'src/timezone/tznames/', 'Default','Australia','India'
82     );
83     CopySetOfFiles('BKI files', [ glob("src\\backend\\catalog\\postgres.*") ], 
84                                    $target .'/share/');
85     CopySetOfFiles('SQL files', [ glob("src\\backend\\catalog\\*.sql") ], 
86                                    $target . '/share/');
87     CopyFiles(
88         'Information schema data',
89         $target . '/share/',
90         'src/backend/catalog/', 'sql_features.txt'
91     );
92     GenerateConversionScript($target);
93     GenerateTimezoneFiles($target,$conf);
94     GenerateTsearchFiles($target);
95     CopySetOfFiles('Stopword files', 
96                                    [ glob ("src\\backend\\snowball\\stopwords\\*.stop") ], 
97                                    $target . '/share/tsearch_data/');
98     CopySetOfFiles('Dictionaries sample files', 
99                                    [ glob ("src\\backend\\tsearch\\*_sample.*" ) ], 
100                                    $target . '/share/tsearch_data/');
101     CopyContribFiles($config,$target);
102     CopyIncludeFiles($target);
103
104     GenerateNLSFiles($target,$config->{nls}) if ($config->{nls});
105
106     print "Installation complete.\n";
107 }
108
109 sub EnsureDirectories
110 {
111     my $target = shift;
112     mkdir $target unless -d ($target);
113     while (my $d = shift)
114     {
115         mkdir $target . '/' . $d unless -d ($target . '/' . $d);
116     }
117 }
118
119 sub CopyFiles
120 {
121     my $what = shift;
122     my $target = shift;
123     my $basedir = shift;
124
125     print "Copying $what";
126     while (my $f = shift)
127     {
128         print ".";
129         $f = $basedir . $f;
130         die "No file $f\n" if (!-f $f);
131         lcopy($f, $target . basename($f));
132     }
133     print "\n";
134 }
135
136 sub CopySetOfFiles
137 {
138     my $what = shift;
139     my $flist = shift;
140     my $target = shift;
141     print "Copying $what" if $what;
142     foreach (@$flist)
143     {
144         next if /regress/; # Skip temporary install in regression subdir
145         next if /ecpg.test/; # Skip temporary install in regression subdir
146         my $tgt = $target . basename($_);
147         print ".";
148         lcopy($_, $tgt) || croak "Could not copy $_: $!\n";
149     }
150     print "\n";
151 }
152
153 sub CopySolutionOutput
154 {
155     my $conf = shift;
156     my $target = shift;
157     my $rem = qr{Project\("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"\) = "([^"]+)"};
158
159     my $sln = read_file("pgsql.sln") || croak "Could not open pgsql.sln\n";
160     print "Copying build output files...";
161     while ($sln =~ $rem)
162     {
163         my $pf = $1;
164         my $dir;
165         my $ext;
166
167         $sln =~ s/$rem//;
168
169         my $proj = read_file("$pf.vcproj") || croak "Could not open $pf.vcproj\n";
170         if ($proj !~ qr{ConfigurationType="([^"]+)"})
171         {
172             croak "Could not parse $pf.vcproj\n";
173         }
174         if ($1 == 1)
175         {
176             $dir = "bin";
177             $ext = "exe";
178         }
179         elsif ($1 == 2)
180         {
181             $dir = "lib";
182             $ext = "dll";
183         }
184         else
185         {
186
187             # Static lib, such as libpgport, only used internally during build, don't install
188             next;
189         }
190         lcopy("$conf\\$pf\\$pf.$ext","$target\\$dir\\$pf.$ext") || croak "Could not copy $pf.$ext\n";
191         lcopy("$conf\\$pf\\$pf.pdb","$target\\symbols\\$pf.pdb") || croak "Could not copy $pf.pdb\n";
192         print ".";
193     }
194     print "\n";
195 }
196
197 sub GenerateConversionScript
198 {
199     my $target = shift;
200     my $sql = "";
201     my $F;
202
203     print "Generating conversion proc script...";
204     my $mf = read_file('src/backend/utils/mb/conversion_procs/Makefile');
205     $mf =~ s{\\\s*[\r\n]+}{}mg;
206     $mf =~ /^CONVERSIONS\s*=\s*(.*)$/m
207       || die "Could not find CONVERSIONS line in conversions Makefile\n";
208     my @pieces = split /\s+/,$1;
209     while ($#pieces > 0)
210     {
211         my $name = shift @pieces;
212         my $se = shift @pieces;
213         my $de = shift @pieces;
214         my $func = shift @pieces;
215         my $obj = shift @pieces;
216         $sql .= "-- $se --> $de\n";
217         $sql .=
218 "CREATE OR REPLACE FUNCTION $func (INTEGER, INTEGER, CSTRING, INTERNAL, INTEGER) RETURNS VOID AS '\$libdir/$obj', '$func' LANGUAGE C STRICT;\n";
219         $sql .= "DROP CONVERSION pg_catalog.$name;\n";
220         $sql .= "CREATE DEFAULT CONVERSION pg_catalog.$name FOR '$se' TO '$de' FROM $func;\n";
221     }
222     open($F,">$target/share/conversion_create.sql")
223       || die "Could not write to conversion_create.sql\n";
224     print $F $sql;
225     close($F);
226     print "\n";
227 }
228
229 sub GenerateTimezoneFiles
230 {
231     my $target = shift;
232     my $conf = shift;
233     my $mf = read_file("src/timezone/Makefile");
234     $mf =~ s{\\\s*[\r\n]+}{}mg;
235     $mf =~ /^TZDATA\s*:?=\s*(.*)$/m || die "Could not find TZDATA row in timezone makefile\n";
236     my @tzfiles = split /\s+/,$1;
237     unshift @tzfiles,'';
238     print "Generating timezone files...";
239     system("$conf\\zic\\zic -d \"$target/share/timezone\" " . join(" src/timezone/data/", @tzfiles));
240     print "\n";
241 }
242
243 sub GenerateTsearchFiles
244 {
245     my $target = shift;
246
247     print "Generating tsearch script...";
248     my $F;
249     my $tmpl = read_file('src/backend/snowball/snowball.sql.in');
250     my $mf = read_file('src/backend/snowball/Makefile');
251     $mf =~ s{\\\s*[\r\n]+}{}mg;
252     $mf =~ /^LANGUAGES\s*=\s*(.*)$/m
253       || die "Could not find LANGUAGES line in snowball Makefile\n";
254     my @pieces = split /\s+/,$1;
255     open($F,">$target/share/snowball_create.sql")
256       || die "Could not write snowball_create.sql";
257     print $F read_file('src/backend/snowball/snowball_func.sql.in');
258     while ($#pieces > 0)
259     {
260         my $lang = shift @pieces || last;
261         my $asclang = shift @pieces || last;
262         my $txt = $tmpl;
263         my $stop = '';
264
265         if (-s "src/backend/snowball/stopwords/$lang.stop") {
266             $stop = ", StopWords=$lang";
267         }
268
269         $txt =~ s#_LANGNAME_#${lang}#gs;
270         $txt =~ s#_DICTNAME_#${lang}_stem#gs;
271         $txt =~ s#_CFGNAME_#${lang}#gs;
272         $txt =~ s#_ASCDICTNAME_#${asclang}_stem#gs;
273         $txt =~ s#_NONASCDICTNAME_#${lang}_stem#gs;
274         $txt =~ s#_STOPWORDS_#$stop#gs;
275         print $F $txt;
276         print ".";
277     }
278     close($F);
279     print "\n";
280 }
281
282 sub CopyContribFiles
283 {
284     my $config = shift;
285     my $target = shift;
286
287     print "Copying contrib data files...";
288     my $D;
289     opendir($D, 'contrib') || croak "Could not opendir on contrib!\n";
290     while (my $d = readdir($D))
291     {
292         next if ($d =~ /^\./);
293         next unless (-f "contrib/$d/Makefile");
294         next if ($d eq "uuid-ossp");
295         next if ($d eq "sslinfo" && !defined($config->{openssl}));
296         next if ($d eq "xml2" && !defined($config->{xml}));
297
298         my $mf = read_file("contrib/$d/Makefile");
299         $mf =~ s{\\s*[\r\n]+}{}mg;
300         my $flist = '';
301         if ($mf =~ /^DATA_built\s*=\s*(.*)$/m) {$flist .= $1}
302         if ($mf =~ /^DATA\s*=\s*(.*)$/m) {$flist .= " $1"}
303         $flist =~ s/^\s*//; # Remove leading spaces if we had only DATA_built
304
305         if ($flist ne '')
306         {
307             $flist = ParseAndCleanRule($flist, $mf);
308
309             # Special case for contrib/spi
310             $flist = "autoinc.sql insert_username.sql moddatetime.sql refint.sql timetravel.sql"
311               if ($d eq 'spi');
312             foreach my $f (split /\s+/,$flist)
313             {
314                 lcopy('contrib/' . $d . '/' . $f,$target . '/share/contrib/' . basename($f))
315                   || croak("Could not copy file $f in contrib $d");
316                 print '.';
317             }
318         }
319
320         $flist = '';
321         if ($mf =~ /^DATA_TSEARCH\s*=\s*(.*)$/m) {$flist .= $1}
322         if ($flist ne '')
323         {
324             $flist = ParseAndCleanRule($flist, $mf);
325
326             foreach my $f (split /\s+/,$flist)
327             {
328                 lcopy('contrib/' . $d . '/' . $f,$target . '/share/tsearch_data/' . basename($f))
329                   || croak("Could not copy file $f in contrib $d");
330                 print '.';
331             }
332         }
333
334         $flist = '';
335         if ($mf =~ /^DOCS\s*=\s*(.*)$/mg) {$flist .= $1}
336         if ($flist ne '')
337         {
338             $flist = ParseAndCleanRule($flist, $mf);
339
340             # Special case for contrib/spi
341             $flist =
342 "README.spi autoinc.example insert_username.example moddatetime.example refint.example timetravel.example"
343               if ($d eq 'spi');
344             foreach my $f (split /\s+/,$flist)
345             {
346                 lcopy('contrib/' . $d . '/' . $f, $target . '/doc/contrib/' . $f)
347                   || croak("Could not copy file $f in contrib $d");
348                 print '.';
349             }
350         }
351     }
352     closedir($D);
353     print "\n";
354 }
355
356 sub ParseAndCleanRule
357 {
358     my $flist = shift;
359     my $mf = shift;
360
361     # Strip out $(addsuffix) rules
362     if (index($flist, '$(addsuffix ') >= 0)
363     {
364         my $pcount = 0;
365         my $i;
366         for ($i = index($flist, '$(addsuffix ') + 12; $i < length($flist); $i++)
367         {
368             $pcount++ if (substr($flist, $i, 1) eq '(');
369             $pcount-- if (substr($flist, $i, 1) eq ')');
370             last if ($pcount < 0);
371         }
372         $flist = substr($flist, 0, index($flist, '$(addsuffix ')) . substr($flist, $i+1);
373     }
374     return $flist;
375 }
376
377 sub CopyIncludeFiles
378 {
379     my $target = shift;
380
381     EnsureDirectories($target, 'include', 'include/libpq',
382         'include/internal', 'include/internal/libpq',
383         'include/server');
384
385     CopyFiles(
386         'Public headers',
387         $target . '/include/',
388         'src/include/', 'postgres_ext.h', 'pg_config.h', 'pg_config_os.h', 'pg_config_manual.h'
389     );
390     lcopy('src/include/libpq/libpq-fs.h', $target . '/include/libpq/')
391       || croak 'Could not copy libpq-fs.h';
392
393     CopyFiles('Libpq headers', $target . '/include/', 'src/interfaces/libpq/', 'libpq-fe.h');
394     CopyFiles(
395         'Libpq internal headers',
396         $target .'/include/internal/',
397         'src/interfaces/libpq/', 'libpq-int.h', 'pqexpbuffer.h'
398     );
399
400     CopyFiles(
401         'Internal headers',
402         $target . '/include/internal/',
403         'src/include/', 'c.h', 'port.h', 'postgres_fe.h'
404     );
405     lcopy('src/include/libpq/pqcomm.h', $target . '/include/internal/libpq/')
406       || croak 'Could not copy pqcomm.h';
407
408     CopyFiles(
409         'Server headers',
410         $target . '/include/server/',
411         'src/include/', 'pg_config.h', 'pg_config_os.h'
412     );
413     CopySetOfFiles('', 
414                                    [ glob( "src\\include\\*.h" ) ], 
415                                    $target . '/include/server/');
416     my $D;
417     opendir($D, 'src/include') || croak "Could not opendir on src/include!\n";
418
419     while (my $d = readdir($D))
420     {
421         next if ($d =~ /^\./);
422         next if ($d eq 'CVS');
423         next unless (-d 'src/include/' . $d);
424
425         EnsureDirectories($target . '/include/server', $d);
426         system(
427             "xcopy /s /i /q /r /y src\\include\\$d\\*.h \"$target\\include\\server\\$d\\\"")
428           && croak("Failed to copy include directory $d\n");
429     }
430     closedir($D);
431
432     my $mf = read_file('src/interfaces/ecpg/include/Makefile');
433     $mf =~ s{\\s*[\r\n]+}{}mg;
434     $mf =~ /^ecpg_headers\s*=\s*(.*)$/m || croak "Could not find ecpg_headers line\n";
435     CopyFiles(
436         'ECPG headers',
437         $target . '/include/',
438         'src/interfaces/ecpg/include/',
439         'ecpg_config.h', split /\s+/,$1
440     );
441     $mf =~ /^informix_headers\s*=\s*(.*)$/m || croak "Could not find informix_headers line\n";
442     EnsureDirectories($target . '/include', 'informix', 'informix/esql');
443     CopyFiles(
444         'ECPG informix headers',
445         $target .'/include/informix/esql/',
446         'src/interfaces/ecpg/include/',
447         split /\s+/,$1
448     );
449 }
450
451 sub GenerateNLSFiles
452 {
453     my $target = shift;
454     my $nlspath = shift;
455
456     print "Installing NLS files...";
457     EnsureDirectories($target, "share/locale");
458         my @flist;
459         File::Find::find({wanted => 
460                                                   sub { /^nls\.mk\z/s && 
461                                                                         !                                                                       push(@flist, $File::Find::name);        
462                                                         } 
463                                   }, "src");
464     foreach (@flist)
465     {
466         s/nls.mk/po/;
467         my $dir = $_;
468         next unless ($dir =~ /([^\\]+)\\po$/);
469         my $prgm = $1;
470         $prgm = 'postgres' if ($prgm eq 'backend');
471         foreach (glob("$dir/*.po"))
472         {
473             my $lang;
474             next unless /^(.*)\.po/;
475             $lang = $1;
476
477             EnsureDirectories($target, "share/locale/$lang", "share/locale/$lang/LC_MESSAGES");
478             system(
479 "$nlspath\\bin\\msgfmt -o $target\\share\\locale\\$lang\\LC_MESSAGES\\$prgm.mo $dir\\$_"
480               )
481               && croak("Could not run msgfmt on $dir\\$_");
482             print ".";
483         }
484     }
485     print "\n";
486 }
487
488 sub read_file
489 {
490     my $filename = shift;
491     my $F;
492     my $t = $/;
493
494     undef $/;
495     open($F, $filename) || die "Could not open file $filename\n";
496     my $txt = <$F>;
497     close($F);
498     $/ = $t;
499
500     return $txt;
501 }
502
503 1;