diff options
-rw-r--r-- | config/target.in | 4 | ||||
-rw-r--r-- | scripts/build/cc/100-gcc.sh | 218 | ||||
-rw-r--r-- | scripts/build/libc/glibc.sh | 22 | ||||
-rw-r--r-- | scripts/crosstool-NG.sh.in | 10 | ||||
-rw-r--r-- | scripts/functions | 25 |
5 files changed, 224 insertions, 55 deletions
diff --git a/config/target.in b/config/target.in index 8cbaabc0..e8f0fe7d 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 57e46f93..72e9dd0a 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 cff6d95e..c419603a 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 6ae9d5d8..9a4091ab 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 62d264e3..557c0282 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 |