1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
|
#!/usr/bin/env bash
# Copyright (c) the JPEG XL Project Authors. All rights reserved.
#
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# Main entry point for all the Dockerfile for jpegxl-builder. This centralized
# file helps sharing code and configuration between Dockerfiles.
set -eux
MYDIR=$(dirname $(realpath "$0"))
# libjpeg-turbo.
JPEG_TURBO_RELEASE="2.0.4"
JPEG_TURBO_URL="https://github.com/libjpeg-turbo/libjpeg-turbo/archive/${JPEG_TURBO_RELEASE}.tar.gz"
JPEG_TURBO_SHA256="7777c3c19762940cff42b3ba4d7cd5c52d1671b39a79532050c85efb99079064"
# zlib (dependency of libpng)
ZLIB_RELEASE="1.2.11"
ZLIB_URL="https://www.zlib.net/zlib-${ZLIB_RELEASE}.tar.gz"
ZLIB_SHA256="c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1"
# The name in the .pc and the .dll generated don't match in zlib for Windows
# because they use different .dll names in Windows. We avoid that by defining
# UNIX=1. We also install all the .dll files to ${prefix}/lib instead of the
# default ${prefix}/bin.
ZLIB_FLAGS='-DUNIX=1 -DINSTALL_PKGCONFIG_DIR=/${CMAKE_INSTALL_PREFIX}/lib/pkgconfig -DINSTALL_BIN_DIR=/${CMAKE_INSTALL_PREFIX}/lib'
# libpng
LIBPNG_RELEASE="1.6.37"
LIBPNG_URL="https://github.com/glennrp/libpng/archive/v${LIBPNG_RELEASE}.tar.gz"
LIBPNG_SHA256="ca74a0dace179a8422187671aee97dd3892b53e168627145271cad5b5ac81307"
# giflib
GIFLIB_RELEASE="5.2.1"
GIFLIB_URL="https://netcologne.dl.sourceforge.net/project/giflib/giflib-${GIFLIB_RELEASE}.tar.gz"
GIFLIB_SHA256="31da5562f44c5f15d63340a09a4fd62b48c45620cd302f77a6d9acf0077879bd"
# A patch needed to compile GIFLIB in mingw.
GIFLIB_PATCH_URL="https://github.com/msys2/MINGW-packages/raw/3afde38fcee7b3ba2cafd97d76cca8f06934504f/mingw-w64-giflib/001-mingw-build.patch"
GIFLIB_PATCH_SHA256="2b2262ddea87fc07be82e10aeb39eb699239f883c899aa18a16e4d4e40af8ec8"
# webp
WEBP_RELEASE="1.0.2"
WEBP_URL="https://codeload.github.com/webmproject/libwebp/tar.gz/v${WEBP_RELEASE}"
WEBP_SHA256="347cf85ddc3497832b5fa9eee62164a37b249c83adae0ba583093e039bf4881f"
# Google benchmark
BENCHMARK_RELEASE="1.5.2"
BENCHMARK_URL="https://github.com/google/benchmark/archive/v${BENCHMARK_RELEASE}.tar.gz"
BENCHMARK_SHA256="dccbdab796baa1043f04982147e67bb6e118fe610da2c65f88912d73987e700c"
BENCHMARK_FLAGS="-DGOOGLETEST_PATH=${MYDIR}/../../third_party/googletest"
# attribute(format(__MINGW_PRINTF_FORMAT, ...)) doesn't work in our
# environment, so we disable the warning.
BENCHMARK_FLAGS="-DCMAKE_BUILD_TYPE=Release -DBENCHMARK_ENABLE_TESTING=OFF \
-DCMAKE_CXX_FLAGS=-Wno-ignored-attributes \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON"
# V8
V8_VERSION="9.3.22"
# Temporary files cleanup hooks.
CLEANUP_FILES=()
cleanup() {
if [[ ${#CLEANUP_FILES[@]} -ne 0 ]]; then
rm -fr "${CLEANUP_FILES[@]}"
fi
}
trap "{ set +x; } 2>/dev/null; cleanup" INT TERM EXIT
# List of Ubuntu arch names supported by the builder (such as "i386").
LIST_ARCHS=(
amd64
i386
arm64
armhf
)
# List of target triplets supported by the builder.
LIST_TARGETS=(
x86_64-linux-gnu
i686-linux-gnu
arm-linux-gnueabihf
aarch64-linux-gnu
)
LIST_MINGW_TARGETS=(
i686-w64-mingw32
x86_64-w64-mingw32
)
LIST_WASM_TARGETS=(
wasm32
)
# Setup the apt repositories and supported architectures.
setup_apt() {
apt-get update -y
apt-get install -y curl gnupg ca-certificates
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1E9377A2BA9EF27F
# node sources.
cat >/etc/apt/sources.list.d/nodesource.list <<EOF
deb https://deb.nodesource.com/node_14.x bionic main
deb-src https://deb.nodesource.com/node_14.x bionic main
EOF
curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -
local port_list=()
local main_list=()
local ubarch
for ubarch in "${LIST_ARCHS[@]}"; do
if [[ "${ubarch}" != "amd64" && "${ubarch}" != "i386" ]]; then
# other archs are not part of the main mirrors, but available in
# ports.ubuntu.com.
port_list+=("${ubarch}")
else
main_list+=("${ubarch}")
fi
# Add the arch to the system.
if [[ "${ubarch}" != "amd64" ]]; then
dpkg --add-architecture "${ubarch}"
fi
done
# Update the sources.list with the split of supported architectures.
local bkplist="/etc/apt/sources.list.bkp"
[[ -e "${bkplist}" ]] || \
mv /etc/apt/sources.list "${bkplist}"
local newlist="/etc/apt/sources.list.tmp"
rm -f "${newlist}"
port_list=$(echo "${port_list[@]}" | tr ' ' ,)
if [[ -n "${port_list}" ]]; then
local port_url="http://ports.ubuntu.com/ubuntu-ports/"
grep -v -E '^#' "${bkplist}" |
sed -E "s;^deb (http[^ ]+) (.*)\$;deb [arch=${port_list}] ${port_url} \\2;" \
>>"${newlist}"
fi
main_list=$(echo "${main_list[@]}" | tr ' ' ,)
grep -v -E '^#' "${bkplist}" |
sed -E "s;^deb (http[^ ]+) (.*)\$;deb [arch=${main_list}] \\1 \\2\ndeb-src [arch=${main_list}] \\1 \\2;" \
>>"${newlist}"
mv "${newlist}" /etc/apt/sources.list
}
install_pkgs() {
packages=(
# Native compilers (minimum for SIMD is clang-7)
clang-7 clang-format-7 clang-tidy-7
# TODO: Consider adding clang-8 to every builder:
# clang-8 clang-format-8 clang-tidy-8
# For cross-compiling to Windows with mingw.
mingw-w64
wine64
wine-binfmt
# Native tools.
bsdmainutils
cmake
extra-cmake-modules
git
llvm
nasm
ninja-build
parallel
pkg-config
# For compiling / testing JNI wrapper. JDK8 is almost 2x smaller than JDK11
# openjdk-8-jdk-headless would be 50MB smaller, unfortunately, CMake
# does mistakenly thinks it does not contain JNI feature.
openjdk-8-jdk
# These are used by the ./ci.sh lint in the native builder.
clang-format-7
clang-format-8
# For coverage builds
gcovr
# For compiling giflib documentation.
xmlto
# Common libraries.
libstdc++-8-dev
# We don't use tcmalloc on archs other than amd64. This installs
# libgoogle-perftools4:amd64.
google-perftools
# NodeJS for running WASM tests
nodejs
# To generate API documentation.
doxygen
# Freezes version that builds (passes tests). Newer version
# (2.30-21ubuntu1~18.04.4) claims to fix "On Intel Skylake
# (-march=native) generated avx512 instruction can be wrong",
# but newly added tests does not pass. Perhaps the problem is
# that mingw package is not updated.
binutils-source=2.30-15ubuntu1
)
# Install packages that are arch-dependent.
local ubarch
for ubarch in "${LIST_ARCHS[@]}"; do
packages+=(
# Library dependencies. These normally depend on the target architecture
# we are compiling for and can't usually be installed for multiple
# architectures at the same time.
libgif7:"${ubarch}"
libjpeg-dev:"${ubarch}"
libpng-dev:"${ubarch}"
libqt5x11extras5-dev:"${ubarch}"
libstdc++-8-dev:"${ubarch}"
qtbase5-dev:"${ubarch}"
# For OpenEXR:
libilmbase12:"${ubarch}"
libopenexr22:"${ubarch}"
# TCMalloc dependency
libunwind-dev:"${ubarch}"
# Cross-compiling tools per arch.
libc6-dev-"${ubarch}"-cross
libstdc++-8-dev-"${ubarch}"-cross
)
done
local target
for target in "${LIST_TARGETS[@]}"; do
# Per target cross-compiling tools.
if [[ "${target}" != "x86_64-linux-gnu" ]]; then
packages+=(
binutils-"${target}"
gcc-"${target}"
)
fi
done
# Install all the manual packages via "apt install" for the main arch. These
# will be installed for other archs via manual download and unpack.
apt install -y "${packages[@]}" "${UNPACK_PKGS[@]}"
}
# binutils <2.32 need a patch.
install_binutils() {
local workdir=$(mktemp -d --suffix=_install)
CLEANUP_FILES+=("${workdir}")
pushd "${workdir}"
apt source binutils-mingw-w64
apt -y build-dep binutils-mingw-w64
cd binutils-mingw-w64-8ubuntu1
cp "${MYDIR}/binutils_align_fix.patch" debian/patches
echo binutils_align_fix.patch >> debian/patches/series
dpkg-buildpackage -b
cd ..
dpkg -i *deb
popd
}
# Install a library from the source code for multiple targets.
# Usage: install_from_source <tar_url> <sha256> <target> [<target...>]
install_from_source() {
local package="$1"
shift
local url
eval "url=\${${package}_URL}"
local sha256
eval "sha256=\${${package}_SHA256}"
# Optional package flags
local pkgflags
eval "pkgflags=\${${package}_FLAGS:-}"
local workdir=$(mktemp -d --suffix=_install)
CLEANUP_FILES+=("${workdir}")
local tarfile="${workdir}"/$(basename "${url}")
curl -L --output "${tarfile}" "${url}"
if ! echo "${sha256} ${tarfile}" | sha256sum -c --status -; then
echo "SHA256 mismatch for ${url}: expected ${sha256} but found:"
sha256sum "${tarfile}"
exit 1
fi
local target
for target in "$@"; do
echo "Installing ${package} for target ${target} from ${url}"
local srcdir="${workdir}/source-${target}"
mkdir -p "${srcdir}"
tar -zxf "${tarfile}" -C "${srcdir}" --strip-components=1
local prefix="/usr"
if [[ "${target}" != "x86_64-linux-gnu" ]]; then
prefix="/usr/${target}"
fi
# Apply patches to buildfiles.
if [[ "${package}" == "GIFLIB" && "${target}" == *mingw32 ]]; then
# GIFLIB Makefile has several problems so we need to fix them here. We are
# using a patch from MSYS2 that already fixes the compilation for mingw.
local make_patch="${srcdir}/libgif.patch"
curl -L "${GIFLIB_PATCH_URL}" -o "${make_patch}"
echo "${GIFLIB_PATCH_SHA256} ${make_patch}" | sha256sum -c --status -
patch "${srcdir}/Makefile" < "${make_patch}"
elif [[ "${package}" == "LIBPNG" && "${target}" == wasm* ]]; then
# Cut the dependency to libm; there is pull request to fix it, so this
# might not be needed in the future.
sed -i 's/APPLE/EMSCRIPTEN/g' "${srcdir}/CMakeLists.txt"
fi
local cmake_args=()
local export_args=("CC=clang-7" "CXX=clang++-7")
local cmake="cmake"
local make="make"
local system_name="Linux"
if [[ "${target}" == *mingw32 ]]; then
system_name="Windows"
# When compiling with clang, CMake doesn't detect that we are using mingw.
cmake_args+=(
-DMINGW=1
# Googletest needs this when cross-compiling to windows
-DCMAKE_CROSSCOMPILING=1
-DHAVE_STD_REGEX=0
-DHAVE_POSIX_REGEX=0
-DHAVE_GNU_POSIX_REGEX=0
)
local windres=$(which ${target}-windres || true)
if [[ -n "${windres}" ]]; then
cmake_args+=(-DCMAKE_RC_COMPILER="${windres}")
fi
fi
if [[ "${target}" == wasm* ]]; then
system_name="WASM"
cmake="emcmake cmake"
make="emmake make"
export_args=()
cmake_args+=(
-DCMAKE_FIND_ROOT_PATH="${prefix}"
-DCMAKE_PREFIX_PATH="${prefix}"
)
# Static and shared library link to the same file -> race condition.
nproc=1
else
nproc=`nproc --all`
fi
cmake_args+=(-DCMAKE_SYSTEM_NAME="${system_name}")
if [[ "${target}" != "x86_64-linux-gnu" ]]; then
# Cross-compiling.
cmake_args+=(
-DCMAKE_C_COMPILER_TARGET="${target}"
-DCMAKE_CXX_COMPILER_TARGET="${target}"
-DCMAKE_SYSTEM_PROCESSOR="${target%%-*}"
)
fi
if [[ -e "${srcdir}/CMakeLists.txt" ]]; then
# Most packages use cmake for building which is easier to configure for
# cross-compiling.
if [[ "${package}" == "JPEG_TURBO" && "${target}" == wasm* ]]; then
# JT erroneously detects WASM CPU as i386 and tries to use asm.
# Wasm/Emscripten support for dynamic linking is incomplete; disable
# to avoid CMake warning.
cmake_args+=(-DWITH_SIMD=0 -DENABLE_SHARED=OFF)
fi
(
cd "${srcdir}"
export ${export_args[@]}
${cmake} \
-DCMAKE_INSTALL_PREFIX="${prefix}" \
"${cmake_args[@]}" ${pkgflags}
${make} -j${nproc}
${make} install
)
elif [[ "${package}" == "GIFLIB" ]]; then
# GIFLIB doesn't yet have a cmake build system. There is a pull
# request in giflib for adding CMakeLists.txt so this might not be
# needed in the future.
(
cd "${srcdir}"
local giflib_make_flags=(
CFLAGS="-O2 --target=${target} -std=gnu99"
PREFIX="${prefix}"
)
if [[ "${target}" != wasm* ]]; then
giflib_make_flags+=(CC=clang-7)
fi
# giflib make dependencies are not properly set up so parallel building
# doesn't work for everything.
${make} -j${nproc} libgif.a "${giflib_make_flags[@]}"
${make} -j${nproc} all "${giflib_make_flags[@]}"
${make} install "${giflib_make_flags[@]}"
)
else
echo "Don't know how to install ${package}"
exit 1
fi
# CMake mistakenly uses ".so" libraries and EMCC fails to link properly.
if [[ "${target}" == wasm* ]]; then
rm -f "${prefix}/lib"/*.so*
fi
done
}
# Packages that are manually unpacked for each architecture.
UNPACK_PKGS=(
libgif-dev
libclang-common-7-dev
# For OpenEXR:
libilmbase-dev
libopenexr-dev
# TCMalloc
libgoogle-perftools-dev
libtcmalloc-minimal4
libgoogle-perftools4
)
# Main script entry point.
main() {
cd "${MYDIR}"
# Configure the repositories with the sources for multi-arch cross
# compilation.
setup_apt
apt-get update -y
apt-get dist-upgrade -y
install_pkgs
install_binutils
apt clean
# Remove prebuilt Java classes cache.
rm /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/classes.jsa
# Manually extract packages for the target arch that can't install it directly
# at the same time as the native ones.
local ubarch
for ubarch in "${LIST_ARCHS[@]}"; do
if [[ "${ubarch}" != "amd64" ]]; then
local pkg
for pkg in "${UNPACK_PKGS[@]}"; do
apt download "${pkg}":"${ubarch}"
dpkg -x "${pkg}"_*_"${ubarch}".deb /
done
fi
done
# TODO: Add clang from the llvm repos. This is problematic since we are
# installing libclang-common-7-dev:"${ubarch}" from the ubuntu ports repos
# which is not available in the llvm repos so it might have a different
# version than the ubuntu ones.
# Remove the win32 libgcc version. The gcc-mingw-w64-x86-64 (and i686)
# packages install two libgcc versions:
# /usr/lib/gcc/x86_64-w64-mingw32/7.3-posix
# /usr/lib/gcc/x86_64-w64-mingw32/7.3-win32
# (exact libgcc version number depends on the package version).
#
# Clang will pick the best libgcc, sorting by version, but it doesn't
# seem to be a way to specify one or the other one, except by passing
# -nostdlib and setting all the include paths from the command line.
# To check which one is being used you can run:
# clang++-7 --target=x86_64-w64-mingw32 -v -print-libgcc-file-name
# We need to use the "posix" versions for thread support, so here we
# just remove the other one.
local target
for target in "${LIST_MINGW_TARGETS[@]}"; do
update-alternatives --set "${target}-gcc" $(which "${target}-gcc-posix")
local gcc_win32_path=$("${target}-cpp-win32" -print-libgcc-file-name)
rm -rf $(dirname "${gcc_win32_path}")
done
# TODO: Add msan for the target when cross-compiling. This only installs it
# for amd64.
./msan_install.sh
# Build and install qemu user-linux targets.
./qemu_install.sh
# Install emscripten SDK.
./emsdk_install.sh
# Setup environment for building WASM libraries from sources.
source /opt/emsdk/emsdk_env.sh
# Install some dependency libraries manually for the different targets.
install_from_source JPEG_TURBO "${LIST_MINGW_TARGETS[@]}" "${LIST_WASM_TARGETS[@]}"
install_from_source ZLIB "${LIST_MINGW_TARGETS[@]}" "${LIST_WASM_TARGETS[@]}"
install_from_source LIBPNG "${LIST_MINGW_TARGETS[@]}" "${LIST_WASM_TARGETS[@]}"
install_from_source GIFLIB "${LIST_MINGW_TARGETS[@]}" "${LIST_WASM_TARGETS[@]}"
# webp in Ubuntu is relatively old so we install it from source for everybody.
install_from_source WEBP "${LIST_TARGETS[@]}" "${LIST_MINGW_TARGETS[@]}"
install_from_source BENCHMARK "${LIST_TARGETS[@]}" "${LIST_MINGW_TARGETS[@]}"
# Install v8. v8 has better WASM SIMD support than NodeJS 14 (LTS).
# First we need the installer to install v8.
npm install jsvu -g
# install specific version;
HOME=/opt jsvu --os=linux64 "v8@${V8_VERSION}"
ln -s "/opt/.jsvu/v8-${V8_VERSION}" "/opt/.jsvu/v8"
# Cleanup.
find /var/lib/apt/lists/ -mindepth 1 -delete
}
main "$@"
|