#!/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 COMPILER=${COMPILER:-"gcc"} 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##*-} =~ ^(i386|x86_64|alpha|arc|arm|arm64|avr32|blackfin|c6x|cris|frv|h8300|hexagon|ia64|m32r|m68k|microblaze|mips|mn10300|openrisc|parisc|powerpc|s390|score|sh|sh64|sparc|sparc32|sparc64|tile|tilepro|tilegx|um|unicore32|xtensa)$ ]]; then 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]}" else BUILD_DIR="." fi shopt -s nullglob is_clang_worker() { [[ "$COMPILER" =~ "clang" ]] } 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 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 } 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 .. 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 date=$(date +'%Y%m%d') local list=/tmp/0day-ci-crosstool-files-$date local file='clang.tar.xz' [[ -f $list ]] || lftp -c "open $URL && find -d 3 > $list" || return file=$(grep $file $list | tail -1) [[ $file ]] || { echo "Cannot find $file under $URL check $list" return 1 } download_extract "$URL/$file" || { echo "Failed to download $URL/$file" return 1 } } install_crosstool_gcc() { local URL='https://download.01.org/0day-ci/cross-package' local list=/tmp/0day-ci-crosstool-files lftp -c "open $URL && find -d 3 > $list" || return 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}\." $list | grep "${gcc_version}" | tail -1) else file=$(grep "${gcc_arch_pattern}\." $list | tail -1) fi [[ $file ]] || { echo "Cannot find $gcc_arch_pattern under $URL check $list" return 1 } rm $list download_extract "$URL/$file" || { echo "Failed to download $URL/$file" return 1 } } install_crosstool() { if is_clang_worker; 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=${gcc_exec[-1]} } 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 ;; *) 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=${deplibs_path[-1]} [[ -d $deplibs_path ]] && export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$deplibs_path install_dependence "$gcc_exec" || return else opt_cross= fi 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 opt_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" 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_cross CROSS_COMPILE=s390x-linux-gnu-" elif [[ $ARCH = "hexagon" ]]; then opt_cross="LLVM=1 LLVM_IAS=1 CROSS_COMPILE=hexagon-linux-" 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" 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 } setup_crosstool() { if is_clang_worker; then setup_crosstool_clang else setup_crosstool_gcc 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" } if [ -d obj-$ARCH ]; then export KBUILD_OUTPUT=obj-$ARCH O=KBUILD_OUTPUT=obj-$ARCH fi [[ -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