File Coverage

/root/.cpan/build/Inline-0.54_02-wb8_n3/blib/lib/Inline/C.pm
Criterion Covered Total %
statement 279 509 54.8
branch 79 292 27.0
condition 22 83 26.5
subroutine 36 48 75.0
pod 0 39 0.0
total 416 971 42.8


line stmt bran cond sub pod time code
1             package Inline::C;
2             $Inline::C::VERSION = '0.54_02';
3             $Inline::C::VERSION = eval $Inline::C::VERSION;
4              
5 1     1   6 use strict;
  1         2  
  1         46  
6             require Inline;
7 1     1   6 use Config;
  1         2  
  1         49  
8 1     1   752 use Data::Dumper;
  1         7403  
  1         75  
9 1     1   9 use Carp;
  1         2  
  1         57  
10 1     1   6 use Cwd qw(cwd abs_path);
  1         2  
  1         43  
11 1     1   5 use File::Spec;
  1         2  
  1         6112  
12              
13             @Inline::C::ISA = qw(Inline);
14              
15             #==============================================================================
16             # Register this module as an Inline language support module
17             #==============================================================================
18             sub register {
19             return {
20             language => 'C',
21             # XXX Breaking this on purpose; let's see who screams
22             # aliases => ['c'],
23             type => 'compiled',
24             suffix => $Config{dlext},
25 0     0 0 0 };
26             }
27              
28             #==============================================================================
29             # Validate the C config options
30             #==============================================================================
31             sub usage_validate {
32 0     0 0 0 my $key = shift;
33 0         0 return <
34             The value of config option '$key' must be a string or an array ref
35              
36             END
37             }
38              
39             sub validate {
40 1     1 0 3 my $o = shift;
41              
42 1 50       12 print STDERR "validate Stage\n" if $o->{CONFIG}{BUILD_NOISY};
43 1   50     12 $o->{ILSM} ||= {};
44 1   50     7 $o->{ILSM}{XS} ||= {};
45 1   50     7 $o->{ILSM}{MAKEFILE} ||= {};
46 1 50       8 if (not $o->UNTAINT) {
47 0         0 require FindBin;
48 0 0       0 $o->{ILSM}{MAKEFILE}{INC} = "-I\"$FindBin::Bin\"" if not defined $o->{ILSM}{MAKEFILE}{INC};
49             }
50 1 50       6 $o->{ILSM}{AUTOWRAP} = 0 if not defined $o->{ILSM}{AUTOWRAP};
51 1 50       6 $o->{ILSM}{XSMODE} = 0 if not defined $o->{ILSM}{XSMODE};
52 1   50     6 $o->{ILSM}{AUTO_INCLUDE} ||= <
53             #include "EXTERN.h"
54             #include "perl.h"
55             #include "XSUB.h"
56             #include "INLINE.h"
57             END
58 1   50     6 $o->{ILSM}{FILTERS} ||= [];
59             $o->{STRUCT} ||= {
60 1   50     10 '.macros' => '',
61             '.xs' => '',
62             '.any' => 0,
63             '.all' => 0,
64             };
65              
66 1         7 while (@_) {
67 0         0 my ($key, $value) = (shift, shift);
68 0 0       0 if ($key eq 'PRE_HEAD') {
69 0 0       0 unless( -f $value) {
70 0         0 $o->{ILSM}{AUTO_INCLUDE} = $value . "\n" . $o->{ILSM}{AUTO_INCLUDE};
71             }
72             else {
73 0         0 my $insert;
74 0 0       0 open RD, '<', $value or die "Couldn't open $value for reading: $!";
75 0         0 while() {$insert .= $_}
  0         0  
76 0 0       0 close RD or die "Couldn't close $value after reading: $!";
77 0         0 $o->{ILSM}{AUTO_INCLUDE} = $insert . "\n" . $o->{ILSM}{AUTO_INCLUDE};
78             }
79 0         0 next;
80             }
81 0 0 0     0 if ($key eq 'MAKE' or
      0        
82             $key eq 'AUTOWRAP' or
83             $key eq 'XSMODE'
84             ) {
85 0         0 $o->{ILSM}{$key} = $value;
86 0         0 next;
87             }
88 0 0 0     0 if ($key eq 'CC' or
89             $key eq 'LD') {
90 0         0 $o->{ILSM}{MAKEFILE}{$key} = $value;
91 0         0 next;
92             }
93 0 0       0 if ($key eq 'LIBS') {
94 0         0 $o->add_list($o->{ILSM}{MAKEFILE}, $key, $value, []);
95 0         0 next;
96             }
97 0 0       0 if ($key eq 'INC') {
98 0         0 $o->add_string($o->{ILSM}{MAKEFILE}, $key, quote_space($value), '');
99 0         0 next;
100             }
101 0 0 0     0 if ($key eq 'MYEXTLIB' or
      0        
      0        
102             $key eq 'OPTIMIZE' or
103             $key eq 'CCFLAGS' or
104             $key eq 'LDDLFLAGS') {
105 0         0 $o->add_string($o->{ILSM}{MAKEFILE}, $key, $value, '');
106 0         0 next;
107             }
108 0 0       0 if ($key eq 'CCFLAGSEX') {
109 0         0 $o->add_string($o->{ILSM}{MAKEFILE}, 'CCFLAGS', $Config{ccflags} . ' ' . $value, '');
110 0         0 next;
111             }
112 0 0       0 if ($key eq 'TYPEMAPS') {
113 0 0       0 unless(ref($value) eq 'ARRAY') {
114 0 0       0 croak "TYPEMAPS file '$value' not found"
115             unless -f $value;
116 0         0 $value = File::Spec->rel2abs($value);
117             }
118             else {
119 0         0 for (my $i = 0; $i < scalar(@$value); $i++) {
120 0         0 croak "TYPEMAPS file '${$value}[$i]' not found"
121 0 0       0 unless -f ${$value}[$i];
  0         0  
122 0         0 ${$value}[$i] = File::Spec->rel2abs(${$value}[$i]);
  0         0  
  0         0  
123             }
124             }
125 0         0 $o->add_list($o->{ILSM}{MAKEFILE}, $key, $value, []);
126 0         0 next;
127             }
128 0 0       0 if ($key eq 'AUTO_INCLUDE') {
129 0         0 $o->add_text($o->{ILSM}, $key, $value, '');
130 0         0 next;
131             }
132 0 0       0 if ($key eq 'BOOT') {
133 0         0 $o->add_text($o->{ILSM}{XS}, $key, $value, '');
134 0         0 next;
135             }
136 0 0       0 if ($key eq 'PREFIX') {
137 0 0 0     0 croak "Invalid value for 'PREFIX' option"
138             unless ($value =~ /^\w*$/ and
139             $value !~ /\n/);
140 0         0 $o->{ILSM}{XS}{PREFIX} = $value;
141 0         0 next;
142             }
143 0 0       0 if ($key eq 'FILTERS') {
144 0 0 0     0 next if $value eq '1' or $value eq '0'; # ignore ENABLE, DISABLE
145 0 0       0 $value = [$value] unless ref($value) eq 'ARRAY';
146 0         0 my %filters;
147 0         0 for my $val (@$value) {
148 0 0       0 if (ref($val) eq 'CODE') {
149 0         0 $o->add_list($o->{ILSM}, $key, $val, []);
150             }
151             else {
152 0         0 eval { require Inline::Filters };
  0         0  
153 0 0       0 croak "'FILTERS' option requires Inline::Filters to be installed."
154             if $@;
155             %filters = Inline::Filters::get_filters($o->{API}{language})
156 0 0       0 unless keys %filters;
157 0 0       0 if (defined $filters{$val}) {
158             my $filter = Inline::Filters->new($val,
159 0         0 $filters{$val});
160 0         0 $o->add_list($o->{ILSM}, $key, $filter, []);
161             }
162             else {
163 0         0 croak "Invalid filter $val specified.";
164             }
165             }
166             }
167 0         0 next;
168             }
169 0 0       0 if ($key eq 'STRUCTS') {
170             # A list of struct names
171 0 0       0 if (ref($value) eq 'ARRAY') {
    0          
172 0         0 for my $val (@$value) {
173 0 0       0 croak "Invalid value for 'STRUCTS' option"
174             unless ($val =~ /^[_a-z][_0-9a-z]*$/i);
175 0         0 $o->{STRUCT}{$val}++;
176             }
177             }
178             # Enable or disable
179             elsif ($value =~ /^\d+$/) {
180 0         0 $o->{STRUCT}{'.any'} = $value;
181             }
182             # A single struct name
183             else {
184 0 0       0 croak "Invalid value for 'STRUCTS' option"
185             unless ($value =~ /^[_a-z][_0-9a-z]*$/i);
186 0         0 $o->{STRUCT}{$value}++;
187             }
188 0         0 eval { require Inline::Struct };
  0         0  
189 0 0       0 croak "'STRUCTS' option requires Inline::Struct to be installed."
190             if $@;
191 0         0 $o->{STRUCT}{'.any'} = 1;
192 0         0 next;
193             }
194 0 0       0 if($key eq 'PROTOTYPES') {
195 0         0 $o->{CONFIG}{PROTOTYPES} = $value;
196 0 0       0 next if $value eq 'ENABLE';
197 0 0       0 next if $value eq 'DISABLE';
198 0         0 die "PROTOTYPES can be only either 'ENABLE' or 'DISABLE' - not $value";
199             }
200 0 0       0 if($key eq 'PROTOTYPE') {
201 0 0       0 die "PROTOTYPE configure arg must specify a hash reference"
202             unless ref($value) eq 'HASH';
203 0         0 $o->{CONFIG}{PROTOTYPE} = $value;
204 0         0 next;
205             }
206 0         0 my $class = ref $o; # handles subclasses correctly.
207 0         0 croak "'$key' is not a valid config option for $class\n";
208             }
209             }
210              
211             sub add_list {
212 0     0 0 0 my $o = shift;
213 0         0 my ($ref, $key, $value, $default) = @_;
214 0 0       0 $value = [$value] unless ref $value eq 'ARRAY';
215 0         0 for (@$value) {
216 0 0       0 if (defined $_) {
217 0         0 push @{$ref->{$key}}, $_;
  0         0  
218             }
219             else {
220 0         0 $ref->{$key} = $default;
221             }
222             }
223             }
224              
225             sub add_string {
226 0     0 0 0 my $o = shift;
227 0         0 my ($ref, $key, $value, $default) = @_;
228 0 0       0 $value = [$value] unless ref $value;
229 0 0       0 croak usage_validate($key) unless ref($value) eq 'ARRAY';
230 0         0 for (@$value) {
231 0 0       0 if (defined $_) {
232 0         0 $ref->{$key} .= ' ' . $_;
233             }
234             else {
235 0         0 $ref->{$key} = $default;
236             }
237             }
238             }
239              
240             sub add_text {
241 0     0 0 0 my $o = shift;
242 0         0 my ($ref, $key, $value, $default) = @_;
243 0 0       0 $value = [$value] unless ref $value;
244 0 0       0 croak usage_validate($key) unless ref($value) eq 'ARRAY';
245 0         0 for (@$value) {
246 0 0       0 if (defined $_) {
247 0         0 chomp;
248 0         0 $ref->{$key} .= $_ . "\n";
249             }
250             else {
251 0         0 $ref->{$key} = $default;
252             }
253             }
254             }
255              
256             #==============================================================================
257             # Return a small report about the C code..
258             #==============================================================================
259             sub info {
260 0     0 0 0 my $o = shift;
261 0 0       0 return <{ILSM}{XSMODE};
262             No information is currently generated when using XSMODE.
263              
264             END
265 0         0 my $text = '';
266 0         0 $o->preprocess;
267 0         0 $o->parse;
268 0 0       0 if (defined $o->{ILSM}{parser}{data}{functions}) {
269 0         0 $text .= "The following Inline $o->{API}{language} function(s) have been successfully bound to Perl:\n";
270 0         0 my $parser = $o->{ILSM}{parser};
271 0         0 my $data = $parser->{data};
272 0         0 for my $function (sort @{$data->{functions}}) {
  0         0  
273 0         0 my $return_type = $data->{function}{$function}{return_type};
274 0         0 my @arg_names = @{$data->{function}{$function}{arg_names}};
  0         0  
275 0         0 my @arg_types = @{$data->{function}{$function}{arg_types}};
  0         0  
276 0         0 my @args = map {$_ . ' ' . shift @arg_names} @arg_types;
  0         0  
277 0         0 $text .= "\t$return_type $function(" . join(', ', @args) . ")\n";
278             }
279             }
280             else {
281 0         0 $text .= "No $o->{API}{language} functions have been successfully bound to Perl.\n\n";
282             }
283 0 0       0 $text .= Inline::Struct::info($o) if $o->{STRUCT}{'.any'};
284 0         0 return $text;
285             }
286              
287             sub config {
288 0     0 0 0 my $o = shift;
289             }
290              
291             #==============================================================================
292             # Parse and compile C code
293             #==============================================================================
294             my $total_build_time;
295             sub build {
296 1     1 0 2 my $o = shift;
297              
298 1 50       4 if ($o->{CONFIG}{BUILD_TIMERS}) {
299 0         0 eval {require Time::HiRes};
  0         0  
300 0 0       0 croak "You need Time::HiRes for BUILD_TIMERS option:\n$@" if $@;
301 0         0 $total_build_time = Time::HiRes::time();
302             }
303 1         5 $o->call('preprocess', 'Build Preprocess');
304 1         4 $o->call('parse', 'Build Parse');
305 1         5 $o->call('write_XS', 'Build Glue 1');
306 1         3 $o->call('write_Inline_headers', 'Build Glue 2');
307 1         4 $o->call('write_Makefile_PL', 'Build Glue 3');
308 1         3 $o->call('compile', 'Build Compile');
309 0 0       0 if ($o->{CONFIG}{BUILD_TIMERS}) {
310 0         0 $total_build_time = Time::HiRes::time() - $total_build_time;
311 0         0 printf STDERR "Total Build Time: %5.4f secs\n", $total_build_time;
312             }
313             }
314              
315             sub call {
316 8     8 0 25 my ($o, $method, $header, $indent) = (@_, 0);
317 8         11 my $time;
318 8         23 my $i = ' ' x $indent;
319 8 50       22 print STDERR "${i}Starting $header Stage\n" if $o->{CONFIG}{BUILD_NOISY};
320             $time = Time::HiRes::time()
321 8 50       21 if $o->{CONFIG}{BUILD_TIMERS};
322              
323 8         36 $o->$method();
324              
325             $time = Time::HiRes::time() - $time
326 6 50       19154 if $o->{CONFIG}{BUILD_TIMERS};
327 6 50       20 print STDERR "${i}Finished $header Stage\n" if $o->{CONFIG}{BUILD_NOISY};
328             printf STDERR "${i}Time for $header Stage: %5.4f secs\n", $time
329 6 50       17 if $o->{CONFIG}{BUILD_TIMERS};
330 6 50       32 print STDERR "\n" if $o->{CONFIG}{BUILD_NOISY};
331             }
332              
333             #==============================================================================
334             # Apply any
335             #==============================================================================
336             sub preprocess {
337 1     1 0 2 my $o = shift;
338 1 50       4 return if $o->{ILSM}{parser};
339 1         5 $o->get_maps;
340 1         3 $o->get_types;
341 1         2 $o->{ILSM}{code} = $o->filter(@{$o->{ILSM}{FILTERS}});
  1         17  
342             }
343              
344             #==============================================================================
345             # Parse the function definition information out of the C code
346             #==============================================================================
347             sub parse {
348 1     1 0 1 my $o = shift;
349 1 50       4 return if $o->{ILSM}{parser};
350 1 50       4 return if $o->{ILSM}{XSMODE};
351 1         3 my $parser = $o->{ILSM}{parser} = $o->get_parser;
352 1         75096 $parser->{data}{typeconv} = $o->{ILSM}{typeconv};
353 1         4 $parser->{data}{AUTOWRAP} = $o->{ILSM}{AUTOWRAP};
354 1 50       7 Inline::Struct::parse($o) if $o->{STRUCT}{'.any'};
355             $parser->code($o->{ILSM}{code})
356 1 50       13 or croak <
357 0         0 Bad $o->{API}{language} code passed to Inline at @{[caller(2)]}
358             END
359             }
360              
361             # Create and initialize a parser
362             sub get_parser {
363 1     1 0 2 my $o = shift;
364 1 50       4 Inline::C::_parser_test("Inline::C::get_parser called\n") if $o->{CONFIG}{_TESTING};
365 1         472 require Inline::C::ParseRecDescent;
366 1         4 Inline::C::ParseRecDescent::get_parser($o);
367             }
368              
369             #==============================================================================
370             # Gather the path names of all applicable typemap files.
371             #==============================================================================
372             sub get_maps {
373 1     1 0 1 my $o = shift;
374              
375 1 50       5 print STDERR "get_maps Stage\n" if $o->{CONFIG}{BUILD_NOISY};
376 1         3 my $typemap = '';
377 1         3 my $file;
378 1         88 $file = File::Spec->catfile($Config::Config{installprivlib},"ExtUtils","typemap");
379 1 50       48 $typemap = $file if -f $file;
380 1         15 $file = File::Spec->catfile($Config::Config{privlibexp} ,"ExtUtils","typemap");
381 1 50 33     8 $typemap = $file
382             if (not $typemap and -f $file);
383 1 0 33     4 warn "Can't find the default system typemap file"
384             if (not $typemap and $^W);
385              
386 1 50       4 unshift(@{$o->{ILSM}{MAKEFILE}{TYPEMAPS}}, $typemap) if $typemap;
  1         4  
387              
388 1 50       5 if (not $o->UNTAINT) {
389 0         0 require FindBin;
390 0         0 $file = File::Spec->catfile($FindBin::Bin,"typemap");
391 0 0       0 if ( -f $file ) {
392 0         0 push(@{$o->{ILSM}{MAKEFILE}{TYPEMAPS}}, $file);
  0         0  
393             }
394             }
395             }
396              
397             #==============================================================================
398             # This routine parses XS typemap files to get a list of valid types to create
399             # bindings to. This code is mostly hacked out of Larry Wall's xsubpp program.
400             #==============================================================================
401             sub get_types {
402 1     1 0 2 my (%type_kind, %proto_letter, %input_expr, %output_expr);
403 1         2 my $o = shift;
404 1         2 local $_;
405             croak "No typemaps specified for Inline C code"
406 1 50       2 unless @{$o->{ILSM}{MAKEFILE}{TYPEMAPS}};
  1         4  
407              
408 1         3 my $proto_re = "[" . quotemeta('\$%&*@;') . "]";
409 1         1 foreach my $typemap (@{$o->{ILSM}{MAKEFILE}{TYPEMAPS}}) {
  1         4  
410 1 50       23 next unless -e $typemap;
411             # skip directories, binary files etc.
412 1 50       50 warn("Warning: ignoring non-text typemap file '$typemap'\n"), next
413             unless -T $typemap;
414 1 50       30 open(TYPEMAP, $typemap)
415             or warn ("Warning: could not open typemap file '$typemap': $!\n"), next;
416 1         3 my $mode = 'Typemap';
417 1         2 my $junk = "";
418 1         2 my $current = \$junk;
419 1         13 while () {
420 447 100       1060 next if /^\s*\#/;
421 438         580 my $line_no = $. + 1;
422 438 100       746 if (/^INPUT\s*$/) {$mode = 'Input'; $current = \$junk; next}
  1         2  
  1         4  
  1         10  
423 437 100       714 if (/^OUTPUT\s*$/) {$mode = 'Output'; $current = \$junk; next}
  1         3  
  1         2  
  1         6  
424 436 50       702 if (/^TYPEMAP\s*$/) {$mode = 'Typemap'; $current = \$junk; next}
  0         0  
  0         0  
  0         0  
425 436 100       1210 if ($mode eq 'Typemap') {
    100          
    100          
426 54         71 chomp;
427 54         102 my $line = $_;
428 54         87 TrimWhitespace($_);
429             # skip blank lines and comment lines
430 54 100 66     264 next if /^$/ or /^\#/;
431 51 50       454 my ($type,$kind, $proto) =
432             /^\s*(.*?\S)\s+(\S+)\s*($proto_re*)\s*$/ or
433             warn("Warning: File '$typemap' Line $. '$line' TYPEMAP entry needs 2 or 3 columns\n"), next;
434 51         89 $type = TidyType($type);
435 51         96 $type_kind{$type} = $kind;
436             # prototype defaults to '$'
437 51 50       98 $proto = "\$" unless $proto;
438 51 50       65 warn("Warning: File '$typemap' Line $. '$line' Invalid prototype '$proto'\n")
439             unless ValidProtoString($proto);
440 51         75 $proto_letter{$type} = C_string($proto);
441             }
442             elsif (/^\s/) {
443 296         1225 $$current .= $_;
444             }
445             elsif ($mode eq 'Input') {
446 43         161 s/\s+$//;
447 43         108 $input_expr{$_} = '';
448 43         186 $current = \$input_expr{$_};
449             }
450             else {
451 43         149 s/\s+$//;
452 43         94 $output_expr{$_} = '';
453 43         200 $current = \$output_expr{$_};
454             }
455             }
456 1         12 close(TYPEMAP);
457             }
458              
459             my %valid_types =
460 51         55 map {($_, 1)}
461 1         15 grep {defined $input_expr{$type_kind{$_}}}
  51         61  
462             keys %type_kind;
463              
464             my %valid_rtypes =
465 52         46 map {($_, 1)}
466 1         9 (grep {defined $output_expr{$type_kind{$_}}}
  51         50  
467             keys %type_kind), 'void';
468              
469 1         6 $o->{ILSM}{typeconv}{type_kind} = \%type_kind;
470 1         3 $o->{ILSM}{typeconv}{input_expr} = \%input_expr;
471 1         1 $o->{ILSM}{typeconv}{output_expr} = \%output_expr;
472 1         3 $o->{ILSM}{typeconv}{valid_types} = \%valid_types;
473 1         8 $o->{ILSM}{typeconv}{valid_rtypes} = \%valid_rtypes;
474             }
475              
476             sub ValidProtoString ($) {
477 51     51 0 60 my $string = shift;
478 51         48 my $proto_re = "[" . quotemeta('\$%&*@;') . "]";
479 51 50       323 return ($string =~ /^$proto_re+$/) ? $string : 0;
480             }
481              
482             sub TrimWhitespace {
483 105     105 0 401 $_[0] =~ s/^\s+|\s+$//go;
484             }
485              
486             sub TidyType {
487 51     51 0 70 local $_ = shift;
488 51         102 s|\s*(\*+)\s*|$1|g;
489 51         102 s|(\*+)| $1 |g;
490 51         98 s|\s+| |g;
491 51         72 TrimWhitespace($_);
492 51         92 $_;
493             }
494              
495             sub C_string ($) {
496 51     51 0 68 (my $string = shift) =~ s|\\|\\\\|g;
497 51         314 $string;
498             }
499              
500             #==============================================================================
501             # Write the XS code
502             #==============================================================================
503             sub write_XS {
504 1     1 0 1 my $o = shift;
505 1         4 my $modfname = $o->{API}{modfname};
506 1         2 my $module = $o->{API}{module};
507 1         18 $o->mkpath($o->{API}{build_dir});
508 1 50       166 open XS, "> ".File::Spec->catfile($o->{API}{build_dir},"$modfname.xs")
509             or croak $!;
510 1 50       6 if ($o->{ILSM}{XSMODE}) {
511 0 0 0     0 warn <{ILSM}{code} !~ /MODULE\s*=\s*$module\b/;
512             While using Inline XSMODE, your XS code does not have a line with
513              
514             MODULE = $module
515              
516             You should use the Inline NAME config option, and it should match the
517             XS MODULE name.
518              
519             END
520 0         0 print XS $o->xs_code;
521             }
522             else {
523 1         4 print XS $o->xs_generate;
524             }
525 1         36 close XS;
526             }
527              
528             #==============================================================================
529             # Generate the XS glue code (piece together lots of snippets)
530             #==============================================================================
531             sub xs_generate {
532 1     1 0 2 my $o = shift;
533 1         4 return join '', ($o->xs_includes,
534             $o->xs_struct_macros,
535             $o->xs_code,
536             $o->xs_struct_code,
537             $o->xs_bindings,
538             $o->xs_boot,
539             );
540             }
541              
542             sub xs_includes {
543 1     1 0 1 my $o = shift;
544 1         6 return $o->{ILSM}{AUTO_INCLUDE};
545             }
546              
547             sub xs_struct_macros {
548 1     1 0 1 my $o = shift;
549 1         5 return $o->{STRUCT}{'.macros'};
550             }
551              
552             sub xs_code {
553 1     1 0 2 my $o = shift;
554 1         4 return $o->{ILSM}{code};
555             }
556              
557             sub xs_struct_code {
558 1     1 0 2 my $o = shift;
559 1         4 return $o->{STRUCT}{'.xs'};
560             }
561              
562             sub xs_boot {
563 1     1 0 1 my $o = shift;
564 1 0 33     3 if (defined $o->{ILSM}{XS}{BOOT} and
565             $o->{ILSM}{XS}{BOOT}) {
566 0         0 return <
567             BOOT:
568             $o->{ILSM}{XS}{BOOT}
569             END
570             }
571 1         15 return '';
572             }
573              
574             sub xs_bindings {
575 1     1 0 2 my $o = shift;
576 1         3 my $dir = '_Inline_test';
577              
578 1 50       4 if($o->{CONFIG}{_TESTING}) {
579 0 0       0 if(! -d $dir) {
580 0         0 my $ok = mkdir $dir;
581 0 0       0 warn $! if !$ok;
582             }
583              
584 0 0       0 if(! -f "$dir/void_test") {
585 0 0       0 warn $! if !open(TEST_FH, '>', "$dir/void_test");
586 0 0       0 warn $! if !close(TEST_FH);
587             }
588             }
589              
590 1         4 my ($pkg, $module) = @{$o->{API}}{qw(pkg module)};
  1         4  
591 1 50       4 my $prefix = (($o->{ILSM}{XS}{PREFIX}) ?
592             "PREFIX = $o->{ILSM}{XS}{PREFIX}" :
593             '');
594              
595             my $prototypes = defined($o->{CONFIG}{PROTOTYPES}) ? $o->{CONFIG}{PROTOTYPES}
596 1 50       5 : 'DISABLE';
597              
598 1         6 my $XS = <
599              
600             MODULE = $module PACKAGE = $pkg $prefix
601              
602             PROTOTYPES: $prototypes
603              
604             END
605              
606 1         3 my $parser = $o->{ILSM}{parser};
607 1         2 my $data = $parser->{data};
608              
609             warn("Warning. No Inline C functions bound to Perl in ", $o->{API}{script}, "\n" .
610             "Check your C function definition(s) for Inline compatibility\n\n")
611 1 0 33     4 if ((not defined$data->{functions}) and ($^W));
612              
613 1         2 for my $function (@{$data->{functions}}) {
  1         3  
614 1         3 my $return_type = $data->{function}->{$function}->{return_type};
615 1         3 my @arg_names = @{$data->{function}->{$function}->{arg_names}};
  1         3  
616 1         3 my @arg_types = @{$data->{function}->{$function}->{arg_types}};
  1         4  
617              
618 1         5 $XS .= join '', ("\n$return_type\n$function (",
619             join(', ', @arg_names), ")\n");
620              
621 1         3 for my $arg_name (@arg_names) {
622 2         4 my $arg_type = shift @arg_types;
623 2 50       8 last if $arg_type eq '...';
624 2         5 $XS .= "\t$arg_type\t$arg_name\n";
625             }
626              
627 1         2 my %h;
628 1 50       5 if (defined($o->{CONFIG}{PROTOTYPE})) {
629 0         0 %h = %{$o->{CONFIG}{PROTOTYPE}};
  0         0  
630             }
631              
632 1 50       4 if(defined($h{$function})) {
633 0         0 $XS .= " PROTOTYPE: $h{$function}\n";
634             }
635              
636 1         2 my $listargs = '';
637 1 50 33     7 $listargs = pop @arg_names if (@arg_names and
638             $arg_names[-1] eq '...');
639 1         3 my $arg_name_list = join(', ', @arg_names);
640              
641 1 50       9 if ($return_type eq 'void') {
    50          
642 0 0       0 if($o->{CONFIG}{_TESTING}) {
643 0         0 $XS .= <
644             PREINIT:
645             PerlIO* stream;
646             I32* temp;
647             PPCODE:
648             temp = PL_markstack_ptr++;
649             $function($arg_name_list);
650             stream = PerlIO_open(\"$dir/void_test\", \"a\");
651             if(stream == NULL) warn(\"%s\\n\", \"Unable to open $dir/void_test for appending\");
652             if (PL_markstack_ptr != temp) {
653             PerlIO_printf(stream, \"%s\\n\", \"TRULY_VOID\");
654             PerlIO_close(stream);
655             PL_markstack_ptr = temp;
656             XSRETURN_EMPTY; /* return empty stack */
657             }
658             PerlIO_printf(stream, \"%s\\n\", \"LIST_CONTEXT\");
659             PerlIO_close(stream);
660             return; /* assume stack size is correct */
661             END
662             }
663             else {
664 0         0 $XS .= <
665             PREINIT:
666             I32* temp;
667             PPCODE:
668             temp = PL_markstack_ptr++;
669             $function($arg_name_list);
670             if (PL_markstack_ptr != temp) {
671             /* truly void, because dXSARGS not invoked */
672             PL_markstack_ptr = temp;
673             XSRETURN_EMPTY; /* return empty stack */
674             }
675             /* must have used dXSARGS; list context implied */
676             return; /* assume stack size is correct */
677             END
678             }
679             }
680             elsif ($listargs) {
681 0         0 $XS .= <
682             PREINIT:
683             I32* temp;
684             CODE:
685             temp = PL_markstack_ptr++;
686             RETVAL = $function($arg_name_list);
687             PL_markstack_ptr = temp;
688             OUTPUT:
689             RETVAL
690             END
691             }
692             }
693 1         2 $XS .= "\n";
694 1         5 return $XS;
695             }
696              
697             #==============================================================================
698             # Generate the INLINE.h file.
699             #==============================================================================
700             sub write_Inline_headers {
701 1     1 0 2 my $o = shift;
702              
703 1 50       69 open HEADER, "> ".File::Spec->catfile($o->{API}{build_dir},"INLINE.h")
704             or croak;
705              
706 1         7 print HEADER <<'END';
707             #define Inline_Stack_Vars dXSARGS
708             #define Inline_Stack_Items items
709             #define Inline_Stack_Item(x) ST(x)
710             #define Inline_Stack_Reset sp = mark
711             #define Inline_Stack_Push(x) XPUSHs(x)
712             #define Inline_Stack_Done PUTBACK
713             #define Inline_Stack_Return(x) XSRETURN(x)
714             #define Inline_Stack_Void XSRETURN(0)
715              
716             #define INLINE_STACK_VARS Inline_Stack_Vars
717             #define INLINE_STACK_ITEMS Inline_Stack_Items
718             #define INLINE_STACK_ITEM(x) Inline_Stack_Item(x)
719             #define INLINE_STACK_RESET Inline_Stack_Reset
720             #define INLINE_STACK_PUSH(x) Inline_Stack_Push(x)
721             #define INLINE_STACK_DONE Inline_Stack_Done
722             #define INLINE_STACK_RETURN(x) Inline_Stack_Return(x)
723             #define INLINE_STACK_VOID Inline_Stack_Void
724              
725             #define inline_stack_vars Inline_Stack_Vars
726             #define inline_stack_items Inline_Stack_Items
727             #define inline_stack_item(x) Inline_Stack_Item(x)
728             #define inline_stack_reset Inline_Stack_Reset
729             #define inline_stack_push(x) Inline_Stack_Push(x)
730             #define inline_stack_done Inline_Stack_Done
731             #define inline_stack_return(x) Inline_Stack_Return(x)
732             #define inline_stack_void Inline_Stack_Void
733             END
734              
735 1         33 close HEADER;
736             }
737              
738             #==============================================================================
739             # Generate the Makefile.PL
740             #==============================================================================
741             sub write_Makefile_PL {
742 1     1 0 1 my $o = shift;
743 1         3 $o->{ILSM}{xsubppargs} = '';
744 1         1 my $i = 0;
745 1         2 for (@{$o->{ILSM}{MAKEFILE}{TYPEMAPS}}) {
  1         5  
746 1         5 $o->{ILSM}{xsubppargs} .= "-typemap \"$_\" ";
747 1         4 $o->{ILSM}{MAKEFILE}{TYPEMAPS}->[$i++] = fix_space($_);
748             }
749              
750             my %options = (
751             VERSION => $o->{API}{version} || '0.00',
752 1         6 %{$o->{ILSM}{MAKEFILE}},
753             NAME => $o->{API}{module},
754 1   50     8 );
755              
756 1 50       64 open MF, "> ".File::Spec->catfile($o->{API}{build_dir},"Makefile.PL")
757             or croak;
758              
759 1         4 print MF <
760             use ExtUtils::MakeMaker;
761             my %options = %\{
762             END
763              
764 1         3 local $Data::Dumper::Terse = 1;
765 1         2 local $Data::Dumper::Indent = 1;
766 1         6 print MF Data::Dumper::Dumper(\ %options);
767              
768 1         116 print MF <
769             \};
770             WriteMakefile(\%options);
771              
772             # Remove the Makefile dependency. Causes problems on a few systems.
773             sub MY::makefile { '' }
774             END
775 1         29 close MF;
776             }
777              
778             #==============================================================================
779             # Run the build process.
780             #==============================================================================
781             sub compile {
782 1     1 0 2 my $o = shift;
783              
784 1         2 my $build_dir = $o->{API}{build_dir};
785 1         2576 my $cwd = &cwd;
786 1 50       21 ($cwd) = $cwd =~ /(.*)/ if $o->UNTAINT;
787              
788 1         24 chdir $build_dir;
789             # Run these in an eval block, so that we get to chdir back to
790             # $cwd if there's a failure. (Ticket #81375.)
791 1         3 eval {
792 1         11 $o->call('makefile_pl', '"perl Makefile.PL"', 2);
793 1         8 $o->call('make', '"make"', 2);
794 0         0 $o->call('make_install', '"make install"', 2);
795             };
796 1         1521 chdir $cwd;
797 1 50       57 die if $@; #Die now that we've done the chdir back to $cwd. (#81375)
798 0         0 $o->call('cleanup', 'Cleaning Up', 2);
799             }
800              
801             sub makefile_pl {
802 1     1 0 3 my ($o) = @_;
803 1         3 my $perl;
804             -f ($perl = $Config::Config{perlpath})
805 1 50 33     126 or ($perl = $^X)
806             or croak "Can't locate your perl binary";
807 1 50       7 $perl = qq{"$perl"} if $perl =~ m/\s/;
808 1         9 $o->system_call("$perl Makefile.PL", 'out.Makefile_PL');
809 1         17 $o->fix_make;
810             }
811             sub make {
812 1     1 0 4 my ($o) = @_;
813             my $make = $o->{ILSM}{MAKE} || $Config::Config{make}
814 1 50 33     115 or croak "Can't locate your make binary";
815 1         15 local $ENV{MAKEFLAGS} = $ENV{MAKEFLAGS} =~ s/(--jobserver-fds=[\d,]+)//;
816 1         8 $o->system_call("$make", 'out.make');
817             }
818             sub make_install {
819 0     0 0 0 my ($o) = @_;
820             my $make = $o->{ILSM}{MAKE} || $Config::Config{make}
821 0 0 0     0 or croak "Can't locate your make binary";
822 0         0 local $ENV{MAKEFLAGS} = $ENV{MAKEFLAGS} =~ s/(--jobserver-fds=[\d,]+)//;
823 0         0 $o->system_call("$make pure_install", 'out.make_install');
824             }
825             sub cleanup {
826 0     0 0 0 my ($o) = @_;
827             my ($modpname, $modfname, $install_lib) =
828 0         0 @{$o->{API}}{qw(modpname modfname install_lib)};
  0         0  
829 0 0       0 if ($o->{API}{cleanup}) {
830 0         0 $o->rmpath(File::Spec->catdir($o->{API}{directory},'build'),
831             $modpname);
832 0         0 my $autodir = File::Spec->catdir($install_lib,'auto',$modpname);
833 0         0 unlink (File::Spec->catfile($autodir,'.packlist'),
834             File::Spec->catfile($autodir,'$modfname.bs'),
835             File::Spec->catfile($autodir,'$modfname.exp'), #MSWin32
836             File::Spec->catfile($autodir,'$modfname.lib'), #MSWin32
837             );
838             }
839             }
840              
841             sub system_call {
842 2     2 0 8 my ($o, $cmd, $output_file) = @_;
843             my $build_noisy =
844             defined $ENV{PERL_INLINE_BUILD_NOISY}
845             ? $ENV{PERL_INLINE_BUILD_NOISY}
846 2 50       10 : $o->{CONFIG}{BUILD_NOISY};
847 2 0 33     10 $build_noisy = undef if $build_noisy and $^O eq 'MSWin32' and $Config::Config{sh} =~ /^cmd/;
      33        
848 2 50       11 if (not $build_noisy) {
849 2         10 $cmd = "$cmd > $output_file 2>&1";
850             }
851 2 50       20 ($cmd) = $cmd =~ /(.*)/ if $o->UNTAINT;
852 2 100       207003 system($cmd) == 0
853             or croak($o->build_error_message($cmd, $output_file, $build_noisy));
854             }
855              
856             sub build_error_message {
857 1     1 0 15 my ($o, $cmd, $output_file, $build_noisy) = @_;
858 1         7 my $build_dir = $o->{API}{build_dir};
859 1         6 my $output = '';
860 1 50 33     58 if (not $build_noisy and
861             open(OUTPUT, $output_file)
862             ) {
863 1         16 local $/;
864 1         271 $output = ;
865 1         13 close OUTPUT;
866             }
867              
868 1         9 my $errcode = $? >> 8;
869 1         37 $output .= <
870              
871             A problem was encountered while attempting to compile and install your Inline
872             $o->{API}{language} code. The command that failed was:
873             \"$cmd\" with error code $errcode
874              
875             The build directory was:
876             $build_dir
877              
878             To debug the problem, cd to the build directory, and inspect the output files.
879              
880             END
881 1 50       16 if ($cmd =~ /^make >/) {
882 1         33 for (sort keys %ENV) {
883 28 100       72 $output .= "$_ = $ENV{$_}\n" if /^MAKE/;
884             }
885             }
886 1         59 return $output;
887             }
888              
889             #==============================================================================
890             # This routine fixes problems with the MakeMaker Makefile.
891             #==============================================================================
892             my %fixes = (
893             INSTALLSITEARCH => 'install_lib',
894             INSTALLDIRS => 'installdirs',
895             XSUBPPARGS => 'xsubppargs',
896             INSTALLSITELIB => 'install_lib',
897             );
898              
899             sub fix_make {
900 1     1   13 use strict;
  1         3  
  1         940  
901 1     1 0 3 my (@lines, $fix);
902 1         4 my $o = shift;
903              
904 1         12 $o->{ILSM}{install_lib} = $o->{API}{install_lib};
905 1         6 $o->{ILSM}{installdirs} = 'site';
906              
907 1 50       39 open(MAKEFILE, '< Makefile')
908             or croak "Can't open Makefile for input: $!\n";
909 1         1000 @lines = ;
910 1         79 close MAKEFILE;
911              
912 1 50       75 open(MAKEFILE, '> Makefile')
913             or croak "Can't open Makefile for output: $!\n";
914 1         5 for (@lines) {
915 1034 100 100     2774 if (/^(\w+)\s*=\s*\S+.*$/ and
916             $fix = $fixes{$1}
917             ) {
918 4         7 my $fixed = $o->{ILSM}{$fix};
919 4 100       44 $fixed = fix_space($fixed) if $fix eq 'install_lib';
920 4         13 print MAKEFILE "$1 = $fixed\n";
921             }
922             else {
923 1030         1635 print MAKEFILE;
924             }
925             }
926 1         171 close MAKEFILE;
927             }
928              
929             sub quote_space {
930              
931             # Do nothing if $ENV{NO_INSANE_DIRNAMES} is set
932 0 0   0 0 0 return $_[0] if $ENV{NO_INSANE_DIRNAMES};
933              
934             # If $_[0] contains one or more doublequote characters, assume
935             # that whitespace has already been quoted as required. Hence,
936             # do nothing other than immediately return $_[0] as is.
937             # We currently don't properly handle tabs either, so we'll
938             # do the same if $_[0] =~ /\t/.
939 0 0 0     0 return $_[0] if ($_[0] =~ /"/ || $_[0] =~ /\t/);
940              
941             # We want to split on /\s\-I/ not /\-I/
942 0         0 my @in = split /\s\-I/, $_[0];
943 0         0 my $s = @in - 1;
944 0         0 my %s;
945             my %q;
946              
947             # First up, let's reinstate the ' ' characters that split
948             # removed
949 0         0 for(my $i = 0; $i < $s; $i++) {
950 0         0 $in[$i] .= ' ';
951             }
952              
953             # This for{} block dies if it finds that any of the ' -I'
954             # occurrences in $_[0] are part of a directory name.
955 0         0 for(my $i = 1; $i < $s; $i++) {
956 0         0 my $t = $in[$i + 1];
957 0         0 while($t =~ /\s$/) {chop $t}
  0         0  
958 0 0       0 die "Found a '", $in[$i], "-I", $t, "' directory.",
959             " INC Config argument is ambiguous.",
960             " Please use doublequotes to signify your intentions"
961             if -d ($in[$i] . "-I" . $t);
962             }
963              
964 0         0 $s++; # Now the same as scalar(@in)
965              
966             # Remove (but also Keep track of the amount of) whitespace
967             # at the end of each element of @in.
968 0         0 for(my $i = 0; $i < $s; $i++) {
969 0         0 my $count = 0;
970 0         0 while($in[$i] =~ /\s$/) {
971 0         0 chop $in[$i];
972 0         0 $count++;
973             }
974 0         0 $s{$i} = $count;
975             }
976              
977             # Note which elements of @in still contain whitespace. These
978             # (and only these) elements will be quoted
979 0         0 for(my $i = 0; $i < $s; $i++) {
980 0 0       0 $q{$i} = 1 if $in[$i] =~ /\s/;
981             }
982              
983             # Reinstate the occurrences of '-I' that were removed by split(),
984             # insert any quotes that are needed, reinstate the whitespace
985             # that was removed earlier, then join() the array back together
986             # again.
987 0         0 for(my $i = 0; $i < $s; $i++) {
988 0 0       0 $in[$i] = '-I' . $in[$i] if $i;
989 0 0       0 $in[$i] = '"' . $in[$i] . '"' if $q{$i};
990 0         0 $in[$i] .= ' ' x $s{$i};
991             }
992              
993             # Note: If there was no whitespace that needed quoting, the
994             # original argument should not have changed in any way.
995              
996 0         0 my $out = join '', @in;
997 0         0 $out =~ s/"\-I\s+\//"\-I\//g;
998 0         0 $_[0] = $out;
999             }
1000              
1001             sub fix_space {
1002 3 50   3 0 11 $_[0] =~ s/ /\\ /g if $_[0] =~ / /;
1003 3         6 $_[0];
1004             }
1005              
1006             #==============================================================================
1007             # This routine used by C/t/09parser to test that the expected parser is in use
1008             #==============================================================================
1009              
1010             sub _parser_test {
1011 0     0     my $dir = '_Inline_test';
1012 0 0         if(! -d $dir) {
1013 0           my $ok = mkdir $dir;
1014 0 0         warn $! if !$ok;
1015             }
1016              
1017 0 0         warn $! if !open(TEST_FH, '>>', "$dir/parser_id");
1018 0           print TEST_FH $_[0];
1019 0 0         warn $! if !close(TEST_FH);
1020             }
1021              
1022             #=======================================================================
1023             # This routine used to cleanup files created by _TESTING (config option)
1024             #=======================================================================
1025              
1026             sub _testing_cleanup {
1027 0     0     my $dir = '_Inline_test';
1028              
1029 0 0         if(-f "$dir/parser_id") {
1030 0 0         warn "Failed to unlink C/$dir/parser_id\n" if !unlink("$dir/parser_id");
1031             }
1032              
1033 0 0         if(-f "$dir/void_test") {
1034 0 0         warn "Failed to unlink C/$dir/void_test\n" if !unlink("$dir/void_test");
1035             }
1036             }
1037              
1038             1;
1039              
1040             __END__