#!/usr/bin/perl -w

$HIP_BASE_VERSION_MAJOR = "3";
$HIP_BASE_VERSION_MINOR = "2";

# Need perl > 5.10 to use logic-defined or
use 5.006; use v5.10.1;
use Getopt::Long;
use Cwd;

# Return name of HIP compiler - either 'nvcc' or 'hcc'
#
use Getopt::Long;
use File::Basename;

Getopt::Long::Configure ( qw{bundling no_ignore_case});
GetOptions(
     "help|h" => \$p_help
    ,"path|p" => \$p_path
    ,"compiler|c" => \$p_compiler
    ,"platform|P" => \$p_platform
    ,"cpp_config|cxx_config|C" => \$p_cpp_config
    ,"full|f|info" => \$p_full,
    ,"version|v" => \$p_version,
    ,"check" => \$p_check,
    ,"newline|n" => \$p_newline
);

if ($p_help) {
    print "usage: hipconfig [OPTIONS]\n";
    print "  --path,  -p        : print HIP_PATH (use env var if set, else determine from hipconfig path)\n";
    print "  --cpp_config, -C   : print C++ compiler options\n";
    print "  --compiler, -c     : print compiler (hcc or nvcc)\n";
    print "  --platform, -P     : print platform (hcc or nvcc)\n";
    print "  --full, -f         : print full config\n";
    print "  --version, -v      : print hip version\n";
    print "  --check            : check configuration\n";
    print "  --newline, -n      : print newline\n";
    print "  --help, -h         : print help message\n";
    exit();
}

#---
# Function to parse config file
sub parse_config_file {
    my ($file, $config) = @_;
    if (open (CONFIG, "$file")) {
        while (<CONFIG>) {
            my $config_line=$_;
            chop ($config_line);
            $config_line =~ s/^\s*//;
            $config_line =~ s/\s*$//;
            if (($config_line !~ /^#/) && ($config_line ne "")) {
                my ($name, $value) = split (/=/, $config_line);
                $$config{$name} = $value;
            }
        }
        close(CONFIG);
    }
}

#---
# Function to check if executable can be run
sub can_run {
    my ($exe) = @_;
    `$exe --version 2>&1`;
    if ($? == 0) {
        return 1;
    } else {
        return 0;
    }
}

# Define HIP_PATH based on location of the script. Same as hipcc.
# Derive ROCM_PATH same as hipcc does. Others are relative to ROCM_PATH. 
$HIP_PATH=$ENV{'HIP_PATH'} // dirname(Cwd::abs_path("$0/../")); # use parent directory of hipcc
if (-e "$HIP_PATH/../.info/version") {
    $ROCM_PATH=$ENV{'ROCM_PATH'} // dirname("$HIP_PATH"); # use parent directory of HIP_PATH
} else {
    $ROCM_PATH=$ENV{'ROCM_PATH'} // "/opt/rocm";
}
$CUDA_PATH=$ENV{'CUDA_PATH'} // '/usr/local/cuda';
$HCC_HOME=$ENV{'HCC_HOME'} // "$ROCM_PATH/hcc";
$HSA_PATH=$ENV{'HSA_PATH'} // "$ROCM_PATH/hsa";

#---
#HIP_PLATFORM controls whether to use NVCC or HCC for compilation:
$HIP_PLATFORM=$ENV{'HIP_PLATFORM'};
if (not defined $HIP_PLATFORM) {
    if (can_run("$HCC_HOME/bin/hcc") or can_run("hcc")) {
        $HIP_PLATFORM = "hcc";
    } elsif (can_run("$CUDA_PATH/bin/nvcc") or can_run("nvcc")) {
        $HIP_PLATFORM = "nvcc";
    } else {
        # Default to hcc for now
        $HIP_PLATFORM = "hcc";
    }
}

if ($HIP_PLATFORM eq "hcc") {
    $CPP_CONFIG= " -D__HIP_PLATFORM_HCC__=   -I$HIP_PATH/include -I$HCC_HOME/include -I$HSA_PATH/include";
}
if ($HIP_PLATFORM eq "nvcc") {
    $CPP_CONFIG = " -D__HIP_PLATFORM_NVCC__=  -I$HIP_PATH/include -I$CUDA_PATH/include";
};

#---
# Read .hipVersion
my %hipVersion = ();
parse_config_file("$HIP_PATH/bin/.hipVersion", \%hipVersion);
$HIP_VERSION_MAJOR = $hipVersion{'HIP_VERSION_MAJOR'} // $HIP_BASE_VERSION_MAJOR;
$HIP_VERSION_MINOR = $hipVersion{'HIP_VERSION_MINOR'} // $HIP_BASE_VERSION_MINOR;
$HIP_VERSION_PATCH = $hipVersion{'HIP_VERSION_PATCH'} // "0";
$HIP_VERSION="$HIP_VERSION_MAJOR.$HIP_VERSION_MINOR.$HIP_VERSION_PATCH";

if ($p_path) {
    print "$HIP_PATH";
    $printed = 1;
}


if ($p_cpp_config) {
    print $CPP_CONFIG;
    $printed = 1;
}


if ($p_compiler or $p_platform) {
    print $HIP_PLATFORM;
    $printed = 1;
}

if ($p_version) {
    print $HIP_VERSION;
    $printed = 1;
}

if (!$printed or $p_full) {
    print "HIP version  : ", $HIP_VERSION, "\n\n";
    print "== hipconfig\n";
    print "HIP_PATH     : ", $HIP_PATH, "\n";
    print "HIP_PLATFORM : ", $HIP_PLATFORM, "\n";
    print "CPP_CONFIG   : ", $CPP_CONFIG, "\n";
    if ($HIP_PLATFORM eq "hcc")
    {
        print "\n" ;
        print "== hcc\n";
        print ("HSA_PATH     : $HSA_PATH\n");
        print ("HCC_HOME     : $HCC_HOME\n");
        system("$HCC_HOME/bin/hcc --version");
        system("$HCC_HOME/bin/llc --version");
        print ("HCC-cxxflags : ");
        system("$HCC_HOME/bin/hcc-config --cxxflags");
        print ("HCC-ldflags  : ");
        system("$HCC_HOME/bin/hcc-config --ldflags");
        printf("\n");
    }
    if ($HIP_PLATFORM eq "nvcc")  {
        print "\n" ;
        print "== nvcc\n";
        #print "CUDA_PATH   :", $CUDA_PATH";
        system("nvcc --version");

    }
    print "\n" ;

    print "=== Environment Variables\n";
    system("echo PATH=\$PATH");
    system("env | egrep '^HIP|^HSA|^HCC|^CUDA|^LD_LIBRARY_PATH'");


    print "\n" ;
    print "== Linux Kernel\n";
    print "Hostname     : "; system ("hostname");
    system ("uname -a");

    if (-e "/usr/bin/lsb_release") {
        system ("/usr/bin/lsb_release -a");
    }

    print "\n" ;
    $printed = 1;
}


if ($p_check) {
    print "\nCheck system installation:\n";

    printf ("%-70s", "check hipconfig in PATH...");
    # Safer to use which hipconfig instead of invoking hipconfig
    if (system ("which hipconfig > /dev/null 2>&1") != 0)  {
        print "FAIL\n";
    } else {
        printf "good\n";
    }

    if ($HIP_PLATFORM eq "hcc")  {
        $LD_LIBRARY_PATH=$ENV{'LD_LIBRARY_PATH'};
        printf("%-70s", "check LD_LIBRARY_PATH ($LD_LIBRARY_PATH) contains HSA_PATH ($HSA_PATH)...");
        if (index($LD_LIBRARY_PATH, $HSA_PATH) == -1) {
            print "FAIL\n";
        } else {
            printf "good\n";
        }

        # TODO - check hipcc / nvcc found and executable.
    }
}


if ($p_newline) {
    print "\n";
}
