blob: dfd6041fda4517f7212ee01a6570a1bd7bc6b7fb [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:
jpegxl-bot849ebf62020-09-29 16:23:20 +020018TEST_STACK_LIMIT="${TEST_STACK_LIMIT:-128}"
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}"
25BUILD_TARGET="${BUILD_TARGET:-}"
jpegxl-botf84edfb2020-04-20 09:48:41 +020026ENABLE_WASM_SIMD="${ENABLE_WASM_SIMD:-0}"
jpegxl-botff093712019-12-27 18:12:34 +010027if [[ -n "${BUILD_TARGET}" ]]; then
28 BUILD_DIR="${BUILD_DIR:-${MYDIR}/build-${BUILD_TARGET%%-*}}"
29else
30 BUILD_DIR="${BUILD_DIR:-${MYDIR}/build}"
31fi
32# Whether we should post a message in the MR when the build fails.
33POST_MESSAGE_ON_ERROR="${POST_MESSAGE_ON_ERROR:-1}"
34
jpegxl-bot9e183e12020-10-29 12:36:26 +010035# Set default compilers to clang if not already set
36export CC=${CC:-clang}
37export CXX=${CXX:-clang++}
38
jpegxl-botf84edfb2020-04-20 09:48:41 +020039# Time limit for the "fuzz" command in seconds (0 means no limit).
40FUZZER_MAX_TIME="${FUZZER_MAX_TIME:-0}"
41
jpegxl-bot63349442020-05-25 08:56:34 +020042SANITIZER="none"
43
44if [[ "${BUILD_TARGET}" == wasm* ]]; then
45 # Check that environment is setup for the WASM build target.
46 if [[ -z "${EMSCRIPTEN}" ]]; then
47 echo "'EMSCRIPTEN' is not defined. Use 'emconfigure' wrapper to setup WASM build environment" >&2
48 return 1
49 fi
jpegxl-bote3c58a02020-06-15 08:51:22 +020050 # Remove the side-effect of "emconfigure" wrapper - it considers NodeJS environment.
51 unset EMMAKEN_JUST_CONFIGURE
jpegxl-bot63349442020-05-25 08:56:34 +020052 EMS_TOOLCHAIN_FILE="${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake"
53 if [[ -f "${EMS_TOOLCHAIN_FILE}" ]]; then
54 CMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE:-${EMS_TOOLCHAIN_FILE}}
55 else
56 echo "Warning: EMSCRIPTEN CMake module not found" >&2
57 fi
jpegxl-bote3c58a02020-06-15 08:51:22 +020058 CMAKE_CROSSCOMPILING_EMULATOR="${MYDIR}/js-wasm-wrapper.sh"
jpegxl-bot63349442020-05-25 08:56:34 +020059fi
60
61if [[ "${BUILD_TARGET%%-*}" == "x86_64" ||
62 "${BUILD_TARGET%%-*}" == "i686" ]]; then
63 # Default to building all targets, even if compiler baseline is SSE4
64 HWY_BASELINE_TARGETS=${HWY_BASELINE_TARGETS:-HWY_SCALAR}
65else
66 HWY_BASELINE_TARGETS=${HWY_BASELINE_TARGETS:-}
67fi
jpegxl-botf84edfb2020-04-20 09:48:41 +020068
jpegxl-botff093712019-12-27 18:12:34 +010069# Convenience flag to pass both CMAKE_C_FLAGS and CMAKE_CXX_FLAGS
jpegxl-bot0709f3a2020-02-19 14:37:22 +010070CMAKE_FLAGS=${CMAKE_FLAGS:-}
jpegxl-botb3a65712020-02-06 13:22:22 +010071CMAKE_C_FLAGS="${CMAKE_C_FLAGS:-} ${CMAKE_FLAGS}"
72CMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS:-} ${CMAKE_FLAGS}"
jpegxl-botf84edfb2020-04-20 09:48:41 +020073
jpegxl-botb3a65712020-02-06 13:22:22 +010074CMAKE_CROSSCOMPILING_EMULATOR=${CMAKE_CROSSCOMPILING_EMULATOR:-}
jpegxl-botff093712019-12-27 18:12:34 +010075CMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS:-}
jpegxl-botf84edfb2020-04-20 09:48:41 +020076CMAKE_FIND_ROOT_PATH=${CMAKE_FIND_ROOT_PATH:-}
jpegxl-botff093712019-12-27 18:12:34 +010077CMAKE_MODULE_LINKER_FLAGS=${CMAKE_MODULE_LINKER_FLAGS:-}
78CMAKE_SHARED_LINKER_FLAGS=${CMAKE_SHARED_LINKER_FLAGS:-}
79CMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE:-}
80
jpegxl-botf84edfb2020-04-20 09:48:41 +020081if [[ "${ENABLE_WASM_SIMD}" -ne "0" ]]; then
jpegxl-bot849ebf62020-09-29 16:23:20 +020082 CMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -msimd128"
83 CMAKE_C_FLAGS="${CMAKE_C_FLAGS} -msimd128"
84 CMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS} -msimd128"
jpegxl-botf84edfb2020-04-20 09:48:41 +020085fi
86
jpegxl-bot63349442020-05-25 08:56:34 +020087if [[ ! -z "${HWY_BASELINE_TARGETS}" ]]; then
88 CMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -DHWY_BASELINE_TARGETS=${HWY_BASELINE_TARGETS}"
89fi
jpegxl-botf84edfb2020-04-20 09:48:41 +020090
jpegxl-bot0709f3a2020-02-19 14:37:22 +010091# Version inferred from the CI variables.
Alex Deymoa368d7d2021-08-06 14:45:03 +020092CI_COMMIT_SHA=${CI_COMMIT_SHA:-${GITHUB_SHA:-}}
jpegxl-bot0709f3a2020-02-19 14:37:22 +010093JPEGXL_VERSION=${JPEGXL_VERSION:-${CI_COMMIT_SHA:0:8}}
jpegxl-botff093712019-12-27 18:12:34 +010094
95# Benchmark parameters
96STORE_IMAGES=${STORE_IMAGES:-1}
97BENCHMARK_CORPORA="${MYDIR}/third_party/corpora"
98
99# Local flags passed to sanitizers.
100UBSAN_FLAGS=(
101 -fsanitize=alignment
102 -fsanitize=bool
103 -fsanitize=bounds
104 -fsanitize=builtin
105 -fsanitize=enum
106 -fsanitize=float-cast-overflow
107 -fsanitize=float-divide-by-zero
108 -fsanitize=integer-divide-by-zero
109 -fsanitize=null
110 -fsanitize=object-size
111 -fsanitize=pointer-overflow
112 -fsanitize=return
113 -fsanitize=returns-nonnull-attribute
114 -fsanitize=shift-base
115 -fsanitize=shift-exponent
116 -fsanitize=unreachable
117 -fsanitize=vla-bound
118
119 -fno-sanitize-recover=undefined
120 # Brunsli uses unaligned accesses to uint32_t, so alignment is just a warning.
121 -fsanitize-recover=alignment
122)
123# -fsanitize=function doesn't work on aarch64 and arm.
124if [[ "${BUILD_TARGET%%-*}" != "aarch64" &&
125 "${BUILD_TARGET%%-*}" != "arm" ]]; then
126 UBSAN_FLAGS+=(
127 -fsanitize=function
128 )
129fi
130if [[ "${BUILD_TARGET%%-*}" != "arm" ]]; then
131 UBSAN_FLAGS+=(
132 -fsanitize=signed-integer-overflow
133 )
134fi
135
jpegxl-bot63349442020-05-25 08:56:34 +0200136CLANG_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 +0100137# Default to "cat" if "colordiff" is not installed or if stdout is not a tty.
138if [[ -t 1 ]]; then
139 COLORDIFF_BIN=$(which colordiff cat | head -n 1)
140else
141 COLORDIFF_BIN="cat"
142fi
jpegxl-botf84edfb2020-04-20 09:48:41 +0200143FIND_BIN=$(which gfind find | head -n 1)
144# "false" will disable wine64 when not installed. This won't allow
145# cross-compiling.
146WINE_BIN=$(which wine64 false | head -n 1)
jpegxl-botff093712019-12-27 18:12:34 +0100147
148CLANG_VERSION="${CLANG_VERSION:-}"
149# Detect the clang version suffix and store it in CLANG_VERSION. For example,
150# "6.0" for clang 6 or "7" for clang 7.
151detect_clang_version() {
152 if [[ -n "${CLANG_VERSION}" ]]; then
153 return 0
154 fi
155 local clang_version=$("${CC:-clang}" --version | head -n1)
jpegxl-bot35ad23d2021-01-29 00:08:06 +0100156 clang_version=${clang_version#"Debian "}
jpegxl-botff093712019-12-27 18:12:34 +0100157 local llvm_tag
158 case "${clang_version}" in
159 "clang version 6."*)
160 CLANG_VERSION="6.0"
161 ;;
jpegxl-bote3c58a02020-06-15 08:51:22 +0200162 "clang version "*)
163 # Any other clang version uses just the major version number.
164 local suffix="${clang_version#clang version }"
165 CLANG_VERSION="${suffix%%.*}"
jpegxl-bot63349442020-05-25 08:56:34 +0200166 ;;
167 "emcc"*)
168 # We can't use asan or msan in the emcc case.
169 ;;
jpegxl-botff093712019-12-27 18:12:34 +0100170 *)
171 echo "Unknown clang version: ${clang_version}" >&2
172 return 1
173 esac
174}
175
176# Temporary files cleanup hooks.
177CLEANUP_FILES=()
178cleanup() {
179 if [[ ${#CLEANUP_FILES[@]} -ne 0 ]]; then
180 rm -fr "${CLEANUP_FILES[@]}"
181 fi
182}
183
184# Executed on exit.
185on_exit() {
186 local retcode="$1"
187 # Always cleanup the CLEANUP_FILES.
188 cleanup
189
190 # Post a message in the MR when requested with POST_MESSAGE_ON_ERROR but only
191 # if the run failed and we are not running from a MR pipeline.
192 if [[ ${retcode} -ne 0 && -n "${CI_BUILD_NAME:-}" &&
193 -n "${POST_MESSAGE_ON_ERROR}" && -z "${CI_MERGE_REQUEST_ID:-}" &&
194 "${CI_BUILD_REF_NAME}" = "master" ]]; then
195 load_mr_vars_from_commit
196 { set +xeu; } 2>/dev/null
197 local message="**Run ${CI_BUILD_NAME} @ ${CI_COMMIT_SHORT_SHA} failed.**
198
199Check the output of the job at ${CI_JOB_URL:-} to see if this was your problem.
200If it was, please rollback this change or fix the problem ASAP, broken builds
201slow down development. Check if the error already existed in the previous build
202as well.
203
204Pipeline: ${CI_PIPELINE_URL}
205
206Previous build commit: ${CI_COMMIT_BEFORE_SHA}
207"
208 cmd_post_mr_comment "${message}"
209 fi
210}
211
212trap 'retcode=$?; { set +x; } 2>/dev/null; on_exit ${retcode}' INT TERM EXIT
213
214
215# These variables are populated when calling merge_request_commits().
216
217# The current hash at the top of the current branch or merge request branch (if
218# running from a merge request pipeline).
219MR_HEAD_SHA=""
220# The common ancestor between the current commit and the tracked branch, such
221# as master. This includes a list
222MR_ANCESTOR_SHA=""
223
224# Populate MR_HEAD_SHA and MR_ANCESTOR_SHA.
225merge_request_commits() {
226 { set +x; } 2>/dev/null
jpegxl-bot44778c62021-05-21 20:39:54 +0200227 # GITHUB_SHA is the current reference being build in GitHub Actions.
228 if [[ -n "${GITHUB_SHA:-}" ]]; then
Alex Deymo4ead4a12021-05-26 16:23:17 +0200229 # GitHub normally does a checkout of a merge commit on a shallow repository
230 # by default. We want to get a bit more of the history to be able to diff
231 # changes on the Pull Request if needed. This fetches 10 more commits which
232 # should be enough given that PR normally should have 1 commit.
233 git -C "${MYDIR}" fetch -q origin "${GITHUB_SHA}" --depth 10
234 MR_HEAD_SHA="$(git rev-parse "FETCH_HEAD^2" 2>/dev/null ||
235 echo "${GITHUB_SHA}")"
jpegxl-botff093712019-12-27 18:12:34 +0100236 else
jpegxl-bot44778c62021-05-21 20:39:54 +0200237 # CI_BUILD_REF is the reference currently being build in the CI workflow.
238 MR_HEAD_SHA=$(git -C "${MYDIR}" rev-parse -q "${CI_BUILD_REF:-HEAD}")
239 fi
240
241 if [[ -n "${CI_MERGE_REQUEST_IID:-}" ]]; then
jpegxl-botff093712019-12-27 18:12:34 +0100242 # Merge request pipeline in CI. In this case the upstream is called "origin"
243 # but it refers to the forked project that's the source of the merge
244 # request. We need to get the target of the merge request, for which we need
245 # to query that repository using our CI_JOB_TOKEN.
246 echo "machine gitlab.com login gitlab-ci-token password ${CI_JOB_TOKEN}" \
247 >> "${HOME}/.netrc"
248 git -C "${MYDIR}" fetch "${CI_MERGE_REQUEST_PROJECT_URL}" \
249 "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}"
250 MR_ANCESTOR_SHA=$(git -C "${MYDIR}" rev-parse -q FETCH_HEAD)
jpegxl-bot44778c62021-05-21 20:39:54 +0200251 elif [[ -n "${GITHUB_BASE_REF:-}" ]]; then
252 # Pull request workflow in GitHub Actions. GitHub checkout action uses
253 # "origin" as the remote for the git checkout.
254 git -C "${MYDIR}" fetch -q origin "${GITHUB_BASE_REF}"
255 MR_ANCESTOR_SHA=$(git -C "${MYDIR}" rev-parse -q FETCH_HEAD)
256 else
257 # We are in a local branch, not a merge request.
258 MR_ANCESTOR_SHA=$(git -C "${MYDIR}" rev-parse -q HEAD@{upstream} || true)
jpegxl-botff093712019-12-27 18:12:34 +0100259 fi
jpegxl-bot44778c62021-05-21 20:39:54 +0200260
jpegxl-botff093712019-12-27 18:12:34 +0100261 if [[ -z "${MR_ANCESTOR_SHA}" ]]; then
262 echo "Warning, not tracking any branch, using the last commit in HEAD.">&2
263 # This prints the return value with just HEAD.
264 MR_ANCESTOR_SHA=$(git -C "${MYDIR}" rev-parse -q "${MR_HEAD_SHA}^")
265 else
jpegxl-bot44778c62021-05-21 20:39:54 +0200266 # GitHub runs the pipeline on a merge commit, no need to look for the common
267 # ancestor in that case.
268 if [[ -z "${GITHUB_BASE_REF:-}" ]]; then
269 MR_ANCESTOR_SHA=$(git -C "${MYDIR}" merge-base \
270 "${MR_ANCESTOR_SHA}" "${MR_HEAD_SHA}")
271 fi
jpegxl-botff093712019-12-27 18:12:34 +0100272 fi
273 set -x
274}
275
276# Load the MR iid from the landed commit message when running not from a
277# merge request workflow. This is useful to post back results at the merge
278# request when running pipelines from master.
279load_mr_vars_from_commit() {
280 { set +x; } 2>/dev/null
281 if [[ -z "${CI_MERGE_REQUEST_IID:-}" ]]; then
282 local mr_iid=$(git rev-list --format=%B --max-count=1 HEAD |
jpegxl-bot0709f3a2020-02-19 14:37:22 +0100283 grep -F "${CI_PROJECT_URL}" | grep -F "/merge_requests" | head -n 1)
jpegxl-botff093712019-12-27 18:12:34 +0100284 # mr_iid contains a string like this if it matched:
285 # Part-of: <https://gitlab.com/wg1/jpeg-xlm/merge_requests/123456>
286 if [[ -n "${mr_iid}" ]]; then
287 mr_iid=$(echo "${mr_iid}" |
288 sed -E 's,^.*merge_requests/([0-9]+)>.*$,\1,')
289 CI_MERGE_REQUEST_IID="${mr_iid}"
290 CI_MERGE_REQUEST_PROJECT_ID=${CI_PROJECT_ID}
291 fi
292 fi
293 set -x
294}
295
296# Posts a comment to the current merge request.
297cmd_post_mr_comment() {
298 { set +x; } 2>/dev/null
299 local comment="$1"
300 if [[ -n "${BOT_TOKEN:-}" && -n "${CI_MERGE_REQUEST_IID:-}" ]]; then
301 local url="${CI_API_V4_URL}/projects/${CI_MERGE_REQUEST_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}/notes"
302 curl -X POST -g \
303 -H "PRIVATE-TOKEN: ${BOT_TOKEN}" \
304 --data-urlencode "body=${comment}" \
305 --output /dev/null \
306 "${url}"
307 fi
308 set -x
309}
310
jpegxl-botf84edfb2020-04-20 09:48:41 +0200311# Set up and export the environment variables needed by the child processes.
312export_env() {
313 if [[ "${BUILD_TARGET}" == *mingw32 ]]; then
314 # Wine needs to know the paths to the mingw dlls. These should be
315 # separated by ';'.
316 WINEPATH=$("${CC:-clang}" -print-search-dirs --target="${BUILD_TARGET}" \
317 | grep -F 'libraries: =' | cut -f 2- -d '=' | tr ':' ';')
318 # We also need our own libraries in the wine path.
319 local real_build_dir=$(realpath "${BUILD_DIR}")
jpegxl-bot9e183e12020-10-29 12:36:26 +0100320 # Some library .dll dependencies are installed in /bin:
jpegxl-botab7c5e92021-04-21 19:22:38 +0200321 export WINEPATH="${WINEPATH};${real_build_dir};${real_build_dir}/third_party/brotli;/usr/${BUILD_TARGET}/bin"
jpegxl-botf84edfb2020-04-20 09:48:41 +0200322
323 local prefix="${BUILD_DIR}/wineprefix"
324 mkdir -p "${prefix}"
325 export WINEPREFIX=$(realpath "${prefix}")
326 fi
jpegxl-bot63349442020-05-25 08:56:34 +0200327 # Sanitizers need these variables to print and properly format the stack
328 # traces:
jpegxl-bote3c58a02020-06-15 08:51:22 +0200329 LLVM_SYMBOLIZER=$("${CC:-clang}" -print-prog-name=llvm-symbolizer || true)
330 if [[ -n "${LLVM_SYMBOLIZER}" ]]; then
jpegxl-bot63349442020-05-25 08:56:34 +0200331 export ASAN_SYMBOLIZER_PATH="${LLVM_SYMBOLIZER}"
332 export MSAN_SYMBOLIZER_PATH="${LLVM_SYMBOLIZER}"
333 export UBSAN_SYMBOLIZER_PATH="${LLVM_SYMBOLIZER}"
334 fi
jpegxl-botf84edfb2020-04-20 09:48:41 +0200335}
336
jpegxl-botff093712019-12-27 18:12:34 +0100337cmake_configure() {
jpegxl-botf84edfb2020-04-20 09:48:41 +0200338 export_env
jpegxl-bot849ebf62020-09-29 16:23:20 +0200339
340 if [[ "${STACK_SIZE:-0}" == 1 ]]; then
341 # Dump the stack size of each function in the .stack_sizes section for
342 # analysis.
343 CMAKE_C_FLAGS+=" -fstack-size-section"
344 CMAKE_CXX_FLAGS+=" -fstack-size-section"
345 fi
346
jpegxl-botff093712019-12-27 18:12:34 +0100347 local args=(
348 -B"${BUILD_DIR}" -H"${MYDIR}"
349 -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}"
350 -G Ninja
351 -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}"
352 -DCMAKE_C_FLAGS="${CMAKE_C_FLAGS}"
353 -DCMAKE_TOOLCHAIN_FILE="${CMAKE_TOOLCHAIN_FILE}"
354 -DCMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS}"
355 -DCMAKE_MODULE_LINKER_FLAGS="${CMAKE_MODULE_LINKER_FLAGS}"
356 -DCMAKE_SHARED_LINKER_FLAGS="${CMAKE_SHARED_LINKER_FLAGS}"
jpegxl-bot0709f3a2020-02-19 14:37:22 +0100357 -DJPEGXL_VERSION="${JPEGXL_VERSION}"
jpegxl-bot63349442020-05-25 08:56:34 +0200358 -DSANITIZER="${SANITIZER}"
jpegxl-bot9e183e12020-10-29 12:36:26 +0100359 # These are not enabled by default in cmake.
360 -DJPEGXL_ENABLE_VIEWERS=ON
361 -DJPEGXL_ENABLE_PLUGINS=ON
362 -DJPEGXL_ENABLE_DEVTOOLS=ON
Alex Deymo263433d2021-06-04 21:07:43 +0200363 # We always use libfuzzer in the ci.sh wrapper.
364 -DJPEGXL_FUZZER_LINK_FLAGS="-fsanitize=fuzzer"
jpegxl-botff093712019-12-27 18:12:34 +0100365 )
jpegxl-botab7c5e92021-04-21 19:22:38 +0200366 if [[ "${BUILD_TARGET}" != *mingw32 ]]; then
367 args+=(
368 -DJPEGXL_WARNINGS_AS_ERRORS=ON
369 )
370 fi
jpegxl-botff093712019-12-27 18:12:34 +0100371 if [[ -n "${BUILD_TARGET}" ]]; then
jpegxl-botf84edfb2020-04-20 09:48:41 +0200372 local system_name="Linux"
373 if [[ "${BUILD_TARGET}" == *mingw32 ]]; then
374 # When cross-compiling with mingw the target must be set to Windows and
375 # run programs with wine.
376 system_name="Windows"
377 args+=(
378 -DCMAKE_CROSSCOMPILING_EMULATOR="${WINE_BIN}"
379 # Normally CMake automatically defines MINGW=1 when building with the
380 # mingw compiler (x86_64-w64-mingw32-gcc) but we are normally compiling
381 # with clang.
382 -DMINGW=1
383 )
384 fi
jpegxl-bot63349442020-05-25 08:56:34 +0200385 # EMSCRIPTEN toolchain sets the right values itself
386 if [[ "${BUILD_TARGET}" != wasm* ]]; then
387 # If set, BUILD_TARGET must be the target triplet such as
388 # x86_64-unknown-linux-gnu.
389 args+=(
390 -DCMAKE_C_COMPILER_TARGET="${BUILD_TARGET}"
391 -DCMAKE_CXX_COMPILER_TARGET="${BUILD_TARGET}"
392 # Only the first element of the target triplet.
393 -DCMAKE_SYSTEM_PROCESSOR="${BUILD_TARGET%%-*}"
394 -DCMAKE_SYSTEM_NAME="${system_name}"
395 )
jpegxl-bot849ebf62020-09-29 16:23:20 +0200396 else
397 # sjpeg confuses WASM SIMD with SSE.
398 args+=(
399 -DSJPEG_ENABLE_SIMD=OFF
400 )
jpegxl-bot63349442020-05-25 08:56:34 +0200401 fi
jpegxl-botff093712019-12-27 18:12:34 +0100402 args+=(
jpegxl-botff093712019-12-27 18:12:34 +0100403 # These are needed to make googletest work when cross-compiling.
404 -DCMAKE_CROSSCOMPILING=1
405 -DHAVE_STD_REGEX=0
406 -DHAVE_POSIX_REGEX=0
407 -DHAVE_GNU_POSIX_REGEX=0
408 -DHAVE_STEADY_CLOCK=0
409 -DHAVE_THREAD_SAFETY_ATTRIBUTES=0
410 )
jpegxl-botf84edfb2020-04-20 09:48:41 +0200411 if [[ -z "${CMAKE_FIND_ROOT_PATH}" ]]; then
412 # find_package() will look in this prefix for libraries.
413 CMAKE_FIND_ROOT_PATH="/usr/${BUILD_TARGET}"
414 fi
jpegxl-bot63349442020-05-25 08:56:34 +0200415 if [[ -z "${CMAKE_PREFIX_PATH}" ]]; then
416 CMAKE_PREFIX_PATH="/usr/${BUILD_TARGET}"
417 fi
jpegxl-botf84edfb2020-04-20 09:48:41 +0200418 # Use pkg-config for the target. If there's no pkg-config available for the
419 # target we can set the PKG_CONFIG_PATH to the appropriate path in most
420 # linux distributions.
jpegxl-botff093712019-12-27 18:12:34 +0100421 local pkg_config=$(which "${BUILD_TARGET}-pkg-config" || true)
jpegxl-botf84edfb2020-04-20 09:48:41 +0200422 if [[ -z "${pkg_config}" ]]; then
423 pkg_config=$(which pkg-config)
424 export PKG_CONFIG_LIBDIR="/usr/${BUILD_TARGET}/lib/pkgconfig"
425 fi
jpegxl-botff093712019-12-27 18:12:34 +0100426 if [[ -n "${pkg_config}" ]]; then
427 args+=(-DPKG_CONFIG_EXECUTABLE="${pkg_config}")
428 fi
429 fi
jpegxl-botb3a65712020-02-06 13:22:22 +0100430 if [[ -n "${CMAKE_CROSSCOMPILING_EMULATOR}" ]]; then
431 args+=(
432 -DCMAKE_CROSSCOMPILING_EMULATOR="${CMAKE_CROSSCOMPILING_EMULATOR}"
433 )
434 fi
jpegxl-botf84edfb2020-04-20 09:48:41 +0200435 if [[ -n "${CMAKE_FIND_ROOT_PATH}" ]]; then
436 args+=(
437 -DCMAKE_FIND_ROOT_PATH="${CMAKE_FIND_ROOT_PATH}"
438 )
439 fi
jpegxl-bot63349442020-05-25 08:56:34 +0200440 if [[ -n "${CMAKE_PREFIX_PATH}" ]]; then
441 args+=(
442 -DCMAKE_PREFIX_PATH="${CMAKE_PREFIX_PATH}"
443 )
444 fi
jpegxl-bot50bbf272020-06-10 14:59:11 +0200445 if [[ -n "${CMAKE_C_COMPILER_LAUNCHER}" ]]; then
446 args+=(
447 -DCMAKE_C_COMPILER_LAUNCHER="${CMAKE_C_COMPILER_LAUNCHER}"
448 )
449 fi
450 if [[ -n "${CMAKE_CXX_COMPILER_LAUNCHER}" ]]; then
451 args+=(
452 -DCMAKE_CXX_COMPILER_LAUNCHER="${CMAKE_CXX_COMPILER_LAUNCHER}"
453 )
454 fi
jpegxl-bote3c58a02020-06-15 08:51:22 +0200455 if [[ -n "${CMAKE_MAKE_PROGRAM}" ]]; then
456 args+=(
457 -DCMAKE_MAKE_PROGRAM="${CMAKE_MAKE_PROGRAM}"
458 )
459 fi
jpegxl-botff093712019-12-27 18:12:34 +0100460 cmake "${args[@]}" "$@"
461}
462
463cmake_build_and_test() {
464 # gtest_discover_tests() runs the test binaries to discover the list of tests
465 # at build time, which fails under qemu.
jpegxl-bot50bbf272020-06-10 14:59:11 +0200466 ASAN_OPTIONS=detect_leaks=0 cmake --build "${BUILD_DIR}" -- all doc
jpegxl-botff093712019-12-27 18:12:34 +0100467 # Pack test binaries if requested.
468 if [[ "${PACK_TEST:-}" == "1" ]]; then
469 (cd "${BUILD_DIR}"
jpegxl-botf84edfb2020-04-20 09:48:41 +0200470 ${FIND_BIN} -name '*.cmake' -a '!' -path '*CMakeFiles*'
Alex Deymob3a008a2021-10-25 18:15:43 +0200471 # gtest / gmock / gtest_main shared libs
472 ${FIND_BIN} lib/ -name 'libg*.so*'
jpegxl-botf84edfb2020-04-20 09:48:41 +0200473 ${FIND_BIN} -type d -name tests -a '!' -path '*CMakeFiles*'
jpegxl-botff093712019-12-27 18:12:34 +0100474 ) | tar -C "${BUILD_DIR}" -cf "${BUILD_DIR}/tests.tar.xz" -T - \
475 --use-compress-program="xz --threads=$(nproc --all || echo 1) -6"
476 du -h "${BUILD_DIR}/tests.tar.xz"
477 # Pack coverage data if also available.
478 touch "${BUILD_DIR}/gcno.sentinel"
jpegxl-botf84edfb2020-04-20 09:48:41 +0200479 (cd "${BUILD_DIR}"; echo gcno.sentinel; ${FIND_BIN} -name '*gcno') | \
jpegxl-botff093712019-12-27 18:12:34 +0100480 tar -C "${BUILD_DIR}" -cvf "${BUILD_DIR}/gcno.tar.xz" -T - \
481 --use-compress-program="xz --threads=$(nproc --all || echo 1) -6"
482 fi
483
484 if [[ "${SKIP_TEST}" -ne "1" ]]; then
485 (cd "${BUILD_DIR}"
486 export UBSAN_OPTIONS=print_stacktrace=1
jpegxl-bot56fd0222020-10-06 14:50:49 +0200487 [[ "${TEST_STACK_LIMIT}" == "none" ]] || ulimit -s "${TEST_STACK_LIMIT}"
jpegxl-botff093712019-12-27 18:12:34 +0100488 ctest -j $(nproc --all || echo 1) --output-on-failure)
489 fi
490}
491
492# Configure the build to strip unused functions. This considerably reduces the
493# output size, specially for tests which only use a small part of the whole
494# library.
495strip_dead_code() {
496 # Emscripten does tree shaking without any extra flags.
497 if [[ "${CMAKE_TOOLCHAIN_FILE##*/}" == "Emscripten.cmake" ]]; then
498 return 0
499 fi
500 # -ffunction-sections, -fdata-sections and -Wl,--gc-sections effectively
501 # discard all unreachable code, reducing the code size. For this to work, we
502 # need to also pass --no-export-dynamic to prevent it from exporting all the
503 # internal symbols (like functions) making them all reachable and thus not a
504 # candidate for removal.
505 CMAKE_CXX_FLAGS+=" -ffunction-sections -fdata-sections"
506 CMAKE_C_FLAGS+=" -ffunction-sections -fdata-sections"
507 if [[ "${OS}" == "Darwin" ]]; then
508 CMAKE_EXE_LINKER_FLAGS+=" -dead_strip"
509 CMAKE_SHARED_LINKER_FLAGS+=" -dead_strip"
510 else
511 CMAKE_EXE_LINKER_FLAGS+=" -Wl,--gc-sections -Wl,--no-export-dynamic"
512 CMAKE_SHARED_LINKER_FLAGS+=" -Wl,--gc-sections -Wl,--no-export-dynamic"
513 fi
514}
515
516### Externally visible commands
517
518cmd_debug() {
519 CMAKE_BUILD_TYPE="Debug"
520 cmake_configure "$@"
521 cmake_build_and_test
522}
523
524cmd_release() {
525 CMAKE_BUILD_TYPE="Release"
526 strip_dead_code
527 cmake_configure "$@"
528 cmake_build_and_test
529}
530
531cmd_opt() {
532 CMAKE_BUILD_TYPE="RelWithDebInfo"
533 CMAKE_CXX_FLAGS+=" -DJXL_DEBUG_WARNING -DJXL_DEBUG_ON_ERROR"
534 cmake_configure "$@"
535 cmake_build_and_test
536}
537
538cmd_coverage() {
jpegxl-botf2aeba72021-03-16 12:35:53 +0100539 # -O0 prohibits stack space reuse -> causes stack-overflow on dozens of tests.
540 TEST_STACK_LIMIT="none"
541
jpegxl-botff093712019-12-27 18:12:34 +0100542 cmd_release -DJPEGXL_ENABLE_COVERAGE=ON "$@"
543
544 if [[ "${SKIP_TEST}" -ne "1" ]]; then
545 # If we didn't run the test we also don't print a coverage report.
546 cmd_coverage_report
547 fi
548}
549
550cmd_coverage_report() {
jpegxl-bote3c58a02020-06-15 08:51:22 +0200551 LLVM_COV=$("${CC:-clang}" -print-prog-name=llvm-cov)
jpegxl-botf84edfb2020-04-20 09:48:41 +0200552 local real_build_dir=$(realpath "${BUILD_DIR}")
jpegxl-botff093712019-12-27 18:12:34 +0100553 local gcovr_args=(
554 -r "${real_build_dir}"
555 --gcov-executable "${LLVM_COV} gcov"
Jon Sneyers702cd542021-09-28 10:19:14 +0200556 # Only print coverage information for the libjxl directories. The rest
jpegxl-botff093712019-12-27 18:12:34 +0100557 # is not part of the code under test.
558 --filter '.*jxl/.*'
559 --exclude '.*_test.cc'
Jon Sneyersc06061c2021-09-28 13:55:29 +0200560 --exclude '.*_testonly..*'
Jon Sneyers702cd542021-09-28 10:19:14 +0200561 --exclude '.*test_utils..*'
jpegxl-botff093712019-12-27 18:12:34 +0100562 --object-directory "${real_build_dir}"
563 )
564
565 (
566 cd "${real_build_dir}"
567 gcovr "${gcovr_args[@]}" --html --html-details \
568 --output="${real_build_dir}/coverage.html"
569 gcovr "${gcovr_args[@]}" --print-summary |
570 tee "${real_build_dir}/coverage.txt"
571 gcovr "${gcovr_args[@]}" --xml --output="${real_build_dir}/coverage.xml"
572 )
573}
574
575cmd_test() {
jpegxl-botf84edfb2020-04-20 09:48:41 +0200576 export_env
jpegxl-botff093712019-12-27 18:12:34 +0100577 # Unpack tests if needed.
578 if [[ -e "${BUILD_DIR}/tests.tar.xz" && ! -d "${BUILD_DIR}/tests" ]]; then
579 tar -C "${BUILD_DIR}" -Jxvf "${BUILD_DIR}/tests.tar.xz"
580 fi
581 if [[ -e "${BUILD_DIR}/gcno.tar.xz" && ! -d "${BUILD_DIR}/gcno.sentinel" ]]; then
582 tar -C "${BUILD_DIR}" -Jxvf "${BUILD_DIR}/gcno.tar.xz"
583 fi
584 (cd "${BUILD_DIR}"
585 export UBSAN_OPTIONS=print_stacktrace=1
jpegxl-bot56fd0222020-10-06 14:50:49 +0200586 [[ "${TEST_STACK_LIMIT}" == "none" ]] || ulimit -s "${TEST_STACK_LIMIT}"
jpegxl-botf84edfb2020-04-20 09:48:41 +0200587 ctest -j $(nproc --all || echo 1) --output-on-failure "$@")
jpegxl-botff093712019-12-27 18:12:34 +0100588}
589
jpegxl-bot5175d112021-02-23 16:59:45 +0100590cmd_gbench() {
591 export_env
592 (cd "${BUILD_DIR}"
593 export UBSAN_OPTIONS=print_stacktrace=1
594 lib/jxl_gbench \
595 --benchmark_counters_tabular=true \
596 --benchmark_out_format=json \
597 --benchmark_out=gbench.json "$@"
598 )
599}
600
Alex Deymo263433d2021-06-04 21:07:43 +0200601cmd_asanfuzz() {
602 CMAKE_CXX_FLAGS+=" -fsanitize=fuzzer-no-link"
603 CMAKE_C_FLAGS+=" -fsanitize=fuzzer-no-link"
604 cmd_asan -DJPEGXL_ENABLE_FUZZERS=ON "$@"
605}
606
607cmd_msanfuzz() {
608 # Install msan if needed before changing the flags.
609 detect_clang_version
610 local msan_prefix="${HOME}/.msan/${CLANG_VERSION}"
611 if [[ ! -d "${msan_prefix}" || -e "${msan_prefix}/lib/libc++abi.a" ]]; then
612 # Install msan libraries for this version if needed or if an older version
613 # with libc++abi was installed.
614 cmd_msan_install
615 fi
616
617 CMAKE_CXX_FLAGS+=" -fsanitize=fuzzer-no-link"
618 CMAKE_C_FLAGS+=" -fsanitize=fuzzer-no-link"
619 cmd_msan -DJPEGXL_ENABLE_FUZZERS=ON "$@"
620}
621
jpegxl-botff093712019-12-27 18:12:34 +0100622cmd_asan() {
jpegxl-bot63349442020-05-25 08:56:34 +0200623 SANITIZER="asan"
jpegxl-botff093712019-12-27 18:12:34 +0100624 CMAKE_C_FLAGS+=" -DJXL_ENABLE_ASSERT=1 -g -DADDRESS_SANITIZER \
625 -fsanitize=address ${UBSAN_FLAGS[@]}"
626 CMAKE_CXX_FLAGS+=" -DJXL_ENABLE_ASSERT=1 -g -DADDRESS_SANITIZER \
627 -fsanitize=address ${UBSAN_FLAGS[@]}"
628 strip_dead_code
jpegxl-botb3a65712020-02-06 13:22:22 +0100629 cmake_configure "$@" -DJPEGXL_ENABLE_TCMALLOC=OFF
jpegxl-botff093712019-12-27 18:12:34 +0100630 cmake_build_and_test
631}
632
633cmd_tsan() {
jpegxl-bot63349442020-05-25 08:56:34 +0200634 SANITIZER="tsan"
jpegxl-botff093712019-12-27 18:12:34 +0100635 local tsan_args=(
636 -DJXL_ENABLE_ASSERT=1
637 -g
638 -DTHREAD_SANITIZER
639 ${UBSAN_FLAGS[@]}
640 -fsanitize=thread
641 )
642 CMAKE_C_FLAGS+=" ${tsan_args[@]}"
643 CMAKE_CXX_FLAGS+=" ${tsan_args[@]}"
644
645 CMAKE_BUILD_TYPE="RelWithDebInfo"
646 cmake_configure "$@" -DJPEGXL_ENABLE_TCMALLOC=OFF
647 cmake_build_and_test
648}
649
650cmd_msan() {
jpegxl-bot63349442020-05-25 08:56:34 +0200651 SANITIZER="msan"
jpegxl-botff093712019-12-27 18:12:34 +0100652 detect_clang_version
653 local msan_prefix="${HOME}/.msan/${CLANG_VERSION}"
654 if [[ ! -d "${msan_prefix}" || -e "${msan_prefix}/lib/libc++abi.a" ]]; then
655 # Install msan libraries for this version if needed or if an older version
656 # with libc++abi was installed.
657 cmd_msan_install
658 fi
659
660 local msan_c_flags=(
661 -fsanitize=memory
662 -fno-omit-frame-pointer
663 -fsanitize-memory-track-origins
664
665 -DJXL_ENABLE_ASSERT=1
666 -g
667 -DMEMORY_SANITIZER
668
669 # Force gtest to not use the cxxbai.
670 -DGTEST_HAS_CXXABI_H_=0
671 )
672 local msan_cxx_flags=(
673 "${msan_c_flags[@]}"
674
675 # Some C++ sources don't use the std at all, so the -stdlib=libc++ is unused
676 # in those cases. Ignore the warning.
677 -Wno-unused-command-line-argument
678 -stdlib=libc++
679
680 # We include the libc++ from the msan directory instead, so we don't want
681 # the std includes.
682 -nostdinc++
683 -cxx-isystem"${msan_prefix}/include/c++/v1"
684 )
685
686 local msan_linker_flags=(
687 -L"${msan_prefix}"/lib
688 -Wl,-rpath -Wl,"${msan_prefix}"/lib/
689 )
690
jpegxl-botff093712019-12-27 18:12:34 +0100691 CMAKE_C_FLAGS+=" ${msan_c_flags[@]} ${UBSAN_FLAGS[@]}"
692 CMAKE_CXX_FLAGS+=" ${msan_cxx_flags[@]} ${UBSAN_FLAGS[@]}"
693 CMAKE_EXE_LINKER_FLAGS+=" ${msan_linker_flags[@]}"
694 CMAKE_MODULE_LINKER_FLAGS+=" ${msan_linker_flags[@]}"
695 CMAKE_SHARED_LINKER_FLAGS+=" ${msan_linker_flags[@]}"
696 strip_dead_code
697 cmake_configure "$@" \
jpegxl-botb3a65712020-02-06 13:22:22 +0100698 -DCMAKE_CROSSCOMPILING=1 -DRUN_HAVE_STD_REGEX=0 -DRUN_HAVE_POSIX_REGEX=0 \
699 -DJPEGXL_ENABLE_TCMALLOC=OFF
jpegxl-botff093712019-12-27 18:12:34 +0100700 cmake_build_and_test
701}
702
703# Install libc++ libraries compiled with msan in the msan_prefix for the current
704# compiler version.
705cmd_msan_install() {
706 local tmpdir=$(mktemp -d)
707 CLEANUP_FILES+=("${tmpdir}")
708 # Detect the llvm to install:
709 export CC="${CC:-clang}"
710 export CXX="${CXX:-clang++}"
711 detect_clang_version
jpegxl-bote3c58a02020-06-15 08:51:22 +0200712 local llvm_tag="llvmorg-${CLANG_VERSION}.0.0"
jpegxl-botff093712019-12-27 18:12:34 +0100713 case "${CLANG_VERSION}" in
714 "6.0")
715 llvm_tag="llvmorg-6.0.1"
716 ;;
717 "7")
718 llvm_tag="llvmorg-7.0.1"
719 ;;
jpegxl-botff093712019-12-27 18:12:34 +0100720 esac
721 local llvm_targz="${tmpdir}/${llvm_tag}.tar.gz"
722 curl -L --show-error -o "${llvm_targz}" \
723 "https://github.com/llvm/llvm-project/archive/${llvm_tag}.tar.gz"
724 tar -C "${tmpdir}" -zxf "${llvm_targz}"
725 local llvm_root="${tmpdir}/llvm-project-${llvm_tag}"
726
727 local msan_prefix="${HOME}/.msan/${CLANG_VERSION}"
728 rm -rf "${msan_prefix}"
729
730 declare -A CMAKE_EXTRAS
731 CMAKE_EXTRAS[libcxx]="\
732 -DLIBCXX_CXX_ABI=libstdc++ \
733 -DLIBCXX_INSTALL_EXPERIMENTAL_LIBRARY=ON"
734
735 for project in libcxx; do
736 local proj_build="${tmpdir}/build-${project}"
737 local proj_dir="${llvm_root}/${project}"
738 mkdir -p "${proj_build}"
739 cmake -B"${proj_build}" -H"${proj_dir}" \
740 -G Ninja \
741 -DCMAKE_BUILD_TYPE=Release \
742 -DLLVM_USE_SANITIZER=Memory \
743 -DLLVM_PATH="${llvm_root}/llvm" \
744 -DLLVM_CONFIG_PATH="$(which llvm-config llvm-config-7 llvm-config-6.0 | \
745 head -n1)" \
746 -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}" \
747 -DCMAKE_C_FLAGS="${CMAKE_C_FLAGS}" \
748 -DCMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS}" \
749 -DCMAKE_SHARED_LINKER_FLAGS="${CMAKE_SHARED_LINKER_FLAGS}" \
750 -DCMAKE_INSTALL_PREFIX="${msan_prefix}" \
751 ${CMAKE_EXTRAS[${project}]}
752 cmake --build "${proj_build}"
753 ninja -C "${proj_build}" install
754 done
755}
756
Alex Deymo13396662021-06-15 20:07:37 +0200757# Internal build step shared between all cmd_ossfuzz_* commands.
758_cmd_ossfuzz() {
759 local sanitizer="$1"
760 shift
761 mkdir -p "${BUILD_DIR}"
762 local real_build_dir=$(realpath "${BUILD_DIR}")
763
764 # oss-fuzz defines three directories:
765 # * /work, with the working directory to do re-builds
766 # * /src, with the source code to build
767 # * /out, with the output directory where to copy over the built files.
768 # We use $BUILD_DIR as the /work and the script directory as the /src. The
769 # /out directory is ignored as developers are used to look for the fuzzers in
770 # $BUILD_DIR/tools/ directly.
771
Alex Deymob1f80162021-07-15 11:45:50 +0200772 if [[ "${sanitizer}" = "memory" && ! -d "${BUILD_DIR}/msan" ]]; then
Alex Deymo13396662021-06-15 20:07:37 +0200773 sudo docker run --rm -i \
774 --user $(id -u):$(id -g) \
775 -v "${real_build_dir}":/work \
776 gcr.io/oss-fuzz-base/msan-libs-builder \
777 bash -c "cp -r /msan /work"
778 fi
779
Alex Deymob1f80162021-07-15 11:45:50 +0200780 # Args passed to ninja. These will be evaluated as a string separated by
781 # spaces.
782 local jpegxl_extra_args="$@"
783
Alex Deymo13396662021-06-15 20:07:37 +0200784 sudo docker run --rm -i \
785 -e JPEGXL_UID=$(id -u) \
786 -e JPEGXL_GID=$(id -g) \
787 -e FUZZING_ENGINE="${FUZZING_ENGINE:-libfuzzer}" \
788 -e SANITIZER="${sanitizer}" \
789 -e ARCHITECTURE=x86_64 \
790 -e FUZZING_LANGUAGE=c++ \
791 -e MSAN_LIBS_PATH="/work/msan" \
Alex Deymob1f80162021-07-15 11:45:50 +0200792 -e JPEGXL_EXTRA_ARGS="${jpegxl_extra_args}" \
Alex Deymo13396662021-06-15 20:07:37 +0200793 -v "${MYDIR}":/src/libjxl \
794 -v "${MYDIR}/tools/ossfuzz-build.sh":/src/build.sh \
795 -v "${real_build_dir}":/work \
Alex Deymo13396662021-06-15 20:07:37 +0200796 gcr.io/oss-fuzz/libjxl
797}
798
799cmd_ossfuzz_asan() {
800 _cmd_ossfuzz address "$@"
801}
802cmd_ossfuzz_msan() {
803 _cmd_ossfuzz memory "$@"
804}
805cmd_ossfuzz_ubsan() {
806 _cmd_ossfuzz undefined "$@"
807}
808
809cmd_ossfuzz_ninja() {
810 [[ -e "${BUILD_DIR}/build.ninja" ]]
811 local real_build_dir=$(realpath "${BUILD_DIR}")
812
Alex Deymoe8a9c5e2021-07-02 13:47:34 +0200813 if [[ -e "${BUILD_DIR}/msan" ]]; then
814 echo "ossfuzz_ninja doesn't work with msan builds. Use ossfuzz_msan." >&2
815 exit 1
816 fi
817
Alex Deymo13396662021-06-15 20:07:37 +0200818 sudo docker run --rm -i \
819 --user $(id -u):$(id -g) \
820 -v "${MYDIR}":/src/libjxl \
821 -v "${real_build_dir}":/work \
822 gcr.io/oss-fuzz/libjxl \
823 ninja -C /work "$@"
824}
825
jpegxl-botff093712019-12-27 18:12:34 +0100826cmd_fast_benchmark() {
827 local small_corpus_tar="${BENCHMARK_CORPORA}/jyrki-full.tar"
828 mkdir -p "${BENCHMARK_CORPORA}"
829 curl --show-error -o "${small_corpus_tar}" -z "${small_corpus_tar}" \
830 "https://storage.googleapis.com/artifacts.jpegxl.appspot.com/corpora/jyrki-full.tar"
831
832 local tmpdir=$(mktemp -d)
833 CLEANUP_FILES+=("${tmpdir}")
834 tar -xf "${small_corpus_tar}" -C "${tmpdir}"
835
836 run_benchmark "${tmpdir}" 1048576
837}
838
839cmd_benchmark() {
840 local nikon_corpus_tar="${BENCHMARK_CORPORA}/nikon-subset.tar"
841 mkdir -p "${BENCHMARK_CORPORA}"
842 curl --show-error -o "${nikon_corpus_tar}" -z "${nikon_corpus_tar}" \
843 "https://storage.googleapis.com/artifacts.jpegxl.appspot.com/corpora/nikon-subset.tar"
844
845 local tmpdir=$(mktemp -d)
846 CLEANUP_FILES+=("${tmpdir}")
847 tar -xvf "${nikon_corpus_tar}" -C "${tmpdir}"
848
849 local sem_id="jpegxl_benchmark-$$"
850 local nprocs=$(nproc --all || echo 1)
851 images=()
852 local filename
853 while IFS= read -r filename; do
854 # This removes the './'
855 filename="${filename:2}"
856 local mode
857 if [[ "${filename:0:4}" == "srgb" ]]; then
858 mode="RGB_D65_SRG_Rel_SRG"
859 elif [[ "${filename:0:5}" == "adobe" ]]; then
860 mode="RGB_D65_Ado_Rel_Ado"
861 else
862 echo "Unknown image colorspace: ${filename}" >&2
863 exit 1
864 fi
865 png_filename="${filename%.ppm}.png"
866 png_filename=$(echo "${png_filename}" | tr '/' '_')
867 sem --bg --id "${sem_id}" -j"${nprocs}" -- \
868 "${BUILD_DIR}/tools/decode_and_encode" \
869 "${tmpdir}/${filename}" "${mode}" "${tmpdir}/${png_filename}"
870 images+=( "${png_filename}" )
jpegxl-botf84edfb2020-04-20 09:48:41 +0200871 done < <(cd "${tmpdir}"; ${FIND_BIN} . -name '*.ppm' -type f)
jpegxl-botff093712019-12-27 18:12:34 +0100872 sem --id "${sem_id}" --wait
873
874 # We need about 10 GiB per thread on these images.
875 run_benchmark "${tmpdir}" 10485760
876}
877
878get_mem_available() {
879 if [[ "${OS}" == "Darwin" ]]; then
880 echo $(vm_stat | grep -F 'Pages free:' | awk '{print $3 * 4}')
881 else
882 echo $(grep -F MemAvailable: /proc/meminfo | awk '{print $2}')
883 fi
884}
885
886run_benchmark() {
887 local src_img_dir="$1"
888 local mem_per_thread="${2:-10485760}"
889
890 local output_dir="${BUILD_DIR}/benchmark_results"
891 mkdir -p "${output_dir}"
892
893 # The memory available at the beginning of the benchmark run in kB. The number
894 # of threads depends on the available memory, and the passed memory per
895 # thread. We also add a 2 GiB of constant memory.
896 local mem_available="$(get_mem_available)"
897 # Check that we actually have a MemAvailable value.
898 [[ -n "${mem_available}" ]]
899 local num_threads=$(( (${mem_available} - 1048576) / ${mem_per_thread} ))
900 if [[ ${num_threads} -le 0 ]]; then
901 num_threads=1
902 fi
903
904 local benchmark_args=(
905 --input "${src_img_dir}/*.png"
Jon Sneyers100afad2021-06-10 14:51:14 +0200906 --codec=jpeg:yuv420:q85,webp:q80,jxl:fast:d1,jxl:fast:d1:downsampling=8,jxl:fast:d4,jxl:fast:d4:downsampling=8,jxl:cheetah:m,jxl:m:cheetah:P6,jxl:m:falcon:q80
jpegxl-botff093712019-12-27 18:12:34 +0100907 --output_dir "${output_dir}"
908 --noprofiler --show_progress
909 --num_threads="${num_threads}"
910 )
911 if [[ "${STORE_IMAGES}" == "1" ]]; then
912 benchmark_args+=(--save_decompressed --save_compressed)
913 fi
jpegxl-bot849ebf62020-09-29 16:23:20 +0200914 (
jpegxl-bot56fd0222020-10-06 14:50:49 +0200915 [[ "${TEST_STACK_LIMIT}" == "none" ]] || ulimit -s "${TEST_STACK_LIMIT}"
jpegxl-bot849ebf62020-09-29 16:23:20 +0200916 "${BUILD_DIR}/tools/benchmark_xl" "${benchmark_args[@]}" | \
917 tee "${output_dir}/results.txt"
918
919 # Check error code for benckmark_xl command. This will exit if not.
920 return ${PIPESTATUS[0]}
921 )
jpegxl-botff093712019-12-27 18:12:34 +0100922
923 if [[ -n "${CI_BUILD_NAME:-}" ]]; then
924 { set +x; } 2>/dev/null
925 local message="Results for ${CI_BUILD_NAME} @ ${CI_COMMIT_SHORT_SHA} (job ${CI_JOB_URL:-}):
926
927$(cat "${output_dir}/results.txt")
928"
929 cmd_post_mr_comment "${message}"
930 set -x
931 fi
932}
933
934# Helper function to wait for the CPU temperature to cool down on ARM.
935wait_for_temp() {
936 { set +x; } 2>/dev/null
Alex Deymobaeaa1a2021-06-16 12:55:19 +0200937 local temp_limit=${1:-38000}
jpegxl-botff093712019-12-27 18:12:34 +0100938 if [[ -z "${THERMAL_FILE:-}" ]]; then
939 echo "Must define the THERMAL_FILE with the thermal_zoneX/temp file" \
940 "to read the temperature from. This is normally set in the runner." >&2
941 exit 1
942 fi
943 local org_temp=$(cat "${THERMAL_FILE}")
944 if [[ "${org_temp}" -ge "${temp_limit}" ]]; then
945 echo -n "Waiting for temp to get down from ${org_temp}... "
946 fi
947 local temp="${org_temp}"
Alex Deymobaeaa1a2021-06-16 12:55:19 +0200948 local secs=0
jpegxl-botff093712019-12-27 18:12:34 +0100949 while [[ "${temp}" -ge "${temp_limit}" ]]; do
950 sleep 1
951 temp=$(cat "${THERMAL_FILE}")
Alex Deymobaeaa1a2021-06-16 12:55:19 +0200952 echo -n "${temp} "
953 secs=$((secs + 1))
954 if [[ ${secs} -ge 5 ]]; then
955 break
956 fi
jpegxl-botff093712019-12-27 18:12:34 +0100957 done
958 if [[ "${org_temp}" -ge "${temp_limit}" ]]; then
959 echo "Done, temp=${temp}"
960 fi
961 set -x
962}
963
964# Helper function to set the cpuset restriction of the current process.
965cmd_cpuset() {
jpegxl-bot21f5f752020-06-30 13:06:56 +0200966 [[ "${SKIP_CPUSET:-}" != "1" ]] || return 0
jpegxl-botff093712019-12-27 18:12:34 +0100967 local newset="$1"
968 local mycpuset=$(cat /proc/self/cpuset)
969 mycpuset="/dev/cpuset${mycpuset}"
970 # Check that the directory exists:
971 [[ -d "${mycpuset}" ]]
jpegxl-botb3a65712020-02-06 13:22:22 +0100972 if [[ -e "${mycpuset}/cpuset.cpus" ]]; then
973 echo "${newset}" >"${mycpuset}/cpuset.cpus"
974 else
975 echo "${newset}" >"${mycpuset}/cpus"
976 fi
977}
978
979# Return the encoding/decoding speed from the Stats output.
980_speed_from_output() {
jpegxl-bot6b5144c2020-08-24 13:35:47 +0200981 local speed="$1"
982 local unit="${2:-MP/s}"
983 if [[ "${speed}" == *"${unit}"* ]]; then
984 speed="${speed%% ${unit}*}"
985 speed="${speed##* }"
986 echo "${speed}"
987 fi
jpegxl-botff093712019-12-27 18:12:34 +0100988}
989
jpegxl-bot6b5144c2020-08-24 13:35:47 +0200990
jpegxl-botff093712019-12-27 18:12:34 +0100991# Run benchmarks on ARM for the big and little CPUs.
992cmd_arm_benchmark() {
jpegxl-bot9e183e12020-10-29 12:36:26 +0100993 # Flags used for cjxl encoder with .png inputs
jpegxl-bot6b5144c2020-08-24 13:35:47 +0200994 local jxl_png_benchmarks=(
jpegxl-botff093712019-12-27 18:12:34 +0100995 # Lossy options:
jpegxl-bot9e183e12020-10-29 12:36:26 +0100996 "--epf=0 --distance=1.0 --speed=cheetah"
997 "--epf=2 --distance=1.0 --speed=cheetah"
998 "--epf=0 --distance=8.0 --speed=cheetah"
999 "--epf=1 --distance=8.0 --speed=cheetah"
1000 "--epf=2 --distance=8.0 --speed=cheetah"
1001 "--epf=3 --distance=8.0 --speed=cheetah"
jpegxl-bot131953a2020-11-10 15:30:00 +01001002 "--modular -Q 90"
1003 "--modular -Q 50"
jpegxl-botff093712019-12-27 18:12:34 +01001004 # Lossless options:
jpegxl-bot131953a2020-11-10 15:30:00 +01001005 "--modular"
1006 "--modular -E 0 -I 0"
1007 "--modular -P 5"
1008 "--modular --responsive=1"
jpegxl-botff093712019-12-27 18:12:34 +01001009 # Near-lossless options:
jpegxl-bot9e183e12020-10-29 12:36:26 +01001010 "--epf=0 --distance=0.3 --speed=fast"
jpegxl-bot131953a2020-11-10 15:30:00 +01001011 "--modular -Q 97"
jpegxl-botff093712019-12-27 18:12:34 +01001012 )
1013
jpegxl-bot9e183e12020-10-29 12:36:26 +01001014 # Flags used for cjxl encoder with .jpg inputs. These should do lossless
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001015 # JPEG recompression (of pixels or full jpeg).
1016 local jxl_jpeg_benchmarks=(
1017 "--num_reps=3"
1018 )
1019
jpegxl-botff093712019-12-27 18:12:34 +01001020 local images=(
1021 "third_party/testdata/imagecompression.info/flower_foveon.png"
1022 )
1023
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001024 local jpg_images=(
1025 "third_party/testdata/imagecompression.info/flower_foveon.png.im_q85_420.jpg"
1026 )
1027
jpegxl-bot21f5f752020-06-30 13:06:56 +02001028 if [[ "${SKIP_CPUSET:-}" == "1" ]]; then
1029 # Use a single cpu config in this case.
1030 local cpu_confs=("?")
1031 else
1032 # Otherwise the CPU config comes from the environment:
1033 local cpu_confs=(
1034 "${RUNNER_CPU_LITTLE}"
1035 "${RUNNER_CPU_BIG}"
1036 # The CPU description is something like 3-7, so these configurations only
1037 # take the first CPU of the group.
1038 "${RUNNER_CPU_LITTLE%%-*}"
1039 "${RUNNER_CPU_BIG%%-*}"
1040 )
1041 # Check that RUNNER_CPU_ALL is defined. In the SKIP_CPUSET=1 case this will
1042 # be ignored but still evaluated when calling cmd_cpuset.
1043 [[ -n "${RUNNER_CPU_ALL}" ]]
1044 fi
jpegxl-botb3a65712020-02-06 13:22:22 +01001045
1046 local jpg_dirname="third_party/corpora/jpeg"
1047 mkdir -p "${jpg_dirname}"
jpegxl-botb3a65712020-02-06 13:22:22 +01001048 local jpg_qualities=( 50 80 95 )
1049 for src_img in "${images[@]}"; do
1050 for q in "${jpg_qualities[@]}"; do
1051 local jpeg_name="${jpg_dirname}/"$(basename "${src_img}" .png)"-q${q}.jpg"
jpegxl-bot849ebf62020-09-29 16:23:20 +02001052 convert -sampling-factor 1x1 -quality "${q}" \
jpegxl-botb3a65712020-02-06 13:22:22 +01001053 "${src_img}" "${jpeg_name}"
1054 jpg_images+=("${jpeg_name}")
1055 done
1056 done
1057
jpegxl-botff093712019-12-27 18:12:34 +01001058 local output_dir="${BUILD_DIR}/benchmark_results"
1059 mkdir -p "${output_dir}"
1060 local runs_file="${output_dir}/runs.txt"
1061
1062 if [[ ! -e "${runs_file}" ]]; then
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001063 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 +01001064 tee -a "${runs_file}"
1065 fi
1066
jpegxl-botb3a65712020-02-06 13:22:22 +01001067 mkdir -p "${BUILD_DIR}/arm_benchmark"
jpegxl-botff093712019-12-27 18:12:34 +01001068 local flags
1069 local src_img
jpegxl-botb3a65712020-02-06 13:22:22 +01001070 for src_img in "${jpg_images[@]}" "${images[@]}"; do
jpegxl-botff093712019-12-27 18:12:34 +01001071 local src_img_hash=$(sha1sum "${src_img}" | cut -f 1 -d ' ')
jpegxl-bot9e183e12020-10-29 12:36:26 +01001072 local enc_binaries=("${BUILD_DIR}/tools/cjxl")
jpegxl-botb3a65712020-02-06 13:22:22 +01001073 local src_ext="${src_img##*.}"
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001074 for enc_binary in "${enc_binaries[@]}"; do
1075 local enc_binary_base=$(basename "${enc_binary}")
jpegxl-botff093712019-12-27 18:12:34 +01001076
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001077 # Select the list of flags to use for the current encoder/image pair.
1078 local img_benchmarks
jpegxl-botc8ce59f2020-10-12 16:06:35 +02001079 if [[ "${src_ext}" == "jpg" ]]; then
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001080 img_benchmarks=("${jxl_jpeg_benchmarks[@]}")
1081 else
1082 img_benchmarks=("${jxl_png_benchmarks[@]}")
1083 fi
jpegxl-botb3a65712020-02-06 13:22:22 +01001084
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001085 for flags in "${img_benchmarks[@]}"; do
1086 # Encoding step.
1087 local enc_file_hash="${enc_binary_base} || $flags || ${src_img} || ${src_img_hash}"
1088 enc_file_hash=$(echo "${enc_file_hash}" | sha1sum | cut -f 1 -d ' ')
1089 local enc_file="${BUILD_DIR}/arm_benchmark/${enc_file_hash}.jxl"
1090
1091 for cpu_conf in "${cpu_confs[@]}"; do
1092 cmd_cpuset "${cpu_conf}"
1093 # nproc returns the number of active CPUs, which is given by the cpuset
1094 # mask.
1095 local num_threads="$(nproc)"
1096
1097 echo "Encoding with: ${enc_binary_base} img=${src_img} cpus=${cpu_conf} enc_flags=${flags}"
1098 local enc_output
jpegxl-bot131953a2020-11-10 15:30:00 +01001099 if [[ "${flags}" == *"modular"* ]]; then
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001100 # We don't benchmark encoding speed in this case.
1101 if [[ ! -f "${enc_file}" ]]; then
1102 cmd_cpuset "${RUNNER_CPU_ALL:-}"
1103 "${enc_binary}" ${flags} "${src_img}" "${enc_file}.tmp"
1104 mv "${enc_file}.tmp" "${enc_file}"
1105 cmd_cpuset "${cpu_conf}"
1106 fi
1107 enc_output=" ?? MP/s"
1108 else
1109 wait_for_temp
1110 enc_output=$("${enc_binary}" ${flags} "${src_img}" "${enc_file}.tmp" \
1111 2>&1 | tee /dev/stderr | grep -F "MP/s [")
jpegxl-botb3a65712020-02-06 13:22:22 +01001112 mv "${enc_file}.tmp" "${enc_file}"
jpegxl-botb3a65712020-02-06 13:22:22 +01001113 fi
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001114 local enc_speed=$(_speed_from_output "${enc_output}")
1115 local enc_size=$(stat -c "%s" "${enc_file}")
1116
1117 echo "Decoding with: img=${src_img} cpus=${cpu_conf} enc_flags=${flags}"
1118
1119 local dec_output
jpegxl-botb3a65712020-02-06 13:22:22 +01001120 wait_for_temp
jpegxl-bot9e183e12020-10-29 12:36:26 +01001121 dec_output=$("${BUILD_DIR}/tools/djxl" "${enc_file}" \
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001122 --num_reps=5 --num_threads="${num_threads}" 2>&1 | tee /dev/stderr |
1123 grep -E "M[BP]/s \[")
1124 local img_size=$(echo "${dec_output}" | cut -f 1 -d ',')
1125 local img_size_x=$(echo "${img_size}" | cut -f 1 -d ' ')
1126 local img_size_y=$(echo "${img_size}" | cut -f 3 -d ' ')
1127 local img_size_px=$(( ${img_size_x} * ${img_size_y} ))
1128 local dec_speed=$(_speed_from_output "${dec_output}")
jpegxl-botb3a65712020-02-06 13:22:22 +01001129
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001130 # For JPEG lossless recompression modes (where the original is a JPEG)
1131 # decode to JPG as well.
1132 local jpeg_dec_mps_speed=""
1133 local jpeg_dec_mbs_speed=""
1134 if [[ "${src_ext}" == "jpg" ]]; then
1135 wait_for_temp
1136 local dec_file="${BUILD_DIR}/arm_benchmark/${enc_file_hash}.jpg"
jpegxl-botb1c6fdc2021-03-05 18:32:15 +01001137 dec_output=$("${BUILD_DIR}/tools/djxl" "${enc_file}" \
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001138 "${dec_file}" --num_reps=5 --num_threads="${num_threads}" 2>&1 | \
1139 tee /dev/stderr | grep -E "M[BP]/s \[")
1140 local jpeg_dec_mps_speed=$(_speed_from_output "${dec_output}")
1141 local jpeg_dec_mbs_speed=$(_speed_from_output "${dec_output}" MB/s)
1142 if ! cmp --quiet "${src_img}" "${dec_file}"; then
1143 # Add a start at the end to signal that the files are different.
1144 jpeg_dec_mbs_speed+="*"
1145 fi
1146 fi
jpegxl-botff093712019-12-27 18:12:34 +01001147
jpegxl-bot6b5144c2020-08-24 13:35:47 +02001148 # Record entry in a tab-separated file.
1149 local src_img_base=$(basename "${src_img}")
1150 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}" |
1151 tee -a "${runs_file}"
1152 done
jpegxl-botff093712019-12-27 18:12:34 +01001153 done
1154 done
1155 done
jpegxl-bot21f5f752020-06-30 13:06:56 +02001156 cmd_cpuset "${RUNNER_CPU_ALL:-}"
jpegxl-botff093712019-12-27 18:12:34 +01001157 cat "${runs_file}"
1158
1159 if [[ -n "${CI_BUILD_NAME:-}" ]]; then
1160 load_mr_vars_from_commit
1161 { set +x; } 2>/dev/null
1162 local message="Results for ${CI_BUILD_NAME} @ ${CI_COMMIT_SHORT_SHA} (job ${CI_JOB_URL:-}):
1163
1164\`\`\`
1165$(column -t -s " " "${runs_file}")
1166\`\`\`
1167"
1168 cmd_post_mr_comment "${message}"
1169 set -x
1170 fi
1171}
1172
jpegxl-botf84edfb2020-04-20 09:48:41 +02001173# Generate a corpus and run the fuzzer on that corpus.
1174cmd_fuzz() {
1175 local corpus_dir=$(realpath "${BUILD_DIR}/fuzzer_corpus")
1176 local fuzzer_crash_dir=$(realpath "${BUILD_DIR}/fuzzer_crash")
1177 mkdir -p "${corpus_dir}" "${fuzzer_crash_dir}"
1178 # Generate step.
1179 "${BUILD_DIR}/tools/fuzzer_corpus" "${corpus_dir}"
1180 # Run step:
1181 local nprocs=$(nproc --all || echo 1)
1182 (
1183 cd "${BUILD_DIR}"
1184 "tools/djxl_fuzzer" "${fuzzer_crash_dir}" "${corpus_dir}" \
1185 -max_total_time="${FUZZER_MAX_TIME}" -jobs=${nprocs} \
1186 -artifact_prefix="${fuzzer_crash_dir}/"
1187 )
1188}
1189
jpegxl-botff093712019-12-27 18:12:34 +01001190# Runs the linter (clang-format) on the pending CLs.
1191cmd_lint() {
1192 merge_request_commits
jpegxl-bot31c71b02020-12-24 17:42:41 +01001193 { set +x; } 2>/dev/null
Alex Deymod09afef2021-08-03 14:26:28 +02001194 local versions=(${1:-6.0 7 8 9 10 11})
jpegxl-botff093712019-12-27 18:12:34 +01001195 local clang_format_bins=("${versions[@]/#/clang-format-}" clang-format)
1196 local tmpdir=$(mktemp -d)
1197 CLEANUP_FILES+=("${tmpdir}")
1198
jpegxl-bot31c71b02020-12-24 17:42:41 +01001199 local ret=0
1200 local build_patch="${tmpdir}/build_cleaner.patch"
1201 if ! "${MYDIR}/tools/build_cleaner.py" >"${build_patch}"; then
1202 ret=1
1203 echo "build_cleaner.py findings:" >&2
1204 "${COLORDIFF_BIN}" <"${build_patch}"
1205 echo "Run \`tools/build_cleaner.py --update\` to apply them" >&2
1206 fi
1207
jpegxl-botff093712019-12-27 18:12:34 +01001208 local installed=()
1209 local clang_patch
1210 local clang_format
1211 for clang_format in "${clang_format_bins[@]}"; do
1212 if ! which "${clang_format}" >/dev/null; then
1213 continue
1214 fi
1215 installed+=("${clang_format}")
1216 local tmppatch="${tmpdir}/${clang_format}.patch"
Ziemowit Zabawa27d8a0f2021-07-01 16:45:13 +02001217 # We include in this linter all the changes including the uncommitted changes
jpegxl-botff093712019-12-27 18:12:34 +01001218 # to avoid printing changes already applied.
1219 set -x
1220 git -C "${MYDIR}" "${clang_format}" --binary "${clang_format}" \
1221 --style=file --diff "${MR_ANCESTOR_SHA}" -- >"${tmppatch}"
1222 { set +x; } 2>/dev/null
1223
1224 if grep -E '^--- ' "${tmppatch}">/dev/null; then
1225 if [[ -n "${LINT_OUTPUT:-}" ]]; then
1226 cp "${tmppatch}" "${LINT_OUTPUT}"
1227 fi
1228 clang_patch="${tmppatch}"
1229 else
1230 echo "clang-format check OK" >&2
jpegxl-bot31c71b02020-12-24 17:42:41 +01001231 return ${ret}
jpegxl-botff093712019-12-27 18:12:34 +01001232 fi
1233 done
1234
1235 if [[ ${#installed[@]} -eq 0 ]]; then
1236 echo "You must install clang-format for \"git clang-format\"" >&2
1237 exit 1
1238 fi
1239
1240 # clang-format is installed but found problems.
1241 echo "clang-format findings:" >&2
1242 "${COLORDIFF_BIN}" < "${clang_patch}"
1243
1244 echo "clang-format found issues in your patches from ${MR_ANCESTOR_SHA}" \
1245 "to the current patch. Run \`./ci.sh lint | patch -p1\` from the base" \
1246 "directory to apply them." >&2
1247 exit 1
1248}
1249
1250# Runs clang-tidy on the pending CLs. If the "all" argument is passed it runs
1251# clang-tidy over all the source files instead.
1252cmd_tidy() {
1253 local what="${1:-}"
1254
1255 if [[ -z "${CLANG_TIDY_BIN}" ]]; then
jpegxl-bot63349442020-05-25 08:56:34 +02001256 echo "ERROR: You must install clang-tidy-7 or newer to use ci.sh tidy" >&2
jpegxl-botff093712019-12-27 18:12:34 +01001257 exit 1
1258 fi
1259
1260 local git_args=()
1261 if [[ "${what}" == "all" ]]; then
1262 git_args=(ls-files)
1263 shift
1264 else
1265 merge_request_commits
1266 git_args=(
1267 diff-tree --no-commit-id --name-only -r "${MR_ANCESTOR_SHA}"
1268 "${MR_HEAD_SHA}"
1269 )
1270 fi
1271
1272 # Clang-tidy needs the compilation database generated by cmake.
1273 if [[ ! -e "${BUILD_DIR}/compile_commands.json" ]]; then
1274 # Generate the build options in debug mode, since we need the debug asserts
1275 # enabled for the clang-tidy analyzer to use them.
1276 CMAKE_BUILD_TYPE="Debug"
1277 cmake_configure
jpegxl-bot63349442020-05-25 08:56:34 +02001278 # Build the autogen targets to generate the .h files from the .ui files.
1279 local autogen_targets=(
1280 $(ninja -C "${BUILD_DIR}" -t targets | grep -F _autogen: |
1281 cut -f 1 -d :)
1282 )
1283 if [[ ${#autogen_targets[@]} != 0 ]]; then
1284 ninja -C "${BUILD_DIR}" "${autogen_targets[@]}"
1285 fi
jpegxl-botff093712019-12-27 18:12:34 +01001286 fi
1287
1288 cd "${MYDIR}"
1289 local nprocs=$(nproc --all || echo 1)
1290 local ret=0
1291 if ! parallel -j"${nprocs}" --keep-order -- \
1292 "${CLANG_TIDY_BIN}" -p "${BUILD_DIR}" -format-style=file -quiet "$@" {} \
1293 < <(git "${git_args[@]}" | grep -E '(\.cc|\.cpp)$') \
1294 >"${BUILD_DIR}/clang-tidy.txt"; then
1295 ret=1
1296 fi
1297 { set +x; } 2>/dev/null
1298 echo "Findings statistics:" >&2
1299 grep -E ' \[[A-Za-z\.,\-]+\]' -o "${BUILD_DIR}/clang-tidy.txt" | sort \
1300 | uniq -c >&2
1301
1302 if [[ $ret -ne 0 ]]; then
1303 cat >&2 <<EOF
1304Errors found, see ${BUILD_DIR}/clang-tidy.txt for details.
1305To automatically fix them, run:
1306
1307 SKIP_TEST=1 ./ci.sh debug
1308 ${CLANG_TIDY_BIN} -p ${BUILD_DIR} -fix -format-style=file -quiet $@ \$(git ${git_args[@]} | grep -E '(\.cc|\.cpp)\$')
1309EOF
1310 fi
1311
1312 return ${ret}
1313}
1314
jpegxl-bot9e183e12020-10-29 12:36:26 +01001315# Print stats about all the packages built in ${BUILD_DIR}/debs/.
1316cmd_debian_stats() {
1317 { set +x; } 2>/dev/null
1318 local debsdir="${BUILD_DIR}/debs"
1319 local f
1320 while IFS='' read -r -d '' f; do
1321 echo "====================================================================="
1322 echo "Package $f:"
1323 dpkg --info $f
1324 dpkg --contents $f
1325 done < <(find "${BUILD_DIR}/debs" -maxdepth 1 -mindepth 1 -type f \
1326 -name '*.deb' -print0)
1327}
1328
1329build_debian_pkg() {
1330 local srcdir="$1"
1331 local srcpkg="$2"
1332
1333 local debsdir="${BUILD_DIR}/debs"
1334 local builddir="${debsdir}/${srcpkg}"
1335
1336 # debuild doesn't have an easy way to build out of tree, so we make a copy
1337 # of with all symlinks on the first level.
1338 mkdir -p "${builddir}"
1339 for f in $(find "${srcdir}" -mindepth 1 -maxdepth 1 -printf '%P\n'); do
1340 if [[ ! -L "${builddir}/$f" ]]; then
1341 rm -f "${builddir}/$f"
1342 ln -s "${srcdir}/$f" "${builddir}/$f"
1343 fi
1344 done
1345 (
1346 cd "${builddir}"
1347 debuild -b -uc -us
1348 )
1349}
1350
1351cmd_debian_build() {
1352 local srcpkg="${1:-}"
1353
1354 case "${srcpkg}" in
1355 jpeg-xl)
1356 build_debian_pkg "${MYDIR}" "jpeg-xl"
1357 ;;
1358 highway)
1359 build_debian_pkg "${MYDIR}/third_party/highway" "highway"
1360 ;;
1361 *)
1362 echo "ERROR: Must pass a valid source package name to build." >&2
1363 ;;
1364 esac
1365}
1366
Alex Deymoa29161b2021-08-13 12:56:18 +02001367get_version() {
1368 local varname=$1
1369 local line=$(grep -F "set(${varname} " lib/CMakeLists.txt | head -n 1)
1370 [[ -n "${line}" ]]
1371 line="${line#set(${varname} }"
1372 line="${line%)}"
1373 echo "${line}"
1374}
1375
1376cmd_bump_version() {
1377 local newver="${1:-}"
1378
1379 if ! which dch >/dev/null; then
1380 echo "Run:\n sudo apt install debhelper"
1381 exit 1
1382 fi
1383
1384 if [[ -z "${newver}" ]]; then
1385 local major=$(get_version JPEGXL_MAJOR_VERSION)
1386 local minor=$(get_version JPEGXL_MINOR_VERSION)
1387 local patch=0
1388 minor=$(( ${minor} + 1))
1389 else
1390 local major="${newver%%.*}"
1391 newver="${newver#*.}"
1392 local minor="${newver%%.*}"
1393 newver="${newver#${minor}}"
1394 local patch="${newver#.}"
1395 if [[ -z "${patch}" ]]; then
1396 patch=0
1397 fi
1398 fi
1399
1400 newver="${major}.${minor}"
1401 if [[ "${patch}" != "0" ]]; then
1402 newver="${newver}.${patch}"
1403 fi
1404 echo "Bumping version to ${newver} (${major}.${minor}.${patch})"
1405 sed -E \
1406 -e "s/(set\\(JPEGXL_MAJOR_VERSION) [0-9]+\\)/\\1 ${major})/" \
1407 -e "s/(set\\(JPEGXL_MINOR_VERSION) [0-9]+\\)/\\1 ${minor})/" \
1408 -e "s/(set\\(JPEGXL_PATCH_VERSION) [0-9]+\\)/\\1 ${patch})/" \
1409 -i lib/CMakeLists.txt
1410
1411 # Update lib.gni
1412 tools/build_cleaner.py --update
1413
1414 # Mark the previous version as "unstable".
1415 DEBCHANGE_RELEASE_HEURISTIC=log dch -M --distribution unstable --release ''
1416 DEBCHANGE_RELEASE_HEURISTIC=log dch -M \
1417 --newversion "${newver}" \
1418 "Bump JPEG XL version to ${newver}."
1419}
1420
Alex Deymo4ead4a12021-05-26 16:23:17 +02001421# Check that the AUTHORS file contains the email of the committer.
1422cmd_authors() {
1423 merge_request_commits
1424 # TODO(deymo): Handle multiple commits and check that they are all the same
1425 # author.
1426 local email=$(git log --format='%ae' "${MR_HEAD_SHA}^!")
1427 local name=$(git log --format='%an' "${MR_HEAD_SHA}^!")
1428 "${MYDIR}"/tools/check_author.py "${email}" "${name}"
1429}
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.
1491 - STACK_SIZE=1: Generate binaries with the .stack_sizes sections.
jpegxl-botff093712019-12-27 18:12:34 +01001492
1493These optional environment variables are forwarded to the cmake call as
1494parameters:
jpegxl-botf84edfb2020-04-20 09:48:41 +02001495 - CMAKE_BUILD_TYPE
jpegxl-botff093712019-12-27 18:12:34 +01001496 - CMAKE_C_FLAGS
1497 - CMAKE_CXX_FLAGS
jpegxl-bot50bbf272020-06-10 14:59:11 +02001498 - CMAKE_C_COMPILER_LAUNCHER
1499 - CMAKE_CXX_COMPILER_LAUNCHER
jpegxl-botb3a65712020-02-06 13:22:22 +01001500 - CMAKE_CROSSCOMPILING_EMULATOR
jpegxl-botf84edfb2020-04-20 09:48:41 +02001501 - CMAKE_FIND_ROOT_PATH
jpegxl-botff093712019-12-27 18:12:34 +01001502 - CMAKE_EXE_LINKER_FLAGS
jpegxl-bote3c58a02020-06-15 08:51:22 +02001503 - CMAKE_MAKE_PROGRAM
jpegxl-botff093712019-12-27 18:12:34 +01001504 - CMAKE_MODULE_LINKER_FLAGS
1505 - CMAKE_SHARED_LINKER_FLAGS
1506 - CMAKE_TOOLCHAIN_FILE
jpegxl-botff093712019-12-27 18:12:34 +01001507
1508Example:
1509 BUILD_DIR=/tmp/build $0 opt
1510EOF
1511 exit 1
1512 fi
1513
1514 cmd="cmd_${cmd}"
1515 shift
1516 set -x
1517 "${cmd}" "$@"
1518}
1519
1520main "$@"