File Coverage

blib/lib/PDLA/Core/Dev.pm
Criterion Covered Total %
statement 34 235 14.4
branch 3 104 2.8
condition 4 42 9.5
subroutine 13 35 37.1
pod 5 26 19.2
total 59 442 13.3


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