#!/bin/bash
#
# $Id: buildpack 6490 2020-09-10 17:36:27Z idculv $
#
#****s* Scripts/buildpack *
#----------------------------------------------------------------------------------
# SYNOPSIS
#  buildpack   -  build an ROPP module or dependency package for ROPP
#
# USAGE
#   > buildpack package compiler [[NO]CLEAN]
#   For summary help:
#   > buildpack [?|-h|--help]
#
# ARGUMENTS
#   $1 = package generic name (ropp_io, mobufr, ecbufr, eccodes, grib, zlib, hdf5,
#        netcdf, netcdff...) or if blank '?', '-h' or '--help' for summary help
#   $2 = compiler ID (ifort, gfortran, nagfor...)
#        (required, unless help needed)
#   $3 = CLEAN to force clean build from latest archive (tar/zip) file, or
#        NOCLEAN to not perform a 'make clean' before 'make' (or equivalents)
#        (default: use existing install but clean it first)
#
# ENVIRONMENT VARIABLES
#   The following must be pre-set before running this script:
#     ROPP_ROOT  - path to ROPP root installation directory
#
# DESCRIPTION
#   If no package source directory (<package> or <package>-<version>) is
#   found, an archive (tar.gz/tar.Z/tgz/bz2/zip) file is searched for and if
#   found is decompressed and the archive files extracted to the package
#   directory tree. If he third argument is 'CLEAN' then any existing package
#   directory tree is first wiped, forcing a re-install from an archive.
#   The package is then processed, which in most cases any previous build
#   (object/library files etc) is cleaned (unless the 3rd argument is
#   'NOCLEAN'), then the package-dependent build commands are run. This may
#   require compiler- and OS-specific configure files from the configure/
#   sub-directory of the top-level directory containing this script.
#   Libraries & F90 modules are then built and installed to the ROPP compiler
#   directory in ROPP_ROOT/<compiler> or as set in the appropriate configure
#   file.
#   Compiler-independent files, such as BUFR run-time tables, are installed
#   to ROPP_ROOT/data.
#   If the script is run with no arguments or just ?, -h or --help, summary
#   usage info is written to stdout.
#
# FILES
#   The following files are assumed to be present in the same directory
#   in which this script is placed (e.g. ROPP_SRC).
#   1) Package archive files (compressed tarball or zipfile), usually as:
#      <package>-<version>.<type> where type is one of tar.gz, tar.bz2, tgz
#      or zip (e.g. netcdf-c-4.4.0.tar.gz or bufr-25.0.1.tar.gz)
#   2) Directory configure/ containing package configure file usually as:
#      <package>_configure_<compiler>_<os>
#      (e.g. configure/netcdf_configure_ifort_linux)
#      (Note: MetDB BUFR does not use configure files)
#
# INSTALLATION
#   Packages will be installed to ROPP_ROOT (assuming the configure scripts
#   are as provided) thus:
#     ROPP_ROOT/<build>             : this script, source archive files,
#                                     build/configure scripts,
#                                     decompressed archive trees
#     ROPP_ROOT/<compiler>/bin      : binaries (application programs)
#     ROPP_ROOT/<compiler>/include  : include (*.h) and module (*.mod) files
#     ROPP_ROOT/<compiler>/lib[64]  : object libraries (usually lib<package>.a)
#     ROPP_ROOT/<compiler>/man/man1 : 'man' page files (*.1)
#     ROPP_ROOT/data                : compiler-independent files
#                                     (e.g. BUFR tables)
#   Some packages may create other directories & files in ROPP_ROOT/<compiler>.
#   If ROPP_ROOT is undefined, it defaults to the directory which contains this
#   build script. The path defined by ROPP_ROOT is created if necessary &
#   checked that the user has write access.
#
# PACKAGES
#   This version of the script supports the following packages and their
#   (mostly) latest versions; due to dependencies, we recommend to build them
#   in this order:
#     mobufr      v25.0.2     package bufr-<version>
#     ecbufr      v000387     package bufr_<version>
#     eccodes     v2.12.5     package eccodes-<version>-Source
#     grib        v1.14.5     package grib_api-<version>
#     sofa        v20190722   package sofa_f-<version>_c
#     zlib        v1.2.11     package zlib-<version>
#     hdf5        v1.10.6     package hdf5-<version>
#     netcdf      v4.7.3      package netcdf-c-<version>
#     netcdff     v4.5.2      package netcdf-fortran-<version>
#     ropp_*      v10.x,v9.x  package ropp_<module>[-<version>]
#   Earlier or later package versions may have slightly different build
#   details, such as internal source directory layout, so there is no guarantee
#   that this script will build & install any other versions than shown above,
#   though minor version changes should still work.
#
# NOTES
#  1: This script no longer supports the building of netCDF-4 in classic
#     mode, nor releases v4.1.3 or earlier (in which the F90 interface was
#     bundled in the same tarball with the core C code).
#  2: NetCDF-4 depends on HFD5. If the latter is aleady system-installed,
#     we recommend to let the netCDF installer find and use that.
#  3: HDF5 optionally depends on ZLIB. The latter is very likely to be
#     system-installed so  we recommend to let the HDF5 installer (if
#     building your own) find and use that.
#
#---------------------------------------------------------------------
#****
#
# ----------------------------------------------------------------
# Function to print a summary of usage
#
usage()
{
  echo
  echo " buildpack - build a ROPP module or dependency package"
  echo
  echo "Usage:"
  echo " > buildpack package compiler [[NO]CLEAN]"
  echo " > buildpack [?|-h|--help]"
  echo
  echo " Required:"
  echo "   package  - package name (see Supported packages)"
  echo "   compiler - Fortran compiler (see Compilers)"
  echo
  echo " Supported packages:"
  echo "   [MOBUFR|ECBUFR|ECCODES,] [GRIB|ECCODES,] [SOFA,] [ZLIB,] HDF5, NETCDF, NETCDFF"
  echo "   ROPP_UTILS, ROPP_IO, ROPP_PP, ROPP_APPS, ROPP_FM, ROPP_1DVAR"
  echo "   It is recommended to build packages from scratch in the above order,"
  echo "   except only (at most) one of MOBUFR, ECBUFR or ECCODES need be built."
  echo "   GRIB (or ECCODES) and SOFA are also optional."
  echo "   NETCDF  will build the core C-only netCDF-4 package."
  echo "   NETCDFF will build the separate F90 interface package."
  echo "   NETCDF depends on HDF5 (and optionally ZLIB)"
  echo "   and must be built before NETDCFF."
  echo
  echo " Compilers:"
  echo "   Compiler name matching one of the configuration mini-scripts in"
  echo "   ./configure :  <package>_configure_<compiler>_<os>."
  echo "   Examples for <compiler> are:"
  echo "     ifort, sunf95, nagfor, pgf95, gfortran, xlf95..."
  echo
  echo " Options"
  echo "    CLEAN : remove source directory to re-build from latest archive file"
  echo "  NOCLEAN : do not clean source directory before a re-build (with the"
  echo "            same compiler)"
  echo
  exit 0
}
# ----------------------------------------------------------------
# Function to print a message for a missing configure script
#
noconfile()
{
  echo "*** Configure script $1 not found."
  echo
  echo "    Please create a configure script for this combination of package,"
  echo "    compiler and operating system with this file name and re-run the"
  echo "    build. One of the existing files in the configure directory may"
  echo "    be suitable as a template. Please send any new working script to"
  echo "    the ROPP Development Team for inclusion in future releases."
  echo
  exit 1
}
# ----------------------------------------------------------------
# Function to detect the latest version of a distro archive package.
# Usage:
#  latestarc [<path>]<pack>
# Not fool-proof, but works assuming a file name template of the form:
#  <path><pack>*-<vers>.<extn> or <pack>*_<vers>.<extn>
# where:
#  <path> is an optional path (default: PWD);
#  <pack> is the package name (case-sensitive) or file name template
#         up to the varying <vers> part;
#  <vers> is a lexically increasing version ID (usually a number like
#         12, 00012, 1.2 or 1.2.3). The 'latest version' selection will work
#         best if <vers> is consistent in format across all the files
#         matching the template;
#  <extn> is the archive extension type: one of tar.gz, tar.bz2, tgz
#         or zip (this list can be extended by editing 'extns' variable)
# Returns the file with the highest (lexically greatest) <vers> string
# to stdout.
# Example:
#  > ls pack*
#  pack-1.0.tgz  pack-2.2.zip  packnew-4.zip  pack_3.tar.gz
#  > latestarc pack
#  packnew-4.zip
# ----------------------------------------------------------------
#
latestarc(){
  unset ls
  unalias ls > /dev/null 2>&1
  extns=".tar.gz .tar.bz2 .tgz .zip"  # list of archive extensions
  latestver=""
  for e in $extns; do
    for f in $(ls ${TOP}/${1}*${e} 2>/dev/null); do
      thisarc=$f             # save this archive file name
      f=$(basename $f $e)    # remove <path> & <extn> parts
      f=${f#$1pack}          # remove <pack> part
      f=${f#-}               # remove anything up to & including dash
      f=${f#_}               # remove anything up to & including underscore
      if [[ -n $f ]]; then
        thisver=$f           # anything left is <vers>
      else
        thisver="0"  # assume files with no detectable version are 'v0'
      fi
      if [[ -z "$latestver" ]]; then        # initialise with first file found
        latestarc=$thisarc
        latestver=$thisver
      fi
      if [[ $thisver > $latestver ]]; then  # update if higher <vers>
        latestarc=$thisarc
        latestver=$thisver
      fi
    done
  done
  echo $latestarc                                      # return the answer
  unset extns f v latestarc latestver thisarc thisver  # tidy up
}
# ----------------------------------------------------------------
# Function to detect the latest version of a distro directory.
# Usage:
#  latestdir [<path>]<pack>
# Not fool-proof, but works assuming a directory name template of the form:
#  <path><pack>*-<vers> or <pack>*_<vers>
# where:
#  <path> is an optional path (default: PWD);
#  <pack> is the package name (case-sensitive) or directory name template
#         up to the varying <vers> part;
#  <vers> is a lexically increasing version ID (usually a number like
#         12, 00012, 1.2 or 1.2.3). The 'latest version' selection will work
#         best if <vers> is consistent in format across all the files
#         matching the template;
# Returns the directory with the highest (lexically greatest) <vers> string
# to stdout.
# Example:
#  > ls -d pack*
#  pack-1.0/ pack-2.2/  packnew_4/  pack_3/
#  > latestdir pack
#  packnew-4
# ----------------------------------------------------------------
#
latestdir(){
  unset ls
  unalias ls > /dev/null 2>&1
  latestver=""
  for d in $(ls -d ${1}*/ 2>/dev/null); do
    thisdir=${d%%/}               # save this directory/name
    d=$(basename $d); d=${d#$1}   # remove <path><pack> parts
    v=$(expr index $d - 2>/dev/null)      # remove anything else before first '-'...
    if [[ v -le 0 ]]; then
      v=$(expr index $d _ 2>/dev/null)    # ... or '_' if no '-'
    fi
    if [[ v -gt 0 ]]; then
      thisver=${d:$v}                     # what's left is <vers>
    else
      thisver="0"  # assume files with no detectable version are 'v0'
    fi
    if [[ -z "$latestver" ]]; then        # initialise with first file found
      latestdir=$thisdir
      latestver=$thisver
    fi
    if [[ $thisver > $latestver ]]; then  # update if higher <vers>
      latestdir=$thisdir
      latestver=$thisver
    fi
  done
  echo ${latestdir%%/}                           # return the answer
  unset d v latestdir latestver thisdir thisver  # tidy up
}
# ----------------------------------------------------------------
# Function to extract a package version number from package ID string
# which should be of the generic form <pkg-name>-<version>
# Package ID is assumed to of the form abc-[xyz]-d[.d[.d]][-ijk]
# where abc is the main package name, xyz & ijk are optional strings
# not begining with a digit and d is one or more digits. The dashes may
# instead be underscores. The algorithm sucessively strips off characters
# ending in a delimiter ('-' or '_') and tests the first character of the
# remaining string; if this is a digit the version ID is assumed to be the
# whole of the remaining string. The exception is ROPP modules which do not
# have a version part if installing as the full package; in this case the
# version is extracted from the README.ropp file in the current directory.
# If no version number is detected the version is returned as "?".
get_version(){
  local version=${1%-Source}  # remove grib_api non-version postfix
  local version=${version%_c}  # remove sofa non-version postfix
  local oldver=""
  local digit=""
  while [[ 0 ]]; do
    version=${version#*-}; version=${version#*_}
    if [[ "$version" == "$oldver" ]];then version="?"; break; fi
    digit=$(echo $version | grep "^[0-9]")
    if [[ "$version" == "1dvar" ]];then digit=""; fi
    if [[ -n $digit ]]; then break; fi
    oldver=$version
  done
  if [[ $version = "?" ]] && [[ ${1:0:5} == "ropp_" ]]; then
    if [[ -f README.ropp ]]; then
      release=$(grep "(Release" README.ropp | awk '{print $1 " " $2}')
      version=${release:10}; version=${version%%")"}
      if [[ -n $release ]]; then
        version=${release:10}; version=${version%%")"}
      fi
    fi
  fi
  echo $version
}
# ----------------------------------------------------------------
# Function to test that a target directory is writable by the user
# $1 = target directory as either an absolute path or as an environment
# variable name which is set to an absolute path (e.g. ROPP_ROOT)
# Script will exit if path is not writable (or EV is not set, or path is not
# a directory), or silently return if it is.
test_write(){
  local testpath=$1
  if [[ ${testpath:0:1} != "/" ]]; then testpath=$(eval echo \$$1); fi
  if [[ -z $1 ]]; then
    echo "*** No argument given."
    echo "    Usage: test_write <abs-path>"
    echo "       or: test_write <env-var-name>"
    exit 1
  elif [[ -z "$testpath" ]]; then
    echo "*** Environment variable $1 is not set."
    echo "    Please set a directory path for $1"
    exit 1
  elif [[ ! -d $testpath ]]; then
    echo "*** Path $testpath is not a directory."
    echo "    Please set a valid directory path for $1"
    exit 1
  elif [[ ! -w $testpath ]]; then
    echo "*** You do not have write permission to $testpath"
    echo "    Please set another path for $1"
    exit 1
  fi
}
# ----------------------------------------------------------------
# The NAGware 'nagfor' v6 compiler installed on MetO systems requires access
# to a licence server, without which any compilation will fail. The server will
# only be contacted if the correct programming environment is first set via a
# 'module' command in the appropriate prg_* script. This function is a dirty
# fix for local MetO use of 'nagfor60' only; it should silently do nothing for
# any other compiler (including any other nagfor versions) or on non-MetO
# systems. Change the default or v6 version details as required.
# NB: Should nagfor v6.0 (or later) become the default, then this function may
# be redundant.
#
nagmod() {
  if [[ ${compiler:0:6} == "nagfor" ]]; then
    local nagver=$($compiler -V 2>&1 | grep 6.0)
    if [[ -n $nagver ]]; then
      if [[ $1 == "default" ]]; then
         nagver=5.2
      else
         nagver=6.0.0
      fi
      local prgenv=/usr/local/bin/prg_nagfor-${nagver}_64
      if [[ -x $prgenv ]]; then echo; source $prgenv; fi
    fi
  fi
}
# ----------------------------------------------------------------
# Function to build/test/install MetDB BUFR library
#
build_MOBUFR()
{
  echo
  echo "------------------------------------------------------------------"
  echo ">> Building MetDB BUFR (v${version}) with '$compiler' F95 compiler on $OS"
  echo "------------------------------------------------------------------"
#
  if [[ -z $BUFR_LIBRARY ]]; then export BUFR_LIBRARY=$ROPP_ROOT/data/bufr; fi
  mkdir -p $BUFR_LIBRARY > /dev/null 2>&1
  test_write BUFR_LIBRARY
#
  echo
  cd $package
  ./buildbufr -u -y -p $PREFIX
  ./buildbufr -c -p $PREFIX -f $compiler -t
  if [[ $? -ne 0 ]]; then
    echo
    echo "*** Failed to build MetDB BUFR library"
    errstat=1
  fi
}
# ----------------------------------------------------------------
# Function to build/test/install ECMWF BUFR library
#
build_ECBUFR()
{
  echo
  echo "------------------------------------------------------------------"
  echo ">> Building ECMWF BUFR (v${version}) with '$compiler' F95 compiler on $OS"
  echo "------------------------------------------------------------------"
#
  if [[ -z $BUFR_TABLES ]]; then export BUFR_TABLES=$ROPP_ROOT/data/bufr/; fi
  mkdir -p $BUFR_TABLES > /dev/null 2>&1
  test_write BUFR_TABLES
  export INSTALL_DIR=$PREFIX
  INSTALL="cp -uvp"
  if [[ $OS == "AIX" ]]; then INSTALL="cp"; fi
#
  confile="configure/ecbufr_configure_${compiler}_${os}"
  if [[ -f ${TOP}/$confile ]]; then
    echo "  - using configure script $confile"
    cp $confile $package/config/config.${os}_${compiler}
  else
    noconfile $confile
  fi
  echo
  cd $package
#
# ECMWF package doesn't support AIX or Cygwin, so fudge some config/
# options files based on the Linux ones
#
  if [[ $OS == "AIX" ]]; then
    cp ./options/options_linux ./options/options_aix
    cp ./pbio/sources.linux    ./pbio/sources.tmp
    sed s/gbyte_le/gbyte/      ./pbio/sources.tmp > ./pbio/sources.aix
    rm ./pbio/sources.tmp
  elif [[ $OS == "CYGWIN" ]]; then
    cp ./options/options_linux ./options/options_cygwin
    cp ./pbio/sources.linux    ./pbio/sources.cygwin
  fi
  echo
  echo ">> Building..."
  cd ./bufrdc
  make ARCH=$os CNAME=_$compiler LIB=bufr clean all
  cd ../pbio
  make ARCH=$os CNAME=_$compiler LIB=bufr clean all
  cd ../bufrtables
  make ARCH=$os CNAME=_$compiler LIB=bufr clean links
  if [[ $? -eq 0 ]]; then
    echo
    echo ">> Installing..."
# Systems with non-GNU 'cp' (like AIX) may not support the -d flag
# (preserve links). If not, the resulting installed BUFR tables
# will be real files, not softlinks
    cp -d links.sh tmp > /dev/null 2>&1
    if [[ $? -eq 0 ]]; then
      keeplinks="-d"
      rm tmp
    else
      keeplinks=""
    fi
    mkdir -p $BUFR_TABLES
    $INSTALL $keeplinks ?000*.TXT $BUFR_TABLES
    $INSTALL ../libbufr.a $INSTALL_DIR/lib
    echo
    echo ">> Testing..."
    cd ../examples
    if [[ ! -f ../config/fortran2c_$compiler ]]; then
      echo "FORTRAN2C =" > ../config/fortran2c_$compiler
    fi
    make ARCH=$os CNAME=_$compiler LIB=bufr clean
#
# ECMWF code is all f77 and contains some old deprecated features
# which NAG doesn't support and which cause errors. We also
# need to use the NAG interfaces fudge to support getenv() and
# similar 'system' calls.
#
    if [[ ${compiler:0:3} == "nag" ]]; then
      cp -v ../../configure/nag_interfaces.f90 .
      nagf=$compiler
      if [[ $nagf == "nag" ]]; then nagf=f95; fi
      echo $nagf -c -w -f77 nag_interfaces.f90
      $nagf -c -w -f77 nag_interfaces.f90
      mv Makefile Makefile_notnag
      sed s/create_bufr\.o/"create_bufr.o nag_interfaces.o"/g Makefile_notnag \
          > Makefile
      mv create_bufr.F create_bufr.F_notnag
      sed s/\(a\,\$\)\'/\(a\)\',advance=\'no\'/g create_bufr.F_notnag \
            > create_bufr.F
    fi
    make ARCH=$os CNAME=_$compiler LIB=bufr create_bufr
    if [[ $? -eq 0 ]]; then
      ./create_bufr <<EOF
1
1
EOF
    fi
    if [[ -f nag_interfaces.f90 ]]; then
      mv Makefile_notnag Makefile
      mv create_bufr.F_notnag create_bufr.F
      rm nag_interfaces.*
    fi
  else
    echo
    echo "*** Failed to build ECMWF BUFR library"
    errstat=1
  fi
}
# ----------------------------------------------------------------
# Function to build/test/install GRIB library
#
build_GRIB()
{
  echo
  echo "------------------------------------------------------------------"
  echo ">> Building GRIB-API (v$version) with '$compiler' compiler on $OS "
  echo "------------------------------------------------------------------"
  echo
#
  confile="configure/grib_configure_${compiler}_${os}"
  if [[ -f ${TOP}/$confile ]]; then
    echo "  - using configure script $confile"
  else
    noconfile $confile
  fi
#
  echo
  cd $package
#
  if [[ -f Makefile ]]; then
   echo "------------------------------------------------------------------"
   echo ">> Deep cleaning..."
   echo
   make distclean
   do_clean="n"
   echo
  else
   do_clean="y"
  fi
  echo "------------------------------------------------------------------"
  echo ">> Configuring..."
  echo
  cat $TOP/$confile
  echo
  $TOP/$confile $PREFIX
  echo
  if [[ $do_clean = "y" ]]; then
   echo "------------------------------------------------------------------"
   echo ">> Cleaning..."
   echo
   make clean
   echo
  fi
  if [[ ! -f data/bad.grib ]] && \
     [[ -f ../grib_api_test_data.tar.gz ]]; then
   echo "------------------------------------------------------------------"
   echo ">> Pre-loading test data..."
   tar -xvf ../grib_api_test_data.tar.gz
  fi
  echo "------------------------------------------------------------------"
  echo ">> Building, testing & installing..."
  echo
  make && make check && make install
  if [[ $? -ne 0 ]]; then
    echo
    echo "*** Failed to build GRIB library"
    errstat=1
  fi
}
# ----------------------------------------------------------------
# Function to build/test/install GRIB library
#
build_ECCODES()
{
  echo
  echo "------------------------------------------------------------------"
  echo ">> Building ecCodes (v$version) with '$compiler' compiler on $OS "
  echo "------------------------------------------------------------------"
  echo
#
  confile="configure/eccodes_configure_${compiler}_${os}"
  if [[ -f ${TOP}/$confile ]]; then
   echo "  - using configure script $confile"
   echo
   cd $package
   rm CMakeCache.txt
   rm -r CMakeFiles/

   echo "------------------------------------------------------------------"
   echo ">> Building, testing & installing..."
   $TOP/$confile
  else
   noconfile $confile
  fi
}
# ----------------------------------------------------------------
# Function to build/test/install SOFA library
#
build_SOFA()
{
  echo
  echo "------------------------------------------------------------------"
  echo ">> Building SOFA (v$version) with '$compiler' compiler on $OS     "
  echo "------------------------------------------------------------------"
  echo
#
  confile="configure/sofa_configure_${compiler}_${os}"
  if [[ -f ${TOP}/$confile ]]; then
    echo "  - using configure script $confile"
  else
    noconfile $confile
  fi
  echo
  export ROPP_BUILD_DEPS_PATH=$PWD

# Folder name change following the 20160503 version.
  if [ $version -le 20160503 ]; then
    cd $package/$(basename $pkgarc |cut -c8-17)/f77/src/ # assumes standard naming convention
  else
    cd $package/$(basename $pkgarc |cut -c8-15)/f77/src/ # assumes standard naming convention
  fi
# SOFA is already configured, to run with gfortran on linux,
# so the 'configuration' script just edits the existing makefile -
# it doesn't generate it, as the (proper) configuration scripts of the other
# dependency packages do. So we have a slightly different decision tree for SOFA.
  if [[ ! -f makefile ]]; then
    echo "------------------------------------------------------------------"
    echo ">>No makefile in $package/${pkgarc: 7:10}/f77/src ..."
    echo
    errstat=1
    echo
  else
    echo "------------------------------------------------------------------"
    echo ">> Configuring..."
    echo     ${TOP}/$confile
    echo
    $TOP/$confile $PREFIX
    echo
    echo "------------------------------------------------------------------"
    echo ">> Deep cleaning..."
    echo 
    make distclean
    echo
    echo "------------------------------------------------------------------"
    echo ">> Building & installing ..."
    echo
    make all  &&  make install
    echo "------------------------------------------------------------------"
    echo ">> Checking ..."
    echo
    make test
    if [[ $? -ne 0 ]]; then
      echo
      echo "*** Parts of the SOFA library could not be validated"
      errstat=1
    fi
  fi
  cd $ROPP_BUILD_DEPS_PATH
}
# ----------------------------------------------------------------
# Function to build/test/install ZLIB library
#
build_ZLIB()
{
  echo
  echo "------------------------------------------------------------------"
  echo ">> Building ZLIB (v$version) with '$compiler' compiler on $OS     "
  echo "------------------------------------------------------------------"
  echo
#
  confile="configure/zlib_configure_${compiler}_${os}"
  if [[ -f ${TOP}/$confile ]]; then
    echo "  - using configure script $confile"
  else
    noconfile $confile
  fi
#
  echo
  cd $package
#
  if [[ -f Makefile ]]; then
   echo "------------------------------------------------------------------"
   echo ">> Deep cleaning..."
   echo
   make distclean
   do_clean="n"
   echo
  else
   do_clean="y"
  fi
  echo "------------------------------------------------------------------"
  echo ">> Configuring..."
  echo
  cat $TOP/$confile
  echo
  $TOP/$confile $PREFIX
  echo
  if [[ $do_clean = "y" ]]; then
   echo "------------------------------------------------------------------"
   echo ">> Cleaning..."
   echo
   make clean
   echo
  fi
  echo "------------------------------------------------------------------"
  echo ">> Building, testing & installing..."
  echo
  make && make check && make install
  if [[ $? -ne 0 ]]; then
    echo
    echo "*** Failed to build ZLIB library"
    errstat=1
  fi
}
# ----------------------------------------------------------------
# Function to build/test/install HDF5 library
#
build_HDF5()
{
  echo
  echo "------------------------------------------------------------------"
  echo ">> Building HDF5 (v$version) with '$compiler' compiler on $OS     "
  echo "------------------------------------------------------------------"
  echo
#
  confile="configure/hdf5_configure_${compiler}_${os}"
  if [[ -f ${TOP}/$confile ]]; then
    echo "  - using configure script $confile"
  else
    noconfile $confile
  fi
#
  echo
  cd $package
#
  if [[ -f Makefile ]]; then
   echo "------------------------------------------------------------------"
   echo ">> Deep cleaning..."
   echo
   make distclean
   do_clean="n"
   echo
  else
   do_clean="y"
  fi
  echo "------------------------------------------------------------------"
  echo ">> Configuring..."
  echo
  cat $TOP/$confile
  echo
  $TOP/$confile $PREFIX
  echo
  if [[ $do_clean = "y" ]]; then
   echo "------------------------------------------------------------------"
   echo ">> Cleaning..."
   echo
   make clean
   echo
  fi
  echo "------------------------------------------------------------------"
  echo ">> Building, testing & installing..."
  echo
  make && make check && make install
  if [[ $? -ne 0 ]]; then
    echo
    echo "*** Failed to build HDF5 library"
    errstat=1
  fi
}
# ----------------------------------------------------------------
# Function to build/test/install netCDF-4 core C-only or
# F90 interface library
#
build_NETCDF()
{
  echo
  echo "------------------------------------------------------------------"
  echo ">> Building netCDF-4 $module (v$version) with '$compiler' compiler on $OS"
  echo "------------------------------------------------------------------"
  echo
#
  if [[ ${module:0:4} == "core" ]]; then
    confile="configure/netcdf_configure_${compiler}_${os}"
  else
    confile="configure/netcdff_configure_${compiler}_${os}"
    rm -rf $PREFIX/include/netcdf*.mod
  fi
  if [[ -f ${TOP}/$confile ]]; then
    echo "  - using configure script $confile"
  else
    noconfile $confile
  fi
#
  echo
  cd $package
#
  if [[ -f Makefile ]]; then
    echo "------------------------------------------------------------------"
    echo ">> Deep cleaning..."
    echo
    make distclean
    do_clean="n"
    echo
  else
    do_clean="y"
  fi
  echo "------------------------------------------------------------------"
  echo ">> Configuring..."
  echo
  cat $TOP/$confile
  echo
  $TOP/$confile $PREFIX
  echo
  if [[ $do_clean = "y" ]]; then
    echo "------------------------------------------------------------------"
    echo ">> Cleaning..."
    echo
    make clean
    echo
  fi
  echo "------------------------------------------------------------------"
  echo ">> Building, testing & installing..."
  echo
  make check install
  if [[ $? -ne 0 ]]; then
    echo
    echo "*** Failed to build netCDF-4 $module library"
    errstat=1
  fi
}
# ----------------------------------------------------------------
# --- Function to build/install one of ROPP libraries ---
#
build_ROPP()
{
  module=$(echo $package | cut -d"_" -f2 | cut -d"-" -f1 )
  MODULE=$(echo $module | tr [:lower:] [:upper:])
  echo
  echo "------------------------------------------------------------------"
  echo ">> Building ROPP_$MODULE (v${version}) with '$compiler' compiler on $OS"
  echo "------------------------------------------------------------------"
  echo
#
  confile="configure/ropp_configure_${compiler}_${os}"
  if [[ -f ${TOP}/$confile ]]; then
    echo "  - using configure script $confile"
  else
    noconfile $confile
  fi
#
  echo
  cd $package
  cleanerr=0
#
  if [[ $do_clean = "y" ]] && [[ -f Makefile ]]; then
    echo "------------------------------------------------------------------"
    echo ">> Deep cleaning..."
    echo
    make distclean
    cleanerr=$?
    do_clean="n"
    echo
  fi
  if [[ ! -f Makefile ]] || [[ $cleanerr -ne 0 ]]; then
    echo "------------------------------------------------------------------"
    echo ">> Configuring..."
    echo
    cat $TOP/$confile
    echo
    $TOP/$confile $PREFIX
    echo
    if [[ ! -f Makefile ]]; then
      echo "*** Failed to generate Makefile"
      echo
      exit 1
    fi
  fi
  if [[ $do_clean = "y" ]]; then
   echo "------------------------------------------------------------------"
   echo ">> Cleaning..."
   echo
   make clean
   echo
  fi
  echo "------------------------------------------------------------------"
  echo ">> Building & installing..."
  echo
  make install
  if [[ $? -eq 0 ]]; then
    if [[ -f tests/Makefile ]]; then
      echo "------------------------------------------------------------------"
      echo ">> Testing ROPP_$MODULE..."
      echo
      cd tests
      make test
      if [[ $? -ne 0 ]]; then
        echo
        echo
        echo "*** Failed testing ROPP_$MODULE"
        errstat=1
      fi
    fi
  else
    echo
    echo "*** Failed to build ROPP_$MODULE library"
    errstat=1
  fi
}
#
# ---------------------- Start of script ------------------------------
#
# --- Environment set-up
#
# the following command sets g=rwx as default for group shared builds;
# this can be an removed if building from a single account.
umask 002
#
# the following is to ensure we don't pick up any inappropriate
# user libraries or incompatible linker options
unset LDFLAGS
#
TOP=$(dirname $0)
if [[ $TOP = "." ]]; then
  TOP=$PWD
fi
export TOP
errstat=0
#
# --- Installation root directory checks
#
if [[ -z $ROPP_ROOT ]]; then
  echo "WARNING: Environment variable ROPP_ROOT is not set."
  echo "         Using $TOP as default"
  echo
  export ROPP_ROOT=$TOP
fi
mkdir -p $ROPP_ROOT > /dev/null 2>&1
if [[ $? -ne 0 ]]; then
  echo "*** Failed to create ROPP installation directory $ROPP_ROOT"
  echo "    Check that you have write permissions for this path"
  exit 1
fi
test_write ROPP_ROOT
#
# --- O/S name: truncate at first space; remove version ID
#     from 'Cygwin' & make uppercase (with duplicate in lowercase)
#
export OS=$(uname | cut -d" " -f1 | \
                    sed s/_NT-.*// | \
                    tr [:lower:] [:upper:])
export os=$(echo $OS | tr [:upper:] [:lower:])
#
# --- over-ride any external user settings...
#
export MAN=""
export LDFLAGS=""
#
#--- Check command line inputs
#
if [[ "$1" = "-?"     ]] || \
   [[ "$1" = "-h"     ]] || \
   [[ "$1" = "--help" ]]; then
  usage
fi
if [[ -z "$1"         ]] || \
   [[ -z "$2"         ]]; then
  usage
fi
#
#--- Parse command line for package, compiler & cleaning option
#
package=$(echo $1 | tr [:upper:] [:lower:])
PACKAGE=$(echo $package | tr [:lower:] [:upper:])
#
export compiler=$2
#
# --- Make the basic install tree if it doesn't already exist
#    (this would be done within the package installer, but we
#     do it here in case the package build fails)
#
export PREFIX=$ROPP_ROOT/$compiler
mkdir -p $ROPP_ROOT/data
mkdir -p $PREFIX/bin
mkdir -p $PREFIX/include
mkdir -p $PREFIX/lib
mkdir -p $PREFIX/lib64
mkdir -p $PREFIX/man/man1
#
CLEAN=$3
#
# --- Set up for supported packages
#
module="/"
case $PACKAGE in
  BUFR)    source="http://www.romsaf.org"
           package=bufr-2
           PACKAGE=MOBUFR
   ;;
  MOBUFR)  source="http://www.romsaf.org"
           package=bufr-2
   ;;
  ECBUFR)  source="http://www.ecmwf.int/products/data/software/bufr.html"
           package=bufr_000
   ;;
  GRIB)    source="https://software.ecmwf.int/wiki/display/GRIB/Home"
           package=grib_api-1
   ;;
  ECCODES) source="https://confluence.ecmwf.int/display/ECC/ecCodes+Home"
           package=eccodes-2
   ;;
  SOFA)    source="http://www.iausofa.org"
           package=sofa
   ;;
  ZLIB)    source="http://www.zlib.net"
           package=zlib-1
   ;;
  HDF5)    source="http://www.hdfgroup.org/HDF5"
           package=hdf5-1
   ;;
  NETCDF)  source="http://www.unidata.ucar.edu/software/netcdf/"
           package=netcdf-c-4
           module="core C"
   ;;
  NETCDFF) source="http://www.unidata.ucar.edu/software/netcdf/"
           package=netcdf-fortran-4
           module="Fortran interface"
           PACKAGE=NETCDF
   ;;
  ROPP_*)  source="http://www.romsaf.org"
           module=${PACKAGE:5}
           PACKAGE="ROPP"
   ;;
  *) echo "*** Package $PACKAGE not supported"
     echo
     exit 1
   ;;
esac
#
#--- Is required uncompressed package tree present?
#
pkgdir=$(latestdir $package)
#
echo
echo ">> Checking $PACKAGE $module package ..."
#
if [[ -d $pkgdir ]] && [[ "$CLEAN" = "CLEAN" ]]; then
  echo "  - Wiping old source directory $pkgdir..."
  rm -Rf $pkgdir
fi
#
if [[ ! -d $pkgdir ]]; then
  echo
  echo "*** Source directory not found - looking for distro archive file..."
#
  pkgarc=$(latestarc $package)
  if [[ -f $pkgarc ]]; then
    echo "  - Found $pkgarc - unpacking..."
    ext=${pkgarc: -3:3}
    case $ext in
     bz2) bzcat $pkgarc > temp.tar
          tar -xvf temp.tar
          rm temp.tar
          ;;
     zip) unzip $pkgarc
          ;;
       *) gunzip -c $pkgarc > temp.tar
          tar -xvf temp.tar
          rm temp.tar
          ;;
    esac
    pkgdir=$(latestdir $package)
    CLEAN="NOCLEAN"
  else
    echo
    echo "*** Archive tar/zip file not found either."
    if [[ -n $source ]]; then
      echo "    Download the latest archive from:"
      echo "    $source"
    fi
    echo
    exit 1
  fi
fi
#
export package=$pkgdir
#echo 'After export package=$pkgdir: $package = ' $package

export version=$(get_version $pkgdir)
#echo 'After version=$(get_version $pkgdir): $version = ' $version

if [[ "$version" = "?" ]]; then
  pkgarc=$(latestarc $package)
#  echo 'After pkgarc=$(latestarc $package): $pkgarc = ' $pkgarc

  export version=$(get_version ${pkgarc%.tar.gz})
#  echo 'After version=$(get_version ${pkgarc%.tar.gz}): $version = ' $version
fi

#
if [[ "$CLEAN" = "NOCLEAN" ]]; then
  CLEAN="n"
else
  CLEAN="y"
fi
export do_clean=$CLEAN
export PATH=$PATH:$PREFIX/bin
#export LD_LIBRARY_PATH=$PREFIX/lib:$PREFIX/lib64:$LD_LIBRARY_PATH
export BUFR_LIBRARY=$ROPP_ROOT/data/bufr/
export BUFR_TABLES=$ROPP_ROOT/data/bufr/
#
echo
echo " - Found installed source package $package (${PACKAGE} ${module} version ${version})"
#
#--- Now we're ready to do the actual package build & installation
#
nagmod
build_$PACKAGE
nagmod default
#
#--- Finally, show what's just been installed (or not!)
#
echo
if [[ -d $PREFIX/include ]]; then
  echo
  echo "Directory: $PREFIX/include"
  ls -ltr $PREFIX/include | tail
fi
if [[ -d $PREFIX/lib ]]; then
  echo
  echo "Directory: $PREFIX/lib"
  ls -ltr $PREFIX/lib | tail
fi
if [[ -d $PREFIX/lib64 ]]; then
  echo
  echo "Directory: $PREFIX/lib64"
  ls -ltr $PREFIX/lib64 | tail
fi
if [[ -d $PREFIX/bin ]]; then
  echo
  echo "Directory: $PREFIX/bin"
  ls -ltr $PREFIX/bin | tail
fi
if [[ -d $PREFIX/man/man1 ]]; then
  echo
  echo "Directory: $PREFIX/man/man1"
  ls -ltr $PREFIX/man/man1 | tail
fi
if [[ -d $PREFIX/share/man/man1 ]]; then
  echo
  echo "Directory: $PREFIX/share/man/man1"
  ls -ltr $PREFIX/share/man/man1 | tail
fi
echo
echo "------------------------------------------------------------------"
if [[ $errstat -eq 0 ]]; then
  echo "Done. Check messages to confirm successful build & installation"
else
  echo "** An error occured. Check messages to find the problem"
fi
echo "------------------------------------------------------------------"
echo
#
exit $errstat
