File Coverage

blib/lib/PDLA/Core/Dev.pm
Criterion Covered Total %
statement 25 238 10.5
branch 0 110 0.0
condition 2 41 4.8
subroutine 8 35 22.8
pod 5 26 19.2
total 40 450 8.8


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             PDLA::Core::Dev - PDLA development module
4              
5             =head1 DESCRIPTION
6              
7             This module encapsulates most of the stuff useful for
8             PDLA development and is often used from within Makefile.PL's.
9              
10             =head1 SYNOPSIS
11              
12             use PDLA::Core::Dev;
13              
14             =head1 FUNCTIONS
15              
16             =cut
17              
18             # Stuff used in development/install environment of PDLA Makefile.PL's
19             # - not part of PDLA itself.
20              
21             package PDLA::Core::Dev;
22              
23 2     2   10 use File::Path;
  2         4  
  2         170  
24 2     2   12 use File::Basename;
  2         3  
  2         169  
25 2     2   1324 use ExtUtils::Manifest;
  2         18164  
  2         153  
26 2     2   2237 use English; require Exporter;
  2         10399  
  2         19  
27              
28             @ISA = qw( Exporter );
29              
30             @EXPORT = qw( isbigendian genpp %PDLA_DATATYPES
31             PDLA_INCLUDE PDLA_TYPEMAP
32             PDLA_AUTO_INCLUDE PDLA_BOOT
33             PDLA_INST_INCLUDE PDLA_INST_TYPEMAP
34             pdlpp_postamble_int pdlpp_stdargs_int
35             pdlpp_postamble pdlpp_stdargs write_dummy_make
36             unsupported getcyglib trylink
37             pdlpp_mkgen
38             );
39              
40             # Installation locations
41             # beware: whereami_any now appends the /Basic or /PDLA directory as appropriate
42              
43             # The INST are here still just in case we want to change something later.
44              
45             # print STDERR "executing PDLA::Core::Dev from",join(',',caller),"\n";
46              
47             # Return library locations
48              
49              
50 0     0 0 0 sub PDLA_INCLUDE { '"-I'.whereami_any().'/Core"' };
51 0     0 0 0 sub PDLA_TYPEMAP { whereami_any().'/Core/typemap.pdl' };
52             # sub PDLA_INST_INCLUDE { '-I'.whereami_any().'/Core' };
53             # sub PDLA_INST_TYPEMAP { whereami_any().'/Core/typemap.pdl' };
54              
55 0     0 0 0 sub PDLA_INST_INCLUDE {&PDLA_INCLUDE}
56 0     0 0 0 sub PDLA_INST_TYPEMAP {&PDLA_TYPEMAP}
57              
58             sub PDLA_AUTO_INCLUDE {
59 0     0 0 0 my ($symname) = @_;
60 0   0     0 $symname ||= 'PDLA';
61 0         0 return << "EOR";
62             #include
63             static Core* $symname; /* Structure holds core C functions */
64             static SV* CoreSV; /* Gets pointer to perl var holding core structure */
65             EOR
66             }
67              
68             sub PDLA_BOOT {
69 1     1 0 3 my ($symname, $module) = @_;
70 1   50     4 $symname ||= 'PDLA';
71 1   50     4 $module ||= 'The code';
72 1         8 return << "EOR";
73              
74             perl_require_pv ("PDLA/Core.pm"); /* make sure PDLA::Core is loaded */
75             #ifndef aTHX_
76             #define aTHX_
77             #endif
78             if (SvTRUE (ERRSV)) Perl_croak(aTHX_ "%s",SvPV_nolen (ERRSV));
79             CoreSV = perl_get_sv("PDLA::SHARE",FALSE); /* SV* value */
80             if (CoreSV==NULL)
81             Perl_croak(aTHX_ "We require the PDLA::Core module, which was not found");
82             $symname = INT2PTR(Core*,SvIV( CoreSV )); /* Core* value */
83             if ($symname->Version != PDLA_CORE_VERSION)
84             Perl_croak(aTHX_ "[$symname->Version: \%d PDLA_CORE_VERSION: \%d XS_VERSION: \%s] $module needs to be recompiled against the newly installed PDLA", $symname->Version, PDLA_CORE_VERSION, XS_VERSION);
85              
86             EOR
87             }
88              
89             # whereami_any returns appended 'Basic' or 'PDLA' dir as appropriate
90 2     2   1412 use Cwd qw/abs_path/;
  2         3  
  2         1442  
91             sub whereami_any {
92 0   0 0 0   my $dir = (&whereami(1) or &whereami_inst(1) or
93             die "Unable to determine ANY directory path to PDLA::Core::Dev module\n");
94 0           return abs_path($dir);
95             }
96              
97             sub whereami {
98 0     0 0   for $dir (@INC,qw|. .. ../.. ../../.. ../../../..|) {
99 0 0         return ($_[0] ? $dir . '/Basic' : $dir)
    0          
100             if -e "$dir/Basic/Core/Dev.pm";
101             }
102 0 0         die "Unable to determine UNINSTALLED directory path to PDLA::Core::Dev module\n"
103             if !$_[0];
104 0           return undef;
105             }
106              
107             sub whereami_inst {
108 0     0 0   for $dir (@INC,map {$_."/blib"} qw|. .. ../.. ../../.. ../../../..|) {
  0            
109 0 0         return ($_[0] ? $dir . '/PDLA' : $dir)
    0          
110             if -e "$dir/PDLA/Core/Dev.pm";
111             }
112 0 0         die "Unable to determine INSTALLED directory path to PDLA::Core::Dev module\n"
113             if !$_[0];
114 0           return undef;
115             }
116              
117             #
118             # To access PDLA's configuration use %PDLA::Config. Makefile.PL has been set up
119             # to create this variable so it is available during 'perl Makefile.PL' and
120             # it can be eval-ed during 'make'
121              
122             unless ( %PDLA::Config ) {
123              
124             # look for the distribution and then the installed version
125             # (a manual version of whereami_any)
126             #
127             my $dir;
128             $dir = whereami(1);
129             if ( defined $dir ) {
130             $dir = abs_path($dir . "/Core");
131             } else {
132             # as no argument given whereami_inst will die if it fails
133             # (and it also returns a slightly different path than whereami(1)
134             # does, since it does not include "/PDLA")
135             #
136             $dir = whereami_inst;
137             $dir = abs_path($dir . "/PDLA");
138             }
139              
140             my $dir2 = $dir;
141             $dir2 =~ s/\}/\\\}/g;
142             eval sprintf('require q{%s/Config.pm};', $dir2);
143              
144             die "Unable to find PDLA's configuration info\n [$@]"
145             if $@;
146             }
147              
148             # Data types to C types mapping
149             # get the map from Types.pm
150             {
151             # load PDLA::Types only if it has not been previously loaded
152             my $loaded_types = grep (m%(PDLA|Core)/Types[.]pm$%, keys %INC);
153             $@ = ''; # reset
154             eval('require "'.whereami_any().'/Core/Types.pm"') # lets dist Types.pm win
155             unless $loaded_types; # only when PDLA::Types not yet loaded
156             if($@) { # if PDLA::Types doesn't work try with full path (during build)
157             my $foo = $@;
158             $@="";
159             eval('require PDLA::Types');
160             if($@) {
161             die "can't find PDLA::Types: $foo and $@" unless $@ eq "";
162             }
163             }
164             }
165             PDLA::Types->import();
166              
167             my $inc = defined $PDLA::Config{MALLOCDBG}->{include} ?
168             "$PDLA::Config{MALLOCDBG}->{include}" : '';
169             my $libs = defined $PDLA::Config{MALLOCDBG}->{libs} ?
170             "$PDLA::Config{MALLOCDBG}->{libs}" : '';
171              
172             %PDLA_DATATYPES = ();
173             foreach $key (keys %PDLA::Types::typehash) {
174             $PDLA_DATATYPES{$PDLA::Types::typehash{$key}->{'sym'}} =
175             $PDLA::Types::typehash{$key}->{'ctype'};
176             }
177              
178             # non-blocking IO configuration
179              
180             $O_NONBLOCK = defined $Config{'o_nonblock'} ? $Config{'o_nonblock'}
181             : 'O_NONBLOCK';
182              
183             =head2 isbigendian
184              
185             =for ref
186              
187             Is the machine big or little endian?
188              
189             =for example
190              
191             print "Your machins is big endian.\n" if isbigendian();
192              
193             returns 1 if the machine is big endian, 0 if little endian,
194             or dies if neither. It uses the C element of
195             perl's C<%Config> array.
196              
197             =for usage
198              
199             my $retval = isbigendian();
200              
201             =cut
202              
203             # ' emacs parsing dummy
204              
205             # big/little endian?
206             sub isbigendian {
207 2     2   13 use Config;
  2         4  
  2         5286  
208             my $byteorder = $Config{byteorder} ||
209 0   0 0 1   die "ERROR: Unable to find 'byteorder' in perl's Config\n";
210 0 0         return 1 if $byteorder eq "4321";
211 0 0         return 1 if $byteorder eq "87654321";
212 0 0         return 0 if $byteorder eq "1234";
213 0 0         return 0 if $byteorder eq "12345678";
214 0           die "ERROR: PDLA does not understand your machine's byteorder ($byteorder)\n";
215             }
216              
217             #################### PDLA Generic PreProcessor ####################
218             #
219             # Preprocesses *.g files to *.c files allowing 'generic'
220             # type code which is converted to code for each type.
221             #
222             # e.g. the code:
223             #
224             # pdl x;
225             # GENERICLOOP(x.datatype)
226             # generic *xx = x.data;
227             # for(i=0; i
228             # xx[i] = i/nvals;
229             # ENDGENERICLOOP
230             #
231             # is converted into a giant switch statement:
232             #
233             # pdl x;
234             # switch (x.datatype) {
235             #
236             # case PDLA_L:
237             # {
238             # PDLA_Long *xx = x.data;
239             # for(i=0; i
240             # xx[i] = i/nvals;
241             # }break;
242             #
243             # case PDLA_F:
244             # {
245             # PDLA_Float *xx = x.data;
246             #
247             # .... etc. .....
248             #
249             # 'generic' is globally substituted for each relevant data type.
250             #
251             # This is used in PDLA to write generic functions (taking pdl or void
252             # objects) which is still efficient with perl writing the actual C
253             # code for each type.
254             #
255             # 1st version - Karl Glazebrook 4/Aug/1996.
256             #
257             # Also makes the followings substitutions:
258             #
259             # (i) O_NONBLOCK - open flag for non-blocking I/O (5/Aug/96)
260             #
261              
262              
263             sub genpp {
264              
265 0     0 0   $gotstart = 0; @gencode = ();
  0            
266              
267 0           while (<>) { # Process files in @ARGV list - result to STDOUT
268              
269             # Do the miscellaneous substitutions first
270              
271 0           s/O_NONBLOCK/$O_NONBLOCK/go; # I/O
272              
273 0 0         if ( m/ (\s*)? \b GENERICLOOP \s* \( ( [^\)]* ) \) ( \s*; )? /x ){ # Start of generic code
274             #print $MATCH, "=$1=\n";
275              
276 0 0         die "Found GENERICLOOP while searching for ENDGENERICLOOP\n" if $gotstart;
277 0           $loopvar = $2;
278 0           $indent = $1;
279 0           print $PREMATCH;
280              
281 0           @gencode = (); # Start saving code
282 0           push @gencode, $POSTMATCH;
283 0           $gotstart = 1;
284 0           next;
285             }
286              
287 0 0         if ( m/ \b ENDGENERICLOOP ( \s*; )? /x ) {
288              
289 0 0         die "Found ENDGENERICLOOP while searching for GENERICLOOP\n" unless $gotstart;
290              
291 0           push @gencode, $PREMATCH;
292              
293 0           flushgeneric(); # Output the generic code
294              
295 0           print $POSTMATCH; # End of genric code
296 0           $gotstart = 0;
297 0           next;
298             }
299              
300 0 0         if ($gotstart) {
301 0           push @gencode, $_;
302             }
303             else {
304 0           print;
305             }
306              
307             } # End while
308             }
309              
310             sub flushgeneric { # Construct the generic code switch
311              
312 0     0 0   print $indent,"switch ($loopvar) {\n\n";
313              
314 0           for $case (keys %PDLA_DATATYPES) {
315              
316 0           $type = $PDLA_DATATYPES{$case};
317              
318 0           print $indent,"case $case:\n"; # Start of this case
319 0           print $indent," {";
320              
321             # Now output actual code with substutions
322              
323 0           for (@gencode) {
324 0           $line = $_;
325              
326 0           $line =~ s/\bgeneric\b/$type/g;
327              
328 0           print " ",$line;
329             }
330              
331 0           print "}break;\n\n"; # End of this case
332             }
333 0           print $indent,"default:\n";
334 0           print $indent,' croak ("Not a known data type code=%d",'.$loopvar.");\n";
335 0           print $indent,"}";
336              
337             }
338              
339              
340             sub genpp_cmdline {
341 0     0 0   my ($in, $out) = @_;
342 0           require ExtUtils::MM;
343 0           my $MM = bless { NAME => 'Fake' }, 'MM';
344 0           my $devpm = whereami_any()."/Core/Dev.pm";
345 0           sprintf($MM->oneliner(<<'EOF'), $devpm) . qq{ "$in" > "$out"};
346             require "%s"; PDLA::Core::Dev->import(); genpp();
347             EOF
348             }
349              
350              
351             # Standard PDLA postamble
352             #
353             # This is called via .../Gen/Inline/Pdlapp.pm, in the case that the INTERNAL
354             # flag for the compilation is off (grep "ILSM" in that file to find the reference).
355             # If it's ON, then postamble_int gets called instead.
356              
357              
358             sub postamble {
359 0     0 0   my ($self) = @_;
360 0           sprintf <<'EOF', genpp_cmdline(qw($< $@));
361              
362             # Rules for the generic preprocessor
363              
364             .SUFFIXES: .g
365             .g.c :
366             %s
367              
368             EOF
369             }
370              
371             # Expects list in format:
372             # [gtest.pd, GTest, PDLA::GTest, ['../GIS/Proj', ...] ], [...]
373             # source, prefix,module/package, optional deps
374             # The idea is to support in future several packages in same dir - EUMM
375             # 7.06 supports
376             # each optional dep is a relative dir that a "make" will chdir to and
377             # "make" first - so the *.pd file can then "use" what it makes
378              
379             # This is the function internal for PDLA.
380              
381             sub pdlpp_postamble_int {
382 0     0 0   join '',map { my($src,$pref,$mod, $deps) = @$_;
  0            
383 0 0 0       die "If give dependencies, must be array-ref" if $deps and !ref $deps;
384 0           my $w = whereami_any();
385 0           $w =~ s%/((PDLA)|(Basic))$%%; # remove the trailing subdir
386 0           my $top = File::Spec->abs2rel($w);
387 0           my $basic = File::Spec->catdir($top, 'Basic');
388 0           my $core = File::Spec->catdir($basic, 'Core');
389 0           my $gen = File::Spec->catdir($basic, 'Gen');
390 0           my $depbuild = '';
391 0 0         for my $dep (@{$deps || []}) {
  0            
392 0           my $target = '';
393 0 0         if ($dep eq 'core') {
394 0           $dep = $top;
395 0           $target = ' core';
396             }
397 0           require ExtUtils::MM;
398 0           $dep =~ s#([\(\)])#\\$1#g; # in case of unbalanced (
399 0           $depbuild .= MM->oneliner("exit(!(chdir q($dep) && !system(q(\$(MAKE)$target))))");
400 0           $depbuild .= "\n\t";
401             }
402             qq|
403              
404             $pref.pm: $src $core/Types.pm
405             $depbuild\$(PERLRUNINST) \"-MPDLA::PP qw/$mod $mod $pref/\" $src
406              
407             $pref.xs: $pref.pm
408             \$(TOUCH) \$@
409              
410             $pref.c: $pref.xs
411              
412             $pref\$(OBJ_EXT): $pref.c
413             |
414 0           } (@_)
415             }
416              
417              
418             # This is the function to be used outside the PDLA tree.
419             sub pdlpp_postamble {
420 0     0 0   join '',map { my($src,$pref,$mod) = @$_;
  0            
421 0           my $w = whereami_any();
422 0           $w =~ s%/((PDLA)|(Basic))$%%; # remove the trailing subdir
423 0           qq|
424              
425             $pref.pm: $src
426             \$(PERL) "-I$w" \"-MPDLA::PP qw/$mod $mod $pref/\" $src
427              
428             $pref.xs: $pref.pm
429             \$(TOUCH) \$@
430              
431             $pref.c: $pref.xs
432              
433             $pref\$(OBJ_EXT): $pref.c
434             |
435             } (@_)
436             }
437              
438             sub pdlpp_stdargs_int {
439 0     0 0   my($rec) = @_;
440 0           my($src,$pref,$mod) = @$rec;
441 0           my $w = whereami();
442             my $malloclib = exists $PDLA::Config{MALLOCDBG}->{libs} ?
443 0 0         $PDLA::Config{MALLOCDBG}->{libs} : '';
444             my $mallocinc = exists $PDLA::Config{MALLOCDBG}->{include} ?
445 0 0         $PDLA::Config{MALLOCDBG}->{include} : '';
446 0 0 0       my $libsarg = $libs || $malloclib ? "$libs $malloclib " : ''; # for Win32
447             return (
448 0 0         %::PDLA_OPTIONS,
    0          
449             'NAME' => $mod,
450             'VERSION_FROM' => "$w/Basic/Core/Version.pm",
451             'TYPEMAPS' => [&PDLA_TYPEMAP()],
452             'OBJECT' => "$pref\$(OBJ_EXT)",
453             PM => {"$pref.pm" => "\$(INST_LIBDIR)/$pref.pm"},
454             MAN3PODS => {"$pref.pm" => "\$(INST_MAN3DIR)/$mod.\$(MAN3EXT)"},
455             'INC' => &PDLA_INCLUDE()." $inc $mallocinc",
456             'LIBS' => $libsarg ? [$libsarg] : [],
457             'clean' => {'FILES' => "$pref.xs $pref.pm $pref\$(OBJ_EXT) $pref.c"},
458             (eval ($ExtUtils::MakeMaker::VERSION) >= 6.57_02 ? ('NO_MYMETA' => 1) : ()),
459             );
460             }
461              
462             sub pdlpp_stdargs {
463 0     0 0   my($rec) = @_;
464 0           my($src,$pref,$mod) = @$rec;
465             return (
466 0 0         %::PDLA_OPTIONS,
    0          
467             'NAME' => $mod,
468             'TYPEMAPS' => [&PDLA_INST_TYPEMAP()],
469             'OBJECT' => "$pref\$(OBJ_EXT)",
470             PM => {"$pref.pm" => "\$(INST_LIBDIR)/$pref.pm"},
471             MAN3PODS => {"$pref.pm" => "\$(INST_MAN3DIR)/$mod.\$(MAN3EXT)"},
472             'INC' => &PDLA_INST_INCLUDE()." $inc",
473             'LIBS' => $libs ? ["$libs "] : [],
474             'clean' => {'FILES' => "$pref.xs $pref.pm $pref\$(OBJ_EXT) $pref.c"},
475             'dist' => {'PREOP' => '$(PERL) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)" -MPDLA::Core::Dev -e pdlpp_mkgen $(DISTVNAME)' },
476             (eval ($ExtUtils::MakeMaker::VERSION) >= 6.57_02 ? ('NO_MYMETA' => 1) : ()),
477             );
478             }
479              
480             # pdlpp_mkgen($dir)
481             # - scans $dir/MANIFEST for all *.pd files and creates corresponding *.pm files
482             # in $dir/GENERATED/ subdir; needed for proper doc rendering at metacpan.org
483             # - it is used in Makefile.PL like:
484             # dist => { PREOP=>'$(PERL) -MPDLA::Core::Dev -e pdlpp_mkgen $(DISTVNAME)' }
485             # so all the magic *.pm generation happens during "make dist"
486             # - it is intended to be called as a one-liner:
487             # perl -MPDLA::Core::Dev -e pdlpp_mkgen DirName
488             #
489             sub pdlpp_mkgen {
490 0 0   0 0   my $dir = @_ > 0 ? $_[0] : $ARGV[0];
491 0 0 0       die "pdlpp_mkgen: unspecified directory" unless defined $dir && -d $dir;
492 0           my $file = "$dir/MANIFEST";
493 0 0         die "pdlpp_mkgen: non-existing '$dir/MANIFEST'" unless -f $file;
494              
495 0           my @pairs = ();
496 0           my $manifest = ExtUtils::Manifest::maniread($file);
497 0           for (keys %$manifest) {
498 0 0         next if $_ !~ m/\.pd$/; # skip non-pd files
499 0 0         next if $_ =~ m/^(t|xt)\//; # skip *.pd files in test subdirs
500 0 0         next unless -f $_;
501 0           my $content = do { local $/; open my $in, '<', $_; <$in> };
  0            
  0            
  0            
502 0 0         if ($content =~ /=head1\s+NAME\s+(\S+)\s+/sg) {
503 0           push @pairs, [$_, $1];
504             }
505             else {
506 0           warn "pdlpp_mkgen: unknown module name for '$_' (use proper '=head1 NAME' section)\n";
507             }
508             }
509              
510 0           my %added = ();
511 0           for (@pairs) {
512 0           my ($pd, $mod) = @$_;
513 0           (my $prefix = $mod) =~ s|::|/|g;
514 0           my $manifestpm = "GENERATED/$prefix.pm";
515 0           $prefix = "$dir/GENERATED/$prefix";
516 0           File::Path::mkpath(dirname($prefix));
517             #there is no way to use PDLA::PP from perl code, thus calling via system()
518 0           my @in = map { "-I$_" } @INC, 'inc';
  0            
519 0           my $rv = system($^X, @in, "-MPDLA::PP qw[$mod $mod $prefix]", $pd);
520 0 0 0       if ($rv == 0 && -f "$prefix.pm") {
521 0           $added{$manifestpm} = "mod=$mod pd=$pd (added by pdlpp_mkgen)";
522 0           unlink "$prefix.xs"; #we need only .pm
523             }
524             else {
525 0           warn "pdlpp_mkgen: cannot convert '$pd'\n";
526             }
527             }
528              
529 0 0         if (scalar(keys %added) > 0) {
530             #maniadd works only with this global variable
531 0           local $ExtUtils::Manifest::MANIFEST = $file;
532 0           ExtUtils::Manifest::maniadd(\%added);
533             }
534             }
535              
536             sub unsupported {
537 0     0 0   my ($package,$os) = @_;
538 0           "No support for $package on $os platform yet. Will skip build process";
539             }
540              
541             sub write_dummy_make {
542 0     0 0   my ($msg) = @_;
543 0           $msg =~ s#\n*\z#\n#;
544 0           $msg =~ s#^\s*#\n#gm;
545 0           print $msg;
546 0           require ExtUtils::MakeMaker;
547 0           ExtUtils::MakeMaker::WriteEmptyMakefile(NAME => 'Dummy', DIR => []);
548             }
549              
550             sub getcyglib {
551 0     0 0   my ($lib) = @_;
552 0           my $lp = `gcc -print-file-name=lib$lib.a`;
553 0           $lp =~ s|/[^/]+$||;
554 0           $lp =~ s|^([a-z,A-Z]):|//$1|g;
555 0           return "-L$lp -l$lib";
556             }
557              
558             =head2 trylink
559              
560             =for ref
561              
562             a perl configure clone
563              
564             =for example
565              
566             if (trylink 'libGL', '', 'char glBegin(); glBegin();', '-lGL') {
567             $libs = '-lGLU -lGL';
568             $have_GL = 1;
569             } else {
570             $have_GL = 0;
571             }
572             $maybe =
573             trylink 'libwhatever', $inc, $body, $libs, $cflags,
574             {MakeMaker=>1, Hide=>0, Clean=>1};
575              
576             Try to link some C-code making up the body of a function
577             with a given set of library specifiers
578              
579             return 1 if successful, 0 otherwise
580              
581             =for usage
582              
583             trylink $infomsg, $include, $progbody, $libs [,$cflags,{OPTIONS}];
584              
585             Takes 4 + 2 optional arguments.
586              
587             =over 5
588              
589             =item *
590              
591             an informational message to print (can be empty)
592              
593             =item *
594              
595             any commands to be included at the top of the generated C program
596             (typically something like C<#include "mylib.h">)
597              
598             =item *
599              
600             the body of the program (in function main)
601              
602             =item *
603              
604             library flags to use for linking. Preprocessing
605             by MakeMaker should be performed as needed (see options and example).
606              
607             =item *
608              
609             compilation flags. For example, something like C<-I/usr/local/lib>.
610             Optional argument. Empty if omitted.
611              
612             =item *
613              
614             OPTIONS
615              
616             =over
617              
618             =item MakeMaker
619              
620             Preprocess library strings in the way MakeMaker does things. This is
621             advisable to ensure that your code will actually work after the link
622             specs have been processed by MakeMaker.
623              
624             =item Hide
625              
626             Controls if linking output etc is hidden from the user or not.
627             On by default except within the build of the PDLA distribution
628             where the config value set in F prevails.
629              
630             =item Clean
631              
632             Remove temporary files. Enabled by default. You might want to switch
633             it off during debugging.
634              
635             =back
636              
637             =back
638              
639             =cut
640              
641              
642             sub trylink {
643 0 0   0 1   my $opt = ref $_[$#_] eq 'HASH' ? pop : {};
644 0           my ($txt,$inc,$body,$libs,$cflags) = @_;
645 0   0       $cflags ||= '';
646 0           require File::Spec;
647 0           require File::Temp;
648 0     0     my $cdir = sub { return File::Spec->catdir(@_)};
  0            
649 0     0     my $cfile = sub { return File::Spec->catfile(@_)};
  0            
650 2     2   18 use Config;
  2         4  
  2         2264  
651              
652             # check if MakeMaker should be used to preprocess the libs
653 0           for my $key(keys %$opt) {$opt->{lc $key} = $opt->{$key}}
  0            
654 0   0       my $mmprocess = exists $opt->{makemaker} && $opt->{makemaker};
655             my $hide = exists $opt->{hide} ? $opt->{hide} :
656 0 0         exists $PDLA::Config{HIDE_TRYLINK} ? $PDLA::Config{HIDE_TRYLINK} : 1;
    0          
657 0 0         my $clean = exists $opt->{clean} ? $opt->{clean} : 1;
658 0 0         if ($mmprocess) {
659 0           require ExtUtils::MakeMaker;
660 0           require ExtUtils::Liblist;
661 0           my $self = new ExtUtils::MakeMaker {DIR => [],'NAME' => 'NONE'};
662              
663 0           my @libs = $self->ext($libs, 0);
664              
665 0 0         print "processed LIBS: $libs[0]\n" unless $hide;
666 0           $libs = $libs[0]; # replace by preprocessed libs
667             }
668              
669 0 0         print " Trying $txt...\n " unless $txt =~ /^\s*$/;
670              
671 0 0         my $HIDE = !$hide ? '' : '>/dev/null 2>&1';
672 0 0         if($^O =~ /mswin32/i) {$HIDE = '>NUL 2>&1'}
  0            
673              
674 0           my $tempd;
675              
676 0   0       $tempd = File::Temp::tempdir(CLEANUP=>1) || die "trylink: could not make TEMPDIR";
677             ### if($^O =~ /MSWin32/i) {$tempd = File::Spec->tmpdir()}
678             ### else {
679             ### $tempd = $PDLA::Config{TEMPDIR} ||
680             ### }
681              
682 0           my ($tc,$te) = map {&$cfile($tempd,"testfile$_")} ('.c','');
  0            
683 0 0         open FILE,">$tc" or die "trylink: couldn't open testfile `$tc' for writing, $!";
684 0           my $prog = <<"EOF";
685             $inc
686              
687             int main(void) {
688             $body
689              
690             return 0;
691              
692             }
693              
694             EOF
695              
696 0           print FILE $prog;
697 0           close FILE;
698             # print "test prog:\n$prog\n";
699             # make sure we can overwrite the executable. shouldn't need this,
700             # but if it fails and HIDE is on, the user will never see the error.
701 0 0         open(T, ">$te") or die( "unable to write to test executable `$te'");
702 0           close T;
703 0 0         print "$Config{cc} $cflags -o $te $tc $libs $HIDE ...\n" unless $hide;
704 0 0 0       my $success = (system("$Config{cc} $cflags -o $te $tc $libs $HIDE") == 0) &&
705             -e $te ? 1 : 0;
706 0 0         unlink "$te","$tc" if $clean;
707 0 0         print $success ? "\t\tYES\n" : "\t\tNO\n" unless $txt =~ /^\s*$/;
    0          
708 0 0 0       print $success ? "\t\tSUCCESS\n" : "\t\tFAILED\n"
    0          
709             if $txt =~ /^\s*$/ && !$hide;
710 0           return $success;
711             }
712              
713             =head2 datatypes_switch
714              
715             =for ref
716              
717             prints on C XS text for F.
718              
719             =cut
720              
721             sub datatypes_switch {
722 0     0 1   my $ntypes = $#PDLA::Types::names;
723 0           my @m;
724 0           foreach my $i ( 0 .. $ntypes ) {
725 0           my $type = PDLA::Type->new( $i );
726 0           my $typesym = $type->symbol;
727 0           my $cname = $type->ctype;
728 0           $cname =~ s/^PDLA_//;
729 0           push @m, "\tcase $typesym: retval = PDLA.bvals.$cname; break;";
730             }
731 0           print map "$_\n", @m;
732             }
733              
734             =head2 generate_core_flags
735              
736             =for ref
737              
738             prints on C XS text with core flags, for F.
739              
740             =cut
741              
742             my %flags = (
743             hdrcpy => { set => 1 },
744             fflows => { FLAG => "DATAFLOW_F" },
745             bflows => { FLAG => "DATAFLOW_B" },
746             is_inplace => { FLAG => "INPLACE", postset => 1 },
747             donttouch => { FLAG => "DONTTOUCHDATA" },
748             allocated => { },
749             vaffine => { FLAG => "OPT_VAFFTRANSOK" },
750             anychgd => { FLAG => "ANYCHANGED" },
751             dimschgd => { FLAG => "PARENTDIMSCHANGED" },
752             tracedebug => { FLAG => "TRACEDEBUG", set => 1},
753             );
754             #if ( $bvalflag ) { $flags{baddata} = { set => 1, FLAG => "BADVAL" }; }
755              
756             sub generate_core_flags {
757             # access (read, if set is true then write as well; if postset true then
758             # read first and write new value after that)
759             # to piddle's state
760 0     0 1   foreach my $name ( keys %flags ) {
761 0   0       my $flag = "PDLA_" . ($flags{$name}{FLAG} || uc($name));
762 0 0         if ( $flags{$name}{set} ) {
    0          
763 0           print <<"!WITH!SUBS!";
764             int
765             $name(x,mode=0)
766             pdl *x
767             int mode
768             CODE:
769             if (items>1)
770             { setflag(x->state,$flag,mode); }
771             RETVAL = ((x->state & $flag) > 0);
772             OUTPUT:
773             RETVAL
774              
775             !WITH!SUBS!
776             } elsif ($flags{$name}{postset}) {
777 0           print <<"!WITH!SUBS!";
778             int
779             $name(x,mode=0)
780             pdl *x
781             int mode
782             CODE:
783             RETVAL = ((x->state & $flag) > 0);
784             if (items>1)
785             { setflag(x->state,$flag,mode); }
786             OUTPUT:
787             RETVAL
788              
789             !WITH!SUBS!
790             } else {
791 0           print <<"!WITH!SUBS!";
792             int
793             $name(self)
794             pdl *self
795             CODE:
796             RETVAL = ((self->state & $flag) > 0);
797             OUTPUT:
798             RETVAL
799              
800             !WITH!SUBS!
801             }
802             } # foreach: keys %flags
803             }
804              
805             =head2 generate_badval_init
806              
807             =for ref
808              
809             prints on C XS text with badval initialisation, for F.
810              
811             =cut
812              
813             sub generate_badval_init {
814 0     0 1   for my $type (PDLA::Types::types()) {
815 0           my $typename = $type->ctype;
816 0           $typename =~ s/^PDLA_//;
817 0           my $bval = $type->defbval;
818 0 0 0       if ($PDLA::Config{BADVAL_USENAN} && $type->usenan) {
819             # note: no defaults if usenan
820 0           print "\tPDLA.bvals.$typename = PDLA.NaN_$type;\n"; #Core NaN value
821             } else {
822 0           print "\tPDLA.bvals.$typename = PDLA.bvals.default_$typename = $bval;\n";
823             }
824             }
825             # PDLA.bvals.Byte = PDLA.bvals.default_Byte = UCHAR_MAX;
826             # PDLA.bvals.Short = PDLA.bvals.default_Short = SHRT_MIN;
827             # PDLA.bvals.Ushort = PDLA.bvals.default_Ushort = USHRT_MAX;
828             # PDLA.bvals.Long = PDLA.bvals.default_Long = INT_MIN;
829              
830             }
831              
832             1;