
#
# A rule is a target, dependencies, and a build command.
# Dependencies are separated by spaces.
#

$rulenum = 0;
$now = time;

sub Rule
{
    local ($target) = shift;
    print "$target depeneds on $_[0]\n"
	if ($print_rules);
    $alltargets[$rulenum] = $target;
    $alldepends[$rulenum] = shift;
    $allcommand[$rulenum] = shift;
    $allrules{$target} .= ' ' . $rulenum;
    $rulenum++;
}

sub ImplicitRule
{
    local ($src, $depends) = @_;
    local ($target);
    if ($src =~ /\.c$/) {
	$target = $` . '.o';
	&Rule($target, "$src $headers", $CCRule);
	return $target;
    } elsif ($src =~ /\.C$/) {
	$target = $` . '.o';
	&Rule($target, "$src $headers", $CPlusPlusRule);
	return $target;
    } else {
	print STDERR "Do not know what to do with $src\n";
	return $src;
    }
}


sub Make
{
    local ($target) = shift;
    if ($status{$target} eq 'b') {
	print STDERR "Warning: recursive dependency detected\n";
    } elsif ($status{$target} eq 'B') {
	return $buildtime{$target};
    } else {
	$status{$target} = 'b';
	local (@rules) = split(' ', $allrules{$target});
	local ($dep, $rule, $when, $when1);
	local (@stat) = stat $target;
	if (@stat) {
	    $buildtime{$target} = $stat[9];
	} else {
	    if (!@rules) {
		print "Do not know how to build $target\n";
		$buildtime{$target} = -1;
	    }
	}
      buildme:
	for $rule (@rules) {
	    local (@depends) = split(' ', $alldepends[$rule]);
	    $when = 0;
	    for $dep (@depends) {
		$when1 = &Make($dep);
		if ($when1 == -1) {
		    print "Cannot build $target because build of $dep failed\n";
		    $buildtime{$target} = -1;
		    last buildme;
		}
		$when = $when1 if ($when1 > $when);
	    }
	    if ($when >= $buildtime{$target}) {
		eval "$allcommand[$rule]";
		if ($@) {
		    print STDERR "Build of $target failed: $@";
		    $buildtime{$target} = -1;
		    last buildme;
		}
		$buildtime{$target} = $now;
	    }
	}
	$status{$target} = 'B';
	return $buildtime{$target};
    }
}

sub Sh
{
    print "@_\n";
    local($status) = $punt_commands ? 0 : ((system @_) >> 8);
    if ($status) {
	die "exit code $status";
    }
}
    
$CCRule = '&Sh("$CC " . (defined($CFlags{$target}) ? $CFlags{$target} : $CFlags) . " -c $depends[0]")';
$CPlusPlusRule = '&Sh("$CPlusPlus " . 
      (defined($CPlusPlusFlags{$target}) ? $CPlusPlusFlags{$target} : $CPlusPlusFlags) . 
      " -c -o $target $depends[0]")';
$LinkRule = '&Sh("$LINK " . (defined($LDFlags{$target}) ? $LDFlags{$target} : $LDFlags) . 
    " -o $target @depends " . $Libraries{$target})';

sub SimpleProgramTarget
{
    local ($target) = shift;
    local ($objs, $obj, $headers, $src);
    for (@_) {
	($src,$headers) = split(':');
	$obj = &ImplicitRule ($src, $headers);
	$objs .= " $obj";
    }
    &Rule ($target, $objs, $LinkRule);
}


$CC = '/bin/cc';
$LINK = '/bin/cc';
$CFlags = '-g';
$CPlusPlus = 'gcc';
$CPlusPlusFlags = '-g';

