File Coverage

blib/lib/Alien/PNG.pm
Criterion Covered Total %
statement 80 117 68.3
branch 19 50 38.0
condition 2 12 16.6
subroutine 14 16 87.5
pod 3 3 100.0
total 118 198 59.6


line stmt bran cond sub pod time code
1             package Alien::PNG;
2 4     4   276945 use strict;
  4         33  
  4         116  
3 4     4   20 use warnings;
  4         7  
  4         102  
4 4     4   1723 use Alien::PNG::ConfigData;
  4         10  
  4         151  
5 4     4   2191 use File::ShareDir qw(dist_dir);
  4         109557  
  4         209  
6 4     4   29 use File::Spec;
  4         7  
  4         80  
7 4     4   17 use File::Find;
  4         14  
  4         292  
8 4     4   1882 use File::Spec::Functions qw(catdir catfile rel2abs);
  4         3370  
  4         331  
9 4     4   3444 use File::Temp ();
  4         77918  
  4         114  
10 4     4   2044 use ExtUtils::CBuilder;
  4         244277  
  4         6785  
11              
12             =head1 NAME
13              
14             Alien::PNG - building, finding and using PNG binaries
15              
16             =head1 VERSION
17              
18             Version 0.3_01
19              
20             =cut
21              
22             our $VERSION = '0.3_01';
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 1139 my $package = shift;
171 10         27 my @params = @_;
172 10 50       62 return _png_config_via_script(@params) if Alien::PNG::ConfigData->config('script');
173 10 50       33 return _png_config_via_win32_pkgconfig(@params) if Alien::PNG::ConfigData->config('win32_pkgconfig');
174 10 50       26 return _png_config_via_config_data(@params) if Alien::PNG::ConfigData->config('config');
175             }
176              
177             ### get version info from given header file
178             sub get_header_version {
179 2     2 1 94 my ($package, $header) = @_;
180 2 50       7 return unless $header;
181              
182             # try to find header
183 2         7 my $root = Alien::PNG->config('prefix');
184             #warn 'Finding in '.$root.'/include';
185 2         20 my $include = File::Spec->catfile($root, 'include');
186 2         6 my @files;
187 2 100   12   311 find({ wanted => sub { push @files, rel2abs($_) if /\Q$header\E$/ }, follow => 1, no_chdir => 1, follow_skip => 2 }, $include);
  12         750  
188 2 50       63 return unless @files;
189              
190             # get version info
191 2 50       77 open(DAT, $files[0]) || return;
192 2         2035 my @raw=;
193 2         44 close(DAT);
194              
195             # generic magic how to get version major/minor/patchlevel
196 2         604 my ($v_maj) = grep(/^#define[ \t]+[A-Z_]+?MAJOR[A-Z_]*[ \t]+[0-9]+/, @raw);
197 2         17 $v_maj =~ s/^#define[ \t]+[A-Z_]+[ \t]+([0-9]+)[.\r\n]*$/$1/;
198 2         589 my ($v_min) = grep(/^#define[ \t]+[A-Z_]+MINOR[A-Z_]*[ \t]+[0-9]+/, @raw);
199 2         12 $v_min =~ s/^#define[ \t]+[A-Z_]+[ \t]+([0-9]+)[.\r\n]*$/$1/;
200 2         773 my ($v_pat) = grep(/^#define[ \t]+[A-Z_]+(PATCHLEVEL|MICRO|RELEASE)[A-Z_]*[ \t]+[0-9]+/, @raw);
201 2         11 $v_pat =~ s/^#define[ \t]+[A-Z_]+[ \t]+([0-9]+)[.\r\n]*$/$1/;
202 2 50 33     19 return if (($v_maj eq '')||($v_min eq '')||($v_pat eq ''));
      33        
203 2         231 return "$v_maj.$v_min.$v_pat";
204             }
205              
206             ### check presence of header(s) specified as params
207             sub check_header {
208 2     2 1 11403 my ($package, @header) = @_;
209 2         54 print STDERR "[$package] Testing header(s): " . join(', ', @header) . "\n";
210 2         37 my $cb = ExtUtils::CBuilder->new(quiet => 1);
211 2         53139 my ($fs, $src) = File::Temp::tempfile('aaXXXX', SUFFIX => '.c', UNLINK => 1);
212 2         1136 my $inc = '';
213 2         13 $inc .= "#include <$_>\n" for @header;
214 2         76 syswrite($fs, <
215             #include
216             #if defined(_WIN32) && !defined(__CYGWIN__)
217             /* GL/gl.h on Win32 requires windows.h being included before */
218             #include
219             #endif
220             $inc
221             int demofunc(void) { return 0; }
222              
223             MARKER
224 2         27 close($fs);
225             #open OLDERR, ">&STDERR";
226             #open STDERR, ">", File::Spec->devnull();
227 2         5 my $obj = eval { $cb->compile( source => $src, extra_compiler_flags => Alien::PNG->config('cflags')); };
  2         24  
228             #open(STDERR, ">&OLDERR");
229 2 50       157846 if($obj) {
230 2         268 unlink $obj;
231 2         113 return 1;
232             }
233             else {
234 0         0 print STDERR "###TEST FAILED### for: " . join(', ', @header) . "\n";
235 0         0 return 0;
236             }
237             }
238              
239             ### internal functions
240             sub _png_config_via_script
241             {
242 0     0   0 my $param = shift;
243 0         0 my @add_libs = @_;
244 0         0 my $devnull = File::Spec->devnull();
245 0         0 my $script = Alien::PNG::ConfigData->config('script');
246 0 0 0     0 return unless ($script && ($param =~ /[a-z0-9_]*/i));
247 0         0 my $val = `$script --$param 2>$devnull`;
248 0         0 $val =~ s/[\r\n]*$//;
249 0 0       0 if($param eq 'cflags') {
    0          
250 0         0 $val .= ' ' . Alien::PNG::ConfigData->config('additional_cflags');
251             }
252             elsif($param eq 'libs') {
253 0 0       0 $val .= ' ' . join(' ', @add_libs) if scalar @add_libs;
254 0         0 $val .= ' ' . Alien::PNG::ConfigData->config('additional_libs');
255             }
256 0         0 return $val;
257             }
258              
259             sub _png_config_via_win32_pkgconfig
260             {
261 0     0   0 my $param = shift;
262 0         0 my @add_libs = @_;
263 0         0 my $devnull = File::Spec->devnull();
264 0         0 my $pkgconfig = Alien::PNG::ConfigData->config('win32_pkgconfig');
265 0 0 0     0 return unless ($pkgconfig && ($param =~ /[a-z0-9_]*/i));
266              
267 0         0 my ($prefix) = grep { /\/perl\/lib$/ } @INC;
  0         0  
268 0 0       0 return unless $prefix;
269 0         0 $prefix =~ s/\/perl\/lib$/\/c/;
270 0         0 $pkgconfig->{prefix} = $prefix;
271              
272 0 0       0 if (ref $pkgconfig->{$param} eq 'ARRAY') {
    0          
273 0         0 return map { s/\@PrEfIx\@/$prefix/g; } @{$pkgconfig->{$param}};
  0         0  
  0         0  
274             }
275             elsif (ref $pkgconfig->{$param} eq 'HASH') {
276 0         0 map { $pkgconfig->{$param}{$_} =~ s/\@PrEfIx\@/$prefix/g } keys %{$pkgconfig->{$param}};
  0         0  
  0         0  
277             }
278             else {
279 0         0 $pkgconfig->{$param} =~ s/\@PrEfIx\@/$prefix/g;
280             }
281              
282 0         0 $pkgconfig->{$param};
283             }
284              
285             sub _png_config_via_config_data
286             {
287 10     10   19 my $param = shift;
288 10         21 my @add_libs = @_;
289 10         39 my $share_dir = dist_dir('Alien-PNG');
290 10         1193 my $subdir = Alien::PNG::ConfigData->config('share_subdir');
291 10 50       29 return unless $subdir;
292 10         61 my $real_prefix = catdir($share_dir, $subdir);
293 10 50       63 return unless ($param =~ /[a-z0-9_]*/i);
294 10         30 my $val = Alien::PNG::ConfigData->config('config')->{$param};
295 10 50       30 return unless $val;
296             # handle additional flags
297 10 100       49 if($param eq 'cflags') {
    50          
298 2         9 $val .= ' ' . Alien::PNG::ConfigData->config('additional_cflags');
299             }
300             elsif($param eq 'libs') {
301 0 0       0 $val .= ' ' . join(' ', @add_libs) if scalar @add_libs;
302 0         0 $val .= ' ' . Alien::PNG::ConfigData->config('additional_libs');
303             }
304             # handle @PrEfIx@ replacement
305 10 100       36 if ($param =~ /^(ld_shared_libs|ld_paths)$/) {
    50          
306 2         4 s/\@PrEfIx\@/$real_prefix/g foreach (@{$val});
  2         13  
307             }
308             elsif ($param =~ /^(ld_shlib_map)$/) {
309 0         0 while (my ($k, $v) = each %$val ) {
310 0         0 $val->{$k} =~ s/\@PrEfIx\@/$real_prefix/g;
311             }
312             }
313             else {
314 8         40 $val =~ s/\@PrEfIx\@/$real_prefix/g;
315             }
316 10         85 return $val;
317             }
318              
319             1;