File Coverage

blib/lib/PDL/Core/Dev.pm
Criterion Covered Total %
statement 43 247 17.4
branch 6 112 5.3
condition 4 41 9.7
subroutine 17 37 45.9
pod 6 27 22.2
total 76 464 16.3


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