#! /usr/bin/perl use File::FnMatch qw(fnmatch); use MdwOpt; our $CROSSDIR = "@crossdir@"; (our $ME = $0) =~ s:^.*/::; ###-------------------------------------------------------------------------- ### Utilities. sub usage (*) { my ($fh) = @_; print $fh "usage: $ME [-kns] [-j N] =ARCHGLOB|:FLAVOUR ... [--] CMD [ARGS ...]\n"; } sub barf ($) { my ($msg) = @_; print STDERR "$0: $msg\n"; exit 2; } ###-------------------------------------------------------------------------- ### Read and prepare the configuration. our %C = (); open my $fh, "<", "$CROSSDIR/etc/config.sh" or barf "open config: $!"; while (<$fh>) { chomp; if (/^\s*(#|$)/) { next; } if (!/^([^=]+)='(.*)'$/) { barf "bad config line `$_'"; } my ($k, $v) = ($1, $2); $v =~ s/'\\''/'/g; $C{$k} = $v; } our @ALLARCH; our %FLAVOUR; for my $f (split ' ', $C{"FLAVOURS"}) { (my $v = $f) =~ tr/-/_/; my @a = split ' ', $C{"${v}_ARCHS"}; @{$FLAVOUR{$f}} = @a; push @ALLARCH, @a; } ###-------------------------------------------------------------------------- ### Parse the command line. our @ARCH = (); our $JOBS = undef; our $KEEPGOING = 0; our $SILENT = 0; our $DRYRUN = 0; our $DIR = "."; our $MARKER = "{}"; our @CMD = (); my $mo = new MdwOpt "hC:j:km:ns", { "help" => { 'return' => "h" }, "directory" => { 'return' => 'C', 'arg' => 'req' }, "jobs" => { 'return' => "j", 'arg' => 'req' }, "keep-going" => { 'return' => "k" }, "marker" => { 'return' => "m", 'arg' => 'req' }, "dry-run" => { 'return' => "n" }, "silent" => { 'return' => "s" } }, \@ARGV, ['inorder']; my $bad = 0; OPT: for (;;) { my ($opt, $arg) = $mo->read; last OPT unless defined $opt; if ($opt eq "h") { usage STDOUT; exit 0; } elsif ($opt eq "C") { $DIR = $arg; } elsif ($opt eq "j") { $arg =~ /^[+]?\d+$/ or barf "bad integer `$arg'"; $JOBS = $arg; } elsif ($opt eq "k") { $KEEPGOING = 1; } elsif ($opt eq "m") { $MARKER = $arg; } elsif ($opt eq "n") { $DRYRUN = $arg; } elsif ($opt eq "s") { $SILENT = $arg; } elsif ($opt eq '') { if ($arg =~ /^=(.*)$/) { my $pat = $1; my $match = 0; ARCH: for my $a (@ALLARCH) { next ARCH unless fnmatch $pat, $a; $match = 1; push @ARCH, $a; } $match or barf "no architectures match `$pat'"; } elsif ($arg =~ /^:(.*)$/) { my $f = $1; exists $FLAVOUR{$f} or barf "no architeture flavour `$f'"; push @ARCH, @{%FLAVOUR{$f}}; } else { push @CMD, $arg; last OPT; } } else { $bad = 1; } } $bad = 1 unless @ARCH && @CMD; push @CMD, $mo->rest, @{$mo->{argv}}; if ($bad) { usage STDERR; exit 2; } ###-------------------------------------------------------------------------- ### Hack the arguments and run `make'. sub hack ($) { my ($x) = @_; $x =~ s/'/'\\''/g; $x =~ s/\$/\$\$/g; $x =~ s/\Q$MARKER/\$*/g; return "'$x'"; } our $TARGET = "run"; if ($CMD[0] eq 'make') { $TARGET = "run-make"; shift @CMD; } our @MAKE = ("make"); push @MAKE, "-f$CROSSDIR/Makefile"; push @MAKE, "-j$JOBS" if defined $JOBS; push @MAKE, "-k" if $KEEPGOING; push @MAKE, "-n" if $DRYRUN; push @MAKE, "-s" if $SILENT; push @MAKE, $TARGET; push @MAKE, "ARCHS=" . join " ", @ARCH; push @MAKE, "ARGS=" . join " ", map { hack $_ } @CMD; push @MAKE, "CROSSDIR=$CROSSDIR"; push @MAKE, "DIR=" . hack $DIR; exec @MAKE; barf "make: $!"; ###----- That's all, folks --------------------------------------------------