]> git.imager.perl.org - imager.git/blob - Makefile.PL
update Changes
[imager.git] / Makefile.PL
1 #!perl -w
2 use strict;
3 use ExtUtils::MakeMaker;
4 use Cwd;
5 use Config;
6 use File::Spec;
7 use Getopt::Long;
8 use ExtUtils::Manifest qw(maniread);
9 use ExtUtils::Liblist;
10 use vars qw(%formats $VERBOSE $INCPATH $LIBPATH $NOLOG $DEBUG_MALLOC $MANUAL $CFLAGS $LFLAGS $DFLAGS);
11 use lib 'inc', 'lib';
12 use Imager::Probe;
13
14 # EU::MM runs Makefile.PL all in the same process, so sub-modules will
15 # see this
16 our $BUILDING_IMAGER = 1;
17
18 # used to display a summary after we've probed the world
19 our %IMAGER_LIBS;
20
21 #
22 # IM_INCPATH      colon seperated list of paths to extra include paths
23 # IM_LIBPATH      colon seperated list of paths to extra library paths
24 #
25 # IM_VERBOSE      turns on verbose mode for the library finding and such
26 # IM_MANUAL       to manually select which libraries are used and which not
27 # IM_ENABLE       to programmatically select which libraries are used
28 #                 and which are not
29 # IM_NOLOG        if true logging will not be compiled into the module
30 # IM_DEBUG_MALLOC if true malloc debbuging will be compiled into the module
31 #                 do not use IM_DEBUG_MALLOC in production - this slows
32 #                 everything down by alot
33 # IM_CFLAGS       Extra flags to pass to the compiler
34 # IM_LFLAGS       Extra flags to pass to the linker
35 # IM_DFLAGS       Extra flags to pass to the preprocessor
36
37 my $KEEP_FILES = $ENV{IMAGER_KEEP_FILES};
38
39 # make sure --verbose will dump environment settings
40 if (grep $_ =~ /^--?v(?:erbose)?$/, @ARGV) {
41   $VERBOSE = 1;
42 }
43
44 # modules/features bundled with Imager that can be enabled/disabled
45 # withs --enable/--disable
46 my @bundled = qw(FT1 FT2 GIF JPEG PNG T1 TIFF W32);
47
48 # extra modules bundled with Imager not available on CPAN
49 my @extras = qw(CountColor DynTest ICO SGI Mandelbrot Flines);
50
51 # alternate names for modules
52 my %bundled_names = qw(win32 w32 tt ft1);
53
54 getenv();     # get environment variables
55
56 my $lext=$Config{'so'};   # Get extensions of libraries
57 my $aext=$Config{'_a'};
58
59 my $help; # display help if set
60 my @enable; # list of drivers to enable
61 my @disable; # or list of drivers to disable
62 my @incpaths; # places to look for headers
63 my @libpaths; # places to look for libraries
64 my $coverage; # build for coverage testing
65 my $assert; # build with assertions
66 my $trace_context; # trace context management to stderr
67 GetOptions("help" => \$help,
68            "enable=s" => \@enable,
69            "disable=s" => \@disable,
70            "incpath=s", \@incpaths,
71            "libpath=s" => \@libpaths,
72            "verbose|v" => \$VERBOSE,
73            "nolog" => \$NOLOG,
74            'coverage' => \$coverage,
75            "assert|a" => \$assert,
76            "tracecontext" => \$trace_context);
77
78 setenv();
79
80 if ($ENV{AUTOMATED_TESTING}) {
81   $assert = 1;
82 }
83
84 if ($VERBOSE) { 
85   print "Verbose mode\n"; 
86   require Data::Dumper; 
87   import Data::Dumper qw(Dumper);
88 }
89
90 if ($help) {
91   usage();
92 }
93
94 my @defines;
95
96 if ($NOLOG)   { print "Logging not compiled into module\n"; }
97 else { 
98   push @defines, [ IMAGER_LOG => 1, "Logging system" ];
99 }
100
101 if ($assert) {
102   push @defines, [ IM_ASSERT => 1, "im_assert() are effective" ];
103 }
104
105 if ($DEBUG_MALLOC) {
106   push @defines, [ IMAGER_DEBUG_MALLOC => 1, "Use Imager's DEBUG malloc()" ];
107   print "Malloc debugging enabled\n";
108 }
109
110 if (@enable && @disable) {
111   print STDERR "Only --enable or --disable can be used, not both, try --help\n";
112   exit 1;
113 }
114
115 my %definc;
116 my %deflib;
117 my @incs; # all the places to look for headers
118 my @libs; # all the places to look for libraries
119
120 init();       # initialize global data
121 pathcheck();  # Check if directories exist
122
123 my @enabled_bundled;
124 if (exists $ENV{IM_ENABLE}) {
125   push @enable, split ' ', $ENV{IM_ENABLE};
126 }
127 if (@enable) {
128   my %en = map { lc $_ => 1 } map_bundled(@enable);
129   @enabled_bundled = grep $en{lc $_}, @bundled;
130 }
131 elsif (@disable) {
132   my %dis = map { lc $_ => 1 } map_bundled(@disable);
133   @enabled_bundled = grep !$dis{lc $_}, @bundled;
134 }
135 else {
136   @enabled_bundled = @bundled;
137 }
138
139 # Pick what libraries are used
140 if ($MANUAL) {
141   manual();
142 } else {
143   automatic();
144 }
145
146 my @objs = qw(Imager.o context.o draw.o polygon.o image.o io.o iolayer.o
147               log.o gaussian.o conv.o pnm.o raw.o feat.o combine.o
148               filters.o dynaload.o stackmach.o datatypes.o
149               regmach.o trans2.o quant.o error.o convert.o
150               map.o tags.o palimg.o maskimg.o img8.o img16.o rotate.o
151               bmp.o tga.o color.o fills.o imgdouble.o limits.o hlines.o
152               imext.o scale.o rubthru.o render.o paste.o compose.o flip.o
153               perlio.o);
154
155 my $lib_define = '';
156 my $lib_inc = '';
157 my $lib_libs = '';
158 for my $frmkey (sort { $formats{$a}{order} <=> $formats{$b}{order} } keys %formats) {
159   my $frm = $formats{$frmkey};
160   if ($frm->{enabled}) {
161     push @defines, [ $frm->{def}, 1, "$frmkey available" ];
162     push @objs, $frm->{objfiles};
163     $lib_define .= " $frm->{DEFINE}" if $frm->{DEFINE};
164     $lib_inc    .= " $frm->{INC}"    if $frm->{INC};
165     $lib_libs   .= " $frm->{LIBS}"   if $frm->{LIBS};
166   }
167 }
168
169 my $OSLIBS = '';
170 my $OSDEF  = "-DOS_$^O";
171
172 if ($^O eq 'hpux')                { $OSLIBS .= ' -ldld'; }
173 if (defined $Config{'d_dlsymun'}) { $OSDEF  .= ' -DDLSYMUN'; }
174
175 if ($Config{useithreads}) {
176   if ($Config{i_pthread}) {
177     print "POSIX threads\n";
178     push @objs, "mutexpthr.o";
179   }
180   elsif ($^O eq 'MSWin32') {
181     print "Win32 threads\n";
182     push @objs, "mutexwin.o";
183   }
184   else {
185     print "Unsupported threading model\n";
186     push @objs, "mutexnull.o";
187     if ($ENV{AUTOMATED_TESTING}) {
188       die "OS unsupported: no threading support code for this platform\n";
189     }
190   }
191 }
192 else {
193   print "No threads\n";
194   push @objs, "mutexnull.o";
195 }
196
197 my @typemaps = qw(typemap.local typemap);
198 if ($] < 5.008) {
199     unshift @typemaps, "typemap.oldperl";
200 }
201
202 if ($trace_context) {
203   $CFLAGS .= " -DIMAGER_TRACE_CONTEXT";
204 }
205
206 my $tests = 't/*.t t/*/*.t';
207 if (-d "xt" && scalar(() = glob("xt/*.t"))) {
208   $tests .= " xt/*.t";
209 }
210
211 my %opts=
212   (
213    NAME         => 'Imager',
214    VERSION_FROM => 'Imager.pm',
215    LIBS         => "$LFLAGS -lm $lib_libs $OSLIBS",
216    DEFINE       => "$OSDEF $lib_define $CFLAGS",
217    INC          => "$lib_inc $DFLAGS",
218    OBJECT       => join(' ', @objs),
219    DIR          => [ sort grep -d, @enabled_bundled, @extras ],
220    clean          => { FILES=>'testout rubthru.c scale.c conv.c  filters.c gaussian.c render.c rubthru.c' },
221    PM             => gen_PM(),
222    PREREQ_PM      =>
223    { 
224     'Test::More' => 0.47,
225     'Scalar::Util' => 1.00,
226     'XSLoader'    => 0,
227    },
228    TYPEMAPS       => \@typemaps,
229    test =>        { TESTS => $tests },
230   );
231
232 if ($coverage) {
233     if ($Config{gccversion}) {
234         push @ARGV, 'OPTIMIZE=-ftest-coverage -fprofile-arcs -g';
235         $opts{dynamic_lib} = { OTHERLDFLAGS => '-ftest-coverage -fprofile-arcs' };
236     }
237     else {
238         die "Don't know the coverage C flags for your compiler\n";
239     }
240 }
241
242 # eval to prevent warnings about versions with _ in them
243 my $MM_ver = eval $ExtUtils::MakeMaker::VERSION;
244 if ($MM_ver > 6.06) {
245   $opts{AUTHOR} = 'Tony Cook <tonyc@cpan.org>, Arnar M. Hrafnkelsson';
246   $opts{ABSTRACT} = 'Perl extension for Generating 24 bit Images';
247 }
248
249 if ($MM_ver >= 6.46) {
250   $opts{META_MERGE} =
251     {
252      recommends =>
253      {
254       "Parse::RecDescent" => 0
255      },
256      license => "perl",
257      dynamic_config => 1,
258      no_index =>
259      {
260       directory =>
261       [
262        "PNG",
263        "GIF",
264        "TIFF",
265        "JPEG",
266        "W32",
267        "FT2",
268        "T1",
269       ],
270      },
271      resources =>
272      {
273       homepage => "http://imager.perl.org/",
274       repository => "git://git.imager.perl.org/imager.git",
275       bugtracker => "http://rt.cpan.org/NoAuth/Bugs.html?Dist=Imager",
276      },
277     };
278 }
279
280 make_imconfig(\@defines);
281
282 if ($VERBOSE) { print Dumper(\%opts); }
283 mkdir('testout',0777); # since we cannot include it in the archive.
284
285 -d "probe" and rmdir "probe";
286
287 WriteMakefile(%opts);
288
289 my @good;
290 my @bad;
291 for my $name (sort { lc $a cmp lc $b } keys %IMAGER_LIBS) {
292   if ($IMAGER_LIBS{$name}) {
293     push @good, $name;
294   }
295   else {
296     push @bad, $name;
297   }
298 }
299
300 print "\n";
301 print "Libraries found:\n" if @good;
302 print "  $_\n" for @good;
303 print "Libraries *not* found:\n" if @bad;
304 print "  $_\n" for @bad;
305
306 exit;
307
308
309 sub MY::postamble {
310     my $self = shift;
311     my $perl = $self->{PERLRUN} ? '$(PERLRUN)' : '$(PERL)';
312     my $mani = maniread;
313
314     my @ims = grep /\.im$/, keys %$mani;
315 '
316 dyntest.$(MYEXTLIB) : dynfilt/Makefile
317         cd dynfilt && $(MAKE) $(PASTHRU)
318
319 lib/Imager/Regops.pm : regmach.h regops.perl
320         $(PERL) regops.perl regmach.h lib/Imager/Regops.pm
321
322 imconfig.h : Makefile.PL
323         $(ECHO) "imconfig.h out-of-date with respect to $?"
324         $(PERLRUN) Makefile.PL
325         $(ECHO) "==> Your Makefile has been rebuilt - re-run your make command <=="
326 '.qq!
327 lib/Imager/APIRef.pod : \$(C_FILES) \$(H_FILES) apidocs.perl
328         $perl apidocs.perl lib/Imager/APIRef.pod
329
330 !.join('', map _im_rule($perl, $_), @ims)
331
332 }
333
334 sub _im_rule {
335   my ($perl, $im) = @_;
336
337   (my $c = $im) =~ s/\.im$/.c/;
338   return <<MAKE;
339
340 $c: $im lib/Imager/Preprocess.pm
341         $perl -Ilib -MImager::Preprocess -epreprocess $im $c
342
343 MAKE
344
345 }
346
347 # manual configuration of helper libraries
348
349 sub manual {
350   print <<EOF;
351
352       Please answer the following questions about
353       which formats are avaliable on your computer
354
355       Warning: if you use manual configuration you are responsible for
356       configuring extra include/library directories as necessary using
357       INC and LIBS command-line assignments.
358
359 press <return> to continue
360 EOF
361
362   <STDIN>; # eat one return
363
364   for my $frm(sort { $formats{$b}{order} <=> $formats{$a}{order} } keys %formats) {
365   SWX:
366     if ($formats{$frm}{docs}) { print "\n",$formats{$frm}{docs},"\n\n"; }
367     print "Enable $frm support: ";
368     my $gz = <STDIN>;
369     chomp($gz);
370     if ($gz =~ m/^(y|yes|n|no)/i) {
371       if ($gz =~ /y/i) {
372         $formats{$frm}{enabled} = 1;
373         $IMAGER_LIBS{$frm} = 1;
374       }
375     } else { goto SWX; }
376   }
377 }
378
379
380 # automatic configuration of helper libraries
381
382 sub automatic {
383   print "Automatic probing:\n" if $VERBOSE;
384
385   if (grep $_ eq "FT1", @enabled_bundled) {
386     my %probe =
387       (
388        name => "FT1",
389        inccheck => sub { -e File::Spec->catfile($_[0], "ftnameid.h") },
390        libbase => "ttf",
391        testcode => _ft1_test_code(),
392        testcodeheaders => [ "freetype.h", "stdio.h" ],
393        incpaths => \@incpaths,
394        libpaths => \@libpaths,
395        alternatives =>
396        [
397         {
398          incsuffix => "freetype",
399         }
400        ],
401        verbose => $VERBOSE,
402       );
403     my $probe_res = Imager::Probe->probe(\%probe);
404     $IMAGER_LIBS{FT1} = defined $probe_res;
405     if ($probe_res) {
406       $formats{FT1}{enabled} = 1;
407       @{$formats{FT1}}{qw/DEFINE INC LIBS/} =
408         @$probe_res{qw/DEFINE INC LIBS/};
409     }
410   }
411 }
412
413 sub pathcheck {
414   if ($VERBOSE) {
415     print "pathcheck\n";
416     print "  Include paths:\n";
417     for (@incs) { print $_,"\n"; }
418   }
419   @incs=grep { -d $_ && -r _ && -x _ or ( print("  $_ doesnt exist or is unaccessible - removed.\n"),0) } @incs;
420
421   if ($VERBOSE) {
422     print "\nLibrary paths:\n";
423     for (@libs) { print $_,"\n"; }
424   }
425   @libs=grep { -d $_ && -r _ && -x _ or ( print("  $_ doesnt exist or is unaccessible - removed.\n"),0) } @libs;
426   print "\ndone.\n";
427 }
428
429
430 # Format data initialization
431
432 # format definition is:
433 # defines needed
434 # default include path
435 # files needed for include (boolean perl code)
436 # default lib path
437 # libs needed
438 # files needed for link (boolean perl code)
439 # object files needed for the format
440
441
442 sub init {
443
444   my @definc = qw(/usr/include);
445   @definc{@definc}=(1) x @definc;
446   @incs=
447     (
448      split(/\Q$Config{path_sep}/, $INCPATH),
449      map _tilde_expand($_), map { split /\Q$Config{path_sep}/ } @incpaths 
450     );
451   if ($Config{locincpth}) {
452     push @incs, grep -d, split ' ', $Config{locincpth};
453   }
454   if ($^O =~ /win32/i && $Config{cc} =~ /\bcl\b/i) {
455     push(@incs, split /;/, $ENV{INCLUDE}) if exists $ENV{INCLUDE};
456   }
457   if ($Config{incpath}) {
458     push @incs, grep -d, split /\Q$Config{path_sep}/, $Config{incpath};
459   }
460   push @incs, grep -d,
461       qw(/sw/include 
462          /usr/include/freetype2
463          /usr/local/include/freetype2
464          /usr/local/include/freetype1/freetype
465          /usr/include /usr/local/include /usr/include/freetype
466          /usr/local/include/freetype);
467   if ($Config{ccflags}) {
468     my @hidden = map { /^-I(.*)$/ ? ($1) : () } split ' ', $Config{ccflags};
469     push @incs, @hidden;
470     @definc{@hidden} = (1) x @hidden;
471   }
472
473   @libs= ( split(/\Q$Config{path_sep}/,$LIBPATH),
474     map _tilde_expand($_), map { split /\Q$Config{path_sep}/} @libpaths );
475   if ($Config{loclibpth}) {
476     push @libs, grep -d, split ' ', $Config{loclibpth};
477   }
478   
479   push @libs, grep -d, qw(/sw/lib),  split(/ /, $Config{'libpth'});
480   push @libs, grep -d, split / /, $Config{libspath} if $Config{libspath};
481   if ($^O =~ /win32/i && $Config{cc} =~ /\bcl\b/i) {
482     push(@libs, split /;/, $ENV{LIB}) if exists $ENV{LIB};
483   }
484   if ($^O eq 'cygwin') {
485     push(@libs, '/usr/lib/w32api') if -d '/usr/lib/w32api';
486     push(@incs, '/usr/include/w32api') if -d '/usr/include/w32api';
487   }
488   if ($Config{ldflags}) {
489     # some builds of perl put -Ldir into ldflags without putting it in
490     # loclibpth, let's extract them
491     my @hidden = grep -d, map { /^-L(.*)$/ ? ($1) : () }
492       split ' ', $Config{ldflags};
493     push @libs, @hidden;
494     # don't mark them as seen - EU::MM will remove any libraries
495     # it can't find and it doesn't look for -L in ldflags
496     #@deflib{@hidden} = @hidden;
497   }
498   push @libs, grep -d, qw(/usr/local/lib);
499
500   $formats{FT1}=
501     {
502      order=>'31',
503      def=>'HAVE_LIBTT',
504      objfiles=>'fontft1.o',
505      LIBS => "-lttf",
506      docs=>q{
507 Freetype 1.x supports Truetype fonts and is obsoleted by Freetype 2.x.
508
509 It's probably insecure.
510 }
511                        };
512   # Make fix indent
513   for (keys %formats) { $formats{$_}->{docs} =~ s/^\s+/  /mg; }
514 }
515
516
517
518 sub gen {
519   my $V = $ENV{$_[0]};
520   print "  $_[0]: '$V'\n"
521       if $VERBOSE && defined $V;
522   defined($V) ? $V : "";
523 }
524
525
526 # Get information from environment variables
527
528 sub getenv {
529
530   $VERBOSE ||= gen("IM_VERBOSE");
531
532   print "Environment config:\n" if $VERBOSE;
533
534   ($INCPATH,
535    $LIBPATH,
536    $NOLOG,
537    $DEBUG_MALLOC,
538    $MANUAL,
539    $CFLAGS,
540    $LFLAGS,
541    $DFLAGS) = map { gen $_ } qw(IM_INCPATH
542                                 IM_LIBPATH
543                                 IM_NOLOG
544                                 IM_DEBUG_MALLOC
545                                 IM_MANUAL
546                                 IM_CFLAGS
547                                 IM_LFLAGS
548                                 IM_DFLAGS);
549 }
550
551 # populate the environment so that sub-modules get the same info
552 sub setenv {
553   $ENV{IM_VERBOSE} = 1 if $VERBOSE;
554   $ENV{IM_INCPATH} = join $Config{path_sep}, @incpaths if @incpaths;
555   $ENV{IM_LIBPATH} = join $Config{path_sep}, @libpaths if @libpaths;
556 }
557
558 sub make_imconfig {
559   my ($defines) = @_;
560
561   open CONFIG, "> imconfig.h"
562     or die "Cannot create imconfig.h: $!\n";
563   print CONFIG <<EOS;
564 /* This file is automatically generated by Makefile.PL.
565    Don't edit this file, since any changes will be lost */
566
567 #ifndef IMAGER_IMCONFIG_H
568 #define IMAGER_IMCONFIG_H
569 EOS
570   for my $define (@$defines) {
571     if ($define->[2]) {
572       print CONFIG "\n/*\n  $define->[2]\n*/\n\n";
573     }
574     print CONFIG "#define $define->[0] $define->[1]\n";
575   }
576   if ($Config{gccversion} && $Config{gccversion} =~ /^([0-9]+)/ && $1 > 3) {
577     print CONFIG <<EOS;
578 /*
579
580 Compiler supports the GCC __attribute__((format...)) syntax.
581
582 */
583
584 #define IMAGER_FORMAT_ATTR 1
585
586 EOS
587   }
588
589   if ($Config{d_snprintf}) {
590     print CONFIG <<EOS;
591 /* We can use snprintf() */
592 #define IMAGER_SNPRINTF 1
593
594 EOS
595   }
596
597   if ($Config{d_vsnprintf}) {
598     print CONFIG <<EOS;
599 /* We can use vsnprintf() */
600 #define IMAGER_VSNPRINTF 1
601
602 EOS
603   }
604
605   print CONFIG <<EOS;
606 /*
607  Type and format code for formatted output as with printf.
608
609  This is intended for formatting i_img_dim values.
610 */
611 typedef $Config{ivtype} i_dim_format_t;
612 #define i_DF $Config{ivdformat}
613 EOS
614
615   print CONFIG "\n#endif\n";
616   close CONFIG;
617 }
618
619 sub usage {
620   print STDERR <<EOS;
621 Usage: $0 [--enable feature1,feature2,...] [other options]
622        $0 [--disable feature1,feature2,...]  [other options]
623        $0 --help
624 Possible feature names are:
625   T1-fonts
626 Other options:
627   --verbose | -v
628     Verbose library probing (or set IM_VERBOSE in the environment)
629   --nolog
630     Disable logging (or set IM_NOLOG in the environment)
631   --incpath dir
632     Add to the include search path
633   --libpath dir
634     Add to the library search path
635   --coverage
636     Build for coverage testing.
637   --assert
638     Build with assertions active.
639 EOS
640   exit 1;
641
642 }
643
644 # generate the PM MM argument
645 # I'd prefer to modify the public version, but there doesn't seem to be 
646 # a public API to do that
647 sub gen_PM {
648   my %pm;
649   my $instbase = '$(INST_LIBDIR)';
650
651   # first the basics, .pm and .pod files
652   $pm{"Imager.pm"} = "$instbase/Imager.pm";
653
654   my $mani = maniread();
655
656   for my $filename (keys %$mani) {
657     if ($filename =~ m!^lib/! && $filename =~ /\.(pm|pod)$/) {
658       (my $work = $filename) =~ s/^lib//;
659       $pm{$filename} = $instbase . $work;
660     }
661   }
662
663   # need the typemap
664   $pm{typemap} = $instbase . '/Imager/typemap';
665
666   # and the core headers
667   for my $filename (keys %$mani) {
668     if ($filename =~ /^\w+\.h$/) {
669       $pm{$filename} = $instbase . '/Imager/include/' . $filename;
670     }
671   }
672
673   # and the generated header
674   $pm{"imconfig.h"} = $instbase . '/Imager/include/imconfig.h';
675
676   \%pm;
677 }
678
679 my $home;
680 sub _tilde_expand {
681   my ($path) = @_;
682
683   if ($path =~ m!^~[/\\]!) {
684     defined $home or $home = $ENV{HOME};
685     if (!defined $home && $^O eq 'MSWin32'
686        && defined $ENV{HOMEDRIVE} && defined $ENV{HOMEPATH}) {
687       $home = $ENV{HOMEDRIVE} . $ENV{HOMEPATH};
688     }
689     unless (defined $home) {
690       $home = eval { (getpwuid($<))[7] };
691     }
692     defined $home or die "You supplied $path, but I can't find your home directory\n";
693     $path =~ s/^~//;
694     $path = File::Spec->catdir($home, $path);
695   }
696
697   $path;
698 }
699
700 sub _ft1_test_code {
701   return <<'CODE';
702 TT_Engine engine;
703 TT_Error error;
704
705 error = TT_Init_FreeType(&engine);
706 if (error) {
707    printf("FT1: Could not initialize engine\n");
708    exit(1);
709 }
710
711 return 0;
712 CODE
713 }
714
715 sub map_bundled {
716   my (@names) = @_;
717
718   @names = map { split /,/ } @names;
719
720   my @outnames;
721   for my $name (@names) {
722     push @outnames, $name;
723     push @outnames, $bundled_names{$name}
724       if $bundled_names{$name};
725   }
726
727   @outnames;
728 }
729
730 1;