#!/bin/bash -eu # This requires: # * Native and cross GNU toolchain (gcc, gcc-$toolsarch) # * LLVM toolchain (clang, lld) # * QEMU user-space static binaries (qemu-user-static) # * rsync # * patchelf # * m4 (for sparc build) # * git (for logging the current commit) build_gnu() { echo "I: Using $("$toolsarch-gcc" --version | head -1)" echo "I: Using $("$toolsarch-ld" --version | head -1)" mkdir -p "build/gnu-$toolsarch" echo "I: Generating kernel UAPI headers for ARCH=$kernelarch" make -C ../linux "ARCH=$kernelarch" \ "INSTALL_HDR_PATH=$PWD/build/gnu-$toolsarch/linux" headers_install \ || return echo "I: Building with ARCH=$arch CROSS_COMPILE=$toolsarch- ${makeflags[*]}" make -C "build/gnu-$toolsarch" -f "$PWD/../klibc/Makefile" -j"$nproc" \ "ARCH=$arch" "CROSS_COMPILE=$toolsarch-" "KBUILD_SRC=$PWD/../klibc" \ "${makeflags[@]}" all test \ || return } build_llvm() { echo "I: Using $(clang --version | head -1)" echo "I: Using $(ld.lld --version | head -1)" mkdir -p "build/llvm-$toolsarch" echo "I: Generating kernel UAPI headers for ARCH=$kernelarch" make -C ../linux "ARCH=$kernelarch" \ "INSTALL_HDR_PATH=$PWD/build/llvm-$toolsarch/linux" headers_install \ || return echo "I: Building with ARCH=$arch CROSS_COMPILE=$toolsarch- CC='clang -target $toolsarch' HOSTCC=clang LD=ld.lld ${makeflags[*]}" make -C "build/llvm-$toolsarch" -f "$PWD/../klibc/Makefile" -j"$nproc" \ "ARCH=$arch" "CROSS_COMPILE=$toolsarch-" "KBUILD_SRC=$PWD/../klibc" \ "CC=clang -target $toolsarch" "HOSTCC=clang" "LD=ld.lld" \ "${makeflags[@]}" all test \ || return } # Some architectures have Clang but limited or missing LLD support. # The "mixed" toolchain is Clang + GNU ld. build_mixed() { echo "I: Using $(clang --version | head -1)" echo "I: Using $("$toolsarch-ld" --version | head -1)" mkdir -p "build/mixed-$toolsarch" echo "I: Generating kernel UAPI headers for ARCH=$kernelarch" make -C ../linux "ARCH=$kernelarch" \ "INSTALL_HDR_PATH=$PWD/build/mixed-$toolsarch/linux" headers_install \ || return echo "I: Building with ARCH=$arch CROSS_COMPILE=$toolsarch- CC='clang -target $toolsarch' HOSTCC=clang ${makeflags[*]}" make -C "build/mixed-$toolsarch" -f "$PWD/../klibc/Makefile" -j"$nproc" \ "ARCH=$arch" "CROSS_COMPILE=$toolsarch-" "KBUILD_SRC=$PWD/../klibc" \ "CC=clang -target $toolsarch" "HOSTCC=clang" "${makeflags[@]}" \ all test \ || return } clean() { echo "I: Cleaning" (cd ../klibc && git clean -d -f -x) rm -rf "build/$tools-$toolsarch" } qemu_prefix() { # XXX We assume build architecture is x86_64 case "$arch" in i386 | x86_64) ;; *) echo "qemu-$qemuarch-static --" ;; esac } run_built() { timeout 30 $(qemu_prefix) "$@" } patch_interp() { # Patching in a longer interpreter name can break things, so # use a short-ish relative filename test -L "build/$tools-$toolsarch/k.so" \ || ln -s usr/klibc/klibc.so "build/$tools-$toolsarch/k.so" patchelf --set-interpreter "build/$tools-$toolsarch/k.so" "$@" } run_test_program() { local flavour="$1" local progname="$2" shift 2 local logname="test-$tools-$toolsarch-$flavour-$progname.log" local err=0 case "$flavour" in static) run_built "build/$tools-$toolsarch/usr/klibc/tests/$progname" > "$logname" \ || err=$? ;; shared) patch_interp "build/$tools-$toolsarch/usr/klibc/tests/$progname.shared" run_built "build/$tools-$toolsarch/usr/klibc/tests/$progname.shared" > "$logname" \ || err=$? ;; esac if [ "$err" -eq 0 ]; then if grep -qw ERROR "$logname"; then echo "E: $progname: Error found in output" return 1 fi while [ $# -ge 1 ]; do if ! grep -qF -- "$1" "$logname"; then echo "E: $progname: Expected text '$1' not found in output" return 1 fi shift done echo "I: $progname: pass" else echo "E: $progname: fail" return 1 fi } run_shell_static() { local command="$1" if run_built "build/$tools-$toolsarch/usr/dash/static/sh" -c "$command"; then echo "I: shell '$command': pass" else echo "E: shell '$command': fail" return 1 fi } run_shell_shared() { local command="$1" patch_interp "build/$tools-$toolsarch/usr/dash/shared/sh" if run_built "build/$tools-$toolsarch/usr/dash/shared/sh" -c "$command"; then echo "I: shell '$command': pass" else echo "E: shell '$command': fail" return 1 fi } run_tests_flavour() { local flavour="$1" local err=0 run_test_program "$flavour" microhello || err=1 run_test_program "$flavour" minihello || err=1 run_test_program "$flavour" hello || err=1 run_test_program "$flavour" environ 'Verifying envp == environ... ok' \ || err=1 run_test_program "$flavour" fcntl || err=1 run_test_program "$flavour" malloctest || err=1 run_test_program "$flavour" malloctest2 || err=1 run_test_program "$flavour" opentest "Line 1 = $(head -1 /etc/passwd)" \ || err=1 run_test_program "$flavour" pipetest || err=1 run_test_program "$flavour" select || err=1 run_test_program "$flavour" setjmptest \ "calling longjmp with 256... setjmp returned 256" || err=1 run_test_program "$flavour" sigint "Signal received OK" || err=1 run_test_program "$flavour" socket || err=1 run_test_program "$flavour" sscanf || err=1 run_test_program "$flavour" stdio "Hello, World!" \ "Hello again - and some more - and some more" || err=1 run_test_program "$flavour" strlcpycat || err=1 run_test_program "$flavour" strsearch || err=1 run_test_program "$flavour" vfork || err=1 return $err } run_tests() { local err=0 run_tests_flavour static || err=1 run_shell_static "exit" || err=1 run_shell_static "$(qemu_prefix) build/$tools-$toolsarch/usr/utils/static/true; exit" || err=1 run_tests_flavour shared || err=1 run_shell_shared "exit" || err=1 patch_interp "build/$tools-$toolsarch/usr/utils/shared/true" run_shell_shared "$(qemu_prefix) build/$tools-$toolsarch/usr/utils/shared/true; exit" || err=1 return $err } process() { arch="$1" kernelarch="$2" tools="$3" toolsarch="$4" qemuarch="$5" shift 5 makeflags=("$@") if [ "$limit_arch" ] && [ "$arch" != "$limit_arch" ]; then return fi if [ "$limit_kernelarch" ] && [ "$kernelarch" != "$limit_kernelarch" ]; then return fi if [ "$limit_tools" ] && [ "$tools" != "$limit_tools" ]; then return fi if [ "$limit_toolsarch" ] && [ "$toolsarch" != "$limit_toolsarch" ]; then return fi case "$qemuarch" in *:*) export QEMU_CPU="${qemuarch#*:}" qemuarch="${qemuarch%:*}" ;; *) unset QEMU_CPU ;; esac echo "I: Architecture $arch/$tools-$toolsarch: begin" if clean && build_$tools && run_tests; then echo "I: Architecture $arch/$tools-$toolsarch: pass" clean || true else echo "E: Architecture $arch/$tools-$toolsarch: fail" fi } usage='\ Usage: test-many-klibcs [OPTIONS] Options: --architecture KLIBC-ARCH --kernel-architecture KERNEL-ARCH --tools gnu|llvm|mixed --tools-architecture GNU-TRIPLET' limit_arch= limit_kernelarch= limit_tools= limit_toolsarch= args=$(getopt -l architecture:,kernel-architecture:,tools:,tools-architecture: \ -l help -o '' -n test-many-klibcs -s bash \ -- "$@") \ || exit 2 eval set -- "$args" while true; do case "$1" in --architecture) limit_arch="$2" shift 2 ;; --kernel-architecture) limit_kernelarch="$2" shift 2 ;; --tools) limit_tools="$2" shift 2 ;; --tools-architecture) limit_toolsarch="$2" shift 2 ;; --help) echo "$usage" exit 0 ;; --) shift break ;; *) echo 'Internal error!' >&2 exit 1 ;; esac done if [ "$#" -gt 0 ]; then echo "$usage" >&2 exit 2 fi echo "I: $0 started at $(date)" echo "I: Using klibc $(GIT_DIR=../klibc/.git git describe)" echo "I: Using Linux $(make -C ../linux -s kernelversion)" nproc="$(nproc || echo 1)" echo "I: Using concurrency of $nproc" # klibc kernel tools tools arch QEMU make flags process alpha alpha gnu alpha-linux-gnu alpha # arm OABI is no longer supported in Debian. #process arm arm gnu arm-linux-gnu arm process arm arm gnu arm-linux-gnueabi arm CONFIG_AEABI=y process arm arm gnu arm-linux-gnueabihf arm CONFIG_AEABI=y CPU_ARCH=armv7-a+fp CPU_TUNE=cortex-a8 CONFIG_KLIBC_THUMB=y process arm arm llvm arm-linux-gnueabihf arm CONFIG_AEABI=y CPU_ARCH=armv7-a CPU_TUNE=cortex-a8 CONFIG_KLIBC_THUMB=y process arm64 arm64 gnu aarch64-linux-gnu aarch64 process arm64 arm64 llvm aarch64-linux-gnu aarch64 process i386 x86 gnu i686-linux-gnu i386 process i386 x86 llvm i686-linux-gnu i386 CONFIG_REGPARM= # ia64 cross-compiler is currently missing in Debian, as is QEMU support. #process ia64 ia64 gnu ia64-linux-gnu ??? process m68k m68k gnu m68k-linux-gnu m68k process mips mips gnu mips-linux-gnu mips process mips mips mixed mips-linux-gnu mips process mips64 mips gnu mips64-linux-gnuabi64 mips64 process mips64 mips mixed mips64-linux-gnuabi64 mips64 process mips mips gnu mipsel-linux-gnu mipsel process mips mips mixed mipsel-linux-gnu mipsel process mips64 mips gnu mips64el-linux-gnuabi64 mips64el process mips64 mips mixed mips64el-linux-gnuabi64 mips64el process mips mips gnu mipsisa32r6-linux-gnu mips:mips32r6-generic process mips mips mixed mipsisa32r6-linux-gnu mips:mips32r6-generic process mips64 mips gnu mipsisa64r6-linux-gnuabi64 mips64:I6400 process mips64 mips mixed mipsisa64r6-linux-gnuabi64 mips64:I6400 process mips mips gnu mipsisa32r6el-linux-gnu mipsel:mips32r6-generic process mips mips mixed mipsisa32r6el-linux-gnu mipsel:mips32r6-generic process mips64 mips gnu mipsisa64r6el-linux-gnuabi64 mips64el:I6400 process mips64 mips mixed mipsisa64r6el-linux-gnuabi64 mips64el:I6400 process parisc parisc gnu hppa-linux-gnu hppa process ppc powerpc gnu powerpc-linux-gnu ppc process ppc powerpc llvm powerpc-linux-gnu ppc process ppc64 powerpc gnu powerpc64-linux-gnu ppc64 process ppc64 powerpc mixed powerpc64-linux-gnu ppc64 process ppc64 powerpc gnu powerpc64le-linux-gnu ppc64le process ppc64 powerpc mixed powerpc64le-linux-gnu ppc64le process riscv64 riscv gnu riscv64-linux-gnu riscv64 process riscv64 riscv mixed riscv64-linux-gnu riscv64 # 32-bit s390 is no longer supported in Debian. #process s390 s390 gnu s390-linux-gnu s390 process s390x s390 gnu s390x-linux-gnu s390x process s390x s390 mixed s390x-linux-gnu s390x process sh sh gnu sh4-linux-gnu sh4 process sparc sparc gnu sparc64-linux-gnu sparc32plus LD="sparc64-linux-gnu-ld -m elf32_sparc" process sparc64 sparc gnu sparc64-linux-gnu sparc64 process sparc64 sparc mixed sparc64-linux-gnu sparc64 process x86_64 x86 gnu x86_64-linux-gnu x86_64 process x86_64 x86 llvm x86_64-linux-gnu x86_64 echo "I: $0 finished at $(date)"