#!/usr/bin/perl -w

# usage: put this file in $DATADIR, then make symlinks for each
# of the compilers:
# 
#  cd $DATADIR
#  for arch in powerpc i386; do
#    for version in "" "-3.3" "-4.0"; do
#      for gcc in cc c++ gcc g++; do
#        if [ -f "/usr/bin/${gcc}${version}" ]; then
#          ln -s "/usr/bin/${gcc}${version}" "${arch}-apple-darwin${DARWINVER}-${gcc}${version}"
#        fi
#      done
#    done
#  done
# 
# install distcc and ccache, then set:
#
# export CCACHE_PREFIX=$DATADIR/gcc-translator.pl
# export DISTCC_TRANS=true
#
# assuming you've got ccache set up to do symlinks to take over gcc, the gcc-translator script
# will automatically translate gcc calls into target-style gcc names (powerpc-apple-darwin8-gcc)

use strict;

my $DISTCCBIN = '/sw/bin/distcc';
my $DATADIR = '/sw/var/lib/distcc';

if ($ENV{'DISTCC_TRANS'} !~ /^(true|1|yes|y)$/i) {
	exit run_command($DISTCCBIN, @ARGV);
}

my $DEBUG = 0;

my $arch_lookup = {
	ppc   => 'powerpc',
	ppc64 => 'powerpc',
	i386  => 'i386',
};

my $reverse_arch_lookup = {
	'powerpc' => 'ppc',
	'i386'    => 'i386',
};

$ENV{'PATH'} = $DATADIR . ':' . $ENV{'PATH'};

if ($0 =~ /(powerpc|i386)-apple-([^\d]+)(\d+)-(.*)$/) {
	my ($archname, $os, $version, $compiler) = ($1, $2, $3, $4);

	my @command = ('/usr/bin/' . $compiler);
	if (exists $reverse_arch_lookup->{$archname}) {
		push(@command, '-arch', $reverse_arch_lookup->{$archname});
	}
	push(@command, @ARGV);
	exit run_command(@command);
}

my $compiler = shift(@ARGV) || 'gcc';
if ($compiler !~ m#/#) {
	$compiler = which($compiler);
}

my $arch;
my @args;

$compiler = render_symlinks($compiler);

my $lastarg;
for my $arg (@ARGV) {
	if ($arg eq "-arch") {
		$lastarg = "arch";
	} elsif (defined $lastarg and $lastarg eq "arch") {
		$arch = $arch_lookup->{$arg} if (exists $arch_lookup->{$arg});
		$lastarg = undef;
	} else {
		push(@args, $arg);
	}
}

chomp(my $uname = lc(`uname -s -r -p`));
my ($osname, $version, $archname) = split(/\s+/, $uname);
$version =~ s/^(\d+).*$/$1/;

if (not defined $arch) {
	$arch = $archname;
}

$compiler = "${arch}-apple-${osname}${version}-" . basename($compiler);

my @command = ($DISTCCBIN, $compiler, @args);
exit run_command(@command);

sub run_command {
	print STDERR "@command\n" if ($DEBUG);

	my $exit = system(@_);

	if ($exit == -1) {
		die "failed to execute $DISTCCBIN $compiler @args\n";
	} elsif ($exit & 127) {
		printf STDERR "child died with signal %d, %s coredump\n", ($? & 127),  ($? & 128) ? 'with' : 'without';
	} else {
		return int($exit >> 8);
	}
}

sub render_symlinks {
	my $filename = shift;

	if (defined $filename and -l $filename) {
		my $linkname = readlink($filename);
		if ($linkname !~ m#/#) {
			$linkname = dirname($filename) . $linkname;
		}
		return render_symlinks($linkname);
	}

	return $filename;
}

sub which {
	my $filename = shift;

	for my $dir (split(/:/, $ENV{'PATH'})) {
		my $fullname = $dir . '/' . $filename;
		next if (-l $fullname and (readlink($fullname) =~ /distcc/ or readlink($fullname) =~ /ccache/));

		if (-f $dir . '/' . $filename) {
			return $dir . '/' . $filename;
		}
	}
}

sub basename {
	my $filename = shift;

	return @{[ $filename =~ m#^.*/([^/]+)$#]}[0];
}

sub dirname {
	my $filename = shift;

	return @{[ $filename =~ m#^(.*/)[^/]*$# ]}[0];
}
