#!/usr/bin/env bash
#
#  BLIS    
#  An object-based framework for developing high-performance BLAS-like
#  libraries.
#
#  Copyright (C) 2014, The University of Texas at Austin
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are
#  met:
#   - Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
#   - Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#   - Neither the name of The University of Texas at Austin nor the names
#     of its contributors may be used to endorse or promote products
#     derived from this software without specific prior written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
#  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
#  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
#  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
#  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
#  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#

#
# -- Helper functions ----------------------------------------------------------
#

print_usage()
{
	# Echo usage info.
	echo " "
	echo " ${script_name} (BLIS ${version})"
	#echo " "
	#echo " BLIS ${version}"
	echo " "
	echo " Field G. Van Zee"
	echo " "
	echo " Configure BLIS's build system for compilation using a specified"
	echo " configuration directory."
	echo " "
	echo " Usage:"
	echo " "
	echo "   ${script_name} [options] [env. vars.] confname"
	echo " "
	echo " Arguments:"
	echo " "
	echo "   confname      The name of the sub-directory inside of the 'config'"
	echo "                 directory containing the desired BLIS configuration."
	echo "                 Note that confname MUST be specified; if it is not,"
	echo "                 configure will complain. To build a completely generic"
	echo "                 implementation, use the 'generic' configuration"
	echo " "
	echo " Options:"
	echo " "
	echo "   -p PREFIX, --prefix=PREFIX"
	echo " "
	echo "                 The path to which make will install buid products."
	echo "                 If not given, PREFIX defaults to \$(HOME)/blis. If"
	echo "                 the path refers to a directory that does not exist,"
	echo "                 it will be created."
	echo " "
	echo "   -d DEBUG, --enable-debug[=DEBUG]"
	echo " "
	echo "                 Enable debugging symbols in the library. If argument"
	echo "                 DEBUG is given as 'opt', then optimization flags are"
	echo "                 kept in the framework, otherwise optimization is"
	echo "                 turned off."
	echo " "
	echo "   --enable-verbose-make, --disable-verbose-make"
	echo " "
	echo "                 Enable (disabled by default) verbose compilation"
	echo "                 output during make."
	echo " "
	echo "   --disable-static, --enable-static"
	echo " "
	echo "                 Disable (enabled by default) building BLIS as a static"
	echo "                 library. May be combined with --enable-shared."
	echo " "
	echo "   --enable-shared, --disable-static"
	echo " "
	echo "                 Enable (disabled by default) building BLIS as a shared"
	echo "                 library. May be combined with --enable-static."
	echo " "
	echo "   -t MODEL, --enable-threading[=MODEL], --disable-threading"
	echo " "
	echo "                 Enable threading in the library, using threading model"
	echo "                 MODEL={openmp,pthreads,no}. If MODEL=no or "
	echo "                 --disable-threading is specified, threading will be"
	echo "                 disabled. The default is 'no'."
	echo " "
	echo "   --disable-packbuf-pools, --enable-packbuf-pools"
	echo " "
	echo "                 Disable (enabled by default) use of internal memory"
	echo "                 pools for managing packing buffers. When disabled,"
	echo "                 the function specified by BLIS_MALLOC_POOL is called"
	echo "                 on-demand, whenever a packing buffer is needed, and"
	echo "                 the buffer is released via the function specified by"
	echo "                 BLIS_FREE_POOL() when the loop in which it was"
	echo "                 allocated terminates. When enabled, the memory pools"
	echo "                 minimize calls to both BLIS_MALLOC_POOL() and"
	echo "                 BLIS_FREE_POOL(), especially in a multithreaded"
	echo "                 environment, but does so through a mechanism that may"
	echo "                 incur additional overhead in some (but not all)"
	echo "                 situations."
	echo " "
	echo "   -q, --quiet   Suppress informational output. By default, configure"
	echo "                 is verbose. (NOTE: -q is not yet implemented)"
	echo " "
	echo "   -i SIZE, --int-size=SIZE"
	echo " "
	echo "                 Set the size (in bits) of internal BLIS integers and"
	echo "                 integer types used in native BLIS interfaces. The"
	echo "                 default inteter type size is architecture dependent."
	echo "                 (Hint: You can always find this value printed at the"
	echo "                 beginning of the testsuite output.)"
	echo " "
	echo "   -b SIZE, --blas-int-size=SIZE"
	echo " "
	echo "                 Set the size (in bits) of integer types in external"
	echo "                 BLAS and CBLAS interfaces, if enabled. The default"
	echo "                 integer type size used in BLAS/CBLAS is 32 bits."
	echo " "
	echo "   --disable-blas, --enable-blas"
	echo " "
	echo "                 Disable (enabled by default) building the BLAS"
	echo "                 compatibility layer."
	echo " "
	echo "   --enable-cblas, --disable-cblas"
	echo " "
	echo "                 Enable (disabled by default) building the CBLAS"
	echo "                 compatibility layer. This automatically enables the"
	echo "                 BLAS compatibility layer as well."
	echo " "
	echo "   --force-version=STRING"
	echo " "
	echo "                 Force configure to use an arbitrary version string"
	echo "                 STRING. This option may be useful when repackaging"
	echo "                 custom versions of BLIS by outside organizations."
	echo " "
	echo "   -c, --show-config-lists"
	echo " "
	echo "                 Print the config and kernel lists, and kernel-to-config"
	echo "                 map after they are read from file. This can be useful"
	echo "                 when debugging certain configuration issues, and/or as"
	echo "                 a sanity check to make sure these lists are constituted"
	echo "                 as expected."
	echo " "
	echo "   -h, --help    Output this information and quit."
	echo " "
	echo " Environment Variables:"
	echo " "
	echo "   CC            Specifies the C compiler to use."
	echo " "
	echo "   Environment variables may also be specified as command line"
	echo "   options, e.g.:"
	echo " "
	echo "     ./configure [options] CC=gcc sandybridge"
	echo " "
	echo "   Note that not all compilers are compatible with a given"
	echo "   configuration."
	echo " "

	# Exit with non-zero exit status
	exit 1
}

query_array()
{
	array_name=$1
	key_name=$2

	var_name="${array_name}_${key_name}"

	echo "${!var_name}"
}

read_registry_file()
{
	local cname clist

	filename="$1"
	while read -r line
	do
		curline="${line}"

		#echo "curline: ${curline}"

		# Remove leading whitespace from the current line.
		# NOTE: read -r already prunes leading whitespace
		#curline=$(echo "${curline}" | sed "s/^[ \t]*//")

		# Remove everything after comment character '#'.
		curline=${curline%%#*}

		# We've stripped out leading whitespace and trailing comments. If
		# the line is now empty, then we can skip it altogether.
		if [ "x${curline}" = "x" ]; then
			continue;
		fi

		# Read the config name and config list for the current line.
		cname=${curline%%:*}
		list=${curline##*:}

		# If we encounter a slash, it means the name of the configuration
		# and the kernel set needed by that configuration are different.
		if [[ "${list}" == *[/]* ]]; then

			#echo "Slash found."
			klist=""
			clist=""
			for item in "${list}"; do

				# The sub-configuration name is always the first sub-word in
				# the slash-separated compound word.
				config=${item%%/*}

				# Delete the sub-configuration name from the front of the
				# string, leaving the slash-separated kernel names (or just
				# the kernel name, if there is only one).
				kernels=${list#*/}

				# Replace the slashes with spaces to transform the string
				# into a space-separated list of kernel names.
				kernels=$(echo -e ${kernels} | sed -e "s/\// /g")

				clist="${clist} ${config}"
				klist="${klist} ${kernels}"
			done
		else
			#echo "Slash not found."
			clist=${list}
			klist=${list}
		fi

		# Strip out whitespace from the config name and config/kernel list
		# on each line.
		cname=$(canonicalize_ws "${cname}")
		clist=$(canonicalize_ws "${clist}")
		klist=$(canonicalize_ws "${klist}")

		# Store the config and kernel lists to the entry in the associative
		# arrays that corresponds to the config name.
		#config_registry[${cname}]=${clist}
		#kernel_registry[${cname}]=${klist}
		printf -v "config_registry_${cname}" %s "${clist}"
		printf -v "kernel_registry_${cname}" %s "${klist}"
		

	done < "${filename}"

	# Now go back through the kernel registry and substitute any remaining
	# configuration names occurring in the kernel list (right side of ':')
	# with its registered kernel set.
	#for config in "${!kernel_registry[@]}"; do
	for kr_var in ${!kernel_registry_*}; do

		config=${kr_var##kernel_registry_}

		#for ker in ${kernel_registry[$config]}; do
		for ker in ${!kr_var}; do

			#kers_ker="${kernel_registry[${ker}]}"
			kers_ker=$(query_array "kernel_registry" ${ker})

			# If kers_ker is empty string, then ker was not found as a key
			# in the kernel list associative array. In that case, we continue
			# and will echo an error later in the script.
			if [ "${kers_ker}" == "" ]; then
				#echo "  kernel for ${ker} is empty string! no entry in kernel list."
				continue;
			fi

			# If the current config/kernel (ker) differs from its singleton kernel
			# entry (kers_ker), then that singleton entry was specified to use
			# a different configuration's kernel set. Thus, we need to replace the
			# occurrence in the current config/kernel name with that of the kernel
			# set it needs.
			if [ "${ker}" != "${kers_ker}" ]; then

				#klist="${kernel_registry[$config]}"
				klist=$(query_array "kernel_registry" ${config})

				# Replace the current config with its requisite kernels,
				# canonicalize whitespace, and then remove duplicate kernel
				# set names, if they exist. Finally, update the kernel registry
				# with the new kernel list.
				newklist=$(echo -e "${klist}" | sed -e "s/${ker}/${kers_ker}/g")
				newklist=$(canonicalize_ws "${newklist}")
				newklist=$(rm_duplicate_words "${newklist}")

				#kernel_registry[${config}]=${newklist}
				printf -v "kernel_registry_${config}" %s "${newklist}"
			fi

		done

	done
}

build_kconfig_registry()
{
	familyname="$1"

	#clist="${config_registry[${familyname}]}"
	clist=$(query_array "config_registry" ${familyname})

	for config in ${clist}; do

		#echo "${config}"

		# Look up the kernel for the current sub-configuration.
		#kernels="${kernel_registry[${config}]}"
		kernels=$(query_array "kernel_registry" ${config})

		for kernel in ${kernels}; do

			#echo "  ${kernel}"

			# Add the sub-configuration to the list associated with the
			# kernel.

			# Query the current sub-configs for the current ${kernel}.
			#cur_configs="${kconfig_registry[${kernel}]}"
			cur_configs=$(query_array "kconfig_registry" ${kernel})

			# Add the current sub-configuration to the list of sub-configs
			# we just queried.
			newvalue=$(canonicalize_ws "${cur_configs} ${config}")

			# Update the array.
			#kconfig_registry[${kernel}]="${newvalue}"
			printf -v "kconfig_registry_${kernel}" %s "${newvalue}"

		done
		
	done
}

is_word_in_list()
{
	word="$1"
	list="$2"
	rval="false"

	for item in ${list}; do

		if [ "${item}" == "${word}" ]; then
			rval="true"
			break
		fi
	done

	echo "${rval}"
}

is_singleton()
{
	list="$1"
	rval="false"

	count_str=""
	for item in ${list}; do

		count_str="${count_str}x"
	done

	if [ "${count_str}" == "x" ]; then
		rval="true"
	fi

	echo "${rval}"
}

canonicalize_ws()
{
	local str="$1"

	# Remove leading and trailing whitespace.
	str=$(echo -e "${str}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')

	# Remove duplicate spaces between words.
	str=$(echo -e "${str}" | tr -s " ")

	# Update the input argument.
	echo "${str}"
}

rm_duplicate_words()
{
	str="$1"

	str=$(echo "${str}" | awk '{for (i=1;i<=NF;i++) if (!a[$i]++) printf("%s%s",$i,FS)}{printf("\n")}')

	echo "${str}"
}

select_cc()
{
	local rval found_cc

	se_suf="stderr.txt"

	# Initialize our selected compiler to empty.
	found_cc=""

	# If CC was specified on the configure command line, see if it works.
	if [ -n "${CC}" ]; then

		se_file="cc_${se_suf}"

		# See if CC works and/or is present.
		rval=$(${CC} --version 2> ${se_file})

		if [ -z "$(cat ${se_file})" ]; then
			found_cc=${CC}
		fi

		rm ${se_file}
	fi

	# Now check if gcc works.
	if [ -z "${found_cc}" ]; then

		se_file="gcc_${se_suf}"

		# See if CC works and/or is present.
		rval=$(gcc --version 2> ${se_file})

		if [ -z "$(cat ${se_file})" ]; then
			found_cc=gcc
		fi

		rm ${se_file}
	fi

	# Now check if clang works.
	if [ -z "${found_cc}" ]; then

		se_file="clang_${se_suf}"

		# See if CC works and/or is present.
		rval=$(clang --version 2> ${se_file})

		if [ -z "$(cat ${se_file})" ]; then
			found_cc=clang
		fi

		rm ${se_file}
	fi

	# If neither $CC, nor gcc, nor clang work, then we're probably all dead,
	# so this fallback selection won't matter.
	if [ -z "${found_cc}" ]; then

		found_cc=cc
	fi

	# Return the selected compiler.
	echo "${found_cc}"
}

auto_detect()
{
	local rval autocc config_defines

	# Find a compiler that works.
	autocc=$(select_cc)

	# For debugging: reveal what compiler was chosen for auto-detection.
	#touch "${autocc}.txt"

	# Tweak the flags we use based on the compiler. This is mostly just
	# an opportunity to turn off annoying warnings that some compilers
	# may throw off.
	if [ "${autocc}" == "clang" ]; then
		autoccflags="-Wno-tautological-compare"
	else
		autoccflags=
	fi

	# Locate our source files.
	bli_arch_c="bli_arch.c"
	bli_cpuid_c="bli_cpuid.c"
	main_c="auto_detect.c"

	bli_arch_c_filepath=$(find ${dist_path}/frame -name "${bli_arch_c}")
	bli_cpuid_c_filepath=$(find ${dist_path}/frame -name "${bli_cpuid_c}")
	main_c_filepath=$(find ${dist_path}/build -name "${main_c}")

	# Locate headers needed directly by the above files.
	bli_arch_h="bli_arch.h"
	bli_cpuid_h="bli_cpuid.h"
	bli_typed_h="bli_type_defs.h"

	bli_arch_h_filepath=$(find ${dist_path}/frame -name "${bli_arch_h}")
	bli_cpuid_h_filepath=$(find ${dist_path}/frame -name "${bli_cpuid_h}")
	bli_typed_h_filepath=$(find ${dist_path}/frame -name "${bli_typed_h}")

	bli_arch_h_path=${bli_arch_h_filepath%/${bli_arch_h}}
	bli_cpuid_h_path=${bli_cpuid_h_filepath%/${bli_cpuid_h}}
	bli_typed_h_path=${bli_typed_h_filepath%/${bli_typed_h}}

	# Locate other headers needed by bli_type_defs.h.
	bli_mutex_h="bli_mutex.h"
	bli_malloc_h="bli_malloc.h"

	bli_mutex_h_filepath=$(find ${dist_path}/frame -name "${bli_mutex_h}")
	bli_malloc_h_filepath=$(find ${dist_path}/frame -name "${bli_malloc_h}")

	bli_mutex_h_path=${bli_mutex_h_filepath%/${bli_mutex_h}}
	bli_malloc_h_path=${bli_malloc_h_filepath%/${bli_malloc_h}}

	# Define the executable name.
	autodetect_x="auto-detect.x"

	# Create #defines for all of the BLIS_CONFIG_ macros in bli_cpuid.c.
	config_defines=$(grep BLIS_CONFIG_ ${bli_cpuid_c_filepath} \
	                 | sed -e 's/#ifdef /-D/g')

	# Compile the auto-detect program using source code inside the
	# framework.
	$autocc ${config_defines} \
	        -DBLIS_CONFIGURETIME_CPUID \
	        -I${bli_cpuid_h_path} \
	        -I${bli_arch_h_path} \
	        -I${bli_typed_h_path} \
	        -I${bli_mutex_h_path} \
	        -I${bli_malloc_h_path} \
	        -std=c99 \
	        ${autoccflags} \
	        ${bli_arch_c_filepath} \
	        ${bli_cpuid_c_filepath} \
	        ${main_c_filepath} \
	     -o ${autodetect_x}

	# Run the auto-detect program.
	#detected_config=`./${autodetect_x}`
	detected_config=$(./${autodetect_x})

	# Remove the executable file.
	rm -f ./${autodetect_x}

	# Return the detected sub-configuration name.
	echo "${detected_config}"
}

#
# -- main function -------------------------------------------------------------
#

main()
{
	#declare -A config_registry
	#declare -A kernel_registry
	#declare -A kconfig_registry

	# The name of the script, stripped of any preceeding path.
	script_name=${0##*/}

	# The path to the script. We need this to find the top-level directory
	# of the source distribution in the event that the user has chosen to
	# build elsewhere.
	dist_path=${0%/${script_name}}

	# The path to the directory in which we are building. We do this to
	# make explicit that we distinguish between the top-level directory
	# of the distribution and the directory in which we are building.
	cur_dirpath="."

	# The file in which the version string is kept.
	version_file="version"
	version_filepath="${dist_path}/${version_file}"

	# The name of and path to the directory named "build" in the top-level
	# directory of the source distribution.
	build_dir='build'
	build_dirpath="${dist_path}/${build_dir}"

	# The name/path to the registry (master list) of supported configurations.
	registry_file="config_registry"
	registry_filepath=${dist_path}/${registry_file}

	# The names/paths for the template config.mk.in and its instantiated
	# counterpart.
	config_mk_in='config.mk.in'
	config_mk_out='config.mk'
	config_mk_in_path="${build_dirpath}/${config_mk_in}"
	config_mk_out_path="${cur_dirpath}/${config_mk_out}"

	# The names/paths for the template bli_config.h.in and its instantiated
	# counterpart.
	bli_config_h_in='bli_config.h.in'
	bli_config_h_out='bli_config.h'
	bli_config_h_in_path="${build_dirpath}/${bli_config_h_in}"
	bli_config_h_out_path="${cur_dirpath}/${bli_config_h_out}"

	# Path to 'update-version-file.sh' script.
	update_version_file_sh="${build_dirpath}/update-version-file.sh"

	# Path to 'mirror-tree.sh' script.
	mirror_tree_sh="${build_dirpath}/mirror-tree.sh"

	# Path to 'gen-make-frags.sh' script and directory.
	gen_make_frags_dirpath="${build_dirpath}/gen-make-frags"
	gen_make_frags_sh="${gen_make_frags_dirpath}/gen-make-frag.sh"

	# The name of the (top-level) configuration directory.
	config_dir='config'
	config_dirpath="${dist_path}/${config_dir}"

	# The name of the (top-level) kernels directory.
	kernels_dir='kernels'
	kernels_dirpath="${dist_path}/${kernels_dir}"

	# The name of the (top-level) reference kernels directory.
	refkern_dir='ref_kernels'
	refkern_dirpath="${dist_path}/${refkern_dir}"

	# The root directory of the BLIS framework.
	frame_dir='frame'
	frame_dirpath="${dist_path}/${frame_dir}"

	# The name of the directory in which object files will be kept.
	obj_dir='obj'
	obj_dirpath="${cur_dirpath}/${obj_dir}"

	# The name of the directory in which libraries will be kept.
	lib_dir='lib'
	lib_dirpath="${cur_dirpath}/${lib_dir}"

	# The name of the directory in which headers will be kept.
	include_dir='include'
	include_dirpath="${cur_dirpath}/${include_dir}"

	# The name of the directory in which the test suite is kept.
	testsuite_dir='testsuite'

	# The install prefix flag.
	install_prefix_def="${HOME}/blis"
	install_prefix=''
	prefix_flag=''

	# The debug flag.
	debug_type=''
	debug_flag=''

	# The threading flag.
	threading_model='no'

	# Option variables.
	quiet_flag=''
	show_config_list=''
	
	# Additional flags.
	enable_verbose='no'
	enable_static='yes'
	enable_shared='no'
	enable_packbuf_pools='yes'
	int_type_size=0
	blas2blis_int_type_size=32
	enable_blas2blis='yes'
	enable_cblas='no'
	force_version='no'

	# The name of the chosen configuration (the configuration "family").
	config_name=''

	# The list of sub-configurations associated with config_name.
	config_list=''

	# The list of kernel sets that will be needed by the sub-configurations
	# in config_list..
	kernel_list=''

	# The list of kernel:sub-configuration pairs for all kernels contained
	# in kernel_list.
	kconfig_map=''

	# Dummy file. Used to check whether the cwd is the same as the top-level
	# source distribution directory.
	dummy_file='_blis_dir_detect.tmp'


	# -- Command line option/argument parsing ----------------------------------

	# Process our command line options.
	while getopts ":hp:d:t:qci:b:-:" opt; do
		case $opt in
			-)
				case "$OPTARG" in
					help)
						print_usage
						;;
					quiet)
						quiet_flag=1
						;;
					prefix=*)
						prefix_flag=1
						install_prefix=${OPTARG#*=}
						;;
					enable-debug)
						debug_flag=1
						debug_type=noopt
						;;
					enable-debug=*)
						debug_flag=1
						debug_type=${OPTARG#*=}
						;;
					disable-debug)
						debug_flag=0
						;;
					enable-verbose-make)
						enable_verbose='yes'
						;;
					disable-verbose-make)
						enable_verbose='no'
						;;
					enable-static)
						enable_static='yes'
						;;
					disable-static)
						enable_static='no'
						;;
					enable-shared)
						enable_shared='yes'
						;;
					disable-shared)
						enable_shared='no'
						;;
					enable-threading=*)
						threading_model=${OPTARG#*=}
						;;
					disable-threading)
						threading_model='no'
						;;
					enable-packbuf-pools)
						enable_packbuf_pools='yes'
						;;
					disable-packbuf-pools)
						enable_packbuf_pools='no'
						;;
					int-size=*)
						int_type_size=${OPTARG#*=}
						;;
					blas-int-size=*)
						blas2blis_int_type_size=${OPTARG#*=}
						;;
					enable-blas)
						enable_blas2blis='yes'
						;;
					disable-blas)
						enable_blas2blis='no'
						;;
					enable-cblas)
						enable_cblas='yes'
						;;
					disable-cblas)
						enable_cblas='no'
						;;
					force-version=*)
						force_version=${OPTARG#*=}
						;;
					show-config-list)
						show_config_list=1
						;;
					*)
						print_usage
						;;
				esac;;
			h)
				print_usage
				;;
			p)
				prefix_flag=1
				install_prefix=$OPTARG
				;;
			d)
				debug_flag=1
				debug_type=$OPTARG
				;;
			q)
				quiet_flag=1
				;;
			t)
				threading_model=$OPTARG
				;;
			i)
				int_type_size=$OPTARG
				;;
			b)
				blas2blis_int_type_size=$OPTARG
				;;
			c)
				show_config_list=1
				;;
			\?)
				print_usage
				;;
		esac
	done
	shift $(($OPTIND - 1))
	
	# Parse environment variables
	while [ $# -gt 0 ]; do
		case $1 in
			CC=*)
				CC=${1#*=}
				shift
				;;
			*=*)
				print_usage
				;;
			*)
				break
				;;
		esac
	done


	# -- Read the configuration registry ---------------------------------------

	# Make sure the config registry file exists and can be opened.
	if [ ! -f "${registry_filepath}" ]; then

		echo "${script_name}: could not open '${registry_file}' file; cannot continue."
		echo "${script_name}: BLIS distribution appears to be incomplete."

		exit 1
	fi

	# Read the registered configuration names and lists into an associative
	# array.
	echo -n "${script_name}: reading configuration registry..."
	read_registry_file ${registry_filepath}
	echo "done."


	# -- Acquire the BLIS version ----------------------------------------------

	# Check whether we need to update the version file.
	${update_version_file_sh} -o "${script_name}" "${version_filepath}"

	# Query which version of BLIS this is.
	version=$(cat ${version_filepath})

	# Initial message.
	echo "${script_name}: starting configuration of BLIS ${version}."

	# Check if the user requested a custom version string.
	if [ "x${force_version}" = "xno" ]; then
		echo "${script_name}: configuring with official version string."
	else
		echo "${script_name}: configuring with custom version string '${force_version}'."
		version="${force_version}"
	fi


	# -- Various pre-configuration checks --------------------------------------

	# Set config_name based on the number of arguments leftover (after command
	# line option processing).
	if [ $# = "0" ]; then

		#configs_avail="auto "$(ls ${config_dirpath})

		echo "${script_name}: "
		echo "${script_name}: *** No configuration given! ***"
		echo "${script_name}: "
		echo "${script_name}: Default configuration behavior is not implemented (for your"
		echo "${script_name}: own safety). Please re-run '${script_name}' and specify one"
		echo "${script_name}: of the existing configurations in the source distribution's"
		echo "${script_name}  '${registry_file}' file:"
		echo "${script_name}: "
		#for k in "${!config_registry[@]}"; do
		for cr_var in ${!config_registry_*}; do

			#v=${config_registry[$k]}
			k=${cr_var##config_registry_}; v=${!cr_var}

			echo "${script_name}:   $k (${v})"
		done
		echo "${script_name}: "

		exit 1

	elif [ $# != "1" ]; then   # more than one configuration argument given.

		print_usage

	fi

	if [ $1 = "auto" ]; then

		echo "${script_name}: automatic configuration requested."

		# Call the auto_detect() function and save the returned string in
		# config_name.
		config_name=$(auto_detect)

		echo "${script_name}: hardware detection driver returned '${config_name}'."
	else

		# Use the command line argument as the configuration name.
		config_name=$1

		#echo "${script_name}: manual configuration requested."
		echo "${script_name}: manual configuration requested; configuring with '${config_name}'."

	fi

	# Use the selected config name to look up the list of configurations
	# and kernels associated with that name.
	#config_list=${config_registry[${config_name}]}
	#kernel_list=${kernel_registry[${config_name}]}
	config_list=$(query_array "config_registry" ${config_name})
	kernel_list=$(query_array "kernel_registry" ${config_name})

	# Use the config_registry and kernel_registry to build a kconfig_registry
	# for the selected config_name.
	build_kconfig_registry "${config_name}"

	# Print the configuration list and kernel list, if requested.
	if [ "${show_config_list}" == "1" ]; then

		echo "${script_name}: configuration list:"
		#for k in "${!config_registry[@]}"; do
		for cr_var in ${!config_registry_*}; do

			#v=${config_registry[$k]}
			k=${cr_var##config_registry_}; v=${!cr_var}

			echo "${script_name}:   $k: ${v}"
		done

		echo "${script_name}: kernel list:"
		#for k in "${!kernel_registry[@]}"; do
		for kr_var in ${!kernel_registry_*}; do

			#v=${kernel_registry[$k]}
			k=${kr_var##kernel_registry_}; v=${!kr_var}

			echo "${script_name}:   $k: ${v}"
		done

		echo "${script_name}: kernel-to-config map for '${config_name}':"
		#for k in "${!kconfig_registry[@]}"; do
		for kc_var in ${!kconfig_registry_*}; do

			#v=${kconfig_registry[$k]}
			k=${kc_var##kconfig_registry_}; v=${!kc_var}

			echo "${script_name}:   $k: ${v}"
		done
	fi

	# For each kernel in the kernel list, reduce the list of associated
	# sub-configurations (in the kconfig_registry) to a singleton using
	# the following rules:
	# 1. If the list is a singleton, use that name.
	# 2. If the list contains a sub-configuration name that matches the
	#    kernel name, use that name.
	# 3. Otherwise, use the first name in the list.
	# We use the chosen singleton to ceate a "kernel:subconfig" pair, which
	# we accumulate into a list. This list is the kernel-to-config map, or
	# kconfig_map.

	# We use a sorted version of kernel_list so that it ends up matching the
	# display order of the kconfig_registry above.
	kernel_list_sort=$(echo ${kernel_list} | xargs -n1 | sort -u)

	kconfig_map=""
	for kernel in ${kernel_list_sort}; do

		#configs="${kconfig_registry[$kernel]}"
		configs=$(query_array "kconfig_registry" ${kernel})

		has_one_kernel=$(is_singleton "${configs}")
		contains_kernel=$(is_word_in_list "${kernel}" "${configs}")

		# Check if the list is a singleton.
		if [ "${has_one_kernel}" == "true" ]; then

			reducedclist="${configs}"

		# Check if the list contains a sub-config name that matches the kernel.
		elif [ "${contains_kernel}" == "true" ]; then

			reducedclist="${kernel}"

		# Otherwise, use the first name.
		else

			first_config=${configs%% *}
			reducedclist="${first_config}"
		fi

		# Create a new "kernel:subconfig" pair and add it to the kconfig_map
		# list, removing whitespace.
		new_pair="${kernel}:${reducedclist}"
		kconfig_map=$(canonicalize_ws "${kconfig_map} ${new_pair}")
	done

	if [ "${show_config_list}" == "1" ]; then

		echo "${script_name}: kernel-to-config map for '${config_name}' (chosen pairs):"
		for k in ${kconfig_map}; do
			echo "${script_name}:   $k"
		done
	fi


	echo "${script_name}: checking configuration against contents of '${registry_file}'."

	# First, ensure that the config name is registered (ie: it is present
	# in the config_registry file).
	if [ -z "${config_list}" ]; then

		# NOTE: This branch should never execute when using auto-detection,
		# but we have it here just in case.
		if [ $1 = "auto" ]; then

			echo "${script_name}: 'auto-detected configuration '${conf}' is NOT registered!"
			echo "${script_name}: "
			echo "${script_name}: *** Cannot continue with unregistered configuration '${conf}'. ***"
			echo "${script_name}: "
			exit 1;

		else

			echo "${script_name}: 'user-specified configuration '${conf}' is NOT registered!"
			echo "${script_name}: "
			echo "${script_name}: *** Cannot continue with unregistered configuration '${conf}'. ***"
			echo "${script_name}: "
			exit 1;

		fi

	else

		# This branch executes when the configuration is found to be present
		# (i.e. registered) in the config_registry file.

		echo "${script_name}: configuration '${config_name}' is registered."
		echo "${script_name}: '${config_name}' is defined as having the following sub-configurations:"
		echo "${script_name}:    ${config_list}"
		echo "${script_name}: which collectively require the following kernels:"
		echo "${script_name}:    ${kernel_list}"

	fi


	echo "${script_name}: checking sub-configurations:"

	# Now, verify that the constituent configurations associated with the
	# config name are all valid.
	for conf in ${config_list}; do

		# First confirm that the current configuration is registered.
		#this_clist=${config_registry[${conf}]}
		this_clist=$(query_array "config_registry" ${conf})

		# If the config_list associated with conf is empty, then it was
		# never entered into the config_registry to begin with. Thus,
		# conf must be unregistered.
		if [ -z "${this_clist}" ]; then
			echo "${script_name}: '${conf}' is NOT registered!"
			echo "${script_name}: "
			echo "${script_name}: *** Cannot continue with unregistered configuration '${conf}'. ***"
			echo "${script_name}: "
			exit 1;
		else
			echo -n "${script_name}:   '${conf}' is registered."
		fi

		# Then confirm that the current sub-configuration directory exists.
		if [ ! -d "${config_dirpath}/${conf}" ]; then
			echo "..but does NOT exist!"
			echo "${script_name}: "
			echo "${script_name}: *** Cannot continue with nonexistent configuration '${conf}'. ***"
			echo "${script_name}: "
			exit 1;
		else
			echo "..and exists."
		fi
	done


	echo "${script_name}: checking sub-configurations' requisite kernels:"

	# Also, let's verify that the requisite kernel sets associated with
	# the config name all correspond to directories that exist.
	for kernel in ${kernel_list}; do

		echo -n "${script_name}:   '${kernel}' kernels..."

		# Confirm that the current kernel sub-directory exists.
		if [ ! -d "${kernels_dirpath}/${kernel}" ]; then
			echo "do NOT exist!"
			echo "${script_name}: "
			echo "${script_name}: *** Cannot continue with nonexistent kernel '${kernel}'. ***"
			echo "${script_name}: "
			exit 1;
		else
			echo "exist."
		fi
	done


	# -- Prepare variables for subsitution into template files -----------------

	# Set the install prefix if it was not already set when parsing the install
	# prefix flag.
	if [ -n "${prefix_flag}" ]; then
		echo "${script_name}: using install prefix '${install_prefix}'."
	else
		install_prefix="${install_prefix_def}"
		echo "${script_name}: no install prefix given; defaulting to '${install_prefix}'."
	fi

	# Check if the debug flag was specified.
	if [ -n "${debug_flag}" ]; then
		if [ "x${debug_type}" = "xopt" ]; then
			echo "${script_name}: enabling debug symbols with optimizations."
                elif [ "x${debug_type}" = "xsde" ]; then
			debug_type='sde'
			echo "${script_name}: enabling SDE processor emulation."
		else
			debug_type='noopt'
			echo "${script_name}: enabling debug symbols; optimizations disabled."
		fi
	else
		debug_type='off'
		echo "${script_name}: debug symbols disabled."
	fi

	# Check if the verbose make flag was specified.
	if [ "x${enable_verbose}" = "xyes" ]; then
		echo "${script_name}: enabling verbose make output. (disable with 'make V=0'.)"
	else
		echo "${script_name}: disabling verbose make output. (enable with 'make V=1'.)"
	fi

	# Check if the static lib flag was specified.
	if [ "x${enable_static}" = "xyes" ]; then
		echo "${script_name}: building BLIS as a static library."
	fi
	
	# Check if the shared lib flag was specified.
	if [ "x${enable_shared}" = "xyes" ]; then
		echo "${script_name}: building BLIS as a shared library."
	fi
	
	# Check if neither flag was specified.
	if [ "x${enable_static}" = "xno" -a "x${enable_shared}" = "xno" ]; then
		echo "Neither a shared nor static library build has been requested."
		exit 1
	fi

	# Check the threading model flag and standardize its value, if needed.
	# NOTE: 'omp' is deprecated but still supported; 'openmp' is preferred.
	enable_openmp='no'
	enable_openmp_01=0
	enable_pthreads='no'
	enable_pthreads_01=0
	if [ "x${threading_model}" = "xauto" ]; then
		echo "${script_name}: determining the threading model automatically."
	elif [ "x${threading_model}" = "xopenmp" ] ||
	     [ "x${threading_model}" = "xomp" ]; then
		echo "${script_name}: using OpenMP for threading."
		enable_openmp='yes'
		enable_openmp_01=1
		threading_model="openmp" # Standardize the value.
	elif [ "x${threading_model}" = "xpthreads" ] ||
	     [ "x${threading_model}" = "xpthread" ] ||
	     [ "x${threading_model}" = "xposix" ]; then
		echo "${script_name}: using Pthreads for threading."
		enable_pthreads='yes'
		enable_pthreads_01=1
		threading_model="pthreads" # Standardize the value.
	elif [ "x${threading_model}" = "xno" ] ||
	     [ "x${threading_model}" = "xnone" ]; then
		echo "${script_name}: threading is disabled."
	else
		echo "Unsupported threading model: ${threading_model}."
		exit 1
	fi
	
	# Convert 'yes' and 'no' flags to booleans.
	if [ "x${enable_packbuf_pools}" = "xyes" ]; then
		echo "${script_name}: internal memory pools for packing buffers are enabled."
		enable_packbuf_pools_01=1
	else
		echo "${script_name}: internal memory pools for packing buffers are disabled."
		enable_packbuf_pools_01=0
	fi
	if [ "x${enable_blas2blis}" = "xyes" ]; then
		echo "${script_name}: the BLAS compatibility layer is enabled."
		enable_blas2blis_01=1
	else
		echo "${script_name}: the BLAS compatibility layer is disabled."
		enable_blas2blis_01=0
	fi
	if [ "x${enable_cblas}" = "xyes" ]; then
		echo "${script_name}: the CBLAS compatibility layer is enabled."
		enable_cblas_01=1
		# Force BLAS layer when CBLAS is enabled
		enable_blas2blis='yes'
	else
		echo "${script_name}: the CBLAS compatibility layer is disabled."
		enable_cblas_01=0
	fi
	
	# Report integer sizes
	if [ "x${int_type_size}" = "x32" ]; then
		echo "${script_name}: the internal integer size is 32-bit."
	elif [ "x${int_type_size}" = "x64" ]; then
		echo "${script_name}: the internal integer size is 64-bit."
	else
		echo "${script_name}: the internal integer size is automatically determined."
	fi
	if [ "x${blas2blis_int_type_size}" = "x32" ]; then
		echo "${script_name}: the BLAS/CBLAS interface integer size is 32-bit."
	elif [ "x${blas2blis_int_type_size}" = "x64" ]; then
		echo "${script_name}: the BLAS/CBLAS interface integer size is 64-bit."
	else
		echo "${script_name}: the BLAS/CBLAS interface integer size is automatically determined."
	fi


	# Variables that contain forward slashes, such as paths, need extra
	# escaping when used in sed commands. We insert those extra escape
	# characters here so that the sed commands below do the right thing.
	install_prefix_esc=$(echo "${install_prefix}" | sed 's/\//\\\//g')
	dist_path_esc=$(echo "${dist_path}"           | sed 's/\//\\\//g')
	cc_esc=$(echo "${CC}" | sed 's/\//\\\//g')

	# Create a #define for the configuration family (config_name).
	uconf=$(echo ${config_name} | tr '[:lower:]' '[:upper:]')
	config_name_define="#define BLIS_FAMILY_${uconf}\n"

	# Create a list of #defines, one for each configuration in config_list.
	config_list_defines=""
	for conf in ${config_list}; do

		# Convert the current config name to uppercase.
		uconf=$(echo ${conf} | tr '[:lower:]' '[:upper:]')

		# Create a #define and add it to the running list.
		config_define="BLIS_CONFIG_${uconf}"
		config_list_defines="${config_list_defines}#define ${config_define}\n"
	done

	# Create a list of #defines, one for each kernel set in kernel_list.
	kernel_list_defines=""
	for kern in ${kernel_list}; do

		# Convert the current config name to uppercase.
		uconf=$(echo ${kern} | tr '[:lower:]' '[:upper:]')

		# Create a #define and add it to the running list.
		kernel_define="BLIS_KERNELS_${uconf}"
		kernel_list_defines="${kernel_list_defines}#define ${kernel_define}\n"
	done


	# -- Instantiate config.mk, bli_config.h files from templates --------------

	# Begin substituting information into the config_mk_in file, outputting
	# to config_mk_out.
	echo "${script_name}: creating ${config_mk_out_path} from ${config_mk_in_path}"
	cat "${config_mk_in_path}" \
		| sed -e "s/@version@/${version}/g" \
		| sed -e "s/@config_name@/${config_name}/g" \
		| sed -e "s/@config_list@/${config_list}/g" \
		| sed -e "s/@kernel_list@/${kernel_list}/g" \
		| sed -e "s/@kconfig_map@/${kconfig_map}/g" \
		| sed -e "s/@dist_path@/${dist_path_esc}/g" \
		| sed -e "s/@CC@/${cc_esc}/g" \
		| sed -e "s/@debug_type@/${debug_type}/g" \
		| sed -e "s/@install_prefix@/${install_prefix_esc}/g" \
		| sed -e "s/@enable_verbose@/${enable_verbose}/g" \
		| sed -e "s/@enable_static@/${enable_static}/g" \
		| sed -e "s/@enable_dynamic@/${enable_shared}/g" \
		| sed -e "s/@threading_model@/${threading_model}/g" \
		| sed -e "s/@enable_blas2blis@/${enable_blas2blis}/g" \
		| sed -e "s/@enable_cblas@/${enable_cblas}/g" \
		> "${config_mk_out_path}"
		

	# Begin substituting information into the bli_config_h_in file, outputting
	# to bli_config_h_out. NOTE: We use perl instead of sed because the version
	# of sed used on OS X is old and does not handle the '\n' character
	# intuitively, which was used when constructing ${config_name_define},
	# ${config_list_defines}, and ${kernel_list_defines}.
	echo "${script_name}: creating ${bli_config_h_out_path} from ${bli_config_h_in_path}"
	cat "${bli_config_h_in_path}" \
		| perl -pe "s/\@config_name_define\@/${config_name_define}/g" \
		| perl -pe "s/\@config_list_defines\@/${config_list_defines}/g" \
		| perl -pe "s/\@kernel_list_defines\@/${kernel_list_defines}/g" \
		| sed   -e "s/@enable_openmp@/${enable_openmp_01}/g" \
		| sed   -e "s/@enable_pthreads@/${enable_pthreads_01}/g" \
		| sed   -e "s/@enable_packbuf_pools@/${enable_packbuf_pools_01}/g" \
		| sed   -e "s/@int_type_size@/${int_type_size}/g" \
		| sed   -e "s/@blas2blis_int_type_size@/${blas2blis_int_type_size}/g" \
		| sed   -e "s/@enable_blas2blis@/${enable_blas2blis_01}/g" \
		| sed   -e "s/@enable_cblas@/${enable_cblas_01}/g" \
		> "${bli_config_h_out_path}"


	# -- Create top-level object directories -----------------------------------

	# Create obj sub-directories (if they do not already exist).
	base_obj_dirpath="${obj_dirpath}/${config_name}"

	echo "${script_name}: creating ${base_obj_dirpath}"
	mkdir -p ${base_obj_dirpath}


	obj_config_dirpath="${base_obj_dirpath}/${config_dir}"

	echo "${script_name}: creating ${obj_config_dirpath}"
	mkdir -p ${obj_config_dirpath}
	for conf in ${config_list}; do
		echo "${script_name}: creating ${obj_config_dirpath}/${conf}"
		mkdir -p ${obj_config_dirpath}/${conf}
	done


	obj_kernels_dirpath="${base_obj_dirpath}/${kernels_dir}"

	echo "${script_name}: creating ${obj_kernels_dirpath}"
	mkdir -p ${obj_kernels_dirpath}
	for kern in ${kernel_list}; do
		echo "${script_name}: creating ${obj_kernels_dirpath}/${kern}"
		mkdir -p ${obj_kernels_dirpath}/${kern}
	done


	obj_refkern_dirpath="${base_obj_dirpath}/${refkern_dir}"

	echo "${script_name}: creating ${obj_refkern_dirpath}"
	mkdir -p ${obj_refkern_dirpath}
	for conf in ${config_list}; do
		echo "${script_name}: creating ${obj_refkern_dirpath}/${conf}"
		mkdir -p ${obj_refkern_dirpath}/${conf}
	done


	obj_frame_dirpath="${base_obj_dirpath}/${frame_dir}"

	echo "${script_name}: creating ${obj_frame_dirpath}"
	mkdir -p ${obj_frame_dirpath}


	obj_testsuite_dirpath="${base_obj_dirpath}/${testsuite_dir}"

	echo "${script_name}: creating ${obj_testsuite_dirpath}"
	mkdir -p ${obj_testsuite_dirpath}


	# Create lib directory (if it does not already exist).
	base_lib_dirpath="${lib_dirpath}/${config_name}"

	echo "${script_name}: creating ${base_lib_dirpath}"
	mkdir -p ${base_lib_dirpath}

	# Create include directory (if it does not already exist).
	base_include_dirpath="${include_dirpath}/${config_name}"

	echo "${script_name}: creating ${base_include_dirpath}"
	mkdir -p ${base_include_dirpath}


	# -- Mirror source directory hierarchies to object directories -------------

	# Mirror each of the sub-configuration directories to the object directory.
	for conf in ${config_list}; do

		echo "${script_name}: mirroring ${config_dirpath}/${conf} to ${obj_config_dirpath}/${conf}"
		${mirror_tree_sh} "${config_dirpath}/${conf}" "${obj_config_dirpath}/${conf}"
	done

	# Mirror optimized kernels source tree to its object sub-directory.
	# We perform the mirroring on each configuration/kernel sub-directory
	# within 'kernels'.
	for kern in ${kernel_list}; do

		# Only mirror the optimized kernels source directory if it exists.
		# There are occasions where one of the sub-configurations in the
		# config_list does not correspond to a kernels sub-directory, such
		# as when architecture B is so close to architecture A that B can
		# use A's kernel source code unmodified (though perhaps with
		# different blocksizes).
		#if [ -d "${kernels_dirpath}/${conf}" ]; then

		echo "${script_name}: mirroring ${kernels_dirpath}/${kern} to ${obj_kernels_dirpath}/${kern}"
		${mirror_tree_sh} "${kernels_dirpath}/${kern}" "${obj_kernels_dirpath}/${kern}"
		#else
		#	echo "${script_name}: mirroring ${kernels_dirpath}/${conf} skipped... directory does not exist"
		#fi
	done

	# Mirror reference kernels source tree to its object sub-directory.
	for conf in ${config_list}; do

		echo "${script_name}: mirroring ${refkern_dirpath} to ${obj_refkern_dirpath}/${conf}"
		${mirror_tree_sh} "${refkern_dirpath}" "${obj_refkern_dirpath}/${conf}"
	done

	# Mirror framework source tree to its object sub-directory.
	echo "${script_name}: mirroring ${frame_dirpath} to ${obj_frame_dirpath}"
	${mirror_tree_sh} ${frame_dirpath} ${obj_frame_dirpath}


	# -- Generate makefile fragements ------------------------------------------

	clist_contains_cname=$(is_word_in_list "${config_name}" "${config_list}")

	# If the config_list does not already contain the config_name, generate
	# makefiles in that directory.
	if [ "${clist_contains_cname}" == "false" ]; then

		${gen_make_frags_sh} \
				 -h -r -v1 \
				 -o ${script_name} \
				 -p 'CONFIG' \
				 ${config_dirpath}/${config_name} \
				 ${gen_make_frags_dirpath}/fragment.mk \
				 ${gen_make_frags_dirpath}/suffix_list \
				 ${gen_make_frags_dirpath}/ignore_list
	fi

	# Generate makefile fragments for each of the sub-configurations present
	# in the configuration list.
	for conf in ${config_list}; do

		${gen_make_frags_sh} \
				 -h -r -v1 \
				 -o ${script_name} \
				 -p 'CONFIG' \
				 ${config_dirpath}/${conf} \
				 ${gen_make_frags_dirpath}/fragment.mk \
				 ${gen_make_frags_dirpath}/suffix_list \
				 ${gen_make_frags_dirpath}/ignore_list
	done

	# Generate makefile fragments for each of the kernel sets required by
	# the configuration list (in the kernel list).
	for kern in ${kernel_list}; do

		${gen_make_frags_sh} \
				 -h -r -v1 \
				 -o ${script_name} \
				 -p 'KERNELS' \
				 ${kernels_dirpath}/${kern} \
				 ${gen_make_frags_dirpath}/fragment.mk \
				 ${gen_make_frags_dirpath}/suffix_list \
				 ${gen_make_frags_dirpath}/ignore_list
	done

	# Generate makefile fragments in the reference kernels directory.
	${gen_make_frags_sh} \
			 -h -r -v1 \
			 -o ${script_name} \
			 -p 'REFKERN' \
			 ${refkern_dirpath} \
			 ${gen_make_frags_dirpath}/fragment.mk \
			 ${gen_make_frags_dirpath}/suffix_list \
			 ${gen_make_frags_dirpath}/ignore_list

	# Generate makefile fragments in the framework directory.
	${gen_make_frags_sh} \
			 -h -r -v1 \
			 -o ${script_name} \
			 -p 'FRAME' \
			 ${frame_dirpath} \
			 ${gen_make_frags_dirpath}/fragment.mk \
			 ${gen_make_frags_dirpath}/suffix_list \
			 ${gen_make_frags_dirpath}/ignore_list


	# -- Handle out-of-tree builds ---------------------------------------------

	# Under some circumstances, we need to create a symbolic link to the
	# Makefile. We only proceed with this if configure was run with a path
	# other than "./".
	if [ ${dist_path} != "./" ]; then

		# At this point, we know the user did not run "./configure". But we
		# have not yet ruled out "<fullpath>/configure" or some # equivalent
		# that uses relative paths. To further rule out these possibilities,
		# we create a dummy file in the current build directory.
		touch "./${dummy_file}"

		# If the dummy file we just created in the current directory does not
		# appear in the source distribution path, then we are in a different
		# directory and thus we must create a symbolic link.
		if [ ! -f "${dist_path}/${dummy_file}" ]; then

			# If 'Makefile' does not already exist in the current directory,
			# create a symbolic link to it. If one does exist, we us -f to
			# force creation of a new link.
			if [ ! -e "./Makefile" ]; then

				echo "${script_name}: creating symbolic link to Makefile."
				ln -s "${dist_path}/Makefile"

			else
				echo "${script_name}: symbolic link to Makefile already exists; forcing creation of new link."
				ln -sf "${dist_path}/Makefile"
			fi

			# If 'common.mk' does not already exist in the current directory,
			# create a symbolic link to it. If one does exist, we us -f to
			# force creation of a new link.
			if [ ! -e "./common.mk" ]; then

				echo "${script_name}: creating symbolic link to common.mk."
				ln -s "${dist_path}/common.mk"

			else
				echo "${script_name}: symbolic link to common.mk already exists; forcing creation of new link."
				ln -sf "${dist_path}/common.mk"
			fi

			echo "${script_name}: configured to build outside of source distribution."
		else

			# Echo what is happening. 
			echo "${script_name}: configured to build within top-level directory of source distribution."
		fi

		# Remove the dummy file.
		rm -f "./${dummy_file}"
	fi


	# Exit peacefully.
	return 0
}


# The script's main entry point, passing all parameters given.
main "$@"

