summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorAlexey Neyman <stilor@att.net>2016-03-30 19:15:54 (GMT)
committerAlexey Neyman <stilor@att.net>2016-08-23 18:00:27 (GMT)
commit82072d0cbc238000fd1547551deb198aa8c8d466 (patch)
tree47497379bd1d9a1f0c2c2bb264f3e6dc9ab81705 /scripts
parentcc86d80da26aa27c382dee5ef44d21f450b3ae60 (diff)
multilib: Determine which options may pass through.
On some arches (e.g. MIPS) the options like -mabi do not work if specified more than once (see the comment in 100-gcc.sh). Therefore, we need to determine which of the options produced by <arch>.sh can be passed to multilib builds and which must be removed (i.e., which options vary among the multilibs). This presents a chicken-and-egg problem. GCC developers, in their infinite wisdom, do not allow arbitrary multilib specification to be supplied to GCC's configure. Instead, the target (and sometimes some extra options) determine the set of multilibs - which may include different CPUs, different ABIs, different endianness, different FPUs, different floating-point ABIs, ... That is, we don't know which parts vary until we build GCC and ask it. So, the solution implemented here is: - For multilib builds, start with empty CT_ARCH_TARGET_CFLAGS/LDFLAGS. - For multilib builds, require core pass 1. Pass 1 does not build any target binaries, so at that point, our target options have not been used yet. - Provide an API to modify the environment variables for the steps that follow the current one. - As a part of multilib-related housekeeping, determine the variable part of multilibs and filter out these options; pass the rest into CT_TARGET_CFLAGS/LDFLAGS. This still does not handle extra dependencies between GCC options (like -ma implying -mcpu=X -mtune=Y, etc.) but I feel that would complicate matters too much. Let's leave this until there's a compelling case for it. Also, query GCC's sysroot suffix for targets that use it (SuperH, for example) - the default multilib may not work if the command line specifies the default option explicitly (%sysroot_suffix_spec is not aware of multilib defaults). Signed-off-by: Alexey Neyman <stilor@att.net>
Diffstat (limited to 'scripts')
-rw-r--r--scripts/build/cc/100-gcc.sh218
-rw-r--r--scripts/build/libc/glibc.sh22
-rw-r--r--scripts/crosstool-NG.sh.in10
-rw-r--r--scripts/functions25
4 files changed, 220 insertions, 55 deletions
diff --git a/scripts/build/cc/100-gcc.sh b/scripts/build/cc/100-gcc.sh
index 57e46f9..72e9dd0 100644
--- a/scripts/build/cc/100-gcc.sh
+++ b/scripts/build/cc/100-gcc.sh
@@ -85,6 +85,167 @@ cc_gcc_lang_list() {
}
#------------------------------------------------------------------------------
+# Return a value of a requested GCC spec
+cc_gcc_get_spec() {
+ local spec=$1
+ local cc_and_cflags=$2
+
+ # GCC does not provide a facility to request a value of a spec string.
+ # The only way to do that I found was to augment the spec file with
+ # some dummy suffix handler that does nothing except printing it.
+ touch temp-input.spec_eval
+ {
+ echo ".spec_eval:"
+ echo "echo %(${spec})"
+ } > "tmp-specs-${spec}"
+ ${cc_and_cflags} -specs="tmp-specs-${spec}" -E temp-input.spec_eval
+}
+
+#------------------------------------------------------------------------------
+# Report the type of a GCC option
+cc_gcc_classify_opt() {
+ # Options present in multiple architectures
+ case "${1}" in
+ -march=*) echo "arch"; return;;
+ -mabi=*) echo "abi"; return;;
+ -mcpu=*|-mmcu=*) echo "cpu"; return;;
+ -mtune=*) echo "tune"; return;;
+ -mfpu=*) echo "fpu"; return;;
+ -mhard-float|-msoft-float|-mno-soft-float|-mno-float|-mfloat-abi=*|\
+ -mfpu|-mno-fpu) echo "float"; return;;
+ -EB|-EL|-mbig-endian|-mlittle-endian|-mbig|-mlittle|-meb|-mel|-mb|-ml) echo "endian"; return;;
+ -mthumb|-marm) echo "mode"; return;;
+ esac
+
+ # Arch-specific options and aliases
+ case "${CT_ARCH}" in
+ m68k)
+ case "${1}" in
+ -m68881) echo "float"; return;;
+ -m5[234]*|-mcfv4e) echo "cpu"; return;;
+ -m68*|-mc68*) echo "arch"; return;;
+ esac
+ ;;
+ mips)
+ case "${1}" in
+ -mips[1234]|-mips32|-mips32r*|-mips64|-mips64r*) echo "cpu"; return;;
+ esac
+ ;;
+ sh)
+ case "${1}" in
+ -m[12345]*) echo "cpu"; return;;
+ esac
+ esac
+
+ # All tried and failed
+ echo "unknown"
+}
+
+#------------------------------------------------------------------------------
+# This function lists the multilibs configured in the compiler (even if multilib
+# is disabled - so that it lists the default GCC/OS directory, which may differ
+# from the default 'lib'). It then performs a few multilib checks/quirks:
+#
+# 1. On SuperH target, configuring with default CPU (e.g. by supplying the target
+# name as 'sh4', which is what CT-NG does) results in the compiler being unable to
+# run if that same switch is passed to the resulting gcc (e.g. 'gcc -m4'). The reason
+# for this behavior is that the script that determines the sysroot suffix is not
+# aware of the default multilib selection, so it generates <sysroot>/m4 as the
+# suffixed sysroot. But the main driver, knowing that -m4 is the default, does not
+# even attempt to fall back to the non-suffixed sysroot (as it does with non-default
+# multilibs) - as a result, gcc fails to find any library if invoked with -m4.
+# The right solution would be to drop the default CPU from the multilib list
+# completely, or make the print-sysroot-suffix.sh script aware of the defaults
+# (which is not easy, as the defaults are not in tmake_file, but rather in tm_file...)
+#
+# 2. On MIPS target, gcc (or rather, ld, which it invokes under the hood) chokes
+# if supplied with two -mabi=* options. I.e., 'gcc -mabi=n32' and 'gcc -mabi=32' both
+# work, but 'gcc -mabi=32 -mabi=n32' produces an internal error in ld. Thus we do
+# not supply target's CFLAGS in multilib builds - and after compiling pass-1 gcc,
+# attempt to determine which CFLAGS need to be filtered out.
+cc_gcc_multilib_housekeeping() {
+ local cc host
+ local flags osdir dir multilibs i f
+ local multilib_defaults
+ local suffix sysroot base lnk
+ local ml_arch ml_abi ml_cpu ml_tune ml_fpu ml_float ml_endian ml_mode ml_unknown ml
+ local new_cflags
+
+ for arg in "$@"; do
+ eval "${arg// /\\ }"
+ done
+
+ if [ \( "${CT_CANADIAN}" = "y" -o "${CT_CROSS_NATIVE}" = "y" \) -a "${host}" = "${CT_HOST}" ]; then
+ CT_DoLog EXTRA "Canadian Cross/Cross-native unable to confirm multilibs configuration "\
+ "directly; will use build-compiler for housekeeping."
+ # Since we cannot run the desired compiler, substitute build-CC with the assumption
+ # that the host-CC is configured in the same way.
+ cc="${CT_BUILDTOOLS_PREFIX_DIR}/bin/${CT_TARGET}-gcc"
+ fi
+
+ # sed: prepend dashes or do nothing if default is empty string
+ multilib_defaults=( $( cc_gcc_get_spec multilib_defaults "${cc}" | \
+ ${sed} 's/\(^\|[[:space:]]\+\)\([^[:space:]]\)/ -\2/g' ) )
+ CT_DoLog EXTRA "gcc default flags: '${multilib_defaults}'"
+
+ multilibs=( $( "${cc}" -print-multi-lib ) )
+ if [ ${#multilibs[@]} -ne 0 ]; then
+ CT_DoLog EXTRA "gcc configured with these multilibs (including the default):"
+ for i in "${multilibs[@]}"; do
+ dir="${i%%;*}"
+ flags="${i#*;}"
+ flags=${flags//@/ -}
+ osdir=$( "${cc}" -print-multi-os-directory ${flags} )
+ CT_DoLog EXTRA " '${flags}' --> lib/${dir}/ (gcc) lib/${osdir} (os)"
+ for f in ${flags}; do
+ eval ml_`cc_gcc_classify_opt ${f}`=seen
+ done
+ done
+ else
+ CT_DoLog WARN "no multilib configuration: GCC unusable?"
+ fi
+
+ # Filtering out some of the options provided in CT-NG config. Then *prepend*
+ # them to CT_TARGET_CFLAGS, like scripts/crosstool-NG.sh does. Zero out
+ # the stashed MULTILIB flags so that we don't process them again in the passes
+ # that follow.
+ CT_DoLog DEBUG "Configured target CFLAGS: '${CT_ARCH_TARGET_CFLAGS_MULTILIB}'"
+ ml_unknown= # Pass through anything we don't know about
+ for f in ${CT_ARCH_TARGET_CFLAGS_MULTILIB}; do
+ eval ml=\$ml_`cc_gcc_classify_opt ${f}`
+ if [ "${ml}" != "seen" ]; then
+ new_cflags="${new_cflags} ${f}"
+ fi
+ done
+ CT_DoLog DEBUG "Filtered target CFLAGS: '${new_cflags}'"
+ CT_EnvModify CT_TARGET_CFLAGS "${new_cflags} ${CT_TARGET_CFLAGS}"
+ CT_EnvModify CT_ARCH_TARGET_CFLAGS_MULTILIB ""
+
+ # Currently, the only LDFLAGS are endianness-related
+ CT_DoLog DEBUG "Configured target LDFLAGS: '${CT_ARCH_TARGET_LDFLAGS_MULTILIB}'"
+ if [ "${ml_endian}" != "seen" ]; then
+ CT_EnvModify CT_TARGET_LDFLAGS "${CT_ARCH_TARGET_LDFLAGS_MULTILIB} ${CT_TARGET_LDFLAGS}"
+ CT_EnvModify CT_ARCH_TARGET_LDFLAGS_MULTILIB ""
+ fi
+ CT_DoLog DEBUG "Filtered target LDFLAGS: '${CT_ARCH_TARGET_LDFLAGS_MULTILIB}'"
+
+ # Sysroot suffix fixup for the multilib default.
+ suffix=$( cc_gcc_get_spec sysroot_suffix_spec "${cc} ${multilib_defaults}" )
+ if [ -n "${suffix}" ]; then
+ base=${suffix%/*}
+ sysroot=$( "${cc}" -print-sysroot )
+ if [ -n "${base}" ]; then
+ CT_DoExecLog ALL mkdir -p "${sysroot}${base}"
+ lnk=$( echo "${base#/}" | ${sed} -e 's,[^/]*,..,g' )
+ else
+ lnk=.
+ fi
+ CT_DoExecLog ALL rm -f "${sysroot}${suffix}"
+ CT_DoExecLog ALL ln -sfv "${lnk}" "${sysroot}${suffix}"
+ fi
+}
+
+#------------------------------------------------------------------------------
# Core gcc pass 1
do_gcc_core_pass_1() {
local -a core_opts
@@ -201,9 +362,6 @@ do_gcc_core_backend() {
local -a core_targets_install
local -a extra_user_config
local arg
- local dir
- local flags
- local osdir
for arg in "$@"; do
eval "${arg// /\\ }"
@@ -542,7 +700,7 @@ do_gcc_core_backend() {
# tree makes the libtoolized utilities that are built next assume
# that, for example, libsupc++ is an "accessory library", and not include
# -lsupc++ to the link flags. That breaks ltrace, for example.
- CT_DoLog EXTRA "Housekeeping for final gcc compiler"
+ CT_DoLog EXTRA "Housekeeping for core gcc compiler"
CT_Pushd "${prefix}"
find . -type f -name "*.la" -exec rm {} \; |CT_DoLog ALL
CT_Popd
@@ -563,32 +721,8 @@ do_gcc_core_backend() {
CT_DoExecLog ALL ln -sfv "${CT_TARGET}-gcc${ext}" "${prefix}/bin/${CT_TARGET}-cc${ext}"
fi
- if [ "${CT_CANADIAN}" = "y" -a "${mode}" = "baremetal" \
- -a "${host}" = "${CT_HOST}" ]; then
- CT_DoLog EXTRA "Canadian Cross unable to confirm multilibs configured correctly"
- else
- multilibs=( $( "${prefix}/bin/${CT_TARGET}-gcc" -print-multi-lib ) )
- if [ ${#multilibs[@]} -ne 0 ]; then
- CT_DoLog EXTRA "gcc configured with these multilibs (including the default):"
- for i in "${multilibs[@]}"; do
- dir="${i%%;*}"
- flags="${i#*;}"
- flags=${flags//@/ -}
- osdir=$( "${prefix}/bin/${CT_TARGET}-gcc" -print-multi-os-directory ${flags} )
- CT_DoLog EXTRA " '${flags}' --> lib/${dir}/ (gcc) lib/${osdir} (os)"
- # When building core GCC, create the necessary directories for libc & friends.
- case "${build_step}" in
- core1|core2)
- CT_DoExecLog ALL mkdir -p "${CT_PREFIX_DIR}/lib/${osdir}"
- CT_DoExecLog ALL mkdir -p "${CT_SYSROOT_DIR}/lib/${osdir}"
- CT_DoExecLog ALL mkdir -p "${CT_SYSROOT_DIR}/usr/lib/${osdir}"
- ;;
- esac
- done
- else
- CT_DoLog WARN "no multilib configuration: GCC unusable?"
- fi
- fi
+ cc_gcc_multilib_housekeeping cc="${prefix}/bin/${CT_TARGET}-gcc" \
+ host="${host}"
}
#------------------------------------------------------------------------------
@@ -695,9 +829,6 @@ do_gcc_backend() {
local -a final_LDFLAGS
local tmp
local arg
- local dir
- local flags
- local osdir
for arg in "$@"; do
eval "${arg// /\\ }"
@@ -978,24 +1109,9 @@ do_gcc_backend() {
file="$( ls -1 "${CT_PREFIX_DIR}/bin/${CT_TARGET}-gcc."* 2>/dev/null || true )"
[ -z "${file}" ] || ext=".${file##*.}"
if [ -f "${CT_PREFIX_DIR}/bin/${CT_TARGET}-gcc${ext}" ]; then
- CT_DoExecLog ALL ln -sfv "${CT_TARGET}-gcc${ext}" "${CT_PREFIX_DIR}/bin/${CT_TARGET}-cc${ext}"
+ CT_DoExecLog ALL ln -sfv "${CT_TARGET}-gcc${ext}" "${prefix}/bin/${CT_TARGET}-cc${ext}"
fi
- if [ "${CT_CANADIAN}" = "y" ]; then
- CT_DoLog EXTRA "Canadian Cross unable to confirm multilibs configured correctly"
- else
- multilibs=( $( "${prefix}/bin/${CT_TARGET}-gcc" -print-multi-lib ) )
- if [ ${#multilibs[@]} -ne 0 ]; then
- CT_DoLog EXTRA "gcc configured with these multilibs (including the default):"
- for i in "${multilibs[@]}"; do
- dir="${i%%;*}"
- flags="${i#*;}"
- flags=${flags//@/ -}
- osdir=$( "${prefix}/bin/${CT_TARGET}-gcc" -print-multi-os-directory $flags )
- CT_DoLog EXTRA " '${flags}' --> lib/${dir}/ (gcc) lib/${osdir} (os)"
- done
- else
- CT_DoLog WARN "no multilib configuration: GCC unusable?"
- fi
- fi
+ cc_gcc_multilib_housekeeping cc="${prefix}/bin/${CT_TARGET}-gcc" \
+ host="${host}"
}
diff --git a/scripts/build/libc/glibc.sh b/scripts/build/libc/glibc.sh
index cff6d95..c419603 100644
--- a/scripts/build/libc/glibc.sh
+++ b/scripts/build/libc/glibc.sh
@@ -111,13 +111,29 @@ do_libc_backend() {
# (default target, not multilib)
multi_last=y
fi
+
+ # 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/
+ multi_flags=$( echo "${multilib#*;}" | ${sed} -r -e 's/@/ -/g;' )
multi_dir="${multilib%%;*}"
if [ "${multi_dir}" != "." ]; then
CT_DoStep INFO "Building for multilib subdir='${multi_dir}'"
- extra_flags="$( echo "${multilib#*;}" \
- |${sed} -r -e 's/@/ -/g;' \
- )"
+ extra_flags="${multi_flags}"
extra_dir="/${multi_dir}"
# glibc install its files in ${extra_dir}/{usr/,}lib
diff --git a/scripts/crosstool-NG.sh.in b/scripts/crosstool-NG.sh.in
index 6ae9d5d..9a4091a 100644
--- a/scripts/crosstool-NG.sh.in
+++ b/scripts/crosstool-NG.sh.in
@@ -292,7 +292,7 @@ if [ -z "${CT_RESTART}" ]; then
*/*) CT_Abort "Sysroot name contains forbidden slash(es): '${CT_SYSROOT_NAME}'";;
esac
- # Arrange paths depending on wether we use sysroot or not.
+ # Arrange paths depending on whether we use sysroot or not.
if [ "${CT_USE_SYSROOT}" = "y" ]; then
CT_SYSROOT_REL_DIR="${CT_SYSROOT_DIR_PREFIX:+${CT_SYSROOT_DIR_PREFIX}/}${CT_SYSROOT_NAME}"
CT_SYSROOT_DIR="${CT_PREFIX_DIR}/${CT_TARGET}/${CT_SYSROOT_REL_DIR}"
@@ -628,6 +628,14 @@ if [ "${CT_ONLY_DOWNLOAD}" != "y" -a "${CT_ONLY_EXTRACT}" != "y" ]; then
# sub-shell ending with !0. bash-3 does not, while bash-4 does,
# so the following line is for bash-3; bash-4 would choke above.
[ $? -eq 0 ]
+ # Pick up environment changes.
+ if [ -r "${CT_BUILD_DIR}/env.modify.sh" ]; then
+ CT_DoLog DEBUG "Step '${step}' modified the environment:"
+ CT_DoExecLog DEBUG cat "${CT_BUILD_DIR}/env.modify.sh"
+ . "${CT_BUILD_DIR}/env.modify.sh"
+ CT_DoExecLog DEBUG rm -f "${CT_BUILD_DIR}/env.modify.sh"
+
+ fi
if [ "${CT_STOP}" = "${step}" ]; then
do_stop=1
fi
diff --git a/scripts/functions b/scripts/functions
index 62d264e..557c028 100644
--- a/scripts/functions
+++ b/scripts/functions
@@ -1183,6 +1183,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,6 +1311,23 @@ CT_DoBuildTargetTuple() {
# Now on for the target LDFLAGS
CT_ARCH_TARGET_LDFLAGS="${CT_ARCH_TARGET_LDFLAGS} ${CT_ARCH_ENDIAN_LDFLAG}"
+
+ # 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
}
# This function determines the target tuple for a given set of compiler