Ignore Hadrian build products.
[ghc.git] / boot
1 #!/usr/bin/env perl
2
3 use warnings;
4 use strict;
5
6 use Cwd;
7 use File::Path 'rmtree';
8 use File::Basename;
9
10 my %required_tag;
11 my $validate;
12 my $curdir;
13
14 # See Trac #11530
15 $ENV{GREP_OPTIONS} = '';
16
17 $required_tag{"-"} = 1;
18 $validate = 0;
19
20 $curdir = &cwd()
21     or die "Can't find current directory: $!";
22
23 while ($#ARGV ne -1) {
24     my $arg = shift @ARGV;
25
26     if ($arg =~ /^--required-tag=(.*)/) {
27         $required_tag{$1} = 1;
28     }
29     elsif ($arg =~ /^--validate$/) {
30         $validate = 1;
31     }
32     else {
33         die "Bad arg: $arg";
34     }
35 }
36
37 sub sanity_check_line_endings {
38     local $/ = undef;
39     open FILE, "packages" or die "Couldn't open file: $!";
40     binmode FILE;
41     my $string = <FILE>;
42     close FILE;
43
44     if ($string =~ /\r/) {
45         print STDERR <<EOF;
46 Found ^M in packages.
47 Perhaps you need to run
48     git config --global core.autocrlf false
49 and re-check out the tree?
50 EOF
51         exit 1;
52     }
53 }
54
55 sub sanity_check_tree {
56     my $tag;
57     my $dir;
58
59     if (-d ".git"  &&
60         system("git config remote.origin.url | grep github.com > /dev/null") == 0 &&
61         system("git config --get-regexp '^url.*github.com/.*/packages-.insteadOf' > /dev/null") != 0) {
62         # If we cloned from github, make sure the url rewrites are set.
63         # Otherwise 'git submodule update --init' prints confusing errors.
64         die <<EOF;
65 It seems you cloned this repository from GitHub. But your git config files
66 don't contain the url rewrites that are needed to make this work (GitHub
67 doesn't support '/' in repository names, so we use a different naming scheme
68 for the submodule repositories there).
69
70 Please run the following commands first:
71
72   git config --global url."git://github.com/ghc/packages-".insteadOf     git://github.com/ghc/packages/
73   git config --global url."http://github.com/ghc/packages-".insteadOf    http://github.com/ghc/packages/
74   git config --global url."https://github.com/ghc/packages-".insteadOf   https://github.com/ghc/packages/
75   git config --global url."ssh://git\@github.com/ghc/packages-".insteadOf ssh://git\@github.com/ghc/packages/
76   git config --global url."git\@github.com:/ghc/packages-".insteadOf      git\@github.com:/ghc/packages/
77
78 And then:
79
80   git submodule update --init
81   ./boot
82
83 Or start over, and clone the GHC repository from the haskell server:
84
85   git clone --recursive git://git.haskell.org/ghc.git
86
87 For more information, see:
88   * https://ghc.haskell.org/trac/ghc/wiki/Newcomers or
89   * https://ghc.haskell.org/trac/ghc/wiki/Building/GettingTheSources#CloningfromGitHub
90 EOF
91     }
92
93     # Check that we have all boot packages.
94     open PACKAGES, "< packages";
95     while (<PACKAGES>) {
96         if (/^#/) {
97             # Comment; do nothing
98         }
99         elsif (/^([a-zA-Z0-9\/.-]+) +([^ ]+) +[^ ]+ +[^ ]+$/) {
100             $dir = $1;
101             $tag = $2;
102
103             # If $tag is not "-" then it is an optional repository, so its
104             # absence isn't an error.
105             if (defined($required_tag{$tag})) {
106                 # We would like to just check for a .git directory here,
107                 # but in an lndir tree we avoid making .git directories,
108                 # so it doesn't exist. We therefore require that every repo
109                 # has a LICENSE file instead.
110                 if (! -f "$dir/LICENSE") {
111                     print STDERR "Error: $dir/LICENSE doesn't exist.\n";
112                     die "Maybe you haven't done 'git submodule update --init'?";
113                 }
114             }
115         }
116         else {
117             die "Bad line in packages file: $_";
118         }
119     }
120     close PACKAGES;
121 }
122
123 # Create libraries/*/{ghc.mk,GNUmakefile}
124 sub boot_pkgs {
125     my @library_dirs = ();
126
127     my $package;
128
129     for $package (glob "libraries/*/") {
130         $package =~ s/\/$//;
131         my $pkgs = "$package/ghc-packages";
132         if (-f $pkgs) {
133             open PKGS, "< $pkgs"
134                 or die "Failed to open $pkgs: $!";
135             while (<PKGS>) {
136                 chomp;
137                 s/\r//g;
138                 if (/.+/) {
139                     push @library_dirs, "$package/$_";
140                 }
141             }
142         }
143         else {
144             push @library_dirs, $package;
145         }
146     }
147
148     for $package (@library_dirs) {
149         my $dir = &basename($package);
150         my @cabals = glob("$package/*.cabal.in");
151         if ($#cabals < 0) {
152             @cabals = glob("$package/*.cabal");
153         }
154         if ($#cabals > 0) {
155             die "Too many .cabal file in $package\n";
156         }
157         if ($#cabals eq 0) {
158             my $cabal = $cabals[0];
159             my $pkg;
160             my $top;
161             if (-f $cabal) {
162                 $pkg = $cabal;
163                 $pkg =~ s#.*/##;
164                 $pkg =~ s/\.cabal.in$//;
165                 $pkg =~ s/\.cabal$//;
166                 $top = $package;
167                 $top =~ s#[^/]+#..#g;
168                 $dir = $package;
169                 $dir =~ s#^libraries/##g;
170
171                 print "Creating $package/ghc.mk\n";
172                 open GHCMK, "> $package/ghc.mk"
173                     or die "Opening $package/ghc.mk failed: $!";
174                 print GHCMK "${package}_PACKAGE = ${pkg}\n";
175                 print GHCMK "${package}_dist-install_GROUP = libraries\n";
176                 print GHCMK "\$(if \$(filter ${dir},\$(PACKAGES_STAGE0)),\$(eval \$(call build-package,${package},dist-boot,0)))\n";
177                 print GHCMK "\$(if \$(filter ${dir},\$(PACKAGES_STAGE1)),\$(eval \$(call build-package,${package},dist-install,1)))\n";
178                 print GHCMK "\$(if \$(filter ${dir},\$(PACKAGES_STAGE2)),\$(eval \$(call build-package,${package},dist-install,2)))\n";
179                 close GHCMK
180                     or die "Closing $package/ghc.mk failed: $!";
181
182                 print "Creating $package/GNUmakefile\n";
183                 open GNUMAKEFILE, "> $package/GNUmakefile"
184                     or die "Opening $package/GNUmakefile failed: $!";
185                 print GNUMAKEFILE "dir = ${package}\n";
186                 print GNUMAKEFILE "TOP = ${top}\n";
187                 print GNUMAKEFILE "include \$(TOP)/mk/sub-makefile.mk\n";
188                 print GNUMAKEFILE "FAST_MAKE_OPTS += stage=0\n";
189                 close GNUMAKEFILE
190                     or die "Closing $package/GNUmakefile failed: $!";
191             }
192         }
193     }
194 }
195
196 # autoreconf everything that needs it.
197 sub autoreconf {
198     my $dir;
199     my $fail;
200
201     foreach $dir (".", glob("libraries/*/")) {
202         if (-f "$dir/configure.ac") {
203             next if (my $pid = fork);
204             die "fork failed: $!" if (! defined $pid);
205             print "Booting $dir\n";
206             chdir $dir or die "can't change to $dir: $!";
207             exec("autoreconf");
208             exit 1;
209         }
210     }
211
212     # Wait for all child processes to finish.
213     while (wait() != -1) {
214         $fail = 1 if $?;
215     }
216
217     die "Running autoreconf failed" if $fail;
218 }
219
220 sub checkBuildMk {
221     if ($validate eq 0 && ! -f "mk/build.mk") {
222         print <<EOF;
223
224 WARNING: You don't have a mk/build.mk file.
225
226 By default a standard GHC build will be done, which uses optimisation
227 and builds the profiling libraries. This will take a long time, so may
228 not be what you want if you are developing GHC or the libraries, rather
229 than simply building it to use it.
230
231 For information on creating a mk/build.mk file, please see:
232     http://ghc.haskell.org/trac/ghc/wiki/Building/Using#Buildconfiguration
233
234 EOF
235     }
236 }
237
238 &sanity_check_line_endings();
239 &sanity_check_tree();
240 &boot_pkgs();
241 &autoreconf();
242 &checkBuildMk();
243