line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Language::XS; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
1163
|
use strict 'subs'; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
49
|
|
4
|
2
|
|
|
2
|
|
8
|
use Carp; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
139
|
|
5
|
2
|
|
|
2
|
|
16
|
use Config; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
72
|
|
6
|
2
|
|
|
2
|
|
9
|
use File::Spec; |
|
2
|
|
|
|
|
9
|
|
|
2
|
|
|
|
|
5134
|
|
7
|
|
|
|
|
|
|
#use ExtUtils::MakeMaker; # argh, but knows useful info we can't deduce otherwise! |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
require Exporter; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
#BEGIN { $^W=0 } # I'm fed up with bogus and unnecessary warnings nobody can turn off. |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
@EXPORT = (); |
16
|
|
|
|
|
|
|
@EXPORT_OK = (); |
17
|
|
|
|
|
|
|
%EXPORT_TAGS = (); |
18
|
|
|
|
|
|
|
$VERSION = 0.02; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 NAME |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
Language::XS - Write XS code on the fly and load it dynamically. |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=head1 SYNOPSIS |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
use Language::XS; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=head1 DESCRIPTION |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
This module allows C & XS-code creation "on-the-fly", i.e. while your |
31
|
|
|
|
|
|
|
script is running. |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
Here is a very simple example: |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# create a Language::XS-object |
36
|
|
|
|
|
|
|
my $xs = new Language::XS cachedir => undef; |
37
|
|
|
|
|
|
|
# add plain C to the header |
38
|
|
|
|
|
|
|
$xs->hdr("#include "); |
39
|
|
|
|
|
|
|
# add a c function (not using xs syntax) |
40
|
|
|
|
|
|
|
$xs->cfun('printf ("I was called with %d arguments\n", items);'); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# now compile and find the code-reference |
43
|
|
|
|
|
|
|
my $coderef = $xs->find; |
44
|
|
|
|
|
|
|
# Now call it |
45
|
|
|
|
|
|
|
$coderef->(1, "Zwei", 1/3); |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=head1 METHODS |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=cut |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
#my $xsloader = eval { require XSLoader }; |
52
|
|
|
|
|
|
|
#$xsloader or require DynaLoader; |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# *NIX-specifix |
55
|
|
|
|
|
|
|
my $uid = "XUzNaIcQeUfExxIaD0000"; |
56
|
1
|
|
|
1
|
0
|
9
|
sub next_uid { ++$uid } |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# *NIX-specific |
59
|
|
|
|
|
|
|
my $default_cache = "$ENV{HOME}/.perl-xs-cache"; |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
my %tmpdirs; |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
# this is *NIX-specific, and rather clumsy |
64
|
|
|
|
|
|
|
sub tmpdir_create { |
65
|
1
|
|
|
1
|
0
|
3
|
my $self = shift; |
66
|
1
|
|
50
|
|
|
7
|
my $prefix = ($ENV{TMPDIR}||"/tmp")."/language-xs-"; |
67
|
1
|
|
|
|
|
14
|
my $suffix = "T${$}000"; |
68
|
1
|
|
|
|
|
232
|
$suffix++ while !mkdir "$prefix$suffix", 0700; |
69
|
1
|
|
|
|
|
5
|
$tmpdirs{"$prefix$suffix"} = 1; |
70
|
1
|
|
|
|
|
6
|
"$prefix$suffix"; |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
sub tmpdir_cleanup { |
74
|
1
|
|
|
1
|
0
|
2
|
my $dir = shift; |
75
|
1
|
50
|
|
|
|
8
|
return unless exists $tmpdirs{$dir}; |
76
|
1
|
50
|
|
|
|
43
|
if (opendir DIR, $dir) { |
77
|
1
|
|
|
|
|
38
|
while (my $name = readdir DIR) { |
78
|
4
|
|
|
|
|
170
|
unlink "$dir/$name"; |
79
|
|
|
|
|
|
|
} |
80
|
1
|
|
|
|
|
14
|
closedir DIR; |
81
|
|
|
|
|
|
|
} |
82
|
1
|
|
|
|
|
107
|
rmdir $dir; |
83
|
1
|
|
|
|
|
10
|
delete $tmpdirs{$dir}; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
END { |
87
|
2
|
|
|
2
|
|
769
|
for $dir (keys %tmpdirs) { |
88
|
1
|
|
|
|
|
4
|
tmpdir_cleanup $dir; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub sanitize_id($) { |
93
|
4
|
|
|
4
|
0
|
7
|
my $id = shift; |
94
|
4
|
|
|
|
|
10
|
$id =~ y{0-9a-zA-Z\-_.:/\\}{}cd; |
95
|
4
|
|
|
|
|
9
|
$id; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=head2 new attr => value, ... |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
Creates a new Language::XS object. Known attributes are: |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
id a unique id that woill be shared among all modules |
103
|
|
|
|
|
|
|
cachedir the common directory where shared objects should be cached. |
104
|
|
|
|
|
|
|
set to undef when you want to disable sharing (must be |
105
|
|
|
|
|
|
|
an absolute path) |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
Default values will be supplied when necessary. Two common idioms are: |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
$xs = new Language::XS; # caching enabled |
110
|
|
|
|
|
|
|
$xs = new Language::XS cachedir => undef; # caching disabled |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
=cut |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# id = unique id (for caching) |
115
|
|
|
|
|
|
|
sub new { |
116
|
1
|
|
|
1
|
1
|
415
|
my $class = shift; |
117
|
1
|
|
|
|
|
5
|
$self = bless { |
118
|
|
|
|
|
|
|
id => next_uid(), |
119
|
|
|
|
|
|
|
cachedir => $default_cache, |
120
|
|
|
|
|
|
|
dirty => 0, |
121
|
|
|
|
|
|
|
@_ |
122
|
|
|
|
|
|
|
}; |
123
|
1
|
|
|
|
|
11
|
$self->{id} = sanitize_id $self->{id}; |
124
|
1
|
|
|
|
|
5
|
$self->{package} = "language_xs_$self->{id}"; |
125
|
1
|
50
|
0
|
|
|
5
|
$self->{sofile} ||= File::Spec->catfile($self->{cachedir}, "$self->{id}.$Config{dlext}") if $self->{cachedir}; |
126
|
1
|
|
|
|
|
3
|
$self; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub DESTROY { |
130
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
131
|
0
|
|
|
|
|
0
|
tmpdir_cleanup($self->{tmpdir}); |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=head2 cached |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
Returns true when as shared object with the given id already exists. This obviously only makes sense when |
137
|
|
|
|
|
|
|
you gave the module a unique id. |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=cut |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
sub cached($) { |
142
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
143
|
0
|
0
|
|
|
|
0
|
$self->{cachedir} && -e $self->{sofile}; |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# prepend linenumber-heuristic |
147
|
|
|
|
|
|
|
sub _lineno($$) { |
148
|
2
|
|
|
2
|
|
4
|
my ($code, $id) = @_; |
149
|
2
|
|
|
|
|
16
|
my @c = caller(1); |
150
|
2
|
|
|
|
|
4
|
my $line = $c[2]*1; |
151
|
2
|
50
|
|
|
|
7
|
$id = $c[3] unless $id; |
152
|
2
|
|
|
|
|
5
|
$id = sanitize_id $id; |
153
|
2
|
50
|
|
|
|
10
|
$line++ if $code =~ /\n/; # assume here document |
154
|
2
|
|
|
|
|
22
|
"\n#line $line \"$id\"\n".$code."\n"; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=head2 hdr sourcecode, [id] |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
Add C to the header portion. Similar to the header portion of |
160
|
|
|
|
|
|
|
an XS module, you can insert any valid C-code here. Most often you'd add |
161
|
|
|
|
|
|
|
some include directives, though. |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
C can be used to identify this portion (for error messages). |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=cut |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# add simple C code as header |
168
|
|
|
|
|
|
|
sub hdr($$$) { |
169
|
1
|
|
|
1
|
1
|
156
|
my ($self, $code, $id) = @_; |
170
|
1
|
|
|
|
|
3
|
$self->{dirty} = 1; |
171
|
1
|
|
|
|
|
5
|
$self->{hdr} .= _lineno($code, $id); |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
=head2 cfun functionbody, [id], [prototype] |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
Adds a XS function whose body is given in C. Unlike |
177
|
|
|
|
|
|
|
XS, you have to do argument processing (i.e. fiddling with C) |
178
|
|
|
|
|
|
|
yourself. C specifies the function name (for C or error |
179
|
|
|
|
|
|
|
messages), and can be omitted (which results in a default name). |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
C is an optional string that specifies the perl |
182
|
|
|
|
|
|
|
protoype. Remember that only the parser will evaluate prototypes. |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=cut |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# add a function body written in C |
187
|
|
|
|
|
|
|
sub cfun($$$$) { |
188
|
1
|
|
|
1
|
1
|
5
|
my ($self, $body, $id, $prototype) = @_; |
189
|
1
|
|
|
|
|
3
|
$self->{dirty} = 1; |
190
|
1
|
|
50
|
|
|
3
|
$self->{fun}{$id||"default"} = [_lineno($body, $id), $prototype]; |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=head2 xsfun xs-source |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
Similar to C, but is able to parse normal XS syntax (most of it, |
196
|
|
|
|
|
|
|
that is). Pity that I haven't yet implemented this function, since that |
197
|
|
|
|
|
|
|
would require serious recoding of C. |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=cut |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
# add a function body written in XS |
202
|
|
|
|
|
|
|
sub xsfun($$$) { |
203
|
0
|
|
|
0
|
1
|
0
|
croak "add_xsfun not yet, implemented, use add_cfun isntead"; |
204
|
0
|
|
|
|
|
0
|
my ($self, $body) = @_; |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=head2 uselib lib... |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
Link against all the libraries given as arguments. The libraries should be |
210
|
|
|
|
|
|
|
specified as strings of the form C<-llibrary>. Additional search paths can |
211
|
|
|
|
|
|
|
be given using C<-L/path/to/libs>. See L. |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=cut |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
sub uselib { |
216
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
217
|
0
|
|
|
|
|
0
|
$self->{libs} .= " @_"; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
=head2 incpath path... |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
Add additional include paths. These paths are prepended to the other |
223
|
|
|
|
|
|
|
include paths. |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=cut |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
sub incpath { |
228
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
229
|
0
|
|
|
|
|
0
|
for (@_) { |
230
|
0
|
|
|
|
|
0
|
$self->{incpath} .= " -I$_"; |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
sub gen_cfile { |
235
|
1
|
|
|
1
|
0
|
3
|
my $self = shift; |
236
|
1
|
|
|
|
|
2
|
my $boot; |
237
|
1
|
50
|
|
|
|
101
|
open CFILE, ">".$self->{cfile} or croak "$self->{cfile}: $!"; |
238
|
1
|
|
|
|
|
26
|
print CFILE "#include \"EXTERN.h\"\n", |
239
|
|
|
|
|
|
|
"#include \"perl.h\"\n", |
240
|
|
|
|
|
|
|
"#include \"XSUB.h\"\n", |
241
|
|
|
|
|
|
|
$self->{hdr}."\n"; |
242
|
1
|
|
|
|
|
2
|
while (my ($id, $def) = each %{$self->{fun}}) { |
|
2
|
|
|
|
|
11
|
|
243
|
1
|
|
|
|
|
4
|
my ($body, $prot) = @$def; |
244
|
1
|
|
|
|
|
3
|
$id = sanitize_id $id; |
245
|
1
|
|
|
|
|
4
|
my $fun = "$self->{package}_$id"; |
246
|
1
|
|
|
|
|
5
|
print CFILE "XS($fun)\n{\n dXSARGS;\n\n$body\n\n XSRETURN_EMPTY;\n}\n\n"; |
247
|
1
|
50
|
|
|
|
6
|
$proto = $proto ? "newXSproto(0, $fun, __FILE__, \"$prot\")" |
248
|
|
|
|
|
|
|
: "newXS(0, $fun, __FILE__)"; |
249
|
1
|
|
|
|
|
7
|
$boot .= " hv_store (hv, \"$id\", ".(length $id).", newRV_noinc ((SV *)$proto), 0);\n"; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
1
|
|
|
|
|
5
|
print CFILE "XS(boot_$self->{package})\n{\n dXSARGS;\n HV *hv = (HV *)SvRV (ST (0));\n$boot}\n\n"; |
253
|
1
|
|
|
|
|
167
|
close CFILE; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
# somewhat os-specific |
257
|
|
|
|
|
|
|
sub run_cmd { |
258
|
2
|
|
|
2
|
0
|
376
|
my ($wd, $cmd) = @_; |
259
|
2
|
50
|
|
|
|
1888
|
if (0 == open CMD, "-|") { |
260
|
0
|
0
|
|
|
|
0
|
open STDERR, ">&STDOUT" or exit 1; |
261
|
0
|
0
|
|
|
|
0
|
chdir $wd or die "unable to cd to '$wd': $!\n"; |
262
|
0
|
|
|
|
|
0
|
exec $Config{sh}, "-c", $cmd; |
263
|
0
|
|
|
|
|
0
|
exit 127; # unreachable |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
#open CMD, "$cmd 2>&1 |" or croak "unable to execute '$cmd': $!"; |
266
|
2
|
|
|
|
|
151
|
local $/; |
267
|
2
|
|
|
|
|
382096
|
$cmd = ; |
268
|
2
|
|
|
|
|
215
|
((close CMD), $cmd); |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
# very os-specific(!) |
272
|
|
|
|
|
|
|
sub gen_sofile { |
273
|
1
|
|
|
1
|
0
|
4
|
my $self = shift; |
274
|
1
|
|
|
|
|
5
|
local $^W = 0; # perl is rather borken |
275
|
1
|
|
|
|
|
1070
|
($self->{ofile} = $self->{cfile}) =~ s/\.c$/$Config{_o}/; |
276
|
1
|
|
|
|
|
4000
|
my ($ok, $msg) = run_cmd $self->{tmpdir}, |
277
|
|
|
|
|
|
|
"$Config{cc} -c $self->{incpath} $Config{ccflags} $Config{optimize} $Config{large} ". |
278
|
|
|
|
|
|
|
"$Config{split} $Config{cccdlflags} $self->{cflags} -I$Config{archlibexp}/CORE $self->{cfile}"; |
279
|
1
|
|
|
|
|
65
|
$self->{messages} .= $msg; |
280
|
1
|
|
33
|
|
|
97
|
$ok &&= -e $self->{ofile}; |
281
|
1
|
50
|
|
|
|
14
|
if ($ok) { |
282
|
|
|
|
|
|
|
# perl_archive is os-specific(!) also export_list(!) |
283
|
1
|
50
|
|
|
|
22
|
if ($self->{libs}) { |
284
|
0
|
|
|
|
|
0
|
require ExtUtils::Liblist; |
285
|
0
|
|
|
|
|
0
|
@$self{'extralibs', 'bsloadlibs', 'ldloadlibs', 'ld_run_path'} = |
286
|
|
|
|
|
|
|
ExtUtils::Liblist::ext($self, $self->{libs}, 0); |
287
|
|
|
|
|
|
|
} |
288
|
1
|
|
|
|
|
45
|
($ok, $msg) = run_cmd $self->{tmpdir}, |
289
|
|
|
|
|
|
|
"LD_RUN_PATH=\"$self->{ld_run_path}\" $Config{ld} -o $self->{sofile} ". |
290
|
|
|
|
|
|
|
"$Config{lddlflags} $self->{ofile} $self->{otherldflags} $self->{perl_archive} ". |
291
|
|
|
|
|
|
|
"$self->{ldloadlibs} $self->{export_list}"; |
292
|
1
|
|
33
|
|
|
92
|
$ok &&= -e $self->{sofile}; |
293
|
1
|
|
|
|
|
9
|
$self->{messages} .= $msg; |
294
|
1
|
50
|
|
|
|
13
|
if ($ok) { |
295
|
1
|
|
|
|
|
62
|
chmod 0755, $self->{sofile}; |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
} |
298
|
1
|
|
|
|
|
9
|
unlink $ofile; |
299
|
1
|
|
|
|
|
6
|
$self->{dirty} = 0; |
300
|
1
|
|
|
|
|
30
|
$ok; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=head2 gen |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
Create the shared object file. This method is called automatically by |
306
|
|
|
|
|
|
|
C and even by C. This function returns a truth status and |
307
|
|
|
|
|
|
|
fills the messages attribute (see C) with any compiler/linker |
308
|
|
|
|
|
|
|
warnings or errors. |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=cut |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
# generate code (& optionally cache) |
313
|
|
|
|
|
|
|
sub gen($) { |
314
|
1
|
|
|
1
|
1
|
7
|
my $self = shift; |
315
|
1
|
|
33
|
|
|
8
|
$self->{tmpdir} ||= tmpdir_create(); |
316
|
1
|
|
|
|
|
5
|
$self->{messages} = ""; |
317
|
1
|
|
|
|
|
2
|
delete $self->{loaded}; |
318
|
1
|
50
|
33
|
|
|
52
|
$self->{sofile} ||= File::Spec->catfile($self->{tmpdir}, "$self->{id}.$Config{dlext}") unless $self->{sofile}; |
319
|
1
|
|
33
|
|
|
17
|
$self->{cfile} ||= File::Spec->catfile($self->{tmpdir}, "$self->{id}.c"); |
320
|
1
|
50
|
33
|
|
|
5
|
if ($self->{cachdir} && ! -d $self->{cachedir}) { |
321
|
0
|
0
|
|
|
|
0
|
mkdir $self->{cachedir},0755 or croak "unable to create '$self->{cachedir}': $!"; |
322
|
|
|
|
|
|
|
} |
323
|
1
|
|
33
|
|
|
26
|
my $ok = $self->gen_cfile && $self->gen_sofile; |
324
|
1
|
|
|
|
|
115
|
unlink $self->{cfile}; |
325
|
1
|
50
|
|
|
|
11
|
tmpdir_cleanup($self->{tmpdir}) if $self->{cachedir}; |
326
|
1
|
|
|
|
|
17
|
$ok; |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=head2 messages |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
Returns the compiler messages (created & updated by C). |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=cut |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
sub messages { |
336
|
1
|
|
|
1
|
1
|
390
|
shift->{messages}; |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=head2 load |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
Tries to load the shared object, generating it if necessary. Returns a |
342
|
|
|
|
|
|
|
truth status. |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=cut |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
sub load { |
347
|
1
|
|
|
1
|
1
|
6
|
my $self = shift; |
348
|
1
|
50
|
|
|
|
7
|
if (!$self->{loaded}) { |
349
|
1
|
50
|
33
|
|
|
17
|
if (!$self->{sofile} || $self->{dirty}) { |
350
|
0
|
0
|
|
|
|
0
|
$self->gen or return 0; |
351
|
|
|
|
|
|
|
} |
352
|
1
|
|
|
|
|
21
|
require DynaLoader; |
353
|
1
|
50
|
|
|
|
171
|
$self->{dl_lib} = DynaLoader::dl_load_file($self->{sofile}) or croak "unable to load $self->{sofile}"; |
354
|
1
|
50
|
|
|
|
22
|
$self->{dl_boot} = DynaLoader::dl_find_symbol($self->{dl_lib}, "boot_$self->{package}") or croak "no entry point found"; |
355
|
1
|
|
|
|
|
44
|
$self->{dl_boot_cv} = DynaLoader::dl_install_xsub(__PACKAGE__."boot_$self->{package}", $self->{dl_boot}); |
356
|
1
|
|
|
|
|
9
|
$self->{dl_hash} = { }; |
357
|
1
|
|
|
|
|
37
|
$self->{dl_boot_cv}->($self->{dl_hash}); |
358
|
1
|
|
|
|
|
10
|
$self->{loaded} = 1; |
359
|
|
|
|
|
|
|
} |
360
|
1
|
|
|
|
|
5
|
$self->{loaded}; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=head2 find [id] |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
Find the function (either xs or c) with id C and return a code-ref to |
366
|
|
|
|
|
|
|
it. If C is omitted, the default function (see C) is returned |
367
|
|
|
|
|
|
|
instead. If no shared object is loaded, calls C. |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=cut |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
sub find { |
372
|
1
|
|
|
1
|
1
|
172
|
my ($self, $fun) = @_; |
373
|
1
|
50
|
|
|
|
5
|
$self->load unless $self->{loaded}; |
374
|
1
|
|
50
|
|
|
14
|
$self->{dl_hash}{$fun||"default"}; |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=head1 BUGS/PROBLEMS |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
Requires a C compiler (or even worse: the same C compiler perl was compiled with). |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
Does (most probably) not work on many os's, especially non-unix ones. |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
You cannot yet use normal XS syntax. |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
Line number handling could be better. |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
=head1 AUTHOR |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
Marc Lehmann . |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=head1 SEE ALSO |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
perl(1). |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
=cut |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
# compatibility cruft for ExtUtils::Liblist |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
sub lsdir { |
400
|
0
|
|
|
0
|
0
|
|
my($self) = shift; |
401
|
0
|
|
|
|
|
|
my($dir, $regex) = @_; |
402
|
0
|
|
|
|
|
|
my(@ls); |
403
|
0
|
|
|
|
|
|
require DirHandle; |
404
|
0
|
|
|
|
|
|
my $dh = new DirHandle; |
405
|
0
|
0
|
0
|
|
|
|
$dh->open($dir || ".") or return (); |
406
|
0
|
|
|
|
|
|
@ls = $dh->read; |
407
|
0
|
|
|
|
|
|
$dh->close; |
408
|
0
|
0
|
|
|
|
|
@ls = grep(/$regex/, @ls) if $regex; |
409
|
0
|
|
|
|
|
|
@ls; |
410
|
|
|
|
|
|
|
} |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
1; |
413
|
|
|
|
|
|
|
|