From f2ffdf798ddcd5b471a5055c18215ca2988ddf29 Mon Sep 17 00:00:00 2001 From: Alexey Neyman Date: Tue, 5 Apr 2016 14:47:20 -0700 Subject: First stab at multilib/uClibc. Create a separate 'libc_backend_once', install headers into a subdirectory (different sets of headers are installed for 32- and 64-bit architectures), and create a symlink for the dynamic linker location expected by GCC. Signed-off-by: Alexey Neyman diff --git a/scripts/build/arch.sh b/scripts/build/arch.sh index 6414b54..b75c1be 100644 --- a/scripts/build/arch.sh +++ b/scripts/build/arch.sh @@ -29,11 +29,33 @@ CT_DoArchUClibcSelectArch() { } # uClibc: Adjust configuration file according to the CT-NG configuration -# Usage CT_DoArchUClibcConfig +# Usage: CT_DoArchUClibcConfig CT_DoArchUClibcConfig() { CT_DoLog WARN "Support for '${CT_ARCH}' is not implemented in uClibc config tweaker." CT_DoLog WARN "Exact configuration file must be provided." } +# Multilib/uClibc: Adjust configuration file for given CFLAGS +# Usage: CT_DoArchUClibcCflags +CT_DoArchUClibcCflags() { + local cfg="${1}" + local cflags="${2}" + + # Likely, any non-default cflags need to be reflected into the config. + # It may work if we just pass them into EXTRA_CFLAGS, but we have no + # idea as they might interact with the CFLAGS inferred by uClibc from + # the configuration file. + if [ "${cflags}" != "" ]; then + CT_DoLog WARN "Multilib configuration not supported for uClibc/${CT_ARCH}" + fi +} + +# Multilib/uClibc: Adjust header installation path for given CFLAGS +# Usage: CT_DoArchUClibcHeaderDir +CT_DoArchUClibcHeaderDir() { + # Only needed if a given architecture may select different uClibc architectures. + :; +} + # Override from the actual arch implementation as needed. . "${CT_LIB_DIR}/scripts/build/arch/${CT_ARCH}.sh" diff --git a/scripts/build/arch/arm.sh b/scripts/build/arch/arm.sh index 8af0072..b728311 100644 --- a/scripts/build/arch/arm.sh +++ b/scripts/build/arch/arm.sh @@ -27,7 +27,6 @@ CT_DoArchTupleValues() { thumb) CT_ARCH_CC_CORE_EXTRA_CONFIG="--with-mode=thumb" CT_ARCH_CC_EXTRA_CONFIG="--with-mode=thumb" -# CT_ARCH_TARGET_CFLAGS="-mthumb" ;; esac @@ -38,6 +37,23 @@ CT_DoArchTupleValues() { if [ "${CT_ARCH_ARM_TUPLE_USE_EABIHF}" = "y" ]; then CT_TARGET_SYS="${CT_TARGET_SYS}hf" fi + + # If building multilib, zero out any WITH_*/*_CFLAG - GCC on ARM does not allow + # any of them with multilib. + if [ "${CT_MULTILIB}" = "y" ]; then + CT_ARCH_WITH_ARCH= + CT_ARCH_WITH_ABI= + CT_ARCH_WITH_CPU= + CT_ARCH_WITH_TUNE= + CT_ARCH_WITH_FPU= + CT_ARCH_WITH_FLOAT= + CT_ARCH_ARCH_CFLAG= + CT_ARCH_ABI_CFLAG= + CT_ARCH_CPU_CFLAG= + CT_ARCH_TUNE_CFLAG= + CT_ARCH_FPU_CFLAG= + CT_ARCH_FLOAT_CFLAG= + fi } CT_DoArchUClibcConfig() { @@ -45,6 +61,15 @@ CT_DoArchUClibcConfig() { CT_DoArchUClibcSelectArch "${cfg}" "arm" + case "${CT_ARCH_ARM_MODE}" in + arm) + CT_KconfigDisableOption "COMPILE_IN_THUMB_MODE" "${cfg}" + ;; + thumb) + CT_KconfigEnableOption "COMPILE_IN_THUMB_MODE" "${cfg}" + ;; + esac + # FIXME: CONFIG_ARM_OABI does not exist in neither uClibc/uClibc-ng # FIXME: CONFIG_ARM_EABI does not seem to affect anything in either of them, too # (both check the compiler's built-in define, __ARM_EABI__ instead) except for @@ -58,3 +83,38 @@ CT_DoArchUClibcConfig() { CT_KconfigEnableOption "CONFIG_ARM_OABI" "${cfg}" fi } + +CT_DoArchUClibcCflags() { + local cfg="${1}" + local cflags="${2}" + local f + + for f in ${cflags}; do + case "${f}" in + -mthumb) + CT_KconfigEnableOption "COMPILE_IN_THUMB_MODE" "${cfg}" + ;; + -marm) + CT_KconfigDisableOption "COMPILE_IN_THUMB_MODE" "${cfg}" + ;; + -mlittle-endian) + CT_KconfigDisableOption "ARCH_BIG_ENDIAN" "${cfg}" + CT_KconfigDisableOption "ARCH_WANTS_BIG_ENDIAN" "${cfg}" + CT_KconfigEnableOption "ARCH_LITTLE_ENDIAN" "${cfg}" + CT_KconfigEnableOption "ARCH_WANTS_LITTLE_ENDIAN" "${cfg}" + ;; + -mbig-endian) + CT_KconfigEnableOption "ARCH_BIG_ENDIAN" "${cfg}" + CT_KconfigEnableOption "ARCH_WANTS_BIG_ENDIAN" "${cfg}" + CT_KconfigDisableOption "ARCH_LITTLE_ENDIAN" "${cfg}" + CT_KconfigDisableOption "ARCH_WANTS_LITTLE_ENDIAN" "${cfg}" + ;; + -mhard-float|-mfloat-abi=hard|-mfloat-abi=softfp) + CT_KconfigEnableOption "UCLIBC_HAS_FPU" "${cfg}" + ;; + -msoft-float|-mfloat-abi=soft) + CT_KconfigDisableOption "UCLIBC_HAS_FPU" "${cfg}" + ;; + esac + done +} diff --git a/scripts/build/arch/mips.sh b/scripts/build/arch/mips.sh index 030e77b..6097c89 100644 --- a/scripts/build/arch/mips.sh +++ b/scripts/build/arch/mips.sh @@ -47,3 +47,25 @@ CT_DoArchUClibcConfig() { CT_KconfigDeleteOption "CONFIG_MIPS_ISA_MIPS64" "${cfg}" CT_KconfigDeleteOption "CONFIG_MIPS_ISA_MIPS64R2" "${cfg}" } + +CT_DoArchUClibcCflags() { + local cfg="${1}" + local cflags="${2}" + local f + + for f in ${cflags}; do + case "${f}" in + -mabi=*) + CT_KconfigDisableOption "CONFIG_MIPS_O32_ABI" "${cfg}" + CT_KconfigDisableOption "CONFIG_MIPS_N32_ABI" "${cfg}" + CT_KconfigDisableOption "CONFIG_MIPS_N64_ABI" "${cfg}" + case "${f#-mabi=}" in + 32) CT_KconfigEnableOption "CONFIG_MIPS_O32_ABI" "${cfg}";; + n32) CT_KconfigEnableOption "CONFIG_MIPS_N32_ABI" "${cfg}";; + 64) CT_KconfigEnableOption "CONFIG_MIPS_N64_ABI" "${cfg}";; + *) CT_Abort "Unsupported ABI: ${f#-mabi=}";; + esac + ;; + esac + done +} diff --git a/scripts/build/arch/x86.sh b/scripts/build/arch/x86.sh index 4193278..9cd14a0 100644 --- a/scripts/build/arch/x86.sh +++ b/scripts/build/arch/x86.sh @@ -130,3 +130,40 @@ CT_DoArchUClibcConfig() { ;; esac } + +CT_DoArchUClibcCflags() { + local cfg="${1}" + local cflags="${2}" + local f + + for f in ${cflags}; do + case "${f}" in + -m64) + CT_DoArchUClibcSelectArch "${cfg}" "x86_64" + ;; + -m32) + # Since it's a part of multilib with 64-bit flavor, default + # to new architecture (i686). + CT_DoArchUClibcSelectArch "${cfg}" "i386" + CT_KconfigDisableOption "CONFIG_386" "${cfg}" + CT_KconfigDisableOption "CONFIG_486" "${cfg}" + CT_KconfigDisableOption "CONFIG_586" "${cfg}" + CT_KconfigEnableOption "CONFIG_686" "${cfg}" + ;; + -mx32) + CT_Abort "uClibc does not support x32 ABI" + ;; + esac + done +} + +CT_DoArchUClibcHeaderDir() { + local dir_var="${1}" + local cflags="${2}" + + # If it is non-default multilib, add a suffix with architecture (reported by gcc) + # to the headers installation path. + if [ -n "${cflags}" ]; then + eval "${dir_var}="$( ${CT_TARGET}-gcc -print-multiarch ${cflags} ) + fi +} diff --git a/scripts/build/libc/uClibc.sh b/scripts/build/libc/uClibc.sh index 1e2a290..822d381 100644 --- a/scripts/build/libc/uClibc.sh +++ b/scripts/build/libc/uClibc.sh @@ -63,12 +63,13 @@ do_libc() { do_libc_backend libc_mode=final } -# Common backend for 1st and 2nd passes +# Common backend for 1st and 2nd passes. do_libc_backend() { local libc_mode - local multi_os_dir multi_root multilib_dir startfiles_dir - local jflag=${CT_LIBC_UCLIBC_PARALLEL:+${JOBSFLAGS}} - local -a make_args + local -a multilibs + local multilib + local multi_dir multi_os_dir multi_flags + local ldso ldso_f ldso_d multilib_dir for arg in "$@"; do eval "${arg// /\\ }" @@ -80,14 +81,86 @@ do_libc_backend() { *) CT_Abort "Unsupported (or unset) libc_mode='${libc_mode}'";; esac + # See glibc.sh for the explanation of this magic. + multilibs=( $("${CT_TARGET}-gcc" -print-multi-lib 2>/dev/null) ) + 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} ) + + CT_DoStep INFO "Building for multilib '${multi_flags}'" + do_libc_backend_once multi_dir="${multi_dir}" \ + multi_os_dir="${multi_os_dir}" \ + multi_flags="${multi_flags}" \ + multi_root="${multi_root}" \ + libc_mode="${libc_mode}" + CT_EndStep + done + + if [ "${libc_mode}" = "final" -a "${CT_SHARED_LIBS}" = "y" ]; then + # uClibc and GCC disagree where the dynamic linker lives. uClibc always + # places it in the MULTILIB_DIR, while gcc does that for *some* variants + # and expects it in /lib for the other. So, create a symlink from lib + # to the actual location, but only if that will not override the actual + # file in /lib. Thus, need to do this after all the variants are built. + CT_mkdir_pushd "${CT_BUILD_DIR}/build-libc-test-ldso" + echo "int main(void) { return 0; }" > dummy.c + for multilib in "${multilibs[@]}"; do + multi_flags=$( echo "${multilib#*;}" | ${sed} -r -e 's/@/ -/g;' ) + multi_os_dir=$( "${CT_TARGET}-gcc" -print-multi-os-directory ${multi_flags} ) + multi_root=$( "${CT_TARGET}-gcc" -print-sysroot ${multi_flags} ) + multilib_dir="/lib/${multi_os_dir}" + CT_SanitizeVarDir multilib_dir + + CT_DoExecLog ALL "${CT_TARGET}-gcc" -o dummy dummy.c ${multi_flags} + ldso=$( ${CT_TARGET}-readelf -Wl dummy | \ + grep 'Requesting program interpreter: ' | \ + sed -e 's,.*: ,,' -e 's,\].*,,' ) + ldso_d="${ldso%/ld*.so.*}" + ldso_f="${ldso##*/}" + if [ -z "${ldso}" -o "${ldso_d}" = "${multilib_dir}" ]; then + # GCC cannot produce shared executable, or the base directory + # for ld.so is the same as the multi_os_directory + continue + fi + + # If there is no such file in the expected ldso dir, create a symlink to + # multilib_dir ld.so + if [ ! -r "${multi_root}${ldso}" ]; then + # Convert ldso_d to "how many levels we need to go up" and remove + # leading slash. + ldso_d=$( echo "${ldso_d#/}" | sed 's,[^/]\+,..,g' ) + CT_DoExecLog ALL ln -sf "${ldso_d}${multilib_dir}/${ldso_f}" \ + "${multi_root}${ldso}" + fi + done + CT_Popd + fi + + CT_EndStep +} + +# Common backend for 1st and 2nd passes, once per multilib. +do_libc_backend_once() { + local libc_mode + local multi_dir multi_os_dir multi_root multilib_dir startfiles_dir + local jflag=${CT_LIBC_UCLIBC_PARALLEL:+${JOBSFLAGS}} + local -a make_args + local build_dir + local extra_cflags f cfg_cflags cf + local hdr_install_subdir + + for arg in "$@"; do + eval "${arg// /\\ }" + done + # Simply copy files until uClibc has the ability to build out-of-tree CT_DoLog EXTRA "Copying sources to build dir" - CT_DoExecLog ALL cp -a "${CT_SRC_DIR}/${uclibc_name}-${CT_LIBC_VERSION}" \ - "${CT_BUILD_DIR}/build-libc-${libc_mode}" - cd "${CT_BUILD_DIR}/build-libc-${libc_mode}" + build_dir="${CT_BUILD_DIR}/build-libc-${libc_mode}${multi_dir//\//_}" + CT_DoExecLog ALL cp -a "${CT_SRC_DIR}/${uclibc_name}-${CT_LIBC_VERSION}" "${build_dir}" + cd "${build_dir}" - multi_os_dir=$( "${CT_TARGET}-gcc" -print-multi-os-directory ) - multi_root=$( "${CT_TARGET}-gcc" -print-sysroot ) multilib_dir="lib/${multi_os_dir}" startfiles_dir="${multi_root}/usr/${multilib_dir}" CT_SanitizeVarDir multilib_dir startfiles_dir @@ -103,7 +176,6 @@ do_libc_backend() { # - We do _not_ want to strip anything for now, in case we specifically # asked for a debug toolchain, thus the STRIPTOOL= assignment. make_args=( CROSS_COMPILE="${CT_TARGET}-" \ - UCLIBC_EXTRA_CFLAGS="-pipe" \ PREFIX="${multi_root}/" \ MULTILIB_DIR="${multilib_dir}" \ LOCALE_DATA_FILENAME="${uclibc_locale_tarball}.tgz" \ @@ -120,10 +192,45 @@ do_libc_backend() { CT_LIBC_UCLIBC_CONFIG_FILE="${CT_LIB_DIR}/contrib/uClibc-defconfigs/${uclibc_name}.config" fi - manage_uClibc_config "${CT_LIBC_UCLIBC_CONFIG_FILE}" .config - + manage_uClibc_config "${CT_LIBC_UCLIBC_CONFIG_FILE}" .config "${multi_flags}" CT_DoYes | CT_DoExecLog ALL ${make} "${make_args[@]}" oldconfig + # Now filter the multilib flags. manage_uClibc_config did the opposite of + # what Rules.mak in uClibc would do: by the multilib's CFLAGS, it determined + # the applicable configuration options. We don't want to pass the same options + # in the UCLIBC_EXTRA_CFLAGS again (on some targets, the options do not correctly + # override each other). On the other hand, we do not want to lose the options + # that are not reflected in the .config. + extra_cflags="-pipe" + { echo "include Rules.mak"; echo "show-cpu-flags:"; printf '\t@echo $(CPU_CFLAGS)\n'; } \ + > .show-cpu-cflags.mk + cfg_cflags=$( ${make} "${make_args[@]}" \ + --no-print-directory -f .show-cpu-cflags.mk show-cpu-flags ) + CT_DoExecLog ALL rm -f .show-cpu-cflags.mk + CT_DoLog DEBUG "CPU_CFLAGS detected by uClibc: ${cfg_cflags[@]}" + for f in ${multi_flags}; do + for cf in ${cfg_cflags}; do + if [ "${f}" = "${cf}" ]; then + f= + break + fi + done + if [ -n "${f}" ]; then + extra_cflags+=" ${f}" + fi + done + CT_DoLog DEBUG "Filtered multilib CFLAGS: ${extra_cflags}" + make_args+=( UCLIBC_EXTRA_CFLAGS="${extra_cflags}" ) + + # uClibc does not have a way to select the installation subdirectory for headers, + # it is always $(DEVEL_PREFIX)/include. Also, we're reinstalling the headers + # at the final stage (see the note below), we may already have the subdirectory + # in /usr/include. + CT_DoArchUClibcHeaderDir hdr_install_subdir "${multi_flags}" + if [ -n "$hdr_install_subdir" ]; then + CT_DoExecLog ALL cp -a "${multi_root}/usr/include" "${multi_root}/usr/include.saved" + fi + if [ "${libc_mode}" = "startfiles" ]; then CT_DoLog EXTRA "Building headers" CT_DoExecLog ALL ${make} "${make_args[@]}" headers @@ -146,7 +253,7 @@ do_libc_backend() { # No problem to create it for other archs. CT_DoLog EXTRA "Building dummy shared libs" CT_DoExecLog ALL "${CT_TARGET}-gcc" -nostdlib -nostartfiles \ - -shared -x c /dev/null -o libdummy.so + -shared ${multi_flags} -x c /dev/null -o libdummy.so CT_DoLog EXTRA "Installing start files" CT_DoExecLog ALL ${install} -m 0644 lib/crt1.o lib/crti.o lib/crtn.o \ @@ -182,7 +289,14 @@ do_libc_backend() { CT_DoExecLog ALL ${make} "${make_args[@]}" install fi # libc_mode == final - CT_EndStep + # Now, if installing headers into a subdirectory, put everything in its place. + # Remove the header subdirectory if it existed already. + if [ -n "$hdr_install_subdir" ]; then + CT_DoExecLog ALL mv "${multi_root}/usr/include" "${multi_root}/usr/include.new" + CT_DoExecLog ALL mv "${multi_root}/usr/include.saved" "${multi_root}/usr/include" + CT_DoExecLog ALL rm -rf "${multi_root}/usr/include/${hdr_install_subdir}" + CT_DoExecLog ALL mv "${multi_root}/usr/include.new" "${multi_root}/usr/include/${hdr_install_subdir}" + fi } # Initialises the .config file to sensible values @@ -191,6 +305,7 @@ do_libc_backend() { manage_uClibc_config() { src="$1" dst="$2" + flags="$3" # Start with fresh files CT_DoExecLog ALL cp "${src}" "${dst}" @@ -364,6 +479,7 @@ manage_uClibc_config() { # Now allow architecture to tweak as it wants CT_DoArchUClibcConfig "${dst}" + CT_DoArchUClibcCflags "${dst}" "${flags}" } do_libc_post_cc() { -- cgit v0.10.2-6-g49f6