blob: 0f45de0e8281ea3941b28a924db73cb09dfa2f7e [file] [log] [blame]
#!/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)"