]> git.imager.perl.org - imager.git/blobdiff - Makefile.PL
- use scanline oriented operations to flip images instead of pixel
[imager.git] / Makefile.PL
index 7b0040290809f0f390d47e1c925b3d382193e06d..0b71b80745f2e1e62689641b8b6f1838d5b2f8d2 100644 (file)
@@ -5,10 +5,10 @@ use Cwd;
 use Config;
 use File::Spec;
 use Getopt::Long;
-use vars qw(%Recommends);
-require "metafile.pl";
 use ExtUtils::Manifest qw(maniread);
 use vars qw(%formats $VERBOSE $INCPATH $LIBPATH $NOLOG $DEBUG_MALLOC $MANUAL $CFLAGS $LFLAGS $DFLAGS);
+use lib 'inc';
+use Devel::CheckLib;
 
 #
 # IM_INCPATH      colon seperated list of paths to extra include paths
@@ -25,7 +25,8 @@ use vars qw(%formats $VERBOSE $INCPATH $LIBPATH $NOLOG $DEBUG_MALLOC $MANUAL $CF
 # IM_CFLAGS       Extra flags to pass to the compiler
 # IM_LFLAGS       Extra flags to pass to the linker
 # IM_DFLAGS       Extra flags to pass to the preprocessor
-# IM_SUPPRESS_PROMPT  Suppress the prompt asking about gif support
+
+my $KEEP_FILES = $ENV{IMAGER_KEEP_FILES};
 
 getenv();     # get environment variables
 
@@ -37,17 +38,25 @@ my @enable; # list of drivers to enable
 my @disable; # or list of drivers to disable
 my @incpaths; # places to look for headers
 my @libpaths; # places to look for libraries
-my $noprobe; # non-zero to disable newer probes
 my $noexif; # non-zero to disable EXIF parsing of JPEGs
+my $no_gif_set_version; # disable calling EGifSetGifVersion
+my $coverage; # build for coverage testing
+my $assert; # build with assertions
 GetOptions("help" => \$help,
            "enable=s" => \@enable,
            "disable=s" => \@disable,
            "incpath=s", \@incpaths,
            "libpath=s" => \@libpaths,
-           "noprobe" => \$noprobe,
            "verbose|v" => \$VERBOSE,
            "nolog" => \$NOLOG,
-          "noexif" => \$noexif);
+          "noexif" => \$noexif,
+           "nogifsetversion" => \$no_gif_set_version,
+          'coverage' => \$coverage,
+          "assert|a" => \$assert);
+
+if ($ENV{AUTOMATED_TESTING}) {
+  $assert = 1;
+}
 
 if ($VERBOSE) { 
   print "Verbose mode\n"; 
@@ -66,6 +75,10 @@ else {
   push @defines, [ IMAGER_LOG => 1, "Logging system" ];
 }
 
+if ($assert) {
+  push @defines, [ IM_ASSERT => 1, "im_assert() are effective" ];
+}
+
 if ($DEBUG_MALLOC) {
   push @defines, [ IMAGER_DEBUG_MALLOC => 1, "Use Imager's DEBUG malloc()" ];
   print "Malloc debugging enabled\n";
@@ -111,18 +124,25 @@ if ($MANUAL) {
 gifcheck();
 
 my $lib_cflags = '';
+my $lib_lflags = '';
 my $F_LIBS = '';
 my $F_OBJECT = '';
 for my $frmkey (sort { $formats{$a}{order} <=> $formats{$b}{order} } keys %formats) {
   my $frm = $formats{$frmkey};
   push @defines, [ $frm->{def}, 1, "$frmkey available" ];
-  $F_LIBS   .= ' '  .$frm->{libfiles};
   $F_OBJECT .= ' '  .$frm->{objfiles};
   if ($frm->{cflags}) {
     $lib_cflags   .= ' '  .$frm->{cflags};
     ++$definc{$_} for map { /^-I(.*)$/ ? ($1) : () }
       grep /^-I./, split ' ', $frm->{cflags};
   }
+  if ($frm->{lflags}) {
+    $lib_lflags .= ' ' . $frm->{lflags};
+  }
+  else {
+    $F_LIBS   .= ' '  .$frm->{libfiles};
+  }
+
 }
 
 unless ($noexif) {
@@ -147,32 +167,57 @@ my @objs = qw(Imager.o draw.o polygon.o image.o io.o iolayer.o
               filters.o dynaload.o stackmach.o datatypes.o
               regmach.o trans2.o quant.o error.o convert.o
               map.o tags.o palimg.o maskimg.o img16.o rotate.o
-              bmp.o tga.o rgb.o color.o fills.o imgdouble.o limits.o hlines.o
-              imext.o);
-
-$Recommends{Imager} =
-  { 'Parse::RecDescent' => 0 };
+              bmp.o tga.o color.o fills.o imgdouble.o limits.o hlines.o
+              imext.o scale.o rubthru.o render.o paste.o compose.o flip.o);
 
 my %opts=(
           'NAME'         => 'Imager',
           'VERSION_FROM' => 'Imager.pm',
-          'LIBS'         => "$LFLAGS -lm $OSLIBS $F_LIBS",
+          'LIBS'         => "$LFLAGS -lm $lib_lflags $OSLIBS $F_LIBS",
           'DEFINE'       => "$OSDEF $CFLAGS",
           'INC'          => "$lib_cflags $DFLAGS $F_INC",
           'OBJECT'       => join(' ', @objs, $F_OBJECT),
-          clean          => { FILES=>'testout meta.tmp' },
+          clean          => { FILES=>'testout rubthru.c scale.c conv.c  filters.c gaussian.c render.c rubthru.c' },
           PM             => gen_PM(),
+         PREREQ_PM      => { 'Test::More' => 0.47 },
          );
 
-if ($ExtUtils::MakeMaker::VERSION > 6.06) {
+if ($coverage) {
+    if ($Config{gccversion}) {
+       push @ARGV, 'OPTIMIZE=-ftest-coverage -fprofile-arcs';
+       #$opts{dynamic_lib} = { OTHERLDFLAGS => '-ftest-coverage -fprofile-arcs' };
+    }
+    else {
+       die "Don't know the coverage C flags for your compiler\n";
+    }
+}
+
+# eval to prevent warnings about versions with _ in them
+my $MM_ver = eval $ExtUtils::MakeMaker::VERSION;
+if ($MM_ver > 6.06) {
   $opts{AUTHOR} = 'Tony Cook <tony@imager.perl.org>, Arnar M. Hrafnkelsson';
   $opts{ABSTRACT} = 'Perl extension for Generating 24 bit Images';
 }
 
+if ($MM_ver >= 6.46) {
+  $opts{META_MERGE} =
+    {
+     recommends =>
+     {
+      "Parse::RecDescent" => 0
+     },
+     license => "perl",
+     dynamic_config => 1,
+    };
+}
+
 make_imconfig(\@defines);
 
 if ($VERBOSE) { print Dumper(\%opts); }
 mkdir('testout',0777); # since we cannot include it in the archive.
+
+-d "probe" and rmdir "probe";
+
 WriteMakefile(%opts);
 
 exit;
@@ -181,6 +226,9 @@ exit;
 sub MY::postamble {
     my $self = shift;
     my $perl = $self->{PERLRUN} ? '$(PERLRUN)' : '$(PERL)';
+    my $mani = maniread;
+
+    my @ims = grep /\.im$/, keys %$mani;
 '
 dyntest.$(MYEXTLIB) : dynfilt/Makefile
        cd dynfilt && $(MAKE) $(PASTHRU)
@@ -193,10 +241,23 @@ imconfig.h : Makefile.PL
        $(PERLRUN) Makefile.PL
        $(ECHO) "==> Your Makefile has been rebuilt - re-run your make command <=="
 '.qq!
-lib/Imager/APIRef.pm : \$(C_FILES) apidocs.perl
-       $perl apidocs.perl lib/Imager/APIRef.pm
+lib/Imager/APIRef.pod : \$(C_FILES) \$(H_FILES) apidocs.perl
+       $perl apidocs.perl lib/Imager/APIRef.pod
 
-!;
+!.join('', map _im_rule($perl, $_), @ims)
+
+}
+
+sub _im_rule {
+  my ($perl, $im) = @_;
+
+  (my $c = $im) =~ s/\.im$/.c/;
+  return <<MAKE;
+
+$c: $im lib/Imager/Preprocess.pm
+       $perl -Ilib -MImager::Preprocess -epreprocess $im $c
+
+MAKE
 
 }
 
@@ -245,32 +306,6 @@ sub gifcheck {
     delete $formats{'ungif'};
   }
 
- RETR:
-  if (($formats{'gif'} or $formats{'ungif'}) && !$ENV{IM_SUPPRESS_PROMPT}) {
-    print <<EOFF;
-
-You have libgif or libungif installed.  They are both known to have
-bugs.  Imager can crash or display other strange behaviour after
-reading or writing gif images.  Some of the gif tests can even fail
-since they stress some parts of the buggy code.
-
-libungif 4.1.2 and later is safe.  giflib 4.1.3 needs at least one
-patch to have all the bugs fixed, see README for details.
-
-Of course it's possible your operating system distributor has patched
-all of these problems and you have nothing to worry about.
-
-Do you want to remove gif support? [Y/n]
-EOFF
-    my $resp = <STDIN>;
-    chomp($resp);
-    if ($resp ne "n") {
-      delete $formats{'gif'};
-      delete $formats{'ungif'};
-      return;
-    }
-  }
-
   for my $frm (qw(gif ungif)) {
     checkformat($frm) if ($MANUAL and $formats{$frm});
   }
@@ -299,11 +334,13 @@ EOFF
 
   push @defines, [ IM_GIFMAJOR => $major, "Parsed giflib version" ];
   push @defines, [ IM_GIFMINOR => $minor ];
+  push @defines, [ IM_NO_SET_GIF_VERSION => 1, "Disable EGifSetGifVersion" ]
+    if $no_gif_set_version;
 }
 
 
-sub gd {
-  my($path,$chk)=@_;
+sub grep_directory {
+  my($path, $chk)=@_;
 
 #    print "checking path $path\n";
   if ( !opendir(DH,$path) ) {
@@ -316,35 +353,71 @@ sub gd {
   return map $path, @l;
 }
 
+sub _probe_default {
+  my ($format, $frm) = @_;
+
+  my $lib_check=$formats{$frm}{'libcheck'};
+  my $inc_check=$formats{$frm}{'inccheck'};
+
+  if ($lib_check) {
+    my @l;
+    for my $lp (@libs) {
+      push(@l, grep_directory($lp,$lib_check));
+    }
+    
+    my @i;
+    for my $ip (@incs) {
+      push(@i, $ip) if $inc_check->($ip,$frm);
+    }
+    
+    printf("%10s: includes %s - libraries %s\n",$frm,(@i?'found':'not found'),(@l?'found':'not found'));
+    $formats{$frm}{incdir} = \@i;
+    $formats{$frm}{libdir} = \@l;
+    return 1 if scalar(@i && @l);
+  }
+  else {
+    printf("%10s: not available\n", $frm);
+  }
+
+  return 0;
+}
 
 sub checkformat {
   my $frm=shift;
 
   print "  checkformat($frm)\n" if $VERBOSE;
   
-  my $code = $formats{$frm}{'code'};
-  if ($code && !$noprobe) {
-    print "    Calling probe function\n" if $VERBOSE;
-    return 1 if $code->($formats{$frm}, $frm);
-  }
+  my $format = $formats{$frm};
 
-  my $libchk=$formats{$frm}{'libcheck'};
-  my $incchk=$formats{$frm}{'inccheck'};
+  my @probes;
+  if (my $code = $format->{'code'}) {
+    if (ref $code eq 'ARRAY') {
+      push @probes, @$code;
+    }
+    else {
+      push @probes, $code;
+    }
+  }
+  push @probes, \&_probe_default;
 
-  my @l;
-  for my $lp (@libs) {
-    push(@l, gd($lp,$libchk));
+  print "    Calling probe function\n" if $VERBOSE;
+  my $found;
+  for my $func (@probes) {
+    if ($func->($format, $frm)) {
+      ++$found;
+      last;
+    }
   }
 
-  my @i;
-  for my $ip (@incs) {
-    push(@i, $ip) if $incchk->($ip,$frm);
+  $found or return;
+
+  if ($format->{postcheck}) {
+    print "    Calling postcheck function\n" if $VERBOSE;
+    $format->{postcheck}->($format, $frm)
+      or return;
   }
 
-  printf("%10s: includes %s - libraries %s\n",$frm,(@i?'found':'not found'),(@l?'found':'not found'));
-  $formats{$frm}{incdir} = \@i;
-  $formats{$frm}{libdir} = \@l;
-  return scalar(@i && @l);
+  return 1;
 }
 
 
@@ -381,14 +454,20 @@ sub init {
 
   my @definc = qw(/usr/include);
   @definc{@definc}=(1) x @definc;
-  @incs=(split(/\Q$Config{path_sep}/, $INCPATH),
-        map { split /\Q$Config{path_sep}/} @incpaths );
+  @incs=
+    (
+     split(/\Q$Config{path_sep}/, $INCPATH),
+     map _tilde_expand($_), map { split /\Q$Config{path_sep}/ } @incpaths 
+    );
   if ($Config{locincpth}) {
     push @incs, grep -d, split ' ', $Config{locincpth};
   }
   if ($^O =~ /win32/i && $Config{cc} =~ /\bcl\b/i) {
     push(@incs, split /;/, $ENV{INCLUDE}) if exists $ENV{INCLUDE};
   }
+  if ($Config{incpath}) {
+    push @incs, grep -d, split /\Q$Config{path_sep}/, $Config{incpath};
+  }
   push @incs, grep -d,
       qw(/sw/include 
          /usr/include/freetype2
@@ -403,7 +482,7 @@ sub init {
   }
 
   @libs= ( split(/\Q$Config{path_sep}/,$LIBPATH),
-    map { split /\Q$Config{path_sep}/} @libpaths );
+    map _tilde_expand($_), map { split /\Q$Config{path_sep}/} @libpaths );
   if ($Config{loclibpth}) {
     push @libs, grep -d, split ' ', $Config{loclibpth};
   }
@@ -427,6 +506,7 @@ sub init {
     # it can't find and it doesn't look for -L in ldflags
     #@deflib{@hidden} = @hidden;
   }
+  push @libs, grep -d, qw(/usr/local/lib);
 
   $formats{'jpeg'}={
                    order=>'21',
@@ -449,7 +529,8 @@ sub init {
                    objfiles=>'tiff.o',
                    docs=>q{
                            In order to use tiff with this module you need to have libtiff
-                           installed on your computer}
+                           installed on your computer},
+                   postcheck => \&postcheck_tiff,
                   };
 
   $formats{'png'}={
@@ -457,7 +538,7 @@ sub init {
                   def=>'HAVE_LIBPNG',
                   inccheck=>sub { -e catfile($_[0], 'png.h') },
                   libcheck=>sub { $_[0] eq "libpng$aext" or $_[0] eq "libpng.$lext" },
-                  libfiles=>'-lpng -lz',
+                  libfiles=>$^O eq 'MSWin32' ? '-lpng -lzlib' : '-lpng -lz',
                   objfiles=>'png.o',
                   docs=>q{
                           Png stands for Portable Network Graphics and is intended as
@@ -540,19 +621,25 @@ Uses the Win32 GDI for rendering text.
 This currently only works on under normal Win32 and cygwin.
 DOCS
                    };
-  $formats{'freetype2'} = {
-                           order=>'29',
-                           def=>'HAVE_FT2',
-                           inccheck=>sub { -e catfile($_[0], 'ft2build.h') },
-                           libcheck=>sub { $_[0] eq "libfreetype$aext" or $_[0] eq "libfreetype.$lext" },
-                           libfiles=>'-lfreetype',
-                           objfiles=>'freetyp2.o',
-                           docs=><<DOCS,
+  $formats{'freetype2'} = 
+  {
+   order=>'29',
+   def=>'HAVE_FT2',
+   # we always use a probe function
+   #inccheck=>sub { -e catfile($_[0], 'ft2build.h') },
+   #libcheck=>sub { $_[0] eq "libfreetype$aext" or $_[0] eq "libfreetype.$lext" },
+   libfiles=>'-lfreetype',
+   objfiles=>'freetyp2.o',
+   docs=><<DOCS,
 Freetype 2 supports both Truetype and Type 1 fonts, both of which are
 scalable.  It also supports a variety of other fonts.
 DOCS
-                           code => \&freetype2_probe,
-                          };
+   code =>
+   [ 
+    \&freetype2_probe_ftconfig,
+    \&freetype2_probe_scan
+   ],
+  };
 
   # Make fix indent
   for (keys %formats) { $formats{$_}->{docs} =~ s/^\s+/  /mg; }
@@ -661,10 +748,10 @@ sub freetype1_probe {
     }
   }
 
+  return unless $found_inc && $found_lib;
   printf("%10s: includes %s - libraries %s\n", $frmkey,
         ($found_inc ? 'found' : 'not found'), 
         ($found_lib ? 'found' : 'not found'));
-  return unless $found_inc && $found_lib;
 
   $frm->{cflags} = "-I$found_inc";
   $frm->{libfiles} = "-lttf";
@@ -673,7 +760,7 @@ sub freetype1_probe {
 }
 
 # probes for freetype2 by trying to run freetype-config
-sub freetype2_probe {
+sub freetype2_probe_ftconfig {
   my ($frm, $frmkey) = @_;
 
   is_exe('freetype-config') or return;
@@ -705,13 +792,89 @@ sub freetype2_probe {
                   map "-I$_", reverse @incdirs);
   }
   $frm->{cflags} = $cflags;
-  $frm->{libfiles} = $lflags;
+  $frm->{lflags} = $lflags;
 
   printf "%10s: configured via freetype-config\n", $frmkey;
 
   return 1;
 }
 
+# attempt to probe for freetype2 by scanning directories
+# we can't use the normal scan since we need to find the directory
+# containing most of the includes
+sub freetype2_probe_scan {
+  my ($frm, $frmkey) = @_;
+
+  my $found_inc;
+  my $found_inc2;
+ INCS:
+  for my $inc (@incs) {
+    my $path = File::Spec->catfile($inc, 'ft2build.h');
+    -e $path or next;
+
+    # try to find what it's including
+    my $ftheader;
+    open FT2BUILD, "< $path"
+      or next;
+    while (<FT2BUILD>) {
+      if (m!^\s*\#\s*include\s+<([\w/.]+)>!
+         || m!^\s*\#\s*include\s+"([\w/.]+)"!) {
+       $ftheader = $1;
+       last;
+      }
+    }
+    close FT2BUILD;
+    $ftheader
+      or next;
+    # non-Unix installs put this directly under the same directory in
+    # theory
+    if (-e File::Spec->catfile($inc, $ftheader)) {
+      $found_inc = $inc;
+      last INCS;
+    }
+    for my $subdir (qw/freetype2 freetype/) {
+      $path = File::Spec->catfile($inc, $subdir, 'fterrors.h');
+      -e $path and next;
+
+      $found_inc = $inc;
+      $found_inc2 = File::Spec->catdir($inc, $subdir);
+      last INCS;
+    }
+  }
+
+  my $found_lib;
+ LIBS:
+  for my $lib (@libs) {
+    my $a_path = File::Spec->catfile($lib, "libfreetype$aext");
+    my $l_path = File::Spec->catfile($lib, "libfreetype.$lext");
+    if (-e $a_path || -e $l_path) {
+      $found_lib = $lib;
+      last LIBS;
+    }
+  }
+
+  printf("%10s: includes %s - libraries %s\n", $frmkey,
+        ($found_inc ? 'found' : 'not found'), 
+        ($found_lib ? 'found' : 'not found'));
+
+  return unless $found_inc && $found_lib;
+
+  $frm->{cflags} = _make_I($found_inc);
+  $frm->{cflags} .= " " . _make_I($found_inc2) if $found_inc2;
+  $frm->{libfiles} = "-lfreetype";
+
+  return 1;
+}
+
+sub _make_I {
+  my ($inc_dir) = @_;
+
+  $definc{$inc_dir}
+    and return '';
+
+  $inc_dir =~ / / ? qq!-I"$inc_dir"! : "-I$inc_dir";
+}
+
 # probes for libpng via pkg-config
 sub png_probe {
   my ($frm, $frmkey) = @_;
@@ -736,7 +899,7 @@ sub png_probe {
   chomp $cflags;
   chomp $lflags;
   $frm->{cflags} = $cflags;
-  $frm->{libfiles} = $lflags;
+  $frm->{lflags} = $lflags;
 
   printf "%10s: configured via `pkg-config $config ...`\n", $frmkey;
 
@@ -750,9 +913,16 @@ sub catfile {
 sub is_exe {
   my ($name) = @_;
 
+  my @exe_suffix = $Config{_exe};
+  if ($^O eq 'MSWin32') {
+    push @exe_suffix, qw/.bat .cmd/;
+  }
+
   for my $dir (File::Spec->path) {
-    -x catfile($dir, "$name$Config{_exe}")
-      and return 1;
+    for my $suffix (@exe_suffix) {
+      -x catfile($dir, "$name$suffix")
+       and return 1;
+    }
   }
 
   return;
@@ -774,8 +944,12 @@ Other options:
     Add to the include search path
   --libpath dir
     Add to the library search path
-  --noprobe
-    Don't use pkg-config or freetype2-config to probe for freetype2 and libpng
+  --coverage
+    Build for coverage testing.
+  --assert
+    Build with assertions active.
+  --noexif
+    Disable EXIF parsing.
 EOS
   exit 1;
 
@@ -815,3 +989,99 @@ sub gen_PM {
 
   \%pm;
 }
+
+my $home;
+sub _tilde_expand {
+  my ($path) = @_;
+
+  if ($path =~ m!^~[/\\]!) {
+    defined $home or $home = $ENV{HOME};
+    if (!defined $home && $^O eq 'MSWin32'
+       && defined $ENV{HOMEDRIVE} && defined $ENV{HOMEPATH}) {
+      $home = $ENV{HOMEDRIVE} . $ENV{HOMEPATH};
+    }
+    unless (defined $home) {
+      $home = eval { (getpwuid($<))[7] };
+    }
+    defined $home or die "You supplied $path, but I can't find your home directory\n";
+    $path =~ s/^~//;
+    $path = File::Spec->catdir($home, $path);
+  }
+
+  $path;
+}
+
+sub postcheck_tiff {
+  my ($format, $frm) = @_;
+
+  -d "probe" or mkdir "probe";
+
+  my $tiffver_name = "probe/tiffver.txt";
+
+  my $lib;
+  if ($Config{cc} =~ /\b(cl|bcc)\b/) {
+    $lib = "libtiff";
+  }
+  else {
+    $lib = "tiff";
+  }
+
+  my $good =
+    eval {
+      assert_lib
+       (
+        debug => $VERBOSE,
+        incpath => $format->{incdir},
+        libpath => $format->{libdir},
+        lib => $lib,
+        header => [ qw(stdio.h tiffio.h) ],
+        function => <<FUNCTION,
+  {
+    const char *vers = TIFFGetVersion();
+    FILE *f = fopen("$tiffver_name", "wb");
+    if (!f)
+      return 1;
+    fputs(vers, f);
+    if (fclose(f))
+      return 1;
+    return 0;
+  }
+FUNCTION
+       );
+      1;
+    };
+
+  unless ($good && -s $tiffver_name
+         && open(VERS, "< probe/tiffver.txt")) {
+    unlink $tiffver_name unless $KEEP_FILES;
+    print <<EOS;
+    **tiff: cannot determine libtiff version number
+      tiff: DISABLED
+EOS
+    return;
+  }
+
+  # version file seems to be there, load it up
+  my $ver_str = do { local $/; <VERS> };
+  close VERS;
+  unlink $tiffver_name unless $KEEP_FILES;
+
+  my ($version) = $ver_str =~ /(\d+\.\d+\.\d+)/;
+
+  if ($version eq '3.9.0') {
+    print <<EOS;
+    **tiff: libtiff 3.9.0 introduced a serious bug, please install 3.9.1
+      tiff: DISABLED
+EOS
+    return;
+  }
+
+  return 1;
+}
+
+# This isn't a module, but some broken tools, like
+# Module::Depends::Instrusive insist on treating it like one.
+#
+# http://rt.cpan.org/Public/Bug/Display.html?id=21229
+
+1;