File Coverage

blib/lib/Alien/PNG.pm
Criterion Covered Total %
statement 79 97 81.4
branch 18 40 45.0
condition 2 9 22.2
subroutine 14 15 93.3
pod 3 3 100.0
total 116 164 70.7


line stmt bran cond sub pod time code
1             package Alien::PNG;
2 4     4   278279 use strict;
  4         34  
  4         121  
3 4     4   20 use warnings;
  4         8  
  4         102  
4 4     4   1726 use Alien::PNG::ConfigData;
  4         10  
  4         150  
5 4     4   2181 use File::ShareDir qw(dist_dir);
  4         109678  
  4         227  
6 4     4   32 use File::Spec;
  4         9  
  4         82  
7 4     4   19 use File::Find;
  4         12  
  4         251  
8 4     4   1930 use File::Spec::Functions qw(catdir catfile rel2abs);
  4         3364  
  4         298  
9 4     4   3047 use File::Temp ();
  4         78158  
  4         123  
10 4     4   1978 use ExtUtils::CBuilder;
  4         245807  
  4         5575  
11              
12             =head1 NAME
13              
14             Alien::PNG - building, finding and using PNG binaries
15              
16             =head1 VERSION
17              
18             Version 0.2
19              
20             =cut
21              
22             our $VERSION = '0.2';
23             $VERSION = eval $VERSION;
24              
25             =head1 SYNOPSIS
26              
27             Alien::PNG tries (in given order) during its installation:
28              
29             =over
30              
31             =item * Locate an already installed PNG via 'libpng-config' script.
32              
33             =item * Check for PNG libs in directory specified by PNG_INST_DIR variable.
34             In this case the module performs PNG library detection via
35             '$PNG_INST_DIR/bin/libpng-config' script.
36              
37             =item * Download prebuilt PNG binaries (if available for your platform).
38              
39             =item * Build PNG binaries from source codes (if possible on your system).
40              
41             =back
42              
43             Later you can use Alien::PNG in your module that needs to link agains PNG
44             and/or related libraries like this:
45              
46             # Sample Makefile.pl
47             use ExtUtils::MakeMaker;
48             use Alien::PNG;
49              
50             WriteMakefile(
51             NAME => 'Any::PNG::Module',
52             VERSION_FROM => 'lib/Any/PNG/Module.pm',
53             LIBS => Alien::PNG->config('libs', [-lAdd_Lib]),
54             INC => Alien::PNG->config('cflags'),
55             # + additional params
56             );
57              
58             =head1 DESCRIPTION
59              
60             Please see L for the manifest of the Alien namespace.
61              
62             In short C can be used to detect and get
63             configuration settings from an installed PNG and related libraries.
64             Based on your platform it offers the possibility to download and
65             install prebuilt binaries or to build PNG & co. from source codes.
66              
67             The important facts:
68              
69             =over
70              
71             =item * The module does not modify in any way the already existing PNG
72             installation on your system.
73              
74             =item * If you reinstall PNG libs on your system you do not need to
75             reinstall Alien::PNG (providing that you use the same directory for
76             the new installation).
77              
78             =item * The prebuild binaries and/or binaries built from sources are always
79             installed into perl module's 'share' directory.
80              
81             =item * If you use prebuild binaries and/or binaries built from sources
82             it happens that some of the dynamic libraries (*.so, *.dll) will not
83             automaticly loadable as they will be stored somewhere under perl module's
84             'share' directory. To handle this scenario Alien::PNG offers some special
85             functionality (see below).
86              
87             =back
88              
89             =head1 METHODS
90              
91             =head2 config()
92              
93             This function is the main public interface to this module. Basic
94             functionality works in a very similar maner to 'libpng-config' script:
95              
96             Alien::PNG->config('prefix'); # gives the same string as 'libpng-config --prefix'
97             Alien::PNG->config('version'); # gives the same string as 'libpng-config --version'
98             Alien::PNG->config('libs'); # gives the same string as 'libpng-config --libs'
99             Alien::PNG->config('cflags'); # gives the same string as 'libpng-config --cflags'
100              
101             On top of that this function supports special parameters:
102              
103             Alien::PNG->config('ld_shared_libs');
104              
105             Returns a list of full paths to shared libraries (*.so, *.dll) that will be
106             required for running the resulting binaries you have linked with PNG libs.
107              
108             Alien::PNG->config('ld_paths');
109              
110             Returns a list of full paths to directories with shared libraries (*.so, *.dll)
111             that will be required for running the resulting binaries you have linked with
112             PNG libs.
113              
114             Alien::PNG->config('ld_shlib_map');
115              
116             Returns a reference to hash of value pairs '' => ',
117             where '' is shortname for PNG related library like: PNG.
118              
119             NOTE: config('ld_') return an empty list/hash if you have decided to
120             use PNG libraries already installed on your system. This concerns 'libpng-config'
121             detection and detection via '$PNG_INST_DIR/bin/libpng-config'.
122              
123             =head2 check_header()
124              
125             This function checks the availability of given header(s) when using compiler
126             options provided by "Alien::PNG->config('cflags')".
127              
128             Alien::PNG->check_header('png.h');
129             Alien::PNG->check_header('png.h', 'pngconf.h');
130              
131             Returns 1 if all given headers are available, 0 otherwise.
132              
133             =head2 get_header_version()
134              
135             Tries to find a header file specified as a param in PNG prefix direcotry and
136             based on "#define" macros inside this header file tries to get a version triplet.
137              
138             Alien::PNG->get_header_version('png.h');
139              
140             Returns string like '1.2.3' or undef if not able to find and parse version info.
141              
142             =head1 BUGS
143              
144             Please post issues and bugs at L
145              
146             =head1 AUTHOR
147              
148             Tobias Leich
149             CPAN ID: FROGGS
150             FROGGS@cpan.org
151              
152             =head1 ACKNOWLEDGEMENTS
153              
154             This module is based on Alien::SDL, so in fact the credits has to be given to these guys.
155             kmx - complete redesign between versions 0.7.x and 0.8.x
156              
157             =head1 COPYRIGHT
158              
159             This program is free software; you can redistribute
160             it and/or modify it under the same terms as Perl itself.
161              
162             The full text of the license can be found in the
163             LICENSE file included with this module.
164              
165             =cut
166              
167             ### get config params
168             sub config
169             {
170 10     10 1 1129 my $package = shift;
171 10         29 my @params = @_;
172 10 50       63 return _png_config_via_script(@params) if(Alien::PNG::ConfigData->config('script'));
173 10 50       32 return _png_config_via_config_data(@params) if(Alien::PNG::ConfigData->config('config'));
174             }
175              
176             ### get version info from given header file
177             sub get_header_version {
178 2     2 1 99 my ($package, $header) = @_;
179 2 50       9 return unless $header;
180              
181             # try to find header
182 2         8 my $root = Alien::PNG->config('prefix');
183             #warn 'Finding in '.$root.'/include';
184 2         20 my $include = File::Spec->catfile($root, 'include');
185 2         5 my @files;
186 2 100   12   291 find({ wanted => sub { push @files, rel2abs($_) if /\Q$header\E$/ }, follow => 1, no_chdir => 1, follow_skip => 2 }, $include);
  12         745  
187 2 50       62 return unless @files;
188              
189             # get version info
190 2 50       79 open(DAT, $files[0]) || return;
191 2         2125 my @raw=;
192 2         46 close(DAT);
193              
194             # generic magic how to get version major/minor/patchlevel
195 2         662 my ($v_maj) = grep(/^#define[ \t]+[A-Z_]+?MAJOR[A-Z_]*[ \t]+[0-9]+/, @raw);
196 2         19 $v_maj =~ s/^#define[ \t]+[A-Z_]+[ \t]+([0-9]+)[.\r\n]*$/$1/;
197 2         614 my ($v_min) = grep(/^#define[ \t]+[A-Z_]+MINOR[A-Z_]*[ \t]+[0-9]+/, @raw);
198 2         14 $v_min =~ s/^#define[ \t]+[A-Z_]+[ \t]+([0-9]+)[.\r\n]*$/$1/;
199 2         754 my ($v_pat) = grep(/^#define[ \t]+[A-Z_]+(PATCHLEVEL|MICRO|RELEASE)[A-Z_]*[ \t]+[0-9]+/, @raw);
200 2         11 $v_pat =~ s/^#define[ \t]+[A-Z_]+[ \t]+([0-9]+)[.\r\n]*$/$1/;
201 2 50 33     23 return if (($v_maj eq '')||($v_min eq '')||($v_pat eq ''));
      33        
202 2         235 return "$v_maj.$v_min.$v_pat";
203             }
204              
205             ### check presence of header(s) specified as params
206             sub check_header {
207 2     2 1 3581 my ($package, @header) = @_;
208 2         82 print STDERR "[$package] Testing header(s): " . join(', ', @header) . "\n";
209 2         47 my $cb = ExtUtils::CBuilder->new(quiet => 1);
210 2         51518 my ($fs, $src) = File::Temp::tempfile('aaXXXX', SUFFIX => '.c', UNLINK => 1);
211 2         1298 my $inc = '';
212 2         25 $inc .= "#include <$_>\n" for @header;
213 2         81 syswrite($fs, <
214             #include
215             #if defined(_WIN32) && !defined(__CYGWIN__)
216             /* GL/gl.h on Win32 requires windows.h being included before */
217             #include
218             #endif
219             $inc
220             int demofunc(void) { return 0; }
221              
222             MARKER
223 2         32 close($fs);
224             #open OLDERR, ">&STDERR";
225             #open STDERR, ">", File::Spec->devnull();
226 2         7 my $obj = eval { $cb->compile( source => $src, extra_compiler_flags => Alien::PNG->config('cflags')); };
  2         26  
227             #open(STDERR, ">&OLDERR");
228 2 50       162137 if($obj) {
229 2         215 unlink $obj;
230 2         86 return 1;
231             }
232             else {
233 0         0 print STDERR "###TEST FAILED### for: " . join(', ', @header) . "\n";
234 0         0 return 0;
235             }
236             }
237              
238             ### internal functions
239             sub _png_config_via_script
240             {
241 0     0   0 my $param = shift;
242 0         0 my @add_libs = @_;
243 0         0 my $devnull = File::Spec->devnull();
244 0         0 my $script = Alien::PNG::ConfigData->config('script');
245 0 0 0     0 return unless ($script && ($param =~ /[a-z0-9_]*/i));
246 0         0 my $val = `$script --$param 2>$devnull`;
247 0         0 $val =~ s/[\r\n]*$//;
248 0 0       0 if($param eq 'cflags') {
    0          
249 0         0 $val .= ' ' . Alien::PNG::ConfigData->config('additional_cflags');
250             }
251             elsif($param eq 'libs') {
252 0 0       0 $val .= ' ' . join(' ', @add_libs) if scalar @add_libs;
253 0         0 $val .= ' ' . Alien::PNG::ConfigData->config('additional_libs');
254             }
255 0         0 return $val;
256             }
257              
258             sub _png_config_via_config_data
259             {
260 10     10   19 my $param = shift;
261 10         22 my @add_libs = @_;
262 10         46 my $share_dir = dist_dir('Alien-PNG');
263 10         1217 my $subdir = Alien::PNG::ConfigData->config('share_subdir');
264 10 50       26 return unless $subdir;
265 10         55 my $real_prefix = catdir($share_dir, $subdir);
266 10 50       69 return unless ($param =~ /[a-z0-9_]*/i);
267 10         31 my $val = Alien::PNG::ConfigData->config('config')->{$param};
268 10 50       38 return unless $val;
269             # handle additional flags
270 10 100       39 if($param eq 'cflags') {
    50          
271 2         7 $val .= ' ' . Alien::PNG::ConfigData->config('additional_cflags');
272             }
273             elsif($param eq 'libs') {
274 0 0       0 $val .= ' ' . join(' ', @add_libs) if scalar @add_libs;
275 0         0 $val .= ' ' . Alien::PNG::ConfigData->config('additional_libs');
276             }
277             # handle @PrEfIx@ replacement
278 10 100       42 if ($param =~ /^(ld_shared_libs|ld_paths)$/) {
    50          
279 2         5 s/\@PrEfIx\@/$real_prefix/g foreach (@{$val});
  2         14  
280             }
281             elsif ($param =~ /^(ld_shlib_map)$/) {
282 0         0 while (my ($k, $v) = each %$val ) {
283 0         0 $val->{$k} =~ s/\@PrEfIx\@/$real_prefix/g;
284             }
285             }
286             else {
287 8         36 $val =~ s/\@PrEfIx\@/$real_prefix/g;
288             }
289 10         90 return $val;
290             }
291              
292             1;