xref: /OK3568_Linux_fs/buildroot/utils/test-pkg (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1#!/usr/bin/env bash
2set -e
3
4TOOLCHAINS_CSV='support/config-fragments/autobuild/toolchain-configs.csv'
5TEMP_CONF=""
6
7do_clean() {
8    if [ ! -z "${TEMP_CONF}" ]; then
9        rm -f "${TEMP_CONF}"
10    fi
11}
12
13main() {
14    local o O opts
15    local cfg dir pkg random toolchains_csv toolchain all number mode prepare_only
16    local ret nb nb_skip nb_fail nb_legal nb_tc build_dir keep
17    local -a toolchains
18    local pkg_br_name
19
20    o='hakc:d:n:p:r:t:'
21    O='help,all,keep,prepare-only,config-snippet:,build-dir:,number:,package:,random:,toolchains-csv:'
22    opts="$(getopt -n "${my_name}" -o "${o}" -l "${O}" -- "${@}")"
23    eval set -- "${opts}"
24
25    random=0
26    all=0
27    keep=0
28    number=0
29    mode=0
30    prepare_only=0
31    toolchains_csv="${TOOLCHAINS_CSV}"
32    while [ ${#} -gt 0 ]; do
33        case "${1}" in
34        (-h|--help)
35            help; exit 0
36            ;;
37        (-a|--all)
38            all=1; shift 1
39            ;;
40        (-k|--keep)
41            keep=1; shift 1
42            ;;
43        (--prepare-only)
44            prepare_only=1; shift 1
45            ;;
46        (-c|--config-snippet)
47            cfg="${2}"; shift 2
48            ;;
49        (-d|--build-dir)
50            dir="${2}"; shift 2
51            ;;
52        (-n|--number)
53            number="${2}"; shift 2
54            ;;
55        (-p|--package)
56            pkg="${2}"; shift 2
57            ;;
58        (-r|--random)
59            random="${2}"; shift 2
60            ;;
61        (-t|--toolchains-csv)
62            toolchains_csv="${2}"; shift 2
63            ;;
64        (--)
65            shift; break
66            ;;
67        esac
68    done
69
70    trap do_clean INT TERM HUP EXIT
71
72    if [ -z "${cfg}" ]; then
73        pkg_br_name="${pkg//-/_}"
74        pkg_br_name="BR2_PACKAGE_${pkg_br_name^^}"
75        TEMP_CONF=$(mktemp /tmp/test-${pkg}-config.XXXXXX)
76        echo "${pkg_br_name}=y" > ${TEMP_CONF}
77        cfg="${TEMP_CONF}"
78    fi
79    if [ ! -e "${cfg}" ]; then
80        printf "error: %s: no such file\n" "${cfg}" >&2; exit 1
81    fi
82    if [ -z "${dir}" ]; then
83        dir="${HOME}/br-test-pkg"
84    fi
85
86    if [ ${random} -gt 0 ]; then
87        mode=$((mode+1))
88    fi
89
90    if [ ${number} -gt 0 ]; then
91        mode=$((mode+1))
92    fi
93
94    if [ ${all} -eq 1 ]; then
95        mode=$((mode+1))
96    fi
97
98    # Default mode is to test the N first toolchains, which have been
99    # chosen to be a good selection of toolchains.
100    if [ ${mode} -eq 0 ] ; then
101        number=6
102    elif [ ${mode} -gt 1 ] ; then
103        printf "error: --all, --number and --random are mutually exclusive\n" >&2; exit 1
104    fi
105
106    # Extract the URLs of the toolchains; drop internal toolchains
107    # E.g.: http://server/path/to/name.config,arch,libc
108    #  -->  http://server/path/to/name.config
109    toolchains=($(sed -r -e 's/,.*//; /internal/d; /^#/d; /^$/d;' "${toolchains_csv}" \
110                  |if [ ${random} -gt 0 ]; then \
111                      sort -R |head -n ${random}
112                  elif [ ${number} -gt 0 ]; then \
113                      head -n ${number}
114                  else
115                      sort
116                  fi
117                 )
118               )
119
120    nb_tc="${#toolchains[@]}"
121    if [ ${nb_tc} -eq 0 ]; then
122        printf "error: no toolchain found (networking issue?)\n" >&2; exit 1
123    fi
124
125    nb=0
126    nb_skip=0
127    nb_fail=0
128    nb_legal=0
129    for toolchainconfig in "${toolchains[@]}"; do
130        : $((nb++))
131        toolchain="$(basename "${toolchainconfig}" .config)"
132        build_dir="${dir}/${toolchain}"
133        printf "%40s [%*d/%d]: " "${toolchain}" ${#nb_tc} ${nb} ${nb_tc}
134        build_one "${build_dir}" "${toolchainconfig}" "${cfg}" "${pkg}" "${prepare_only}" && ret=0 || ret=${?}
135        case ${ret} in
136        (0) printf "OK\n";;
137        (1) : $((nb_skip++)); printf "SKIPPED\n";;
138        (2) : $((nb_fail++)); printf "FAILED\n";;
139        (3) : $((nb_legal++)); printf "FAILED\n";;
140        esac
141    done
142
143    printf "%d builds, %d skipped, %d build failed, %d legal-info failed\n" \
144        ${nb} ${nb_skip} ${nb_fail} ${nb_legal}
145
146    return $((nb_fail + nb_legal))
147}
148
149build_one() {
150    local dir="${1}"
151    local toolchainconfig="${2}"
152    local cfg="${3}"
153    local pkg="${4}"
154    local prepare_only="${5}"
155
156    mkdir -p "${dir}"
157
158    CONFIG_= support/kconfig/merge_config.sh -O "${dir}" \
159        "${toolchainconfig}" "support/config-fragments/minimal.config" "${cfg}" \
160        >> "${dir}/logfile" 2>&1
161    # We want all the options from the snippet to be present as-is (set
162    # or not set) in the actual .config; if one of them is not, it means
163    # some dependency from the toolchain or arch is not available, in
164    # which case this config is untestable and we skip it.
165    # We don't care about the locale to sort in, as long as both sort are
166    # done in the same locale.
167    comm -23 <(sort "${cfg}") <(sort "${dir}/.config") >"${dir}/missing.config"
168    if [ -s "${dir}/missing.config" ]; then
169        if [ ${keep} -ne 1 ]; then
170            # Invalid configuration, drop it
171            rm -f "${dir}/.config"
172        fi
173        return 1
174    fi
175    # Remove file, it's empty anyway.
176    rm -f "${dir}/missing.config"
177
178    # Defer building the job to the caller (e.g. a gitlab pipeline)
179    if [ ${prepare_only} -eq 1 ]; then
180        return 0
181    fi
182
183    if [ -n "${pkg}" ]; then
184        if ! make O="${dir}" "${pkg}-dirclean" >> "${dir}/logfile" 2>&1; then
185            return 2
186        fi
187    fi
188
189    # shellcheck disable=SC2086
190    if ! BR_FORCE_CHECK_DEPENDENCIES=YES make O="${dir}" ${pkg} >> "${dir}/logfile" 2>&1; then
191        return 2
192    fi
193
194    # legal-info done systematically, because some packages have different
195    # sources depending on the configuration (e.g. lua-5.2 vs. lua-5.3)
196    if ! make O="${dir}" legal-info >> "${dir}/logfile" 2>&1; then
197        return 3
198    fi
199
200    # If we get here, the build was successful. Clean up the build/host
201    # directories to save disk space, unless 'keep' was set.
202    if [ ${keep} -ne 1 ]; then
203        make O="${dir}" clean >> "${dir}/logfile" 2>&1
204    fi
205}
206
207help() {
208    cat <<_EOF_
209test-pkg: test-build a package against various toolchains and architectures
210
211The supplied config snippet is appended to each toolchain config, the
212resulting configuration is checked to ensure it still contains all options
213specified in the snippet; if any is missing, the build is skipped, on the
214assumption that the package under test requires a toolchain or architecture
215feature that is missing.
216
217In case failures are noticed, you can fix the package and just re-run the
218same command again; it will re-run the test where it failed. If you did
219specify a package (with -p), the package build dir will be removed first.
220
221The list of toolchains is retrieved from ${TOOLCHAINS_CSV}.
222Only the external toolchains are tried, because building a Buildroot toolchain
223would take too long. An alternative toolchains CSV file can be specified with
224the -t option. This file should have lines consisting of the path to the
225toolchain config fragment and the required host architecture, separated by a
226comma. The config fragments should contain only the toolchain and architecture
227settings.
228
229By default, a useful subset of toolchains is tested. If needed, all
230toolchains can be tested (-a), an arbitrary number of toolchains (-n
231in order, -r for random).
232
233Options:
234
235    -h, --help
236        Print this help.
237
238    -c CFG, --config-snippet CFG
239        Use the CFG file as the source for the config snippet. This file
240        should contain all the config options required to build a package.
241
242    -d DIR, --build-dir DIR
243        Do the builds in directory DIR, one sub-dir per toolchain.
244
245    -p PKG, --package PKG
246        Test-build the package PKG, by running 'make PKG'; if not specified,
247        just runs 'make'.
248
249    -a, --all
250        Test all toolchains, instead of the default subset defined by
251        Buildroot developers.
252
253    -n N, --number N
254        Test N toolchains, in the order defined in the toolchain CSV
255        file.
256
257    -r N, --random N
258        Limit the tests to the N randomly selected toolchains.
259
260    -t CSVFILE, --toolchains-csv CSVFILE
261        CSV file containing the paths to config fragments of toolchains to
262        try. If not specified, the toolchains in ${TOOLCHAINS_CSV} will be
263        used.
264
265    -k, --keep
266        Keep the build directories even if the build succeeds.
267        Note: the logfile and configuration is always retained, even without
268        this option.
269
270    --prepare-only
271        Only prepare the .config files, but do not build them. Output the
272        list of build directories to stdout, and the status on stderr.
273
274Example:
275
276    Testing libcec would require a config snippet that contains:
277        BR2_PACKAGE_LIBCEC=y
278
279    Testing libcurl with openSSL support would require a snippet such as:
280        BR2_PACKAGE_OPENSSL=y
281        BR2_PACKAGE_LIBCURL=y
282
283_EOF_
284}
285
286my_name="${0##*/}"
287main "${@}"
288