-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbuild.sh
executable file
·438 lines (402 loc) · 13.8 KB
/
build.sh
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
#!/usr/bin/env bash
set -e -o pipefail
cd "$(dirname "$0")"
ROOT_DIR="$PWD"
BUILD_TYPE="Release"
INSTALL_DEVEL=0
GENERATOR=
EMSCRIPTEN=0
SYSTEM_DEPS=1
BUILD_DEPS=0
BUILD_DEPS_ARGS=()
JOBS_ARGS=()
CONAN_DEPS=1
CMAKE_ARGS=(-D"CMAKE_POSITION_INDEPENDENT_CODE=ON")
CONAN_ARGS=()
CONAN_PROFILE=${CONAN_DEFAULT_PROFILE:-default}
CMAKE_TOOLCHAIN=
DETECT_ARGS=()
CSI=$'\x1b['
run() { echo "➤➤➤ $*"; "$@"; }
print_usage()
{
echo "Usage: ./build.sh [PHASE, ...] [COMPONENT, ...] [PART, ...] [TOOL, ...]"
echo " [-G CMAKE_GENERATOR] [-j JOBS] [-D CMAKE_DEF, ...]"
echo " [--debug|--minsize] [--emscripten] [--unity] [--tidy] [--update]"
echo
echo "Where: PHASE = clean | deps | config | build | test | install | package | graphviz (default: deps..install)"
echo " COMPONENT = core | vfs | data | script | graphics | text | widgets (default: all)"
echo " PART = libs | tools | examples | tests | benchmarks (default: all, 'libs' are implicit)"
echo " TOOL = dar | dati | ff | fire | shed | tc (default: all, narrows 'tools')"
echo
echo "Group aliases:"
echo " only-ff => core tools ff"
echo " only-shed => widgets tools shed"
echo
echo "Other options:"
echo " -G CMAKE_GENERATOR Unix Makefiles | Ninja | ... (default: Ninja if available, Unix Makefiles otherwise)"
echo " -j JOBS Parallel jobs for build and test phases"
echo " -D CMAKE_DEF Passed to cmake"
echo " --debug, --minsize Sets CMAKE_BUILD_TYPE"
echo " --devel Install/package headers, CMake config, static libs."
echo " --emscripten Target Emscripten (i.e. wrap with 'emcmake')"
echo " --unity CMAKE_UNITY_BUILD - batch all source files in each target together"
echo " --asan, --lsan, --ubsan, --tsan"
echo " Build with sanitizers (Address, Leak, UB, Thread)"
echo " --tidy Run clang-tidy on each compiled file"
echo " --iwyu Run include-what-you-use on each compiled file"
echo " --update Passed to conan - update dependencies"
echo " --profile, -pr PROFILE Build profile, passed to conan (also used as label for the toolchain, outside Conan)"
echo " --no-conan-deps Do not run Conan to install missing deps"
echo " --no-system-deps Do not detect and use system-installed deps"
echo " --build-deps Call ./build_deps.py, useful for CI (cannot be combined with --no-system-deps)"
echo " --build-dir Build directory (default: ./build/<build-config>)"
echo " --install-dir Installation directory (default: ./artifacts/<build-config>)"
echo " --toolchain FILE CMake toolchain, also passed to Conan"
}
setup_ninja()
{
command -v ninja >/dev/null || return 1
local NINJA_VERSION
# e.g. "1.10.0
NINJA_VERSION=$(ninja --version)
echo -n "Found ninja ${NINJA_VERSION}"
# strip last part: "1.10"
NINJA_VERSION=$(echo "${NINJA_VERSION}" | cut -d. -f'1,2')
# test major == 1 && minor >= 10 (we require Ninja > 1.10)
if [[ "${NINJA_VERSION%%.*}" -eq "1" && "${NINJA_VERSION##*.}" -ge "10" ]]; then
echo " OK"
return 0
else
echo " NOT COMPATIBLE"
return 1
fi
}
header()
{
if [[ -t 1 ]]; then
echo "${CSI}1m=== ${1} ===${CSI}0m"
else
echo "=== ${1} ==="
fi
}
phase_default=yes
component_default=yes
part_default=yes
tool_default=yes
phase()
{
local PHASE="phase_$1"
test -n "${!PHASE}" -o \( -n "${phase_default}" -a "$1" != "clean" -a "$1" != "package" -a "$1" != "graphviz" \)
}
enable_phase() { phase_default=; eval "phase_$1=yes"; }
enable_component() { component_default=; eval "component_$1=yes"; }
enable_part() { part_default=; eval "part_$1=yes"; }
enable_tool() { tool_default=; eval "tool_$1=yes"; }
# parse args...
while [[ $# -gt 0 ]] ; do
case "$1" in
clean | deps | config | build | test | install | package | graphviz )
enable_phase "$1"
shift 1 ;;
core | vfs | data | script | graphics | text | widgets )
enable_component "$1"
shift 1 ;;
libs | tools | examples | tests | benchmarks )
enable_part "$1"
shift 1 ;;
dar | dati | ff | fire | shed | tc )
enable_tool "$1"
shift 1 ;;
only-ff )
enable_component 'core'
enable_part 'tools'
enable_tool 'ff'
shift 1 ;;
only-shed )
enable_component 'widgets'
enable_part 'tools'
enable_tool 'shed'
shift 1 ;;
-G )
GENERATOR="$2"
shift 2 ;;
-j )
JOBS_ARGS+=(-j "$2")
shift 2 ;;
-D )
CMAKE_ARGS+=(-D "$2")
shift 2 ;;
-D* )
CMAKE_ARGS+=("$1")
shift 1 ;;
--debug )
BUILD_TYPE="Debug"
shift 1 ;;
--minsize )
BUILD_TYPE="MinSizeRel"
shift 1 ;;
--devel )
INSTALL_DEVEL=1
shift 1 ;;
--emscripten )
EMSCRIPTEN=1
shift 1 ;;
--unity )
# Batch all source files in each target together. This is best to be
# sure a unity build works. It might not be best for speed or memory
# consumption, but seems not worse then smaller batches in my tests.
CMAKE_ARGS+=(-D'CMAKE_UNITY_BUILD=1' -D'CMAKE_UNITY_BUILD_BATCH_SIZE=0')
shift 1 ;;
--asan )
CMAKE_ARGS+=(-D'BUILD_WITH_ASAN=1')
shift 1 ;;
--lsan )
CMAKE_ARGS+=(-D'BUILD_WITH_LSAN=1')
shift 1 ;;
--ubsan )
CMAKE_ARGS+=(-D'BUILD_WITH_UBSAN=1')
shift 1 ;;
--tsan )
CMAKE_ARGS+=(-D'BUILD_WITH_TSAN=1')
shift 1 ;;
--tidy )
CMAKE_ARGS+=(-D'ENABLE_TIDY=1')
shift 1 ;;
--iwyu )
CMAKE_ARGS+=(-D'ENABLE_IWYU=1')
shift 1 ;;
--update )
CONAN_ARGS+=('--update')
shift 1 ;;
--no-system-deps )
SYSTEM_DEPS=0
shift 1 ;;
--no-conan-deps )
CONAN_DEPS=0
shift 1 ;;
--build-deps )
BUILD_DEPS=1
shift 1 ;;
--build-dir )
BUILD_DIR="$2"
shift 2 ;;
--install-dir )
INSTALL_DIR="$2"
shift 2 ;;
-pr | --profile )
CONAN_PROFILE="$2"
BUILD_DEPS_ARGS+=("--profile" "$2")
shift 2 ;;
--toolchain )
CONAN_ARGS+=(-c "tools.cmake.cmaketoolchain:user_toolchain=[\"$2\"]")
CMAKE_TOOLCHAIN="$2"
BUILD_DEPS_ARGS+=("--toolchain" "$2")
shift 2 ;;
-h | --help )
print_usage
exit 0 ;;
* )
printf 'Error: Unknown option: %s\n\n' "$1"
print_usage
exit 1 ;;
esac
done
PLATFORM="$(uname)"
ARCH="$(uname -m)"
if [[ "${EMSCRIPTEN}" -eq 1 ]] ; then
PLATFORM="emscripten"
ARCH="wasm"
SYSTEM_DEPS=0
elif [[ ${PLATFORM} = "Darwin" ]] ; then
PLATFORM="macos"
if [[ -n "$MACOSX_DEPLOYMENT_TARGET" ]]; then
PLATFORM="${PLATFORM}-${MACOSX_DEPLOYMENT_TARGET}"
CONAN_ARGS+=(-s "os.version=${MACOSX_DEPLOYMENT_TARGET}")
fi
elif [[ ${PLATFORM} = "Linux" ]] ; then
PLATFORM="linux"
elif [[ ${PLATFORM} = MINGW* ]] ; then
PLATFORM="windows"
fi
VERSION=$(cat "${ROOT_DIR}/VERSION")$(git rev-parse --short HEAD 2>/dev/null | sed 's/^/+/' ; :)
BUILD_CONFIG="${PLATFORM}-$(echo ${BUILD_TYPE} | tr '[:upper:]' '[:lower:]')"
[[ -z "${GENERATOR}" ]] && setup_ninja && GENERATOR="Ninja"
[[ -n "${GENERATOR}" ]] && CMAKE_ARGS+=(-G "${GENERATOR}")
BUILD_DIR=${BUILD_DIR:-"${ROOT_DIR}/build/${BUILD_CONFIG}"}
INSTALL_DIR=${INSTALL_DIR:-"${ROOT_DIR}/artifacts/${BUILD_CONFIG}"}
PACKAGE_OUTPUT_DIR="${ROOT_DIR}/artifacts"
PACKAGE_FILENAME="xcikit-${VERSION}-${PLATFORM}-${ARCH}"
[[ ${BUILD_TYPE} != "Release" ]] && PACKAGE_FILENAME="${PACKAGE_FILENAME}-${BUILD_TYPE}"
CONAN_ARGS+=("-pr:a=${CONAN_PROFILE}")
COMPONENTS=(vfs data script graphics text widgets)
if [[ -z "$component_default" ]]; then
# Disable components that were not selected
for name in "${COMPONENTS[@]}" ; do
component_var="component_$name"
if [[ -z "${!component_var}" ]] ; then
CONAN_ARGS+=(-o "xcikit/*:${name}=False")
else
CONAN_ARGS+=(-o "xcikit/*:${name}=True")
DETECT_ARGS+=("${name}")
fi
done
else
DETECT_ARGS+=("${COMPONENTS[@]}")
fi
PARTS=(tools examples tests benchmarks)
if [[ -z "$part_default" ]]; then
# Disable parts that were not selected
for name in "${PARTS[@]}" ; do
part_var="part_$name"
if [[ -z "${!part_var}" ]] ; then
CONAN_ARGS+=(-o "xcikit/*:${name}=False")
else
CONAN_ARGS+=(-o "xcikit/*:${name}=True")
DETECT_ARGS+=("${name}")
fi
done
else
DETECT_ARGS+=("${PARTS[@]}")
for name in "${PARTS[@]}" ; do
CONAN_ARGS+=(-o "xcikit/*:${name}=True")
done
fi
TOOLS=(dar dati ff fire shed tc)
if [[ -z "$tool_default" ]]; then
# Disable tools that were not selected
for name in "${TOOLS[@]}" ; do
tool_var="tool_$name"
if [[ -z "${!tool_var}" ]] ; then
CONAN_ARGS+=(-o "xcikit/*:${name}_tool=False")
else
CONAN_ARGS+=(-o "xcikit/*:${name}_tool=True")
DETECT_ARGS+=("${name}_tool")
fi
done
else
for name in "${TOOLS[@]}" ; do
CONAN_ARGS+=(-o "xcikit/*:${name}_tool=True")
done
fi
CMAKE_ARGS+=(-D"XCI_INSTALL_DEVEL=${INSTALL_DEVEL}")
# Ninja: force compiler colors, if the output goes to terminal
if [[ -t 1 && "${GENERATOR}" = "Ninja" ]]; then
CMAKE_ARGS+=(-D'FORCE_COLORS=1')
fi
if [[ -z "$PYTHON" ]] ; then
for name in python3 python; do
if command -v $name >/dev/null && $name -c '' 2>/dev/null; then PYTHON=$name; break; fi
done
fi
export XCI_CMAKE_COLORS=1
header "Settings"
echo "CONAN_ARGS: ${CONAN_ARGS[*]}"
echo "CMAKE_ARGS: ${CMAKE_ARGS[*]}"
echo "BUILD_CONFIG: ${BUILD_CONFIG}"
echo "BUILD_DIR: ${BUILD_DIR}"
echo "INSTALL_DIR: ${INSTALL_DIR}"
phase package && echo "PACKAGE_NAME: ${PACKAGE_NAME}"
echo "PYTHON: ${PYTHON}"
echo
if phase clean; then
header "Clean Previous Build"
rm -vrf "${BUILD_DIR}"
rm -vrf "${INSTALL_DIR}"
fi
mkdir -p "${BUILD_DIR}"
if phase deps; then
header "Dependencies"
if [[ "${BUILD_DEPS}" -eq 1 ]]; then
"${PYTHON}" "${ROOT_DIR}/build_deps.py" "${BUILD_DEPS_ARGS[@]}"
fi
(
run cd "${BUILD_DIR}"
if [[ "${SYSTEM_DEPS}" -eq 1 ]]; then
if [[ ! -f 'system_deps.txt' ]] ; then
echo 'Checking for preinstalled dependencies...'
run "${PYTHON}" "${ROOT_DIR}/detect_system_deps.py" "${DETECT_ARGS[@]}" | tee 'system_deps.txt'
fi
# shellcheck disable=SC2207
CONAN_ARGS+=($(tail -n1 'system_deps.txt'))
fi
if [[ "${CONAN_DEPS}" -eq 1 ]]; then
export BUILD_DIR
run conan install "${ROOT_DIR}" \
--build missing \
-s "build_type=${BUILD_TYPE}" \
-c tools.cmake.cmake_layout:build_folder_vars="['settings.os', 'settings.os.version', 'settings.build_type']" \
"${CONAN_ARGS[@]}"
fi
)
echo
fi
if phase config; then
header "Configure"
(
WRAPPER=
[[ "$EMSCRIPTEN" -eq 1 ]] && WRAPPER=emcmake
run cd "${BUILD_DIR}"
# shellcheck disable=SC2207
[[ "${SYSTEM_DEPS}" -eq 1 ]] && CMAKE_ARGS+=($(tail -n2 'system_deps.txt' | head -n1))
[[ "${CONAN_DEPS}" -eq 1 ]] && CMAKE_TOOLCHAIN="${BUILD_DIR}/generators/conan_toolchain.cmake"
run ${WRAPPER} cmake "${ROOT_DIR}" \
"${CMAKE_ARGS[@]}" \
-DCMAKE_TOOLCHAIN_FILE="${CMAKE_TOOLCHAIN}" \
-D"CMAKE_BUILD_TYPE=${BUILD_TYPE}" \
-D"CMAKE_INSTALL_PREFIX=${INSTALL_DIR}" \
-D'CMAKE_EXPORT_COMPILE_COMMANDS=ON'
)
echo
fi
# Enable colored Ninja status, if the output goes to terminal (only for build step)
if [[ -t 1 && "${GENERATOR}" = "Ninja" ]]; then
export NINJA_STATUS="${CSI}1m[${CSI}32m%p ${CSI}0;32m%f${CSI}0m/${CSI}32m%t ${CSI}36m%es${CSI}0m ${CSI}1m]${CSI}0m "
fi
if phase build; then
header "Build"
WRAPPER=
[[ "$EMSCRIPTEN" -eq 1 ]] && WRAPPER=emmake
run ${WRAPPER} cmake --build "${BUILD_DIR}" --config "${BUILD_TYPE}" "${JOBS_ARGS[@]}"
[[ "${GENERATOR}" = "Ninja" ]] && ninja -C "${BUILD_DIR}" -t cleandead
echo
fi
[[ "${GENERATOR}" = "Ninja" ]] && export -n NINJA_STATUS
if phase test; then
header "Test"
(
run cd "${BUILD_DIR}" && \
run ctest --progress --output-on-failure --build-config "${BUILD_TYPE}" "${JOBS_ARGS[@]}"
)
echo
fi
if phase install; then
header "Install"
run cmake --build "${BUILD_DIR}" --config "${BUILD_TYPE}" "${JOBS_ARGS[@]}" --target install
echo
fi
if phase package; then
header "Package"
(
run cd "${BUILD_DIR}" && \
run cpack -G "TGZ;ZIP" -D "CPACK_PACKAGE_FILE_NAME=${PACKAGE_FILENAME}" -C "${BUILD_TYPE}" && \
run mv -v "${BUILD_DIR}/${PACKAGE_FILENAME}"* "${PACKAGE_OUTPUT_DIR}"
)
echo
fi
if phase graphviz; then
header "Graphviz"
(
cd "${BUILD_DIR}"
cmake --graphviz=deps.dot "${ROOT_DIR}"
echo
echo '# Dependency graph:'
sed -nE 's#.*// (.*xci-.*)#\1#p' deps.dot
echo
echo '# SVG export:'
dot -T svg -o deps.svg deps.dot
realpath deps.svg
)
echo
fi
header "Done"