-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild_cp.sh
More file actions
executable file
·331 lines (284 loc) · 9.86 KB
/
Copy pathbuild_cp.sh
File metadata and controls
executable file
·331 lines (284 loc) · 9.86 KB
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
#!/usr/bin/env bash
# Build any CircuitPython port/board/variant.
#
# Usage:
# ./build_cp.sh [--port PORT] [--board BOARD] [--variant VARIANT]
#
# Environment: WORKSPACE_DIR, CP_DIR, PORT, BOARD, VARIANT, CP_BUILD_VENV
# Runs apply_cp_lvgl_patches.sh and usdl2 apply_cp_unix_usdl_patches.sh (unix) before building.
# Creates $SCRIPT_DIR/.venv and installs circuitpython/requirements-dev.txt if needed.
set -euo pipefail
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
BUILD_CP="${BUILD_CP:-$SCRIPT_DIR/build_cp.sh}"
WORKSPACE_DIR="${WORKSPACE_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
CP_DIR="${CP_DIR:-$WORKSPACE_DIR/circuitpython}"
# CircuitPython uses shared-bindings + circuitpython.mk, not MicroPython
# USER_C_MODULES. Clear a leaked env from sibling build_mp.sh / shells so
# lv_micropython_cmod is not pulled into the CP compile.
# FROZEN_MANIFEST is re-set below for unix only (see resolve_unix_frozen_manifest).
unset USER_C_MODULES FROZEN_MANIFEST
PORT="${PORT:-}"
BOARD="${BOARD:-}"
VARIANT="${VARIANT:-}"
while [[ $# -gt 0 ]]; do
case "$1" in
--port) PORT="$2"; shift 2 ;;
--board) BOARD="$2"; shift 2 ;;
--variant) VARIANT="$2"; shift 2 ;;
-h|--help)
echo "Usage: $0 [--port PORT] [--board BOARD] [--variant VARIANT]"
exit 0
;;
*) echo "Unknown option: $1" >&2; exit 1 ;;
esac
done
[[ -d "$CP_DIR/ports" ]] || { echo "CircuitPython not found: $CP_DIR" >&2; exit 1; }
CP_REQUIREMENTS_DEV="${CP_REQUIREMENTS_DEV:-$CP_DIR/requirements-dev.txt}"
CP_BUILD_VENV="${CP_BUILD_VENV:-$SCRIPT_DIR/.venv}"
ensure_espressif_env() {
[[ "$PORT" == espressif ]] || return 0
local idf_export="$PORT_DIR/esp-idf/export.sh"
[[ -f "$idf_export" ]] || {
echo "ESP-IDF export script not found: $idf_export" >&2
exit 1
}
echo "Activating ESP-IDF environment..."
# shellcheck disable=SC1090
if ! . "$idf_export"; then
echo "Failed to activate ESP-IDF. Install tools with:" >&2
echo " cd $PORT_DIR/esp-idf && ./install.sh" >&2
exit 1
fi
# IDF export owns python3 (cmake / idf_component_manager). CircuitPython
# make recipes use $(PYTHON) for qstr / web-workflow — keep the CP venv.
if [[ -x "$CP_BUILD_VENV/bin/python" ]]; then
export PYTHON="$CP_BUILD_VENV/bin/python"
fi
}
ensure_cp_python_env() {
[[ -f "$CP_REQUIREMENTS_DEV" ]] || {
echo "CircuitPython dev requirements not found: $CP_REQUIREMENTS_DEV" >&2
exit 1
}
if [[ ! -d "$CP_BUILD_VENV" ]]; then
echo "Creating Python venv: $CP_BUILD_VENV"
python3 -m venv "$CP_BUILD_VENV"
fi
echo "Ensuring CircuitPython dev requirements in venv..."
if ! "$CP_BUILD_VENV/bin/pip" install -r "$CP_REQUIREMENTS_DEV"; then
echo "Failed to install dev requirements." >&2
echo "If minify_html failed, install Rust (see $CP_DIR/BUILDING.md)." >&2
exit 1
fi
export PATH="$CP_BUILD_VENV/bin:$PATH"
}
pick() {
local label="$1"; shift
local -a items=("$@")
local n i
# Menu on stderr so stdout is only the chosen value (for VAR=$(pick ...)).
echo >&2
echo "$label" >&2
for i in "${!items[@]}"; do
printf ' %2d) %s\n' "$((i + 1))" "${items[$i]}" >&2
done
while true; do
read -r -p "Select [1-${#items[@]}]: " n
if [[ "$n" =~ ^[0-9]+$ ]] && (( n >= 1 && n <= ${#items[@]} )); then
echo "${items[$((n - 1))]}"
return
fi
echo "Invalid selection." >&2
done
}
list_ports() {
local p
for p in "$CP_DIR"/ports/*; do
[[ -f "$p/Makefile" ]] && basename "$p"
done
}
list_boards() {
local port_dir="$CP_DIR/ports/$PORT" d
for d in "$port_dir/boards"/*; do
[[ -f "$d/mpconfigboard.mk" ]] && basename "$d"
done
}
variants_dir() {
local port_dir="$CP_DIR/ports/$PORT"
if [[ -n "$BOARD" && -d "$port_dir/boards/$BOARD/variants" ]]; then
echo "$port_dir/boards/$BOARD/variants"
elif [[ -d "$port_dir/variants" ]]; then
echo "$port_dir/variants"
fi
}
list_variants() {
local dir="$1" d
for d in "$dir"/*; do
[[ -f "$d/mpconfigvariant.mk" ]] && basename "$d"
done
}
print_rerun_hint() {
local -a cmd=("$BUILD_CP")
cmd+=(--port "$PORT")
[[ -n "$BOARD" ]] && cmd+=(--board "$BOARD")
[[ -n "$VARIANT" ]] && cmd+=(--variant "$VARIANT")
local reset="" bold="" cyan=""
if [[ -t 1 ]]; then
reset=$(tput sgr0)
bold=$(tput bold)
cyan=$(tput setaf 6)
fi
printf '\n\n'
printf '%s%sRun again without prompts:%s\n' "$bold" "$cyan" "$reset"
printf ' %s\n' "$(printf '%q ' "${cmd[@]}")"
printf '\n\n'
}
cp_user_config_make_opts() {
CP_USER_CONFIG="${CP_USER_CONFIG:-$WORKSPACE_DIR/cp-user-config}"
if [[ -d "$CP_USER_CONFIG" ]]; then
printf '%s' "-I $(cd "$CP_USER_CONFIG" && pwd)"
fi
}
print_make_commands() {
local -a args=()
local user_config
user_config=$(cp_user_config_make_opts)
[[ -n "$user_config" ]] && args+=("$user_config")
[[ -n "$BOARD" ]] && args+=(BOARD="$BOARD")
[[ -n "$VARIANT" ]] && args+=(VARIANT="$VARIANT")
local reset="" bold="" yellow="" dim=""
if [[ -t 1 ]]; then
reset=$(tput sgr0)
bold=$(tput bold)
yellow=$(tput setaf 3)
dim=$(tput dim)
fi
local quoted=""
if [[ ${#args[@]} -gt 0 ]]; then
quoted=" $(printf '%q ' "${args[@]}")"
fi
printf '\n\n'
printf '%s%sRun make manually:%s\n' "$bold" "$yellow" "$reset"
printf '%s cd %q%s\n' "$dim" "$PORT_DIR" "$reset"
if [[ "$PORT" == espressif ]]; then
printf '%s . ./esp-idf/export.sh%s\n' "$dim" "$reset"
fi
printf '%s make -j clean%s%s\n' "$dim" "$quoted" "$reset"
printf '%s make -j submodules%s%s\n' "$dim" "$quoted" "$reset"
printf '%s make -j%s%s\n' "$dim" "$quoted" "$reset"
printf '\n\n'
}
run_usdl2_patches() {
[[ "$PORT" == unix ]] || return 0
local usdl2_patch="$WORKSPACE_DIR/usdl2/apply_cp_unix_usdl_patches.sh"
[[ -x "$usdl2_patch" ]] || {
echo "usdl2 patch script not found: $usdl2_patch" >&2
echo "Clone https://github.com/PyDevices/usdl2 as a sibling of lv_circuitpython_mod (WORKSPACE_DIR=$WORKSPACE_DIR)." >&2
exit 1
}
local -a patch_args=(--apply)
if [[ -n "$VARIANT" ]]; then
VARIANT="$VARIANT" "$usdl2_patch" "${patch_args[@]}"
else
"$usdl2_patch" "${patch_args[@]}"
fi
}
run_lvgl_patches() {
local -a apply_args=(--apply --port "$PORT")
[[ -n "$BOARD" ]] && apply_args+=(--board "$BOARD")
[[ -n "$VARIANT" ]] && apply_args+=(--variant "$VARIANT")
"$SCRIPT_DIR/apply_cp_lvgl_patches.sh" "${apply_args[@]}"
}
build_dir() {
if [[ -n "$VARIANT" ]]; then
echo "$PORT_DIR/build-$VARIANT"
elif [[ -n "$BOARD" ]]; then
echo "$PORT_DIR/build-$BOARD"
fi
}
print_build_outputs() {
local dir
dir=$(build_dir)
[[ -n "$dir" && -d "$dir" ]] || return 0
local -a outputs=()
local name f
for name in firmware.uf2 firmware.bin micropython circuitpython.uf2; do
f="$dir/$name"
[[ -f "$f" ]] && outputs+=("$f")
done
if [[ ${#outputs[@]} -eq 0 ]]; then
while IFS= read -r -d '' f; do
outputs+=("$f")
done < <(find "$dir" -maxdepth 1 -type f \( -name 'firmware.*' -o -name '*.uf2' \) -print0 2>/dev/null | sort -z)
fi
[[ ${#outputs[@]} -gt 0 ]] || return 0
echo
echo "Build output:"
for f in "${outputs[@]}"; do
echo " $f"
done
echo
}
# 1) Port
if [[ -z "$PORT" ]]; then
mapfile -t _ports < <(list_ports | sort)
[[ ${#_ports[@]} -gt 0 ]] || { echo "No ports found." >&2; exit 1; }
PORT=$(pick "Ports:" "${_ports[@]}")
fi
PORT_DIR="$CP_DIR/ports/$PORT"
[[ -f "$PORT_DIR/Makefile" ]] || { echo "Invalid port: $PORT" >&2; exit 1; }
# 2) Board (only if this port has boards)
mapfile -t _boards < <(list_boards | sort)
if [[ ${#_boards[@]} -gt 0 && -z "$BOARD" ]]; then
BOARD=$(pick "Boards for $PORT:" "${_boards[@]}")
fi
# 3) Variant (only if a variants directory exists)
if _vdir=$(variants_dir); then
mapfile -t _variants < <(list_variants "$_vdir" | sort)
if [[ ${#_variants[@]} -gt 0 && -z "$VARIANT" ]]; then
VARIANT=$(pick "Variants:" "${_variants[@]}")
fi
fi
run_usdl2_patches
run_lvgl_patches
print_rerun_hint
print_make_commands
# Unix coverage/standard use variant manifests. Wrap them so we can freeze
# lib/display_driver.py. MCU ports keep CircuitPython's generated BUILD/manifest.py
# — do not override FROZEN_MANIFEST there.
resolve_unix_frozen_manifest() {
local path=""
if [[ -n "$VARIANT" && -f "$PORT_DIR/variants/$VARIANT/manifest.py" ]]; then
path="$PORT_DIR/variants/$VARIANT/manifest.py"
elif [[ -f "$PORT_DIR/variants/manifest.py" ]]; then
path="$PORT_DIR/variants/manifest.py"
else
echo "No unix frozen manifest for variant=${VARIANT:-}" >&2
exit 1
fi
(cd "$(dirname "$path")" && echo "$(pwd)/$(basename "$path")")
}
make_args=()
user_config=$(cp_user_config_make_opts)
[[ -n "$user_config" ]] && make_args+=("$user_config")
[[ -n "$BOARD" ]] && make_args+=(BOARD="$BOARD")
[[ -n "$VARIANT" ]] && make_args+=(VARIANT="$VARIANT")
if [[ "$PORT" == unix ]]; then
export FROZEN_MANIFEST_UPSTREAM
FROZEN_MANIFEST_UPSTREAM=$(resolve_unix_frozen_manifest)
FROZEN_MANIFEST="$SCRIPT_DIR/manifest.py"
make_args+=(FROZEN_MANIFEST="$FROZEN_MANIFEST")
echo "Frozen manifest: $FROZEN_MANIFEST"
echo " FROZEN_MANIFEST_UPSTREAM=$FROZEN_MANIFEST_UPSTREAM"
fi
ensure_cp_python_env
ensure_espressif_env
echo "Building: port=$PORT${BOARD:+ board=$BOARD}${VARIANT:+ variant=$VARIANT}"
[[ -n "$user_config" ]] && echo "User config: -I ${CP_USER_CONFIG:-$WORKSPACE_DIR/cp-user-config}"
echo
pushd "$PORT_DIR" >/dev/null
make -j clean "${make_args[@]}"
make -j submodules "${make_args[@]}"
make -j "${make_args[@]}"
popd >/dev/null
print_build_outputs