File Coverage

blib/lib/DynaLoader/Functions.pm
Criterion Covered Total %
statement 57 107 53.2
branch 24 70 34.2
condition 8 21 38.1
subroutine 11 17 64.7
pod 6 6 100.0
total 106 221 47.9


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             DynaLoader::Functions - deconstructed dynamic C library loading
4              
5             =head1 SYNOPSIS
6              
7             use DynaLoader::Functions qw(
8             loadable_for_module
9             linkable_for_loadable linkable_for_module);
10              
11             $loadable = loadable_for_module("Acme::Widget");
12             @linkable = linkable_for_loadable($loadable);
13             @linkable = linkable_for_module("Acme::Widget");
14              
15             use DynaLoader::Functions qw(dyna_load dyna_resolve dyna_unload);
16              
17             $libh = dyna_load($loadable, {
18             require_symbols => ["boot_Acme__Widget"],
19             });
20             my $bootfunc = dyna_resolve($libh, "boot_Acme__Widget");
21             dyna_unload($libh);
22              
23             =head1 DESCRIPTION
24              
25             This module provides a function-based interface to dynamic loading as used
26             by Perl. Some details of dynamic loading are very platform-dependent,
27             so correct use of these functions requires the programmer to be mindful
28             of the space of platform variations.
29              
30             =cut
31              
32             package DynaLoader::Functions;
33              
34 2     2   244495 { use 5.006; }
  2         8  
35 2     2   13 use warnings;
  2         5  
  2         73  
36 2     2   15 use strict;
  2         4  
  2         71  
37              
38             our $VERSION = "0.003";
39              
40 2     2   244 use parent "Exporter";
  2         228  
  2         15  
41             our @EXPORT_OK = qw(
42             loadable_for_module linkable_for_loadable linkable_for_module
43             dyna_load dyna_resolve dyna_unload
44             );
45              
46 2     2   138 use constant _IS_VMS => $^O eq "VMS";
  2         3  
  2         153  
47 2     2   9 use constant _IS_NETWARE => $^O eq "NetWare";
  2         4  
  2         2800  
48              
49             # It is presumed that VMS::Filespec will always be installed on VMS.
50             # It is not listed as a dependency of this module, because it is
51             # unavailable on other platforms.
52             require VMS::Filespec if _IS_VMS;
53              
54             # Load Carp lazily, as do DynaLoader and other things at this level.
55 0     0   0 sub _carp { require Carp; Carp::carp(@_); }
  0         0  
56 0     0   0 sub _croak { require Carp; Carp::croak(@_); }
  0         0  
57              
58             # Logic duplicated from Params::Classify. This is too much of an
59             # infrastructure module, an early build dependency, for it to have such
60             # a dependency.
61             sub _is_string($) {
62 6     6   18 my($arg) = @_;
63 6   33     100 return defined($arg) && ref(\$arg) eq "SCALAR";
64             }
65 1 50   1   9 sub _check_string($) { die "argument is not a string\n" unless &_is_string; }
66              
67             # Logic duplicated from Module::Runtime for the same reason.
68             sub _check_module_name($) {
69 0 0   0   0 if(!&_is_string) {
    0          
70 0         0 die "argument is not a module name\n";
71             } elsif($_[0] !~ /\A[A-Z_a-z][0-9A-Z_a-z]*(?:::[0-9A-Z_a-z]+)*\z/) {
72 0         0 die "`$_[0]' is not a module name\n";
73             }
74             }
75              
76             =head1 FUNCTIONS
77              
78             =head2 File finding
79              
80             =over
81              
82             =item loadable_for_module(MODULE_NAME)
83              
84             I<MODULE_NAME> must be the name of a Perl module, in bareword syntax with
85             C<::> separators. The named module is presumed to be an XS extension
86             following standard conventions, and its runtime-loadable C library file is
87             searched for. If found, the name of the library file is returned. If it
88             cannot be found, the function C<die>s with an informative error message.
89              
90             If the named module is actually not an XS extension, or is not installed,
91             or stores its C library in a non-standard place, there is a non-trivial
92             danger that this function will find some other library file and believe
93             it to be the right one. This function should therefore only be used
94             when there is an expectation that the module is installed and would in
95             normal operation load its corresponding C library.
96              
97             =cut
98              
99             sub loadable_for_module($) {
100 0     0 1 0 my($modname) = @_;
101 0         0 _check_module_name($modname);
102 0         0 require DynaLoader;
103             # This logic is derived from DynaLoader::bootstrap(). In places
104             # it mixes native directory names from @INC and Unix-style
105             # /-separated path syntax. This apparently works correctly
106             # everywhere, except for VMS where there's an explicit conversion.
107 0         0 my @modparts = split(/::/,$modname);
108 0         0 my $modfname = $modparts[-1];
109 0 0       0 $modfname = &DynaLoader::mod2fname(\@modparts)
110             if defined &DynaLoader::mod2fname;
111 0         0 if(_IS_NETWARE) {
112             # This ought to be part of mod2fname.
113             $modfname = substr($modfname, 0, 8);
114             }
115 0         0 my $modpname = join("/",@modparts);
116             my $loadlib = DynaLoader::dl_findfile(
117             (map {
118 0 0       0 my $d = $_;
  0         0  
119 0         0 if(_IS_VMS) {
120             $d = VMS::Filespec::unixpath($d);
121             chop $d;
122             }
123 0         0 "-L$d/auto/$modpname";
124             } @INC),
125             @INC,
126             $modfname)
127             or _croak "Can't locate loadable object ".
128             "for module $modname in \@INC (\@INC contains: @INC)";
129 0         0 if(_IS_VMS && ((require Config),
130             $Config::Config{d_vms_case_sensitive_symbols})) {
131             $loadlib = uc($loadlib);
132             }
133 0         0 return $loadlib;
134             }
135              
136             =item linkable_for_loadable(LOADABLE_FILENAME)
137              
138             If symbols in one runtime-loadable C library are to be made available
139             to another runtime-loadable C library, depending on the platform it
140             may be necessary to refer to the exporting library when linking the
141             importing library. Generally this is not required on Unix, but it is
142             required on Windows. Where it is required to refer to the exporting
143             library at link time, the file used may be the loadable library file
144             itself, or may be a separate file used only for this purpose. Given the
145             loadable form of an exporting library, this function determines what is
146             required at link time for an importing library.
147              
148             I<LOADABLE_FILENAME> must be the name of a runtime-loadable C library
149             file. The function checks what is required to link a library that will
150             at runtime import symbols from this library. It returns a list (which
151             will be empty on many platforms) of names of files that must be used as
152             additional objects when linking the importing library.
153              
154             =cut
155              
156             my $linkable_finder = {
157             MSWin32 => sub {
158             require Config;
159             if((my $basename = $_[0]) =~
160             s/\.\Q$Config::Config{dlext}\E\z//oi) {
161             foreach my $suffix (qw(.lib .a)) {
162             my $impname = $basename.$suffix;
163             return ($impname) if -e $impname;
164             }
165             }
166             _croak "Can't locate linkable object for $_[0]";
167             },
168             cygwin => sub { ($_[0]) },
169             }->{$^O};
170              
171             sub linkable_for_loadable($) {
172 0     0 1 0 _check_string($_[0]);
173 0 0       0 if($linkable_finder) {
174 0         0 return $linkable_finder->($_[0]);
175             } else {
176 0         0 return ();
177             }
178             }
179              
180             =item linkable_for_module(MODULE_NAME)
181              
182             Performs the job of L</linkable_for_loadable> (which see for explanation),
183             but based on a module name instead of a loadable library filename.
184              
185             I<MODULE_NAME> must be the name of a Perl module, in bareword syntax
186             with C<::> separators. The function checks what is required to link a
187             library that will at runtime import symbols from the loadable C library
188             associated with the module. It returns a list (which will be empty
189             on many platforms) of names of files that must be used as additional
190             objects when linking the importing library.
191              
192             =cut
193              
194             sub linkable_for_module($) {
195 0 0   0 1 0 if($linkable_finder) {
196 0         0 return $linkable_finder->(loadable_for_module($_[0]));
197             } else {
198 0         0 _check_module_name($_[0]);
199 0         0 return ();
200             }
201             }
202              
203             =back
204              
205             =head2 Low-level dynamic loading
206              
207             =over
208              
209             =item dyna_load(LOADABLE_FILENAME[, OPTIONS])
210              
211             Dynamically load the runtime-loadable C library in the file named
212             I<LOADABLE_FILENAME>. The process is influenced by optional information
213             supplied in the hash referenced by I<OPTIONS>. On the platforms that
214             make dynamic loading easiest it is not necessary to supply any options
215             (in which case the parameter may be omitted), but if wide portability
216             is required then some options are required. The permitted keys in the
217             I<OPTIONS> hash are:
218              
219             =over
220              
221             =item B<resolve_using>
222              
223             Reference to an array, default empty, of names of additional library
224             files required to supply symbols used by the library being loaded.
225             On most platforms this is not used. On those platforms where it is
226             required, the need for this will be known by whatever generated the
227             library to be loaded, and it will normally be set by a bootstrap file
228             (see B<use_bootstrap_options> below).
229              
230             =item B<require_symbols>
231              
232             Reference to an array, default empty, of names of symbols expected to be
233             found in the library being loaded. On most platforms this is not used,
234             but on some a library cannot be loaded without naming at least one symbol
235             for which a need can be satisfied by the library.
236              
237             =item B<use_bootstrap_options>
238              
239             Truth value, default false, controlling whether a "bootstrap" file will
240             be consulted as an additional source of options to control loading.
241             The "bootstrap" file, if it exists, is located in the same directory as
242             the loadable library file, and has a similar name differing only in its
243             C<.bs> ending.
244              
245             =item B<symbols_global>
246              
247             Truth value, default false, indicating whether symbols found in the
248             library being loaded must be made available to subsequently-loaded
249             libraries. Depending on platform, symbols may be so available even if
250             it is not requested. Some platforms, on the other hand, can't provide
251             this facility.
252              
253             On platforms incapable of making loaded symbols globally available,
254             currently loading is liable to claim success while leaving the symbols
255             de facto unavailable. It is intended that in the future such platforms
256             will instead generate an exception when this facility is requested.
257              
258             =item B<unresolved_action>
259              
260             String keyword indicating what should be done if unresolved symbols are
261             detected while loading the library. It may be "B<ERROR>" (default)
262             to treat it as an error, "B<WARN>" to emit a warning, or "B<IGNORE>"
263             to ignore the situation. Some platforms can't detect this problem,
264             so passing this check doesn't guarantee that there won't be any runtime
265             problems due to unresolved symbols.
266              
267             =back
268              
269             On success, returns a handle that can be used to refer to the loaded
270             library for subsequent calls to L</dyna_resolve> and L</dyna_unload>.
271             On failure, C<die>s.
272              
273             =cut
274              
275             sub dyna_load($;$) {
276 1     1 1 226217 my($loadable_filename, $options) = @_;
277 1 50       14 $options = {} if @_ < 2;
278 1         14 _check_string($loadable_filename);
279 1         11 foreach(sort keys %$options) {
280 1 50       21 _croak "bad dyna_load option `$_'" unless /\A(?:
281             resolve_using|require_symbols|use_bootstrap_options|
282             symbols_global|unresolved_action
283             )\z/x;
284             }
285             my $unres_action = exists($options->{unresolved_action}) ?
286 1 50       12 $options->{unresolved_action} : "ERROR";
287 1 50 33     7 _croak "bad dyna_load unresolved_action value `$unres_action'"
288             unless _is_string($unres_action) &&
289             $unres_action =~ /\A(?:ERROR|WARN|IGNORE)\z/;
290 1         20 require DynaLoader;
291 1 50       7 _croak "dynamic loading not available in this perl"
292             unless defined &DynaLoader::dl_load_file;
293             local @DynaLoader::dl_resolve_using =
294             exists($options->{resolve_using}) ?
295 1 50       8 @{$options->{resolve_using}} : ();
  0         0  
296             local @DynaLoader::dl_require_symbols =
297             exists($options->{require_symbols}) ?
298 1 50       8 @{$options->{require_symbols}} : ();
  1         9  
299 1 50       7 if($options->{use_bootstrap_options}) {
300 0         0 (my $bs = $loadable_filename) =~
301             s/(?:\.[0-9A-Z_a-z]+)?(?:;[0-9]*)?\z/\.bs/;
302 0 0       0 if(-s $bs) {
303 0         0 eval { package DynaLoader; do $bs; };
  0         0  
304 0 0       0 warn "$bs: $@" if $@ ne "";
305             }
306             }
307             my $libh = DynaLoader::dl_load_file($loadable_filename,
308 1 50       121 $options->{symbols_global} ? 0x01 : 0)
    50          
309             or _croak "failed to load library $loadable_filename: ".
310 0         0 "@{[DynaLoader::dl_error()]}";
311 1 50 33     20 if($unres_action ne "IGNORE" &&
312             (my @unresolved = DynaLoader::dl_undef_symbols())) {
313 0         0 my $e = "undefined symbols in $loadable_filename: @unresolved";
314 0 0       0 if($unres_action eq "ERROR") {
315 0         0 DynaLoader::dl_unload_file($libh);
316 0         0 _croak $e;
317             } else {
318 0         0 _carp $e;
319             }
320             }
321 1         8 return $libh;
322             }
323              
324             =item dyna_resolve(LIBRARY_HANDLE, SYMBOL_NAME[, OPTIONS])
325              
326             Resolve the symbol I<SYMBOL> in the previously-loaded library
327             identified by the I<LIBRARY_HANDLE>. The process is influenced by
328             optional information supplied in the hash referenced by I<OPTIONS>.
329             The permitted keys in the I<OPTIONS> hash are:
330              
331             =over
332              
333             =item B<unresolved_action>
334              
335             String keyword indicating what should be done if the symbol cannot
336             be resolved. It may be "B<ERROR>" (default) to treat it as an error,
337             "B<WARN>" to emit a warning and return C<undef>, or "B<IGNORE>" to return
338             C<undef> without a warning.
339              
340             =back
341              
342             On success, returns the value of the specified symbol, in a
343             platform-dependent format. Returns C<undef> if the symbol could not be
344             resolved and this is not being treated as an error.
345              
346             =cut
347              
348             sub dyna_resolve($$;$) {
349 3     3 1 840 my($libh, $symbol, $options) = @_;
350 3 50       13 $options = {} if @_ < 3;
351 3         19 foreach(sort keys %$options) {
352 3 50       23 _croak "bad dyna_resolve option `$_'"
353             unless /\Aunresolved_action\z/;
354             }
355             my $unres_action = exists($options->{unresolved_action}) ?
356 3 50       15 $options->{unresolved_action} : "ERROR";
357 3 50 33     11 _croak "bad dyna_load unresolved_action value `$unres_action'"
358             unless _is_string($unres_action) &&
359             $unres_action =~ /\A(?:ERROR|WARN|IGNORE)\z/;
360 3         26 require DynaLoader;
361 3         49 my $val = DynaLoader::dl_find_symbol($libh, $symbol);
362 3 50 66     22 if(!defined($val) && $unres_action ne "IGNORE") {
363 0         0 my $e = "undefined symbol: $symbol";
364 0 0       0 if($unres_action eq "ERROR") {
365 0         0 _croak $e;
366             } else {
367 0         0 _carp $e;
368             }
369             }
370 3         24 return $val;
371             }
372              
373             =item dyna_unload(LIBRARY_HANDLE[, OPTIONS])
374              
375             Unload the previously-loaded library identified by the I<LIBRARY_HANDLE>.
376             The process is influenced by optional information supplied in the hash
377             referenced by I<OPTIONS>. The permitted keys in the I<OPTIONS> hash are:
378              
379             =over
380              
381             =item B<fail_action>
382              
383             String keyword indicating what should be done if unloading detectably
384             fails. It may be "B<ERROR>" (default) to treat it as an error, "B<WARN>"
385             to emit a warning, or "B<IGNORE>" to ignore the situation.
386              
387             =back
388              
389             On some platforms unloading is not possible. On any platform,
390             unloading can be expected to cause mayhem if any code from the library
391             is currently executing, if there are any live references to data in the
392             library, or if any symbols provided by the library are referenced by
393             any subsequently-loaded library.
394              
395             =cut
396              
397             sub dyna_unload($;$) {
398 1     1 1 4 my($libh, $options) = @_;
399 1 50       6 $options = {} if @_ < 2;
400 1         7 foreach(sort keys %$options) {
401 1 50       11 _croak "bad dyna_unload option `$_'" unless /\Afail_action\z/;
402             }
403             my $fail_action = exists($options->{fail_action}) ?
404 1 50       8 $options->{fail_action} : "ERROR";
405 1 50 33     5 _croak "bad dyna_load fail_action value `$fail_action'"
406             unless _is_string($fail_action) &&
407             $fail_action =~ /\A(?:ERROR|WARN|IGNORE)\z/;
408 1         4 my $err;
409 1         7 require DynaLoader;
410 1 50       6 if(defined &DynaLoader::dl_unload_file) {
411 1 50       64 DynaLoader::dl_unload_file($_[0])
412             or $err = DynaLoader::dl_error();
413             } else {
414 0         0 $err = "can't unload on this platform";
415             }
416 1 50 33     10 if(defined($err) && $fail_action ne "IGNORE") {
417 0           my $e = "failed to unload library: $err";
418 0 0         if($fail_action eq "ERROR") {
419 0           _croak $e;
420             } else {
421 0           _carp $e;
422             }
423             }
424             }
425              
426             =back
427              
428             =head1 SEE ALSO
429              
430             L<DynaLoader>,
431             L<ExtUtils::CBuilder>,
432             L<XSLoader>
433              
434             =head1 AUTHOR
435              
436             Andrew Main (Zefram) <zefram@fysh.org>
437              
438             =head1 COPYRIGHT
439              
440             Copyright (C) 2011, 2012, 2013, 2017
441             Andrew Main (Zefram) <zefram@fysh.org>
442              
443             =head1 LICENSE
444              
445             This module is free software; you can redistribute it and/or modify it
446             under the same terms as Perl itself.
447              
448             =cut
449              
450             1;