4 # Package that provides 'make install' functionality for msvc builds
6 # $PostgreSQL: pgsql/src/tools/msvc/Install.pm,v 1.25 2007/10/23 20:46:12 tgl Exp $
16 our (@ISA,@EXPORT_OK);
18 @EXPORT_OK = qw(Install);
27 unlink $target || confess "Could not delete $target\n";
31 || confess "Could not copy $src to $target\n";
43 chdir("../../..") if (-f "../../../configure");
44 chdir("../../../..") if (-f "../../../../configure");
54 die "Could not find debug or release binaries" if ($conf eq "");
55 print "Installing for $conf in $target\n";
57 EnsureDirectories($target, 'bin','lib','share','share/timezonesets','share/contrib','doc',
58 'doc/contrib', 'symbols', 'share/tsearch_data');
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);
69 CopySetOfFiles('config files', $sample_files , $target . '/share/');
73 "$conf\\", "postgres\\postgres.lib","libpq\\libpq.lib", "libecpg\\libecpg.lib", "libpgport\\libpgport.lib"
75 CopySetOfFiles('timezone names',
76 [ glob('src\timezone\tznames\*.txt') ] ,
77 $target . '/share/timezonesets/');
80 $target . '/share/timezonesets/',
81 'src/timezone/tznames/', 'Default','Australia','India'
83 CopySetOfFiles('BKI files', [ glob("src\\backend\\catalog\\postgres.*") ],
85 CopySetOfFiles('SQL files', [ glob("src\\backend\\catalog\\*.sql") ],
88 'Information schema data',
90 'src/backend/catalog/', 'sql_features.txt'
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);
104 GenerateNLSFiles($target,$config->{nls}) if ($config->{nls});
106 print "Installation complete.\n";
109 sub EnsureDirectories
112 mkdir $target unless -d ($target);
113 while (my $d = shift)
115 mkdir $target . '/' . $d unless -d ($target . '/' . $d);
125 print "Copying $what";
126 while (my $f = shift)
130 die "No file $f\n" if (!-f $f);
131 lcopy($f, $target . basename($f));
141 print "Copying $what" if $what;
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($_);
148 lcopy($_, $tgt) || croak "Could not copy $_: $!\n";
153 sub CopySolutionOutput
157 my $rem = qr{Project\("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"\) = "([^"]+)"};
159 my $sln = read_file("pgsql.sln") || croak "Could not open pgsql.sln\n";
160 print "Copying build output files...";
169 my $proj = read_file("$pf.vcproj") || croak "Could not open $pf.vcproj\n";
170 if ($proj !~ qr{ConfigurationType="([^"]+)"})
172 croak "Could not parse $pf.vcproj\n";
187 # Static lib, such as libpgport, only used internally during build, don't install
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";
197 sub GenerateConversionScript
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;
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";
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";
222 open($F,">$target/share/conversion_create.sql")
223 || die "Could not write to conversion_create.sql\n";
229 sub GenerateTimezoneFiles
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;
238 print "Generating timezone files...";
239 system("$conf\\zic\\zic -d \"$target/share/timezone\" " . join(" src/timezone/data/", @tzfiles));
243 sub GenerateTsearchFiles
247 print "Generating tsearch script...";
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');
260 my $lang = shift @pieces || last;
261 my $asclang = shift @pieces || last;
265 if (-s "src/backend/snowball/stopwords/$lang.stop") {
266 $stop = ", StopWords=$lang";
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;
287 print "Copying contrib data files...";
289 opendir($D, 'contrib') || croak "Could not opendir on contrib!\n";
290 while (my $d = readdir($D))
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}));
298 my $mf = read_file("contrib/$d/Makefile");
299 $mf =~ s{\\s*[\r\n]+}{}mg;
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
307 $flist = ParseAndCleanRule($flist, $mf);
309 # Special case for contrib/spi
310 $flist = "autoinc.sql insert_username.sql moddatetime.sql refint.sql timetravel.sql"
312 foreach my $f (split /\s+/,$flist)
314 lcopy('contrib/' . $d . '/' . $f,$target . '/share/contrib/' . basename($f))
315 || croak("Could not copy file $f in contrib $d");
321 if ($mf =~ /^DATA_TSEARCH\s*=\s*(.*)$/m) {$flist .= $1}
324 $flist = ParseAndCleanRule($flist, $mf);
326 foreach my $f (split /\s+/,$flist)
328 lcopy('contrib/' . $d . '/' . $f,$target . '/share/tsearch_data/' . basename($f))
329 || croak("Could not copy file $f in contrib $d");
335 if ($mf =~ /^DOCS\s*=\s*(.*)$/mg) {$flist .= $1}
338 $flist = ParseAndCleanRule($flist, $mf);
340 # Special case for contrib/spi
342 "README.spi autoinc.example insert_username.example moddatetime.example refint.example timetravel.example"
344 foreach my $f (split /\s+/,$flist)
346 lcopy('contrib/' . $d . '/' . $f, $target . '/doc/contrib/' . $f)
347 || croak("Could not copy file $f in contrib $d");
356 sub ParseAndCleanRule
361 # Strip out $(addsuffix) rules
362 if (index($flist, '$(addsuffix ') >= 0)
366 for ($i = index($flist, '$(addsuffix ') + 12; $i < length($flist); $i++)
368 $pcount++ if (substr($flist, $i, 1) eq '(');
369 $pcount-- if (substr($flist, $i, 1) eq ')');
370 last if ($pcount < 0);
372 $flist = substr($flist, 0, index($flist, '$(addsuffix ')) . substr($flist, $i+1);
381 EnsureDirectories($target, 'include', 'include/libpq',
382 'include/internal', 'include/internal/libpq',
387 $target . '/include/',
388 'src/include/', 'postgres_ext.h', 'pg_config.h', 'pg_config_os.h', 'pg_config_manual.h'
390 lcopy('src/include/libpq/libpq-fs.h', $target . '/include/libpq/')
391 || croak 'Could not copy libpq-fs.h';
393 CopyFiles('Libpq headers', $target . '/include/', 'src/interfaces/libpq/', 'libpq-fe.h');
395 'Libpq internal headers',
396 $target .'/include/internal/',
397 'src/interfaces/libpq/', 'libpq-int.h', 'pqexpbuffer.h'
402 $target . '/include/internal/',
403 'src/include/', 'c.h', 'port.h', 'postgres_fe.h'
405 lcopy('src/include/libpq/pqcomm.h', $target . '/include/internal/libpq/')
406 || croak 'Could not copy pqcomm.h';
410 $target . '/include/server/',
411 'src/include/', 'pg_config.h', 'pg_config_os.h'
414 [ glob( "src\\include\\*.h" ) ],
415 $target . '/include/server/');
417 opendir($D, 'src/include') || croak "Could not opendir on src/include!\n";
419 while (my $d = readdir($D))
421 next if ($d =~ /^\./);
422 next if ($d eq 'CVS');
423 next unless (-d 'src/include/' . $d);
425 EnsureDirectories($target . '/include/server', $d);
427 "xcopy /s /i /q /r /y src\\include\\$d\\*.h \"$target\\include\\server\\$d\\\"")
428 && croak("Failed to copy include directory $d\n");
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";
437 $target . '/include/',
438 'src/interfaces/ecpg/include/',
439 'ecpg_config.h', split /\s+/,$1
441 $mf =~ /^informix_headers\s*=\s*(.*)$/m || croak "Could not find informix_headers line\n";
442 EnsureDirectories($target . '/include', 'informix', 'informix/esql');
444 'ECPG informix headers',
445 $target .'/include/informix/esql/',
446 'src/interfaces/ecpg/include/',
456 print "Installing NLS files...";
457 EnsureDirectories($target, "share/locale");
459 File::Find::find({wanted =>
460 sub { /^nls\.mk\z/s &&
461 ! push(@flist, $File::Find::name);
468 next unless ($dir =~ /([^\\]+)\\po$/);
470 $prgm = 'postgres' if ($prgm eq 'backend');
471 foreach (glob("$dir/*.po"))
474 next unless /^(.*)\.po/;
477 EnsureDirectories($target, "share/locale/$lang", "share/locale/$lang/LC_MESSAGES");
479 "$nlspath\\bin\\msgfmt -o $target\\share\\locale\\$lang\\LC_MESSAGES\\$prgm.mo $dir\\$_"
481 && croak("Could not run msgfmt on $dir\\$_");
490 my $filename = shift;
495 open($F, $filename) || die "Could not open file $filename\n";