| #!/usr/bin/env bash |
| set -e |
| |
| TOOLCHAINS_CSV='support/config-fragments/autobuild/toolchain-configs.csv' |
| |
| main() { |
| local o O opts |
| local cfg dir pkg random toolchains_dir toolchain |
| local ret nb nb_skip nb_fail nb_legal nb_tc build_dir |
| local -a toolchains |
| |
| o='hc:d:p:r:t:' |
| O='help,config-snippet:build-dir:package:,random:,toolchains-dir:' |
| opts="$(getopt -n "${my_name}" -o "${o}" -l "${O}" -- "${@}")" |
| eval set -- "${opts}" |
| |
| random=0 |
| toolchains_csv="${TOOLCHAINS_CSV}" |
| while [ ${#} -gt 0 ]; do |
| case "${1}" in |
| (-h|--help) |
| help; exit 0 |
| ;; |
| (-c|--config-snippet) |
| cfg="${2}"; shift 2 |
| ;; |
| (-d|--build-dir) |
| dir="${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 |
| if [ -z "${cfg}" ]; then |
| printf "error: no config snippet specified\n" >&2; exit 1 |
| 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 |
| |
| # 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 |
| toolchains=($(sed -r -e 's/,.*//; /internal/d; /^#/d; /^$/d;' "${toolchains_csv}" \ |
| |if [ ${random} -gt 0 ]; then \ |
| sort -R |head -n ${random} |
| else |
| cat |
| fi |sort |
| ) |
| ) |
| |
| 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 |
| 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}" && 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";; |
| esac |
| done |
| |
| printf "%d builds, %d skipped, %d build failed, %d legal-info failed\n" \ |
| ${nb} ${nb_skip} ${nb_fail} ${nb_legal} |
| } |
| |
| build_one() { |
| local dir="${1}" |
| local toolchainconfig="${2}" |
| local cfg="${3}" |
| local pkg="${4}" |
| |
| mkdir -p "${dir}" |
| |
| support/kconfig/merge_config.sh -O "${dir}" \ |
| "${toolchainconfig}" "support/config-fragments/minimal.config" "${cfg}" \ |
| > /dev/null |
| # 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 |
| return 1 |
| fi |
| # Remove file, it's empty anyway. |
| rm -f "${dir}/missing.config" |
| |
| if [ -n "${pkg}" ]; then |
| if ! make O="${dir}" "${pkg}-dirclean" >> "${dir}/logfile" 2>&1; then |
| return 2 |
| fi |
| fi |
| |
| # shellcheck disable=SC2086 |
| if ! 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 |
| } |
| |
| 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. |
| |
| 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. |
| |
| -p PKG, --package PKG |
| Test-build the package PKG, by running 'make PKG'; if not specified, |
| just runs 'make'. |
| |
| -r N, --random N |
| Limit the tests to the N randomly selected toolchains, instead of |
| building with all 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. |
| |
| 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 "${@}" |