1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
#!/usr/bin/env perl
require 5.008;
BEGIN { $^W = 1; }
use strict;
use File::Basename;
my $whoami = basename($0);
usage() unless @ARGV == 3;
my ($file, $destdir, $objdump) = @ARGV;
my $filedir = dirname($file);
my %dlls = ();
open(O, "$objdump -p $file|") or die "$whoami: can't run objdump\n";
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)\.dll$/;
$dlls{$dll} = 1;
}
}
close(O);
# Search the file's directory, the current directory, and the path for
# dlls since that's what Windows does.
my $sep = ($^O eq 'MSWin32' ? ';' : ':');
my @path = ($filedir, '.', split($sep, $ENV{'PATH'}));
if (-f "$file.manifest")
{
unshift(@path, get_manifest_dirs("$file.manifest"));
}
my @final = ();
my @notfound = ();
dll_loop:
foreach my $dll (sort keys %dlls)
{
my $found = 0;
foreach my $dir (@path)
{
if (-f "$dir/$dll")
{
push(@final, "$dir/$dll");
$found = 1;
last;
}
}
if (! $found)
{
push(@notfound, $dll);
}
}
if (@notfound)
{
die "$whoami: can't find the following dlls: " .
join(', ', @notfound), "\n";
}
foreach my $f (@final)
{
$f =~ s,\\,/,g;
print "Copying $f to $destdir\n";
system("cp -p $f $destdir") == 0 or
die "$whoami: copy $f to $destdir failed\n";
}
sub get_manifest_dirs
{
# Find all system directories in which to search for DLLs based on
# the contents of a Visual Studio manifest file.
my $manifest_file = shift;
require XML::Parser;
my $sysroot = $ENV{'SYSTEMROOT'} or die "$whoami: can't get \$SYSTEMROOT\n";
$sysroot =~ s,\\,/,g;
if ($^O eq 'cygwin')
{
chop($sysroot = `cygpath $sysroot`);
die "$whoami: can't get system root" unless $? == 0;
}
my $winsxs = "$sysroot/WinSxS";
opendir(D, $winsxs) or die "$whoami: can't opendir $winsxs: $!\n";
my @entries = readdir(D);
closedir(D);
my @candidates = ();
my $readAssemblyIdentity = sub
{
my ($parser, $element, %attrs) = @_;
return unless $element eq 'assemblyIdentity';
my $type = $attrs{'type'};
my $name = $attrs{'name'};
my $version = $attrs{'version'};
my $processorArchitecture = $attrs{'processorArchitecture'};
my $publicKeyToken = $attrs{'publicKeyToken'};
my $dir_start = join('_',
$processorArchitecture,
$name,
$publicKeyToken,
$version);
push(@candidates, $dir_start);
};
my $p = new XML::Parser(Handlers => {'Start' => $readAssemblyIdentity});
$p->parsefile($manifest_file);
my @dirs = ();
foreach my $c (@candidates)
{
push(@dirs, map { "$winsxs/$_" } (grep { m/^\Q$c\E/i } @entries));
}
@dirs;
}
sub usage
{
die "Usage: $whoami {exe|dll} destdir\n";
}
|