perkeep/build.pl

339 lines
7.9 KiB
Perl
Executable File

#!/usr/bin/perl
#
# Copyright 2011 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# A simple little build system.
#
# See the configuration at the bottom of this file.
use strict;
use Getopt::Long;
use FindBin;
my $opt_list;
my $opt_eachclean;
my $opt_verbose;
my $opt_test;
chdir($FindBin::Bin) or die "Couldn't chdir to $FindBin::Bin: $!";
GetOptions("list" => \$opt_list,
"eachclean" => \$opt_eachclean,
"verbose" => \$opt_verbose,
"test" => \$opt_test,
) or usage();
sub usage {
die <<EOM
Usage:
build.pl all # build all
build.pl allfast # build all targets that compile quickly
build.pl clean # clean all
build.pl REGEXP # builds specific target, if it matches any targets
build.pl --list
build.pl --eachclean # builds each target with a full clean before it
# (for testing that dependencies are correct)
Other options:
--verbose|-v Verbose
--test|-t Run tests where found
EOM
;
}
my %built; # target -> bool (was it already built?)
my %targets; # dir -> { deps => [ ... ], }
read_targets();
if ($opt_list) {
print "Available targets:\n";
foreach my $target (sort keys %targets) {
print " * $target\n";
}
exit;
}
if ($opt_eachclean) {
my $target = shift;
die "--eachclean doesn't take a target\n" if $target;
foreach my $target (sort keys %targets) {
clean();
%built = ();
build($target);
}
exit;
}
my $target = shift or usage();
if ($target eq "clean") {
clean();
exit;
}
if ($target eq "allfast") {
foreach my $target (sort grep { !$targets{$_}{tags}{not_in_all} } keys %targets) {
build($target);
}
exit;
}
if ($target eq "all") {
foreach my $target (sort keys %targets) {
build($target);
}
exit;
}
my @matches = grep { /$target/ } sort keys %targets;
unless (@matches) {
die "No build targets patching pattern /$target/\n";
}
if (@matches > 1) {
if (scalar(grep { $_ eq $target } @matches) == 1) {
@matches = ($target);
} else {
die "Build pattern is ambiguous, matches multiple targets:\n * " . join("\n * ", @matches) . "\n";
}
}
build($matches[0]);
sub v {
return unless $opt_verbose;
my $msg = shift;
chomp $msg;
print STDERR "# $msg\n";
}
sub clean {
for my $root ("$ENV{GOROOT}/pkg/linux_amd64",
"$ENV{GOROOT}/pkg/linux_386") {
for my $pkg ("camli", "crypto/openpgp") {
my $dir = "$root/$pkg";
next unless -d $dir;
system("rm", "-rfv", $dir);
}
}
foreach my $target (sort keys %targets) {
print STDERR "Cleaning $target\n";
system("make", "-C", $target, "clean");
}
}
sub perform_go_check() {
if ($ENV{GOROOT}) {
die "Your \$GOROOT environment variable isn't a directory.\n" unless -d $ENV{GOROOT};
return 1;
}
# No GOROOT set; see if they have 8g or 6g
if (`which 8g` =~ /\S/ || `which 6g` =~ /\S/) {
die "You seem to have Go installed, but you don't have your ".
"\$GOROOT environment variable set.\n".
"Can't build without it.\n";
}
die "You don't seem to have Go installed. See:\n\n http://golang.org/doc/install.html\n\n";
}
sub build {
my @history = @_;
my $target = $history[0];
if ($target =~ m!/go/!) {
perform_go_check();
}
my $already_built = $built{$target} || 0;
v("Building '$target' (already_built=$already_built; via @history)");
return if $already_built;
$built{$target} = 1;
if ($target =~ /^ext:(.+)/) {
die "\$GOROOT not set" unless $ENV{GOROOT} && -d $ENV{GOROOT};
my $golib = $1;
my @files = glob("$ENV{GOROOT}/pkg/*/${golib}.a");
unless (@files) {
die "You need to run:\n\n\tgoinstall $golib\n";
}
return;
}
my $t = $targets{$target} or die "Bogus build target: $target\n";
# Dependencies first.
my @deps = @{ $t->{deps} };
if (@deps) {
v("Deps of '$target' are @deps");
foreach my $dep (@deps) {
build($dep, @history);
}
v("built deps for $target, now can build");
}
my @quiet = ("--silent");
@quiet = () if $opt_verbose;
if (system("make", @quiet, "-C", $target, "install") != 0) {
my $chain = "";
if (@history > 1) {
$chain = "(via chain @history)";
}
die "Error building $target $chain\n";
}
v("Built '$target'");
if ($opt_test) {
opendir(my $dh, $target);
my @test_files = grep { /_test\.go/ } grep { !/~$/ } readdir($dh);
closedir($dh);
if (@test_files) {
if (system("make", @quiet, "-C", $target, "test") != 0) {
die "Tests failed for $target\n";
}
}
}
}
sub read_targets {
my $last;
for (<DATA>) {
if (m!^\TARGET:\s*(.+)\s*$!) {
my $target = $1;
$last = $target;
$targets{$target} ||= { deps => [] };
next;
}
s/\#.*//;
if (m!^\s+\-\s(\S+)\s*$!) {
my $dep = $1;
my $t = $targets{$last} or die "Unexpected dependency line: $_";
push @{$t->{deps}}, $dep;
next;
}
if (m!^\s+\=\s*(\S+)\s*$!) {
my $tag = $1;
my $t = $targets{$last} or die "Unexpected dependency line: $_";
$t->{tags}{$tag} = 1;
next;
}
}
#use Data::Dumper;
#print Dumper(\%targets);
}
__DATA__
TARGET: server/go/httputil
# (no deps)
TARGET: server/go/auth
# (no deps)
TARGET: server/go/webserver
# (no deps)
TARGET: server/go/blobserver
- server/go/httputil
- lib/go/blobref
- lib/go/blobserver
- lib/go/blobserver/handlers
- lib/go/blobserver/localdisk
- lib/go/mysqlindexer
- server/go/auth
- server/go/webserver
TARGET: server/go/sigserver
- server/go/webserver
- lib/go/blobref
- server/go/auth
- server/go/httputil
- lib/go/jsonsign
- lib/go/ext/openpgp/packet
- lib/go/ext/openpgp/error
- lib/go/ext/openpgp/armor
TARGET: website
TARGET: clients/go/camput
- lib/go/client
- lib/go/blobref
- lib/go/schema
- lib/go/jsonsign
TARGET: clients/go/camget
- lib/go/client
- lib/go/blobref
- lib/go/schema
TARGET: clients/go/camsync
- lib/go/client
- lib/go/blobref
TARGET: lib/go/ext/openpgp/error
TARGET: lib/go/ext/openpgp/packet
- lib/go/ext/openpgp/error
TARGET: lib/go/ext/openpgp/armor
- lib/go/ext/openpgp/error
- lib/go/ext/openpgp/packet
TARGET: lib/go/schema
- lib/go/blobref
- lib/go/testing
TARGET: lib/go/testing
TARGET: lib/go/client
- lib/go/blobref
TARGET: lib/go/jsonsign
- lib/go/blobref
- lib/go/ext/openpgp/packet
- lib/go/ext/openpgp/armor
- lib/go/ext/openpgp/error
TARGET: lib/go/blobref
- lib/go/testing
TARGET: lib/go/blobserver
- lib/go/blobref
- lib/go/testing
TARGET: lib/go/blobserver/handlers
- server/go/auth
- server/go/httputil
- lib/go/blobserver
- lib/go/httprange
- lib/go/testing
TARGET: lib/go/blobserver/localdisk
- lib/go/blobref
- lib/go/blobserver
- lib/go/testing
TARGET: lib/go/httprange
TARGET: clients/android/uploader
=not_in_all # too slow
TARGET: lib/go/mysqlindexer
- ext:github.com/Philio/GoMySQL
- lib/go/blobref
- lib/go/blobserver
- lib/go/testing