Files
Joseph MattielloandClaude Opus 5 5f0925f058 build(spm): drop unsafeFlags -- they make the package unconsumable by version
Kimi review on #625, and it is a real defect that defeats the point of the PR.

SwiftPM REFUSES to build a VERSIONED dependency (`from: "x.y.z"`) on any
package whose targets carry unsafe flags:

    error: 'app': the target 'virtualjaguar-libchdr' in product
           'VirtualJaguar' contains unsafe build flags

Only path and branch/revision dependencies are exempt. So a frontend doing the
natural thing -- pinning a release tag of this repo -- could not build, which
is exactly the "depend on it as a package instead of vendoring it" workflow
this manifest exists to enable.

My verification could not have caught it: `swift build` inside the repo builds
this as the ROOT package, and the root is exempt from the restriction. The
spm-build CI job had the same blind spot. Same shape as the boolean.h
correction earlier on this branch -- a test that structurally cannot observe
the failure it is cited as evidence against.

The flags only silenced unused-function/variable warnings in libchdr's unity
TU. Not worth making the package unusable; removed.

Added a CI job that consumes the package the way a frontend actually would --
a throwaway tagged clone plus a tiny consumer depending on it by version -- so
the restriction is tested rather than remembered. Two things about that job
were established by experiment rather than assumed:

  - It must run `swift build`, NOT `swift package resolve`. Resolve SUCCEEDS
    with unsafe flags present; the graph is only validated for a build.
  - The clone goes in a directory named after the repo, because SwiftPM derives
    package identity from the URL's last path component and not from `name:` in
    the manifest.

Also from the same review: check-package-sources.sh now uses `set -eu` rather
than `set -e`, and `command rm` in its trap. An unset variable expanding to
empty is precisely how a drift guard starts silently passing on nothing, and
this repo's shells alias rm to `rm -i`, which blocks forever with no tty. These
guard scripts get copied from, so the precedent matters.

  swift build (root)                 clean
  scripts/check-package-sources.sh   66 core + 13 libretro-common agree

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 20:33:15 -04:00

88 lines
3.7 KiB
Bash
Executable File

#!/usr/bin/env sh
# Assert Package.swift's source lists still match Makefile.common.
#
# Makefile.common is the single source of truth for what makes up the core.
# Package.swift has to repeat it, because SPM needs the file list in the
# manifest and cannot read a Makefile. A second hand-maintained copy of a list
# that changes every release is exactly the thing that rots: the downstream
# Provenance wrapper carried its own copy and drifted by 27 files over seven
# releases before anyone noticed, which is why this check exists rather than a
# comment asking people to remember.
#
# Fails loudly and names the offending files. It never edits Package.swift --
# same posture as the docs/cd-boot-matrix.md drift guard and the
# version_fallback.h check: a human decides what the right list is.
#
# Usage: sh scripts/check-package-sources.sh
# POSIX sh -- no bashisms.
# -u as well as -e: these guard scripts are copied from, and an unset variable
# silently expanding to empty is exactly how a drift check starts passing on
# nothing. `command rm` because this repo's shells alias rm to `rm -i`, which
# blocks forever with no tty.
set -eu
ROOT=$(cd "$(dirname "$0")/.." && pwd)
cd "$ROOT"
[ -f Makefile.common ] || { echo "check-package-sources: Makefile.common not found" >&2; exit 1; }
[ -f Package.swift ] || { echo "check-package-sources: Package.swift not found" >&2; exit 1; }
TMP=$(mktemp -d)
trap 'command rm -rf "$TMP"' EXIT INT TERM
# --- what Makefile.common says -------------------------------------------
# Every $(CORE_DIR)/....c and $(LIBRETRO_COMM_DIR)/....c mentioned anywhere in
# the file. Deliberately includes the arch-conditional blitter_simd_*.c: SPM
# compiles all three variants and lets each guard itself (see
# src/tom/blitter_simd_arch.h), so the union is the correct comparison.
grep -oE '\$\(CORE_DIR\)/[a-zA-Z0-9_/.-]+\.c' Makefile.common \
| sed 's|\$(CORE_DIR)/||' | sort -u > "$TMP/mk_core"
grep -oE '\$\(LIBRETRO_COMM_DIR\)/[a-zA-Z0-9_/.-]+\.c' Makefile.common \
| sed 's|\$(LIBRETRO_COMM_DIR)/||' | sort -u > "$TMP/mk_lrc"
# --- what Package.swift says ---------------------------------------------
# Read each array by name so the two lists can never be confused for each other
# if the file is reordered.
extract_array() {
# $1 = swift array variable name, $2 = output file
sed -n "/^let $1: \[String\] = \[/,/^\]/p" Package.swift \
| grep -oE '"[^"]+\.c"' | tr -d '"' | sort -u > "$2"
}
extract_array coreSources "$TMP/pkg_core"
extract_array libretroCommonSources "$TMP/pkg_lrc"
for f in mk_core mk_lrc pkg_core pkg_lrc; do
[ -s "$TMP/$f" ] || { echo "check-package-sources: '$f' came out empty -- the parser is broken, not the lists" >&2; exit 1; }
done
# --- compare ---------------------------------------------------------------
status=0
report() {
# $1 = label, $2 = makefile list, $3 = package list
missing=$(comm -23 "$2" "$3")
extra=$(comm -13 "$2" "$3")
if [ -n "$missing" ]; then
status=1
echo "ERROR: in Makefile.common but NOT in Package.swift ($1):" >&2
echo "$missing" | sed 's/^/ /' >&2
fi
if [ -n "$extra" ]; then
status=1
echo "ERROR: in Package.swift but NOT in Makefile.common ($1):" >&2
echo "$extra" | sed 's/^/ /' >&2
fi
}
report "coreSources" "$TMP/mk_core" "$TMP/pkg_core"
report "libretroCommonSources" "$TMP/mk_lrc" "$TMP/pkg_lrc"
if [ "$status" -ne 0 ]; then
echo "" >&2
echo "Makefile.common is the source of truth. Update the arrays in" >&2
echo "Package.swift to match, then re-run this check." >&2
exit 1
fi
echo "check-package-sources.sh: OK -- $(wc -l < "$TMP/mk_core" | tr -d ' ') core + $(wc -l < "$TMP/mk_lrc" | tr -d ' ') libretro-common sources agree"