Skip to content

Commit c75e75a

Browse files
validate: the llvm leg plants FFmpeg's header names under /usr/include instead of installing Ubuntu's
Each public header name of the release compat.ffmpeg names becomes a file that stops the compile and names itself, so a reach of the host's header fails at the include that made it. Ubuntu's ffmpeg closure no longer downloaded within any timeout on ubuntu-26.04 runners (2026-11-06). Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com>
1 parent 51482d5 commit c75e75a

2 files changed

Lines changed: 50 additions & 34 deletions

File tree

‎.github/workflows/validate.yml‎

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,46 +1421,60 @@ jobs:
14211421
# A bare GitHub runner has no libav* under /usr/include, so a
14221422
# descriptor that loses its vendored headers to the host's would still
14231423
# be green here. That is precisely how compat.ffmpeg's -idirafter hole
1424-
# survived: nothing in CI had a system ffmpeg to lose to. Installing
1425-
# the dev headers is what turns this leg into a real test of include
1426-
# ORDER rather than of include EXISTENCE.
1424+
# survived: nothing in CI had a system ffmpeg to lose to. Headers of
1425+
# FFmpeg's own names under /usr/include are what turn this leg into a
1426+
# test of include ORDER rather than of include EXISTENCE.
1427+
#
1428+
# They are planted, not installed: each public header of the release
1429+
# compat.ffmpeg names, as a file that stops the compile, naming itself.
1430+
# A reach of the host's header is then an error at the line that made
1431+
# it, where an installed header of another FFmpeg compiled silently or
1432+
# failed somewhere else. And nothing is downloaded from Ubuntu's mirror,
1433+
# whose ffmpeg closure (~100 MiB at the 2026-11-06 rates) outlasted
1434+
# every timeout on ubuntu-26.04 runners.
14271435
#
14281436
# Deliberately only on the llvm leg. The default leg reaches its
14291437
# compiler through --sysroot, so it is immune by construction and
1430-
# installing there would change an existing job's environment for no
1438+
# planting there would change an existing job's environment for no
14311439
# coverage. Keeping the blast radius to the new leg means a red here
14321440
# is always about the thing this leg was added to watch.
1433-
- name: Install host ffmpeg dev headers (llvm leg only)
1441+
- name: Plant host ffmpeg headers that stop the compile (llvm leg only)
14341442
if: matrix.platform == 'linux' && matrix.toolchain == 'llvm'
14351443
shell: bash
1436-
# Only Ubuntu's own archive is refreshed: a bare `apt-get update` also
1437-
# walks every third-party source the runner image carries (PPAs,
1438-
# vendor repos), and one slow mirror among them held this step for
1439-
# minutes. Bounded timeouts and retries, and no recommended packages.
14401444
run: |
1441-
apt_opts=(-o Acquire::Retries=3 -o Acquire::http::Timeout=20 -o Acquire::https::Timeout=20)
1442-
if [[ -f /etc/apt/sources.list.d/ubuntu.sources ]]; then
1443-
mkdir -p "$RUNNER_TEMP/apt-ubuntu"
1444-
cp /etc/apt/sources.list.d/ubuntu.sources "$RUNNER_TEMP/apt-ubuntu/"
1445-
apt_opts+=(-o Dir::Etc::SourceList=/dev/null -o "Dir::Etc::SourceParts=$RUNNER_TEMP/apt-ubuntu")
1446-
fi
1447-
# IPv4: on 2026-11-06 the install stalled without output for the
1448-
# whole timeout on several runners while the index update had taken
1449-
# seconds. The install now reports its progress, waits for a held
1450-
# dpkg lock rather than stalling on it, and is tried three times.
1451-
apt_opts+=(-o Acquire::ForceIPv4=true -o DPkg::Lock::Timeout=120)
1452-
time sudo timeout 180 apt-get update -qq "${apt_opts[@]}"
1453-
for attempt in 1 2 3; do
1454-
if time sudo timeout 240 apt-get install -y -q --no-install-recommends "${apt_opts[@]}" \
1455-
libavutil-dev libavcodec-dev libavformat-dev \
1456-
libavfilter-dev libavdevice-dev libswscale-dev libswresample-dev; then
1457-
break
1458-
fi
1459-
[[ $attempt == 3 ]] && { echo "::error::the ffmpeg dev headers did not install"; exit 1; }
1460-
echo "::warning::apt-get install failed (attempt $attempt); retrying"
1461-
sudo timeout 120 apt-get update -qq "${apt_opts[@]}" || true
1462-
done
1463-
dpkg -l | grep -E 'libav(util|codec)-dev|libswscale-dev'
1445+
python3 - <<'PY'
1446+
import hashlib, io, re, subprocess, tarfile, urllib.request
1447+
from pathlib import Path
1448+
lua = Path("pkgs/c/compat.ffmpeg.lua").read_text()
1449+
entry = re.search(r'linux\s*=\s*\{\s*\["([^"]+)"\]\s*=\s*\{.*?GLOBAL\s*=\s*"([^"]+)".*?CN\s*=\s*"([^"]+)".*?sha256\s*=\s*"([0-9a-f]{64})"', lua, re.S)
1450+
version, urls, sha = entry.group(1), (entry.group(2), entry.group(3)), entry.group(4)
1451+
data = None
1452+
for url in urls:
1453+
try:
1454+
data = urllib.request.urlopen(url, timeout=120).read()
1455+
except OSError as e:
1456+
print(f"::warning::{url}: {e}")
1457+
continue
1458+
if hashlib.sha256(data).hexdigest() == sha:
1459+
break
1460+
data = None
1461+
if data is None:
1462+
raise SystemExit(f"::error::the FFmpeg {version} source matching the descriptor could not be read")
1463+
libs = ("libavutil", "libavcodec", "libavformat", "libavfilter", "libavdevice", "libswscale", "libswresample")
1464+
planted = 0
1465+
with tarfile.open(fileobj=io.BytesIO(data)) as tar:
1466+
for name in tar.getnames():
1467+
parts = name.split("/")
1468+
if len(parts) == 3 and parts[1] in libs and parts[2].endswith(".h"):
1469+
target = Path("/usr/include") / parts[1] / parts[2]
1470+
text = f'#error "host <{parts[1]}/{parts[2]}> reached: a vendored FFmpeg header was not found first"\n'
1471+
subprocess.run(["sudo", "mkdir", "-p", str(target.parent)], check=True)
1472+
subprocess.run(["sudo", "tee", str(target)], input=text.encode(), check=True, stdout=subprocess.DEVNULL)
1473+
planted += 1
1474+
if planted < 100:
1475+
raise SystemExit(f"::error::only {planted} FFmpeg headers were planted")
1476+
print(f"planted {planted} FFmpeg {version} headers under /usr/include")
1477+
PY
14641478
14651479
# ── Select the toolchain for this leg ─────────────────────────────
14661480
# No version pin: `llvm` resolves to whatever the toolchain family's

‎CHANGELOG.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515

1616
### Chore
1717

18-
- **validate:llvm 腿安装宿主 ffmpeg 头文件时改走 IPv4、等待 dpkg 锁并重试三次。** 2026-11-06 起多个运行器上安装在超时内没有任何
19-
输出,而索引更新只用数秒;安装现在输出进度,失败后重新更新索引再试。
18+
- **validate:llvm 腿不再从 Ubuntu 镜像安装 ffmpeg 开发包,改为在 `/usr/include` 下放置 FFmpeg 公开头文件同名、内容为
19+
`#error` 的文件。** 文件名取自 compat.ffmpeg 描述符所指发布(按描述符的 sha256 校验)。宿主头文件一旦被包含即在包含处报错,
20+
比安装另一版本的头文件更直接地检验包含顺序;2026-11-06 起 ubuntu-26.04 运行器上 ffmpeg 依赖闭包(约 100 MiB)的下载在每个
21+
超时内都完成不了。
2022

2123
### Added
2224

0 commit comments

Comments
 (0)