summaryrefslogtreecommitdiff
path: root/scripts/functions
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/functions')
-rw-r--r--scripts/functions230
1 files changed, 192 insertions, 38 deletions
diff --git a/scripts/functions b/scripts/functions
index 62d264e..3717ffd 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
}
@@ -928,7 +964,7 @@ CT_GetGit() {
else
# Woops...
CT_DoExecLog ALL rm -rf "${dir}"
- CT_DoLog Debug "Could not clone '${basename}'"
+ CT_DoLog DEBUG "Could not clone '${basename}'"
return 1
fi
}
@@ -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
+}