summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Neyman <stilor@att.net>2016-04-05 21:47:20 (GMT)
committerAlexey Neyman <stilor@att.net>2016-08-23 18:00:27 (GMT)
commitf2ffdf798ddcd5b471a5055c18215ca2988ddf29 (patch)
treee0ab6994e184c92494f7035ccc7080dc0bf11e01
parentbf3eceb5d9b27fc65c819abe0b7f3cec704917e7 (diff)
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 <stilor@att.net>
-rw-r--r--scripts/build/arch.sh24
-rw-r--r--scripts/build/arch/arm.sh62
-rw-r--r--scripts/build/arch/mips.sh22
-rw-r--r--scripts/build/arch/x86.sh37
-rw-r--r--scripts/build/libc/uClibc.sh144
5 files changed, 273 insertions, 16 deletions
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 <config-file>
+# Usage: CT_DoArchUClibcConfig <config-file>
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 <config-file> <cflags>
+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 <path-variable> <cflags>
+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() {