Skip to content

Commit 2387de1

Browse files
committed
v3: fix Linux compiler CI regressions
1 parent 42f3787 commit 2387de1

13 files changed

Lines changed: 521 additions & 41 deletions

File tree

ci/qemu_linux_tests.sh

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
#!/usr/bin/env bash
2+
3+
set -Eeuo pipefail
4+
5+
usage() {
6+
cat <<'EOF'
7+
Usage: ci/qemu_linux_tests.sh [options] [-- V arguments]
8+
9+
Sync the current checkout to an existing Debian ARM64 QEMU guest, rebuild V,
10+
and run the Linux test suite. With no V arguments, the script runs `test-all`.
11+
12+
Options:
13+
--no-sync Use the checkout already present in the guest.
14+
--provision Install the packages used by the Linux compiler tests.
15+
-h, --help Show this help.
16+
17+
Environment overrides:
18+
V_QEMU_VM_DIR VM state directory (default: ~/.local/share/v3-qemu-debian13)
19+
V_QEMU_SSH_PORT Forwarded SSH port (default: 2222)
20+
V_QEMU_GUEST SSH target (default: v@127.0.0.1)
21+
V_QEMU_GUEST_REPO Guest checkout (default: /home/v/v3)
22+
V_QEMU_CPUS Virtual CPUs (default: 4)
23+
V_QEMU_MEMORY_MB Guest memory in MiB (default: 16384)
24+
V_QEMU_JOBS V test jobs (default: virtual CPU count)
25+
V_QEMU_VFLAGS Flags inherited by V subprocesses (default: -cc clang)
26+
V_QEMU_NO_FALLBACK Set V_MACOS_V3_NO_FALLBACK (default: 1)
27+
V_QEMU_STOP_AFTER Power off the guest after the run when set to 1
28+
V_QEMU_FIRMWARE AArch64 UEFI firmware path
29+
30+
Examples:
31+
ci/qemu_linux_tests.sh
32+
ci/qemu_linux_tests.sh -- -cc gcc test vlib/v3/
33+
V_QEMU_NO_FALLBACK=0 ci/qemu_linux_tests.sh -- -old-compiler test-all
34+
EOF
35+
}
36+
37+
provision=0
38+
sync_checkout=1
39+
while (($# > 0)); do
40+
case "$1" in
41+
--no-sync)
42+
sync_checkout=0
43+
shift
44+
;;
45+
--provision)
46+
provision=1
47+
shift
48+
;;
49+
-h | --help)
50+
usage
51+
exit 0
52+
;;
53+
--)
54+
shift
55+
break
56+
;;
57+
*)
58+
break
59+
;;
60+
esac
61+
done
62+
63+
repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
64+
vm_dir=${V_QEMU_VM_DIR:-"${HOME}/.local/share/v3-qemu-debian13"}
65+
ssh_port=${V_QEMU_SSH_PORT:-2222}
66+
guest=${V_QEMU_GUEST:-v@127.0.0.1}
67+
guest_repo=${V_QEMU_GUEST_REPO:-/home/v/v3}
68+
cpus=${V_QEMU_CPUS:-4}
69+
memory_mb=${V_QEMU_MEMORY_MB:-16384}
70+
jobs=${V_QEMU_JOBS:-$cpus}
71+
vflags=${V_QEMU_VFLAGS:--cc clang}
72+
no_fallback=${V_QEMU_NO_FALLBACK:-1}
73+
stop_after=${V_QEMU_STOP_AFTER:-0}
74+
75+
qemu_bin=${V_QEMU_BIN:-$(command -v qemu-system-aarch64 || true)}
76+
rsync_bin=${V_QEMU_RSYNC:-$(command -v rsync || true)}
77+
if [[ -z "$qemu_bin" ]]; then
78+
echo 'qemu-system-aarch64 is required (on macOS: brew install qemu).' >&2
79+
exit 1
80+
fi
81+
if [[ -z "$rsync_bin" ]]; then
82+
echo 'rsync is required.' >&2
83+
exit 1
84+
fi
85+
86+
key_file="${vm_dir}/id_ed25519"
87+
known_hosts_file="${vm_dir}/known_hosts"
88+
pid_file="${vm_dir}/qemu.pid"
89+
disk_file="${vm_dir}/disk.qcow2"
90+
vars_file="${vm_dir}/edk2-vars.fd"
91+
seed_file="${vm_dir}/seed.iso"
92+
serial_log="${vm_dir}/serial.log"
93+
qemu_log="${vm_dir}/qemu.log"
94+
95+
for required_file in "$key_file" "$known_hosts_file" "$disk_file" "$vars_file" "$seed_file"; do
96+
if [[ ! -f "$required_file" ]]; then
97+
echo "Missing VM asset: ${required_file}" >&2
98+
echo 'Create the Debian cloud guest first or set V_QEMU_VM_DIR.' >&2
99+
exit 1
100+
fi
101+
done
102+
103+
firmware=${V_QEMU_FIRMWARE:-}
104+
if [[ -z "$firmware" ]]; then
105+
qemu_prefix=$(CDPATH= cd -- "$(dirname -- "$qemu_bin")/.." && pwd)
106+
firmware="${qemu_prefix}/share/qemu/edk2-aarch64-code.fd"
107+
fi
108+
if [[ ! -f "$firmware" ]]; then
109+
echo "Missing AArch64 UEFI firmware: ${firmware}" >&2
110+
echo 'Set V_QEMU_FIRMWARE to the edk2 AArch64 code image.' >&2
111+
exit 1
112+
fi
113+
114+
ssh_options=(
115+
-i "$key_file"
116+
-p "$ssh_port"
117+
-o "UserKnownHostsFile=${known_hosts_file}"
118+
-o StrictHostKeyChecking=yes
119+
-o ConnectTimeout=5
120+
)
121+
122+
vm_is_running() {
123+
[[ -s "$pid_file" ]] && kill -0 "$(<"$pid_file")" 2>/dev/null
124+
}
125+
126+
start_vm() {
127+
if vm_is_running; then
128+
return
129+
fi
130+
if [[ -f "$pid_file" ]]; then
131+
rm -f -- "$pid_file"
132+
fi
133+
local accelerator=tcg
134+
local cpu=max
135+
if [[ $(uname -s) == Darwin ]]; then
136+
accelerator=hvf
137+
cpu=host
138+
fi
139+
"$qemu_bin" \
140+
-machine "virt,accel=${accelerator},highmem=on" \
141+
-cpu "$cpu" \
142+
-smp "$cpus" \
143+
-m "$memory_mb" \
144+
-drive "if=pflash,format=raw,readonly=on,file=${firmware}" \
145+
-drive "if=pflash,format=raw,file=${vars_file}" \
146+
-drive "if=virtio,file=${disk_file},format=qcow2" \
147+
-drive "if=virtio,file=${seed_file},format=raw,readonly=on" \
148+
-device virtio-net-pci,netdev=net0 \
149+
-netdev "user,id=net0,hostfwd=tcp:127.0.0.1:${ssh_port}-:22" \
150+
-display none \
151+
-serial "file:${serial_log}" \
152+
-monitor none \
153+
-daemonize \
154+
-pidfile "$pid_file" \
155+
-D "$qemu_log"
156+
}
157+
158+
wait_for_ssh() {
159+
for _ in {1..120}; do
160+
if ssh "${ssh_options[@]}" "$guest" true 2>/dev/null; then
161+
return
162+
fi
163+
sleep 1
164+
done
165+
echo "Guest SSH did not become ready on port ${ssh_port}." >&2
166+
exit 1
167+
}
168+
169+
power_off() {
170+
if [[ "$stop_after" == 1 ]] && vm_is_running; then
171+
ssh "${ssh_options[@]}" "$guest" 'sudo poweroff' >/dev/null 2>&1 || true
172+
fi
173+
}
174+
trap power_off EXIT
175+
176+
start_vm
177+
wait_for_ssh
178+
179+
host_head=$(git -C "$repo_root" rev-parse HEAD)
180+
guest_head=$(ssh "${ssh_options[@]}" "$guest" "git -C '${guest_repo}' rev-parse HEAD")
181+
if [[ "$host_head" != "$guest_head" ]]; then
182+
echo "Host and guest baselines differ (${host_head} != ${guest_head})." >&2
183+
echo "Update ${guest_repo} in the guest before syncing local changes." >&2
184+
exit 1
185+
fi
186+
187+
if ((sync_checkout)); then
188+
git -C "$repo_root" ls-files -z --cached --others --exclude-standard | "$rsync_bin" -az \
189+
--from0 \
190+
--files-from=- \
191+
--exclude '.detect_tcc*' \
192+
-e "ssh -i ${key_file} -p ${ssh_port} -o UserKnownHostsFile=${known_hosts_file} -o StrictHostKeyChecking=yes" \
193+
"${repo_root}/" "${guest}:${guest_repo}/"
194+
fi
195+
196+
if ((provision)); then
197+
ssh "${ssh_options[@]}" "$guest" "sudo apt-get update && sudo DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential clang git lld rsync pkg-config libssl-dev sqlite3 libsqlite3-dev valgrind libfreetype6-dev libxi-dev libxcursor-dev libgl-dev libxrandr-dev libasound2-dev libegl-dev libwayland-dev libxkbcommon-dev libwayland-egl1 libxkbcommon-x11-dev wayland-protocols libx11-dev libgl1-mesa-dri xauth xvfb"
198+
fi
199+
200+
if (($# == 0)); then
201+
set -- test-all
202+
fi
203+
204+
printf -v guest_repo_q '%q' "$guest_repo"
205+
printf -v jobs_q '%q' "$jobs"
206+
printf -v vflags_q '%q' "$vflags"
207+
printf -v no_fallback_q '%q' "$no_fallback"
208+
printf -v test_command '%q ' ./vnew "$@"
209+
210+
remote_command="cd ${guest_repo_q}"
211+
remote_command+=" && export PATH=${guest_repo_q}:\$PATH VFLAGS=${vflags_q}"
212+
remote_command+=" && if [ ! -f thirdparty/tcc/lib/libgc.a ]; then make; fi"
213+
remote_command+=" && V_C_ERROR_BUG_REPORT_DISABLED=1 ./v -old-compiler -o ./vnew cmd/v"
214+
if ((provision)); then
215+
remote_command+=" && ./vnew retry -- ./vnew install markdown"
216+
remote_command+=" && if [ ! -f thirdparty/sqlite/sqlite3.c ]; then ./vnew -old-compiler run vlib/db/sqlite/install_thirdparty_sqlite.vsh; fi"
217+
fi
218+
remote_command+=" && ./vnew wipe-cache"
219+
remote_command+=" && VJOBS=${jobs_q} V_C_ERROR_BUG_REPORT_DISABLED=1"
220+
remote_command+=" V_MACOS_V3_NO_FALLBACK=${no_fallback_q} ${test_command}"
221+
ssh "${ssh_options[@]}" "$guest" "$remote_command"

cmd/v/macos_v3_test.v

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,9 @@ fn test_macos_v3_relevant_command_selects_user_compilation_and_tests() {
211211
assert !is_macos_v3_relevant_command('build-module', prefs)
212212
prefs.is_script = true
213213
prefs.path = 'script.vsh'
214-
assert is_macos_v3_relevant_command('script.vsh', prefs)
214+
prefs.is_vsh = true
215+
assert !is_macos_v3_relevant_command('script.vsh', prefs)
216+
prefs.is_vsh = false
215217
assert !is_macos_v3_relevant_command('crun', prefs)
216218
for path in ['foo.c.v', 'foo.js.v', 'foo.wasm.v', '.v'] {
217219
prefs.path = path

cmd/v/v.v

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -299,14 +299,15 @@ fn v3_has_v1_only_preferences(prefs &pref.Preferences) bool {
299299
}
300300
return prefs.sanitize || prefs.is_livemain || prefs.is_liveshared
301301
|| prefs.output_cross_c || prefs.experimental || prefs.use_os_system_to_run
302-
|| prefs.is_apk || prefs.json_errors || prefs.no_preludes || prefs.is_quiet
303-
|| prefs.skip_warnings || prefs.skip_notes || prefs.fatal_errors
304-
|| prefs.print_watched_files || prefs.dump_modules.len > 0
305-
|| prefs.dump_files.len > 0 || prefs.dump_defines.len > 0
306-
|| prefs.print_autofree_vars || prefs.is_vlines || prefs.warn_impure_v
307-
|| prefs.trace_calls || prefs.trace_fns.len > 0 || prefs.test_runner.len > 0
308-
|| prefs.exclude.len > 0 || prefs.ldflags.len > 0 || prefs.nofloat
309-
|| prefs.fast_math || prefs.compress || prefs.is_bare || prefs.no_closures
302+
|| prefs.is_apk || prefs.is_vsh || prefs.json_errors || prefs.no_preludes
303+
|| prefs.is_quiet || prefs.skip_warnings || prefs.skip_notes
304+
|| prefs.fatal_errors || prefs.print_watched_files
305+
|| prefs.dump_modules.len > 0 || prefs.dump_files.len > 0
306+
|| prefs.dump_defines.len > 0 || prefs.print_autofree_vars || prefs.is_vlines
307+
|| prefs.warn_impure_v || prefs.trace_calls || prefs.trace_fns.len > 0
308+
|| prefs.test_runner.len > 0 || prefs.exclude.len > 0
309+
|| prefs.ldflags.len > 0 || prefs.nofloat || prefs.fast_math
310+
|| prefs.compress || prefs.is_bare || prefs.no_closures
310311
|| prefs.disable_explicit_mutability || prefs.assert_failure_mode != .default
311312
|| prefs.macosx_version_min != '0'
312313
|| prefs.build_options.any(it in ['-m32', '-m64']) || prefs.backend.is_js()

vlib/sokol/c/declaration.c.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import sokol.memory as _
1010
// Platform-specific library linking
1111
// X11 is the default on Linux
1212
// Use `-d sokol_wayland` to enable Wayland support
13-
#flag linux -DSOKOL_GLCORE
13+
#flag linux -DSOKOL_GLCORE -USOKOL_D3D11 -USOKOL_GLES3 -USOKOL_METAL -USOKOL_VULKAN -USOKOL_WGPU
1414
$if sokol_wayland ? {
1515
#flag linux -lwayland-client -lwayland-egl -lxkbcommon -lxkbcommon-x11 -lEGL -lGL -lpthread -lm -ldl -lX11 -lXi -lXcursor
1616
} $else {

vlib/v3/driver/driver.v

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2284,6 +2284,12 @@ fn should_scope_prealloc_cgen() bool {
22842284
}
22852285

22862286
fn should_parallel_monomorphize() bool {
2287+
// Compiler executables built by TinyCC can corrupt their heap while several
2288+
// specialization workers merge their results. Keep that build serial until
2289+
// the parallel merge is safe under TinyCC as well as clang and GCC.
2290+
$if tinyc {
2291+
return false
2292+
}
22872293
return os.getenv('V3_DISABLE_PARALLEL_MONOMORPHIZE') != '1'
22882294
}
22892295

vlib/v3/eval/eval.v

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5974,7 +5974,6 @@ fn (e &Eval) sizeof_type_name(name string) i64 {
59745974
'bool', 'i8', 'u8', 'byte', 'char' { i64(1) }
59755975
'i16', 'u16' { i64(2) }
59765976
'int', 'i32', 'u32', 'rune', 'f32' { i64(4) }
5977-
'i64', 'u64', 'isize', 'usize', 'f64' { i64(8) }
59785977
else { i64(8) }
59795978
}
59805979
}

0 commit comments

Comments
 (0)