blob: 06b73fd83d5a3c0b927a4d141012d954f0c77bb1 [file] [log] [blame]
jpegxl-botf84edfb2020-04-20 09:48:41 +02001#!/usr/bin/env bash
jpegxl-botbdde6442021-05-25 19:02:18 +02002# Copyright (c) the JPEG XL Project Authors. All rights reserved.
jpegxl-botff093712019-12-27 18:12:34 +01003#
jpegxl-botbdde6442021-05-25 19:02:18 +02004# Use of this source code is governed by a BSD-style
5# license that can be found in the LICENSE file.
jpegxl-botff093712019-12-27 18:12:34 +01006
7# Continuous integration helper module. This module is meant to be called from
8# the .gitlab-ci.yml file during the continuous integration build, as well as
9# from the command line for developers.
10
11set -eu
12
13OS=`uname -s`
14
15MYDIR=$(dirname $(realpath "$0"))
16
17### Environment parameters:
Zoltan Szabadka4e6d7162022-06-17 15:24:50 +020018TEST_STACK_LIMIT="${TEST_STACK_LIMIT:-256}"
jpegxl-botff093712019-12-27 18:12:34 +010019CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE:-RelWithDebInfo}
20CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH:-}
jpegxl-bot50bbf272020-06-10 14:59:11 +020021CMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER:-}
22CMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER:-}
jpegxl-bote3c58a02020-06-15 08:51:22 +020023CMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM:-}
jpegxl-botff093712019-12-27 18:12:34 +010024SKIP_TEST="${SKIP_TEST:-0}"
Zoltan Szabadka520a5de2022-05-26 18:03:07 +020025TEST_SELECTOR="${TEST_SELECTOR:-}"
jpegxl-botff093712019-12-27 18:12:34 +010026BUILD_TARGET="${BUILD_TARGET:-}"
jpegxl-botf84edfb2020-04-20 09:48:41 +020027ENABLE_WASM_SIMD="${ENABLE_WASM_SIMD:-0}"
jpegxl-botff093712019-12-27 18:12:34 +010028if [[ -n "${BUILD_TARGET}" ]]; then
29 BUILD_DIR="${BUILD_DIR:-${MYDIR}/build-${BUILD_TARGET%%-*}}"
30else
31 BUILD_DIR="${BUILD_DIR:-${MYDIR}/build}"
32fi
33# Whether we should post a message in the MR when the build fails.
34POST_MESSAGE_ON_ERROR="${POST_MESSAGE_ON_ERROR:-1}"
35
jpegxl-bot9e183e12020-10-29 12:36:26 +010036# Set default compilers to clang if not already set
37export CC=${CC:-clang}
38export CXX=${CXX:-clang++}
39
jpegxl-botf84edfb2020-04-20 09:48:41 +020040# Time limit for the "fuzz" command in seconds (0 means no limit).
41FUZZER_MAX_TIME="${FUZZER_MAX_TIME:-0}"
42
jpegxl-bot63349442020-05-25 08:56:34 +020043SANITIZER="none"
44
jpegxl-bot63349442020-05-25 08:56:34 +020045
46if [[ "${BUILD_TARGET%%-*}" == "x86_64" ||
47 "${BUILD_TARGET%%-*}" == "i686" ]]; then
48 # Default to building all targets, even if compiler baseline is SSE4
Evgenii Kliuchnikov3a4676f2022-05-27 12:56:25 +000049 HWY_BASELINE_TARGETS=${HWY_BASELINE_TARGETS:-HWY_EMU128}
jpegxl-bot63349442020-05-25 08:56:34 +020050else
51 HWY_BASELINE_TARGETS=${HWY_BASELINE_TARGETS:-}
52fi
jpegxl-botf84edfb2020-04-20 09:48:41 +020053
jpegxl-botff093712019-12-27 18:12:34 +010054# Convenience flag to pass both CMAKE_C_FLAGS and CMAKE_CXX_FLAGS
jpegxl-bot0709f3a2020-02-19 14:37:22 +010055CMAKE_FLAGS=${CMAKE_FLAGS:-}
jpegxl-botb3a65712020-02-06 13:22:22 +010056CMAKE_C_FLAGS="${CMAKE_C_FLAGS:-} ${CMAKE_FLAGS}"
57CMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS:-} ${CMAKE_FLAGS}"
jpegxl-botf84edfb2020-04-20 09:48:41 +020058
jpegxl-botb3a65712020-02-06 13:22:22 +010059CMAKE_CROSSCOMPILING_EMULATOR=${CMAKE_CROSSCOMPILING_EMULATOR:-}
jpegxl-botff093712019-12-27 18:12:34 +010060CMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS:-}
jpegxl-botf84edfb2020-04-20 09:48:41 +020061CMAKE_FIND_ROOT_PATH=${CMAKE_FIND_ROOT_PATH:-}
jpegxl-botff093712019-12-27 18:12:34 +010062CMAKE_MODULE_LINKER_FLAGS=${CMAKE_MODULE_LINKER_FLAGS:-}
63CMAKE_SHARED_LINKER_FLAGS=${CMAKE_SHARED_LINKER_FLAGS:-}
64CMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE:-}
65
jpegxl-botf84edfb2020-04-20 09:48:41 +020066if [[ "${ENABLE_WASM_SIMD}" -ne "0" ]]; then
jpegxl-bot849ebf62020-09-29 16:23:20 +020067 CMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -msimd128"
68 CMAKE_C_FLAGS="${CMAKE_C_FLAGS} -msimd128"
69 CMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS} -msimd128"
jpegxl-botf84edfb2020-04-20 09:48:41 +020070fi
71
jpegxl-bot63349442020-05-25 08:56:34 +020072if [[ ! -z "${HWY_BASELINE_TARGETS}" ]]; then
73 CMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -DHWY_BASELINE_TARGETS=${HWY_BASELINE_TARGETS}"
74fi
jpegxl-botf84edfb2020-04-20 09:48:41 +020075
jpegxl-bot0709f3a2020-02-19 14:37:22 +010076# Version inferred from the CI variables.
Alex Deymoa368d7d2021-08-06 14:45:03 +020077CI_COMMIT_SHA=${CI_COMMIT_SHA:-${GITHUB_SHA:-}}
jpegxl-bot0709f3a2020-02-19 14:37:22 +010078JPEGXL_VERSION=${JPEGXL_VERSION:-${CI_COMMIT_SHA:0:8}}
jpegxl-botff093712019-12-27 18:12:34 +010079
80# Benchmark parameters
81STORE_IMAGES=${STORE_IMAGES:-1}
82BENCHMARK_CORPORA="${MYDIR}/third_party/corpora"
83
84# Local flags passed to sanitizers.
85UBSAN_FLAGS=(
86 -fsanitize=alignment
87 -fsanitize=bool
88 -fsanitize=bounds
89 -fsanitize=builtin
90 -fsanitize=enum
91 -fsanitize=float-cast-overflow
92 -fsanitize=float-divide-by-zero
93 -fsanitize=integer-divide-by-zero
94 -fsanitize=null
95 -fsanitize=object-size
96 -fsanitize=pointer-overflow
97 -fsanitize=return
98 -fsanitize=returns-nonnull-attribute
99 -fsanitize=shift-base
100 -fsanitize=shift-exponent
101 -fsanitize=unreachable
102 -fsanitize=vla-bound
103
104 -fno-sanitize-recover=undefined
105 # Brunsli uses unaligned accesses to uint32_t, so alignment is just a warning.
106 -fsanitize-recover=alignment
107)
108# -fsanitize=function doesn't work on aarch64 and arm.
109if [[ "${BUILD_TARGET%%-*}" != "aarch64" &&
110 "${BUILD_TARGET%%-*}" != "arm" ]]; then
111 UBSAN_FLAGS+=(
112 -fsanitize=function
113 )
114fi
115if [[ "${BUILD_TARGET%%-*}" != "arm" ]]; then
116 UBSAN_FLAGS+=(
117 -fsanitize=signed-integer-overflow
118 )
119fi
120
jpegxl-bot63349442020-05-25 08:56:34 +0200121CLANG_TIDY_BIN=$(which clang-tidy-6.0 clang-tidy-7 clang-tidy-8 clang-tidy | head -n 1)
jpegxl-botff093712019-12-27 18:12:34 +0100122# Default to "cat" if "colordiff" is not installed or if stdout is not a tty.
123if [[ -t 1 ]]; then
124 COLORDIFF_BIN=$(which colordiff cat | head -n 1)
125else
126 COLORDIFF_BIN="cat"
127fi
jpegxl-botf84edfb2020-04-20 09:48:41 +0200128FIND_BIN=$(which gfind find | head -n 1)
129# "false" will disable wine64 when not installed. This won't allow
130# cross-compiling.
131WINE_BIN=$(which wine64 false | head -n 1)
jpegxl-botff093712019-12-27 18:12:34 +0100132
133CLANG_VERSION="${CLANG_VERSION:-}"
134# Detect the clang version suffix and store it in CLANG_VERSION. For example,
135# "6.0" for clang 6 or "7" for clang 7.
136detect_clang_version() {
137 if [[ -n "${CLANG_VERSION}" ]]; then
138 return 0
139 fi
140 local clang_version=$("${CC:-clang}" --version | head -n1)
jpegxl-bot35ad23d2021-01-29 00:08:06 +0100141 clang_version=${clang_version#"Debian "}
jpegxl-botff093712019-12-27 18:12:34 +0100142 local llvm_tag
143 case "${clang_version}" in
144 "clang version 6."*)
145 CLANG_VERSION="6.0"
146 ;;
jpegxl-bote3c58a02020-06-15 08:51:22 +0200147 "clang version "*)
148 # Any other clang version uses just the major version number.
149 local suffix="${clang_version#clang version }"
150 CLANG_VERSION="${suffix%%.*}"
jpegxl-bot63349442020-05-25 08:56:34 +0200151 ;;
152 "emcc"*)
153 # We can't use asan or msan in the emcc case.
154 ;;
jpegxl-botff093712019-12-27 18:12:34 +0100155 *)
156 echo "Unknown clang version: ${clang_version}" >&2
157 return 1
158 esac
159}
160
161# Temporary files cleanup hooks.
162CLEANUP_FILES=()
163cleanup() {
164 if [[ ${#CLEANUP_FILES[@]} -ne 0 ]]; then
165 rm -fr "${CLEANUP_FILES[@]}"
166 fi
167}
168
169# Executed on exit.
170on_exit() {
171 local retcode="$1"
172 # Always cleanup the CLEANUP_FILES.
173 cleanup
174
175 # Post a message in the MR when requested with POST_MESSAGE_ON_ERROR but only
176 # if the run failed and we are not running from a MR pipeline.
177 if [[ ${retcode} -ne 0 && -n "${CI_BUILD_NAME:-}" &&
178 -n "${POST_MESSAGE_ON_ERROR}" && -z "${CI_MERGE_REQUEST_ID:-}" &&
179 "${CI_BUILD_REF_NAME}" = "master" ]]; then
180 load_mr_vars_from_commit
181 { set +xeu; } 2>/dev/null
182 local message="**Run ${CI_BUILD_NAME} @ ${CI_COMMIT_SHORT_SHA} failed.**
183
184Check the output of the job at ${CI_JOB_URL:-} to see if this was your problem.
185If it was, please rollback this change or fix the problem ASAP, broken builds
186slow down development. Check if the error already existed in the previous build
187as well.
188
189Pipeline: ${CI_PIPELINE_URL}
190
191Previous build commit: ${CI_COMMIT_BEFORE_SHA}
192"
193 cmd_post_mr_comment "${message}"
194 fi
195}
196
197trap 'retcode=$?; { set +x; } 2>/dev/null; on_exit ${retcode}' INT TERM EXIT
198
199
200# These variables are populated when calling merge_request_commits().
201
202# The current hash at the top of the current branch or merge request branch (if
203# running from a merge request pipeline).
204MR_HEAD_SHA=""
205# The common ancestor between the current commit and the tracked branch, such
206# as master. This includes a list
207MR_ANCESTOR_SHA=""
208
209# Populate MR_HEAD_SHA and MR_ANCESTOR_SHA.
210merge_request_commits() {
211 { set +x; } 2>/dev/null
jpegxl-bot44778c62021-05-21 20:39:54 +0200212 # GITHUB_SHA is the current reference being build in GitHub Actions.
213 if [[ -n "${GITHUB_SHA:-}" ]]; then
Alex Deymo4ead4a12021-05-26 16:23:17 +0200214 # GitHub normally does a checkout of a merge commit on a shallow repository
215 # by default. We want to get a bit more of the history to be able to diff
216 # changes on the Pull Request if needed. This fetches 10 more commits which
217 # should be enough given that PR normally should have 1 commit.
218 git -C "${MYDIR}" fetch -q origin "${GITHUB_SHA}" --depth 10
219 MR_HEAD_SHA="$(git rev-parse "FETCH_HEAD^2" 2>/dev/null ||
220 echo "${GITHUB_SHA}")"
jpegxl-botff093712019-12-27 18:12:34 +0100221 else
jpegxl-bot44778c62021-05-21 20:39:54 +0200222 # CI_BUILD_REF is the reference currently being build in the CI workflow.
223 MR_HEAD_SHA=$(git -C "${MYDIR}" rev-parse -q "${CI_BUILD_REF:-HEAD}")
224 fi
225
226 if [[ -n "${CI_MERGE_REQUEST_IID:-}" ]]; then
jpegxl-botff093712019-12-27 18:12:34 +0100227 # Merge request pipeline in CI. In this case the upstream is called "origin"
228 # but it refers to the forked project that's the source of the merge
229 # request. We need to get the target of the merge request, for which we need
230 # to query that repository using our CI_JOB_TOKEN.
231 echo "machine gitlab.com login gitlab-ci-token password ${CI_JOB_TOKEN}" \
232 >> "${HOME}/.netrc"
233 git -C "${MYDIR}" fetch "${CI_MERGE_REQUEST_PROJECT_URL}" \
234 "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}"
235 MR_ANCESTOR_SHA=$(git -C "${MYDIR}" rev-parse -q FETCH_HEAD)
jpegxl-bot44778c62021-05-21 20:39:54 +0200236 elif [[ -n "${GITHUB_BASE_REF:-}" ]]; then
237 # Pull request workflow in GitHub Actions. GitHub checkout action uses
238 # "origin" as the remote for the git checkout.
239 git -C "${MYDIR}" fetch -q origin "${GITHUB_BASE_REF}"
240 MR_ANCESTOR_SHA=$(git -C "${MYDIR}" rev-parse -q FETCH_HEAD)
241 else
242 # We are in a local branch, not a merge request.
243 MR_ANCESTOR_SHA=$(git -C "${MYDIR}" rev-parse -q HEAD@{upstream} || true)
jpegxl-botff093712019-12-27 18:12:34 +0100244 fi
jpegxl-bot44778c62021-05-21 20:39:54 +0200245
jpegxl-botff093712019-12-27 18:12:34 +0100246 if [[ -z "${MR_ANCESTOR_SHA}" ]]; then
247 echo "Warning, not tracking any branch, using the last commit in HEAD.">&2
248 # This prints the return value with just HEAD.
249 MR_ANCESTOR_SHA=$(git -C "${MYDIR}" rev-parse -q "${MR_HEAD_SHA}^")
250 else
jpegxl-bot44778c62021-05-21 20:39:54 +0200251 # GitHub runs the pipeline on a merge commit, no need to look for the common
252 # ancestor in that case.
253 if [[ -z "${GITHUB_BASE_REF:-}" ]]; then
254 MR_ANCESTOR_SHA=$(git -C "${MYDIR}" merge-base \
255 "${MR_ANCESTOR_SHA}" "${MR_HEAD_SHA}")
256 fi
jpegxl-botff093712019-12-27 18:12:34 +0100257 fi
258 set -x
259}
260
261# Load the MR iid from the landed commit message when running not from a
262# merge request workflow. This is useful to post back results at the merge
263# request when running pipelines from master.
264load_mr_vars_from_commit() {
265 { set +x; } 2>/dev/null
266 if [[ -z "${CI_MERGE_REQUEST_IID:-}" ]]; then
267 local mr_iid=$(git rev-list --format=%B --max-count=1 HEAD |
jpegxl-bot0709f3a2020-02-19 14:37:22 +0100268 grep -F "${CI_PROJECT_URL}" | grep -F "/merge_requests" | head -n 1)
jpegxl-botff093712019-12-27 18:12:34 +0100269 # mr_iid contains a string like this if it matched:
270 # Part-of: <https://gitlab.com/wg1/jpeg-xlm/merge_requests/123456>
271 if [[ -n "${mr_iid}" ]]; then
272 mr_iid=$(echo "${mr_iid}" |
273 sed -E 's,^.*merge_requests/([0-9]+)>.*$,\1,')
274 CI_MERGE_REQUEST_IID="${mr_iid}"
275 CI_MERGE_REQUEST_PROJECT_ID=${CI_PROJECT_ID}
276 fi
277 fi
278 set -x
279}
280
281# Posts a comment to the current merge request.
282cmd_post_mr_comment() {
283 { set +x; } 2>/dev/null
284 local comment="$1"
285 if [[ -n "${BOT_TOKEN:-}" && -n "${CI_MERGE_REQUEST_IID:-}" ]]; then
286 local url="${CI_API_V4_URL}/projects/${CI_MERGE_REQUEST_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}/notes"
287 curl -X POST -g \
288 -H "PRIVATE-TOKEN: ${BOT_TOKEN}" \
289 --data-urlencode "body=${comment}" \
290 --output /dev/null \
291 "${url}"
292 fi
293 set -x
294}
295
jpegxl-botf84edfb2020-04-20 09:48:41 +0200296# Set up and export the environment variables needed by the child processes.
297export_env() {
298 if [[ "${BUILD_TARGET}" == *mingw32 ]]; then
299 # Wine needs to know the paths to the mingw dlls. These should be
300 # separated by ';'.
301 WINEPATH=$("${CC:-clang}" -print-search-dirs --target="${BUILD_TARGET}" \
302 | grep -F 'libraries: =' | cut -f 2- -d '=' | tr ':' ';')
303 # We also need our own libraries in the wine path.
304 local real_build_dir=$(realpath "${BUILD_DIR}")
jpegxl-bot9e183e12020-10-29 12:36:26 +0100305 # Some library .dll dependencies are installed in /bin:
jpegxl-botab7c5e92021-04-21 19:22:38 +0200306 export WINEPATH="${WINEPATH};${real_build_dir};${real_build_dir}/third_party/brotli;/usr/${BUILD_TARGET}/bin"
jpegxl-botf84edfb2020-04-20 09:48:41 +0200307
308 local prefix="${BUILD_DIR}/wineprefix"
309 mkdir -p "${prefix}"
310 export WINEPREFIX=$(realpath "${prefix}")
311 fi
jpegxl-bot63349442020-05-25 08:56:34 +0200312 # Sanitizers need these variables to print and properly format the stack
313 # traces:
jpegxl-bote3c58a02020-06-15 08:51:22 +0200314 LLVM_SYMBOLIZER=$("${CC:-clang}" -print-prog-name=llvm-symbolizer || true)
315 if [[ -n "${LLVM_SYMBOLIZER}" ]]; then
jpegxl-bot63349442020-05-25 08:56:34 +0200316 export ASAN_SYMBOLIZER_PATH="${LLVM_SYMBOLIZER}"
317 export MSAN_SYMBOLIZER_PATH="${LLVM_SYMBOLIZER}"
318 export UBSAN_SYMBOLIZER_PATH="${LLVM_SYMBOLIZER}"
319 fi
jpegxl-botf84edfb2020-04-20 09:48:41 +0200320}
321
jpegxl-botff093712019-12-27 18:12:34 +0100322cmake_configure() {
jpegxl-botf84edfb2020-04-20 09:48:41 +0200323 export_env
jpegxl-bot849ebf62020-09-29 16:23:20 +0200324
325 if [[ "${STACK_SIZE:-0}" == 1 ]]; then
326 # Dump the stack size of each function in the .stack_sizes section for
327 # analysis.
328 CMAKE_C_FLAGS+=" -fstack-size-section"
329 CMAKE_CXX_FLAGS+=" -fstack-size-section"
330 fi
331
jpegxl-botff093712019-12-27 18:12:34 +0100332 local args=(
333 -B"${BUILD_DIR}" -H"${MYDIR}"
334 -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}"
335 -G Ninja
336 -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}"
337 -DCMAKE_C_FLAGS="${CMAKE_C_FLAGS}"
jpegxl-botff093712019-12-27 18:12:34 +0100338 -DCMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS}"
339 -DCMAKE_MODULE_LINKER_FLAGS="${CMAKE_MODULE_LINKER_FLAGS}"
340 -DCMAKE_SHARED_LINKER_FLAGS="${CMAKE_SHARED_LINKER_FLAGS}"
jpegxl-bot0709f3a2020-02-19 14:37:22 +0100341 -DJPEGXL_VERSION="${JPEGXL_VERSION}"
jpegxl-bot63349442020-05-25 08:56:34 +0200342 -DSANITIZER="${SANITIZER}"
jpegxl-bot9e183e12020-10-29 12:36:26 +0100343 # These are not enabled by default in cmake.
344 -DJPEGXL_ENABLE_VIEWERS=ON
345 -DJPEGXL_ENABLE_PLUGINS=ON
346 -DJPEGXL_ENABLE_DEVTOOLS=ON
Alex Deymo263433d2021-06-04 21:07:43 +0200347 # We always use libfuzzer in the ci.sh wrapper.
348 -DJPEGXL_FUZZER_LINK_FLAGS="-fsanitize=fuzzer"
jpegxl-botff093712019-12-27 18:12:34 +0100349 )
jpegxl-botab7c5e92021-04-21 19:22:38 +0200350 if [[ "${BUILD_TARGET}" != *mingw32 ]]; then
351 args+=(
352 -DJPEGXL_WARNINGS_AS_ERRORS=ON
353 )
354 fi
jpegxl-botff093712019-12-27 18:12:34 +0100355 if [[ -n "${BUILD_TARGET}" ]]; then
jpegxl-botf84edfb2020-04-20 09:48:41 +0200356 local system_name="Linux"
357 if [[ "${BUILD_TARGET}" == *mingw32 ]]; then
358 # When cross-compiling with mingw the target must be set to Windows and
359 # run programs with wine.
360 system_name="Windows"
361 args+=(
362 -DCMAKE_CROSSCOMPILING_EMULATOR="${WINE_BIN}"
363 # Normally CMake automatically defines MINGW=1 when building with the
364 # mingw compiler (x86_64-w64-mingw32-gcc) but we are normally compiling
365 # with clang.
366 -DMINGW=1
367 )
368 fi
jpegxl-bot63349442020-05-25 08:56:34 +0200369 # EMSCRIPTEN toolchain sets the right values itself
370 if [[ "${BUILD_TARGET}" != wasm* ]]; then
371 # If set, BUILD_TARGET must be the target triplet such as
372 # x86_64-unknown-linux-gnu.
373 args+=(
374 -DCMAKE_C_COMPILER_TARGET="${BUILD_TARGET}"
375 -DCMAKE_CXX_COMPILER_TARGET="${BUILD_TARGET}"
376 # Only the first element of the target triplet.
377 -DCMAKE_SYSTEM_PROCESSOR="${BUILD_TARGET%%-*}"
378 -DCMAKE_SYSTEM_NAME="${system_name}"
Luca Versarief97fe02022-05-10 21:36:43 +0200379 -DCMAKE_TOOLCHAIN_FILE="${CMAKE_TOOLCHAIN_FILE}"
jpegxl-bot63349442020-05-25 08:56:34 +0200380 )
jpegxl-bot849ebf62020-09-29 16:23:20 +0200381 else
jpegxl-bot849ebf62020-09-29 16:23:20 +0200382 args+=(
Luca Versarief97fe02022-05-10 21:36:43 +0200383 # sjpeg confuses WASM SIMD with SSE.
jpegxl-bot849ebf62020-09-29 16:23:20 +0200384 -DSJPEG_ENABLE_SIMD=OFF
Luca Versarief97fe02022-05-10 21:36:43 +0200385 # Building shared libs is not very useful for WASM.
386 -DBUILD_SHARED_LIBS=OFF
jpegxl-bot849ebf62020-09-29 16:23:20 +0200387 )
jpegxl-bot63349442020-05-25 08:56:34 +0200388 fi
jpegxl-botff093712019-12-27 18:12:34 +0100389 args+=(
jpegxl-botff093712019-12-27 18:12:34 +0100390 # These are needed to make googletest work when cross-compiling.
391 -DCMAKE_CROSSCOMPILING=1
392 -DHAVE_STD_REGEX=0
393 -DHAVE_POSIX_REGEX=0
394 -DHAVE_GNU_POSIX_REGEX=0
395 -DHAVE_STEADY_CLOCK=0
396 -DHAVE_THREAD_SAFETY_ATTRIBUTES=0
397 )
jpegxl-botf84edfb2020-04-20 09:48:41 +0200398 if [[ -z "${CMAKE_FIND_ROOT_PATH}" ]]; then
399 # find_package() will look in this prefix for libraries.
400 CMAKE_FIND_ROOT_PATH="/usr/${BUILD_TARGET}"
401 fi
jpegxl-bot63349442020-05-25 08:56:34 +0200402 if [[ -z "${CMAKE_PREFIX_PATH}" ]]; then
403 CMAKE_PREFIX_PATH="/usr/${BUILD_TARGET}"
404 fi
jpegxl-botf84edfb2020-04-20 09:48:41 +0200405 # Use pkg-config for the target. If there's no pkg-config available for the
406 # target we can set the PKG_CONFIG_PATH to the appropriate path in most
407 # linux distributions.
jpegxl-botff093712019-12-27 18:12:34 +0100408 local pkg_config=$(which "${BUILD_TARGET}-pkg-config" || true)
jpegxl-botf84edfb2020-04-20 09:48:41 +0200409 if [[ -z "${pkg_config}" ]]; then
410 pkg_config=$(which pkg-config)
411 export PKG_CONFIG_LIBDIR="/usr/${BUILD_TARGET}/lib/pkgconfig"
412 fi
jpegxl-botff093712019-12-27 18:12:34 +0100413 if [[ -n "${pkg_config}" ]]; then
414 args+=(-DPKG_CONFIG_EXECUTABLE="${pkg_config}")
415 fi
416 fi
jpegxl-botb3a65712020-02-06 13:22:22 +0100417 if [[ -n "${CMAKE_CROSSCOMPILING_EMULATOR}" ]]; then
418 args+=(
419 -DCMAKE_CROSSCOMPILING_EMULATOR="${CMAKE_CROSSCOMPILING_EMULATOR}"
420 )
421 fi
jpegxl-botf84edfb2020-04-20 09:48:41 +0200422 if [[ -n "${CMAKE_FIND_ROOT_PATH}" ]]; then
423 args+=(
424 -DCMAKE_FIND_ROOT_PATH="${CMAKE_FIND_ROOT_PATH}"
425 )
426 fi
jpegxl-bot63349442020-05-25 08:56:34 +0200427 if [[ -n "${CMAKE_PREFIX_PATH}" ]]; then
428 args+=(
429 -DCMAKE_PREFIX_PATH="${CMAKE_PREFIX_PATH}"
430 )
431 fi
jpegxl-bot50bbf272020-06-10 14:59:11 +0200432 if [[ -n "${CMAKE_C_COMPILER_LAUNCHER}" ]]; then
433 args+=(
434 -DCMAKE_C_COMPILER_LAUNCHER="${CMAKE_C_COMPILER_LAUNCHER}"
435 )
436 fi
437 if [[ -n "${CMAKE_CXX_COMPILER_LAUNCHER}" ]]; then
438 args+=(
439 -DCMAKE_CXX_COMPILER_LAUNCHER="${CMAKE_CXX_COMPILER_LAUNCHER}"
440 )
441 fi
jpegxl-bote3c58a02020-06-15 08:51:22 +0200442 if [[ -n "${CMAKE_MAKE_PROGRAM}" ]]; then
443 args+=(
444 -DCMAKE_MAKE_PROGRAM="${CMAKE_MAKE_PROGRAM}"
445 )
446 fi
Luca Versarief97fe02022-05-10 21:36:43 +0200447 if [[ "${BUILD_TARGET}" == wasm* ]]; then
448 emcmake cmake "${args[@]}" "$@"
449 else
450 cmake "${args[@]}" "$@"
451 fi
jpegxl-botff093712019-12-27 18:12:34 +0100452}
453
454cmake_build_and_test() {
455 # gtest_discover_tests() runs the test binaries to discover the list of tests
456 # at build time, which fails under qemu.
jpegxl-bot50bbf272020-06-10 14:59:11 +0200457 ASAN_OPTIONS=detect_leaks=0 cmake --build "${BUILD_DIR}" -- all doc
jpegxl-botff093712019-12-27 18:12:34 +0100458 # Pack test binaries if requested.
459 if [[ "${PACK_TEST:-}" == "1" ]]; then
460 (cd "${BUILD_DIR}"
jpegxl-botf84edfb2020-04-20 09:48:41 +0200461 ${FIND_BIN} -name '*.cmake' -a '!' -path '*CMakeFiles*'
Alex Deymob3a008a2021-10-25 18:15:43 +0200462 # gtest / gmock / gtest_main shared libs
463 ${FIND_BIN} lib/ -name 'libg*.so*'
jpegxl-botf84edfb2020-04-20 09:48:41 +0200464 ${FIND_BIN} -type d -name tests -a '!' -path '*CMakeFiles*'
jpegxl-botff093712019-12-27 18:12:34 +0100465 ) | tar -C "${BUILD_DIR}" -cf "${BUILD_DIR}/tests.tar.xz" -T - \
466 --use-compress-program="xz --threads=$(nproc --all || echo 1) -6"
467 du -h "${BUILD_DIR}/tests.tar.xz"
468 # Pack coverage data if also available.
469 touch "${BUILD_DIR}/gcno.sentinel"
jpegxl-botf84edfb2020-04-20 09:48:41 +0200470 (cd "${BUILD_DIR}"; echo gcno.sentinel; ${FIND_BIN} -name '*gcno') | \
jpegxl-botff093712019-12-27 18:12:34 +0100471 tar -C "${BUILD_DIR}" -cvf "${BUILD_DIR}/gcno.tar.xz" -T - \
472 --use-compress-program="xz --threads=$(nproc --all || echo 1) -6"
473 fi
474
475 if [[ "${SKIP_TEST}" -ne "1" ]]; then
476 (cd "${BUILD_DIR}"
477 export UBSAN_OPTIONS=print_stacktrace=1
jpegxl-bot56fd0222020-10-06 14:50:49 +0200478 [[ "${TEST_STACK_LIMIT}" == "none" ]] || ulimit -s "${TEST_STACK_LIMIT}"
Zoltan Szabadka520a5de2022-05-26 18:03:07 +0200479 ctest -j $(nproc --all || echo 1) ${TEST_SELECTOR} --output-on-failure)
jpegxl-botff093712019-12-27 18:12:34 +0100480 fi
481}
482
483# Configure the build to strip unused functions. This considerably reduces the
484# output size, specially for tests which only use a small part of the whole
485# library.
486strip_dead_code() {
487 # Emscripten does tree shaking without any extra flags.
Luca Versarief97fe02022-05-10 21:36:43 +0200488 if [[ "${BUILD_TARGET}" == wasm* ]]; then
jpegxl-botff093712019-12-27 18:12:34 +0100489 return 0
490 fi
491 # -ffunction-sections, -fdata-sections and -Wl,--gc-sections effectively
492 # discard all unreachable code, reducing the code size. For this to work, we
493 # need to also pass --no-export-dynamic to prevent it from exporting all the
494 # internal symbols (like functions) making them all reachable and thus not a
495 # candidate for removal.
496 CMAKE_CXX_FLAGS+=" -ffunction-sections -fdata-sections"
497 CMAKE_C_FLAGS+=" -ffunction-sections -fdata-sections"
498 if [[ "${OS}" == "Darwin" ]]; then
499 CMAKE_EXE_LINKER_FLAGS+=" -dead_strip"
500 CMAKE_SHARED_LINKER_FLAGS+=" -dead_strip"
501 else
502 CMAKE_EXE_LINKER_FLAGS+=" -Wl,--gc-sections -Wl,--no-export-dynamic"
503 CMAKE_SHARED_LINKER_FLAGS+=" -Wl,--gc-sections -Wl,--no-export-dynamic"
504 fi
505}
506
507### Externally visible commands
508
509cmd_debug() {
510 CMAKE_BUILD_TYPE="Debug"
511 cmake_configure "$@"
512 cmake_build_and_test
513}
514
515cmd_release() {
516 CMAKE_BUILD_TYPE="Release"
517 strip_dead_code
518 cmake_configure "$@"
519 cmake_build_and_test
520}
521
522cmd_opt() {
523 CMAKE_BUILD_TYPE="RelWithDebInfo"
524 CMAKE_CXX_FLAGS+=" -DJXL_DEBUG_WARNING -DJXL_DEBUG_ON_ERROR"
525 cmake_configure "$@"
526 cmake_build_and_test
527}
528
529cmd_coverage() {
jpegxl-botf2aeba72021-03-16 12:35:53 +0100530 # -O0 prohibits stack space reuse -> causes stack-overflow on dozens of tests.
531 TEST_STACK_LIMIT="none"
532
jpegxl-botff093712019-12-27 18:12:34 +0100533 cmd_release -DJPEGXL_ENABLE_COVERAGE=ON "$@"
534
535 if [[ "${SKIP_TEST}" -ne "1" ]]; then
536 # If we didn't run the test we also don't print a coverage report.
537 cmd_coverage_report
538 fi
539}
540
541cmd_coverage_report() {
jpegxl-bote3c58a02020-06-15 08:51:22 +0200542 LLVM_COV=$("${CC:-clang}" -print-prog-name=llvm-cov)
jpegxl-botf84edfb2020-04-20 09:48:41 +0200543 local real_build_dir=$(realpath "${BUILD_DIR}")
jpegxl-botff093712019-12-27 18:12:34 +0100544 local gcovr_args=(
545 -r "${real_build_dir}"
546 --gcov-executable "${LLVM_COV} gcov"
Jon Sneyers702cd542021-09-28 10:19:14 +0200547 # Only print coverage information for the libjxl directories. The rest
jpegxl-botff093712019-12-27 18:12:34 +0100548 # is not part of the code under test.
549 --filter '.*jxl/.*'
550 --exclude '.*_test.cc'
Jon Sneyersc06061c2021-09-28 13:55:29 +0200551 --exclude '.*_testonly..*'
Jon Sneyers6a587ab2021-11-18 09:45:18 +0100552 --exclude '.*_debug.*'
Jon Sneyers702cd542021-09-28 10:19:14 +0200553 --exclude '.*test_utils..*'
jpegxl-botff093712019-12-27 18:12:34 +0100554 --object-directory "${real_build_dir}"
555 )
556
557 (
558 cd "${real_build_dir}"
559 gcovr "${gcovr_args[@]}" --html --html-details \
560 --output="${real_build_dir}/coverage.html"
561 gcovr "${gcovr_args[@]}" --print-summary |
562 tee "${real_build_dir}/coverage.txt"
563 gcovr "${gcovr_args[@]}" --xml --output="${real_build_dir}/coverage.xml"
564 )
565}
566
567cmd_test() {
jpegxl-botf84edfb2020-04-20 09:48:41 +0200568 export_env
jpegxl-botff093712019-12-27 18:12:34 +0100569 # Unpack tests if needed.
570 if [[ -e "${BUILD_DIR}/tests.tar.xz" && ! -d "${BUILD_DIR}/tests" ]]; then
571 tar -C "${BUILD_DIR}" -Jxvf "${BUILD_DIR}/tests.tar.xz"
572 fi
573 if [[ -e "${BUILD_DIR}/gcno.tar.xz" && ! -d "${BUILD_DIR}/gcno.sentinel" ]]; then
574 tar -C "${BUILD_DIR}" -Jxvf "${BUILD_DIR}/gcno.tar.xz"
575 fi
576 (cd "${BUILD_DIR}"
577 export UBSAN_OPTIONS=print_stacktrace=1
jpegxl-bot56fd0222020-10-06 14:50:49 +0200578 [[ "${TEST_STACK_LIMIT}" == "none" ]] || ulimit -s "${TEST_STACK_LIMIT}"
jpegxl-botf84edfb2020-04-20 09:48:41 +0200579 ctest -j $(nproc --all || echo 1) --output-on-failure "$@")
jpegxl-botff093712019-12-27 18:12:34 +0100580}
581
jpegxl-bot5175d112021-02-23 16:59:45 +0100582cmd_gbench() {
583 export_env
584 (cd "${BUILD_DIR}"
585 export UBSAN_OPTIONS=print_stacktrace=1
586 lib/jxl_gbench \
587 --benchmark_counters_tabular=true \
588 --benchmark_out_format=json \
589 --benchmark_out=gbench.json "$@"
590 )
591}
592
Alex Deymo263433d2021-06-04 21:07:43 +0200593cmd_asanfuzz() {
Sami Boukorttdfd371e2021-11-30 18:28:19 +0100594 CMAKE_CXX_FLAGS+=" -fsanitize=fuzzer-no-link -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1"
595 CMAKE_C_FLAGS+=" -fsanitize=fuzzer-no-link -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1"
Alex Deymo263433d2021-06-04 21:07:43 +0200596 cmd_asan -DJPEGXL_ENABLE_FUZZERS=ON "$@"
597}
598
599cmd_msanfuzz() {
600 # Install msan if needed before changing the flags.
601 detect_clang_version
602 local msan_prefix="${HOME}/.msan/${CLANG_VERSION}"
603 if [[ ! -d "${msan_prefix}" || -e "${msan_prefix}/lib/libc++abi.a" ]]; then
604 # Install msan libraries for this version if needed or if an older version
605 # with libc++abi was installed.
606 cmd_msan_install
607 fi
608
Sami Boukorttdfd371e2021-11-30 18:28:19 +0100609 CMAKE_CXX_FLAGS+=" -fsanitize=fuzzer-no-link -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1"
610 CMAKE_C_FLAGS+=" -fsanitize=fuzzer-no-link -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1"
Alex Deymo263433d2021-06-04 21:07:43 +0200611 cmd_msan -DJPEGXL_ENABLE_FUZZERS=ON "$@"
612}
613
jpegxl-botff093712019-12-27 18:12:34 +0100614cmd_asan() {
jpegxl-bot63349442020-05-25 08:56:34 +0200615 SANITIZER="asan"
jpegxl-botff093712019-12-27 18:12:34 +0100616 CMAKE_C_FLAGS+=" -DJXL_ENABLE_ASSERT=1 -g -DADDRESS_SANITIZER \
617 -fsanitize=address ${UBSAN_FLAGS[@]}"
618 CMAKE_CXX_FLAGS+=" -DJXL_ENABLE_ASSERT=1 -g -DADDRESS_SANITIZER \
619 -fsanitize=address ${UBSAN_FLAGS[@]}"
620 strip_dead_code
jpegxl-botb3a65712020-02-06 13:22:22 +0100621 cmake_configure "$@" -DJPEGXL_ENABLE_TCMALLOC=OFF
jpegxl-botff093712019-12-27 18:12:34 +0100622 cmake_build_and_test
623}
624
625cmd_tsan() {
jpegxl-bot63349442020-05-25 08:56:34 +0200626 SANITIZER="tsan"
jpegxl-botff093712019-12-27 18:12:34 +0100627 local tsan_args=(
628 -DJXL_ENABLE_ASSERT=1
629 -g
630 -DTHREAD_SANITIZER
631 ${UBSAN_FLAGS[@]}
632 -fsanitize=thread
633 )
634 CMAKE_C_FLAGS+=" ${tsan_args[@]}"
635 CMAKE_CXX_FLAGS+=" ${tsan_args[@]}"
636
637 CMAKE_BUILD_TYPE="RelWithDebInfo"
638 cmake_configure "$@" -DJPEGXL_ENABLE_TCMALLOC=OFF
639 cmake_build_and_test
640}
641
642cmd_msan() {
jpegxl-bot63349442020-05-25 08:56:34 +0200643 SANITIZER="msan"
jpegxl-botff093712019-12-27 18:12:34 +0100644 detect_clang_version
645 local msan_prefix="${HOME}/.msan/${CLANG_VERSION}"
646 if [[ ! -d "${msan_prefix}" || -e "${msan_prefix}/lib/libc++abi.a" ]]; then
647 # Install msan libraries for this version if needed or if an older version
648 # with libc++abi was installed.
649 cmd_msan_install
650 fi
651
652 local msan_c_flags=(
653 -fsanitize=memory
654 -fno-omit-frame-pointer
655 -fsanitize-memory-track-origins
656
657 -DJXL_ENABLE_ASSERT=1
658 -g
659 -DMEMORY_SANITIZER
660
661 # Force gtest to not use the cxxbai.
662 -DGTEST_HAS_CXXABI_H_=0
663 )
664 local msan_cxx_flags=(
665 "${msan_c_flags[@]}"
666
667 # Some C++ sources don't use the std at all, so the -stdlib=libc++ is unused
668 # in those cases. Ignore the warning.
669 -Wno-unused-command-line-argument
670 -stdlib=libc++
671
672 # We include the libc++ from the msan directory instead, so we don't want
673 # the std includes.
674 -nostdinc++
675 -cxx-isystem"${msan_prefix}/include/c++/v1"
676 )
677
678 local msan_linker_flags=(
679 -L"${msan_prefix}"/lib
680 -Wl,-rpath -Wl,"${msan_prefix}"/lib/
681 )
682
jpegxl-botff093712019-12-27 18:12:34 +0100683 CMAKE_C_FLAGS+=" ${msan_c_flags[@]} ${UBSAN_FLAGS[@]}"
684 CMAKE_CXX_FLAGS+=" ${msan_cxx_flags[@]} ${UBSAN_FLAGS[@]}"
685 CMAKE_EXE_LINKER_FLAGS+=" ${msan_linker_flags[@]}"
686 CMAKE_MODULE_LINKER_FLAGS+=" ${msan_linker_flags[@]}"
687 CMAKE_SHARED_LINKER_FLAGS+=" ${msan_linker_flags[@]}"
688 strip_dead_code
689 cmake_configure "$@" \
jpegxl-botb3a65712020-02-06 13:22:22 +0100690 -DCMAKE_CROSSCOMPILING=1 -DRUN_HAVE_STD_REGEX=0 -DRUN_HAVE_POSIX_REGEX=0 \
Moritz Firschingfb836972021-12-30 11:47:03 +0100691 -DJPEGXL_ENABLE_TCMALLOC=OFF -DJPEGXL_WARNINGS_AS_ERRORS=OFF \
692 -DCMAKE_REQUIRED_LINK_OPTIONS="${msan_linker_flags[@]}"
jpegxl-botff093712019-12-27 18:12:34 +0100693 cmake_build_and_test
694}
695
696# Install libc++ libraries compiled with msan in the msan_prefix for the current
697# compiler version.
698cmd_msan_install() {
699 local tmpdir=$(mktemp -d)
700 CLEANUP_FILES+=("${tmpdir}")
701 # Detect the llvm to install:
702 export CC="${CC:-clang}"
703 export CXX="${CXX:-clang++}"
704 detect_clang_version
Evgenii Kliuchnikov06da4702022-07-13 09:01:26 +0000705 # Allow overriding the LLVM checkout.
Evgenii Kliuchnikov316d2ac2022-08-04 10:34:29 +0000706 local llvm_root="${LLVM_ROOT:-}"
Evgenii Kliuchnikov06da4702022-07-13 09:01:26 +0000707 if [ -z "${llvm_root}" ]; then
708 local llvm_tag="llvmorg-${CLANG_VERSION}.0.0"
709 case "${CLANG_VERSION}" in
710 "6.0")
711 llvm_tag="llvmorg-6.0.1"
712 ;;
713 "7")
714 llvm_tag="llvmorg-7.0.1"
715 ;;
716 esac
717 local llvm_targz="${tmpdir}/${llvm_tag}.tar.gz"
718 curl -L --show-error -o "${llvm_targz}" \
719 "https://github.com/llvm/llvm-project/archive/${llvm_tag}.tar.gz"
720 tar -C "${tmpdir}" -zxf "${llvm_targz}"
721 llvm_root="${tmpdir}/llvm-project-${llvm_tag}"
722 fi
jpegxl-botff093712019-12-27 18:12:34 +0100723
724 local msan_prefix="${HOME}/.msan/${CLANG_VERSION}"
725 rm -rf "${msan_prefix}"
726
727 declare -A CMAKE_EXTRAS
728 CMAKE_EXTRAS[libcxx]="\
729 -DLIBCXX_CXX_ABI=libstdc++ \
730 -DLIBCXX_INSTALL_EXPERIMENTAL_LIBRARY=ON"
731
732 for project in libcxx; do
733 local proj_build="${tmpdir}/build-${project}"
734 local proj_dir="${llvm_root}/${project}"
735 mkdir -p "${proj_build}"
736 cmake -B"${proj_build}" -H"${proj_dir}" \
737 -G Ninja \
738 -DCMAKE_BUILD_TYPE=Release \
739 -DLLVM_USE_SANITIZER=Memory \
740 -DLLVM_PATH="${llvm_root}/llvm" \
741 -DLLVM_CONFIG_PATH="$(which llvm-config llvm-config-7 llvm-config-6.0 | \
742 head -n1)" \
743 -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}" \
744 -DCMAKE_C_FLAGS="${CMAKE_C_FLAGS}" \
745 -DCMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS}" \
746 -DCMAKE_SHARED_LINKER_FLAGS="${CMAKE_SHARED_LINKER_FLAGS}" \
747 -DCMAKE_INSTALL_PREFIX="${msan_prefix}" \
748 ${CMAKE_EXTRAS[${project}]}
749 cmake --build "${proj_build}"
750 ninja -C "${proj_build}" install
751 done
752}
753
Alex Deymo13396662021-06-15 20:07:37 +0200754# Internal build step shared between all cmd_ossfuzz_* commands.
755_cmd_ossfuzz() {
756 local sanitizer="$1"
757 shift
758 mkdir -p "${BUILD_DIR}"
759 local real_build_dir=$(realpath "${BUILD_DIR}")
760
761 # oss-fuzz defines three directories:
762 # * /work, with the working directory to do re-builds
763 # * /src, with the source code to build
764 # * /out, with the output directory where to copy over the built files.
765 # We use $BUILD_DIR as the /work and the script directory as the /src. The
766 # /out directory is ignored as developers are used to look for the fuzzers in
767 # $BUILD_DIR/tools/ directly.
768
Alex Deymob1f80162021-07-15 11:45:50 +0200769 if [[ "${sanitizer}" = "memory" && ! -d "${BUILD_DIR}/msan" ]]; then
Alex Deymo13396662021-06-15 20:07:37 +0200770 sudo docker run --rm -i \
771 --user $(id -u):$(id -g) \
772 -v "${real_build_dir}":/work \
773 gcr.io/oss-fuzz-base/msan-libs-builder \
774 bash -c "cp -r /msan /work"
775 fi
776
Alex Deymob1f80162021-07-15 11:45:50 +0200777 # Args passed to ninja. These will be evaluated as a string separated by
778 # spaces.
779 local jpegxl_extra_args="$@"
780
Alex Deymo13396662021-06-15 20:07:37 +0200781 sudo docker run --rm -i \
782 -e JPEGXL_UID=$(id -u) \
783 -e JPEGXL_GID=$(id -g) \
784 -e FUZZING_ENGINE="${FUZZING_ENGINE:-libfuzzer}" \
785 -e SANITIZER="${sanitizer}" \
786 -e ARCHITECTURE=x86_64 \
787 -e FUZZING_LANGUAGE=c++ \
788 -e MSAN_LIBS_PATH="/work/msan" \
Alex Deymob1f80162021-07-15 11:45:50 +0200789 -e JPEGXL_EXTRA_ARGS="${jpegxl_extra_args}" \
Alex Deymo13396662021-06-15 20:07:37 +0200790 -v "${MYDIR}":/src/libjxl \
791 -v "${MYDIR}/tools/ossfuzz-build.sh":/src/build.sh \
792 -v "${real_build_dir}":/work \
Alex Deymo13396662021-06-15 20:07:37 +0200793 gcr.io/oss-fuzz/libjxl
794}
795
796cmd_ossfuzz_asan() {
797 _cmd_ossfuzz address "$@"
798}
799cmd_ossfuzz_msan() {
800 _cmd_ossfuzz memory "$@"
801}
802cmd_ossfuzz_ubsan() {
803 _cmd_ossfuzz undefined "$@"
804}
805
806cmd_ossfuzz_ninja() {
807 [[ -e "${BUILD_DIR}/build.ninja" ]]
808 local real_build_dir=$(realpath "${BUILD_DIR}")
809
Alex Deymoe8a9c5e2021-07-02 13:47:34 +0200810 if [[ -e "${BUILD_DIR}/msan" ]]; then
811 echo "ossfuzz_ninja doesn't work with msan builds. Use ossfuzz_msan." >&2
812 exit 1
813 fi
814
Alex Deymo13396662021-06-15 20:07:37 +0200815 sudo docker run --rm -i \
816 --user $(id -u):$(id -g) \
817 -v "${MYDIR}":/src/libjxl \
818 -v "${real_build_dir}":/work \
819 gcr.io/oss-fuzz/libjxl \
820 ninja -C /work "$@"
821}
822
jpegxl-botff093712019-12-27 18:12:34 +0100823cmd_fast_benchmark() {
824 local small_corpus_tar="${BENCHMARK_CORPORA}/jyrki-full.tar"
825 mkdir -p "${BENCHMARK_CORPORA}"
826 curl --show-error -o "${small_corpus_tar}" -z "${small_corpus_tar}" \
827 "https://storage.googleapis.com/artifacts.jpegxl.appspot.com/corpora/jyrki-full.tar"
828
829 local tmpdir=$(mktemp -d)
830 CLEANUP_FILES+=("${tmpdir}")
831 tar -xf "${small_corpus_tar}" -C "${tmpdir}"
832
833 run_benchmark "${tmpdir}" 1048576
834}
835
836cmd_benchmark() {
837 local nikon_corpus_tar="${BENCHMARK_CORPORA}/nikon-subset.tar"
838 mkdir -p "${BENCHMARK_CORPORA}"
839 curl --show-error -o "${nikon_corpus_tar}" -z "${nikon_corpus_tar}" \
840 "https://storage.googleapis.com/artifacts.jpegxl.appspot.com/corpora/nikon-subset.tar"
841
842 local tmpdir=$(mktemp -d)
843 CLEANUP_FILES+=("${tmpdir}")
844 tar -xvf "${nikon_corpus_tar}" -C "${tmpdir}"
845
846 local sem_id="jpegxl_benchmark-$$"
847 local nprocs=$(nproc --all || echo 1)
848 images=()
849 local filename
850 while IFS= read -r filename; do
851 # This removes the './'
852 filename="${filename:2}"
853 local mode
854 if [[ "${filename:0:4}" == "srgb" ]]; then
855 mode="RGB_D65_SRG_Rel_SRG"
856 elif [[ "${filename:0:5}" == "adobe" ]]; then
857 mode="RGB_D65_Ado_Rel_Ado"
858 else
859 echo "Unknown image colorspace: ${filename}" >&2
860 exit 1
861 fi
862 png_filename="${filename%.ppm}.png"
863 png_filename=$(echo "${png_filename}" | tr '/' '_')
864 sem --bg --id "${sem_id}" -j"${nprocs}" -- \
865 "${BUILD_DIR}/tools/decode_and_encode" \
866 "${tmpdir}/${filename}" "${mode}" "${tmpdir}/${png_filename}"
867 images+=( "${png_filename}" )
jpegxl-botf84edfb2020-04-20 09:48:41 +0200868 done < <(cd "${tmpdir}"; ${FIND_BIN} . -name '*.ppm' -type f)
jpegxl-botff093712019-12-27 18:12:34 +0100869 sem --id "${sem_id}" --wait
870
871 # We need about 10 GiB per thread on these images.
872 run_benchmark "${tmpdir}" 10485760
873}
874
875get_mem_available() {
876 if [[ "${OS}" == "Darwin" ]]; then
877 echo $(vm_stat | grep -F 'Pages free:' | awk '{print $3 * 4}')
878 else
879 echo $(grep -F MemAvailable: /proc/meminfo | awk '{print $2}')
880 fi
881}
882
883run_benchmark() {
884 local src_img_dir="$1"
885 local mem_per_thread="${2:-10485760}"
886
887 local output_dir="${BUILD_DIR}/benchmark_results"
888 mkdir -p "${output_dir}"
889
890 # The memory available at the beginning of the benchmark run in kB. The number
891 # of threads depends on the available memory, and the passed memory per
892 # thread. We also add a 2 GiB of constant memory.
893 local mem_available="$(get_mem_available)"
894 # Check that we actually have a MemAvailable value.
895 [[ -n "${mem_available}" ]]
896 local num_threads=$(( (${mem_available} - 1048576) / ${mem_per_thread} ))
897 if [[ ${num_threads} -le 0 ]]; then
898 num_threads=1
899 fi
900
901 local benchmark_args=(
902 --input "${src_img_dir}/*.png"
Jon Sneyers75a039a2022-04-15 15:12:40 +0200903 --codec=jpeg:yuv420:q85,webp:q80,jxl:d1:6,jxl:d1:6:downsampling=8,jxl:d5:6,jxl:d5:6:downsampling=8,jxl:m:d0:2,jxl:m:d0:3,jxl:m:d2:2
jpegxl-botff093712019-12-27 18:12:34 +0100904 --output_dir "${output_dir}"
905 --noprofiler --show_progress
906 --num_threads="${num_threads}"
907 )
908 if [[ "${STORE_IMAGES}" == "1" ]]; then
909 benchmark_args+=(--save_decompressed --save_compressed)
910 fi
jpegxl-bot849ebf62020-09-29 16:23:20 +0200911 (
jpegxl-bot56fd0222020-10-06 14:50:49 +0200912 [[ "${TEST_STACK_LIMIT}" == "none" ]] || ulimit -s "${TEST_STACK_LIMIT}"
jpegxl-bot849ebf62020-09-29 16:23:20 +0200913 "${BUILD_DIR}/tools/benchmark_xl" "${benchmark_args[@]}" | \
914 tee "${output_dir}/results.txt"
915
916 # Check error code for benckmark_xl command. This will exit if not.
917 return ${PIPESTATUS[0]}
918 )
jpegxl-botff093712019-12-27 18:12:34 +0100919
920 if [[ -n "${CI_BUILD_NAME:-}" ]]; then
921 { set +x; } 2>/dev/null
922 local message="Results for ${CI_BUILD_NAME} @ ${CI_COMMIT_SHORT_SHA} (job ${CI_JOB_URL:-}):
923
924$(cat "${output_dir}/results.txt")
925"
926 cmd_post_mr_comment "${message}"
927 set -x
928 fi
929}
930
931# Helper function to wait for the CPU temperature to cool down on ARM.
932wait_for_temp() {
933 { set +x; } 2>/dev/null
Alex Deymobaeaa1a2021-06-16 12:55:19 +0200934 local temp_limit=${1:-38000}
jpegxl-botff093712019-12-27 18:12:34 +0100935 if [[ -z "${THERMAL_FILE:-}" ]]; then
936 echo "Must define the THERMAL_FILE with the thermal_zoneX/temp file" \
937 "to read the temperature from. This is normally set in the runner." >&2
938 exit 1
939 fi
940 local org_temp=$(cat "${THERMAL_FILE}")
941 if [[ "${org_temp}" -ge "${temp_limit}" ]]; then
942 echo -n "Waiting for temp to get down from ${org_temp}... "
943 fi
944 local temp="${org_temp}"
Alex Deymobaeaa1a2021-06-16 12:55:19 +0200945 local secs=0
jpegxl-botff093712019-12-27 18:12:34 +0100946 while [[ "${temp}" -ge "${temp_limit}" ]]; do
947 sleep 1
948 temp=$(cat "${THERMAL_FILE}")
Alex Deymobaeaa1a2021-06-16 12:55:19 +0200949 echo -n "${temp} "
950 secs=$((secs + 1))
951 if [[ ${secs} -ge 5 ]]; then
952 break
953 fi
jpegxl-botff093712019-12-27 18:12:34 +0100954 done
955 if [[ "${org_temp}" -ge "${temp_limit}" ]]; then
956 echo "Done, temp=${temp}"
957 fi
958 set -x
959}
960
961# Helper function to set the cpuset restriction of the current process.
962cmd_cpuset() {
jpegxl-bot21f5f752020-06-30 13:06:56 +0200963 [[ "${SKIP_CPUSET:-}" != "1" ]] || return 0
jpegxl-botff093712019-12-27 18:12:34 +0100964 local newset="$1"
965 local mycpuset=$(cat /proc/self/cpuset)
966 mycpuset="/dev/cpuset${mycpuset}"
967 # Check that the directory exists:
968 [[ -d "${mycpuset}" ]]
jpegxl-botb3a65712020-02-06 13:22:22 +0100969 if [[ -e "${mycpuset}/cpuset.cpus" ]]; then
970 echo "${newset}" >"${mycpuset}/cpuset.cpus"
971 else
972 echo "${newset}" >"${mycpuset}/cpus"
973 fi
974}
975
976# Return the encoding/decoding speed from the Stats output.
977_speed_from_output() {
jpegxl-bot6b5144c2020-08-24 13:35:47 +0200978 local speed="$1"
979 local unit="${2:-MP/s}"
980 if [[ "${speed}" == *"${unit}"* ]]; then
981 speed="${speed%% ${unit}*}"
982 speed="${speed##* }"
983 echo "${speed}"
984 fi
jpegxl-botff093712019-12-27 18:12:34 +0100985}
986
jpegxl-bot6b5144c2020-08-24 13:35:47 +0200987
jpegxl-botff093712019-12-27 18:12:34 +0100988# Run benchmarks on ARM for the big and little CPUs.
989cmd_arm_benchmark() {
jpegxl-bot9e183e12020-10-29 12:36:26 +0100990 # Flags used for cjxl encoder with .png inputs
jpegxl-bot6b5144c2020-08-24 13:35:47 +0200991 local jxl_png_benchmarks=(
jpegxl-botff093712019-12-27 18:12:34 +0100992 # Lossy options:
jpegxl-bot9e183e12020-10-29 12:36:26 +0100993 "--epf=0 --distance=1.0 --speed=cheetah"
994 "--epf=2 --distance=1.0 --speed=cheetah"
995 "--epf=0 --distance=8.0 --speed=cheetah"
996 "--epf=1 --distance=8.0 --speed=cheetah"
997 "--epf=2 --distance=8.0 --speed=cheetah"
998 "--epf=3 --distance=8.0 --speed=cheetah"
jpegxl-bot131953a2020-11-10 15:30:00 +0100999 "--modular -Q 90"
1000 "--modular -Q 50"
jpegxl-botff093712019-12-27 18:12:34 +01001001 # Lossless options:
jpegxl-bot131953a2020-11-10 15:30:00 +01001002 "--modular"
1003 "--modular -E 0 -I 0"
1004 "--modular -P 5"
1005 "--modular --responsive=1"
jpegxl-botff093712019-12-27 18:12:34 +01001006 # Near-lossless options:
jpegxl-bot9e183e12020-10-29 12:36:26 +01001007 "--epf=0 --distance=0.3 --speed=fast"
jpegxl-bot131953a2020-11-10 15:30:00 +01001008 "--modular -Q 97"
jpegxl-botff093712019-12-27 18:12:34 +01001009 )
1010
jpegxl-bot9e183e12020-10-29 12:36:26 +01001011 # Flags used for cjxl encoder with .jpg inputs. These should do lossless
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001012 # JPEG recompression (of pixels or full jpeg).
1013 local jxl_jpeg_benchmarks=(
1014 "--num_reps=3"
1015 )
1016
jpegxl-botff093712019-12-27 18:12:34 +01001017 local images=(
Evgenii Kliuchnikov73df8b82022-05-13 07:21:25 +00001018 "testdata/jxl/flower/flower.png"
jpegxl-botff093712019-12-27 18:12:34 +01001019 )
1020
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001021 local jpg_images=(
Evgenii Kliuchnikov73df8b82022-05-13 07:21:25 +00001022 "testdata/jxl/flower/flower.png.im_q85_420.jpg"
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001023 )
1024
jpegxl-bot21f5f752020-06-30 13:06:56 +02001025 if [[ "${SKIP_CPUSET:-}" == "1" ]]; then
1026 # Use a single cpu config in this case.
1027 local cpu_confs=("?")
1028 else
1029 # Otherwise the CPU config comes from the environment:
1030 local cpu_confs=(
1031 "${RUNNER_CPU_LITTLE}"
1032 "${RUNNER_CPU_BIG}"
1033 # The CPU description is something like 3-7, so these configurations only
1034 # take the first CPU of the group.
1035 "${RUNNER_CPU_LITTLE%%-*}"
1036 "${RUNNER_CPU_BIG%%-*}"
1037 )
1038 # Check that RUNNER_CPU_ALL is defined. In the SKIP_CPUSET=1 case this will
1039 # be ignored but still evaluated when calling cmd_cpuset.
1040 [[ -n "${RUNNER_CPU_ALL}" ]]
1041 fi
jpegxl-botb3a65712020-02-06 13:22:22 +01001042
1043 local jpg_dirname="third_party/corpora/jpeg"
1044 mkdir -p "${jpg_dirname}"
jpegxl-botb3a65712020-02-06 13:22:22 +01001045 local jpg_qualities=( 50 80 95 )
1046 for src_img in "${images[@]}"; do
1047 for q in "${jpg_qualities[@]}"; do
1048 local jpeg_name="${jpg_dirname}/"$(basename "${src_img}" .png)"-q${q}.jpg"
jpegxl-bot849ebf62020-09-29 16:23:20 +02001049 convert -sampling-factor 1x1 -quality "${q}" \
jpegxl-botb3a65712020-02-06 13:22:22 +01001050 "${src_img}" "${jpeg_name}"
1051 jpg_images+=("${jpeg_name}")
1052 done
1053 done
1054
jpegxl-botff093712019-12-27 18:12:34 +01001055 local output_dir="${BUILD_DIR}/benchmark_results"
1056 mkdir -p "${output_dir}"
1057 local runs_file="${output_dir}/runs.txt"
1058
1059 if [[ ! -e "${runs_file}" ]]; then
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001060 echo -e "binary\tflags\tsrc_img\tsrc size\tsrc pixels\tcpuset\tenc size (B)\tenc speed (MP/s)\tdec speed (MP/s)\tJPG dec speed (MP/s)\tJPG dec speed (MB/s)" |
jpegxl-botff093712019-12-27 18:12:34 +01001061 tee -a "${runs_file}"
1062 fi
1063
jpegxl-botb3a65712020-02-06 13:22:22 +01001064 mkdir -p "${BUILD_DIR}/arm_benchmark"
jpegxl-botff093712019-12-27 18:12:34 +01001065 local flags
1066 local src_img
jpegxl-botb3a65712020-02-06 13:22:22 +01001067 for src_img in "${jpg_images[@]}" "${images[@]}"; do
jpegxl-botff093712019-12-27 18:12:34 +01001068 local src_img_hash=$(sha1sum "${src_img}" | cut -f 1 -d ' ')
jpegxl-bot9e183e12020-10-29 12:36:26 +01001069 local enc_binaries=("${BUILD_DIR}/tools/cjxl")
jpegxl-botb3a65712020-02-06 13:22:22 +01001070 local src_ext="${src_img##*.}"
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001071 for enc_binary in "${enc_binaries[@]}"; do
1072 local enc_binary_base=$(basename "${enc_binary}")
jpegxl-botff093712019-12-27 18:12:34 +01001073
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001074 # Select the list of flags to use for the current encoder/image pair.
1075 local img_benchmarks
jpegxl-botc8ce59f2020-10-12 16:06:35 +02001076 if [[ "${src_ext}" == "jpg" ]]; then
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001077 img_benchmarks=("${jxl_jpeg_benchmarks[@]}")
1078 else
1079 img_benchmarks=("${jxl_png_benchmarks[@]}")
1080 fi
jpegxl-botb3a65712020-02-06 13:22:22 +01001081
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001082 for flags in "${img_benchmarks[@]}"; do
1083 # Encoding step.
1084 local enc_file_hash="${enc_binary_base} || $flags || ${src_img} || ${src_img_hash}"
1085 enc_file_hash=$(echo "${enc_file_hash}" | sha1sum | cut -f 1 -d ' ')
1086 local enc_file="${BUILD_DIR}/arm_benchmark/${enc_file_hash}.jxl"
1087
1088 for cpu_conf in "${cpu_confs[@]}"; do
1089 cmd_cpuset "${cpu_conf}"
1090 # nproc returns the number of active CPUs, which is given by the cpuset
1091 # mask.
1092 local num_threads="$(nproc)"
1093
1094 echo "Encoding with: ${enc_binary_base} img=${src_img} cpus=${cpu_conf} enc_flags=${flags}"
1095 local enc_output
jpegxl-bot131953a2020-11-10 15:30:00 +01001096 if [[ "${flags}" == *"modular"* ]]; then
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001097 # We don't benchmark encoding speed in this case.
1098 if [[ ! -f "${enc_file}" ]]; then
1099 cmd_cpuset "${RUNNER_CPU_ALL:-}"
1100 "${enc_binary}" ${flags} "${src_img}" "${enc_file}.tmp"
1101 mv "${enc_file}.tmp" "${enc_file}"
1102 cmd_cpuset "${cpu_conf}"
1103 fi
1104 enc_output=" ?? MP/s"
1105 else
1106 wait_for_temp
1107 enc_output=$("${enc_binary}" ${flags} "${src_img}" "${enc_file}.tmp" \
1108 2>&1 | tee /dev/stderr | grep -F "MP/s [")
jpegxl-botb3a65712020-02-06 13:22:22 +01001109 mv "${enc_file}.tmp" "${enc_file}"
jpegxl-botb3a65712020-02-06 13:22:22 +01001110 fi
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001111 local enc_speed=$(_speed_from_output "${enc_output}")
1112 local enc_size=$(stat -c "%s" "${enc_file}")
1113
1114 echo "Decoding with: img=${src_img} cpus=${cpu_conf} enc_flags=${flags}"
1115
1116 local dec_output
jpegxl-botb3a65712020-02-06 13:22:22 +01001117 wait_for_temp
jpegxl-bot9e183e12020-10-29 12:36:26 +01001118 dec_output=$("${BUILD_DIR}/tools/djxl" "${enc_file}" \
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001119 --num_reps=5 --num_threads="${num_threads}" 2>&1 | tee /dev/stderr |
1120 grep -E "M[BP]/s \[")
1121 local img_size=$(echo "${dec_output}" | cut -f 1 -d ',')
1122 local img_size_x=$(echo "${img_size}" | cut -f 1 -d ' ')
1123 local img_size_y=$(echo "${img_size}" | cut -f 3 -d ' ')
1124 local img_size_px=$(( ${img_size_x} * ${img_size_y} ))
1125 local dec_speed=$(_speed_from_output "${dec_output}")
jpegxl-botb3a65712020-02-06 13:22:22 +01001126
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001127 # For JPEG lossless recompression modes (where the original is a JPEG)
1128 # decode to JPG as well.
1129 local jpeg_dec_mps_speed=""
1130 local jpeg_dec_mbs_speed=""
1131 if [[ "${src_ext}" == "jpg" ]]; then
1132 wait_for_temp
1133 local dec_file="${BUILD_DIR}/arm_benchmark/${enc_file_hash}.jpg"
jpegxl-botb1c6fdc2021-03-05 18:32:15 +01001134 dec_output=$("${BUILD_DIR}/tools/djxl" "${enc_file}" \
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001135 "${dec_file}" --num_reps=5 --num_threads="${num_threads}" 2>&1 | \
1136 tee /dev/stderr | grep -E "M[BP]/s \[")
1137 local jpeg_dec_mps_speed=$(_speed_from_output "${dec_output}")
1138 local jpeg_dec_mbs_speed=$(_speed_from_output "${dec_output}" MB/s)
1139 if ! cmp --quiet "${src_img}" "${dec_file}"; then
1140 # Add a start at the end to signal that the files are different.
1141 jpeg_dec_mbs_speed+="*"
1142 fi
1143 fi
jpegxl-botff093712019-12-27 18:12:34 +01001144
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001145 # Record entry in a tab-separated file.
1146 local src_img_base=$(basename "${src_img}")
1147 echo -e "${enc_binary_base}\t${flags}\t${src_img_base}\t${img_size}\t${img_size_px}\t${cpu_conf}\t${enc_size}\t${enc_speed}\t${dec_speed}\t${jpeg_dec_mps_speed}\t${jpeg_dec_mbs_speed}" |
1148 tee -a "${runs_file}"
1149 done
jpegxl-botff093712019-12-27 18:12:34 +01001150 done
1151 done
1152 done
jpegxl-bot21f5f752020-06-30 13:06:56 +02001153 cmd_cpuset "${RUNNER_CPU_ALL:-}"
jpegxl-botff093712019-12-27 18:12:34 +01001154 cat "${runs_file}"
1155
1156 if [[ -n "${CI_BUILD_NAME:-}" ]]; then
1157 load_mr_vars_from_commit
1158 { set +x; } 2>/dev/null
1159 local message="Results for ${CI_BUILD_NAME} @ ${CI_COMMIT_SHORT_SHA} (job ${CI_JOB_URL:-}):
1160
1161\`\`\`
1162$(column -t -s " " "${runs_file}")
1163\`\`\`
1164"
1165 cmd_post_mr_comment "${message}"
1166 set -x
1167 fi
1168}
1169
jpegxl-botf84edfb2020-04-20 09:48:41 +02001170# Generate a corpus and run the fuzzer on that corpus.
1171cmd_fuzz() {
1172 local corpus_dir=$(realpath "${BUILD_DIR}/fuzzer_corpus")
1173 local fuzzer_crash_dir=$(realpath "${BUILD_DIR}/fuzzer_crash")
1174 mkdir -p "${corpus_dir}" "${fuzzer_crash_dir}"
1175 # Generate step.
1176 "${BUILD_DIR}/tools/fuzzer_corpus" "${corpus_dir}"
1177 # Run step:
1178 local nprocs=$(nproc --all || echo 1)
1179 (
1180 cd "${BUILD_DIR}"
1181 "tools/djxl_fuzzer" "${fuzzer_crash_dir}" "${corpus_dir}" \
1182 -max_total_time="${FUZZER_MAX_TIME}" -jobs=${nprocs} \
1183 -artifact_prefix="${fuzzer_crash_dir}/"
1184 )
1185}
1186
jpegxl-botff093712019-12-27 18:12:34 +01001187# Runs the linter (clang-format) on the pending CLs.
1188cmd_lint() {
1189 merge_request_commits
jpegxl-bot31c71b02020-12-24 17:42:41 +01001190 { set +x; } 2>/dev/null
Alex Deymod09afef2021-08-03 14:26:28 +02001191 local versions=(${1:-6.0 7 8 9 10 11})
jpegxl-botff093712019-12-27 18:12:34 +01001192 local clang_format_bins=("${versions[@]/#/clang-format-}" clang-format)
1193 local tmpdir=$(mktemp -d)
1194 CLEANUP_FILES+=("${tmpdir}")
1195
jpegxl-bot31c71b02020-12-24 17:42:41 +01001196 local ret=0
1197 local build_patch="${tmpdir}/build_cleaner.patch"
1198 if ! "${MYDIR}/tools/build_cleaner.py" >"${build_patch}"; then
1199 ret=1
1200 echo "build_cleaner.py findings:" >&2
1201 "${COLORDIFF_BIN}" <"${build_patch}"
1202 echo "Run \`tools/build_cleaner.py --update\` to apply them" >&2
1203 fi
1204
jpegxl-botff093712019-12-27 18:12:34 +01001205 local installed=()
1206 local clang_patch
1207 local clang_format
1208 for clang_format in "${clang_format_bins[@]}"; do
1209 if ! which "${clang_format}" >/dev/null; then
1210 continue
1211 fi
1212 installed+=("${clang_format}")
1213 local tmppatch="${tmpdir}/${clang_format}.patch"
Ziemowit Zabawa27d8a0f2021-07-01 16:45:13 +02001214 # We include in this linter all the changes including the uncommitted changes
jpegxl-botff093712019-12-27 18:12:34 +01001215 # to avoid printing changes already applied.
1216 set -x
Moritz Firsching422d09a2022-05-27 20:37:07 +02001217 # Ignoring the error that git-clang-format outputs.
jpegxl-botff093712019-12-27 18:12:34 +01001218 git -C "${MYDIR}" "${clang_format}" --binary "${clang_format}" \
Moritz Firsching422d09a2022-05-27 20:37:07 +02001219 --style=file --diff "${MR_ANCESTOR_SHA}" -- >"${tmppatch}" || true
jpegxl-botff093712019-12-27 18:12:34 +01001220 { set +x; } 2>/dev/null
jpegxl-botff093712019-12-27 18:12:34 +01001221 if grep -E '^--- ' "${tmppatch}">/dev/null; then
1222 if [[ -n "${LINT_OUTPUT:-}" ]]; then
1223 cp "${tmppatch}" "${LINT_OUTPUT}"
1224 fi
1225 clang_patch="${tmppatch}"
1226 else
1227 echo "clang-format check OK" >&2
jpegxl-bot31c71b02020-12-24 17:42:41 +01001228 return ${ret}
jpegxl-botff093712019-12-27 18:12:34 +01001229 fi
1230 done
1231
1232 if [[ ${#installed[@]} -eq 0 ]]; then
1233 echo "You must install clang-format for \"git clang-format\"" >&2
1234 exit 1
1235 fi
1236
1237 # clang-format is installed but found problems.
1238 echo "clang-format findings:" >&2
1239 "${COLORDIFF_BIN}" < "${clang_patch}"
1240
1241 echo "clang-format found issues in your patches from ${MR_ANCESTOR_SHA}" \
1242 "to the current patch. Run \`./ci.sh lint | patch -p1\` from the base" \
1243 "directory to apply them." >&2
1244 exit 1
1245}
1246
1247# Runs clang-tidy on the pending CLs. If the "all" argument is passed it runs
1248# clang-tidy over all the source files instead.
1249cmd_tidy() {
1250 local what="${1:-}"
1251
1252 if [[ -z "${CLANG_TIDY_BIN}" ]]; then
jpegxl-bot63349442020-05-25 08:56:34 +02001253 echo "ERROR: You must install clang-tidy-7 or newer to use ci.sh tidy" >&2
jpegxl-botff093712019-12-27 18:12:34 +01001254 exit 1
1255 fi
1256
1257 local git_args=()
1258 if [[ "${what}" == "all" ]]; then
1259 git_args=(ls-files)
1260 shift
1261 else
1262 merge_request_commits
1263 git_args=(
1264 diff-tree --no-commit-id --name-only -r "${MR_ANCESTOR_SHA}"
1265 "${MR_HEAD_SHA}"
1266 )
1267 fi
1268
1269 # Clang-tidy needs the compilation database generated by cmake.
1270 if [[ ! -e "${BUILD_DIR}/compile_commands.json" ]]; then
1271 # Generate the build options in debug mode, since we need the debug asserts
1272 # enabled for the clang-tidy analyzer to use them.
1273 CMAKE_BUILD_TYPE="Debug"
1274 cmake_configure
jpegxl-bot63349442020-05-25 08:56:34 +02001275 # Build the autogen targets to generate the .h files from the .ui files.
1276 local autogen_targets=(
1277 $(ninja -C "${BUILD_DIR}" -t targets | grep -F _autogen: |
1278 cut -f 1 -d :)
1279 )
1280 if [[ ${#autogen_targets[@]} != 0 ]]; then
1281 ninja -C "${BUILD_DIR}" "${autogen_targets[@]}"
1282 fi
jpegxl-botff093712019-12-27 18:12:34 +01001283 fi
1284
1285 cd "${MYDIR}"
1286 local nprocs=$(nproc --all || echo 1)
1287 local ret=0
1288 if ! parallel -j"${nprocs}" --keep-order -- \
1289 "${CLANG_TIDY_BIN}" -p "${BUILD_DIR}" -format-style=file -quiet "$@" {} \
1290 < <(git "${git_args[@]}" | grep -E '(\.cc|\.cpp)$') \
1291 >"${BUILD_DIR}/clang-tidy.txt"; then
1292 ret=1
1293 fi
1294 { set +x; } 2>/dev/null
1295 echo "Findings statistics:" >&2
1296 grep -E ' \[[A-Za-z\.,\-]+\]' -o "${BUILD_DIR}/clang-tidy.txt" | sort \
1297 | uniq -c >&2
1298
1299 if [[ $ret -ne 0 ]]; then
1300 cat >&2 <<EOF
1301Errors found, see ${BUILD_DIR}/clang-tidy.txt for details.
1302To automatically fix them, run:
1303
1304 SKIP_TEST=1 ./ci.sh debug
1305 ${CLANG_TIDY_BIN} -p ${BUILD_DIR} -fix -format-style=file -quiet $@ \$(git ${git_args[@]} | grep -E '(\.cc|\.cpp)\$')
1306EOF
1307 fi
1308
1309 return ${ret}
1310}
1311
jpegxl-bot9e183e12020-10-29 12:36:26 +01001312# Print stats about all the packages built in ${BUILD_DIR}/debs/.
1313cmd_debian_stats() {
1314 { set +x; } 2>/dev/null
1315 local debsdir="${BUILD_DIR}/debs"
1316 local f
1317 while IFS='' read -r -d '' f; do
1318 echo "====================================================================="
1319 echo "Package $f:"
1320 dpkg --info $f
1321 dpkg --contents $f
1322 done < <(find "${BUILD_DIR}/debs" -maxdepth 1 -mindepth 1 -type f \
1323 -name '*.deb' -print0)
1324}
1325
1326build_debian_pkg() {
1327 local srcdir="$1"
1328 local srcpkg="$2"
1329
1330 local debsdir="${BUILD_DIR}/debs"
1331 local builddir="${debsdir}/${srcpkg}"
1332
1333 # debuild doesn't have an easy way to build out of tree, so we make a copy
1334 # of with all symlinks on the first level.
1335 mkdir -p "${builddir}"
1336 for f in $(find "${srcdir}" -mindepth 1 -maxdepth 1 -printf '%P\n'); do
1337 if [[ ! -L "${builddir}/$f" ]]; then
1338 rm -f "${builddir}/$f"
1339 ln -s "${srcdir}/$f" "${builddir}/$f"
1340 fi
1341 done
1342 (
1343 cd "${builddir}"
1344 debuild -b -uc -us
1345 )
1346}
1347
1348cmd_debian_build() {
1349 local srcpkg="${1:-}"
1350
1351 case "${srcpkg}" in
1352 jpeg-xl)
1353 build_debian_pkg "${MYDIR}" "jpeg-xl"
1354 ;;
1355 highway)
1356 build_debian_pkg "${MYDIR}/third_party/highway" "highway"
1357 ;;
1358 *)
1359 echo "ERROR: Must pass a valid source package name to build." >&2
1360 ;;
1361 esac
1362}
1363
Alex Deymoa29161b2021-08-13 12:56:18 +02001364get_version() {
1365 local varname=$1
1366 local line=$(grep -F "set(${varname} " lib/CMakeLists.txt | head -n 1)
1367 [[ -n "${line}" ]]
1368 line="${line#set(${varname} }"
1369 line="${line%)}"
1370 echo "${line}"
1371}
1372
1373cmd_bump_version() {
1374 local newver="${1:-}"
1375
1376 if ! which dch >/dev/null; then
1377 echo "Run:\n sudo apt install debhelper"
1378 exit 1
1379 fi
1380
1381 if [[ -z "${newver}" ]]; then
1382 local major=$(get_version JPEGXL_MAJOR_VERSION)
1383 local minor=$(get_version JPEGXL_MINOR_VERSION)
1384 local patch=0
1385 minor=$(( ${minor} + 1))
1386 else
1387 local major="${newver%%.*}"
1388 newver="${newver#*.}"
1389 local minor="${newver%%.*}"
1390 newver="${newver#${minor}}"
1391 local patch="${newver#.}"
1392 if [[ -z "${patch}" ]]; then
1393 patch=0
1394 fi
1395 fi
1396
1397 newver="${major}.${minor}"
1398 if [[ "${patch}" != "0" ]]; then
1399 newver="${newver}.${patch}"
1400 fi
1401 echo "Bumping version to ${newver} (${major}.${minor}.${patch})"
1402 sed -E \
1403 -e "s/(set\\(JPEGXL_MAJOR_VERSION) [0-9]+\\)/\\1 ${major})/" \
1404 -e "s/(set\\(JPEGXL_MINOR_VERSION) [0-9]+\\)/\\1 ${minor})/" \
1405 -e "s/(set\\(JPEGXL_PATCH_VERSION) [0-9]+\\)/\\1 ${patch})/" \
1406 -i lib/CMakeLists.txt
1407
1408 # Update lib.gni
1409 tools/build_cleaner.py --update
1410
1411 # Mark the previous version as "unstable".
1412 DEBCHANGE_RELEASE_HEURISTIC=log dch -M --distribution unstable --release ''
1413 DEBCHANGE_RELEASE_HEURISTIC=log dch -M \
1414 --newversion "${newver}" \
1415 "Bump JPEG XL version to ${newver}."
1416}
1417
Alex Deymo4ead4a12021-05-26 16:23:17 +02001418# Check that the AUTHORS file contains the email of the committer.
1419cmd_authors() {
1420 merge_request_commits
Moritz Firsching481329c2022-05-19 13:53:16 +02001421 local emails
1422 local names
1423 readarray -t emails < <(git log --format='%ae' "${MR_HEAD_SHA}...${MR_ANCESTOR_SHA}")
1424 readarray -t names < <(git log --format='%an' "${MR_HEAD_SHA}...${MR_ANCESTOR_SHA}")
1425 for i in "${!names[@]}"; do
1426 echo "Checking name '${names[$i]}' with email '${emails[$i]}' ..."
1427 "${MYDIR}"/tools/check_author.py "${emails[$i]}" "${names[$i]}"
1428 done
Alex Deymo4ead4a12021-05-26 16:23:17 +02001429}
1430
jpegxl-botff093712019-12-27 18:12:34 +01001431main() {
1432 local cmd="${1:-}"
1433 if [[ -z "${cmd}" ]]; then
1434 cat >&2 <<EOF
1435Use: $0 CMD
1436
1437Where cmd is one of:
1438 opt Build and test a Release with symbols build.
1439 debug Build and test a Debug build (NDEBUG is not defined).
1440 release Build and test a striped Release binary without debug information.
1441 asan Build and test an ASan (AddressSanitizer) build.
1442 msan Build and test an MSan (MemorySanitizer) build. Needs to have msan
1443 c++ libs installed with msan_install first.
1444 tsan Build and test a TSan (ThreadSanitizer) build.
Alex Deymo263433d2021-06-04 21:07:43 +02001445 asanfuzz Build and test an ASan (AddressSanitizer) build for fuzzing.
1446 msanfuzz Build and test an MSan (MemorySanitizer) build for fuzzing.
jpegxl-botff093712019-12-27 18:12:34 +01001447 test Run the tests build by opt, debug, release, asan or msan. Useful when
1448 building with SKIP_TEST=1.
jpegxl-bot5175d112021-02-23 16:59:45 +01001449 gbench Run the Google benchmark tests.
jpegxl-botf84edfb2020-04-20 09:48:41 +02001450 fuzz Generate the fuzzer corpus and run the fuzzer on it. Useful after
1451 building with asan or msan.
jpegxl-botff093712019-12-27 18:12:34 +01001452 benchmark Run the benchmark over the default corpus.
1453 fast_benchmark Run the benchmark over the small corpus.
1454
1455 coverage Buils and run tests with coverage support. Runs coverage_report as
1456 well.
1457 coverage_report Generate HTML, XML and text coverage report after a coverage
1458 run.
1459
1460 lint Run the linter checks on the current commit or merge request.
1461 tidy Run clang-tidy on the current commit or merge request.
Alex Deymo4ead4a12021-05-26 16:23:17 +02001462 authors Check that the last commit's author is listed in the AUTHORS file.
jpegxl-botff093712019-12-27 18:12:34 +01001463
1464 msan_install Install the libc++ libraries required to build in msan mode. This
1465 needs to be done once.
1466
jpegxl-bot9e183e12020-10-29 12:36:26 +01001467 debian_build <srcpkg> Build the given source package.
1468 debian_stats Print stats about the built packages.
1469
Alex Deymo13396662021-06-15 20:07:37 +02001470oss-fuzz commands:
1471 ossfuzz_asan Build the local source inside oss-fuzz docker with asan.
1472 ossfuzz_msan Build the local source inside oss-fuzz docker with msan.
1473 ossfuzz_ubsan Build the local source inside oss-fuzz docker with ubsan.
1474 ossfuzz_ninja Run ninja on the BUILD_DIR inside the oss-fuzz docker. Extra
1475 parameters are passed to ninja, for example "djxl_fuzzer" will
1476 only build that ninja target. Use for faster build iteration
1477 after one of the ossfuzz_*san commands.
1478
jpegxl-botff093712019-12-27 18:12:34 +01001479You can pass some optional environment variables as well:
1480 - BUILD_DIR: The output build directory (by default "$$repo/build")
1481 - BUILD_TARGET: The target triplet used when cross-compiling.
1482 - CMAKE_FLAGS: Convenience flag to pass both CMAKE_C_FLAGS and CMAKE_CXX_FLAGS.
1483 - CMAKE_PREFIX_PATH: Installation prefixes to be searched by the find_package.
jpegxl-botf84edfb2020-04-20 09:48:41 +02001484 - ENABLE_WASM_SIMD=1: enable experimental SIMD in WASM build (only).
1485 - FUZZER_MAX_TIME: "fuzz" command fuzzer running timeout in seconds.
jpegxl-botff093712019-12-27 18:12:34 +01001486 - LINT_OUTPUT: Path to the output patch from the "lint" command.
jpegxl-bot21f5f752020-06-30 13:06:56 +02001487 - SKIP_CPUSET=1: Skip modifying the cpuset in the arm_benchmark.
jpegxl-botff093712019-12-27 18:12:34 +01001488 - SKIP_TEST=1: Skip the test stage.
1489 - STORE_IMAGES=0: Makes the benchmark discard the computed images.
jpegxl-bot849ebf62020-09-29 16:23:20 +02001490 - TEST_STACK_LIMIT: Stack size limit (ulimit -s) during tests, in KiB.
Moritz Firsching403ba9b2022-06-29 11:46:08 +02001491 - TEST_SELECTOR: pass additional arguments to ctest, e.g. "-R .Resample.".
jpegxl-bot849ebf62020-09-29 16:23:20 +02001492 - STACK_SIZE=1: Generate binaries with the .stack_sizes sections.
jpegxl-botff093712019-12-27 18:12:34 +01001493
1494These optional environment variables are forwarded to the cmake call as
1495parameters:
jpegxl-botf84edfb2020-04-20 09:48:41 +02001496 - CMAKE_BUILD_TYPE
jpegxl-botff093712019-12-27 18:12:34 +01001497 - CMAKE_C_FLAGS
1498 - CMAKE_CXX_FLAGS
jpegxl-bot50bbf272020-06-10 14:59:11 +02001499 - CMAKE_C_COMPILER_LAUNCHER
1500 - CMAKE_CXX_COMPILER_LAUNCHER
jpegxl-botb3a65712020-02-06 13:22:22 +01001501 - CMAKE_CROSSCOMPILING_EMULATOR
jpegxl-botf84edfb2020-04-20 09:48:41 +02001502 - CMAKE_FIND_ROOT_PATH
jpegxl-botff093712019-12-27 18:12:34 +01001503 - CMAKE_EXE_LINKER_FLAGS
jpegxl-bote3c58a02020-06-15 08:51:22 +02001504 - CMAKE_MAKE_PROGRAM
jpegxl-botff093712019-12-27 18:12:34 +01001505 - CMAKE_MODULE_LINKER_FLAGS
1506 - CMAKE_SHARED_LINKER_FLAGS
1507 - CMAKE_TOOLCHAIN_FILE
jpegxl-botff093712019-12-27 18:12:34 +01001508
1509Example:
1510 BUILD_DIR=/tmp/build $0 opt
1511EOF
1512 exit 1
1513 fi
1514
1515 cmd="cmd_${cmd}"
1516 shift
1517 set -x
1518 "${cmd}" "$@"
1519}
1520
1521main "$@"