summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/target.in4
-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
5 files changed, 224 insertions, 55 deletions
diff --git a/config/target.in b/config/target.in
index 8cbaabc..e8f0fe7 100644
--- a/config/target.in
+++ b/config/target.in
@@ -65,9 +65,13 @@ config ARCH_REQUIRES_MULTILIB
bool
select MULTILIB
+# Multilib requires 1st core pass (i.e., pass without building libgcc)
+# to determine which target cflags vary with multilib and which must be
+# passed from the arch configuration.
config MULTILIB
bool
prompt "Build a multilib toolchain (READ HELP!!!)"
+ select CC_CORE_PASS_1_NEEDED
help
If you say 'y' here, then the toolchain will also contain the C library
optimised for some variants of the selected architecture, besides the
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