#!/usr/bin/perl -w
# *****************************************************************
# * The B3 Project                                                *
# *                                                               *
# * http://www.star.ucl.ac.uk/~rhdt/b3/                           *
# *                                                               *
# * Copyright (C) 2003-2005, The B3 Project                       *
# *                                                               *
# * For conditions regarding warranty, copying and distribution,  *
# * see the accomanying b3/COPYING file which comes with the b3   *
# * distribution                                                  *
# *****************************************************************
#
# File      : $Source: /usr/users/townsend/cvsroot/b3/src/tools/fpx3_deps,v $
# Developer : Rich Townsend <rhdt@star.ucl.ac.uk>
# Synopsis  : Makefile dependency generator for fpx3
#
# $Log: fpx3_deps,v $
# Revision 1.2  2008/12/07 19:35:31  townsend
# Minor fix
#
# Revision 1.1  2006/05/02 00:37:02  rhdt
# Added source
#

# Constants

$FPX3_EXEC = './fpx3';

$FPP_SUFFIX = 'fpp';
$F90_SUFFIX = 'f90';

# Split the command-line arguments into program 
# units and fpx3 arguments

@units = grep !/^-/, @ARGV;
@args = grep /^-/, @ARGV;

# Build up the dependency table

%dep_table = ();

foreach my $unit (@units) {

# Skip the unit if it has already been processed

    exists($dep_table{$unit}) && next;

# Skip if there is no preprocessor file associated
# with the unit

    my $file = "$unit.$FPP_SUFFIX";

    -f $file || next;

# Run the file through fpx3, piping the output
# into a buffer

    open FPX3, "$FPX3_EXEC -nofo ".join(' ', @args)." < $file|" 
	or die "Unable to open pipe to $FPX3_EXEC\n$!";
    my $buffer = join('', <FPX3>);
    close FPX3;

# Extract the dependency info

    foreach $field (('includes', 'uses', 'provides')) {
	$buffer =~ /^!   $field: (.*)$/m;
	$dep_table{$unit}->{$field} = [split(' ', lc $1)];
    }

# Add the uses to the unit list

    push @units, @{$dep_table{$unit}->{'uses'}};

# Loop around

}

# Write out the dependency info

foreach $unit (sort keys %dep_table) {

# Module & include dependencies

    print "$unit.o $unit.mod : ".join(' ', (map "$_.mod", @{$dep_table{$unit}->{'uses'}}), 
				           @{$dep_table{$unit}->{'includes'}})."\n";

# Executable dependencies - only add in if the unit
# has a null provides

    if(!@{$dep_table{$unit}->{'provides'}}) {
	print "$unit : ".join(' ', map "$_.o", keys %{&flatten_deps($unit)})."\n";
    }

}

# Finish

sub flatten_deps {

    my $unit = $_[0];

# Find *all* units that $unit depends upon (including
# itself)

    if(-f "$unit.$FPP_SUFFIX" || -f "$unit.$F90_SUFFIX") {

	my $deps = { $unit => 1 };

	foreach (@{$dep_table{$unit}->{'uses'}}) {
	    $deps = { %{$deps}, %{&flatten_deps($_)} };
	}

	return $deps;

    }

    else {

# Ignore the unit if it has no associated file(s)

	return {};

    }

}
