#!/bin/bash

# This configure script is hand-generated, not auto-generated.  It creates the
# file kaldi.mk, which is %included by the Makefiles in the subdirectories.
# The file kaldi.mk is editable by hand -- for example, you may want to
# uncomment the options -O0 -DKALDI_PARANOID, or edit the DOUBLE_PRECISION
# variable (to be 1 not 0).

#  Example command lines:
# ./configure
# ./configure --shared                # Build shared Kaldi libraries.
# ./configure --mathlib=OPENBLAS      # Build and use OpenBLAS.
#        # Before doing this, cd to ../tools and type "make -j openblas".
# ./configure --openblas-root=/usr    # Use system OpenBLAS.
#        # Note: this is not working correctly on all platforms, do "make test"
#        # and look out for segmentation faults.
# ./configure --atlas-root=../tools/ATLAS/build
# ./configure --use-cuda=no   # disable CUDA detection (will build cpu-only
#                             # version of kaldi even on CUDA-enabled machine.
# ./configure --use-cuda --cudatk-dir=/usr/local/cuda/ --cuda-arch=-arch=sm_70
#        # Use cuda in /usr/local/cuda and set the arch to sm_70
# ./configure --static --fst-root=/opt/cross/armv8hf \
#   --atlas-root=/opt/cross/armv8hf --host=armv8-rpi3-linux-gnueabihf
#        # Cross-compile for armv8hf. This assumes that you have OpenFST built
#        # with the armv8-rpi3-linux-gnueabihf toolchain and installed to
#        # /opt/cross/armv8hf. It also assumes that you have an ATLAS library
#        # built for the target install to /opt/cross/armv8hf and that the
#        # armv8-rpi3-linux-gnueabihf toolchain is available in your path.
# ./configure --static --openblas-root=/opt/cross/arm-linux-androideabi \
#   --fst-root=/opt/cross/arm-linux-androideabi --fst-version=1.6.9 \
#   --android-incdir=/opt/cross/arm-linux-androideabi/sysroot/usr/include \
#   --host=arm-linux-androideabi
#        # Cross-compile for Android on arm. The only difference here is the
#        # addition of the the --android-includes flag because the toolchains
#        # produced by the Android NDK don't always include the C++ stdlib
#        # headers in the normal cross-compile include path.
#   --host=aarch64-linux-android
#        # support for 64bit ARMv8 (AArch64) architecture in Android.

# This should be incremented after any significant change to the configure
# script, i.e. any change affecting kaldi.mk or the build system as a whole.
CONFIGURE_VERSION=14

# We support bash version 3.2 (Macs still ship with this version as of 2019)
# and above.
[[ $BASH_VERSION < '3.2' ]] && {
  echo >&2 "bash version ${BASH_VERSION} is too old, cannot continue." \
           "You won't be able to run Kaldi recipes with it anyway." \
           "Please upgrade. bash version 3.2 or higher is required."
  exit 1;
}

if ! [ -x "$PWD/configure" ]; then
  echo 'You must run "configure" from the src/ directory.'
  exit 1
fi

function usage {
  cat <<EOF
'configure' configures Kaldi installation.

Usage: [VAR=VALUE]... $0 [OPTION]...

The default configuration is to build and link against static Kaldi libraries.
OpenFst and Math libraries are linked dynamically.

Configuration options:
  --help                Display this help message and exit
  --version             Display the version of 'configure' and exit
  --static              Build and link against static libraries [default=no]
  --shared              Build and link against shared libraries [default=no]
  --use-cuda            Build with CUDA [default=yes]
  --with-cudadecoder    Build with CUDA decoder [default=yes]
  --cudatk-dir=DIR      CUDA toolkit directory
  --cuda-arch=FLAGS     Override the default CUDA_ARCH flags. See:
         https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#nvcc-examples.
  --debug-level=N       Use assertion level 0 (disabled), 1, or 2 [default=1]
  --double-precision    Build with BaseFloat set to double if yes [default=no],
                        mostly useful for testing purposes.
  --static-fst          Build with static OpenFst libraries [default=no]
  --fst-root=DIR        OpenFst root directory [default=../tools/openfst/]
  --fst-version=STR     OpenFst version string
  --mathlib=LIB         Math library [default=MKL|OPENBLAS, based on platform]
                        Supported libraries: ATLAS, MKL, CLAPACK, OPENBLAS.
  --static-math         Build with static math libraries [default=no]
  --atlas-root=DIR      ATLAS root directory [default=../tools/ATLAS/]
  --openblas-root=DIR   OpenBLAS root directory
  --clapack-root=DIR    CLAPACK root directory
  --mkl-root=DIR        MKL root directory
  --mkl-libdir=DIR      MKL library directory
  --omp-libdir=DIR      OpenMP directory
  --speex-root=DIR      SPEEX root directory
  --speex-libdir=DIR    SPEEX library directory
  --speex-incdir=DIR    SPEEX include directory
  --static-speex        Build with static speex libraries [default=no]
  --host=HOST           Host triple in the format 'cpu-vendor-os'
                        If provided, it is prepended to all toolchain programs.
  --android-incdir=DIR  Android include directory
  --enable-kenlm        enable kenlm runtime library installed in "../tools/kenlm"
                        via extras/install_kenlm_query_only.sh, [default=no]
  --enable-tcmalloc     enable tcmalloc library installed in "../tools/gperftools"
                        via extras/install_tcmalloc.sh, [default=no]

Following environment variables can be used to override the default toolchain.
  CXX         C++ compiler [default=g++]
  AR          Archive maintenance utility [default=ar]
  AS          Assembler [default=as]
  RANLIB      Archive indexing utility [default=ranlib]

If a host triple is provided, it is prepended to CXX, AR, AS and RANLIB.

Following environment variables can be used to provide additional flags to the
compiler/linker.
  CXXFLAGS    Additional C++ compiler flags, e.g. -I<include-dir>
  LDFLAGS     Additional linker flags, e.g. -L<lib-dir>
  LDLIBS      Additional libraries to pass to the linker, e.g. -l<lib>

EOF
}

# E.g. Die "Invalid switch --foobar"
Die() { echo >&2 "$0: FATAL:" "$@"; exit 1; }

# E.g. abspath=$(rel2abs "../tools") || exit 1
#  - Set 'abspath' to existing absolute path of $1, return 0.
#  - print empty string if path does not exist, return non-0.
function rel2abs {
  [[ $1 ]] && cd -P "$1" 2>/dev/null && pwd
}

# E.g.: GetSwitchValue var --some-switch=foo
# Assign variable named 'var' to 'foo'. Return 0 iff value is not empty.
GetSwitchValue() {
  IFS='=' read -r -- _ $1 <<< "$2" && [[ ${!1} ]]
}

# E.g.: GetSwitchValueOrDie var --some-switch=foo
# Assign variable named 'var' to 'foo'. Die with a fatal error if value is empty.
GetSwitchValueOrDie() {
  GetSwitchValue "$@" ||
    Die "'$2': switch requires a value. See '$0 --help'."
}

# E.g.: GetSwitchExistingPathOrDie var --some-switch=../tools
#  - Set 'var' to absolute path of '../tools' if exists, return 1.
#  - Die with a fatal error if path does not exist or not given in switch.
GetSwitchExistingPathOrDie() {
  GetSwitchValueOrDie "$@"  # Already sets variable named $1 to path.
  local path varname=$1
  path=$(rel2abs "${!varname}") && [[ -d $path ]] ||
    Die "'$2': switch must specify an existing directory. See '$0 --help'."
  builtin printf -v $varname %s "$path"  # Assign $path to variable '$varname'.
}

# TODO(kkm): Kill this. `[[ ${var-} ]]' is the idiomatic equivalent in bash.
#   Even better, do not rely on uninitialized variables.
function is_set {
  local myvar=${1:-notset}
  if [ "$myvar" == "notset" ]; then
    return 1
  else
    return 0
  fi
}

# Lowercase/uppercase argument. Only bash 4.2+ has internal faclilties for this,
# and we support versions down to 3.2.
lcase () { awk '{print tolower($0)}' <<<"$1" ; }
ucase () { awk '{print toupper($0)}' <<<"$1" ; }

function failure {
  echo "***configure failed: $* ***" >&2
  rm -f kaldi.mk
  exit 1;
}

function check_exists {
  [[ -f $1 ]] || failure "$1 not found."
}

function check_library {
  local libpath=$1
  local libname=$2
  local libext=$3
  local full_libname="$libpath/$libname.$libext"
  ##echo "Testing $full_libname" >&2
  test -f "$full_libname" && return ;
  return 1
}

function check_compiler {

  # Part of error message.
  local supported_compiler="GNU g++ >= 5.0, Apple clang >= 6.0 or LLVM clang >= 3.5"
  local compiler=$1
  local compiler_ver_info compiler_ver compiler_ver_num

  compiler_ver_info=$($compiler --version 2>/dev/null) ||
    failure "$compiler is not installed.
You need $supported_compiler."

  case $compiler_ver_info in
    *[gc]++*)
      compiler_ver=$($compiler -dumpversion)
      compiler_ver_num=$(echo $compiler_ver | sed 's/\./ /g' | xargs printf "%d%02d%02d")
      (( compiler_ver_num < 50000 )) &&
        failure "$compiler (g++-$compiler_ver) is not supported.
You need $supported_compiler."
      ;;

    *Apple*)
      compiler_ver=$(echo $compiler_ver_info | grep version | sed "s/.*version \([0-9\.]*\).*/\1/")
      compiler_ver_num=$(echo $compiler_ver_info | grep version | sed "s/.*clang-\([0-9]*\).*/\1/")
      (( compiler_ver_num < 600 )) &&
        failure "$compiler (Apple clang-$compiler_ver) is not supported.
You need $supported_compiler."
      ;;

    *LLVM*|*[Cc]lang)
      compiler_ver=$(echo $compiler_ver_info | grep version | sed "s/.*version \([0-9\.]*\).*/\1/")
      compiler_ver_num=$(echo $compiler_ver | sed 's/\./ /g' | xargs printf "%d%02d")
      (( compiler_ver_num < 305 )) &&
        failure "$compiler (LLVM clang-$compiler_ver) is not supported.
You need $supported_compiler."
      ;;

    *)
      echo >&2 "WARNING: Unfamiliar compiler $compiler. Use at your risk and peril."
  esac

}

function check_for_slow_expf {
  # We cannot run this test if we are cross compiling.
  if [[ "$TARGET_ARCH" == "`uname -m`" ]] ; then
    ( cd probe
      rm -f exp-test
      make -f Makefile.slow_expf 1>/dev/null
      if ! ./exp-test; then
        echo "\
*** WARNING: expf() seems to be slower than exp() on your machine. This is
***          a known bug in old versions of glibc. Please consider updating it.
***          Kaldi will be configured to use exp() instead of expf() in
***          base/kaldi-math.h Exp() routine for single-precision floats."
        echo "CXXFLAGS += -DKALDI_NO_EXPF" >> ../kaldi.mk
      fi
    )
  fi
}

# CUDA is used only in selected directories including src/cudamatrix, src/nnet*
# and src/chain*. It is used to accelerate the neural network training.
# The rest of Kaldi runs on CPUs.

function configure_cuda {
  # Check for CUDA toolkit in the system
  if [ ! -d "$CUDATKDIR" ]; then
    for base in /usr/local/share/cuda /usr/local/cuda /usr/; do
      if [ -f $base/bin/nvcc ]; then
        CUDATKDIR=$base
      fi
    done
  fi

  if [ -d "$CUDATKDIR" ]; then
    if [ ! -f $CUDATKDIR/bin/nvcc ]; then
      failure "Cannnot find nvcc in CUDATKDIR=$CUDATKDIR"
    fi

    if [[ "$TARGET_ARCH" != "`uname -m`" ]] ; then
      failure "Cannot cross compile with CUDA support"
    fi

    # Determine 'CUDA_ARCH',
    CUDA_VERSION=$($CUDATKDIR/bin/nvcc -V | tr '.,' '_ ' |
                     awk '/release/{sub(/.*release/,""); print $1;}') # MAJOR_MINOR,
    [[ $CUDA_VERSION ]] ||
      failure "Cannot figure out CUDA version from the nvcc output.
Either your CUDA is too new or too old."

    COMPILER_VER_INFO=$($CXX --version 2>/dev/null)
    if [[ $COMPILER_VER_INFO == *[gc]"++"* ]]; then
      GCC_VER=$($CXX -dumpversion)
      GCC_VER_NUM=$(echo $GCC_VER | sed 's/\./ /g' | xargs printf "%d%02d%02d")
      case $CUDA_VERSION in
        # Disabling CUDA 7 and CUDA 8 because we now use C++14 to compile CUDA
        # code. It is still possible to use those cuda versions by switching
        # back to C++11 in src/makefiles/cuda_64bit.mk and use CUB <= 1.8.0.
        # See tools/ and https://github.com/kaldi-asr/kaldi/pull/4242
        #7_*)
        #  MIN_UNSUPPORTED_GCC_VER="5.0"
        #  MIN_UNSUPPORTED_GCC_VER_NUM=50000;
        #;;
        #8_*)
        #  MIN_UNSUPPORTED_GCC_VER="6.0"
        #  MIN_UNSUPPORTED_GCC_VER_NUM=60000;
        #;;
        [1-8]_*)
          failure "CUDA version $CUDA_VERSION is too old and unsupported."
          ;;
        9_[01])
          MIN_UNSUPPORTED_GCC_VER="7.0"
          MIN_UNSUPPORTED_GCC_VER_NUM=70000
          ;;
        9_* | 10_0)
          MIN_UNSUPPORTED_GCC_VER="8.0"
          MIN_UNSUPPORTED_GCC_VER_NUM=80000
          ;;
        10_*)
          MIN_UNSUPPORTED_GCC_VER="9.0"
          MIN_UNSUPPORTED_GCC_VER_NUM=90000
          ;;
        11_[0-3])
          MIN_UNSUPPORTED_GCC_VER="10.0"
          MIN_UNSUPPORTED_GCC_VER_NUM=100000
          ;;
        11_*)
          MIN_UNSUPPORTED_GCC_VER="12.0"
          MIN_UNSUPPORTED_GCC_VER_NUM=120000
          ;;
        12_*)
          MIN_UNSUPPORTED_GCC_VER="12.0"
          MIN_UNSUPPORTED_GCC_VER_NUM=120000
          ;;
        *)
          failure "Unsupported CUDA version ${CUDA_VERSION}.
Please open an issue at https://github.com/kaldi-asr/kaldi/issues and include\
 output of either 'nvcc -h' or 'ptxas -h'."
          ;;
      esac
      (( GCC_VER_NUM < MIN_UNSUPPORTED_GCC_VER_NUM )) ||
        failure "CUDA $CUDA_VERSION does not support $CXX (g++-$GCC_VER).\
 Only versions strictly older than $MIN_UNSUPPORTED_GCC_VER are supported."

      case $CUDA_VERSION in
        [1-8]_* | 9_0) CUSOLVER=false ;;
        *) CUSOLVER=true ;;
      esac
    fi

    if [[ ! $CUDA_ARCH ]]; then
      case `uname -m` in
        x86_64 | ppc64le)
          case $CUDA_VERSION in
            # Disabling CUDA 7 and 8. See a few lines above for details.
            #7_*) CUDA_ARCH="-gencode arch=compute_30,code=sm_30 -gencode arch=compute_35,code=sm_35 -gencode arch=compute_50,code=sm_50 -gencode arch=compute_52,code=sm_52" ;;
            #8_*) CUDA_ARCH="-gencode arch=compute_30,code=sm_30 -gencode arch=compute_35,code=sm_35 -gencode arch=compute_50,code=sm_50 -gencode arch=compute_52,code=sm_52 -gencode arch=compute_60,code=sm_60 -gencode arch=compute_61,code=sm_61" ;;
            9_*) CUDA_ARCH="-gencode arch=compute_30,code=sm_30 -gencode arch=compute_35,code=sm_35 -gencode arch=compute_50,code=sm_50 -gencode arch=compute_52,code=sm_52 -gencode arch=compute_60,code=sm_60 -gencode arch=compute_61,code=sm_61 -gencode arch=compute_70,code=sm_70" ;;
            10_*) CUDA_ARCH="-gencode arch=compute_30,code=sm_30 -gencode arch=compute_35,code=sm_35 -gencode arch=compute_50,code=sm_50 -gencode arch=compute_52,code=sm_52 -gencode arch=compute_60,code=sm_60 -gencode arch=compute_61,code=sm_61 -gencode arch=compute_70,code=sm_70 -gencode arch=compute_75,code=sm_75" ;;
            11_0) CUDA_ARCH="-gencode arch=compute_35,code=sm_35 -gencode arch=compute_50,code=sm_50 -gencode arch=compute_52,code=sm_52 -gencode arch=compute_60,code=sm_60 -gencode arch=compute_61,code=sm_61 -gencode arch=compute_70,code=sm_70 -gencode arch=compute_75,code=sm_75 -gencode arch=compute_80,code=sm_80" ;;
            11_*) CUDA_ARCH="-gencode arch=compute_35,code=sm_35 -gencode arch=compute_50,code=sm_50 -gencode arch=compute_52,code=sm_52 -gencode arch=compute_60,code=sm_60 -gencode arch=compute_61,code=sm_61 -gencode arch=compute_70,code=sm_70 -gencode arch=compute_75,code=sm_75 -gencode arch=compute_80,code=sm_80 -gencode arch=compute_86,code=sm_86" ;;
            12_*) CUDA_ARCH="-gencode arch=compute_50,code=sm_50 -gencode arch=compute_52,code=sm_52 -gencode arch=compute_60,code=sm_60 -gencode arch=compute_61,code=sm_61 -gencode arch=compute_70,code=sm_70 -gencode arch=compute_75,code=sm_75 -gencode arch=compute_80,code=sm_80 -gencode arch=compute_86,code=sm_86 -gencode arch=compute_89,code=sm_89 -gencode arch=compute_90,code=sm_90" ;;
            *) failure \
                 "Unsupported CUDA version ${CUDA_VERSION}. Please open an" \
                 "issue at https://github.com/kaldi-asr/kaldi/issues and" \
                 "include output of either 'nvcc -h' or 'ptxas -h'."
          esac
        ;;
        aarch64)
          case $CUDA_VERSION in
            #7_*) CUDA_ARCH="-gencode arch=compute_53,code=sm_53" ;;
            #8_*) CUDA_ARCH="-gencode arch=compute_53,code=sm_53 -gencode arch=compute_62,code=sm_62" ;;
            9_*) CUDA_ARCH="-gencode arch=compute_53,code=sm_53 -gencode arch=compute_62,code=sm_62" ;;
            10_*|11_*|12_*) CUDA_ARCH="-gencode arch=compute_53,code=sm_53 -gencode arch=compute_62,code=sm_62 -gencode arch=compute_72,code=sm_72" ;;
            *) echo "Unsupported CUDA_VERSION (CUDA_VERSION=$CUDA_VERSION), please report it to Kaldi mailing list, together with 'nvcc -h' or 'ptxas -h' which lists allowed -gencode values..."; exit 1 ;;
          esac
        ;;
        *) echo "Unsupported architecture for use of Kaldi with CUDA. Please let us know by opening a bug at:
    https://github.com/kaldi-asr/kaldi/issues/new?template=bug_report.md&title=Unsupported+CUDA+platform+[FILLPLATFORMNAME]"
           exit 1
      esac
    fi

    echo "Using CUDA toolkit $CUDATKDIR (nvcc compiler and runtime libraries)"
    echo >> kaldi.mk
    echo "# CUDA configuration" >> kaldi.mk
    echo >> kaldi.mk

    echo CUDA = true >> kaldi.mk
    echo CUDATKDIR = $CUDATKDIR >> kaldi.mk
    echo "CUDA_ARCH = $CUDA_ARCH" >> kaldi.mk
    echo "HOST_ARCH = `uname -m`" >> kaldi.mk
    echo >> kaldi.mk

    # 64bit/32bit? We do not support cross compilation with CUDA so, use direct
    # calls to uname -m here
    if [ "`uname -m`" == "x86_64" ]; then
      if [ "`uname`" == "Darwin" ]; then
        sed 's/lib64/lib/g' < makefiles/cuda_64bit.mk >> kaldi.mk
      else
        cat makefiles/cuda_64bit.mk >> kaldi.mk
      fi
    elif [ "`uname -m`" == "aarch64" ]; then
      cat makefiles/cuda_64bit.mk >> kaldi.mk
    elif [ "`uname -m`" == "ppc64le" ]; then
      cat makefiles/cuda_64bit.mk >> kaldi.mk
    else
      echo "\
WARNING: CUDA will not be used!
         CUDA is not supported with 32-bit builds."
      exit 1;
    fi

    #add cusolver flags for newer toolkits
    if [ "$CUSOLVER" == "true" ]; then
      echo "CUDA_LDLIBS += -lcusolver" >> kaldi.mk
    fi

  else
    echo "\
WARNING: CUDA will not be used! If you have already installed cuda drivers
         and CUDA toolkit, try using the --cudatk-dir= option. A GPU and CUDA
         are required to run neural net experiments in a realistic time."
  fi
}

function linux_configure_speex {
  # Check whether the user has called tools/extras/install_speex.sh or not
  [ ! -z "$SPEEXROOT" ] || SPEEXROOT=`pwd`/../tools/speex
  [ ! -z "$SPEEXLIBDIR" ] || SPEEXLIBDIR="$SPEEXROOT"/lib
  [ ! -z "$SPEEXINCDIR" ] || SPEEXINCDIR="$SPEEXROOT"/include

  if $static_speex; then
    spx_type=a
  else
    spx_type=so
  fi
  if [ ! -f "$SPEEXLIBDIR/libspeex.${spx_type}" ];then
    echo "\
INFO: Configuring Kaldi not to link with Speex. Don't worry, it's only needed if
      you intend to use 'compress-uncompress-speex', which is very unlikely."
    return
  fi

  if [ -f $SPEEXINCDIR/speex/speex.h ]; then
    echo >> kaldi.mk
    echo CXXFLAGS += -DHAVE_SPEEX -I${SPEEXINCDIR} >> kaldi.mk

    if $static_speex; then
      echo LDLIBS += $SPEEXLIBDIR/libspeex.a
    else
      echo LDLIBS += -L${SPEEXLIBDIR} -lspeex >> kaldi.mk
      echo LDFLAGS += -Wl,-rpath=${SPEEXLIBDIR} >> kaldi.mk
    fi

    echo "Successfully configured with Speex at $SPEEXROOT, (static=[$static_speex])"
  else
    echo "Speex will not be used. If you want to use it, run tools/extras/install_speex.sh first."
  fi
}

function linux_configure_atlas_failure {
  echo ATLASINC = $ATLASROOT/include >> kaldi.mk
  echo ATLASLIBS = [somewhere]/liblapack.a [somewhere]/libcblas.a [somewhere]/libatlas.a [somewhere]/libf77blas.a $ATLASLIBDIR >> kaldi.mk
  echo >> kaldi.mk

  failure "*** $*
***
*** Configure cannot proceed automatically.
***
*** If you know that you have ATLAS installed somewhere on your machine, you may
*** be able to proceed by replacing [somewhere] in kaldi.mk with a directory.
***
*** If you have sudo (root) access you could install the ATLAS package on your
*** machine, e.g. 'sudo apt-get install libatlas-dev libatlas-base-dev' or
*** 'sudo yum install atlas.x86_64' or 'sudo zypper install libatlas3-devel'
***
*** On cygwin, install atlas from the installer GUI; and then run
*** ./configure again.
***
*** Otherwise (or if you prefer OpenBLAS for speed), you could go the OpenBLAS
*** route: cd to ../tools, type 'extras/install_openblas.sh', cd back to here,
*** and type './configure --mathlib=OPENBLAS'."
}

function linux_atlas_check_static {
  # will exit with success if $dir seems to contain ATLAS libraries with
  # right architecture (compatible with default "nm")
  echo "int main(void) { return 0; }" > test_linking.cc;
  if [ -f $dir/libatlas.a ]; then # candidate...
    # Note: on the next line, the variable assignment
    # LANG=en_US should apply just to the program called on that line.
    if LANG=en_US $CXX -o test_linking test_linking.cc -u ATL_flushcache $dir/libatlas.a 2>&1 | grep -i "incompatible" >/dev/null; then
      echo "Directory $dir may contain ATLAS libraries but seems to be wrong architecture";
      rm test_linking test_linking.cc 2>/dev/null
      return 1;
    fi
    rm test_linking test_linking.cc 2>/dev/null
    return 0;
  else
    rm test_linking.cc
    return 1;
  fi
}

function linux_configure_atlas_generic {
  # You pass in a directory (e.g. /usr/lib/atlas-base) and a suffix (e.g. so.3.0)
  # and it tries to find ATLAS libraries with that dir and suffix.  On success it
  # returns 0; on failure, it returns 1.
  dir=$1
  suffix=$2
  ATLASLIBS="$dir/libatlas.$suffix $dir/libf77blas.$suffix $dir/libcblas.$suffix $dir/liblapack_atlas.$suffix"
  for f in $ATLASLIBS; do
    [ ! -f $f ] && return 1;
  done
  lapacklib=$(echo $ATLASLIBS | awk '{print $NF}')
  if ! nm --dynamic $lapacklib | grep ATL_cgetrf >/dev/null; then
    echo "configure: failed to find symbol ATL_cgetrf in library $lapacklib"
    exit 1;
  fi
  libdir=$(dirname $(echo $ATLASLIBS | awk '{print $1}'))
  [ -z "$libdir" ] && echo "Error getting libdir in linux_configure_atlas_generic: dir=$dir,suffix=$suffix" && exit 1;
  echo ATLASINC = $ATLASROOT/include >> kaldi.mk
  echo ATLASLIBS = $ATLASLIBS -Wl,-rpath=$libdir >> kaldi.mk
  echo >> kaldi.mk
  echo "Successfully configured ATLAS with ATLASLIBS=$ATLASLIBS"
}

function linux_configure_atlas_redhat_fat {
  # This is for when only two so-called 'fat' ATLAS libs are provided:
  # libsatlas.so.3 and libtatlas.so.3.
  # See http://stackoverflow.com/questions/13439296/build-shared-libraries-in-atlas.
  m=$1  # 64 or empty.
  ATLASLIBS="/usr/lib$m/atlas/libsatlas.so.3 /usr/lib$m/atlas/libtatlas.so.3"
  for f in $ATLASLIBS; do
    [ ! -f $f ] && return 1;
  done
  libdir=$(dirname $(echo $ATLASLIBS | awk '{print $1}'))
  [ -z "$libdir" ] && echo "Error getting libdir in linux_configure_atlas_redhat_fat" && exit 1;
  echo ATLASINC = $ATLASROOT/include >> kaldi.mk
  echo ATLASLIBS = $ATLASLIBS -Wl,-rpath=$libdir >> kaldi.mk
  echo >> kaldi.mk
  echo "Successfully configured for red hat [dynamic libraries, fat] with ATLASLIBS =$ATLASLIBS"
}

function linux_configure_atlas_static {
  if [ -z $ATLASLIBDIR ]; then # Note: it'll pick up the last one below.
    for dir in /usr{,/local}/lib{64,}{,/atlas,/atlas-sse2,/atlas-sse3} \
       /usr/local/atlas/lib{,64} `pwd`/../tools/ATLAS/build/install/lib/ $ATLASROOT/lib; do
     linux_atlas_check_static && ATLASLIBDIR=$dir
    done
    if [ -z $ATLASLIBDIR ]; then # Note: it'll pick up the last one below.
      echo "Could not find libatlas.a in any of the generic-Linux places, but we'll try other stuff..."
      return 1;
    fi
  elif [ ! -f $ATLASLIBDIR/libatlas.a ]; then
    echo "Could not find libatlas.a in '$ATLASLIBDIR'"
    return 1;
  fi
  echo "Validating presence of ATLAS libs in $ATLASLIBDIR"
  ATLASLIBS=
  # The Lapack part of ATLAS seems to appear under various different names.. but it
  # should always have symbols like ATL_cgetrf and clapack_cgetrf defined, so we test for this.
  for libname in liblapack liblapack_atlas  libclapack; do
    if [ -f $ATLASLIBDIR/${libname}.a -a "$ATLASLIBS" == "" ]; then
      if nm  $ATLASLIBDIR/${libname}.a  | grep ATL_cgetrf >/dev/null && \
	 nm  $ATLASLIBDIR/${libname}.a  | grep clapack_cgetrf >/dev/null; then
         ATLASLIBS=$ATLASLIBDIR/${libname}.a
         echo "Using library $ATLASLIBS as ATLAS's CLAPACK library."
      fi
    fi
  done
  if [ "$ATLASLIBS" == "" ]; then
    echo Could not find any libraries $ATLASLIBDIR/{liblapack,liblapack_atlas,libclapack} that seem to be an ATLAS CLAPACK library.
    return 1;
  fi

  for x in libcblas.a libatlas.a libf77blas.a; do
    if [ ! -f $ATLASLIBDIR/$x ]; then
      echo "Configuring static ATLAS libraries failed: Could not find library $x in directory $ATLASLIBDIR"
      return 1;
    fi
    ATLASLIBS="$ATLASLIBS $ATLASLIBDIR/$x"
  done

  echo ATLASINC = $ATLASROOT/include >> kaldi.mk
  echo ATLASLIBS = $ATLASLIBS >> kaldi.mk
  echo >> kaldi.mk
  echo "Successfully configured for Linux [static libraries] with ATLASLIBS =$ATLASLIBS"
}

#############################    CONFIGURATION    #############################

# If configuration sets any of these variables, we will switch the external
# math library. Here we unset them so that we can check later.
#TODO(kkm): Maybe allow env vars to provide defaults?
ATLASROOT=
CLAPACKROOT=
MATHLIB=
MKLLIBDIR=
MKLROOT=
OPENBLASROOT=

# This variable identifies the type of system where built programs and
# libraries will run. It is set by the configure script when cross compiling.
HOST=

# These environment variables can be used to provide additional flags to the
# compiler/linker. We want these flags to override the flags determined by the
# configure script, so we append them to the appropriate variables (CXXFLAGS,
# LDFLAGS and LDLIBS) after those variables are set by the configure script.
ENV_CXXFLAGS=$CXXFLAGS
ENV_LDFLAGS=$LDFLAGS
ENV_LDLIBS=$LDLIBS

# Default configuration
debug_level=1
double_precision=false
dynamic_kaldi=false
use_cuda=true
with_cudadecoder=true
static_fst=false
static_math=false
static_speex=false
android=false
enable_kenlm=false
enable_tcmalloc=false

FSTROOT=`rel2abs ../tools/openfst`
CUBROOT=`rel2abs ../tools/cub`

# Save the command line to include in kaldi.mk
cmd_line="$0 $@"

while [ $# -gt 0 ];
do
  case "$1" in
  --help)
    usage; exit 0 ;;
  --version)
    echo $CONFIGURE_VERSION; exit 0 ;;
  --static)
    dynamic_kaldi=false;
    static_math=true;
    static_fst=true;
    static_speex=true;
    shift ;;
  --shared)
    dynamic_kaldi=true;
    static_math=false;
    static_fst=false;
    static_speex=false;
    shift ;;
  --debug-level=*)
    GetSwitchValueOrDie debug_level "$1"
    shift ;;
  --double-precision)
    double_precision=true;
    shift ;;
  --double-precision=yes)
    double_precision=true;
    shift ;;
  --double-precision=no)
    double_precision=false;
    shift ;;
  --atlas-root=*)
    GetSwitchExistingPathOrDie ATLASROOT "$1"
    shift ;;
  --use-cuda)
    use_cuda=true;
    shift ;;
  --use-cuda=yes)
    use_cuda=true;
    shift ;;
  --use-cuda=no)
    use_cuda=false;
    shift ;;
  --with-cudadecoder)
    with_cudadecoder=true;
    shift ;;
  --with-cudadecoder=yes)
    with_cudadecoder=true;
    shift ;;
  --with-cudadecoder=no)
    with_cudadecoder=false;
    shift ;;
  --static-math)
    static_math=true;
    shift ;;
  --static-math=yes)
    static_math=true;
    shift ;;
  --static-math=no)
    static_math=false;
    shift ;;
  --static-fst)
    static_fst=true;
    shift ;;
  --static-fst=yes)
    static_fst=true;
    shift ;;
  --static-fst=no)
    static_fst=false;
    shift ;;
  --static-speex)
    static_speex=true;
    shift ;;
  --static-speex=yes)
    static_speex=true;
    shift ;;
  --static-speex=no)
    static_speex=false;
    shift ;;
  --fst-root=*)
    GetSwitchExistingPathOrDie FSTROOT "$1"
    shift ;;
  --cub-root=*)
    GetSwitchExistingPathOrDie CUBROOT "$1"
    shift ;;
  --clapack-root=*)
    GetSwitchExistingPathOrDie CLAPACKROOT "$1"
    shift ;;
  --openblas-root=*)
    GetSwitchExistingPathOrDie OPENBLASROOT "$1"
    shift ;;
  --mkl-root=*)
    GetSwitchExistingPathOrDie MKLROOT "$1"
    shift ;;
  --mkl-libdir=*)
    GetSwitchExistingPathOrDie MKLLIBDIR "$1"
    shift ;;
  --speex-root=*)
    GetSwitchExistingPathOrDie SPEEXROOT "$1"
    shift ;;
  --speex-libdir=*)
    GetSwitchExistingPathOrDie SPEEXLIBDIR "$1"
    shift ;;
  --speex-incdir=*)
    GetSwitchExistingPathOrDie SPEEXINCDIR "$1"
    shift ;;
  --omp-libdir=*)
    GetSwitchExistingPathOrDie OMPLIBDIR "$1"
    shift ;;
  --mathlib=*)
    GetSwitchValueOrDie MATHLIB "$1"
    shift ;;
  --cudatk-dir=*)
    # CUDA is used in src/cudamatrix and src/nnet{,bin} only.
    GetSwitchExistingPathOrDie CUDATKDIR "$1"
    shift ;;
  --cuda-arch=*)
    GetSwitchValueOrDie CUDA_ARCH "$1"
    shift ;;
  --fst-version=*)
    GetSwitchValueOrDie OPENFST_VER "$1"
    shift ;;
  --host=*)
    # The type of system where built programs and libraries will run.
    # It should be in the format cpu-vendor-os. If specified, this script
    # will infer the target architecture from the specified host triple.
    GetSwitchValueOrDie HOST "$1"
    shift ;;
  --android-incdir=*)
    android=true
    static_math=true
    static_fst=true
    dynamic_kaldi=false
    MATHLIB='OPENBLAS'
    GetSwitchExistingPathOrDie ANDROIDINC "$1"
    shift ;;
  --enable-kenlm)
    enable_kenlm=true
    shift ;;
  --enable-tcmalloc)
    enable_tcmalloc=true
    shift ;;
  *)  echo "Unknown argument: $1, exiting"; usage; exit 1 ;;
  esac
done

case "$debug_level" in
  [012]) ;;
  *) failure "Invalid value --debug-level=$debug_level. Supported values are 0, 1, and 2." ;;
esac

# The idea here is that if you change the configuration options from using
# CUDA to not using it, or vice versa, we want to recompile all parts of the
# code that may use a GPU. Touching this file is a way to force this.
touch cudamatrix/cu-common.h 2>/dev/null

if $android && [[ "$CXX" != *clang++*  ]] ; then
  failure "Android build requires clang++. Make sure you have clang++ installed
  on your system and then override the default compiler by setting CXX, e.g.
  CXX=clang++ ./configure"
fi

# If HOST is set
# - If it is not equal to WASM
#   1. We prepend it to CXX, AR, AS and RANLIB.
#   2. We parse the target architecture from the HOST triple.
# - Otherwise we take its value as the target architecture
# Otherwise we set the target architecture to the output of `uname -m`.
if is_set $HOST; then
  # The host triple will be something like "armv8-rpi3-linux-gnueabihf". We
  # need the first field which is the target architecture for this build. The
  # following command will take the host triple "armv8-rpi3-linux-gnueabihf"
  # and return ["armv8", "rpi3", "linux", "gnueabihf"] in PARTS.
  IFS='-' read -ra PARTS <<< "$HOST"

  if [[ "$HOST" != WASM ]]; then
    # The first field in the PARTS list is the target architecture.
    TARGET_ARCH="$PARTS"
    if [[ "$TARGET_ARCH" != aarch64* && "$TARGET_ARCH" != arm* && "$TARGET_ARCH" != ppc64le && \
          "$TARGET_ARCH" != x86* && "$TARGET_ARCH" != i686* ]] ; then
      # We currently only support building for x86[_64], arm*, aarch64* and ppc64le.
      # If TARGET_ARCH was read from the HOST variable, it must be one of these.
      failure "$TARGET_ARCH is not a supported architecture.
      Supported architectures: x86[_64], arm*, aarch64*, ppc64le."
    fi
  else
    TARGET_ARCH="$HOST"
  fi

  HOST_CXX="$HOST-c++"
  HOST_AR="$HOST-ar"
  HOST_AS="$HOST-as"
  HOST_RANLIB="$HOST-ranlib"
else
  TARGET_ARCH="`uname -m`"
  HOST_CXX=c++
  HOST_AR=ar
  HOST_AS=as
  HOST_RANLIB=ranlib
fi

# These environment variables can be used to override the default toolchain.
CXX=${CXX:-$HOST_CXX}
AR=${AR:-$HOST_AR}
AS=${AS:-$HOST_AS}
RANLIB=${RANLIB:-$HOST_RANLIB}

#------------------------------------------------------------------------------
# Matrix algebra library selection and validation.
#--------------

declare -a mathlibs   # Contains e. g. 'atlas', 'mkl'
declare -a incompat   # Contains mutually-inconsistent switches, if any.
auto_lib=             # Deduced lib name, used when $MATHLIB is not set.

# Validate the (optionally) provided MATHLIB value.
case $MATHLIB in
  ''|ATLAS|CLAPACK|MKL|OPENBLAS|OPENBLAS_CLAPACK) : ;;
  *) failure "Unknown --mathlib='${MATHLIB}'. Supported libs: ATLAS CLAPACK MKL OPENBLAS" ;;
esac

# See which library-root switches are set, what mathlib they imply, and whether
# there are any conflicts betweeh the switches.
[[ $MKLLIBDIR || $MKLROOT ]] && { mathlibs+=(mkl); auto_lib=MKL; }
[[ $CLAPACKROOT  ]] && { mathlibs+=(clapack); auto_lib=CLAPACK; }
[[ $OPENBLASROOT ]] && { mathlibs+=(openblas); auto_lib=OPENBLAS; }
[[ $ATLASROOT    ]] && { mathlibs+=(atlas); auto_lib=ATLAS; }

# When --mathlib= is explicitly provided, and some mathlib(s) deduced, but
# MATHLIB is not among them, record a conflict for the --mathlib= value.
shopt -s nocasematch
[[ $MATHLIB && $mathlibs && ! " ${mathlibs[@]} " =~ " $MATHLIB " ]] &&
  incompat+=(--mathlib=$MATHLIB)
shopt -u nocasematch

# If more than one library specified, or a conflict has been recorded above
# already, then add all deduced libraries as conflicting options (not all may
# be conflicting sensu stricto, but let the user deal with it).
if [[ ${#mathlibs[@]} -gt 1 || $incompat ]]; then
  for libpfx in "${mathlibs[@]}"; do
    # Handle --mkl-libdir out of common pattern.
    [[ $libpfx == mkl && $MKLLIBDIR ]] && incompat+=(--mkl-libdir=)
    # All other switches follow the pattern --$libpfx-root.
    incompat+=(--$(lcase $libpfx)-root=)
  done
  failure "Incompatible configuration switches: ${incompat[@]}"
fi

# When no library roots were provided, so that auto_lib is not deduced, and
# MATHLIB is also not explicitly provided by the user, then default to MKL.
[[ ! $auto_lib && ! $MATHLIB ]] &&
  case $TARGET_ARCH in
    x86_64) auto_lib=MKL ;;
    *) auto_lib=OPENBLAS ;;
  esac
: ${MATHLIB:=$auto_lib}

# Define default library roots where known (others may be found by probing).
case $MATHLIB in
  MKL) [[ ! $MKLLIBDIR && ! $MKLROOT ]] && MKLROOT=/opt/intel/mkl ;;
  ATLAS) : ${ATLASROOT:=$(rel2abs ../tools/ATLAS_headers/)} ;;
esac

unset auto_lib incompat libpfx mathlibs

echo "Configuring KALDI to use ${MATHLIB}."

# Back up the old kaldi.mk in case we modified it
if [ -f kaldi.mk ]; then
  echo "Backing up kaldi.mk to kaldi.mk.bak ..."
  cp kaldi.mk kaldi.mk.bak
fi

# Generate the new kaldi.mk file
echo "# This file was generated using the following command:" > kaldi.mk
echo "# $cmd_line" >> kaldi.mk
echo >> kaldi.mk
echo "CONFIGURE_VERSION := $CONFIGURE_VERSION" >> kaldi.mk
echo >> kaldi.mk

echo "# Toolchain configuration" >> kaldi.mk
echo >> kaldi.mk
echo "CXX = $CXX" >> kaldi.mk
echo "AR = $AR" >> kaldi.mk
echo "AS = $AS" >> kaldi.mk
echo "RANLIB = $RANLIB" >> kaldi.mk
echo >> kaldi.mk

echo "Checking compiler $CXX ..."
check_compiler $CXX

echo "# Target achitecture" >> kaldi.mk
echo "ARCH = $TARGET_ARCH" >> kaldi.mk
echo >> kaldi.mk

echo "# Base configuration" >> kaldi.mk
echo >> kaldi.mk
if $dynamic_kaldi ; then
  KALDILIBDIR=`pwd`/lib
  echo "KALDI_FLAVOR := dynamic" >> kaldi.mk
  echo "KALDILIBDIR := $KALDILIBDIR" >> kaldi.mk
fi
echo "DEBUG_LEVEL = $debug_level" >> kaldi.mk
if $double_precision; then
  echo "DOUBLE_PRECISION = 1" >> kaldi.mk
else
  echo "DOUBLE_PRECISION = 0" >> kaldi.mk
fi
echo "Checking OpenFst library in $FSTROOT ..."
if [ ! -f $FSTROOT/include/fst/fst.h  ]; then
  failure "Could not find file $FSTROOT/include/fst/fst.h:
  you may not have installed OpenFst. See ../tools/INSTALL"
fi
OPENFST_VER=${OPENFST_VER:-$(grep 'PACKAGE_VERSION' $FSTROOT/Makefile | sed -e 's:.*= ::')}
OPENFST_VER_NUM=$(echo $OPENFST_VER | sed 's/\./ /g' | xargs printf "%d%02d%02d")
if [ $OPENFST_VER_NUM -lt 10600 ]; then
  failure "OpenFst-$OPENFST_VER is not supported. You need OpenFst >= 1.6.0.)"
fi
echo "OPENFSTINC = $FSTROOT/include" >> kaldi.mk
if $static_fst ; then
  OPENFSTLIBS="$FSTROOT/lib/libfst.a"
else
  if [ "`uname`" == "Darwin"  ]; then
    OPENFSTLIBS="$FSTROOT/lib/libfst.dylib"
    OPENFSTLDFLAGS="-Wl,-rpath -Wl,${FSTROOT}/lib"
  elif [ "`uname`" == "Linux" -o "`uname`" == "FreeBSD" ]; then
    OPENFSTLIBS="$FSTROOT/lib/libfst.so"
    OPENFSTLDFLAGS="-Wl,-rpath=${FSTROOT}/lib"
  else
    failure "Dynamic libraries are not supported on this platform.
             Run configure with --static --static-fst flag."
  fi
fi
if [ ! -f "$OPENFSTLIBS" ]; then
  failure "Static=[$static_fst] OpenFST library not found:  See ../tools/INSTALL"
fi
echo "OPENFSTLIBS = $OPENFSTLIBS" >> kaldi.mk
echo "OPENFSTLDFLAGS = $OPENFSTLDFLAGS" >> kaldi.mk
echo >> kaldi.mk

if $use_cuda; then
   echo "Checking cub library in $CUBROOT ..."
   if [[ ! -f $CUBROOT/cub/cub.cuh ]]; then
     failure "Could not find file $CUBROOT/cub/cub.cuh:
  you may not have installed cub.  Go to ../tools/ and type
  'make cub' to download and unpack it. We'll detect it then."
   else
     echo "CUBROOT = $CUBROOT" >> kaldi.mk
   fi
   echo "WITH_CUDADECODER = $with_cudadecoder" >> kaldi.mk
else
   echo "WITH_CUDADECODER = false" >> kaldi.mk
fi
echo >> kaldi.mk

if $enable_kenlm ; then
  if [ -d ../tools/kenlm ]; then
    KENLM_ROOT=$(rel2abs ../tools/kenlm)
    echo "Checking kenlm library in $KENLM_ROOT"
    if [ -f $KENLM_ROOT/libkenlm.so ]; then
      if [ "$(uname)" == "Linux" ]; then
        echo "KENLM_ROOT = $KENLM_ROOT" >> kaldi.mk
        echo "KENLM_CXXFLAGS = -DHAVE_KENLM  -DKENLM_MAX_ORDER=6  -I$KENLM_ROOT" >> kaldi.mk
        echo "KENLM_LDFLAGS = -Wl,-rpath=$KENLM_ROOT  -L$KENLM_ROOT" >> kaldi.mk
        echo "KENLM_LDLIBS = -lkenlm" >> kaldi.mk
      else
        failure "Sorry, for now --enable-kenlm option is only supported for Linux"
      fi
    else
      failure "can't find libkenlm.so in ../tools/kenlm/,
              refer to ../tools/extras/install_kenlm_query_only.sh for instruction."
    fi
  else
    failure "--enable-kenlm switched on, but can't find kenlm repo in ../tools/kenlm,
            refer to ../tools/extras/install_kenlm_query_only.sh for instruction."
  fi
fi

# OS-specific steps given below append to kaldi.mk
echo "Performing OS specific configuration ..."

if $android ; then
  if [ -z $ANDROIDINC ] ;  then
    failure "--android-incdir must be specified for android builds."
  fi

  if ! is_set $HOST; then
    failure "HOST must be specified for android builds."
  fi

  OPENBLASROOT=`rel2abs "$OPENBLASROOT"`
  if [ -z "$OPENBLASROOT" ]; then
    failure "The location of OPENBLAS must be specified for android builds
             using --openblas-root (and it must exist)"
  fi
  if [ ! -f $OPENBLASROOT/lib/libopenblas.a ]; then
    failure "Expected to find the file $OPENBLASROOT/lib/libopenblas.a"
  fi
  echo "Using OpenBLAS as the linear algebra library."

  OPENBLASLIBS="$OPENBLASROOT/lib/libopenblas.a $OPENBLASROOT/lib/libclapack.a $OPENBLASROOT/lib/liblapack.a $OPENBLASROOT/lib/libblas.a $OPENBLASROOT/lib/libf2c.a"
  echo "OPENBLASINC = $OPENBLASROOT/include" >> kaldi.mk
  echo "OPENBLASLIBS = $OPENBLASLIBS" >> kaldi.mk
  echo "ANDROIDINC = $ANDROIDINC" >> kaldi.mk

  cat makefiles/android_openblas.mk >> kaldi.mk

  echo "Successfully configured for Android with OpenBLAS from $OPENBLASROOT."

elif [ "`uname`" == "Darwin" ]; then
  # Check for Darwin first, because we later call uname -o (for Cygwin)
  # which crashes on Darwin.

  echo "On Darwin: Checking for Accelerate framework ..."
  if [ ! -e /System/Library/Frameworks/Accelerate.framework ]; then
    failure "Need the Accelerate framework to compile on Darwin."
  fi
  OSX_VER=$(sw_vers | grep ProductVersion | awk '{print $2}' | awk '{split($0,a,"."); print a[1] "." a[2]; }')
  OSX_VER_NUM=$(echo $OSX_VER | sed 's/\./ /g' | xargs printf "%d%02d")
  echo "Configuring for OS X version $OSX_VER ..."
  if [ $OSX_VER_NUM -ge 1005 ]; then
    if [ "$MATHLIB" == "CLAPACK" ]; then
      if [ -z "$CLAPACKROOT" ]; then
          failure "Must specify the location of CLAPACK with --clapack-root option (and it must exist)"
      fi
      if [ ! -f ../tools/CLAPACK/clapack.h ]; then
          failure "could not find file ../tools/CLAPACK/clapack.h"
      fi
      if [ ! -d "$CLAPACKROOT" ]; then
          failure "The directory $CLAPACKROOT does not exist"
      fi
      # Also check for cblas.h and f2c.h
      echo "Using CLAPACK libs from $CLAPACKROOT as the linear algebra library."
      echo "CLAPACKROOT = $CLAPACKROOT" >> kaldi.mk
      if [ ! -f makefiles/darwin_clapack.mk ]; then
          failure "makefiles/darwin_clapack.mk not found."
      fi
      cat makefiles/darwin_clapack.mk >> kaldi.mk
      echo "Warning (CLAPACK): this part of the configure process is not properly tested and may not work."
      echo "Successfully configured for Darwin with CLAPACK libs from $CLAPACKROOT"
    else
      cat makefiles/darwin.mk >> kaldi.mk
    fi
  else
    failure "Mac OS X version '$OSX_VER' is not supported."
  fi

  if [ $OSX_VER_NUM == 1011 ]; then
    echo "**BAD WARNING**: You are using OS X El Capitan.  Some versions of this OS"
    echo "**BAD WARNING**: have a bug in the BLAS implementation that affects Kaldi."
    echo "**BAD WARNING**: After compiling, cd to matrix/ and type 'make test'.  The"
    echo "**BAD WARNING**: test will fail if the problem exists in your version. "
    echo "**BAD WARNING**: Eventually this issue will be fixed by system updates from"
    echo "**BAD WARNING**: Apple.  Unexplained crashes with reports of NaNs will"
    echo "**BAD WARNING**: be caused by this bug, but some recipes will (sometimes) work."
    sleep 1; echo -n .; sleep 1; echo -n .; sleep 1; echo .
  fi
  echo "Successfully configured for Darwin with Accelerate framework."
  $use_cuda && configure_cuda

elif [ "`uname -o`" == "Cygwin"  ]; then
  echo "On Cygwin: Checking for linear algebra libraries ..."
  if [ ! -f ../tools/CLAPACK/clapack.h ]; then
      failure "could not find file ../tools/CLAPACK/clapack.h"
  fi
  if [ ! -f /usr/lib/lapack/cygblas-0.dll ]; then
     failure "please first install package liblapack0"
  fi
  cat makefiles/cygwin.mk >> kaldi.mk
  echo "Successfully configured for Cygwin with CLAPACK."

elif [ "`uname`" == "Linux" -o "`uname`" == "FreeBSD"  ]; then
  echo "On Linux: Checking for linear algebra header files ..."
  if [ "$MATHLIB" == "ATLAS" ]; then
    if [ ! -f $ATLASROOT/include/cblas.h ] || [ ! -f $ATLASROOT/include/clapack.h ] ; then
      failure "Could not find required header files cblas.h or clapack.h in ATLAS dir '$ATLASROOT/include'"
    fi
    echo "Using ATLAS as the linear algebra library."

    # Finding out where the libraries are located:
    # First we look for the static libraries and then look for dynamic ones.
    # We're looking for four libraries, all in the same directory, named
    # libcblas.a, libatlas.a, libf77blas.a, and a library that's variously
    # named liblapack.a, libclapack.a, or liblapack_atlas.a, but which exports
    # the symbol ATL_cgetrf.
    # Note: there is a different type of ATLAS installation that is not
    # covered.  We saw a case where there was a directory called /usr/lib/atlas
    # containing {liblapack.a,libblas.a}, and linking against just these two
    # libraries worked.

    ( $static_math && linux_configure_atlas_static ) || \
      linux_configure_atlas_generic /usr/lib "so.3" || \
      linux_configure_atlas_generic /usr/lib/atlas-base "so.3gf" || \
      linux_configure_atlas_generic /usr/lib64/atlas-base "so.3gf" \
      linux_configure_atlas_generic /usr/lib/atlas "so.3" || \
      linux_configure_atlas_generic /usr/lib64/atlas "so.3" || \
      linux_configure_atlas_generic /usr/lib/x86_64-linux-gnu/ "so.3" || \
      linux_configure_atlas_generic /usr/lib/x86_64-linux-gnu/ "so" || \
      linux_configure_atlas_redhat_fat 64 || \
      linux_configure_atlas_redhat_fat || \
      linux_configure_atlas_static || \
      linux_configure_atlas_failure "Failed to configure ATLAS libraries";

    case $TARGET_ARCH in
      arm*)    cat makefiles/linux_atlas_arm.mk ;;
      ppc64le) cat makefiles/linux_atlas_ppc64le.mk ;;
      *)       cat makefiles/linux_atlas.mk ;;
    esac >> kaldi.mk

  elif [[ $MATHLIB = MKL ]]; then
    if [[ $TARGET_ARCH != x86_64 ]]; then
      failure "MKL on Linux is only supported for Intel 64-bit (x86_64) arch.
 ... See makefiles/linux_64_mkl.mk to manually configure for other platforms."
    fi

    # Ubuntu 20+ supplies these packages.
    if $static_math; then
      mkl_sys_package=mkl-static-lp64-seq
    else
      mkl_sys_package=mkl-dynamic-lp64-seq
    fi

    if [[ ! $MKLLIBDIR ]]; then
      echo -n "Configuring MKL library directory: "
      MKLLIBDIR=$(
        if [[ -d $MKLROOT/lib/intel64 ]]; then
          echo "$MKLROOT/lib/intel64"
        elif [[ -d $MKLROOT/lib ]]; then
          echo "$MKLROOT/lib"
        elif pkg-config $mkl_sys_package --exists &>/dev/null; then
          MKLROOT=
          # Return empty path to indicate a system package.
        else
          failure "Could not find the MKL library directory.
Please use the switch --mkl-root and/or --mkl-libdir if you have MKL installed,
or try another math library, e.g. --mathlib=OPENBLAS (Kaldi may be slower)."
        fi) || exit
      echo "Found ${MKLLIBDIR:-system package $mkl_sys_package}"
    fi

    # MKL libraries.
    MKL_LDLIBS=$(
      # If $MKLLIBDIR is empty, we found the package through pkg-config.
      [[ $MKLLIBDIR ]] || { pkg-config $mkl_sys_package --libs; exit; }

      readonly mkl_libs=(mkl_intel_lp64 mkl_core mkl_sequential)

      if $static_math ; then
        suffix=a link_pre="-Wl,--start-group" link_post=" -Wl,--end-group"
      else
        suffix=so link_pre="-Wl,-rpath=$MKLLIBDIR" link_post=
      fi

      linkline="-L$MKLLIBDIR $link_pre"
      for file in ${mkl_libs[@]}; do
        file=lib$file.$suffix
        check_exists $MKLLIBDIR/$file
        linkline+=" -l:$file"
      done
      linkline+=$link_post

      echo "$linkline -ldl -lpthread -lm") || exit
    echo "MKL libs MKL_LDLIBS = $MKL_LDLIBS."

    # MKL includes.
    MKL_CXXFLAGS=$(
      # If $MKLLIBDIR is empty, we found the package through pkg-config.
      if [[ ! $MKLLIBDIR ]]; then
        pkg-config $mkl_sys_package --cflags
      elif [[ -d $MKLROOT/include ]]; then
        echo "-I$MKLROOT/include"
      elif [[ -d $MKLLIBDIR/../../include ]]; then
        echo "-I$MKLLIBDIR/../../include"
      else
        failure "Could not guess the MKL include directory."
      fi) || exit
    echo "MKL compile flags MKL_CXXFLAGS = $MKL_CXXFLAGS."

    echo "*** MKL self-reported version:"
    ( cd probe
      rm -f mkl-test
      g++ mkl-test.cc -o mkl-test $MKL_CXXFLAGS $MKL_LDLIBS &&
        ./mkl-test
    ) || failure "MKL did not pass a simple compile test."

    echo "MKL_CXXFLAGS = $MKL_CXXFLAGS" >> kaldi.mk
    echo "MKL_LDLIBS = $MKL_LDLIBS" >> kaldi.mk
    echo >> kaldi.mk
    check_exists makefiles/linux_x86_64_mkl.mk
    cat makefiles/linux_x86_64_mkl.mk >> kaldi.mk
    echo "Successfully configured for Linux with MKL libraries found in" \
         "${MKLROOT:-distro package}"

  elif [ "$MATHLIB" == "CLAPACK" ]; then
    if [ -z "$CLAPACKROOT" ]; then
      failure "Must specify the location of CLAPACK with --clapack-root option (and it must exist)"
    fi
    if [ ! -f ../tools/CLAPACK/clapack.h ]; then
      failure "could not find file ../tools/CLAPACK/clapack.h"
    fi
    if [ ! -d "$CLAPACKROOT" ]; then
      failure "The directory $CLAPACKROOT does not exist"
    fi
    # Also check for cblas.h and f2c.h
    echo "Using CLAPACK libs from $CLAPACKROOT as the linear algebra library."
    if [ ! -f makefiles/linux_clapack.mk ]; then
      failure "makefiles/linux_clapack.mk not found."
    fi
    if [[ "$TARGET_ARCH" == arm* ]]; then
      cat makefiles/linux_clapack_arm.mk >> kaldi.mk
    else
      echo "CLAPACKROOT = $CLAPACKROOT" >> kaldi.mk
      cat makefiles/linux_clapack.mk >> kaldi.mk
    fi
    echo "Warning (CLAPACK): this part of the configure process is not properly tested and may not work."
    echo "Successfully configured for Linux with CLAPACK libs from $CLAPACKROOT"

  elif [ "$MATHLIB" == "OPENBLAS" ]; then
    if [[ ! $OPENBLASROOT ]]; then
      # Either the user specified --mathlib=OPENBLAS or we've autodetected the
      # system where OpenBLAS is the preferred option (the parser for
      # --openblas-root fails fatally if the path does not exist, so we trust
      # that if set, the variable contains the existing path, converted to
      # absolute form).
      OPENBLASROOT="$(rel2abs ../tools/OpenBLAS/install)" ||
        Die "OpenBLAS not found in '../tools/OpenBLAS/install'.
** This is the only place we look for it. The best option is to build OpenBLAS
** tuned for your system and CPU. To do that, run the following commands:
**
**   cd ../tools; extras/install_openblas.sh
**
** Another option is to specify the location of existing OpenBLAS directory
** with the switch '--openblas-root='. However, even if a package is provided
** for your system, the packaged version is almost always significantly slower
** and often older than the above commands can fetch and build.
**
** You can also use other matrix algebra libraries. For information, see:
**   http://kaldi-asr.org/doc/matrixwrap.html"
    fi
    if [ -f $OPENBLASROOT/lib/libopenblas.so ]; then
      OPENBLASLIBDIR=$OPENBLASROOT/lib
    elif [ -f $OPENBLASROOT/lib64/libopenblas.so ]; then
      # in REDHAT/CentOS package installs, the library is located here
      OPENBLASLIBDIR=$OPENBLASROOT/lib64
    else
      failure "Expected to find the file $OPENBLASROOT/lib/libopenblas.so"
    fi
    if [ -f $OPENBLASROOT/include/cblas.h ] ; then
      OPENBLASINCDIR=$OPENBLASROOT/include
    elif [ -f $OPENBLASROOT/include/openblas/cblas.h ] ; then
      # in REDHAT/CentOS/Ubuntu package installs, the includes are located here
      OPENBLASINCDIR=$OPENBLASROOT/include/openblas
    else
      echo "$0: ***** Using OpenBLAS from $OPENBLASROOT but cblas.h is not found. "
      echo "** Assuming openblas is aleady in a default include path, but"
      echo "** if you get compilation messages about not finding files like cblas.h,"
      echo "** you should look into this (e.g. make sure to install the 'openblas-dev' package,"
      echo "** if it is a package-based install)."
      OPENBLASINCDIR="/usr/include"
    fi
    echo "Your math library seems to be OpenBLAS from $OPENBLASROOT.  Configuring appropriately."
    # TODO(kkm): Probably, OpenBLAS required libgfortran.so.3 at some point, but
    # no longer does. *My* linker does not complain about a missing library, but
    # is it safe to keep the reference if no longer required? Try to figure out
    # how long ago the dependency was dropped.
    if $static_math; then
      echo "Configuring static OpenBlas since --static-math=yes"
      OPENBLASLIBS="-L$OPENBLASLIBDIR -l:libopenblas.a -lgfortran"
    else
      echo "Configuring dynamically loaded OpenBlas since --static-math=no (the default)"
      OPENBLASLIBS="-L$OPENBLASLIBDIR -lopenblas -lgfortran -Wl,-rpath=$OPENBLASLIBDIR"
    fi
    echo "OPENBLASINC = $OPENBLASINCDIR" >> kaldi.mk
    echo "OPENBLASLIBS = $OPENBLASLIBS" >> kaldi.mk
    echo >> kaldi.mk
    case $TARGET_ARCH in
      aarch64*) cat makefiles/linux_openblas_aarch64.mk ;;
      arm*)     cat makefiles/linux_openblas_arm.mk ;;
      ppc64le)  cat makefiles/linux_openblas_ppc64le.mk ;;
      riscv64)  cat makefiles/linux_openblas_riscv64.mk ;;
      *)        cat makefiles/linux_openblas.mk ;;
    esac >> kaldi.mk

    echo "Successfully configured for Linux with OpenBLAS from $OPENBLASROOT"
  elif [ "$MATHLIB" == "OPENBLAS_CLAPACK" ]; then
    if [[ ! $OPENBLASROOT ]]; then
      # Either the user specified --mathlib=OPENBLAS or we've autodetected the
      # system where OpenBLAS is the preferred option (the parser for
      # --openblas-root fails fatally if the path does not exist, so we trust
      # that if set, the variable contains the existing path, converted to
      # absolute form).
      OPENBLASROOT="$(rel2abs ../tools/OpenBLAS/install)" ||
        Die "OpenBLAS not found in '../tools/OpenBLAS/install'.
** This is the only place we look for it. The best option is to build OpenBLAS
** tuned for your system and CPU. To do that, run the following commands:
**
**   cd ../tools; extras/install_openblas.sh
**
** Another option is to specify the location of existing OpenBLAS directory
** with the switch '--openblas-root='. However, even if a package is provided
** for your system, the packaged version is almost always significantly slower
** and often older than the above commands can fetch and build.
**
** You can also use other matrix algebra libraries. For information, see:
**   http://kaldi-asr.org/doc/matrixwrap.html"
    fi
    if [ -f $OPENBLASROOT/lib/libopenblas.so ]; then
      OPENBLASLIBDIR=$OPENBLASROOT/lib
    elif [ -f $OPENBLASROOT/lib64/libopenblas.so ]; then
      # in REDHAT/CentOS package installs, the library is located here
      OPENBLASLIBDIR=$OPENBLASROOT/lib64
    else
      failure "Expected to find the file $OPENBLASROOT/lib/libopenblas.so"
    fi
    if [ -f $OPENBLASROOT/include/cblas.h ] ; then
      OPENBLASINCDIR=$OPENBLASROOT/include
    elif [ -f $OPENBLASROOT/include/openblas/cblas.h ] ; then
      # in REDHAT/CentOS/Ubuntu package installs, the includes are located here
      OPENBLASINCDIR=$OPENBLASROOT/include/openblas
    else
      echo "$0: ***** Using OpenBLAS from $OPENBLASROOT but cblas.h is not found. "
      echo "** Assuming openblas is aleady in a default include path, but"
      echo "** if you get compilation messages about not finding files like cblas.h,"
      echo "** you should look into this (e.g. make sure to install the 'openblas-dev' package,"
      echo "** if it is a package-based install)."
      OPENBLASINCDIR="/usr/include"
    fi
    echo "Your math library seems to be OpenBLAS from $OPENBLASROOT.  Configuring appropriately."
    OPENBLASLIBS="-L$OPENBLASLIBDIR -l:libopenblas.a -l:libblas.a -l:liblapack.a -l:libf2c.a"
    echo "OPENBLASINC = $OPENBLASINCDIR" >> kaldi.mk
    echo "OPENBLASLIBS = $OPENBLASLIBS" >> kaldi.mk
    echo >> kaldi.mk
    case $TARGET_ARCH in
      aarch64*) cat makefiles/linux_openblas_aarch64.mk ;;
      arm*)     cat makefiles/linux_openblas_arm.mk ;;
      ppc64le)  cat makefiles/linux_openblas_ppc64le.mk ;;
      riscv64)  cat makefiles/linux_openblas_riscv64.mk ;;
      *)        cat makefiles/linux_openblas.mk ;;
    esac >> kaldi.mk

    echo >> kaldi.mk
    echo "CXXFLAGS += -DUSE_KALDI_SVD" >> kaldi.mk

    echo "Successfully configured for Linux with OpenBLAS from $OPENBLASROOT"
  else
    failure "Unsupported linear algebra library '$MATHLIB'"
  fi
  $use_cuda && configure_cuda
  linux_configure_speex
else
  failure "Could not detect the platform or we have not yet worked out the
  appropriate configuration for this platform. Please contact the developers."
fi

if $enable_tcmalloc ; then
  if [ -f ../tools/gperftools/lib/libtcmalloc_minimal.so ]; then
    TCMALLOC_ROOT=$(rel2abs ../tools/gperftools)
    echo "Configuring tcmalloc since --enable-tcmalloc"
    if [ "$(uname)" == "Linux" ]; then
      echo "LDLIBS += -Wl,-rpath=$TCMALLOC_ROOT/lib -L$TCMALLOC_ROOT/lib -ltcmalloc_minimal" >> kaldi.mk
    else
      failure "Now, --enable-tcmalloc option is only supported for Linux"
    fi
    echo "Successfully configured tcmalloc for Linux from $TCMALLOC_ROOT"
  else
    failure "Can't find tcmalloc in tools/gperftools. Run" \
            "'extras/install_tcmalloc.sh' in 'tools/' to install."
  fi
fi

# Append the flags set by environment variables last so they can be used
# to override the automatically generated configuration.
echo >> kaldi.mk
echo "# Environment configuration" >> kaldi.mk
echo >> kaldi.mk
if [ -n "$ENV_CXXFLAGS" ]; then echo "CXXFLAGS += $ENV_CXXFLAGS" >> kaldi.mk; fi
if [ -n "$ENV_LDFLAGS" ]; then echo "LDFLAGS += $ENV_LDFLAGS" >> kaldi.mk; fi
if [ -n "$ENV_LDLIBS" ]; then echo "LDLIBS += $ENV_LDLIBS" >> kaldi.mk; fi

# We check for slow exp implementation just before we exit. This check uses
# and possibly modifies the kaldi.mk file that we just generated.
check_for_slow_expf;
echo "Kaldi has been successfully configured. To compile:

  make -j clean depend; make -j <NCPU>

where <NCPU> is the number of parallel builds you can afford to do. If unsure,
use the smaller of the number of CPUs or the amount of RAM in GB divided by 2,
to stay within safe limits. 'make -j' without the numeric value may not limit
the number of parallel jobs at all, and overwhelm even a powerful workstation,
since Kaldi build is highly parallelized."
exit 0
