304 lines
9.5 KiB
Plaintext
304 lines
9.5 KiB
Plaintext
|
#!/usr/bin/env bash
|
||
|
set -e
|
||
|
|
||
|
TOOLCHAINS_CSV='support/config-fragments/autobuild/toolchain-configs.csv'
|
||
|
TEMP_CONF=""
|
||
|
|
||
|
do_clean() {
|
||
|
if [ -n "${TEMP_CONF}" ]; then
|
||
|
rm -f "${TEMP_CONF}"
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
main() {
|
||
|
local o O opts
|
||
|
local cfg dir pkg random toolchains_csv toolchain all number mode prepare_only
|
||
|
local ret nb nb_skip nb_fail nb_legal nb_show nb_tc build_dir keep
|
||
|
local -a toolchains
|
||
|
local pkg_br_name
|
||
|
|
||
|
o='hakc:d:n:p:r:t:'
|
||
|
O='help,all,keep,prepare-only,config-snippet:,build-dir:,number:,package:,random:,toolchains-csv:'
|
||
|
opts="$(getopt -n "${my_name}" -o "${o}" -l "${O}" -- "${@}")"
|
||
|
eval set -- "${opts}"
|
||
|
|
||
|
random=0
|
||
|
all=0
|
||
|
keep=0
|
||
|
number=0
|
||
|
mode=0
|
||
|
prepare_only=0
|
||
|
toolchains_csv="${TOOLCHAINS_CSV}"
|
||
|
while [ ${#} -gt 0 ]; do
|
||
|
case "${1}" in
|
||
|
(-h|--help)
|
||
|
help; exit 0
|
||
|
;;
|
||
|
(-a|--all)
|
||
|
all=1; shift 1
|
||
|
;;
|
||
|
(-k|--keep)
|
||
|
keep=1; shift 1
|
||
|
;;
|
||
|
(--prepare-only)
|
||
|
prepare_only=1; shift 1
|
||
|
;;
|
||
|
(-c|--config-snippet)
|
||
|
cfg="${2}"; shift 2
|
||
|
;;
|
||
|
(-d|--build-dir)
|
||
|
dir="${2}"; shift 2
|
||
|
;;
|
||
|
(-n|--number)
|
||
|
number="${2}"; shift 2
|
||
|
;;
|
||
|
(-p|--package)
|
||
|
pkg="${2}"; shift 2
|
||
|
;;
|
||
|
(-r|--random)
|
||
|
random="${2}"; shift 2
|
||
|
;;
|
||
|
(-t|--toolchains-csv)
|
||
|
toolchains_csv="${2}"; shift 2
|
||
|
;;
|
||
|
(--)
|
||
|
shift; break
|
||
|
;;
|
||
|
esac
|
||
|
done
|
||
|
|
||
|
trap do_clean INT TERM HUP EXIT
|
||
|
|
||
|
if [ -z "${cfg}" ]; then
|
||
|
pkg_br_name="${pkg//-/_}"
|
||
|
pkg_br_name="BR2_PACKAGE_${pkg_br_name^^}"
|
||
|
TEMP_CONF="$(mktemp /tmp/test-"${pkg}"-config.XXXXXX)"
|
||
|
echo "${pkg_br_name}=y" > "${TEMP_CONF}"
|
||
|
cfg="${TEMP_CONF}"
|
||
|
fi
|
||
|
if [ ! -e "${cfg}" ]; then
|
||
|
printf "error: %s: no such file\n" "${cfg}" >&2; exit 1
|
||
|
fi
|
||
|
if [ -z "${dir}" ]; then
|
||
|
dir="${HOME}/br-test-pkg"
|
||
|
fi
|
||
|
|
||
|
if [ "${random}" -gt 0 ]; then
|
||
|
mode=$((mode+1))
|
||
|
fi
|
||
|
|
||
|
if [ "${number}" -gt 0 ]; then
|
||
|
mode=$((mode+1))
|
||
|
fi
|
||
|
|
||
|
if [ "${all}" -eq 1 ]; then
|
||
|
mode=$((mode+1))
|
||
|
fi
|
||
|
|
||
|
# Default mode is to test the N first toolchains, which have been
|
||
|
# chosen to be a good selection of toolchains.
|
||
|
if [ ${mode} -eq 0 ] ; then
|
||
|
number=6
|
||
|
elif [ ${mode} -gt 1 ] ; then
|
||
|
printf "error: --all, --number and --random are mutually exclusive\n" >&2; exit 1
|
||
|
fi
|
||
|
|
||
|
# Extract the URLs of the toolchains; drop internal toolchains
|
||
|
# E.g.: http://server/path/to/name.config,arch,libc
|
||
|
# --> http://server/path/to/name.config
|
||
|
mapfile -t toolchains < <(sed -r -e 's/,.*//; /internal/d; /^#/d; /^$/d;' "${toolchains_csv}" \
|
||
|
| if [ "${random}" -gt 0 ]; then \
|
||
|
sort -R | head -n "${random}"
|
||
|
elif [ "${number}" -gt 0 ]; then \
|
||
|
head -n "${number}"
|
||
|
else
|
||
|
sort
|
||
|
fi
|
||
|
)
|
||
|
|
||
|
nb_tc="${#toolchains[@]}"
|
||
|
if [ "${nb_tc}" -eq 0 ]; then
|
||
|
printf "error: no toolchain found (networking issue?)\n" >&2; exit 1
|
||
|
fi
|
||
|
|
||
|
nb=0
|
||
|
nb_skip=0
|
||
|
nb_fail=0
|
||
|
nb_legal=0
|
||
|
nb_show=0
|
||
|
for toolchainconfig in "${toolchains[@]}"; do
|
||
|
: $((nb++))
|
||
|
toolchain="$(basename "${toolchainconfig}" .config)"
|
||
|
build_dir="${dir}/${toolchain}"
|
||
|
printf "%40s [%*d/%d]: " "${toolchain}" ${#nb_tc} "${nb}" "${nb_tc}"
|
||
|
build_one "${build_dir}" "${toolchainconfig}" "${cfg}" "${pkg}" "${prepare_only}" && ret=0 || ret=${?}
|
||
|
case ${ret} in
|
||
|
(0) printf "OK\n";;
|
||
|
(1) : $((nb_skip++)); printf "SKIPPED\n";;
|
||
|
(2) : $((nb_fail++)); printf "FAILED\n";;
|
||
|
(3) : $((nb_legal++)); printf "FAILED\n";;
|
||
|
(4) : $((nb_show++)); printf "FAILED\n";;
|
||
|
esac
|
||
|
done
|
||
|
|
||
|
printf "%d builds, %d skipped, %d build failed, %d legal-info failed, %d show-info failed\n" \
|
||
|
"${nb}" "${nb_skip}" "${nb_fail}" "${nb_legal}" "${nb_show}"
|
||
|
|
||
|
return $((nb_fail + nb_legal))
|
||
|
}
|
||
|
|
||
|
build_one() {
|
||
|
local dir="${1}"
|
||
|
local toolchainconfig="${2}"
|
||
|
local cfg="${3}"
|
||
|
local pkg="${4}"
|
||
|
local prepare_only="${5}"
|
||
|
|
||
|
mkdir -p "${dir}"
|
||
|
|
||
|
CONFIG_="" support/kconfig/merge_config.sh -O "${dir}" \
|
||
|
"${toolchainconfig}" "support/config-fragments/minimal.config" "${cfg}" \
|
||
|
>> "${dir}/logfile" 2>&1
|
||
|
# We want all the options from the snippet to be present as-is (set
|
||
|
# or not set) in the actual .config; if one of them is not, it means
|
||
|
# some dependency from the toolchain or arch is not available, in
|
||
|
# which case this config is untestable and we skip it.
|
||
|
# We don't care about the locale to sort in, as long as both sort are
|
||
|
# done in the same locale.
|
||
|
comm -23 <(sort "${cfg}") <(sort "${dir}/.config") >"${dir}/missing.config"
|
||
|
if [ -s "${dir}/missing.config" ]; then
|
||
|
if [ ${keep} -ne 1 ]; then
|
||
|
# Invalid configuration, drop it
|
||
|
rm -f "${dir}/.config"
|
||
|
fi
|
||
|
return 1
|
||
|
fi
|
||
|
# Remove file, it's empty anyway.
|
||
|
rm -f "${dir}/missing.config"
|
||
|
|
||
|
# Defer building the job to the caller (e.g. a gitlab pipeline)
|
||
|
if [ "${prepare_only}" -eq 1 ]; then
|
||
|
return 0
|
||
|
fi
|
||
|
|
||
|
if [ -n "${pkg}" ]; then
|
||
|
if ! make O="${dir}" "${pkg}-dirclean" >> "${dir}/logfile" 2>&1; then
|
||
|
return 2
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# shellcheck disable=SC2086
|
||
|
if ! BR_FORCE_CHECK_DEPENDENCIES=YES make O="${dir}" ${pkg} >> "${dir}/logfile" 2>&1; then
|
||
|
return 2
|
||
|
fi
|
||
|
|
||
|
# legal-info done systematically, because some packages have different
|
||
|
# sources depending on the configuration (e.g. lua-5.2 vs. lua-5.3)
|
||
|
if ! make O="${dir}" legal-info >> "${dir}/logfile" 2>&1; then
|
||
|
return 3
|
||
|
fi
|
||
|
|
||
|
# Validate that we generate proper json as show-info
|
||
|
{ tput smso; printf '>>> Running show-info\n'; tput rmso; } >> "${dir}/logfile" 2> /dev/null;
|
||
|
JQ="$(which jq 2> /dev/null)"
|
||
|
if [ -z "${JQ}" ]; then
|
||
|
make O="${dir}" host-jq >> "${dir}/logfile" 2>&1
|
||
|
JQ="${dir}/host/bin/jq"
|
||
|
fi
|
||
|
if ! make O="${dir}" "${pkg:+${pkg}-}show-info" > "${dir}/info.json" 2>> "${dir}/logfile"; then
|
||
|
return 4
|
||
|
fi
|
||
|
if ! "${JQ}" . < "${dir}/info.json" >> "${dir}/logfile" 2>&1; then
|
||
|
return 4
|
||
|
fi
|
||
|
|
||
|
# If we get here, the build was successful. Clean up the build/host
|
||
|
# directories to save disk space, unless 'keep' was set.
|
||
|
if [ ${keep} -ne 1 ]; then
|
||
|
make O="${dir}" clean >> "${dir}/logfile" 2>&1
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
help() {
|
||
|
cat <<_EOF_
|
||
|
test-pkg: test-build a package against various toolchains and architectures
|
||
|
|
||
|
The supplied config snippet is appended to each toolchain config, the
|
||
|
resulting configuration is checked to ensure it still contains all options
|
||
|
specified in the snippet; if any is missing, the build is skipped, on the
|
||
|
assumption that the package under test requires a toolchain or architecture
|
||
|
feature that is missing.
|
||
|
|
||
|
In case failures are noticed, you can fix the package and just re-run the
|
||
|
same command again; it will re-run the test where it failed. If you did
|
||
|
specify a package (with -p), the package build dir will be removed first.
|
||
|
|
||
|
The list of toolchains is retrieved from ${TOOLCHAINS_CSV}.
|
||
|
Only the external toolchains are tried, because building a Buildroot toolchain
|
||
|
would take too long. An alternative toolchains CSV file can be specified with
|
||
|
the -t option. This file should have lines consisting of the path to the
|
||
|
toolchain config fragment and the required host architecture, separated by a
|
||
|
comma. The config fragments should contain only the toolchain and architecture
|
||
|
settings.
|
||
|
|
||
|
By default, a useful subset of toolchains is tested. If needed, all
|
||
|
toolchains can be tested (-a), an arbitrary number of toolchains (-n
|
||
|
in order, -r for random).
|
||
|
|
||
|
Options:
|
||
|
|
||
|
-h, --help
|
||
|
Print this help.
|
||
|
|
||
|
-c CFG, --config-snippet CFG
|
||
|
Use the CFG file as the source for the config snippet. This file
|
||
|
should contain all the config options required to build a package.
|
||
|
|
||
|
-d DIR, --build-dir DIR
|
||
|
Do the builds in directory DIR, one sub-dir per toolchain.
|
||
|
If not specified, defaults to \${HOME}/br-test-pkg
|
||
|
|
||
|
-p PKG, --package PKG
|
||
|
Test-build the package PKG, by running 'make PKG'; if not specified,
|
||
|
just runs 'make'.
|
||
|
|
||
|
-a, --all
|
||
|
Test all toolchains, instead of the default subset defined by
|
||
|
Buildroot developers.
|
||
|
|
||
|
-n N, --number N
|
||
|
Test N toolchains, in the order defined in the toolchain CSV
|
||
|
file.
|
||
|
|
||
|
-r N, --random N
|
||
|
Limit the tests to the N randomly selected toolchains.
|
||
|
|
||
|
-t CSVFILE, --toolchains-csv CSVFILE
|
||
|
CSV file containing the paths to config fragments of toolchains to
|
||
|
try. If not specified, the toolchains in ${TOOLCHAINS_CSV} will be
|
||
|
used.
|
||
|
|
||
|
-k, --keep
|
||
|
Keep the build directories even if the build succeeds.
|
||
|
Note: the logfile and configuration is always retained, even without
|
||
|
this option.
|
||
|
|
||
|
--prepare-only
|
||
|
Only prepare the .config files, but do not build them. Output the
|
||
|
list of build directories to stdout, and the status on stderr.
|
||
|
|
||
|
Example:
|
||
|
|
||
|
Testing libcec would require a config snippet that contains:
|
||
|
BR2_PACKAGE_LIBCEC=y
|
||
|
|
||
|
Testing libcurl with openSSL support would require a snippet such as:
|
||
|
BR2_PACKAGE_OPENSSL=y
|
||
|
BR2_PACKAGE_LIBCURL=y
|
||
|
|
||
|
_EOF_
|
||
|
}
|
||
|
|
||
|
my_name="${0##*/}"
|
||
|
main "${@}"
|