2009-10-22 17:42:18 +00:00
|
|
|
#!/usr/bin/env perl
|
|
|
|
|
|
|
|
require 5.008;
|
|
|
|
BEGIN { $^W = 1; }
|
|
|
|
use strict;
|
|
|
|
use File::Basename;
|
|
|
|
|
|
|
|
my $whoami = basename($0);
|
|
|
|
|
2016-01-24 20:51:21 +00:00
|
|
|
usage() unless @ARGV == 4;
|
|
|
|
my ($file, $destdir, $objdump, $windows_wordsize) = @ARGV;
|
2009-10-22 17:42:18 +00:00
|
|
|
my $filedir = dirname($file);
|
|
|
|
|
|
|
|
my $sep = ($^O eq 'MSWin32' ? ';' : ':');
|
|
|
|
my @path = ($filedir, '.', split($sep, $ENV{'PATH'}));
|
2016-01-24 20:51:21 +00:00
|
|
|
foreach my $var (qw(LIB))
|
|
|
|
{
|
|
|
|
if (exists $ENV{$var})
|
|
|
|
{
|
|
|
|
push(@path, split($sep, $ENV{$var}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
my $redist_suffix = (($windows_wordsize eq '64') ? "x64" : "x86");
|
|
|
|
if (exists $ENV{'VCINSTALLDIR'})
|
|
|
|
{
|
|
|
|
my $redist = $ENV{'VCINSTALLDIR'} . "/Redist/$redist_suffix";
|
|
|
|
if (opendir(D, $redist))
|
|
|
|
{
|
|
|
|
my @entries = readdir(D);
|
|
|
|
closedir(D);
|
|
|
|
foreach my $e (@entries)
|
|
|
|
{
|
|
|
|
if ($e =~ m/\.CRT$/i)
|
|
|
|
{
|
|
|
|
unshift(@path, "$redist/$e");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-08-22 20:22:16 +00:00
|
|
|
if (exists $ENV{'UniversalCRTSdkDir'})
|
2016-01-24 20:51:21 +00:00
|
|
|
{
|
2017-08-22 20:22:16 +00:00
|
|
|
my $redist = $ENV{'UniversalCRTSdkDir'} . "/Redist/ucrt/DLLs/$redist_suffix";
|
2016-01-24 20:51:21 +00:00
|
|
|
unshift(@path, $redist);
|
|
|
|
}
|
2017-08-22 20:22:16 +00:00
|
|
|
|
|
|
|
my $format = undef;
|
|
|
|
my @to_find = get_dlls($file);
|
|
|
|
|
|
|
|
my %final = ();
|
2009-10-22 17:42:18 +00:00
|
|
|
my @notfound = ();
|
2017-08-22 20:22:16 +00:00
|
|
|
|
|
|
|
while (@to_find)
|
2009-10-22 17:42:18 +00:00
|
|
|
{
|
2017-08-22 20:22:16 +00:00
|
|
|
my $dll = shift(@to_find);
|
2009-10-22 17:42:18 +00:00
|
|
|
my $found = 0;
|
|
|
|
foreach my $dir (@path)
|
|
|
|
{
|
2017-08-22 20:22:16 +00:00
|
|
|
if ((-f "$dir/$dll") && is_format("$dir/$dll", $format))
|
|
|
|
{
|
|
|
|
if (! exists $final{$dll})
|
|
|
|
{
|
|
|
|
$final{$dll} = "$dir/$dll";
|
|
|
|
push(@to_find, get_dlls("$dir/$dll"));
|
|
|
|
}
|
|
|
|
$found = 1;
|
|
|
|
last;
|
|
|
|
}
|
2009-10-22 17:42:18 +00:00
|
|
|
}
|
|
|
|
if (! $found)
|
|
|
|
{
|
2017-08-22 20:22:16 +00:00
|
|
|
push(@notfound, $dll);
|
2009-10-22 17:42:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (@notfound)
|
|
|
|
{
|
|
|
|
die "$whoami: can't find the following dlls: " .
|
|
|
|
join(', ', @notfound), "\n";
|
|
|
|
}
|
|
|
|
|
2017-08-22 20:22:16 +00:00
|
|
|
foreach my $dll (sort keys (%final))
|
2009-10-22 17:42:18 +00:00
|
|
|
{
|
2017-08-22 20:22:16 +00:00
|
|
|
my $f = $final{$dll};
|
2009-10-22 17:42:18 +00:00
|
|
|
$f =~ s,\\,/,g;
|
|
|
|
print "Copying $f to $destdir\n";
|
2016-01-24 20:51:21 +00:00
|
|
|
system("cp -p '$f' '$destdir'") == 0 or
|
2009-10-22 17:42:18 +00:00
|
|
|
die "$whoami: copy $f to $destdir failed\n";
|
|
|
|
}
|
|
|
|
|
2017-08-22 20:22:16 +00:00
|
|
|
sub get_dlls
|
|
|
|
{
|
|
|
|
my @result = ();
|
|
|
|
my $exe = shift;
|
2018-01-15 01:09:15 +00:00
|
|
|
open(O, "$objdump -p \"$exe\"|") or die "$whoami: can't run objdump\n";
|
2017-08-22 20:22:16 +00:00
|
|
|
while (<O>)
|
|
|
|
{
|
|
|
|
if (m/^\s+DLL Name:\s+(.+\.dll)/i)
|
|
|
|
{
|
|
|
|
my $dll = $1;
|
|
|
|
$dll =~ tr/A-Z/a-z/;
|
|
|
|
next if $dll =~ m/^(kernel32|user32|msvcrt|advapi32)\.dll$/;
|
|
|
|
push(@result, $dll);
|
|
|
|
}
|
|
|
|
elsif (m/^Magic.*\((PE.+?)\)/)
|
|
|
|
{
|
|
|
|
$format = $1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close(O);
|
|
|
|
if (! defined $format)
|
|
|
|
{
|
|
|
|
die "$whoami: can't determine format of $exe\n";
|
|
|
|
}
|
|
|
|
@result;
|
|
|
|
}
|
|
|
|
|
2013-03-11 16:34:31 +00:00
|
|
|
sub is_format
|
|
|
|
{
|
|
|
|
my ($file, $format) = @_;
|
|
|
|
$file =~ s,\\,/,g;
|
|
|
|
# Special case: msvc*.dll seem to be able to behave both as 32-bit
|
|
|
|
# and 64-bit DLLs. Either that, or this logic is wrong for those
|
|
|
|
# DLLs and it doesn't matter because they're already installed on
|
|
|
|
# my test system (which doesn't have msvc installed on it).
|
|
|
|
if ($file =~ m,/msvc,i)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
my $result = 0;
|
2016-01-24 20:51:21 +00:00
|
|
|
my $file_format = `file "$file"`;
|
2013-03-11 16:34:31 +00:00
|
|
|
print "$file $format $file_format\n";
|
|
|
|
if ($? == 0)
|
|
|
|
{
|
|
|
|
if ($file_format =~ m/\Q${format}\E executable/)
|
|
|
|
{
|
|
|
|
$result = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$result;
|
|
|
|
}
|
|
|
|
|
2009-10-22 17:42:18 +00:00
|
|
|
sub usage
|
|
|
|
{
|
|
|
|
die "Usage: $whoami {exe|dll} destdir\n";
|
|
|
|
}
|