+die unless $ARGV[0] eq '--srcdir';
+die unless @ARGV>=2;
+shift @ARGV;
+($srcdir, @subdirs) = @ARGV;
+
+our $root = [ '.', [ ] ];
+# each node is [ 'relative subdir name', \@children ]
+
+sub build_tree () {
+ foreach my $subdir (@subdirs) {
+ my @path = $subdir eq '.' ? () : split m{/+}, $subdir;
+ my $node = $root;
+ foreach my $d (@path) {
+ my ($c,) = grep { $_->[0] eq $d } @{ $node->[1] };
+ if (!$c) {
+ $c = [ $d, [ ] ];
+ push @{ $node->[1] }, $c;
+ }
+ $node = $c;
+ }
+ }
+}
+
+sub target_varname ($$) {
+ my ($var_prefix, $target) = @_;
+ return $var_prefix.'TARGETS'.($target eq 'all' ? '' : "_$target");
+}
+
+our $writing_output;
+our %output_files;
+
+sub close_any_output_file() {
+ return unless defined $writing_output;
+ O->error and die "error writing $writing_output.tmp: $! (?)\n";
+ close O or die "error closing $writing_output.tmp: $!\n";
+ $writing_output = undef;
+}
+
+sub start_output_file ($) {
+ close_any_output_file();
+ ($writing_output) = @_;
+ die if $output_files{$writing_output}++;
+ my $tmp = "$writing_output.tmp";
+ open O, ">", $tmp or die "create $tmp: $!\n";
+}
+
+sub install_output_files () {
+ close_any_output_file();
+ foreach my $f (sort keys %output_files) {
+ rename "$f.tmp", $f or die "install new $f: $!\n";
+ }
+}
+
+sub o {
+ die unless defined $writing_output;
+ print O @_ or die "error writing $writing_output.tmp: $!\n";
+}
+
+sub write_makefile ($$) {
+ my ($dir_prefix,$depth) = @_;
+ start_output_file("${dir_prefix}Makefile");
+ my $cd = $depth ? join('/', ('..',) x $depth) : '.';
+ o <<END;
+default: all