#!/bin/bash
#
#    $Id: buildbufr $
#
#****k* BUFR/buildbufr *
#-----------------------------------------------------------------------
#
# NAME
#   buildbufr
#
# SYNOPSIS
#   Example script to build BUFR library and support programs.
#
#  > buildbufr [-b bufrdir] [-c] [-f compiler] [-h]
#              [-p prefix]  [-n] [-t] [-z]
#
# OPTIONS
#   -b set BUFR_LIBRARY temporarily to <bufrdir>
#      BUFR tables will be copied here as working versions.
#      Default: existing environment variable definition,
#      or if this is not defined, then <prefix>/data/bufr/
#      Tip: use "-b ." to install locally within the BUFR package tree.
#
#   -c clean build before make (make from scratch)
#      Recommended if trying a different compiler or building
#      an updated package from an existing build in the same
#      location. Default: build only things which have changed.
#
#   -f F90 compiler
#       HP:     one of DEF, NAG or HP                      (Default: HP)
#       Linux:  one of DEF, IFC, IFORT, IFORT8, IFORT9, IFORT10,
#                      PGF, PGF6, PGF7,
#                      NAG, LF95, G95 or GFC               (Default: IFORT)
#       Cygwin: one of DEF, IFORT, G95 or GFC              (Default: G95)
#       Sun OS: one of DEF, FUJITSU                        (Default: FUJITSU)
#      See file f90_compilers.dat for definitive list - other
#      compilers may be supported by adding entries to this file.
#
#   -h print basic usage info and exit.
#
#   -n without -z: don't install executables (Default: install to <prefix>/bin)
#      with    -z: disables default distribution of tarball.
#
#   -p set a prefix (root directory) for build. Default: HOME
#      <prefix>/bin      - location for binary (executable) files
#      <prefix>/lib      - location for BUFR object library (libbufr.a)
#      <prefix>/include  - location for f90 include & module files
#      <prefix>/man/man1 - location for 'man page' files
#      Tip: use "-p ." to install locally within the BUFR package tree.
#
#   -t also build & run MetDB simple test programs. Executable files
#      are built in bufr/metdb/. Default: skip test programs.
#      (testtables and decbufr are always built & run)
#
#   -z builds a distribution as a zip archive. Except for -n all other
#      options are ignored. This option is for local administrator use,
#      and depends on files not in the distribution package. By default,
#      the newly-created package is uploaded to the E-GVAP project hub
#      server and copied to the ROPP archive/build directory; this can
#      be disabled by also using -n.
#
# INPUTS
#   BUFR source code
#
# OUTPUTS
#   Without -z: BUFR object library libbufr.a (bufr.lib for native Windows
#   compilers) & application executables, etc.
#   With -z: ../bufrpack-<ver>.zip where <ver> is the current BUFR package
#   release version ID taken from the README file.
#
# ENVIRONMENT VARIABLES
#   BUFR_LIBRARY   - path to BUFR run-time files
#   PACKAGES       - path to package root directory (used with -z only)
#
# USES
#   f90_select
#   cygpath           (on Cygwin builds only)
#   bufrpack.sh       (with -z only)
#
# DESCRIPTION
#   Assumes a directory structure:
#
#            bufr[-<ver>]/
#              |
#     +--------+---------+
#     |                  |
#   metdb/            extra/
#
#   and that:
#   - we are curently in bufr/ or bufr-<ver>/ (where <ver> is the BUFR
#     package release version ID)
#   - the MetDB BUFR package, including operational tables, is installed
#     in metdb/
#   - non-MetDB files are in extra/
#   - run-time tables will be placed in BUFR_LIBRARY (normally
#     <prefix>/data/bufr/)
#
#   Configured to support a (limited) number of compilers running under
#   HP-UX, SunOS, Linux and Cygwin (Microsoft Windows). See README,
#   README.cygwin & f90_compilers.dat files for details.
#
#   Tip: to save a log of the build,
#     > buildbufr [options] | tee buildbufr.log
#
#   The build script will:
#    - check that the BUFR_LIBRARY environment variable is set
#      if not, set the default to directory <prefix>/data/bufr)
#    - attempt to create the prefix tree if directories do not pre-exist
#    - check that the selected (if using the -f option) or default F90
#      compiler is present & working
#    - install the 'operational' set of BUFR tables from metdb/ to
#      BUFR_LIBRARY
#    - if provided, install any modified BUFR tables in extra/
#      to BUFR_LIBRARY (replacing the operational ones)
#    - clean any previous build (only if using the -c option)
#    - make the kernel MetDB BUFR object library in <prefix>/lib/libbufr.a
#    - build & run the MetDB test programs (if using the -t option)
#    - add some extra support routines to the BUFR object library
#    - make the BUFR application executable programs in <prefix>/bin
#      and run them on test inputs
#    - install man pages from extra/ to <prefix>/man/man1
#
#   NB if the -c option is not used, and a previous build has been done,
#   only changed components will be updated.
#
#   If the -z option is used, a distribution package (zipfile) will be built.
#   Since this uses files not included in the distribution zipfile, this option
#   should only be used on the package development tree. A file called
#   bufrpack-<ver>.zip (where <ver> is the current package release version ID,
#   extracted from te README file) will be created (or replaced_ in the PACKAGES
#   directory (parent of bufr/).
#
# AUTHOR
#   Dave Offiler
#
# MODIFICATION HISTORY
#   1.0  05-Aug-2005  First documented suitable for RoboDoc    D. Offiler
#   1.1  12-Sep-2005  Add support for SunOS                    D. Offiler
#   1.2  21-Sep-2005  BUFR library name bufr.lib for ifort on
#                     Cygwin only (was thus named for any
#                     Cygwin compiler)                         D. Offiler
#   1.3  11-Apr-2006  First change directory to the one
#                     containing this script, so it can be
#                     called from elsewhere                    D. Offiler
#   1.4  26-Jul-2006  (a) Skip running test_tables & decbufr if the
#                     executables weren't built
#                     (b) Install table CT001033 from extra/ to
#                     BUFR_LIBRARY                             D. Offiler
#   1.5  06-Dec-2006  (a) Increase sleep time between main library
#                     build and extra build - make not detecting that
#                     the extra .o files are newer than the .a.
#                     (b) Add -n option to command line.       D. Offiler
#   1.6  14-Jun-2007  Extract release version from README and print
#                     to stdout.                               D. Offiler
#   1.7  28-Mar-2008  Convert Cygwin paths to full Unix-style before
#                     invoking make                            D. Offiler
#   1.8  02-Sep-2008  (a) Run under 'bash' (was 'sh')
#                         Use [[test]] built-in syntax instead of [test] external;
#                         Use $(command) syntax instead of `command` form;
#                         Use bash substringing instead of external editing commands
#                     (b) Delete BUFR sample file if clean & test options present
#                         before building & running MetBD sample test programs
#                     (c) Append $EXE (OS-dependant blank or '.exe.') when invoking
#                         test programs to match correct build program extension
#                         when both could be present (e.g. shared Linux &
#                         Windows/Cygwin partition)
#                     (d) Distro package builder appends version ID to zip file
#                         name & file paths
#                     (e) Updated comment headers.             D. Offiler
#   1.9  13-Aug-2009  (a) Removed use of portability.fi include file -
#                         replaced by nag_interfaces.f90 for transparency
#                         with NAG compiler.
#                     (b) Distro builder creates gzipped tar archive
#                         bufr-<ver>.tar.gz instead  of ZIP archive
#                         bufrpack-<ver>.zip.
#                     (c) MetDB BUFR library renamed libmetdbbufr.a to avoid
#                         clash with ECMWF BUFR library also called libbufr.a
#                     (c) Improved usage info (-h)                  D. Offiler
#   1.10 01-Nov-2009  (a) Rename test_tables to testtables.
#                     (b) Install new tables MASTERTABLE, DATACATEGORY
#                         (replaces TABLEA) and ORIGCENTRE (replaces
#                         CT001033 & CT001034).
#                     (c) Check library for new sec1tables instead of
#                         old codetables when adding extra/ code.   D. Offiler
#
#-------------------------------------------------------------------
#****
#
usage(){
  echo
  echo "Usage: > buildbufr [-c] [-b bufrdir] [-f compiler]"
  echo "                   [-p prefix] [-t] [-z] [-n] [-h]"
  echo
  echo "where:"
  echo " -c : clean build before make (make from scratch)"
  echo "      [Default: build only things which have changed]"
  echo " -b : tempory override of path to install BUFR tables"
  echo "      [Default: BUFR_LIBRARY or if not set, <prefix>/data/bufr]"
  echo " -f : F90 compiler ID"
  echo "      [Default: OS-dependant - see f90_compilers.dat]"
  echo " -p : set a prefix (root directory) for installation. [Default: HOME]"
  echo " -t : run simple MetDB tests to check correct build. [Default: skip tests]"
  echo " -z : build distribution tarball. For local admin use only."
  echo " -n : without -z - disable installation of executables to <prefix>/bin"
  echo "      with    -z - disable default upload of package to E-GVAP server"
  echo " -h : print this usage info "
  echo
  exit
  exit
}
#-------------------------------------------------------------------
#
echo
echo " ============ Build script for BUFR package ============"
#
# --- Start from directory containing this script ---
#
TOP=$(dirname $0)
cd $TOP
TOP=$PWD
#
# --- Parse options after setting defaults ---
#
clean="n"
f90opt="DEF"
PREFIX=$HOME
install_extra="install_mod install_exe"
test="n"
upload="PUBLISH"
zipdist="n"
#
while getopts b:cf:hinp:tz option
do
  case $option in
    b) BUFR_LIBRARY=$OPTARG
       if [[ $BUFR_LIBRARY = "." ]] || [[ $BUFR_LIBRARY = "./" ]]; then
         BUFR_LIBRARY=$PWD/data/bufr/
       fi
       ;;
    c) clean="y"
       ;;
    f) f90opt=$OPTARG
       ;;
    h) usage
       ;;
    n) install_extra="install_mod"
       upload=""
       ;;
    p) PREFIX=$OPTARG
       if [[ $PREFIX = "." ]] || [[ $PREFIX = "./" ]]; then
         PREFIX=$PWD
       fi
       if [[ ! ${PREFIX:0:1} = "/" ]]; then
         PREFIX=$PWD/$PREFIX
       fi
       ;;
    t) test="y"
       ;;
    z) zipdist="y"
       ;;
  esac
done
#
# ---- Build zip archive distribution package ----
#
if [[ $zipdist = "y" ]]; then
  if [[ -f scripts/bufrpack.sh ]]; then
    scripts/bufrpack.sh $upload
  else
    echo
    echo "*** Package builder script not available in this distribution"
  fi
  exit
 fi
#
# --- Setup for OS-specific stuff ---
#
OS=$(uname | cut -c 1-6 | tr "[:lower:]" "[:upper:]")
case $OS in
  AIX)
    echo "                      (AIX Unix)"
    INSTALL="cp -f -p"
    DELETE="rm -f"   
    ;;
  HP-UX)
    echo "                      (HP Unix)"
    INSTALL="cp -f -p"
    DELETE="rm -f"
    ;;
  SUNOS)
    echo "                       (Sun-OS)"
    INSTALL="cp -f -p"
    DELETE="rm -f"
    ;;
  CYGWIN)
    echo "                   (Windows/Cygwin)"
    INSTALL="cp --update --verbose --preserve"
    DELETE="rm --force --verbose"
    ;;
  *)
    uname -a | grep nec > /dev/null
    if [[ $? -eq 0 ]]; then
      echo "                     (NEC Linux)"
      INSTALL="cp --update --verbose --preserve"
      DELETE="rm --force --verbose"
    else
      echo "                       (Linux)"
      INSTALL="cp --update --verbose --preserve=timestamps"
      DELETE="rm --force --verbose"
     fi
    ;;
esac
#
#  --- Data files & directories ---
#
if [[ -z "$BUFR_LIBRARY" ]]; then
  BUFR_LIBRARY=$PREFIX/data/bufr/
fi
#
# --- Show release info
#
release="on $(hostname)"
if [[ -f RELEASE ]]; then
  echo
  cat RELEASE
elif [[ -f README ]]; then
  release=$(grep "(Release" README | awk '{print $1 " " $2}')
fi
runtime=$(date "+%H:%M %z on %A, %d-%b-%Y")
echo
echo ">> Building BUFR $release at $runtime"
#
# ---- Under Cywin (Windows) convert paths to semi-Windows style ----
#      E.g. if C: is 'mounted' to mount point /c, then c:\include is
#      mapped to /c/include, which the Intel compiler confuses with
#      the /c (compile only) switch. We use the cygpath utility to
#      convert such paths to c:/include which the compiler is happy
#      with and doesn't cause bash any problems with backslashes
#      either, which could be interpreted as escape characters.
#      A further issue is to remove any trailing '/' from some paths.
#
if [[ $OS = "CYGWIN" ]]; then
  HOME=$(cygpath -m $HOME | sed s#"\/$"##)
  TOP=$(cygpath -m $TOP)
  PREFIX=$(cygpath -m $PREFIX)
  BUFR_LIBRARY=$(cygpath -m $BUFR_LIBRARY)
fi
#
PREFIX=$(echo $PREFIX | sed s#"\/$"##)
BINDIR=$PREFIX/bin
LIBDIR=$PREFIX/lib
INCDIR=$PREFIX/include
MANDIR=$PREFIX/man
DATDIR=$PREFIX/data
#
# --- Ensure the last character of BUFR_LIBRARY is a '/'
#     and is a full path
#
BUFR_LIBRARY=${BUFR_LIBRARY%%/}/
if [[ $BUFR_LIBRARY = "./" ]]; then
  BUFR_LIBRARY=$TOP/
fi
export BUFR_LIBRARY
#
# --- Create any missing directories ---
#
echo
echo ">> Checking target directories..."
if [[ $OS = "AIX" ]]; then
mkdir -p $BINDIR
mkdir -p $LIBDIR
mkdir -p $INCDIR
mkdir -p $MANDIR/man1
mkdir -p $DATDIR/bufr
mkdir -p ${BUFR_LIBRARY%%/}
else
mkdir -p -v $BINDIR
mkdir -p -v $LIBDIR
mkdir -p -v $INCDIR
mkdir -p -v $MANDIR/man1
mkdir -p -v $DATDIR/bufr
mkdir -p -v ${BUFR_LIBRARY%%/}
fi
#
#  --- Set up favourite compiler ---
#
echo
if [[ $OS = "CYGWIN" ]]; then
  INCDIR=$(cygpath -u $INCDIR)
fi
export INCDIR
. ./f90_select f90opt=$f90opt
echo ">> Using $f90name compiler ($FF)"
echo
echo ">> Setting up file syntax for $OS..."
OBJ=".o"
EXE=""
TARGET=libmetdbbufr
BUFRLIB=${TARGET}.a
MAKEFILE1="Makefile_BUFRrelease"
MAKEFILE2="Makefile_BUFRtest"
MAKEFILE3="Makefile"
if [[ $OS = "CYGWIN" ]]; then
  if [[ $FF = "ifort" ]]; then
    OBJ=".obj"
    sed s/"\\.o"/"\\.obj"/g metdb/$MAKEFILE1 > metdb/${MAKEFILE1}_CYGWIN
    MAKEFILE1="${MAKEFILE1}_CYGWIN"
  fi
#
# ---- Under Cywin (Windows) convert paths to Unix style ----
#      The 'make' utility doesn't like having ':' appear in file names -
#      which it uses as a syntax separator. So we use the cygpath utility
#      here to convert semi-Windows style cygdrive/c:/include (/c:/include
#      if mounted) to /cygdrive/c/include (or /c/include). Oh the joys of
#      working with Windows!
#
  PREFIX=$(cygpath -u $PREFIX)
  BINDIR=$PREFIX/bin
  LIBDIR=$PREFIX/lib
  INCDIR=$PREFIX/include
  MANDIR=$PREFIX/man
  DATDIR=$PREFIX/data
  EXE=".exe"
fi
#
#  --- Install operational & local BUFR tables ---
#
echo
echo ">> Copying operational BUFR tables to $BUFR_LIBRARY..."
$INSTALL $TOP/metdb/TABLEB  $BUFR_LIBRARY
$INSTALL $TOP/metdb/TABLED  $BUFR_LIBRARY
$INSTALL $TOP/metdb/CODEFIG $BUFR_LIBRARY
#
echo
echo ">> Copying local BUFR tables to $BUFR_LIBRARY..."
$INSTALL $TOP/extra/MASTERTABLE  $BUFR_LIBRARY
$INSTALL $TOP/extra/DATACATEGORY $BUFR_LIBRARY
$INSTALL $TOP/extra/ORIGCENTRE   $BUFR_LIBRARY
if [[ -s $TOP/extra/CODEFIG ]]; then
  $INSTALL $TOP/extra/CODEFIG $BUFR_LIBRARY
fi
if [[ -s $TOP/extra/TABLEB ]]; then
  $INSTALL $TOP/extra/TABLEB $BUFR_LIBRARY
fi
if [[ -s $TOP/extra/TABLED ]]; then
  $INSTALL $TOP/extra/TABLED $BUFR_LIBRARY
fi
#
#  --- Build MetDB kernel BUFR object library ---
#
echo
cd $TOP/metdb
if [[ "$clean" = "y" ]]; then
  echo ">> Cleaning BUFR kernel object library..."
  echo
  make -f $MAKEFILE1 clean
  if [[ -f $BUFRLIB ]]; then
    $DELETE $BUFRLIB
  fi
  if [[ -f $LIBDIR/$BUFRLIB ]]; then
    $DELETE $LIBDIR/$BUFRLIB
  fi
  echo
fi
echo ">> Building BUFR kernel object library $BUFRLIB..."
echo
make -f $MAKEFILE1 FF=$FF FFLAGS="$FFLAGS" \
                   CC=$CC CFLAGS="$CFLAGS" TARGET=$TARGET
echo
if [[ -f $BUFRLIB ]]; then
  cp $BUFRLIB $TOP/extra
#
#  --- Optionally build & run MetDB simple encode/decode test programs ---
#
  BUFRDEC_FILE="$TOP/metdb/TestMessage.bufr"
  export BUFRDEC_FILE
  if [[ "$test" = "y" ]]; then
    echo
    $INSTALL $TOP/extra/$MAKEFILE2 $TOP/metdb/
    if [[ $clean = "y" ]]; then
      echo
      echo ">> Cleaning test programs & data..."
      make -f $MAKEFILE2 OBJ=$OBJ EXE=$EXE \
                         BUFRLIB=$BUFRLIB clean
      if [[ -f $BUFRDEC_FILE ]]; then
        $DELETE $BUFRDEC_FILE
      fi
    fi
    echo
    echo ">> Testing basic encode/decode..."
    echo
    make -f $MAKEFILE2 FF=$FF FFLAGS="$FFLAGS" \
                       OBJ=$OBJ EXE=$EXE BUFRLIB=$BUFRLIB
    echo
    echo "   - Encoding..."
    echo
    ./BUFRencode${EXE}
    if [[ -f $BUFRDEC_FILE ]]; then
      echo
      echo "   - Decoding..."
      ./BUFRdecode${EXE}
    else
      echo
      echo "*** Encode failed! ***"
    fi
  fi
#
# ---- Build & run extra utility routines & programs ---
#
  echo
  cd $TOP/extra
  if [[ "$clean" = "y" ]]; then
    echo ">> Cleaning BUFR extra utilities..."
    echo
    make -f $MAKEFILE3 PREFIX=$PREFIX OBJ=$OBJ EXE=$EXE clean
    $DELETE $MANDIR/man1/decbufr.1
    echo
  fi
#
  echo ">> Adding BUFR extra routines to $BUFRLIB"
  echo "   and making BUFR utility programs in $BINDIR..."
  echo

  ar -t $BUFRLIB | grep sec1tables > /dev/null
  if [[ $? -eq 0 ]]; then
    echo
    echo "$BUFRLIB is up to date"
  else
    touch -t $(date "+%Y%m%d")0000 $BUFRLIB  # force make to add 'new' bits
  fi
#
# --- NAG compiler needs system interfaces adding to the library
#
  if [[ ${f90name:0:3} = "NAG" ]]; then
    NAGIF=nag_interfaces.f90
  else
    NAGIF=""
  fi

  echo
  make -f $MAKEFILE3 FF=$FF FFLAGS="$FFLAGS" PREFIX=$PREFIX \
                     OBJ=$OBJ EXE=$EXE BUFRLIB=$BUFRLIB NAGIF=$NAGIF
  if [[ $? -eq 0 ]]; then
    make -f $MAKEFILE3 PREFIX=$PREFIX EXE=$EXE $install_extra
  fi
  echo
  if [[ -f testtables ]]; then
    echo ">> Testing BUFR run-time Tables A,B,D and Code Tables..."
    ./testtables${EXE} < testtables.dat
  else
    echo "*** Failed to build testtables - correct error(s) and re-run"
  fi
  echo
  if [[ -f decbufr ]]; then
    echo ">> Testing decbufr..."
    ./decbufr${EXE} $BUFRDEC_FILE -d
  else
    echo "*** Failed to build decbufr - correct error(s) and re-run"
  fi
#
  echo
  echo ">> Installing $BUFRLIB to $LIBDIR..."
  $INSTALL $BUFRLIB $LIBDIR
#
else
   echo "*** Failed to build BUFR library - correct error(s) and re-run"
fi
#
# --- Install man pages ---
#
echo
echo ">> Copying MAN files to $MANDIR/man1..."
$INSTALL $TOP/extra/*.1 $MANDIR/man1
#
echo
cd $TOP
#
exit
