File Coverage

blib/lib/Alien/Judy.pm
Criterion Covered Total %
statement 59 59 100.0
branch 6 12 50.0
condition 1 2 50.0
subroutine 12 12 100.0
pod 2 2 100.0
total 80 87 91.9


line stmt bran cond sub pod time code
1             # This is the Alien::Judy module, a way to ensure that users who don't
2             # natively have libJudy on their system can still get one. It provides
3             # libJudy.so and Judy.h at the path $Config{sitearch}/Alien/Judy.
4             package Alien::Judy;
5             # ABSTRACT: A wrapper for installing the Judy library
6              
7 1     1   75577 use strict;
  1         2  
  1         49  
8 1     1   7 use warnings;
  1         3  
  1         43  
9 1     1   6 use vars qw( $VERSION $DEBUG $HANDLE );
  1         8  
  1         69  
10 1     1   6 use Config ();
  1         2  
  1         25  
11 1     1   6 use Cwd ();
  1         1  
  1         15  
12 1     1   5 use File::Spec ();
  1         2  
  1         20  
13 1     1   5 use DynaLoader ();
  1         2  
  1         46  
14              
15             # This module allows users to import its three public functions
16             # inc_dirs(), lib_dirs(), and dl_load_libjudy().
17 1         11 use Sub::Exporter -setup => {
18             exports => [qw( inc_dirs lib_dirs dl_load_libjudy )]
19 1     1   3156 };
  1         34804  
20              
21             # The provided functions inc_dirs() and lib_dirs() are currently
22             # identical. Initially, they weren't.
23             *lib_dirs = \&inc_dirs;
24              
25             # TODO: add literate documentation
26             sub inc_dirs {
27             # Find files from ., $sitearch and @INC.
28 15 50       5274 my @dirs =
29 1     1 1 19 grep { defined() && length() }
30             @Config::Config{qw(sitearchexp sitearch)},
31             @INC,
32             Cwd::getcwd();
33              
34             # But first try to find them in $_/Alien/Judy/
35 15         91 unshift @dirs,
36 1         7 map { File::Spec->catdir( $_, 'Alien', 'Judy' ) }
37             @dirs;
38              
39             # Return the unique-ified list
40 1         4 my %seen;
41             return
42 1         3 grep { ! $seen{$_}++ }
  30         101  
43             @dirs;
44             }
45              
46             # This module depends on libJudy from
47             # http://judy.sourceforge.net. Either I can find it as a
48             # system-installed library:
49             #
50             # apt-get install libjudydebian1 # for libJudy.so
51             # apt-get install libjudy-dev # for Judy.h
52             #
53             # Or I can get it by the perl CPAN module Alien::Judy which builds and
54             # installs Judy.h and libJudy.so into $Config{sitearch}/Alien/Judy.
55             #
56             # CPAN testers however won't have actually installed libJudy so I'll
57             # need to find it in @INC as set by $ENV{PERL5LIB} with a typical
58             # value of:
59             #
60             # $INC[...] = '/home/josh/.cpan/build/Alien-Judy-0.01/blib/arch'
61             #
62             # but the files Judy.h and libJudy.so are a couple levels deeper at:
63             #
64             # $INC[...] = '/home/josh/.cpan/build/Alien-Judy-0.01/blib/arch/Alien/Judy'
65             #
66             sub _libjudy_candidates {
67             # Get a list of possible libJudy.so files.
68             #
69             # When writing this module, I found it would occasionally not only
70             # find libJudy.so but also blib/arch/Judy/Judy.so which is the
71             # Perl XS module. That was when this -lJudy resolving code was
72             # directly in the Judy cpan module though which has a lib/Judy.xs
73             # file. It's plausible that it's entirely irrelevant now that this
74             # is in Alien::Judy.
75             #
76 1     1   436488 my @candidate_libs = DynaLoader::dl_findfile('-lJudy');
77 1 50       15 if ( $DEBUG ) {
78 1         123 printf STDERR "candidates=@candidate_libs at %s line %d.\n", __FILE__, __LINE__;
79             }
80              
81             # I found that Solaris would find libJudy.so with DynaLoader but
82             # ld.so.1 when loading libJudy.so for Judy.pm would fail to find
83             # the right library to link against.
84             #
85             # I don't particularly understand it however what worked was to
86             # attempt to load libJudy.so.1 first.
87 1         128 my @dot_one =
88 1         7 grep { -f }
89 1         8 map { "$_.1" }
90             @candidate_libs;
91              
92 1         5 unshift @candidate_libs, @dot_one;
93              
94 1         7 return @candidate_libs;
95             }
96              
97             sub _dl_load_libjudy {
98 1     1   4 my @candidate_libs = @_;
99              
100             # The libJudy I find must provide the base functions from the
101             # libJudy library. This is to possibly skip "wrong" libJudy
102             # libraries.
103             # @DynaLoader::dl_require_symbols = 'Judy1Test';
104              
105             # Attempt to load each candidate until something succeeds. If one
106             # of the candidates happens to be the Perl XS module
107             # blib/arch/Judy/Judy.so then I'd like loading to keep trying and
108             # not fail. If I know how to predictably filter
109             # blib/arch/Judy/Judy.so out of this list I'd do that.
110 1         8 my $libjudy_loaded;
111             CANDIDATE_LIBRARY:
112 1         5 for my $libjudy_file ( @candidate_libs ) {
113 1         5 my $ok = eval {
114 1         205150 $HANDLE = DynaLoader::dl_load_file( $libjudy_file, 0x01 );
115 1         13 1;
116             };
117 1 50       12 if ( $DEBUG ) {
118 1 50       15 my $msgf =
119             $ok
120             ? "Loaded $libjudy_file at %s line %d.\n"
121             : "Couldn't load $libjudy_file: $@ at %s line %d.\n";
122 1         58 printf STDERR $msgf, __FILE__, __LINE__;
123             }
124              
125 1 50       15 if ( $ok ) {
126 1         7 $libjudy_loaded = 1;
127 1         7 last CANDIDATE_LIBRARY;
128             }
129             }
130              
131 1         5 return $libjudy_loaded;
132             }
133              
134             sub dl_load_libjudy {
135 1     1 1 331 local @DynaLoader::dl_library_path = (
136             @DynaLoader::dl_library_path,
137             lib_dirs()
138             );
139              
140             # Enable DynaLoader debugging along with Judy debugging
141 1         4 local $DynaLoader::dl_debug = $DynaLoader::dl_debug;
142 1 50       5 if ( $DEBUG ) {
143 1   50     7 $DynaLoader::dl_debug ||= 1;
144             }
145              
146 1         5 my @libjudy_files = _libjudy_candidates();
147              
148 1         9 my $ok = _dl_load_libjudy( @libjudy_files );
149              
150 1         23 return $ok;
151             }
152              
153             $VERSION = '0.26';
154              
155             1;