OSDN Git Service

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