diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 80eaccb..ec4ea52 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -104,6 +104,59 @@ jobs: - name: Run tests run: cd coreutils && make test + # There is no Vinix runner on GitHub, so this job does not run the suite. It + # cross-compiles every tool for the target instead, which is the check that + # catches what the platform-gated files in src/*/ get wrong: a tool whose + # shared .v and its _nix/_default variants disagree will not build for Vinix + # even though it builds for Windows, and that is exactly how `timeout` was + # broken on all three Unix targets before this existed. + vinix-cross-build: + runs-on: ubuntu-latest + steps: + - name: Checkout Latest V + uses: actions/checkout@v6 + with: + repository: vlang/v + path: v + - name: Build V + run: cd v && make && sudo ./v symlink && cd - + - name: Checkout Coreutils + uses: actions/checkout@v6 + with: + path: coreutils + - name: V doctor + run: v doctor + - name: Cross-compile every tool for Vinix + shell: bash + run: | + cd coreutils + # Read the ignore list straight out of build.vsh so the two cannot + # drift. `grep -n` and `sed -n` are both 1-based, so the key's own + # line is the one to read and there is no offset to get wrong. + # The key word itself is dropped, since it is not a tool name. + ignored=$(grep -E "^\s*'vinix':" build.vsh | grep -oE "'[a-z0-9_]+'" | tr -d "'" + | grep -vx 'vinix') + echo "vinix ignores: ${ignored:-}" + ok=0 skipped=0 failed=0 + for d in src/*/; do + name=$(basename "$d") + # A tool directory is one holding at least one .v file. + compgen -G "$d*.v" >/dev/null || continue + if printf '%s\n' "$ignored" | grep -qx "$name"; then + skipped=$((skipped + 1)) + continue + fi + if v -os vinix -o "/tmp/vinix_${name}.c" "$d" >/dev/null 2>&1; then + ok=$((ok + 1)) + else + echo "::error file=$d::cross-compile for vinix failed: $name" + v -os vinix -o "/tmp/vinix_${name}.c" "$d" 2>&1 | head -20 || true + failed=$((failed + 1)) + fi + done + echo "vinix cross-compile: ok=$ok skipped=$skipped failed=$failed" + [ "$failed" -eq 0 ] + ubuntu-gnu-coreutils: runs-on: ubuntu-latest steps: diff --git a/build.vsh b/build.vsh index 9308ea4..6d3291d 100755 --- a/build.vsh +++ b/build.vsh @@ -43,7 +43,14 @@ const ignore_dirs = { // TODO: nohup is included in Win32 version 'nohup', ] + // Vinix is a Unix-like, so it shares the macOS list. The two categories + // differ for a reason worth spelling out: `stat` and `sync` are excluded on + // macOS because the BSD syscall surface differs from Linux, and Vinix + // follows POSIX closely enough that they do build there; `uptime` is + // excluded everywhere because it reads the utmp database, which Vinix + // does not implement yet. 'macos': ['stat', 'sync', 'uptime'] + 'vinix': ['uptime'] }[user_os()] or { [] } unbuffer_stdout() diff --git a/src/timeout/timeout.v b/src/timeout/timeout.v index 943685d..3f75cdf 100644 --- a/src/timeout/timeout.v +++ b/src/timeout/timeout.v @@ -249,7 +249,7 @@ fn handle_timeout(mut p os.Process, kill_after_ms i64, signal string, preserve_s if verbose { eprintln('${app_name}: sending signal ${signal} to command') } - terminate_process(p, sig_num, !foreground) + terminate_process(mut &p, sig_num, !foreground) if kill_after_ms > 0 { kill_start := time.now() @@ -263,7 +263,7 @@ fn handle_timeout(mut p os.Process, kill_after_ms i64, signal string, preserve_s if verbose { eprintln('${app_name}: sending signal KILL to command') } - terminate_process(p, 9, !foreground) + terminate_process(mut &p, 9, !foreground) } return handle_process_exit(mut p, preserve_status, 124) } diff --git a/src/timeout/timeout_default.c.v b/src/timeout/timeout_default.c.v index 48f756b..a912be6 100644 --- a/src/timeout/timeout_default.c.v +++ b/src/timeout/timeout_default.c.v @@ -4,7 +4,7 @@ fn setup_process_group(p os.Process, foreground bool) { // Fallback } -fn terminate_process(p os.Process, sig_num int, process_group bool) { +fn terminate_process(mut p &os.Process, sig_num int, process_group bool) { // Fallback: try to kill the process p.signal_kill() } diff --git a/src/timeout/timeout_nix.c.v b/src/timeout/timeout_nix.c.v index 00f4349..5a2d001 100644 --- a/src/timeout/timeout_nix.c.v +++ b/src/timeout/timeout_nix.c.v @@ -12,7 +12,7 @@ fn setup_process_group(p os.Process, foreground bool) { } } -fn terminate_process(p os.Process, sig_num int, process_group bool) { +fn terminate_process(mut p &os.Process, sig_num int, process_group bool) { pid := if process_group { -p.pid } else { p.pid } C.kill(pid, sig_num) } diff --git a/src/timeout/timeout_windows.c.v b/src/timeout/timeout_windows.c.v index c0c688a..a035f98 100644 --- a/src/timeout/timeout_windows.c.v +++ b/src/timeout/timeout_windows.c.v @@ -7,7 +7,7 @@ fn setup_process_group(p os.Process, foreground bool) { // A pointer, because signalling a process changes it. Passing it by value, as the // nix version can, made the compiler reference it for us and then reject that as // deprecated automatic referencing. -fn terminate_process(p os.Process, sig_num int, process_group bool) { +fn terminate_process(mut p &os.Process, sig_num int, process_group bool) { // TERM, Windows doesn't seem to support signals like Unixes does if sig_num == 15 { p.signal_term()