added extra modules to install
[xmltv.git] / Makefile.PL
1 #!/usr/bin/perl -w
2 # $Id: Makefile.PL,v 1.278 2006/04/23 16:26:58 rmeden Exp $
3
4 use ExtUtils::MakeMaker;
5 use Config;
6 use File::Basename ();
7 use File::Find;
8
9 # Don't use ':config pass_through' because that requires Getopt::Long
10 # 2.24 or later, and we don't have a clean way to require that.
11 #
12 use Getopt::Long; Getopt::Long::Configure('pass_through');
13
14 # Suppress 'isn't numeric' warnings from MakeMaker - see
15 # <http://sourceforge.net/tracker/?func=detail&atid=424135&aid=870170&group_id=39046>.
16 #
17 $SIG{__WARN__} = sub {
18     for (my $msg = shift) {
19         $_ = "warning: something's wrong" if not defined;
20         warn $_
21           unless /Argument .+ isn.t numeric in numeric lt .+MakeMaker.pm/;
22     }
23 };
24
25 # ExtUtils::MakeMaker before 6.21 or so has a bug when PREFIX is not
26 # given explicitly -
27 # <http://article.gmane.org/gmane.comp.tv.xmltv.devel/3634>.
28 #
29 unless ($ExtUtils::MakeMaker::VERSION >= 6.21) {
30     if (not grep /^PREFIX=/, @ARGV) {
31         warn "You may want to explicitly give PREFIX to work around MakeMaker bugs.\n";
32     }
33 }
34
35 use strict;
36
37 sub test_module( $$ );
38 sub check_date_manip();
39 sub test_special( $$ );
40 sub targets( $ );
41
42 if ($] == 5.006) {
43     warn <<END
44 Some installations of perl 5.6.0 are buggy and crash while running
45 this script.  If you get 'segmentation fault' below, please report it
46 to the xmltv-users mailing list so we can try to work around the bug.
47 At present the only known fix is to upgrade to a newer perl version
48 such as 5.6.1 or 5.8.3.
49 END
50   ;
51 }
52
53 # A couple of undocumented options to help with building the Windows
54 # distribution even on hosts that don't have all the necessary
55 # modules.  By default, we only warn if dependencies are missing.
56 # If --strict-deps is passed in, then the whole process fails.
57 #
58 my $opt_strictdeps = 0;
59 my $opt_yes = 0;
60 my $opt_default = 0;
61 my $opt_components;
62 GetOptions('strict-deps'  => \$opt_strictdeps,  # be strict about dependencies
63            yes            => \$opt_yes,         # answer yes to all questions
64            default        => \$opt_default,     # answer default to all questions
65            'components=s' => \$opt_components,
66           );
67
68 our $VERSION;
69 $VERSION = '0.5.43';
70
71 # Fragment of Makefile text to give the directory where files should
72 # be installed.  The extra '.' in the middle of the path is to avoid
73 # beginning with '//', which means a network share on Cygwin.
74 #
75 my $location = '$(DESTDIR)/./$(PREFIX)';
76
77 our %extra_constants;
78 %extra_constants
79   = (INST_PLAINDOC   => 'blib/doc',
80      INSTALLPLAINDOC => "$location/share/doc/xmltv-$::VERSION",
81      INST_SHARE      => 'blib/share',
82      INSTALLSHARE    => "$location/share/xmltv",
83
84      # Manual page constants, shouldn't really be needed, but work
85      # around bugs and make sure this stuff is the same across
86      # MakeMaker versions.
87      INSTALLMAN1DIR  => "$location/share/man/man1",
88      INSTALLMAN3DIR  => "$location/share/man/man3",
89
90      # For Debian, the scripts will get .1p and the module will get .3pm.
91      MAN1EXT         => '1p',
92      MAN3EXT         => '3pm',
93
94      # Directory to install into when making Windows binary dist.
95      WINDOWS_DIST    => "xmltv-$VERSION-win32",
96      VERSION         => "$VERSION",
97     );
98
99 # The following lists of dependencies and files to be installed may
100 # get modified later depending on what the user chooses.
101 #
102
103 # Documentation files to be installed.  This is a global variable
104 # because it is accessed by some code we add to MakeMaker.
105 #
106 our @docs;
107 @docs = qw(doc/COPYING doc/QuickStart doc/README.win32 README);
108
109 # Executables to be installed.
110 my @exes
111   = qw(filter/tv_extractinfo_en
112        filter/tv_grep
113        filter/tv_sort
114        filter/tv_to_latex
115        filter/tv_to_text
116        filter/tv_to_potatoe
117        filter/tv_cat
118        filter/tv_split
119        filter/tv_imdb
120        filter/tv_remove_some_overlapping
121        tools/tv_validate_grabber
122        tools/tv_validate_file
123        tools/tv_find_grabbers
124       );
125
126 # Libraries to be installed.
127 my %pm
128   = ('lib/XMLTV.pm'               => '$(INST_LIBDIR)/XMLTV.pm',
129      'lib/TZ.pm'                  => '$(INST_LIBDIR)/XMLTV/TZ.pm',
130      'lib/Clumps.pm'              => '$(INST_LIBDIR)/XMLTV/Clumps.pm',
131      'lib/Usage.pm'               => '$(INST_LIBDIR)/XMLTV/Usage.pm',
132      'lib/Date.pm'                => '$(INST_LIBDIR)/XMLTV/Date.pm',
133      'lib/Version.pm'             => '$(INST_LIBDIR)/XMLTV/Version.pm',
134      'lib/Ask.pm'                 => '$(INST_LIBDIR)/XMLTV/Ask.pm',
135      'lib/Ask/Tk.pm'              => '$(INST_LIBDIR)/XMLTV/Ask/Tk.pm',
136      'lib/Ask/Term.pm'            => '$(INST_LIBDIR)/XMLTV/Ask/Term.pm',
137      'lib/GUI.pm'                 => '$(INST_LIBDIR)/XMLTV/GUI.pm',     
138      'lib/ProgressBar.pm'         => '$(INST_LIBDIR)/XMLTV/ProgressBar.pm',
139      'lib/ProgressBar/None.pm'    => '$(INST_LIBDIR)/XMLTV/ProgressBar/None.pm',
140      'lib/ProgressBar/Term.pm'    => '$(INST_LIBDIR)/XMLTV/ProgressBar/Term.pm',
141      'lib/ProgressBar/Tk.pm'      => '$(INST_LIBDIR)/XMLTV/ProgressBar/Tk.pm',
142      'lib/Summarize.pm'           => '$(INST_LIBDIR)/XMLTV/Summarize.pm',
143      'lib/IMDB.pm'                => '$(INST_LIBDIR)/XMLTV/IMDB.pm',
144      'lib/Gunzip.pm'              => '$(INST_LIBDIR)/XMLTV/Gunzip.pm',
145      'lib/Capabilities.pm'        => '$(INST_LIBDIR)/XMLTV/Capabilities.pm',
146      'lib/Description.pm'        => '$(INST_LIBDIR)/XMLTV/Description.pm',
147      'lib/Configure.pm'           => '$(INST_LIBDIR)/XMLTV/Configure.pm',
148      'lib/Configure/Writer.pm'    => '$(INST_LIBDIR)/XMLTV/Configure/Writer.pm',
149      'lib/Options.pm'             => '$(INST_LIBDIR)/XMLTV/Options.pm',
150      'lib/ValidateFile.pm'        => '$(INST_LIBDIR)/XMLTV/ValidateFile.pm',
151      'lib/ValidateGrabber.pm'     => '$(INST_LIBDIR)/XMLTV/ValidateGrabber.pm',
152      'filter/Grep.pm'             => '$(INST_LIBDIR)/XMLTV/Grep.pm',
153      'grab/Memoize.pm'            => '$(INST_LIBDIR)/XMLTV/Memoize.pm',
154      'grab/Grab_XML.pm'           => '$(INST_LIBDIR)/XMLTV/Grab_XML.pm',
155      'grab/DST.pm'                => '$(INST_LIBDIR)/XMLTV/DST.pm',
156      'grab/Config_file.pm'        => '$(INST_LIBDIR)/XMLTV/Config_file.pm',
157      'grab/Get_nice.pm'           => '$(INST_LIBDIR)/XMLTV/Get_nice.pm',
158      'grab/Mode.pm'               => '$(INST_LIBDIR)/XMLTV/Mode.pm',
159     );
160
161 # Modules required to install.
162 my %prereqs
163   = (
164      'LWP'         => 5.65,
165      # XML::Parser is required by XML::Twig, but older versions have a
166      # bug when $SIG{__DIE__} is set (well, could be a perl bug, but
167      # anyway it doesn't appear with 2.34).
168      #
169      'XML::Parser' => 2.34,
170      'XML::Twig'   => 3.10,
171      'Date::Manip' => 5.42,
172      'XML::Writer' => '0.4.6',
173      'Memoize'     => 0,
174      'Storable'    => 2.04,
175     );
176
177 # Files which are run to generate source code.
178 my %pl_files = ('filter/tv_grep.PL'     => 'filter/tv_grep',
179                 'tools/tv_validate_file.PL'     => 'tools/tv_validate_file',
180                 'tools/tv_validate_grabber.PL'     => 'tools/tv_validate_grabber',
181                 'lib/XMLTV.pm.PL'       => 'lib/XMLTV.pm',
182                );
183
184 # Some tools which are generated from .PL files need the share/
185 # directory passed as an extra argument.
186 #
187 my @need_share = ( 'tools/tv_validate_file',
188                    'tools/tv_validate_grabber',
189                    );
190
191 # Files to be installed in the system-wide share/ directory.
192 my %share_files = ('xmltv.dtd' => 'xmltv.dtd');
193
194 # Files which 'make clean' should remove, but doesn't by default, so
195 # we have to patch it.
196 #
197 my @to_clean = ('filter/tv_grep',
198                 'tools/tv_validate_file',
199                 'tools/tv_validate_grabber',
200                 'lib/XMLTV.pm');
201
202 # Extra dependencies to add to the Makefile.
203 my @deps = ('filter/tv_grep' => [ qw(filter/tv_grep.in pm_to_blib) ],
204             'tools/tv_validate_file' => [ qw(tools/tv_validate_file.in) ],
205             'tools/tv_validate_grabber' => [ qw(tools/tv_validate_grabber.in) ],
206             'lib/XMLTV.pm' => [ 'lib/XMLTV.pm.in' ]);
207
208 # Some grabbers which are generated from .PL files need the share/
209 # directory passed as an extra argument.
210 #
211 my @grab_need_share;
212
213 # 'Recommended but not required'.  It isn't currently handled to have
214 # the same module in both sets.
215 #
216 my %recommended
217   = (
218      # For Debian, we ignore this package, since only the
219      # CGI script uses it and we don't install that.
220      #'Lingua::EN::Numbers::Ordinate' => 0
221      'Lingua::Preferred' => '0.2.4',
222      'Term::ProgressBar' => 2.03,
223      'Compress::Zlib' => 0,
224      'Unicode::String' => 0,
225     );
226
227 # And Log::TraceMessages is 'suggested' but we don't warn about that.
228
229 if ($opt_yes) {
230     *ask = sub { print "$_[0] yes\n"; 1 };
231 }
232 elsif ($opt_default) {
233     *ask = sub { print "$_[0] $_[2]\n"; $_[2] };
234 }
235 else {
236     require 'lib/Ask/Term.pm';
237     *ask = \&XMLTV::Ask::Term::ask_boolean;
238 }
239
240 # Weird shit happens when you change things like PREFIX without
241 # rebuilding everything explicitly.
242 #
243 if (-e 'Makefile') {
244     warn <<END
245 There is already a Makefile.  To avoid weird problems it is
246 recommended you run 'make distclean' to clear out old built files
247 before generating a new Makefile.
248
249 END
250   ;
251     if (! ask(0, "Do you wish to continue anyway?", 0)) {
252         exit(1);
253     }
254 }
255
256 # Now prompt about how much to install.  This is really only to
257 # reduce dependencies.  In the long run things like tv_check can be
258 # spun off into separate projects.
259 #
260 my @opt_components
261   = (
262
263 # tv_grab_de not currently working
264 #     { name => 'tv_grab_de',
265 #       blurb => 'Grabber for Germany and Austria',
266 #       exes => [ 'grab/de/tv_grab_de' ],
267 #     },
268
269 # Disabled 2006-04-12 since it doesn't provide data anymore.
270 #     { name     => 'tv_grab_au',
271 #       blurb    => 'Grabber for Australia',
272 #       exes     => [ 'grab/au/tv_grab_au' ],
273 #       deps     => [ 'grab/au/tv_grab_au' => [ 'grab/au/tv_grab_au.in' ] ],
274 #       pl_files => { 'grab/au/tv_grab_au.PL' => 'grab/au/tv_grab_au' },
275 #       to_clean => [ 'grab/au/tv_grab_au' ],
276 #       share_files => { 'grab/au/channel_ids' => 'tv_grab_au/channel_ids' },
277 #       grab_need_share => [ 'au' ],
278 #     },
279
280      { name => 'tv_grab_br',
281        blurb => 'Grabber for Brazil',
282        exes => [ 'grab/br/tv_grab_br' ],
283        prereqs => { 'HTML::TreeBuilder' => 0 ,
284                     'HTML::Entities' => 1.27 , }
285      },
286
287      { name => 'tv_grab_br_net',
288        blurb => 'Grabber for Brazil NET Cable',
289        exes => [ 'grab/br_net/tv_grab_br_net' ],
290        prereqs => { 'WWW::Mechanize' => 1.16 ,
291                     'HTTP::Cookies' => 1.39 , }
292      },
293
294      { name     => 'tv_grab_ch',
295        blurb    => 'Grabber for Switzerland',
296        exes     => [ 'grab/ch/tv_grab_ch' ],
297        deps     => [ 'grab/ch/tv_grab_ch' => [ 'grab/ch/tv_grab_ch.in' ] ],
298        pl_files => { 'grab/ch/tv_grab_ch.PL' => 'grab/ch/tv_grab_ch' },
299        to_clean => [ 'grab/ch/tv_grab_ch' ],
300        share_files => { 'grab/ch/channel_ids' => 'tv_grab_ch/channel_ids' },
301        grab_need_share => [ 'ch' ],
302      },
303
304      { name => 'tv_grab_uk_rt',
305        blurb => 'Alternative grabber for Britain',
306        exes => [ 'grab/uk_rt/tv_grab_uk_rt' ],
307        pl_files => { 'grab/uk_rt/tv_grab_uk_rt.PL' => 'grab/uk_rt/tv_grab_uk_rt' },
308        share_files => { 'grab/uk_rt/channel_ids' => 'tv_grab_uk_rt/channel_ids' },
309        to_clean => [ 'grab/uk_rt/tv_grab_uk_rt' ],
310        deps => [ 'grab/uk_rt/tv_grab_uk_rt' => [ 'grab/uk_rt/tv_grab_uk_rt.in' ] ],
311        grab_need_share => [ 'uk_rt' ],
312        prereqs => { 'HTML::Entities' => 1.27 } ,
313      },
314
315      { name => 'tv_grab_uk_bleb',
316        blurb => 'Fast alternative grabber for the UK',
317        exes => [ 'grab/uk_bleb/tv_grab_uk_bleb' ],
318        pl_files => { 'grab/uk_bleb/tv_grab_uk_bleb.PL' => 'grab/uk_bleb/tv_grab_uk_bleb' },
319        share_files => { 'grab/uk_bleb/icon_urls' => 'tv_grab_uk_bleb/icon_urls' },
320        to_clean => [ 'grab/uk_bleb/tv_grab_uk_bleb' ],
321        deps => [ 'grab/uk_bleb/tv_grab_uk_bleb' => [ 'grab/uk_bleb/tv_grab_uk_bleb.in' ] ],
322        grab_need_share => [ 'uk_bleb' ],
323        prereqs => { 'IO::Scalar' => 0, 'Archive::Zip' => 0 },
324      },
325
326      { name => 'tv_grab_be',
327        blurb => 'Grabber for Belgium and Luxemburg',
328        exes => [ 'grab/be/tv_grab_be' ],
329        pl_files => { 'grab/be/tv_grab_be.PL' => 'grab/be/tv_grab_be' },
330        share_files => { 'grab/be/channel_ids_fr' => 'tv_grab_be/channel_ids_fr',
331                         'grab/be/channel_ids_nl' => 'tv_grab_be/channel_ids_nl' },
332        to_clean => [ 'grab/be/tv_grab_be' ],
333        deps => [ 'grab/be/tv_grab_be' => [ 'grab/be/tv_grab_be.in' ] ],
334        grab_need_share => [ 'be' ],
335        prereqs => { 'HTML::Entities' => 1.27 } ,
336      },
337
338      { name => 'tv_grab_is',
339        blurb => 'Grabber for Iceland',
340        exes => [ 'grab/is/tv_grab_is' ],
341      },
342
343      { name => 'tv_grab_it',
344        blurb => 'Grabber for Italy',
345        exes => [ 'grab/it/tv_grab_it' ],
346        pl_files => { 'grab/it/tv_grab_it.PL' => 'grab/it/tv_grab_it' },
347        share_files => { 'grab/it/channel_ids' => 'tv_grab_it/channel_ids' },
348        to_clean => [ 'grab/it/tv_grab_it', 'grab/it/tv_grab_it.in2' ],
349        deps => [ 'grab/it/tv_grab_it' => [ 'grab/it/tv_grab_it.in' ] ],
350        grab_need_share => [ 'it' ],
351      },
352
353      { name     => 'tv_grab_na_dd',
354        blurb => 'Grabber for North America using DataDirect',
355        exes     => [ 'grab/na_dd/tv_grab_na_dd' ],
356        pl_files => { 'grab/na_dd/tv_grab_na_dd.PL' => 'grab/na_dd/tv_grab_na_dd' },
357        deps     => [ 'grab/na_dd/tv_grab_na_dd' => [ 'grab/na_dd/tv_grab_na_dd.in' ] ],
358        to_clean => [ 'grab/na_dd/tv_grab_na_dd' ],
359        prereqs => { 'SOAP::Lite' => 0,
360                     'Term::ReadKey' => 0 },
361        grab_need_share => [ 'na_dd' ],
362      },
363
364      { name     => 'tv_grab_na_icons',
365        blurb    => 'Grabber for North American Channel Icons',
366        exes     => [ 'grab/na_icons/tv_grab_na_icons' ],
367        deps     => [ 'grab/na_icons/tv_grab_na_icons' => [ 'grab/na_icons/tv_grab_na_icons.in' ] ],
368        pl_files => { 'grab/na_icons/tv_grab_na_icons.PL' => 'grab/na_icons/tv_grab_na_icons' },
369        to_clean => [ 'grab/na_icons/tv_grab_na_icons' ],
370        prereqs  => { 'HTML::TableExtract' => 0,
371                     'WWW::Mechanize' => 1.02 },
372        grab_need_share => [ 'na_icons' ],
373      },
374
375      { name => 'tv_grab_fi',
376        blurb => 'Grabber for Finland',
377        exes => [ 'grab/fi/tv_grab_fi' ],
378        prereqs => { 'HTML::TreeBuilder' => 0 } },
379
380      { name => 'tv_grab_es',
381        blurb => 'Grabber for Spain - Analogic Terrestrial/Cable',
382        exes => [ 'grab/es/tv_grab_es' ],
383        prereqs => { 'HTML::TreeBuilder' => 0 } },
384
385 #Removed for Debian due to missing Locale::Hebrew dependency                     
386 #     { name => 'tv_grab_il',
387 #       blurb => 'Grabber for Israel',
388 #       exes => [ 'grab/il/tv_grab_il' ],
389 #       prereqs => { 'HTML::TreeBuilder' => 0, 
390 #                    'Locale::Hebrew' => 0 } },
391
392 #
393 # tv_grab_es_digital no longer functioning due to site changes
394 #
395 #     { name => 'tv_grab_es_digital',
396 #       blurb => 'Grabber for Spain - Digital Satellite (D+)',
397 #       exes => [ 'grab/es_digital/tv_grab_es_digital' ],
398 #       prereqs => { 'HTML::TreeBuilder' => 0 } },
399
400      { name => 'tv_grab_nl',
401        blurb => 'Grabber for the Netherlands',
402        exes => [ 'grab/nl/tv_grab_nl' ],
403        prereqs => { 'HTML::TreeBuilder' => 0 },
404      },
405
406      { name => 'tv_grab_nl_wolf',
407        blurb => 'Alternative grabber for the Netherlands',
408        exes => [ 'grab/nl_wolf/tv_grab_nl_wolf' ],
409        prereqs => { 'HTML::TreeBuilder' => 0 } },
410
411      { name => 'tv_grab_huro',
412        blurb => 'Grabber for Hungary and Romania',
413        exes => [ 'grab/huro/tv_grab_huro' ],
414        pl_files => { 'grab/huro/tv_grab_huro.PL'
415                      => 'grab/huro/tv_grab_huro' },
416        share_files => { 'grab/huro/jobmap'
417                         => 'tv_grab_huro/jobmap',
418                         'grab/huro/catmap.hu'
419                         => 'tv_grab_huro/catmap.hu',
420                         'grab/huro/catmap.ro'
421                         => 'tv_grab_huro/catmap.ro' },
422        to_clean => [ 'grab/huro/tv_grab_huro' ],
423        deps => [ 'grab/huro/tv_grab_huro'
424                  => [ 'grab/huro/tv_grab_huro.in' ] ],
425        grab_need_share => [ 'huro' ],
426        prereqs => { 'HTML::TreeBuilder' => 0 } },
427
428      { name => 'tv_grab_dk',
429        blurb => 'Grabber for Denmark',
430        exes => [ 'grab/dk/tv_grab_dk' ],
431        prereqs => { 'HTML::TreeBuilder' => 0 } },
432
433      { name => 'tv_grab_jp',
434        blurb => 'Grabber for Japan',
435        exes => [ 'grab/jp/tv_grab_jp' ],
436        prereqs => { 'HTML::TreeBuilder' => 0,
437                     'Text::Kakasi' => 0 } },
438
439      { name => 'tv_grab_de_tvtoday',
440        blurb => 'Grabber for Germany',
441        exes => [ 'grab/de_tvtoday/tv_grab_de_tvtoday' ],
442        pl_files => { 'grab/de_tvtoday/tv_grab_de_tvtoday.PL'
443                      => 'grab/de_tvtoday/tv_grab_de_tvtoday' },
444        share_files => { 'grab/de_tvtoday/channel_ids'
445                         => 'tv_grab_de_tvtoday/channel_ids' },
446        to_clean => [ 'grab/de_tvtoday/tv_grab_de_tvtoday' ],
447        deps => [ 'grab/de_tvtoday/tv_grab_de_tvtoday'
448                  => [ 'grab/de_tvtoday/tv_grab_de_tvtoday.in' ] ],
449        grab_need_share => [ 'de_tvtoday' ],
450        prereqs => { 'HTML::Entities' => 1.27,
451                     'HTML::TreeBuilder' => 0 },
452      },
453
454      { name => 'tv_grab_se_swedb',
455        blurb => 'Grabber for Sweden',
456        exes => [ 'grab/se_swedb/tv_grab_se_swedb' ],
457        prereqs => { 'XML::LibXML' => 0,
458                     'Compress::Zlib' => 0,
459                     'IO::Stringy' => 0,
460                     'HTTP::Cache::Transparent' => 0,
461                   },
462      },
463
464      { name => 'tv_grab_fr',
465        blurb => 'Grabber for France',
466        exes => [ 'grab/fr/tv_grab_fr' ],
467        prereqs => { 'HTML::Entities' => 1.27,
468                     'HTML::TreeBuilder' => 0 },
469      },
470
471      { name => 'tv_grab_no',
472        blurb => 'Grabber for Norway',
473        exes => [ 'grab/no/tv_grab_no' ],
474        prereqs => { 'HTML::Entities' => 1.27 },
475      },
476
477 # Removed for Debian due to missing Unicode::UTF8Simple dependency.
478 #     { name => 'tv_grab_pt',
479 #       blurb => 'Grabber for Portugal',
480 #       exes => [ 'grab/pt/tv_grab_pt' ],
481 #       prereqs => { 'HTML::TreeBuilder' => 0,
482 #                    'Unicode::UTF8simple' => 0,
483 #                  }
484 #     },
485
486      { name => 'tv_grab_za',
487        blurb => 'Grabber for South Africa',
488        exes => [ 'grab/za/tv_grab_za' ],
489        prereqs => { 'HTML::TreeBuilder' => 0,
490                     'HTML::Entities' => 1.27 } },
491
492      { name => 'tv_check',
493        blurb => 'Program to report exceptions and changes in a schedule',
494        exes => [ 'choose/tv_check/tv_check' ],
495        docs => [ qw(choose/tv_check/README.tv_check
496                     choose/tv_check/tv_check_doc.html
497                     choose/tv_check/tv_check_doc.jpg
498                    ) ],
499        prereqs => { 'Tk' => 0,
500                     'Tk::TableMatrix' => 0,
501                   } },
502
503      { name => 'tv_pick_cgi',
504        blurb => 'CGI program to filter listings (to install manually)',
505        prereqs => { 'CGI' => 0 },
506        type => 'run',
507      },
508
509      { name => 'tv_grab_ee',
510        blurb => 'Grabber for Estonia',
511        exes => [ 'grab/ee/tv_grab_ee' ],
512        prereqs => { 'LWP::Simple' => 0 } },
513
514     { name => 'tv_grab_re',
515        blurb => 'Grabber for Reunion Island (France)',
516        exes => [ 'grab/re/tv_grab_re' ],
517        prereqs => { 'HTML::TreeBuilder' => 0 ,
518                     'HTML::Entities'    => 0 } },
519     );
520
521 # Now we need to prompt about each optional component.  The style of
522 # prompting, though not the code, is based on SOAP::Lite.  I would
523 # like to add '--noprompt' and '--with tv_grab_nl' options to help
524 # automated package building, but I haven't implemented that yet.
525 #
526
527 # For each component work out whether its prereqs are installed and
528 # store the result in {missing} - either false, or a hashref.
529 #
530 foreach my $info (@opt_components) {
531     my $name = $info->{name};
532     my %modules_missing;
533     our %module_prereqs;
534     local *module_prereqs = $info->{prereqs} || {};
535     foreach (sort keys %module_prereqs) {
536         my $ver = $module_prereqs{$_};
537         next if test_module($_, $ver)->[0] eq 'OK';
538         warn "strange, module prereq $_ mentioned twice"
539           if defined $modules_missing{$_};
540         $modules_missing{$_} = $ver;
541     }
542
543     our @special_prereqs;
544     my %special_missing;
545     local *special_prereqs = $info->{special_prereqs} || {};
546     foreach (@special_prereqs) {
547         my ($sub, $name, $ver, $friendly_ver) = @$_;
548         next if test_special($sub, $ver)->[0] eq 'OK';
549         warn "strange, special prereq $name mentioned twice"
550           if defined $special_missing{$name};
551         $special_missing{$name} = $friendly_ver;
552     }
553         
554     my %missing = (%modules_missing, %special_missing);
555     if (not keys %missing) {
556         $info->{missing} = 0;
557     }
558     else {
559         $info->{missing} = \%missing;
560     }
561 }
562
563 if (not defined $opt_components) {
564     # Generate a default configuration that installs as much as possible.
565     print STDERR <<END
566
567 Choose which optional components of xmltv you want to install.  The
568 XMLTV.pm library and the filter programs such as tv_grep and tv_sort
569 are installed by default; here you choose grabbers for different
570 countries and front-ends for managing listings.
571
572 END
573       ;
574
575     my $width = 0;
576     foreach my $info (@opt_components) {
577         my $w = length("$info->{blurb} ($info->{name})");
578         $width = $w if $w > $width;
579     }
580     foreach my $info (@opt_components) {
581         my $missing = $info->{missing};
582         my $s = "$info->{blurb} ($info->{name})";
583
584         # Guess a default value for {install} based on whether
585         # prerequisites were found.
586         #
587         $info->{install} = $opt_yes || not $info->{missing};
588
589         print STDERR ($s, ' ' x (1 + $width - length $s),
590                       $info->{install} ? '[yes]' : '[no]',
591                       "\n");
592     }
593     print STDERR "\n";
594     if (not ask(0, 'Do you want to proceed with this configuration?', 1)) {
595         # Need to set {install} for each component by prompting.
596         foreach my $info (@opt_components) {
597             my $missing = $info->{missing};
598             my $name = $info->{name};
599             print STDERR "\n* $info->{blurb} ($name)\n\n";
600             if ($missing) {
601                 print STDERR "These dependencies are missing for $name:\n\n";
602                 foreach (sort keys %$missing) {
603                     print STDERR "$_";
604                     my $min_ver = $missing->{$_};
605                     if ($min_ver) {
606                         print STDERR " (version $min_ver or higher)";
607                     }
608                     print STDERR "\n";
609                 }
610                 print STDERR "\n";
611             }
612
613             my $msg;
614             my $type = $info->{type};
615             if (not defined $type or $type eq 'install') {
616                 $msg = "Do you wish to install $name?";
617             } elsif ($type eq 'run') {
618                 $msg = "Do you plan to run $name?";
619             } else {
620                 die;
621             }
622         
623             $info->{install} =
624               ask(0, $msg, not $missing);
625         }
626     }
627 }
628 else {
629     my @to_install = split /\s+/, $opt_components;
630     my %by_name;
631     foreach (@opt_components) {
632         $by_name{$_->{name}} = $_;
633         $_->{install} = 0; # default if not mentioned
634     }
635     foreach (@to_install) {
636         my $i = $by_name{$_};
637         die "unknown component $_\n" if not $i;
638         $i->{install} = 1;
639     }
640 }       
641
642 foreach my $info (@opt_components) {
643     next if not $info->{install};
644     push @exes, @{$info->{exes}}                  if $info->{exes};
645     push @docs, @{$info->{docs}}                  if $info->{docs};
646     %pm = (%pm, %{$info->{pm}})                   if $info->{pm};
647     %prereqs = (%prereqs, %{$info->{prereqs}})    if $info->{prereqs};
648     %pl_files = (%pl_files, %{$info->{pl_files}}) if $info->{pl_files};
649     %share_files = (%share_files, %{$info->{share_files}})
650       if $info->{share_files};
651     push @to_clean, @{$info->{to_clean}}          if $info->{to_clean};
652     push @deps, @{$info->{deps}}                  if $info->{deps};
653     push @grab_need_share, @{$info->{grab_need_share}}
654       if $info->{grab_need_share};
655 }
656
657 my $warned_uninstall_broken = 1;
658
659
660 # Test the installed version of a module.
661 #
662 # Parameters:
663 #   Name of module
664 #   Version required, or 0 for don't care
665 #
666 # Returns a tuple of two scalars: the first scalar is one of
667 #
668 # OK            - a recent enough version is installed.
669 # NOT_INSTALLED - the module is not installed.
670 # FAILED        - the second scalar contains an error message.
671 # TOO_OLD       - the second scalar contains the version found.
672 #
673 sub test_module( $$ ) {
674     my ($mod, $minver) = @_;
675     die if not defined $mod; die if not defined $minver;
676     eval "require $mod";
677     if ($@) {
678         # This if-test is separate to suppress spurious 'Use of
679         # uninitialized value in numeric lt (<)' warning.
680         #
681         if ($@ ne '') {
682             if ($@ =~ /^Can\'t locate \S+\.pm in \@INC/) {
683                 return [ 'NOT_INSTALLED', undef ];
684             }
685             else {
686                 chomp (my $msg = $@);
687                 return [ 'FAILED', $msg ];
688             }
689         }
690     }
691
692     my $ver = $mod->VERSION;
693     if ($minver ne '0') {
694         return [ 'TOO_OLD', undef ] if not defined $ver;
695         return [ 'TOO_OLD', $ver ] if $ver lt $minver;
696     }
697
698     return [ 'OK', undef ];
699 }
700
701 # Run a subroutine and check that its output has the correct version.
702 #
703 # Parameters:
704 #   code reference to run
705 #   minumum version
706 #
707 # The code ref should return undef meaning 'package not present' or
708 # else a version number.
709 #
710 # Returns as for test_module() (but 'FAILED' not an option).
711 #
712 sub test_special( $$ ) {
713     my ($sub, $minver) = @_;
714     my $ver = $sub->();
715     return [ 'NOT_INSTALLED', undef ] if not defined $ver;
716     if ($minver ne '0') {
717         return [ 'TOO_OLD', undef ] if not defined $ver;
718         return [ 'TOO_OLD', $ver ] if $ver lt $minver;
719     }
720     return [ 'OK', undef ];
721 }
722
723 # MakeMaker's warning message can be intimidating, check ourselves
724 # first.  We warn about missing 'recommended' modules but don't abort
725 # because of them.
726 #
727 my $err = 0;
728 foreach my $p ((sort keys %prereqs), (sort keys %recommended)) {
729     my $required = (defined $prereqs{$p});
730     my $verbed = $required ? 'required' : 'recommended';
731     my $Verbed = uc(substr($verbed, 0, 1)) . substr($verbed, 1);
732     my $minver = $required ? $prereqs{$p} : $recommended{$p};
733     die "bad minver for $p" if not defined $minver;
734     my ($r, $more) = @{test_module($p, $minver)};
735     if ($r eq 'OK') {
736         # Installed and recent enough.
737     }
738     elsif ($r eq 'NOT_INSTALLED') {
739         print STDERR "Module $p seems not to be installed.\n";
740         print(($minver ? "$p $minver" : $p), " is $verbed.\n");
741         ++ $err if $required;
742     }
743     elsif ($r eq 'FAILED') {
744         print STDERR "$Verbed module $p failed to load: $more\n";
745         print(($minver ? "$p $minver" : $p), " is $verbed.\n");
746         ++ $err if $required;
747     }
748     elsif ($r eq 'TOO_OLD') {
749         if (defined $more) {
750             print STDERR "$p-$minver is $verbed, but $more is installed\n";
751         }
752         else {
753             print STDERR "$p-$minver is $verbed, but an unknown version is installed\n";
754         }
755         ++ $err if $required;
756     }
757     else { die }
758 }
759 if ($err) {
760     if ($opt_strictdeps) {
761         die "Required modules missing.  Makefile will not be created.\n";
762     }
763     else {
764         warn "Required modules missing, 'make' is unlikely to work\n";
765     }
766 }
767
768 WriteMakefile
769   (
770    'NAME'          => 'XMLTV',
771    # No VERSION_FROM, it's set in this file
772    'EXE_FILES'     => \@exes,
773    'PL_FILES'      => \%pl_files,
774    'PM'            => \%pm,
775    'PREREQ_PM'     => \%prereqs,
776     # No special parameters for 'make clean' or 'make dist'
777 );
778
779
780 sub MY::constants {
781     package MY;
782     my $inherited = shift->SUPER::constants(@_);
783     die if not keys %::extra_constants;
784     foreach (sort keys %::extra_constants) {
785         $inherited .= "$_ = $::extra_constants{$_}\n";
786     }
787     return $inherited;
788 }
789 sub MY::install {
790     package MY;
791     my $inherited = shift->SUPER::install(@_);
792
793     # Decided that 'plaindoc_install' should be directly under
794     # 'install', not under the misleadingly named 'doc_install'.
795     #
796     my %extra_deps = (install => [ 'plaindoc_install', 'share_install' ]);
797     foreach my $t (keys %extra_deps) {
798         foreach my $d (@{$extra_deps{$t}}) {
799             $inherited =~ s/^(\s*$t\s+::\s.+)/$1 $d/m or die;
800         }
801     }
802
803     foreach (qw(plaindoc share)) {
804         my $target = $_ . '_install';
805         my $uc = uc;
806
807         my $inst_var = "INST_$uc";
808         my $extra = <<END
809 # Add code to create the directory under blib/.
810 \$($inst_var)/.exists :: \$(PERL_INC)/perl.h
811         \@\$(MKPATH) \$($inst_var)
812         \@\$(EQUALIZE_TIMESTAMP) \$(PERL_INC)/perl.h \$($inst_var)/.exists
813         -\@\$(CHMOD) \$(PERM_RWX) \$($inst_var)
814
815 # Create a target to install to the final location.
816 $target ::
817         \@echo Installing contents of \$(INST_$uc) into \$(INSTALL$uc)
818         \@\$(MOD_INSTALL) \\
819                 \$(INST_$uc) \$(INSTALL$uc)
820
821 END
822   ;
823         $extra =~ s/ {8}/\t/g;
824         $inherited .= $extra;
825     }
826
827     # Remove existing non-working 'uninstall' target.
828     $inherited =~ s!^uninstall\s:.*$!!m
829       or die "no uninstall target in: $inherited";
830
831     # For each *_install create a corresponding _uninstall.
832     my $targets = ::targets($inherited);
833     foreach (qw(pure_perl_install pure_site_install plaindoc_install share_install)) {
834         die "no $_ in: $inherited" if not defined $targets->{$_};
835         my @t = @{$targets->{$_}}; # make a copy
836         my $done = 0;
837         foreach (@t) {
838             if (s/\@\$\(MOD_INSTALL\)/\$(PERL) -I. -MUninstall -e "uninstall(\@ARGV)"/) {
839                 $done = 1;
840                 last;
841             }
842             s/Installing contents of (\S+) into (\S+)/Removing contents of $1 from $2/;
843         }
844         if (not $done) {
845             print STDERR "couldn't find \@\$(MOD_INSTALL) in target $_, uninstall may not work\n"
846               unless $warned_uninstall_broken;
847         }
848         (my $new_target = $_) =~ s/install$/uninstall/ or die;
849         foreach ("\n\n$new_target ::\n", @t) {
850             $inherited .= $_;
851         }
852     }
853     $inherited .= 'pure_uninstall :: pure_$(INSTALLDIRS)_uninstall' . "\n";
854     $inherited .= 'uninstall :: all pure_uninstall plaindoc_uninstall share_uninstall' . "\n";
855
856     # Add a target for a Windows distribution.  Note this is
857     # singlequoted and then we substitute one variable by hand!
858     #
859     $inherited .= q{
860
861 xmltv.exe :: $(EXE_FILES) lib/exe_wrap.pl lib/exe_opt.pl
862         echo $(EXE_FILES)                             >exe_files.txt
863         perl lib/exe_opt.pl $(VERSION)                >exe_opt.txt
864         echo -lib  $(INST_ARCHLIB) --lib $(INST_LIB) >>exe_opt.txt
865         echo -add  "$(EXE_FILES)"                    >>exe_opt.txt
866         echo -bind exe_files.txt                     >>exe_opt.txt
867         echo -exe  xmltv.exe                         >>exe_opt.txt
868         perlapp @exe_opt.txt lib/exe_wrap.pl
869         $(RM_F) exe_files.txt
870         $(RM_F) exe_opt.txt
871
872 windows_dist ::
873         @perl -e "if (-e '$location') { print STDERR qq[To build a Windows distribution, please rerun Makefile.PL with\nPREFIX set to a new (nonexistent) directory then 'make windows_dist'.\n(Remember that only absolute paths work properly with MakeMaker.)\n]; exit 1 }"
874         @perl -e 'print "Have you updated doc/README.win32 for this release? "; exit 1 unless <STDIN> =~ /^[yY]/'
875         $(MAKE) install
876         perl -MExtUtils::Command -e mv $(INSTALLPLAINDOC) $location/doc/
877         perl -MExtUtils::Command -e rm_r $location/share/doc
878         perl -MExtUtils::Command -e mkpath $location/doc/man
879         # Generate plain text documentation from pod.
880         perl -e "chdir 'blib/script' or die; foreach (<*>) { system qq'pod2text <\$$_ >$location/doc/man/\$$_.txt' }"
881         # Remove 'real' manual pages, not needed on Windows.
882         perl -MExtUtils::Command -e rm_rf $location/man $location/share/man
883         # My MakeMaker creates this dud directory.
884         perl -MExtUtils::Command -e rm_rf $location/5.8.0
885         rmdir $location/share/doc
886         # Generate Date::Manip docs by filtering perldoc output.  The
887         # use of temp files instead of pipes is so set -e works properly.
888         #
889         echo Extracting part of Date::Manip manual page into $location/doc/man/date_formats.txt
890         echo "This is an extract from the documentation of Perl's Date::Manip module," >>$location/doc/man/date_formats.txt
891         echo "describing the different format strings that may be used for dates."     >>$location/doc/man/date_formats.txt
892         echo "Bear in mind that depending on your Windows version you will need to"    >>$location/doc/man/date_formats.txt
893         echo "quote the % characters on the command line somehow (see README.win32)."  >>$location/doc/man/date_formats.txt
894         echo "" >>$location/doc/man/date_formats.txt
895         perldoc -u Date::Manip >$location/doc/man/date_formats.txt.tmp
896         perl -ne "BEGIN { print qq'\n=pod\n\n' } print if (/^The format options are:/ .. /^=/) and not /^=/" <$location/doc/man/date_formats.txt.tmp >$location/doc/man/date_formats.txt.tmp.1
897         pod2text <$location/doc/man/date_formats.txt.tmp.1 >>$location/doc/man/date_formats.txt
898         perl -MExtUtils::Command -e rm_f $location/doc/man/date_formats.txt.tmp*
899         # Don't use $(INSTALLBIN), it seems to disregard PREFIX passed
900         # to 'make'.
901         #
902         perl -MExtUtils::Command -e rm_rf $location/bin/ $location/lib/ $(INSTMANDIR) $(INSTALLMAN3DIR)
903         perl -MExtUtils::Command -e cp xmltv.dtd $location
904         perl -MExtUtils::Command -e cp ChangeLog $location
905         # The following command will not be necessary when the source
906         # tree was checked out on a DOSish system.  It may not even
907         # work properly when run on a DOSish system - should check.
908         #
909         # (Simulation in perl of find | xargs; there's probably a
910         # better way but I'm too lazy to find it.)
911         #
912         perl -MFile::Find -e "find(sub { print qq[\\$$File::Find::name\n] if -f and not /[.]jpg/ }, '$location')" | perl -e 'chomp(@ARGV = (@ARGV, <STDIN>)); exec @ARGV' perl -i -pe 'BEGIN { binmode STDIN } s/\r*\n*$$/\r\n/'
913         perl -MExtUtils::Command -e mv $location/doc/README* $location
914         perl -MExtUtils::Command -e mv $location/README.win32 $location/README
915         @echo
916         @echo Part of a Windows distribution tree has been made in $location/.
917         @echo Now copy in the executables!
918
919 };
920     $inherited =~ s/\$location/$location/g or die;
921
922     return $inherited;
923 }
924
925 # Extend installbin() to put doc and share under blib/.
926 sub MY::installbin {
927     package MY;
928     my $inherited = shift->SUPER::installbin(@_);
929
930     # Add a target for each documentation file.
931     my %doc_files;
932     foreach (@::docs) {
933         $doc_files{$_} = File::Basename::basename($_);
934     }
935
936     my %new_filetypes = (plaindoc => \%doc_files, share => \%share_files);
937     my %seen_dir;
938     foreach my $filetype (sort keys %new_filetypes) {
939         my $uc = uc $filetype;
940         our %files; local *files = $new_filetypes{$filetype};
941         foreach my $src (sort keys %files) {
942             my $inst_pos = $files{$src};
943             my $extra = '';
944
945             # The directory containing this file in blib/ needs to be created.
946             my @dirs = split m!/!, $inst_pos; pop @dirs;
947             foreach (0 .. $#dirs) {
948                 my $dir = join('/', @dirs[0 .. $_]);
949                 my $parent = join('/', @dirs[0 .. $_-1]);
950                 next if $seen_dir{$dir}++;
951                 die if (length $parent and not $seen_dir{$parent});
952                 my $parent_exists = "\$(INST_$uc)/$parent/.exists";
953                 $parent_exists =~ tr!/!/!s;
954                 $extra .= <<END
955 \$(INST_$uc)/$dir/.exists :: \$(PERL_INC)/perl.h $parent_exists
956         \@\$(MKPATH) \$(INST_$uc)/$dir
957         \@\$(EQUALIZE_TIMESTAMP) \$(PERL_INC)/perl.h \$(INST_$uc)/$dir/.exists
958         -\@\$(CHMOD) \$(PERM_RWX) \$(INST_$uc)/$dir
959 END
960   ;
961             }
962             my $dir_exists = "\$(INST_$uc)/" . join('/', @dirs) . '/.exists';
963             $dir_exists =~ tr!/!/!s;
964
965             $extra .= <<END
966 \$(INST_$uc)/$inst_pos: $src Makefile $dir_exists
967         \@\$(RM_F) \$(INST_$uc)/$inst_pos
968         perl -MExtUtils::Command -e cp $src \$(INST_$uc)/$inst_pos
969         -\@\$(CHMOD) \$(PERM_RW) \$(INST_$uc)/$inst_pos
970 END
971               ;
972             $extra =~ s/ {8}/\t/g;
973             $inherited .= $extra;
974         }
975
976         # These targets need to be added to pure_all, using a new target
977         # pure_$filetype.
978         #
979         $inherited =~ s/^(\s*pure_all\s+::\s.+)/$1 pure_$filetype/m
980           or die "no pure_all in: $inherited";
981         $inherited .= "pure_$filetype :: ";
982         foreach (sort keys %files) {
983             my $inst_pos = $files{$_};
984             $inherited .= "\$(INST_$uc)/$inst_pos ";
985         }
986         $inherited .= "\n\t\@\$(NOOP)\n";
987         
988         # And realclean should remove them, by calling realclean_$filetype.
989         $inherited =~ s/^(\s*realclean\s+::\s.+)/$1 realclean_$filetype/m or die;
990         $inherited .= "realclean_$filetype ::\n\t\$(RM_F) ";
991         foreach (sort keys %files) {
992             my $inst_pos = $files{$_};
993             $inherited .= "\$(INST_$uc)/$inst_pos ";
994         }
995         $inherited .= "\n";
996     }
997
998     return $inherited;
999 }
1000
1001 # 'make clean' doesn't remove generated files from *.PL (see posting
1002 # to makemaker@perl.org).  Fix it.
1003 #
1004 sub MY::clean {
1005     package MY;
1006     my $inherited = shift->SUPER::clean(@_);
1007     $inherited =~ s/\s+$//;
1008     $inherited .= "\n\t-\$(RM_F) $_\n" foreach @to_clean;
1009     return $inherited;
1010 }
1011
1012 sub MY::processPL {
1013     package MY;
1014     my $inherited = shift->SUPER::processPL(@_);
1015
1016     # Add some exra dependencies.
1017     my ($k, $v);
1018     while (@deps) {
1019         ($k, $v, @deps) = @deps;
1020         $inherited =~ s!^(\s*$k\s+::\s.+)!"$1 " . join(' ', @$v)!me
1021           or die "no $k in: $inherited";
1022     }
1023
1024     # And some of the .in generators need the share/ directory passed
1025     # as an extra argument.  This is the location in the installed
1026     # system, not that where files are being copied, so $(PREFIX) but
1027     # no $(DESTDIR).
1028     #
1029     foreach (@grab_need_share) {
1030         $inherited =~
1031           s<(grab/$_/tv_grab_$_.PL grab/$_/tv_grab_$_)\s*$>
1032             <$1 \$(PREFIX)/share/xmltv>m
1033             or die "no call to $_.PL in: $inherited";
1034     }
1035
1036     foreach (@need_share) {
1037         $inherited =~
1038           s<($_.PL $_)\s*$>
1039             <$1 \$(PREFIX)/share/xmltv>m
1040             or die "no call to $_.PL in: $inherited";
1041     }
1042
1043
1044     return $inherited;
1045 }
1046
1047 sub MY::makefile {
1048     package MY;
1049     my $inherited = shift->SUPER::makefile(@_);
1050     return $inherited;
1051 }
1052
1053 # Fix filename of some generated manpages.
1054 sub MY::manifypods {
1055     package MY;
1056
1057                 for (my $inherited = shift->SUPER::manifypods(@_)) {
1058         foreach my $s (qw(Grab_XML DST Config_file Get_nice Mode Summarize Gunzip GUI Date ValidateGrabber Options Configure ValidateFile Configure::Writer)) {
1059             s!\$\(INST_MAN3DIR\)/(?:grab::|)$s[.]\$\(MAN3EXT\)!"\$(INST_MAN3DIR)/XMLTV::$s.\$(MAN3EXT)"!;
1060             s!\$\(INSTALLMAN3DIR\)/$s.\$\(MAN3EXT\)!"\$(INSTALLMAN3DIR)/XMLTV::$s.\$(MAN3EXT)"!;
1061         }
1062         return $_;
1063     }
1064 }
1065
1066 # Split a section of makefile into targets.
1067 sub targets( $ ) {
1068     my @lines = split /\n/, shift;
1069     $_ .= "\n" foreach @lines;
1070     my %r;
1071     my $curr_target;
1072     foreach (@lines) {
1073         if (/^(\S+)\s+:/) {
1074             # Beginning of a new target.
1075             my $name = $1;
1076             die "target $name seen twice" if defined $r{$name};
1077             $r{$name} = $curr_target = [];
1078         }
1079         elsif (/^\s+/ and defined $curr_target) {
1080             # Commands for the target.
1081             push @$curr_target, $_;
1082         }
1083         elsif (/^\s*(?:\#.*)?$/) {
1084             undef $curr_target;
1085         }
1086         else {
1087             chomp;
1088             die "bad makefile line: '$_'";
1089         }
1090     }
1091     return \%r;
1092 }