#!/usr/bin/perl -w
## pocc-make.pl for pocc in /Users/pouchet
##
## Made by Louis-Noel Pouchet
## Contact: <louis-noel.pouchet@inria.fr>
##
## Started on  Wed Apr 15 18:50:36 2009 Louis-Noel Pouchet
## Last update Wed Jul 13 19:58:30 2011 Louis-Noel Pouchet
##
#
# pocc-make: this file is part of the PoCC project.
#
# PoCC, the Polyhedral Compiler Collection package
#
# Copyright (C) 2009 Louis-Noel Pouchet
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1
# of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# The complete GNU General Public Licence Notice can be found as the
# `COPYING.LESSER' file in the root directory.
#
# Author:
# Louis-Noel Pouchet <Louis-Noel.Pouchet@inria.fr>
#

use Switch;
use Term::ANSIColor;

## Some global variables.
$BDIR_MK = ".";
$INST_MK = ".";
$CONFIGURE = "";
$DRIVER = "";

$BUILDED_LIST = "";

sub print_config
{
    my (%config) = @_;
    ## Print config table.
    for $soft (keys %config) {
	for $field (keys %{$config{$soft}}) {
	    $value = $config{$soft}{$field};
	    print "$soft: $field -> $value\n";
	}
    }
}


sub read_config_file
{
    my ($file) = @_;
    my %config_data;
    open FILE, "$file" or die $!;
    my $mode = "";
    my $line;
    while (<FILE>) {
	if ($_ !~ /^#|^[\s\t]*\n/) {
	    $_ =~ s/(.*)\n/$1/g;
	    if ($_ =~ /^\[.*\]/) {
		$mode = $_;
		$mode =~ s/^\[(.*)\].*/$1/g;
	    }
	    else {
		my @entry = split(/:/, $_);
		$entry[0] =~ s/\s//g;
		my $data = $entry[1];
		my $i;
		for ($i = 2; $i <= $#entry; $i++) {
		    $data = $data . ":" . $entry[$i];
		}
		$config_data{$mode}{$entry[0]} = $data;
	    }
	}
    }

    #print_config(%config_data);

    return %config_data;
}


sub get_all_soft
{
    my %driver_data = read_config_file($DRIVER);
    my $softlist = $driver_data{"pocc-driver"}{"software-versions"};
    $softlist =~ s/\s+/ /g;
    $softlist =~ s/^\s//g;
    return split(/ /, $softlist);
}


sub needs_install
{
    return 1;
}


sub make_soft
{
    my ($soft, $force, %softinfo) = @_;
    my $softbootstrap = "";
    my $category = $softinfo{"category"};
    $category =~ s/\s//g;
    my $prefix = $BDIR_MK . "/" . $category;
    my $srcdir = $prefix . "/" . $soft;

    ## Bootstrap.
    my $force_configure = "no";
    if (defined($softinfo{"bootstrap"})) {
	$softbootstrap = $softinfo{"bootstrap"};
	$softbootstrap =~ s/^\s//g;
	$res = `find $srcdir -maxdepth 1 -name "*configure"`;
	if (($res eq "") || ($force eq "force-hard")) {
	    print "[PoCC] Bootstrapping in $srcdir\n";
	    $val = system("cd $srcdir && $softbootstrap");
	    $force_configure = "yes";
	    die "Error in bootsraping of $soft\n" if ($val != 0);
	}
    }
    ## Configure.
    my $mod = $softinfo{"module"};
    $mod =~ s/\s//g;
    my $instdir = $INST_MK . "/" . $category . "/install-$mod";
    my $config_args = "";
    if (defined($softinfo{"configure"})) {
	$config_args = $softinfo{"configure"};
	$config_args =~ s/\$poccsrcdir/$INST_MK/g;
    }
    $res = `find $srcdir -maxdepth 1 -name "*Makefile"`;
    if ($res eq "" || $force_configure eq "yes") {
	print "[PoCC] Configuring $soft in $srcdir with --disable-static --enable-shared --prefix=$instdir $config_args\n";
	$val = system("cd $srcdir && ./configure --disable-static --enable-shared --prefix=$instdir $config_args");
	die "Error in configuration of $soft\n" if ($val != 0);
    }

    $needed_pu = `find $BDIR_MK/driver/pocc-utils -newer $INST_MK/driver/install-pocc/include/pocc-utils 2>&1 | grep -v "/\.svn/"`;
    $needs_build = `find $srcdir -newer $instdir/include/$mod 2>&1| grep -v "/\.svn/"`;

    $needs_build = "yes" if (! ($needed_pu eq ""));
    if ($needs_build eq "") {
	if (defined($softinfo{"make-depends"})) {
	    $softinfo{"make-depends"} =~ s/\s+/ /g;
	    $softinfo{"make-depends"} =~ s/^\s//g;
	    @dep_modules = split(/ /, $softinfo{"make-depends"});
	    my $i;
	    for ($i = 0; $i <= $#dep_modules; $i++) {
		$needs_build = "yes" if ($BUILDED_LIST =~ /$dep_modules[$i]/);
	    }
	}
    }
    if (! ($needs_build eq "") || ($force eq "force")) {
	$val = system("cd $srcdir && make");
	die "Error in making of $soft\n" if ($val != 0);
	if (needs_install($srcdir,$instdir)) {
	    $val = system("cd $srcdir && make install");
	    die "Error in making install of $soft\n" if ($val != 0);
	}
	$BUILDED_LIST = $BUILDED_LIST . " " . $softinfo{"module"};
    }
    else {
	print "[PoCC-make] $soft already up-to-date\n";
    }
}


sub order_by_deps
{
    my ($mode, %config) = @_;
    my @soft = get_all_soft($mode);
    my $i;
    my $j;
    my $deps_i;
    my $deps_j;
    my $mod_i;
    my $mod_j;

    ## I am really lazy...
    my $converged;
    do {
	$converged = 1;
	for ($i = 0; $i < $#soft; $i++) {
	    if (defined($config{$soft[$i]}{"make-depends"})) {
		$deps_i = $config{$soft[$i]}{"make-depends"};
		$deps_i =~ s/\s+/ /g;
		$deps_i =~ s/^\s//g;
	    }
	    else {
		$deps_i = "";
	    }
	    $mod_i = $config{$soft[$i]}{"module"};
	    $mod_i =~ s/ //g;
	    for ($j = $i + 1; $j <= $#soft; $j++) {
		if (defined($config{$soft[$j]}{"make-depends"})) {
		    $deps_j = $config{$soft[$j]}{"make-depends"};
		    $deps_j =~ s/\s+/ /g;
		    $deps_j =~ s/^\s//g;
		}
		else {
		    $deps_j = "";
		}
		$mod_j = $config{$soft[$j]}{"module"};
		$mod_j =~ s/ //g;
		if ($deps_i =~ $mod_j) {
		    my $tmp = $soft[$i];
		    $soft[$i] = $soft[$j];
		    $soft[$j] = $tmp;
		    $deps_i = $deps_j;
		    $mod_i = $mod_j;
		    $converged = 0;
		}
	    }
	}
    }
    until ($converged != 0);

    return @soft;
}


sub make_all_soft
{
    print "[PoCC-make] Making all required soft\n";
    my ($mode, $force, %config) = @_;
    my @soft = order_by_deps($mode, %config);
    my $i;

    for ($i = 0; $i <= $#soft; $i++) {
	make_soft($soft[$i], $force, %{$config{$soft[$i]}});
    }
}


sub make
{
    my ($basedir, $inst_prefix, $soft, $force) = @_;
    $BDIR_MK = $basedir;
    $INST_MK = $inst_prefix;
    $CONFIGURE = "$BDIR_MK/config/configure.cfg";
    $DRIVER = "$BDIR_MK/config/driver.cfg";
    print (colored ("[PoCC-make] Full Make of PoCC. This takes a while...", "green green"), "\n");
    my %config_data = read_config_file($CONFIGURE);

    if ($soft eq "all") {
	#make_pocc_utils();
	make_all_soft($mode, $force, %config_data);
	#make_pocc();
    }
    else {
	if (! defined($config_data{$soft})) {
	    die "Unkown software $soft. Please update config/configure.cfg\n";
	}
	make_soft($soft, $force, %{$config_data{$soft}});
    }

     print (colored ("[PoCC-make] Done", "green green"), "\n");
}
