#!/bin/bash # # linux kernel CROSS make wrapper # # It will download/unpack the cross tool chain if necessary, # then invoke make with suitable options. # # It detects ARCH in 4 ways. # # - make.i386 # make it a symlink to this script # - make.cross ARCH=i386 # - cd obj-i386; make.cross # - export ARCH=i386; make.cross # # Specify compiler and version (default is gcc): # - COMPILER=gcc-9.3.0 make.cross ARCH=arm64 # - COMPILER=clang make.cross ARCH=arm64 # # Copyright (c) 2014, Intel Corporation. # Author: Fengguang Wu # Credit: Tony Breeds for crosstool check_install_path() { if [[ $COMPILER_INSTALL_PATH ]]; then echo "Compiler will be installed in $COMPILER_INSTALL_PATH" else return 1 fi } install_packages() { local ret=0 [[ -x /usr/bin/xz ]] || { echo Please install: xz-utils or xz ret=1 } [[ -x /usr/bin/lftp ]] || { echo Please install: lftp ret=1 } [[ -x /usr/bin/ldd ]] || { echo Please install: libc-bin ret=1 } return $ret } install_dependence() { local exec=$1 local errors=$(ldd $exec | grep "not found") [[ $errors ]] || return 0 echo "$errors" | grep -q "libc.so.6.*GLIBC_" && { echo Please update: libc6 or glibc } echo "ldd $exec" echo "$errors" return 1 } download_extract() { local URL="$1" local file="$(basename $URL)" local dir="$COMPILER_INSTALL_PATH/$(basename $(dirname $URL))" mkdir -p $COMPILER_INSTALL_PATH || { echo "Can't use $COMPILER_INSTALL_PATH as compiler install path, please choose a different COMPILER_INSTALL_PATH" return 1 } mkdir -p $dir || return cd $dir || return echo lftpget -c $URL lftpget -c $URL || return cd - || return echo tar Jxf $dir/$file -C $COMPILER_INSTALL_PATH tar Jxf $dir/$file -C $COMPILER_INSTALL_PATH } install_crosstool_clang() { local URL='https://download.01.org/0day-ci/cross-package' local file='clang/clang.tar.xz' download_extract "$URL/$file" || { echo "Failed to download $URL/$file" return 1 } } install_crosstool_gcc() { [[ $URL ]] || local URL='https://download.01.org/0day-ci/cross-package' local list=/tmp/0day-ci-crosstool-files timeout 3m lftp -c "open $URL/ && find -d 3" | sort -V > $list || { echo "Cannot get list from $URL" echo "Please set new url, e.g. export URL=https://cdn.kernel.org/pub/tools/crosstool/files/bin/x86_64" return 1 } local file local gcc_arch_pattern=$(echo "${gcc_arch}" | sed 's/*/.*/g') local gcc_version [[ $COMPILER =~ - ]] && gcc_version=${COMPILER##*-} if [[ $gcc_version ]]; then # for arch has more than 1 cross tool available, like x86_64-gcc-9.3.0-nolibc_arm-linux-gnueabi.tar.xz # and x86_64-gcc-9.3.0-nolibc_arm-linux-gnueabihf.tar.xz for arm, match "arm-linux-gnueabi." instead of # "arm-linux-gnueabi" to get single tool package which match exactly. file=$(grep "${gcc_arch_pattern}\..*tar\.xz$" $list | grep "${gcc_version}" | tail -1) else file=$(grep "${gcc_arch_pattern}\..*tar\.xz$" $list | tail -1) fi [[ $file ]] || { echo "Cannot find $gcc_arch_pattern under $URL check $list" echo "Please set new url, e.g. export URL=https://cdn.kernel.org/pub/tools/crosstool/files/bin/x86_64" return 1 } rm $list download_extract "$URL/$file" || { echo "Failed to download $URL/$file" return 1 } } install_crosstool() { if [[ "$COMPILER" =~ "clang" ]]; then install_crosstool_clang || { echo "clang crosstool install failed" return 1 } else install_crosstool_gcc || { echo "gcc crosstool install failed" return 1 } fi } install_cross_compiler() { install_packages && install_crosstool } setup_gcc_exec() { gcc_exec=($COMPILER_INSTALL_PATH/${COMPILER}*/${gcc_arch}/bin/${gcc_arch}-gcc) [[ -x $gcc_exec ]] || install_cross_compiler || { echo "Install gcc cross compiler failed" return 1 } gcc_exec=($COMPILER_INSTALL_PATH/${COMPILER}*/${gcc_arch}/bin/${gcc_arch}-gcc) [[ -x $gcc_exec ]] || { echo "No cross compiler for $ARCH" return 1 } # use highest available version gcc_exec=$(tr ' ' '\n' <<< ${gcc_exec[@]} | sort -V | tail -n1) } update_path_env_for_parisc() { local gcc_arch=$1 local gcc_exec setup_gcc_exec || return gcc_path=$(dirname $gcc_exec) [[ $PATH =~ $gcc_path ]] || export PATH=$gcc_path:$PATH } setup_compiler_for_parisc() { local gcc_arch=hppa-linux update_path_env_for_parisc $gcc_arch || return if grep -s -q 'CONFIG_64BIT=y' $BUILD_DIR/.config; then # 64bit build needs both hppa-linux and hppa64-linux # > Assembler messages: # > ../arch/parisc/kernel/vdso32/sigtramp.S:39: Error: unknown pseudo-op: `.proc' # > ../arch/parisc/kernel/vdso32/restart_syscall.S:16: Error: bad or irreducible absolute expression # > ../arch/parisc/kernel/vdso32/sigtramp.S:40: Error: unknown pseudo-op: `.callinfo' gcc_arch=hppa64-linux update_path_env_for_parisc $gcc_arch || return fi echo "PATH=$PATH" } setup_compiler_for_xtensa() { local variant variant=$(grep -s -h '^CONFIG_XTENSA_VARIANT_CUSTOM_NAME=' $BUILD_DIR/.config | head -n1 | cut -f2 -d'"') if [[ "$variant" = 'fsf' ]]; then gcc_arch=$ARCH-linux elif [[ $variant ]]; then gcc_arch=xtensa-${variant}-linux else gcc_arch=$ARCH-linux fi } setup_crosstool_gcc() { local gcc_arch local gcc_exec case $ARCH in i386|x86_64) gcc_arch= ;; arc) # start to support big endian arc toolchain form gcc-9.3.0 # for earlier gcc version, will failed to find arceb-elf for # big endian arceb-elf tool chain if grep -q 'CONFIG_CPU_BIG_ENDIAN=y' $BUILD_DIR/.config; then gcc_arch=arceb-elf else gcc_arch=arc-elf fi ;; c6x) gcc_arch=$ARCH-elf ;; um) gcc_arch= ;; arm) gcc_arch=arm-linux-gnueabi ;; arm64) gcc_arch=aarch64-linux* ;; powerpc) gcc_arch=powerpc-linux grep -q 'CONFIG_PPC64=y' $BUILD_DIR/.config && { if grep -q 'CONFIG_CPU_LITTLE_ENDIAN=y' $BUILD_DIR/.config; then gcc_arch=powerpc64le-linux else gcc_arch=powerpc64-linux fi } ;; blackfin) gcc_arch=bfin-uclinux ;; sh) gcc_arch=sh4-linux ;; parisc|parisc64) setup_compiler_for_parisc || return ;; openrisc) gcc_arch=or1k-linux ;; riscv) if grep -q 'CONFIG_32BIT=y' $BUILD_DIR/.config; then gcc_arch=riscv32-linux else gcc_arch=riscv64-linux fi ;; s390) gcc_arch=s390-linux ;; tile|tilegx) gcc_arch=tilegx-linux ;; mn10300) gcc_arch=am33_2.0-linux ;; nds32) gcc_arch=nds32le-linux ;; xtensa) setup_compiler_for_xtensa ;; loongarch) gcc_arch=loongarch64-linux ;; *) gcc_arch=$ARCH-linux ;; esac if [[ $gcc_arch ]]; then setup_gcc_exec || return opt_cross="CROSS_COMPILE=${gcc_exec%gcc}" # load build-in depends libs local deplibs_path=($COMPILER_INSTALL_PATH/${COMPILER}*/${gcc_arch}/libexec/gcc/${gcc_arch}/*) deplibs_path=$(tr ' ' '\n' <<< ${deplibs_path[@]} | sort -V | tail -n1) [[ -d $deplibs_path ]] && export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$deplibs_path install_dependence "$gcc_exec" || return else opt_cross= fi return 0 } is_llvm_equal_one_supported() { [[ $kernel_version_major ]] || return [[ $kernel_version_major -lt 5 ]] && return 1 [[ $kernel_version_major -eq 5 && $kernel_version_minor -lt 7 ]] && return 1 grep -q -F "ifneq (\$(LLVM),)" Makefile || return [[ $ARCH = "s390" ]] && return 1 [[ $ARCH =~ "powerpc" || $ARCH =~ "mips" || $ARCH =~ "riscv" ]] && [[ $kernel_version_major -eq 5 && $kernel_version_minor -lt 18 ]] && return 1 return 0 } setup_crosstool_clang() { local cross_clang=("$COMPILER_INSTALL_PATH"/clang/bin/clang) [[ -x $cross_clang ]] || install_cross_compiler || { echo "Install clang compiler failed" return 1 } install_dependence "$cross_clang" || return local cross_clang_path=$(dirname $cross_clang) local opt_ldd="LD=${cross_clang_path}/ld.lld HOSTLD=${cross_clang_path}/ld.lld" local opt_objcopy="OBJCOPY=llvm-objcopy" [[ $ARCH = s390 ]] && { opt_ldd= # from binutils-s390x-linux-gnu opt_objcopy="OBJCOPY=/usr/s390x-linux-gnu/bin/objcopy" } export PATH="$cross_clang_path:$PATH" # https://www.kernel.org/doc/html/latest/kbuild/llvm.html local opt_default_cross="HOSTCC=$cross_clang CC=$cross_clang $opt_ldd $opt_objcopy \ AR=llvm-ar NM=llvm-nm STRIP=llvm-strip OBJDUMP=llvm-objdump OBJSIZE=llvm-size READELF=llvm-readelf HOSTCXX=clang++ HOSTAR=llvm-ar" local opt_llvm_ias= if is_llvm_equal_one_supported; then opt_cross="LLVM=1" [[ $kernel_version_major -lt 5 || ($kernel_version_major -eq 5 && $kernel_version_minor -lt 15) ]] && opt_llvm_ias="LLVM_IAS=1" else opt_cross=$opt_default_cross fi # TODO: CROSS_COMPILE is not necessary for new kernel if [[ $ARCH = "arm64" ]]; then opt_cross="$opt_cross CROSS_COMPILE=aarch64-linux-gnu-" elif [[ $ARCH = "arm" ]]; then opt_cross="$opt_cross CROSS_COMPILE=arm-linux-gnueabi-" elif [[ $ARCH = "s390" ]]; then opt_cross="$opt_default_cross CROSS_COMPILE=s390x-linux-gnu-" elif [[ $ARCH = "hexagon" ]]; then opt_cross="$opt_cross CROSS_COMPILE=hexagon-linux-" opt_llvm_ias="LLVM_IAS=1" elif [[ $ARCH = "powerpc" ]]; then local cross_compile='powerpc-linux-gnu-' grep -q 'CONFIG_PPC64=y' $BUILD_DIR/.config && { if grep -q 'CONFIG_CPU_LITTLE_ENDIAN=y' $BUILD_DIR/.config; then cross_compile='powerpc64le-linux-gnu-' else cross_compile='powerpc64-linux-gnu-' fi } opt_cross="$opt_cross CROSS_COMPILE=$cross_compile" [[ $kernel_version_major -eq 5 && $kernel_version_minor -gt 14 && $kernel_version_minor -lt 18 ]] && opt_llvm_ias="LLVM_IAS=0" elif [[ $ARCH = "riscv" ]]; then if grep -q 'CONFIG_32BIT=y' $BUILD_DIR/.config; then opt_cross="$opt_cross $(COMPILER=gcc && setup_crosstool_gcc && echo $opt_cross)" else opt_cross="$opt_cross CROSS_COMPILE=riscv64-linux-gnu-" fi else opt_cross="$opt_cross CROSS_COMPILE=$ARCH-linux-gnu-" fi [[ $opt_llvm_ias ]] && opt_cross="$opt_cross $opt_llvm_ias" : } setup_crosstool() { local kernel_version=$(make kernelversion) local kernel_version_major=$(echo "$kernel_version" | cut -d. -f1) local kernel_version_minor=$(echo "$kernel_version" | cut -d. -f2) if [[ "$COMPILER" =~ "clang" ]]; then setup_crosstool_clang else setup_crosstool_gcc fi } make_cross_main() { shopt -s nullglob COMPILER=${COMPILER:-"gcc"} arch_list=( alpha arc arm arm64 avr32 blackfin c6x cris csky frv h8300 hexagon i386 loongarch m32r m68k microblaze mips mn10300 nios2 openrisc parisc parisc64 powerpc riscv s390 score sh sh32 sh64 sparc sparc32 sparc64 tile tilegx tilepro um unicore32 x86 x86_64 xtensa ) if [[ ! "$0" =~ 'make.cross' && "$0" =~ make\.([a-z0-9_]+) ]]; then export ARCH="${BASH_REMATCH[1]}" elif [[ "$*" =~ ARCH=([a-z0-9_]+) ]]; then export ARCH="${BASH_REMATCH[1]}" elif [[ ${PWD##*-} =~ ^($(IFS=\| && echo "${arch_list[*]}"))$ ]]; then echo "ARCH set to ${PWD##*-}" export ARCH=${PWD##*-} elif [[ ! $ARCH ]]; then export ARCH=x86_64 fi [[ "$*" =~ ARCH=([a-z0-9_]+) ]] && [[ $ARCH != ${BASH_REMATCH[1]} ]] && { echo "Conflicting ARCH specified! $ARCH ${BASH_REMATCH[1]}" exit 1 } if [[ "$*" =~ O=([^ ]+) ]]; then BUILD_DIR="${BASH_REMATCH[1]}" elif [[ -n "$KBUILD_OUTPUT" ]]; then BUILD_DIR="$KBUILD_OUTOUT" elif [[ -d obj-$ARCH ]]; then BUILD_DIR=obj-$ARCH O=O=obj-$ARCH else BUILD_DIR="." fi check_install_path || { echo "Please set COMPILER_INSTALL_PATH to specify compiler install path" echo "E.g. COMPILER_INSTALL_PATH=\$HOME/0day COMPILER=clang make.cross ARCH=x86_64" echo exit 1 } setup_crosstool || { echo "setup_crosstool failed" exit 1 } [[ "$*" =~ (-j|--jobs) ]] || { nr_cpu=$(getconf _NPROCESSORS_CONF) opt_jobs="--jobs=$((nr_cpu * 2))" } [[ "$*" =~ "ARCH=$ARCH" ]] || { opt_arch="ARCH=$ARCH" } [[ -f arch/$ARCH/boot/dts/Makefile ]] && make_dts="CONFIG_OF_ALL_DTBS=y CONFIG_DTC=y" [[ -f .make-env ]] && source ./.make-env if [[ -d source && -L source ]]; then echo make --keep-going -C source O=$PWD $make_dts $opt_arch $opt_cross $subarch $opt_jobs "$@" exec make --keep-going -C source O=$PWD $make_dts $opt_arch $opt_cross $subarch $opt_jobs "$@" else echo make --keep-going $O $make_dts $opt_arch $opt_cross $subarch $opt_jobs "$@" exec make --keep-going $O $make_dts $opt_arch $opt_cross $subarch $opt_jobs "$@" fi } [[ "${#BASH_SOURCE[@]}" -eq 1 ]] && make_cross_main "$@"