File Coverage

blib/lib/Alien/SDL.pm
Criterion Covered Total %
statement 96 123 78.0
branch 21 48 43.7
condition 2 9 22.2
subroutine 16 17 94.1
pod 3 3 100.0
total 138 200 69.0


line stmt bran cond sub pod time code
1             package Alien::SDL;
2 4     4   61419 use strict;
  4         8  
  4         139  
3 4     4   13 use warnings;
  4         6  
  4         97  
4 4     4   1695 use Alien::SDL::ConfigData;
  4         6  
  4         135  
5 4     4   2401 use File::ShareDir qw(dist_dir);
  4         20403  
  4         310  
6 4     4   27 use File::Spec;
  4         6  
  4         64  
7 4     4   14 use File::Find;
  4         25  
  4         213  
8 4     4   1972 use File::Spec::Functions qw(catdir catfile rel2abs);
  4         2559  
  4         256  
9 4     4   2718 use File::Temp;
  4         69139  
  4         274  
10 4     4   1903 use Capture::Tiny;
  4         20546  
  4         194  
11 4     4   24 use Config;
  4         14  
  4         5836  
12              
13             =head1 NAME
14              
15             Alien::SDL - building, finding and using SDL binaries
16              
17             =head1 VERSION
18              
19             Version 1.445_2
20              
21             =cut
22              
23             our $VERSION = '1.445_2';
24             $VERSION = eval $VERSION;
25              
26             =head1 SYNOPSIS
27              
28             Alien::SDL tries (in given order) during its installation:
29              
30             =over
31              
32             =item * When given C<--with-sdl-config> option use specified sdl-config
33             script to locate SDL libs.
34              
35             perl Build.PL --with-sdl-config=/opt/sdl/bin/sdl-config
36              
37             or use the default script named 'sdl-config' by running:
38              
39             perl Build.PL --with-sdl-config
40              
41             B Using --with-sdl-config avoids considering any other
42             build methods; no prompt with other available build options.
43              
44             =item * Locate an already installed SDL via 'sdl-config' script.
45              
46             =item * Check for SDL libs in directory specified by SDL_INST_DIR variable.
47             In this case the module performs SDL library detection via
48             '$SDL_INST_DIR/bin/sdl-config' script.
49              
50             SDL_INST_DIR=/opt/sdl perl ./Build.PL
51              
52             =item * Download prebuilt SDL binaries (if available for your platform).
53              
54             =item * Build SDL binaries from source codes (if possible on your system).
55              
56             =back
57              
58             Later you can use Alien::SDL in your module that needs to link against SDL
59             and/or related libraries like this:
60              
61             # Sample Makefile.pl
62             use ExtUtils::MakeMaker;
63             use Alien::SDL;
64              
65             WriteMakefile(
66             NAME => 'Any::SDL::Module',
67             VERSION_FROM => 'lib/Any/SDL/Module.pm',
68             LIBS => Alien::SDL->config('libs', [-lAdd_Lib]),
69             INC => Alien::SDL->config('cflags'),
70             # + additional params
71             );
72              
73             =head1 DESCRIPTION
74              
75             Please see L for the manifesto of the Alien namespace.
76              
77             In short C can be used to detect and get
78             configuration settings from an installed SDL and related libraries.
79             Based on your platform it offers the possibility to download and
80             install prebuilt binaries or build SDL & co. from source codes.
81              
82             The important facts:
83              
84             =over
85              
86             =item * The module does not modify in any way the already existing SDL
87             installation on your system.
88              
89             =item * If you reinstall SDL libs on your system you do not need to
90             reinstall Alien::SDL (providing that you use the same directory for
91             the new installation).
92              
93             =item * The prebuilt binaries and/or binaries built from sources are always
94             installed into perl module's 'share' directory.
95              
96             =item * If you use the prebuilt binaries and/or binaries built from sources
97             it happens that some of the dynamic libraries (*.so, *.dll) will not
98             be automatically loadable as they will be stored somewhere under the perl
99             module's 'share' directory. To handle this scenario Alien::SDL offers some
100             special functionality (see below).
101              
102             =back
103              
104             =head1 METHODS
105              
106             =head2 config()
107              
108             This function is the main public interface to this module. Basic
109             functionality works in a very similar maner to 'sdl-config' script:
110              
111             Alien::SDL->config('prefix'); # gives the same string as 'sdl-config --prefix'
112             Alien::SDL->config('version'); # gives the same string as 'sdl-config --version'
113             Alien::SDL->config('libs'); # gives the same string as 'sdl-config --libs'
114             Alien::SDL->config('cflags'); # gives the same string as 'sdl-config --cflags'
115              
116             On top of that this function supports special parameters:
117              
118             Alien::SDL->config('ld_shared_libs');
119              
120             Returns a list of full paths to shared libraries (*.so, *.dll) that will be
121             required for running the resulting binaries you have linked with SDL libs.
122              
123             Alien::SDL->config('ld_paths');
124              
125             Returns a list of full paths to directories with shared libraries (*.so, *.dll)
126             that will be required for running the resulting binaries you have linked with
127             SDL libs.
128              
129             Alien::SDL->config('ld_shlib_map');
130              
131             Returns a reference to hash of value pairs '' => ',
132             where '' is shortname for SDL related library like: SDL, SDL_gfx, SDL_net,
133             SDL_sound ... + some non-SDL shortnames e.g. smpeg, jpeg, png.
134              
135             NOTE: config('ld_') return an empty list/hash if you have decided to
136             use SDL libraries already installed on your system. This concerns 'sdl-config'
137             detection and detection via '$SDL_INST_DIR/bin/sdl-config'.
138              
139             =head2 check_header()
140              
141             This function checks the availability of given header(s) when using compiler
142             options provided by "Alien::SDL->config('cflags')".
143              
144             Alien::SDL->check_header('SDL.h');
145             Alien::SDL->check_header('SDL.h', 'SDL_net.h');
146              
147             Returns 1 if all given headers are available, 0 otherwise.
148              
149             =head2 get_header_version()
150              
151             Tries to find a header file specified as a param in SDL prefix direcotry and
152             based on "#define" macros inside this header file tries to get a version triplet.
153              
154             Alien::SDL->get_header_version('SDL_mixer.h');
155             Alien::SDL->get_header_version('SDL_version.h');
156             Alien::SDL->get_header_version('SDL_gfxPrimitives.h');
157             Alien::SDL->get_header_version('SDL_image.h');
158             Alien::SDL->get_header_version('SDL_mixer.h');
159             Alien::SDL->get_header_version('SDL_net.h');
160             Alien::SDL->get_header_version('SDL_ttf.h');
161             Alien::SDL->get_header_version('smpeg.h');
162              
163             Returns string like '1.2.3' or undef if not able to find and parse version info.
164              
165             =head1 BUGS
166              
167             Please post issues and bugs at L
168              
169             =head1 AUTHOR
170              
171             Kartik Thakore
172             CPAN ID: KTHAKORE
173             Thakore.Kartik@gmail.com
174             http://yapgh.blogspot.com
175              
176             =head1 ACKNOWLEDGEMENTS
177              
178             kmx - complete redesign between versions 0.7.x and 0.8.x
179              
180             =head1 COPYRIGHT
181              
182             This program is free software; you can redistribute
183             it and/or modify it under the same terms as Perl itself.
184              
185             The full text of the license can be found in the
186             LICENSE file included with this module.
187              
188             =cut
189              
190             ### get config params
191             sub config
192             {
193 11     11 1 1153 my $package = shift;
194 11         23 my @params = @_;
195 11 50       50 return _sdl_config_via_script(@params) if(Alien::SDL::ConfigData->config('script'));
196 11 50       52 return _sdl_config_via_config_data(@params) if(Alien::SDL::ConfigData->config('config'));
197             }
198              
199             ### get version info from given header file
200             sub get_header_version {
201 2     2 1 13 my ($package, $header) = @_;
202 2 50       6 return unless $header;
203              
204             # try to find header
205 2         8 my $root = Alien::SDL->config('prefix');
206             #warn 'Finding in '.$root.'/include';
207 2         19 my $include = File::Spec->catfile($root, 'include');
208 2         4 my @files;
209 2 100   230   266 find({ wanted => sub { push @files, rel2abs($_) if /\Q$header\E$/ }, follow => 1, no_chdir => 1, follow_skip => 2 }, $include);
  230         6246  
210 2 50       13 return unless @files;
211              
212             # get version info
213 2 50       77 open(DAT, $files[0]) || return;
214 2         94 my @raw=;
215 2         13 close(DAT);
216              
217             # generic magic how to get version major/minor/patchlevel
218 2         38 my ($v_maj) = grep(/^#define[ \t]+[A-Z_]+?MAJOR[A-Z_]*[ \t]+[0-9]+/, @raw);
219 2         11 $v_maj =~ s/^#define[ \t]+[A-Z_]+[ \t]+([0-9]+)[.\r\n]*$/$1/;
220 2         28 my ($v_min) = grep(/^#define[ \t]+[A-Z_]+MINOR[A-Z_]*[ \t]+[0-9]+/, @raw);
221 2         6 $v_min =~ s/^#define[ \t]+[A-Z_]+[ \t]+([0-9]+)[.\r\n]*$/$1/;
222 2         39 my ($v_pat) = grep(/^#define[ \t]+[A-Z_]+(PATCHLEVEL|MICRO|RELEASE)[A-Z_]*[ \t]+[0-9]+/, @raw);
223 2         6 $v_pat =~ s/^#define[ \t]+[A-Z_]+[ \t]+([0-9]+)[.\r\n]*$/$1/;
224 2 50 33     16 return if (($v_maj eq '')||($v_min eq '')||($v_pat eq ''));
      33        
225 2         24 return "$v_maj.$v_min.$v_pat";
226             }
227              
228             ### check presence of header(s) specified as params
229             sub check_header {
230 2     2 1 1290 my ($package, @header) = @_;
231 2         25 print STDERR "[$package] Testing header(s): " . join(', ', @header);
232              
233 2         70221 require ExtUtils::CBuilder; # PAR packer workaround
234              
235 2         46105 my $config = {};
236 2 50       14 if($^O eq 'cygwin') {
237 0         0 my $ccflags = $Config{ccflags};
238 0         0 $ccflags =~ s/-fstack-protector//;
239 0         0 $config = { ld => 'gcc', cc => 'gcc', ccflags => $ccflags };
240             }
241              
242 2         16 my $cb = ExtUtils::CBuilder->new( quiet => 1, config => $config );
243 2         47976 my ($fs, $src) = File::Temp::tempfile('aaXXXX', SUFFIX => '.c', UNLINK => 1);
244 2         1184 my $inc = '';
245 2         4 my $i = 0;
246 2         6 foreach (@header) {
247 3 50       12 @header = (splice(@header, 0, $i) , 'stdio.h', splice(@header, $i)) if $_ eq 'jpeglib.h';
248 3         6 $i++;
249             }
250 2         9 $inc .= "#include <$_>\n" for @header;
251 2         163 syswrite($fs, <
252             #if defined(_WIN32) && !defined(__CYGWIN__)
253             /* GL/gl.h on Win32 requires windows.h being included before */
254             #include
255             #endif
256             $inc
257             int demofunc(void) { return 0; }
258              
259             MARKER
260 2         22 close($fs);
261 2         3 my $obj;
262 2         5 my $stdout = '';
263 2         4 my $stderr = '';
264             ($stdout, $stderr) = Capture::Tiny::capture {
265 2     2   1849 $obj = eval { $cb->compile( source => $src, extra_compiler_flags => Alien::SDL->config('cflags')); };
  2         17  
266 2         82 };
267              
268 2 50       148608 if($obj) {
269 2         61 print STDERR "\n";
270 2         146 unlink $obj;
271 2         39 return 1;
272             }
273             else {
274 0 0       0 if( $stderr ) {
275 0         0 $stderr =~ s/[\r\n]$//;
276 0         0 $stderr =~ s/^\Q$src\E[\d\s:]*//;
277 0         0 print STDERR " NOK: ($stderr)\n";
278             }
279             # on Windows (MSVC) stdout is set, but not stderr
280             else {
281 0         0 $stdout =~ s/[\r\n]$//;
282 0         0 $stdout =~ s/.+[\r\n]//;
283 0         0 $stdout =~ s/^\Q$src\E[\(\)\d\s:]*//;
284 0         0 print STDERR " NOK: ($stdout)\n";
285             }
286              
287 0         0 return 0;
288             }
289             }
290              
291             ### internal functions
292             sub _sdl_config_via_script
293             {
294 0     0   0 my $param = shift;
295 0         0 my @add_libs = @_;
296 0         0 my $devnull = File::Spec->devnull();
297 0         0 my $script = Alien::SDL::ConfigData->config('script');
298 0 0 0     0 return unless ($script && ($param =~ /[a-z0-9_]*/i));
299 0         0 my $val = `$script --$param 2>$devnull`;
300 0         0 $val =~ s/[\r\n]*$//;
301 0 0       0 if($param eq 'cflags') {
    0          
    0          
302 0         0 $val .= ' ' . Alien::SDL::ConfigData->config('additional_cflags');
303             }
304             elsif($param eq 'libs') {
305 0 0       0 $val .= ' ' . join(' ', @add_libs) if scalar @add_libs;
306 0         0 $val .= ' ' . Alien::SDL::ConfigData->config('additional_libs');
307             }
308             elsif($param =~ /^(ld_shlib_map|ld_shared_libs|ld_paths)$/) {
309 0         0 $val = Alien::SDL::ConfigData->config('config')->{$param};
310             }
311 0         0 return $val;
312             }
313              
314             sub _sdl_config_via_config_data
315             {
316 11     11   16 my $param = shift;
317 11         13 my @add_libs = @_;
318 11         41 my $share_dir = dist_dir('Alien-SDL');
319 11         906 my $subdir = Alien::SDL::ConfigData->config('share_subdir');
320 11 50       30 return unless $subdir;
321 11         60 my $real_prefix = catdir($share_dir, $subdir);
322 11 50       47 return unless ($param =~ /[a-z0-9_]*/i);
323 11         36 my $val = Alien::SDL::ConfigData->config('config')->{$param};
324 11 50       34 return unless $val;
325             # handle additional flags
326 11 100       44 if($param eq 'cflags') {
    50          
327 2         6 $val .= ' ' . Alien::SDL::ConfigData->config('additional_cflags');
328             }
329             elsif($param eq 'libs') {
330 0 0       0 $val .= ' ' . join(' ', @add_libs) if scalar @add_libs;
331 0         0 $val .= ' ' . Alien::SDL::ConfigData->config('additional_libs');
332             }
333             # handle @PrEfIx@ replacement
334 11 100       38 if ($param =~ /^(ld_shared_libs|ld_paths)$/) {
    100          
335 2         2 s/\@PrEfIx\@/$real_prefix/g foreach (@{$val});
  2         25  
336             }
337             elsif ($param =~ /^(ld_shlib_map)$/) {
338 1         5 while (my ($k, $v) = each %$val ) {
339 14         47 $val->{$k} =~ s/\@PrEfIx\@/$real_prefix/g;
340             }
341             }
342             else {
343 8         34 $val =~ s/\@PrEfIx\@/$real_prefix/g;
344             }
345 11         76 return $val;
346             }
347              
348             1;