#!/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 " -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}" } # # -- 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' int_type_size=0 blas2blis_int_type_size=32 enable_blas2blis='yes' enable_cblas='no' force_version='no' # The path to the auto-detection script. auto_detect_sh="${build_dirpath}/auto-detect/auto-detect.sh" # 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' ;; 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." # Run the auto-detect script and save the result in config_name. config_name=`${build_dirpath}/auto-detect/auto-detect.sh` echo "${script_name}: auto-detect script 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 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 (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 the # auto-detect script, 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_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 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 # 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/@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 "/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 "$@"