Commit | Line | Data |
---|---|---|
6cb0a33a MW |
1 | #! /usr/bin/perl |
2 | ||
3 | use Data::Dumper; | |
4 | ||
5 | use File::FnMatch qw(fnmatch); | |
6 | use MdwOpt; | |
7 | ||
8 | our $CROSSDIR = "@crossdir@"; | |
9 | (our $ME = $0) =~ s:^.*/::; | |
10 | ||
11 | ###-------------------------------------------------------------------------- | |
12 | ### Utilities. | |
13 | ||
14 | sub usage (*) { | |
15 | my ($fh) = @_; | |
16 | print $fh | |
17 | "usage: $ME [-j N] =ARCHGLOB|:FLAVOUR ... [--] CMD [ARGS ...]\n"; | |
18 | } | |
19 | sub barf ($) { | |
20 | my ($msg) = @_; | |
21 | print STDERR "$0: $msg\n"; | |
22 | exit 2; | |
23 | } | |
24 | ||
25 | ###-------------------------------------------------------------------------- | |
26 | ### Read and prepare the configuration. | |
27 | ||
28 | our %C = (); | |
29 | open my $fh, "<", "$CROSSDIR/etc/config.sh" or barf "open config: $!"; | |
30 | while (<$fh>) { | |
31 | chomp; | |
32 | if (/^\s*(#|$)/) { next; } | |
33 | if (!/^([^=]+)='(.*)'$/) { barf "bad config line `$_'"; } | |
34 | my ($k, $v) = ($1, $2); | |
35 | $v =~ s/'\\''/'/g; | |
36 | $C{$k} = $v; | |
37 | } | |
38 | ||
39 | our @ALLARCH; | |
40 | our %FLAVOUR; | |
41 | for my $f (split ' ', $C{"FLAVOURS"}) { | |
42 | (my $v = $f) =~ tr/-/_/; | |
43 | my @a = split ' ', $C{"${v}_ARCHS"}; | |
44 | @{$FLAVOUR{$f}} = @a; | |
45 | push @ALLARCH, @a; | |
46 | } | |
47 | ||
48 | ###-------------------------------------------------------------------------- | |
49 | ### Parse the command line. | |
50 | ||
51 | our @ARCH = (); | |
52 | our $JOBS = undef; | |
53 | our $DIR = "."; | |
54 | our $MARKER = "{}"; | |
55 | our @CMD = (); | |
56 | ||
57 | my $mo = new MdwOpt "hC:j:m:", | |
58 | { "help" => { 'return' => "h" }, | |
59 | "directory" => { 'return' => 'C', 'arg' => 'req' }, | |
60 | "jobs" => { 'return' => "j", 'arg' => 'req' }, | |
61 | "marker" => { 'return' => "m", 'arg' => 'req' } }, | |
62 | \@ARGV, | |
63 | ['inorder']; | |
64 | my $bad = 0; | |
65 | OPT: for (;;) { | |
66 | my ($opt, $arg) = $mo->read; | |
67 | last OPT unless defined $opt; | |
68 | if ($opt eq "h") { usage STDOUT; exit 0; } | |
69 | elsif ($opt eq "C") { $DIR = $arg; } | |
70 | elsif ($opt eq "j") | |
71 | { $arg =~ /^[+]?\d+$/ or barf "bad integer `$arg'"; $JOBS = $arg; } | |
72 | elsif ($opt eq "m") { $MARKER = $arg; } | |
73 | elsif ($opt eq '') { | |
74 | if ($arg =~ /^=(.*)$/) { | |
75 | my $pat = $1; | |
76 | my $match = 0; | |
77 | ARCH: for my $a (@ALLARCH) { | |
78 | next ARCH unless fnmatch $pat, $a; | |
79 | $match = 1; push @ARCH, $a; | |
80 | } | |
81 | $match or barf "no architectures match `$pat'"; | |
82 | } elsif ($arg =~ /^:(.*)$/) { | |
83 | my $f = $1; | |
84 | exists $FLAVOUR{$f} or barf "no architeture flavour `$f'"; | |
85 | push @ARCH, @{%FLAVOUR{$f}}; | |
86 | } else { | |
87 | push @CMD, $arg; | |
88 | last OPT; | |
89 | } | |
90 | } else { | |
91 | $bad = 1; | |
92 | } | |
93 | } | |
94 | $bad = 1 unless @ARCH && @CMD; | |
95 | push @CMD, $mo->rest, @{$mo->{argv}}; | |
96 | if ($bad) { usage STDERR; exit 2; } | |
97 | ||
98 | ###-------------------------------------------------------------------------- | |
99 | ### Hack the arguments and run `make'. | |
100 | ||
101 | sub hack ($) { | |
102 | my ($x) = @_; | |
103 | $x =~ s/'/'\\''/g; | |
104 | $x =~ s/\$/\$\$/g; | |
105 | $x =~ s/\Q$MARKER/\$*/g; | |
106 | return "'$x'"; | |
107 | } | |
108 | ||
109 | our $TARGET = "run"; | |
110 | if ($CMD[0] eq 'make') { $TARGET = "run-make"; shift @CMD; } | |
111 | our @MAKE = ("make"); | |
112 | push @MAKE, "-f$CROSSDIR/Makefile"; | |
113 | push @MAKE, "-j$JOBS" if defined $JOBS; | |
114 | push @MAKE, $TARGET; | |
115 | push @MAKE, "ARCHS=" . join " ", @ARCH; | |
116 | push @MAKE, "ARGS=" . join " ", map { hack $_ } @CMD; | |
117 | push @MAKE, "CROSSDIR=$CROSSDIR"; | |
118 | push @MAKE, "DIR=" . hack $DIR; | |
119 | exec @MAKE; | |
120 | barf "make: $!"; | |
121 | ||
122 | ###----- That's all, folks -------------------------------------------------- |