diff options
Diffstat (limited to 'scripts/functions')
-rw-r--r-- | scripts/functions | 228 |
1 files changed, 191 insertions, 37 deletions
diff --git a/scripts/functions b/scripts/functions index ca7713a0..3717ffd8 100644 --- a/scripts/functions +++ b/scripts/functions @@ -1,6 +1,6 @@ # -*- mode: sh; tab-width: 4 -*- # vi: ts=4:sw=4:sts=4:et -# This file contains some usefull common functions +# This file contains some useful common functions # Copyright 2007 Yann E. MORIN # Licensed under the GPL v2. See COPYING in the root of this package @@ -308,21 +308,57 @@ CT_SanitizePath() { PATH="${new}" } -# Sanitise the directory name contained in the variable passed as argument: +# Sanitize the directory name contained in the variable passed as argument: # - remove duplicate / -# Usage: CT_SanitiseVarDir CT_PREFIX_DIR -CT_SanitiseVarDir() { +# - remove . (current dir) at the beginning, in the middle or at the end +# - resolve .. (parent dir) if there is a previous component +# - remove .. (parent dir) if at the root +# +# Usage: CT_SanitizeVarDir CT_PREFIX_DIR +CT_SanitizeVarDir() { local var local old_dir - local new_dir + local new_dir tmp for var in "$@"; do eval "old_dir=\"\${${var}}\"" - new_dir="$( printf "${old_dir}" \ - |${sed} -r -e 's:/+:/:g;' \ - )" + new_dir=$( echo "${old_dir}" | ${awk} ' +{ + isabs = $1 == "" # Started with a slash + trail = $NF == "" # Ending with a slash + ncomp = 0 # Components in a path so far + for (i = 1; i <= NF; i++) { + # Double-slash or current dir? Ignore + if ($i == "" || $i == ".") { + continue; + } + # .. pops the last component unless it is at the beginning + if ($i == ".." && ncomp != 0 && comps[ncomp] != "..") { + ncomp--; + continue; + } + comps[++ncomp] = $i; + } + seencomp = 0 + for (i = 1; i <= ncomp; i++) { + if (comps[i] == ".." && isabs) { + # /../ at the beginning is equivalent to / + continue; + } + printf "%s%s", isabs || i != 1 ? "/" : "", comps[i]; + seencomp = 1; + } + if (!seencomp && !isabs && !trail) { + # Eliminated all components, but no trailing slash - + # if the result is appened with /foo, must not become absolute + printf "."; + } + if ((!seencomp && isabs) || (seencomp && trail)) { + printf "/"; + } +}' FS=/ ) eval "${var}=\"${new_dir}\"" - CT_DoLog DEBUG "Sanitised '${var}': '${old_dir}' -> '${new_dir}'" + CT_DoLog DEBUG "Sanitized '${var}': '${old_dir}' -> '${new_dir}'" done } @@ -1183,6 +1219,14 @@ CT_DoConfigSub() { fi } +# Normally, each step is executed in a sub-shell and thus cannot modify the +# environment for the next step(s). When this is needed, it can do so by +# invoking this function. +# Usage: CT_EnvModify VAR VALUE +CT_EnvModify() { + echo "${1}=\"${2}\"" >> "${CT_BUILD_DIR}/env.modify.sh" +} + # Compute the target tuple from what is provided by the user # Usage: CT_DoBuildTargetTuple # In fact this function takes the environment variables to build the target @@ -1303,25 +1347,23 @@ CT_DoBuildTargetTuple() { # Now on for the target LDFLAGS CT_ARCH_TARGET_LDFLAGS="${CT_ARCH_TARGET_LDFLAGS} ${CT_ARCH_ENDIAN_LDFLAG}" -} -# This function determines the target tuple for a given set of compiler -# flags, using either GCC's multiarch feature (if supported; if not, -# GCC prints nothing and exits with status 0), falling back to calling -# the architecture-specific functions. -CT_DoMultilibTarget() { - local target="$1"; shift - local -a multi_flags=( "$@" ) - local gcc_multiarch - - gcc_multiarch=$( "${CT_TARGET}-gcc" -print-multiarch "${multi_flags[@]}" ) - if [ -n "${gcc_multiarch}" ]; then - echo "${gcc_multiarch}" - return + # Now, a multilib quirk. We may not be able to pass CT_ARCH_TARGET_CFLAGS + # and CT_ARCH_TARGET_LDFLAGS to gcc: even though GCC build appends the multilib + # flags afterwards, on some architectures the build breaks because some + # flags do not completely override each other. For example, on mips target, + # 'gcc -mabi=32' and 'gcc -mabi=n32' both work, but 'gcc -mabi=32 -mabi=n32' + # triggers an internal linker error. Likely a bug in GNU binutils, but we + # have to work it around for now: *do not pass the CT_ARCH_TARGET_ flags*. + # Instead, save them into a different variable here. Then, after the first + # core pass, we'll know which of them vary with multilibs (i.e. must be + # filtered out). + if [ "${CT_MULTILIB}" = "y" ]; then + CT_ARCH_TARGET_CFLAGS_MULTILIB="${CT_ARCH_TARGET_CFLAGS}" + CT_ARCH_TARGET_CFLAGS= + CT_ARCH_TARGET_LDFLAGS_MULTILIB="${CT_ARCH_TARGET_LDFLAGS}" + CT_ARCH_TARGET_LDFLAGS= fi - - # Fall back to arch-specific guesswork - CT_DoArchMultilibTarget "${target}" "${multi_flags[@]}" } # This function does pause the build until the user strikes "Return" @@ -1413,7 +1455,6 @@ CT_DoSaveState() { /^(FUNCNAME|GROUPS|PPID|SHELLOPTS)=/d;' >"${state_dir}/env.sh" CT_DoTarballIfExists "${CT_BUILDTOOLS_PREFIX_DIR}" "${state_dir}/buildtools_dir" - CT_DoTarballIfExists "${CT_CONFIG_DIR}" "${state_dir}/config_dir" CT_DoTarballIfExists "${CT_PREFIX_DIR}" "${state_dir}/prefix_dir" --exclude '*.log' CT_DoLog STATE " Saving log file" @@ -1443,7 +1484,6 @@ CT_DoLoadState(){ CT_DoLog INFO "Restoring state at step '${state_name}', as requested." CT_DoExtractTarballIfExists "${state_dir}/prefix_dir" "${CT_PREFIX_DIR}" - CT_DoExtractTarballIfExists "${state_dir}/config_dir" "${CT_CONFIG_DIR}" CT_DoExtractTarballIfExists "${state_dir}/buildtools_dir" "${CT_BUILDTOOLS_PREFIX_DIR}" # Restore the environment, discarding any error message @@ -1470,9 +1510,9 @@ CT_DoLoadState(){ # This function sets a kconfig option to a specific value in a .config file # Usage: CT_KconfigSetOption <option> <value> <file> CT_KconfigSetOption() { - option="$1" - value="$2" - file="$3" + local option="$1" + local value="$2" + local file="$3" ${grep} -E -q "^${option}=.*" "${file}" && \ ${sed} -i -r -e "s;^${option}=.*$;${option}=${value};" "${file}" || \ @@ -1484,8 +1524,8 @@ CT_KconfigSetOption() { # This function enables a kconfig option to '=y' in a .config file # Usage: CT_KconfigEnableOption <option> <file> CT_KconfigEnableOption() { - option="$1" - file="$2" + local option="$1" + local file="$2" CT_KconfigSetOption "${option}" "y" "${file}" } @@ -1493,8 +1533,8 @@ CT_KconfigEnableOption() { # This function disables a kconfig option in a .config file # Usage: CT_KconfigDisableOption <option> <file> CT_KconfigDisableOption() { - option="${1}" - file="${2}" + local option="${1}" + local file="${2}" ${grep} -E -q "^# ${option} is not set$" "${file}" || \ ${grep} -E -q "^${option}=.*$" "${file}" && \ @@ -1506,11 +1546,125 @@ CT_KconfigDisableOption() { # is set or commented out. # Usage: CT_KconfigDeleteOption <option> <file> CT_KconfigDeleteOption() { - option="${1}" - file="${2}" + local option="${1}" + local file="${2}" ${grep} -E -q "^# ${option} is not set$" "${file}" && \ ${sed} -i -r -e "/^# ${option} is not set$/d" "${file}" || \ ${grep} -E -q "^${option}=.*$" "${file}" && \ ${sed} -i -r -e "/^${option}=.*$/d" "${file}" || true } + +# Multilib iterator. The caller should be in a directory where the directories +# will be created, one per multilib, and the specified command will be run in +# each of them. The following arguments will be passed to the invoked command: +# multi_flags CFLAGS for this multilib +# multi_dir GCC internal library location for the multilib +# multi_os_dir OS library location for the multilib +# multi_root Sysroot for this multilib +# multi_target Target tuple, either as reported by GCC or by our guesswork +# multi_count Total number of multilibs +# multi_index Index of the current multilib +# Any additional arguments passed to this function will be forwarded to the called +# function as well. +# Usage: CT_IterateMultilibs <function> <prefix> <additional-args...> +CT_IterateMultilibs() { + local func="${1}" + local prefix="${2}" + local -a multilibs + local multi_dir multi_os_dir multi_root multi_flags multi_index multi_target + local root_suffix + + # Name used internally below + if [ "${prefix}" = "sysroot-check" ]; then + CT_Abort "Bad prefix used in CT_IterateMultilibs" + fi + + # Drop mandatory arguments + shift 2 + + # If gcc is not configured for multilib, it still prints a single line + # for the default settings + multilibs=( $("${CT_TARGET}-gcc" -print-multi-lib 2>/dev/null) ) + CT_DoExecLog ALL rm -rf "sysroot-check" + for multilib in "${multilibs[@]}"; do + # GCC makes the distinction between: + # multilib (-print-multi-lib or -print-multi-directory) and + # multilib-os (--print-multi-os-directory) + # as the gcc library and gcc sysroot library paths, respectively. + # For example, on x86_64: + # multilib: -m32=32 -m64=. + # multilib-os: -m32=../lib -m64=../lib64 + # Moreover, while some multilibs can coexist in the same sysroot (e.g. + # on x86), some have a "sysroot suffix" to separate incompatible variants. + # Such sysroot suffixes combine with multilib-os directories, e.g. + # on sh4 with -m4a multilib, the search order in sysroot is (dropping some + # directories for brevity: + # <sysroot>/m4a/lib/m4a/ + # <sysroot>/m4a/usr/lib/m4a/ + # <sysroot>/m4a/lib/ + # <sysroot>/m4a/usr/lib/ + # The problem is that while GCC itself is aware of these subtleties, the + # binutils (notably, ld) it invokes under the hood are not. For example, + # if a shared library libfoo.so.1 requires libbar.so.1, ld will only search + # for libbar.so.1 in <sysroot>/m4a/usr/lib, but not in <sysroot>/m4a/usr/lib/m4a. + # In other words, 'gcc -lfoo -lbar' will work for both the default and -m4a + # cases, and 'gcc -lfoo' will work for the default, but not for -m4a. To + # address this, we first try to determine if the sysroot alone makes the + # configuration sufficiently unique. If there are no multilibs within the + # same suffixed sysroot, we can drop the multi_os_dir and both gcc and ld + # will work. If not, we'll supply both multi_root/multi_os_dir (which will + # likely break later, e.g. while building final GCC with C++ support). But, + # we've done all we can. + multi_flags=$( echo "${multilib#*;}" | ${sed} -r -e 's/@/ -/g;' ) + multi_dir="${multilib%%;*}" + multi_os_dir=$( "${CT_TARGET}-gcc" -print-multi-os-directory ${multi_flags} ) + multi_root=$( "${CT_TARGET}-gcc" -print-sysroot ${multi_flags} ) + root_suffix="${multi_root#${CT_SYSROOT_DIR}}" + CT_DoExecLog ALL mkdir -p "sysroot-check${root_suffix}" + if [ -e "sysroot-check${root_suffix}/seen" ]; then + CT_DoExecLog ALL rm -f "sysroot-check${root_suffix}/unique" + else + CT_DoExecLog ALL touch "sysroot-check${root_suffix}/seen" \ + "sysroot-check${root_suffix}/unique" + fi + done + + # Now, actual iteration. + # This uses either GCC's multiarch feature (if supported; if not, + # GCC prints nothing and exits with status 0), falling back to calling + # the architecture-specific functions. + multi_index=1 + for multilib in "${multilibs[@]}"; do + multi_flags=$( echo "${multilib#*;}" | ${sed} -r -e 's/@/ -/g;' ) + multi_dir="${multilib%%;*}" + multi_os_dir=$( "${CT_TARGET}-gcc" -print-multi-os-directory ${multi_flags} ) + multi_root=$( "${CT_TARGET}-gcc" -print-sysroot ${multi_flags} ) + multi_target=$( "${CT_TARGET}-gcc" -print-multiarch ${multi_flags} ) + root_suffix="${multi_root#${CT_SYSROOT_DIR}}" + + # If GCC did not report the target tuple (i.e. this configuration is not + # multiarch-capable), fall back to our guesswork. + if [ -z "${multi_target}" ]; then + multi_target="${CT_TARGET}" + CT_DoArchMultilibTarget multi_target ${multi_flags} + fi + + # Avoid multi_os_dir if it's the only directory in this sysroot. + if [ -e "sysroot-check${root_suffix}/unique" ]; then + multi_os_dir=. + fi + + CT_mkdir_pushd "${prefix}_${multi_dir//\//_}" + $func multi_dir="${multi_dir}" \ + multi_os_dir="${multi_os_dir}" \ + multi_flags="${multi_flags}" \ + multi_root="${multi_root}" \ + multi_target="${multi_target}" \ + multi_index="${multi_index}" \ + multi_count="${#multilibs[@]}" \ + "$@" + CT_Popd + multi_index=$((multi_index+1)) + done +} |