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