[t/spec] Note that tests being skipped are out of sync with the spec.
[pugs.git] / Makefile.PL.old
blobbf439d08625b819e2de774259b3e2ea326f6acc5
1 #!/usr/bin/env perl
3 =pod
5 =head1 NAME
7 Makefile.PL - Configure pugs build
9 =head1 SYNOPSIS
11 perl Makefile.PL [options]
13 Options:
15     --precompile-prelude        Force prelude to be precompiled
16     --no-precompile-prelude     Force prelude not to be precompiled
17     --help                      Print documentation (build system overview)
19 =head1 DESCRIPTION
21 Build System Overview
23  - Makefile.PL calls get_pugs_config() in inc/Module/Install/Pugs.pm which
24    then calls util/PugsConfig.pm to get configuration data printed with
25    ./pugs -V
26  - Makefile.PL calls GHC to compile Setup.hs to ./Setup.exe.
27  - Makefile.PL writes a Makefile that will call util/build_pugs.pl
28    upon "make".
29  - build_pugs.pl writes a Pugs.cabal file based on the flags given in
30    the Makefile.
31  - build_pugs.pl calls ./Setup.exe.
32  - Setup.exe builds dist/build/libHSPugs-6.XXX.YYY.a and returns to
33    build_pugs.pl.
34  - build_pugs.pl calls GHC to build ./pugs.exe
35    (by simply linking the freshly built libHSPugs package with src/Main.hs).
37 =cut
39 use 5.006;
40 use strict;
41 use warnings;
42 use Config;
43 use Cwd qw(abs_path cwd);
44 use File::Spec;
45 use File::Copy;
46 use File::Basename;
47 use FindBin;
48 use ExtUtils::Embed;
49 BEGIN { chdir $FindBin::RealBin };
50 use inc::Module::Install;
51 use lib 'inc';
52 use PugsBuild::Config;
53 use Carp;
54 use Getopt::Long;
55 use Pod::Usage;
56 use POSIX qw/uname/;
58 our %options;
59 GetOptions \%options, qw( precompile-prelude! help ) or pod2usage(2);
61 pod2usage(-verbose => 2) if $options{'help'};
63 if ( $options{'precompile-prelude'} ) {
64     $PugsBuild::Config::Conf->{precompile_prelude} = $options{'precompile-prelude'}
67 # Win32/CygWin GHC appears to be more memory hungry than its
68 # *nix counterpart, causing it to bail part-way through builds.
69 # This value will be used only if 'ghc_heap_size' in config.yml
70 # is not defined.
72 use constant WIN32_GHC_HEAPSIZE => "348m";
74 # Special case for migration - remove old version of Syck
75 unlink 'src/Data/Yaml/Syck.hs' if -e 'src/Data/Yaml/Syck.hs';
77 my @warn;
78 my $pugs = "pugs$Config{_exe}";
79 my ($fs) = ($Config{sitelib} =~ /([\/\\])/)
80        or die "Can't determine file_sep";
81 my $thispugs = ".${fs}pugs$Config{_exe}";
82 my $version_h = "src/Pugs/pugs_version.h";
83 my $config_h = "src/Pugs/pugs_config.h";
84 my @srcdirs  = grep {-d} glob("src"), glob("src/*"), glob("src/*/*"), glob("src/*/*/*");
86 # On Win32, svn may create '_svn' dirs rather than '.svn'.  Hide them manually.
87 # Details: http://svn.collab.net/repos/svn/trunk/notes/asp-dot-net-hack.txt
88 @srcdirs = grep {! m|\b_svn\b|} @srcdirs if $ENV{SVN_ASP_DOT_NET_HACK};
90 my @hsfiles  = map {glob "$_/[A-Z]*.hs"} @srcdirs;
91 push @hsfiles, qw<src/Pugs/Config.hs src/Pugs/CodeGen/PIR/Prelude.hs>;
92 my @hppfiles = map {my $x=$_; $x=~s/\.hs$/.hpp/; $x} @hsfiles;
94 warn_cygwin     ();
96 for my $var (qw( PERL5LIB PERLLIB )) {
97     if (grep { m{^(?:\.?[\\/]+)*lib$} } split(/\Q$Config{path_sep}\E/, ($ENV{$var} || next))) {
98         die <<"EOD";
99 *** The "$var" environment variable contains a naked 'lib',
100     which will disrupt the Pugs build process.
102     Please remove it and run Makefile.PL again.
104     }
105     last; # PERLLIB is ignored when PERL5LIB is in place
108 print "*** Probing configuration (please ignore any warnings)...\n\n";
110 name            ('Perl6-Pugs');
111 version_from    ('lib/Perl6/Pugs.pm');
112 abstract_from   ('lib/Perl6/Pugs.pm');
113 author          ('Audrey Tang <cpan@audreyt.org>');
114 license         ('perl');
115 install_script  ($pugs);
116 install_script  ('script/pugscc');
117 install_script  ('util/prove6');
118 recommends      ('Perl6::Bible');
119 recommends      ('Inline');
120 recommends      ('Filter::Simple');
121 recommends      ('LWP::Simple');
122 recommends      ('LWP');
123 build_requires  ('ExtUtils::MakeMaker' => 6.15);
124 build_requires  ('FindBin');
125 build_requires  ('File::Path');
126 include         ('Module::Install::Makefile::Name');
127 include         ('Module::Install::Makefile::Version');
128 build_subdirs   (map fixpaths($_), grep {
129                    -f "$_/Makefile.PL" && not -l "$_/Makefile.PL"
130                  } glob("ext/*"), glob("docs/*")
131                 );
133 my $version = version();
134 $version .= 0 until length($version) >= length('0.123456');
135 $version =~ s{6\.(\d{3})(\d{3})?}{join '.', 6, int($1), int($2||0)}e;
136 version($version);
138 makemaker_args  (
139     test => { TESTS => "`perl t/spec/fudgeall pugs t/*/*.t t/*/*/*.t`" }, # , "perl5/*/t/*.t" },
140     MAN1PODS => {},
143 if (my $prefix = PugsBuild::Config->lookup('install_dir')) {
144     makemaker_args(PREFIX => $prefix);
147 clean_files     (map fixpaths($_),
148     $version_h, $config_h,
149     (map {"$_/*.hpp"} @srcdirs),
150     "pugs$Config{_exe}", "pil$Config{_exe}",
151     "src/gen_prelude$Config{_exe}",
152     "Setup$Config{_exe}", "util/ghc-pkg-wrapper$Config{_exe}",
153     "util/runcompiler$Config{_exe}", qw(
154     src/Pugs/pugs_config.h src/Pugs/Config.hs blib6 dist
155     src/Pugs/Prelude.hs src/Pugs/CodeGen/PIR/Prelude.hs test.log
156     src/Pugs/Embed/Parrot.hs src/Pugs/Embed/Parrot_hsc.*
157     src/Pugs/*/*_stub.*
158     util/ghc-pkg-wrapper.hs util/ghc-pkg-wrapper.hi util/ghc-pkg-wrapper.o
159     util/runcompiler.hs util/runcompiler.hi util/runcompiler.o
160     temp-ex* unlink-test* Prelude Pugs.cabal Setup.hi Setup.o
161     .setup-config .installed-pkg-config
162     temp-test.*.*-out tempfile.*.* create_this_file create_this_file2
163     third-party/*/*.hi third-party/*/*.o
164     third-party/*/dist
165     ),
166     object_files("src/Pugs", "src/Pugs/*", "src/Pugs/*/*"),
167     object_files("src/MO", "src/MO/*", "src/MO/*/*"),
170 set_postamble   ();
171 no_index        (
172     directory =>
173         qw< inc debian modules perl5 ext script util docs examples src >
175 sign            (1);
176 WritePugs       (5);
178 print(('=' x 78), "\n\n");
180 print @warn;
182 print << ".";
183 *** Enter '$Config{make}' to build Pugs.  If compilation is too slow,
184     consider using '$Config{make} soon' instead.
188 ################################################################################
189 sub object_files  {
190     map { ("$_/*.o", "$_/*.hi") } @_;
193 sub try_package {
194     my ($ghc, $ghcpkg, $code) = @_;
195     my @packages = qw(-hide-all-packages -package base);
196     push(@packages, "-package $ghcpkg");
197     if (not try_compile
198         ($code , $ghc, @packages),
199     ) {
200         # We are missing mtl,network,time,whatever somehow,
201         # likely because GHC 6.6's extra pkg is not there
202         die <<"EOD";
203 *** Could not load the "$ghcpkg" package in your GHC installation.
205     This is likely because the "extralibs" of GHC 6.6 was not built along
206     with the base GHC distribution.
208     To install extra libraries, extract both "-src" and "-src-extralibs"
209     distributions from http://haskell.org/ghc/download_ghc_66.html in the
210     same directory, then cd into ghc-6.6/ and build GHC from there.
211     In Ubuntu Feisty/debian type
212      "sudo aptitude install libghc6-$ghcpkg-dev"
214     }
218 sub set_postamble {
219     my @srcfiles = map { glob("$_/*.*hs") } @srcdirs;
220     push @srcfiles, map { glob("$_/*.*hs-boot") } @srcdirs;
221     push @srcfiles, map { map { substr($_, 0, -1) } glob("$_/*.*hsc") } @srcdirs;
223     my ($ghc, $ghc_version, $ghc_flags, $ghc_pkg) = assert_ghc();
224     my $hsc2hs = $ENV{HSC2HS};
225     my $setup = File::Spec->catfile(".", "Setup$Config{_exe}");
226     my $ghc_wrapper = File::Spec->catfile(".", "util", "runcompiler$Config{_exe}");
227     my $ghc_pkg_wrapper = File::Spec->catfile(".", "util", "ghc-pkg-wrapper$Config{_exe}");
228     my $config_path = File::Spec->catfile(cwd(), 'third-party', 'installed', 'packages.conf');
230     if (!$hsc2hs) {
231         $hsc2hs = $ghc;
232         $hsc2hs =~ s{(.*)ghc}{$1hsc2hs};
233     }
235     preprocess(
236             File::Spec->catfile('util', 'runcompiler.hs.in'),
237             File::Spec->catfile('util', 'runcompiler.hs'),
238             CONFIG_PATH => $config_path,
239             GHC => $ghc,
240             GHC_PKG => $ghc_pkg,
241     );
242     preprocess(
243             File::Spec->catfile('util', 'ghc-pkg-wrapper.hs.in'),
244             File::Spec->catfile('util', 'ghc-pkg-wrapper.hs'),
245             CONFIG_PATH => $config_path,
246             GHC => $ghc,
247             GHC_PKG => $ghc_pkg,
248     );
250     # set up install path for third-party modules
251     mkdir File::Spec->catdir('third-party', 'installed');
253     compile_hs($ghc, 'Setup', $setup);
254     compile_hs($ghc, File::Spec->catfile('util', 'ghc-pkg-wrapper'), $ghc_pkg_wrapper);
255     compile_hs($ghc, File::Spec->catfile('util', 'runcompiler'), $ghc_wrapper);
257     # Add GHC to PATH
258     local $ENV{PATH} = dirname($ghc) . $Config{path_sep} . $ENV{PATH};
261     try_package($ghc,
262                 'mtl',
263                 "import Control.Monad.RWS\n"
264                 . "main = let (x, (), ()) = runRWS (return ()) () () in return x\n"
265                 );
266     try_package($ghc,
267                 'network',
268                 "import Network.BSD\n"
269                 . "main = let x = defaultProtocol in return x\n"
270                 );
271     try_package($ghc,
272                 'time',
273                 "import Data.Time\n"
274                 . "main = return 1\n"
275                );
277     #
278     # We probably need to promote this to a config.yml + autodetect
279     # thing, but until it's done, put the condition here at least and
280     # don't hardcode it into the postamble.
281     #
282     # Note that the -fdebugging flag only existed in GHC trunk builds
283     # around May 2007, and would not be present either before or afterwards.
284     # (In the newer builds it's enabled by default and supports a much more
285     # comprehensive feature set, including single-stepping and tracing.)
286     #
287     my $ghci_debugging =
288             (defined $ENV{PUGS_GHCI_DEBUGGING} ? $ENV{PUGS_GHCI_DEBUGGING} : 1)
289         ? '-fdebugging' : '';
291     if ($ghc_version =~ /^(\d+\.\d+)/) {
292         $ghci_debugging = '' if $1 <= 6.6 or $1 >= 6.8;
293     }
295     $ghc = $ghc_wrapper;
296     $ghc_pkg = $ghc_pkg_wrapper;
298     my $heap;
300     $heap = PugsBuild::Config->lookup('ghc_heap_size') || $heap;
301     $ghc_flags .= " +RTS -M$heap -RTS" if $heap;
302     # $ghc_flags .= ' -dcore-lint';
303     # $ghc_flags .= " -keep-tmp-files";
305     if ($ENV{PUGS_EMBED} and $ENV{PUGS_EMBED} =~ /\bhaskell\b/i) {
306         if (has_ghc_package('plugins')
307             and  try_compile("import System.Eval\n"
308                             ."main :: IO ()\n"
309                             .'main = (eval_ "return ()" [] [] [] [] :: IO (Either [String] (Maybe ()))) >> return ()', $ghc, '-package', 'plugins')) {
310             $ghc_flags .= ' -package plugins -DPUGS_HAVE_HSPLUGINS ';
311         }
312         else {
313             push @warn, << '.';
314 *** Inline Haskell support disabled.  If you want dynamic loading
315     of haskell modules, please install the hs-plugins library:
316         http://www.cse.unsw.edu.au/~dons/hs-plugins/
317     Remember to "make register" after "make install" for hs-plugins!
320         }
321     }
323     if (has_ghc_package('readline')
324         and  try_compile("import System.Console.Readline\n"
325                         ."main :: IO ()\n"
326                         ."main = do\n"
327                         ."  setCatchSignals False\n"
328                         ."  setCatchSigwinch False\n"
329                         .'  _ <- readline "" '."\n"
330                         .'  return ()', $ghc)) {
331       $ghc_flags .= ' -DPUGS_HAVE_READLINE '; # -package readline';
332     }
333     else {
334       push @warn, << '.';
335 *** Readline support disabled.  If you want readline support,
336     please install the GNU readline library.
339     }
341     my $ghc_output = ''; # "-o pugs$Config{_exe} src/Main.hs";
342     my $hasktags = $ENV{HASKTAGS} || 'hasktags';
344     # map a bunch of .c files to a bunch of expected .o files
345     my $o = sub { map { substr($_, 0, -1) . 'o' } @_ };
347     my @prereqs = ();
348     my @derived_srcfiles = qw< src/Pugs/Embed/Parrot.hs src/Pugs/pugs_config.h src/Pugs/pugs_version.h src/Pugs/Config.hs src/Pugs/Prelude.hs src/Pugs/CodeGen/PIR/Prelude.hs >;
350     my $embed_flags = "-I" . cwd();
351     my $hsc2hs_flags = "";
352     my $ccdlflags = "";
354     # [-!]perl5 does not work with the \bFLAG\b convention used in this file.
355     # It should be removed, or the convention, and code, fixed.
356     # Went in 2006-08-30.  Depreciated 2006-09-11.
357     if ($ENV{PUGS_EMBED} and $ENV{PUGS_EMBED} =~ /[-!]perl5\b/i) {
358         push @warn,  << '.';
359 *** PUGS_EMBED flags "-perl5" and "!perl5" are depreciated and buggy.
360     Please use "noperl5" instead.
363     }
364     if (!$ENV{PUGS_EMBED} or $ENV{PUGS_EMBED} !~ /(?:[-!]|\bno)perl5\b/i) {
365         $ENV{PUGS_EMBED} .= " perl5 ";
366         #push @prereqs, "src/perl5/p5embed.o"; # XXX
367         # $ghc_output .= " src/perl5/p5embed.o ";
368         $embed_flags .= " -DPUGS_HAVE_PERL5 -isrc/perl5 ";
369         my $flags = "$Config{ccflags} $Config{ccdlflags} ";
370         if ($flags =~ /\S/) {
371             $flags =~ s{([\\"'])}{\\$1}g;
372             my @flags = grep { length $_ } split /\s+/, $flags;
373             if ($^O eq 'MSWin32') {
374                 if ($Config{libperl} =~ /lib(\w+)\.a/) {
375                     $embed_flags .= " -optl-l$1 ";
376                 }
377                 elsif (defined &Win32::BuildNumber) {
378                     # We are on ActivePerl -- Kluge massively!
380                     no warnings 'once';
381                     our %MY_CONFIG = %Config;
382                     *Config = *MY_CONFIG;
383                     *Config::Config = *MY_CONFIG;
384                     *ExtUtils::MM_Win32::Config = *MY_CONFIG;
385                     *ExtUtils::MM_Unix::Config = *MY_CONFIG;
387                     $Config{ccflags} =~ s/-libpath:"?(.*?)"? //g;
388                     $Config{ccdlflags} =~ s/-libpath:"?(.*?)"? //g;
389                     $Config{lddlflags} =~ s/-libpath:"?(.*?)"? //g;
390                     $Config{ldflags} =~ s/-libpath:"?(.*?)"? //g or die "ldflags: $Config{ldflags} does not contain -libpath:";
392                     my $lib = "$1/$Config{libperl}";
393                     $embed_flags .= " -optl\"$lib\" ";
395                     $flags = "$Config{ccflags} $Config{ccdlflags}";
396                     $flags =~ s{([\\"'])}{\\$1}g;
397                     @flags = grep { length $_ } split /\s+/, $flags;
398                 }
399                 else {
400                     warn "Unrecognized libperl shared library: $Config{libperl}, proceeding anyway...\n";
401                 }
403                 $ccdlflags .= (/^-[DIL]/ ? ' -optc' : ' -optl') . qq["$_" ] for @flags;
404                 $embed_flags .= " -optc-Ddirent=DIRENT";
405             }
406             else {
407                 $embed_flags .= " -optc$_" for grep length, split(/\s+/, ccopts());
408                 $embed_flags .= " -optl$_" for grep length, split(/\s+/, ldopts());
410             }
412             $embed_flags .= " $_" for grep { /-[DIL]/ } split(/\s+/, ccopts());
413             $embed_flags .= " $_" for grep { /-[DIL]/ } split(/\s+/, ldopts());
415             if ($Config{osname} eq 'cygwin') {
416                 my $cygpath = sub {
417                     my $path = `cygpath -m @_`;
418                     chomp $path;
419                     return $path;
420                 };
421                 $embed_flags =~ s{(/usr/\S+)}{$cygpath->($1)}eg;
422                 $embed_flags =~ s{/cygdrive/(\w)/}{$1:/}g;
423                 #warn "** Cygwin embedding flags: embed_flags\n";
424             }
425         }
426     }
427     else {
428         push @warn, << '.';
429 *** Perl 5 embedding disabled.  If you want Perl 5 support, please set the
430     PUGS_EMBED environment variable to not contain "noperl5".
433     }
435     if ($ENV{PUGS_EMBED} and $ENV{PUGS_EMBED} =~ /\bparrot\b/i and $Config{cc} eq 'cl') {
436         push @warn, << '.';
437 *** Parrot linking not supported with MSVC.  Parrot linking will be disabled.
440         $ENV{PUGS_EMBED} =~ s/\bparrot\b//g;
441     }
443     # Respect CC setting
444     my $cc = $ENV{CC} || 'gcc';
445     $ghc_flags .= " -pgmc $cc " unless $cc eq 'gcc';
447     if ($Config{cf_by} eq 'Debian Project' and $ENV{PUGS_EMBED} and $ENV{PUGS_EMBED} =~ /\bperl5\b/i) {
448         # Is it safe to remove 'Debian Project' above, to test on all platforms?
449         my $need_path = 1;
450         my $libperlpath = '';
451         my $libperl = $Config{libperl};
452         foreach my $path (split(/\s/, $Config{libpth} . ' ' . $Config{libsdirs})) {
453             if (-e "$path/libperl.so") {
454                 $need_path = 0;
455                 last;
456             } elsif (-e "$path/$libperl") {
457                 $libperlpath ||= $path;
458             }
459         }
460         if ($need_path) {
461             my $message = '';
462             $message .= qq[        * Symlink $libperlpath/$libperl to libperl.so\n] if ($libperlpath and $libperl);
463             $message .= qq[        * Install libperl-dev package\n] if ($Config{cf_by} eq 'Debian Project');
464             die <<EOD;
465 *** Could not find libperl.so in: $Config{libpth} $Config{libsdirs}
466     Solutions include:
467         * Add noperl5 to PUGS_EMBED
468 $message
470         }
471     }
473     if ($ENV{PUGS_EMBED} and $ENV{PUGS_EMBED} =~ /\bparrot\b/i) {
474         my $base = $ENV{PARROT_PATH};
475         my $parrot_config = which('parrot-config.imc') || which('parrot-config.pir') || which('parrot-config') || '';
476         if (!$base && -e $parrot_config) {
477             $base = (File::Spec->splitpath($parrot_config))[1];
478         }
479         if (!$base) {
480             $parrot_config = which('parrot-config') || '';
481             $base = (File::Spec->splitpath($parrot_config))[1] if -e $parrot_config;
482         }
483         if (!$base and -d File::Spec->catdir(File::Spec->updir, 'parrot')) {
484             $base = abs_path(File::Spec->catdir(File::Spec->updir, 'parrot'));
485         }
486         if (!$base and -d File::Spec->catdir(File::Spec->updir, 'parrot-trunk')) {
487             $base = abs_path(File::Spec->catdir(File::Spec->updir, 'parrot-trunk'));
488         }
490         my $temp = File::Spec->catfile($base, 'parrot-config.imc');
491         if (!$parrot_config && -e $temp) {
492           $parrot_config = $temp;
493         }
495         $temp = File::Spec->catfile($base, 'parrot-config.pir');
496         if (!$parrot_config && -e $temp) {
497           $parrot_config = $temp;
498         }
500         $temp = File::Spec->catfile($base, 'parrot-config');
501         if (!$parrot_config && -e $temp) {
502           $parrot_config = $temp;
503         }
505         $base =~ s/bin\/*$//;
507         (-d $base and -e $parrot_config)
508             or die "*** Please set \$ENV{PARROT_PATH} to the base path with a built parrot tree.\n";
509         my $ldflags = parrot_config($base, $parrot_config, 'ldflags');
510         my $libs = parrot_config($base, $parrot_config, 'libs');
511         my $icuflags = parrot_config($base, $parrot_config, 'icu_shared');
512         my $include_path = parrot_config($base, $parrot_config, 'prefix') . parrot_config($base, $parrot_config, 'inc');
513         my $rpath_blib = parrot_config($base, $parrot_config, 'rpath_blib');
514         my $build_dir = parrot_config($base, $parrot_config, 'top_builddir', 'build_dir');
515         my $is_shared = parrot_config($base, $parrot_config, 'parrot_is_shared');
516         my $parrot_libdir = parrot_config($base, $parrot_config, 'lib_dir');
518         # Convert flags to -optc-*,etc, to pass through ghc. c/ompiler l/inker
519         $ldflags =~ s/(^|\s)-/$1-optl-/g;
520         $libs =~ s/(^|\s)-/$1-optl-/g;
521         $icuflags =~ s/(^|\s)-/$1-optl-/g;
522         $include_path =~ s/(^|\s)-/$1-optc-/g;
523         $embed_flags .= " -I$include_path" if $include_path =~ /\S/;
524         $rpath_blib =~ s/(^|\s)-/$1-optl-/g;
526         $embed_flags .= " -I$base/include -L$base/lib -L$base/blib/lib -DPUGS_HAVE_PARROT -L/usr/local/lib $ldflags ";
527         $embed_flags .= " -lparrot $libs $icuflags ";
528         my $config = $parrot_libdir."/parrot/config/install_config$Config{_o}";
529         $config = $parrot_libdir."/parrot/config/parrot_config$Config{_o}" unless -e $config;
530         $config = $parrot_libdir."/parrot/config/null_config$Config{_o}" unless -e $config;
531         $config = "$build_dir/src/install_config$Config{_o}" unless -e $config;
532         $config = "$build_dir/src/parrot_config$Config{_o}" unless -e $config;
533         $config = "$build_dir/src/null_config$Config{_o}" unless -e $config;
535         die <<"EOD" unless -e $config or $is_shared;
536 *** Could not find src/null_config.o in $build_dir.
537     Solutions include:
538         * Remove parrot from PUGS_EMBED
539         * Place a built Parrot source tree under $build_dir.
542         $embed_flags .= " $config ";
543         $embed_flags .= " $rpath_blib " if -d $build_dir;
545         # parrot include paths for hsc2hs
546         $hsc2hs_flags .= " -DPUGS_HAVE_PARROT -I$base/include ";
548         push @warn, << ".";
549 *** Embedded 'parrot' enabled.  You can use it for Perl 6 regex support by
550     setting the PUGS_REGEX_ENGINE environment variable to "PGE" at runtime.
552     }
553     else {
554         my $whichparrot = can_run('parrot');
556         if ($whichparrot) {
557             push @warn, << ".";
558 *** External 'parrot' executable found in your PATH at:
560         $whichparrot
562     You can use it for Perl 6 regex support by setting the
563     PUGS_REGEX_ENGINE environment variable to "PGE" at runtime.
565     If you want to link against Parrot, set the PUGS_EMBED environment
566     variable to contain 'parrot', the PARROT_PATH environment variable to
567     the path of a built parrot tree, then run Makefile.PL again.
570         }
571     }
573     my $is_win32 = ($^O =~ /MSWin|mingw|cygwin/i);
574     my $threaded = (try_compile_and_run("main :: IO ()\nmain = return ()", $ghc, "-threaded")) ? '-threaded' : '';
576     if ($threaded && $ENV{PUGS_NO_THREADS}) {
577         push @warn, << '.';
578 *** Thread support disabled due to explicit request in PUGS_NO_THREADS.
581         $threaded = '';
582     }
584     my $find_ver = sub {
585         `$_[0] $_ 2>&1` =~ /(.* (?:version|build) .*)/i && return $1
586             for qw{--version -v -V -? /?};
587         return "unknown";
588     };
590     unlink (my $build_config = 'current.build.yml');
591     my $config = get_pugs_config(
592         uname               =>  join (" ", (uname)[0,2,4] ),
593         regex_engine        =>  ( $ENV{PUGS_REGEX_ENGINE} ?  $ENV{PUGS_REGEX_ENGINE} : 'default' ),
594         embedded            =>  join (" ", ( $embed_flags =~ /HAVE_PERL5/ ?  $Config{perlpath} : 'noperl' ),
595                                     ( $embed_flags =~ /HAVE_PARROT/
596                                         ?  abs_path( File::Spec->catfile( "$ENV{PARROT_PATH}", "parrot" ) )
597                                         : 'noparrot' ),
598                                     ( $ENV{PUGS_EMBED} =~ /\bhaskell\b/ ?  $ghc : 'nohaskell' )
599                                 ),
600         ghc                 =>  join (" ", [ assert_ghc() ]->[0], $ghc_version,
601                                     ( $ghc_flags =~ /HAVE_READLINE/ ?  'readline' : 'noreadline' ),
602                                     ( $ghc_flags =~ /HAVE_HSPLUGINS/ ?  'hsplugins' : 'nohsplugins' ),
603                                     ( $threaded ? "threads" : "nothreads" ),
604                                 ),
605         cc                  =>  $find_ver->( $Config{cc} ),
606     );
608     {
609         # maybe move this to inc/PugsBuild/MiniYAML.pm ?
610         open my $fh, '>', $build_config or die "Cannot open $build_config for writing";
611         print $fh "# *** NOTE ***\n";
612         print $fh "# This file is generated during Makefile.PL.\n";
613         print $fh "# Changes will not persist after running Makefile.PL\n";
614         for ( sort keys %$config ) {
615             print $fh "$_: $config->{$_}\n";
616         }
617         close $fh;
618     }
620     # As of now, Test::TAP::HTMLMatrix is the key dependency for smokes,
621     # so we need only check for that.
622     eval { require Test::TAP::HTMLMatrix } or push @warn, << '.';
623 *** You do not appear to have a Smoke Kit installed. You can still build
624     Pugs and even run `make test', but you won't be able to run the more
625     modern `make smoke' target to produce nice graphs and send them to the
626     public smoke server. Installing Task::Smoke from CPAN will bring in
627     the necessary dependencies.
630     # XXX - hsplugins doesn't build with profiles
631     my $profiled_flags = $ghc_flags;
632     $profiled_flags =~ s{-DPUGS_HAVE_HSPLUGINS}{};
633     $profiled_flags =~ s{-package plugins}{};
635     my $emit = sub {
636         my $o = shift;
637         my $c = substr($o, 0, -1) . 'c';
638         return "$o : $c\n\t$ghc $threaded $embed_flags $ghc_flags -no-link -no-hs-main -O -o $o $c\n";
639     };
641     mkdir 'dist';
642     mkdir 'dist/build';
643     mkdir 'dist/build/src';
645     # Using the Win32 Haskell compiler results in a setup program that
646     # doesn't grok cygwin paths.  This kludge takes any /cygdrive/
647     # style paths and rewrites them.  This really should be factored
648     # out to a common module.  Better still, we should make a Cygwin-native
649     # GHC.
651     if ($Config{osname} eq 'cygwin') {
653         # NB.  We're exploiting for's aliasing of variables.
654         foreach my $path ($ghc_pkg, $hsc2hs, $ghc) {
655                         $path = `cygpath -m $path`; chomp $path;
656         }
657     }
659     my $setup_flags = "--prefix=\$(DESTDIR) --with-hc-pkg=$ghc_pkg --with-hsc2hs=$hsc2hs --ghc --with-compiler=$ghc";
660     my $precompile_prelude = ' --precompile-prelude '.PugsBuild::Config->lookup('precompile_prelude');
662     my $svn_entries = '';
664     my $svn_admin_dir = $ENV{SVN_ASP_DOT_NET_HACK} ? '_svn' : '.svn';
665     if (-d $svn_admin_dir) {
666         $svn_entries = File::Spec->catfile($svn_admin_dir, 'entries');
667     }
668     #$svn_entries = 'force_run';
670     # logic for Judy:
672 #    if ($Config{osname} ne 'MSWin32') {
673 #        warn "Configuring Judy...\n";
674 #        chdir "third-party/judy/Judy-1.0.3";
675 #        copy('src/Judy.h', '../../HsJudy');
676 #        system("./configure") unless -e "config.status" and -e "Makefile";
677 #        chdir "../../..";
678 #    }
680 #    my $judyclean;
681 #    if ($Config{osname} eq 'MSWin32') {
682 #        $judyclean = 'cd third-party\judy\Judy-1.0.3\src && '.
683 #            'nmake /nologo /F Makefile.win32 clean';
684 #    } else {
685 #        my $make = $Config{make};
687 #        # Judy at this moment wants GNU make.
688 #        $make = 'gmake' unless `$make --version` =~ /GNU/;
690 #        $judyclean = "cd third-party/judy/Judy-1.0.3 \&\& $make clean \&\& perl cleanmore.pl";
691 #    }
693     my @ghci_flags = qw( -hide-all-packages -package base -package filepath -package parsec -package template-haskell -package readline -package unix -package haskell98 -package mtl -package stm -package network -package HsSyck -package pugs-hsregex );
695     postamble(fixpaths(<< "."));
696 $config_h : lib/Perl6/Pugs.pm util/config_h.pl
697         \$(PERL) util/config_h.pl "$ghc $ghc_flags"
699 $version_h :
700         \$(PERL) util/version_h.pl $version_h
702 @{[join("\n", map {$emit->($_)} grep { /\.o$/ } @prereqs)]}
704 src/Pugs/Config.hs : util/PugsConfig.pm current.build.yml
705         \$(PERL) -Iutil -MPugsConfig -e "PugsConfig->write_config_module" > src/Pugs/Config.hs
707 src/gen_prelude$Config{_exe} : src/gen_prelude.hs
708         $ghc -O0 --make -o src/gen_prelude$Config{_exe} src/gen_prelude.hs
710 src/Pugs/CodeGen/PIR/Prelude.hs : src/gen_prelude$Config{_exe} src/perl6/Prelude/PIR.pm
711         \@\$(PERL) -e "mkdir q-src/Pugs/CodeGen/PIR-"
712         src/gen_prelude$Config{_exe} Pugs.CodeGen.PIR.Prelude < src/perl6/Prelude/PIR.pm > src/Pugs/CodeGen/PIR/Prelude.hs
714 src/Pugs/Prelude.hs : src/perl6/Prelude.pm util/gen_prelude.pl
715         \$(PERL) util/gen_prelude.pl -v --touch --inline -i src/perl6/Prelude.pm --output src/Pugs/Prelude.hs
717 ${() = '%.hpp : %.hs @prereqs $version_h
718         $ghc $threaded $ghc_flags -DHADDOCK -E \$< -o \$@
719         \$(PERL) util/munge_haddock.pl \$@'; \''}
721 .SUFFIXES: .hs .hpp
723 .hs.hpp :
724         $ghc $threaded $ghc_flags -DHADDOCK -E \$< -o \$@
725         \$(PERL) util/munge_haddock.pl \$@
727 .SUFFIXES: .hsc .hs
729 .hsc.hs :
730         \$(PERL) -MFile::Spec -e "sub p () { File::Spec->splitpath(ARGV->[0]) }; chdir((p)[1]); system(q($hsc2hs), qw($hsc2hs_flags), (p)[2]);" \$<
732 .SUFFIXES: .grammar .hs
734 .grammar.hs :
735         \$(PERL) util/file_to_hs.pl \$< \$@
737 .SUFFIXES: .pil .hs
739 .pil.hs :
740         \$(PERL) util/file_to_hs.pl \$< \$@
742 util/drift.pl:
744 @{[ mk_drift_rules( qw(src/Emit/PIR src/Pugs/AST/Internals src/Pugs/PIL1 src/Pugs/PIL2) ) ]}
746 haddock : $version_h $config_h @hppfiles dist/doc/html
747         haddock -t Pugs-$version -h -o dist/doc/html/ @hppfiles
748         \@\$(RM_F) @{[map "$_.pre", @hppfiles]} @hppfiles
749         \@\$(PERL) -le "print and print q-*** API Documentation generated in @{[File::Spec->catfile('dist', 'doc', 'html', 'index.html')]}-"
751 # make haddock one file at a time to get partial, unlinked output
752 haddock-broken : $version_h $config_h @hppfiles dist/doc/html
753 @{[join("\n", map {"\thaddock -t Pugs-$version -h -o dist/doc/html/ $_"} @hppfiles)]}
754         \@\$(RM_F) @{[map "$_.pre", @hppfiles]} @hppfiles
755         \@\$(PERL) -le "print and print q-*** Unlinked API Documentation generated in @{[File::Spec->catfile('dist', 'doc', 'html', 'index.html')]}-"
757 dist/doc/html :
758         \@\$(PERL) -MFile::Path -e "mkpath q-dist/doc/html-"
760 pugs_requirements : instances src/Pugs/Config.hs src/Pugs/CodeGen/PIR/Prelude.hs @srcfiles $version_h $config_h config.yml src/perl6/Prelude.pm src/Pugs/Prelude.hs
762 prof :: profiled
764 soonprof :: unoptimised-profiled
766 unoptimized-profiled :: unoptimised-profiled
768 unoptimised-profiled :: pugs_requirements
769         \$(PERL) util/build_pugs.pl _+SETUP $setup_flags _-SETUP _+GHC $version $ghc $ghc_pkg $ghc_version $setup --make -O0 -auto-all -prof $threaded $profiled_flags $ccdlflags $embed_flags $ghc_output _-GHC _+GEN_PRELUDE $precompile_prelude --pugs $thispugs
771 profiled :: pugs_requirements
772         \$(PERL) util/build_pugs.pl _+SETUP $setup_flags _-SETUP _+GHC $version $ghc $ghc_pkg $ghc_version $setup --make -O -auto-all -prof $threaded $profiled_flags $ccdlflags $embed_flags $ghc_output _-GHC _+GEN_PRELUDE $precompile_prelude --pugs $thispugs
774 pugs.prof :: profiled
775         find t -type f | grep -v D | grep -v R | grep -v pugsrun | ./pugs +RTS -p -RTS -e 'my sub exit {}; for =\$\$*IN -> \$\$t is copy { \$\$t .= chomp; require \$\$t }'
777 optimised :: optimized
779 optimized :: pugs_requirements
780         \$(PERL) util/build_pugs.pl _+SETUP $setup_flags _-SETUP _+GHC $version $ghc $ghc_pkg $ghc_version $setup --make -O $threaded $ghc_flags $ccdlflags $embed_flags $ghc_output _-GHC _+GEN_PRELUDE $precompile_prelude --pugs $thispugs
782 soon :: unoptimized
784 unoptimised :: unoptimized
786 unoptimized :: pugs_requirements
787         \$(PERL) util/build_pugs.pl _+SETUP $setup_flags _-SETUP _+GHC $version $ghc $ghc_pkg $ghc_version $setup --make -O0 $threaded $ghc_flags $ccdlflags $embed_flags $ghc_output _-GHC _+GEN_PRELUDE $precompile_prelude --pugs $thispugs
789 $pugs : pugs_requirements
790         \$(PERL) util/build_pugs.pl _+SETUP $setup_flags _-SETUP _+GHC $version $ghc $ghc_pkg $ghc_version $setup --make __optimization__ $threaded $ghc_flags $ccdlflags $embed_flags $ghc_output _-GHC _+GEN_PRELUDE $precompile_prelude --pugs $thispugs
793 pirtest : test-pir
795 pirsmoke : smoke-pir
797 jssmoke : smoke-js
799 test :: blib6/lib/Test.pm.yml
801 prelude :: blib6/lib/Prelude.pm.yml
803 pure_all :: blib6/lib/Test.pm.yml
805 test-all : test test-js test-pir test-perl5
807 test-pir :
808         \$(PERL) -e "ENV->{HARNESS_PERL_SWITCHES}=q+-B PIR+; system qq+$Config{make}+, q+test+"
810 test-js :
811         \$(PERL) -e "ENV->{HARNESS_PERL_SWITCHES}=q+-B JS+; system qq+$Config{make}+, q+test+"
813 test-perl5 :
814         \$(PERL) -e "ENV->{HARNESS_PERL_SWITCHES}=q+-B PERL5+; system qq+$Config{make}+, q+test+"
816 test-redsix :
817         \$(PERL) -e "ENV->{HARNESS_PERL_SWITCHES}=q+-B REDSIX+; system qq+$Config{make}+, q+test+"
819 blib6/lib/Test.pm.yml :: ext/Test/lib/Test.pm
820         \$(NOECHO) \$(ECHO) "Precompiling Test.pm..."
821         $thispugs -CParse-YAML ext/Test/lib/Test.pm > blib6/lib/Test.pm.yml
823 blib6/lib/Prelude.pm.yml :
824         \$(NOECHO) \$(ECHO) "Precompiling Prelude.pm..."
825         util/gen_prelude.pl -v -i src/perl6/Prelude.pm -p $thispugs --output blib6/lib/Prelude.pm.yml
827 upload-smoke : smoke.yml
828         \$(PERL) util/smokeserv/smokeserv-client.pl smoke.html smoke.yml
830 smoke-upload : upload-smoke
832 smoke.yml :
833         \$(PERL) util/run-smoke.pl . smoke.html
835 smoke : smoke-pugs
837 smoke-all : smoke-pugs smoke-js smoke-pir smoke-perl5
839 smoke-pugs : $pugs util/run-smoke.pl all blib6/lib/Test.pm.yml
840         \$(PERL) util/run-smoke.pl . smoke.html
842 smoke-pir : $pugs util/run-smoke.pl all
843         \$(PERL) util/run-smoke.pl . smoke-pir.html -BPIR
845 smoke-jsperl5 : $pugs util/run-smoke.pl all
846         \$(PERL) -e "ENV->{PUGS_RUNTIME}=q+JSPERL5+; exec qw+$^X util/run-smoke.pl . smoke-jsperl5.html+"
848 smoke-js : $pugs util/run-smoke.pl all
849         \$(PERL) -e "ENV->{PUGS_RUNTIME}=q+JS+; exec qw+$^X util/run-smoke.pl . smoke-js.html+"
851 smoke-perl5 : $pugs util/run-smoke.pl all
852         \$(PERL) -e "ENV->{PUGS_RUNTIME}=q+PERL5+; exec qw+$^X util/run-smoke.pl . smoke-perl5.html -BPERL5+"
854 smoke-redsix : $pugs util/run-smoke.pl all
855         \$(PERL) -e "ENV->{PUGS_RUNTIME}=q+REDSIX+; exec qw+$^X util/run-smoke.pl . smoke-redsix.html -BREDSIX+"
858 ghci : @prereqs @derived_srcfiles
859         $ghc @{[ dethread_flags($ghc_flags) ]} $ghc_output -DPUGS_UNDER_GHCI -no-link --make -O0 -fglasgow-exts -L. -idist/build -Ldist/build -idist/build/src -Ldist/build/src -isrc src/Prereqs.hs @prereqs
860         \@\$(RM_RF) src/Pugs/*/*_stub.*
861         $ghc @{[ dethread_flags($ghc_flags) ]} @ghci_flags $ghc_output -DPUGS_UNDER_GHCI --interactive -fglasgow-exts $ghci_debugging -L. -idist/build -Ldist/build -idist/build/src -Ldist/build/src -isrc src/Main.hs @prereqs
863 ctags : @prereqs @derived_srcfiles
864         echo ":ctags" | $ghc $ghc_flags @ghci_flags $ghc_output --interactive -osuf moose -hisuf miise -fglasgow-exts -L. -idist/build -Ldist/build -idist/build/src -Ldist/build/src -isrc src/Main.hs @prereqs
866 etags : @prereqs @derived_srcfiles
867         echo ":etags" | $ghc $ghc_flags @ghci_flags $ghc_output --interactive -osuf moose -hisuf miise -fglasgow-exts -L. -idist/build -Ldist/build -idist/build/src -Ldist/build/src -isrc src/Main.hs @prereqs
869 pil$Config{_exe} : $config_h @srcfiles src/PIL/Native/Bootstrap.hs src/PIL/Native/Syntax.hs
870         $ghc $ghc_flags --make -fglasgow-exts -H0 -isrc -Isrc -L. -fno-warn-name-shadowing -o pil$Config{_exe} -main-is PIL.main src/PIL.hs
872 pili : pil$Config{_exe}
873         $ghc --interactive -fglasgow-exts -isrc -Isrc -L. -static -fno-warn-name-shadowing src/PIL.hs
875 tags : @srcfiles
876         $hasktags -c @{[ grep { !/PIL/ } @srcfiles ]}
877         sort tags > tags.tmp
878         mv tags.tmp tags
880 config.yml:
882 src/perl6/Prelude.pm:
884 INST6_ARCHLIB = blib6/arch
885 INST6_SCRIPT = blib6/script
886 INST6_BIN = blib6/bin
887 INST6_LIB = blib6/lib
888 INST6_MAN1DIR = blib6/man1
889 INST6_MAN3DIR = blib6/man3
890 INSTPUGS_LIB = blib6/pugs
892 build_perl5 ::
893 @{[for_perl5("
894         cd __DIR__ && $^X Makefile.PL && \$(MAKE)
895 ")]}
897 clean ::
898         \@\$(RM_RF) third-party/installed
899 @{[for_perl5("
900         -cd __DIR__ && \$(TEST_F) \$(FIRST_MAKEFILE) && \$(MAKE) clean
901 ")]}
903 realclean ::
904         \@\$(RM_RF) third-party/installed
906 @{[for_perl5("
907         -cd __DIR__ && \$(TEST_F) \$(FIRST_MAKEFILE) && \$(MAKE) realclean
908 ")]}
910 pure_all :: build_perl5
911         \$(PERLRUN) util/src_to_blib.pl
913 register ::
914         \$(PERLRUN) util/ghc_setup.pl copy --copy-prefix=\$(DESTDIR)
915         \$(PERLRUN) util/ghc_setup.pl register --prefix=\$(DESTDIR)
917 pure_site_install ::
918         \$(NOECHO) \$(MOD_INSTALL) \\
919                 \$(INST6_LIB) \$(DESTDIR)$config->{sitelib} \\
920                 \$(INST6_ARCHLIB) \$(DESTDIR)$config->{sitearch} \\
921                 \$(INST6_BIN) \$(DESTDIR)$config->{sitebin} \\
922                 \$(INST6_SCRIPT) \$(DESTDIR)$config->{sitescript} \\
923                 \$(INST6_MAN1DIR) \$(DESTDIR)$config->{installsiteman1dir} \\
924                 \$(INST6_MAN3DIR) \$(DESTDIR)$config->{installsiteman3dir} \\
925                 \$(INSTPUGS_LIB) \$(DESTDIR)$config->{sitelib}/auto/pugs
926 #       \$(PERLRUN) util/ghc_setup.pl copy --copy-prefix=\$(DESTDIR)
928 pure_vendor_install ::
929         \$(NOECHO) \$(MOD_INSTALL) \\
930                 \$(INST6_LIB) \$(DESTDIR)$config->{privlib} \\
931                 \$(INST6_ARCHLIB) \$(DESTDIR)$config->{archlib} \\
932                 \$(INST6_BIN) \$(DESTDIR)$config->{installbin} \\
933                 \$(INST6_SCRIPT) \$(DESTDIR)$config->{installscript} \\
934                 \$(INST6_MAN1DIR) \$(DESTDIR)$config->{installman1dir} \\
935                 \$(INST6_MAN3DIR) \$(DESTDIR)$config->{installman3dir} \\
936                 \$(INSTPUGS_LIB) \$(DESTDIR)$config->{privlib}/auto/pugs
937 #       \$(PERLRUN) util/ghc_setup.pl copy --copy-prefix=\$(DESTDIR)
941 sub for_perl5 {
942     my $cmd = shift;
943     $cmd =~ s{\n}{}g;
944     my @cmds;
945     foreach my $dir (grep { -d } glob('perl5/*')) {
946         -e "$dir/Makefile.PL" or next;
948         # Skip XS modules for now
949         next if glob("$dir/*.xs") or glob("$dir/*.i") or $dir =~ /-\d+/;
951         my $this = $cmd;
952         $this =~ s{__DIR__}{$dir}g;
953         push @cmds, $this;
954     }
955     return join("\n", @cmds);
958 our $do_run;
959 sub try_compile_and_run {
960     local $do_run = 1;
961     try_compile(@_);
964 sub try_compile {
965     my $code = shift;
966     my $temp = "pugs-tmp-$$";
967     my $ghc  = shift or croak "try_compile called without path to ghc";
969     eval {
970         open TMP, "> $temp.hs";
971         print TMP $code;
972         close TMP;
973         system(
974             $ghc, @_,
975             "--make", "-v0",
976             -o => "$temp.exe",
977             "$temp.hs"
978         );
980     };
982     my $ok = -s "$temp.exe";
984     if ($do_run) {
985         $ok = 0 unless system(abs_path("$temp.exe")) == 0;
986     }
988     unlink("$temp.exe");
989     unlink("$temp.hs");
990     unlink("$temp.hi");
991     unlink("$temp.o");
993     return $ok;
996 sub parrot_config {
997     my $base = shift;
998     my $parrot_config = shift;
999     my $ac_path = abs_path();
1000     my $sp_base = $base;
1001     $sp_base =~ s{\\}{\/}g;
1002     chdir( $sp_base ) or die "Can't change dir to '$sp_base'";
1003     my $parrot = "parrot$Config{_exe}";
1004     $parrot = "bin/$parrot" if not -e $parrot;
1005     my $value;
1006     while (@_) {
1007         my $config = shift;
1008         $value = `./$parrot $parrot_config $config`;
1009         $value =~ /no such key:/ or last;
1010     }
1011     die $value if $value =~ /no such key:/;
1012     chomp($value);
1013     chdir( $ac_path ) or die "Can't change dir to '$ac_path'";
1014     return $value;
1017 sub which {
1018     my $file = shift;
1019     for ( File::Spec->path() ) {
1020         my $full_name = File::Spec->catfile($_, $file);
1021         return $full_name if -e $full_name;
1022     }
1023     return undef;
1026 sub preprocess {
1027     my ($infile, $outfile, %substitutions) = @_;
1029     open IN, '<', $infile or die "failed to open $infile ($!)";
1030     open OUT, '>', $outfile or die "failed to open $outfile ($!)";
1032     if ($Config{osname} eq 'cygwin') {
1033                 for my $path (values %substitutions){
1034                         $path = `cygpath -m $path`; chomp $path;
1035                 }
1036     }
1038     while (<IN>) {
1039         while (my ($pat, $subst) = each(%substitutions)) {
1040             $subst =~ s{\\}{\\\\}g;
1041             s/__${pat}__/$subst/g
1042         }
1043         print OUT $_;
1044     }
1046     close OUT;
1047     close IN;
1050 sub compile_hs {
1051     my ($ghc, $prefix, $out) = @_;
1053     unlink($prefix . $_) for (
1054         $Config{_exe},
1055         '.o',
1056         '.hi',
1057     );
1059     my $rv = system($ghc, '--make', '-o' => $out,
1060         (-e $prefix. '.hs') ? $prefix.'.hs' : $prefix.'.lhs'
1061     );
1062     unless (-s $out) {
1063         die << ".";
1064 *** Building Setup$Config{_exe} failed (exit code $rv)
1065     Please check your GHC and Cabal installation.
1067     }
1070 sub mk_drift_rules {
1071     join "\n\n",
1072     ("instances: " . join " ", map { "$_/Instances.hs" } @_),
1073     (map { "$_.hs:" } @_),
1074     map { <<"." } @_;
1075 $_/Instances.hs: $_.hs util/drift.pl
1076 \t\$(PERL) util/drift.pl $_.hs
1079 __END__