Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions .github/workflows/desktop-linux.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: Desktop Linux

on:
workflow_dispatch:
workflow_call:
pull_request:
paths:
- ".github/workflows/desktop-linux.yml"
- ".github/workflows/release.yml"
- "versions.env"
- "scripts/build-desktop-cli.sh"
- "scripts/common.sh"
- "scripts/fetch-sources.sh"
- "scripts/verify-desktop-cli.sh"
- "patches/x264/**"
- "tests/desktop_cli/**"

permissions:
contents: read

env:
FFMPEG_WORKSPACE: ${{ github.workspace }}-build

jobs:
build:
name: Build and verify ${{ matrix.arch }}
strategy:
fail-fast: false
matrix:
include:
- arch: x64
runner: ubuntu-22.04
image: quay.io/pypa/manylinux_2_28_x86_64@sha256:39df0042d5cc900b085aa25a0659368b42a0006c54c474299b785b44c1b4ff82
- arch: arm64
runner: ubuntu-22.04-arm
image: quay.io/pypa/manylinux_2_28_aarch64@sha256:f5f03dedf61b47d69d0742d36047db78adeee3bdb7a9910ff52304750ecf2514
runs-on: ${{ matrix.runner }}
timeout-minutes: 120

steps:
- uses: actions/checkout@v4

- name: Install verification tools
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends binutils python3 ripgrep

- name: Build desktop CLI
run: |
mkdir -p "$FFMPEG_WORKSPACE"
docker run --rm \
-v "$PWD:/src:ro" -v "$FFMPEG_WORKSPACE:/build" \
-w /src -e FFMPEG_WORKSPACE=/build \
"${{ matrix.image }}" bash -ec '
dnf upgrade -y --security
dnf install -y meson ninja-build nasm ripgrep xz-devel
export PATH="/opt/python/cp312-cp312/bin:$PATH"
git config --global --add safe.directory /src
scripts/build-desktop-cli.sh desktop-linux-${{ matrix.arch }}
'

- name: Verify on Ubuntu
run: |
mkdir -p artifact
tar -xzf "$FFMPEG_WORKSPACE/dist/desktop/linux-${{ matrix.arch }}/ffmpeg.tar.gz" -C artifact
WORK_ROOT="$RUNNER_TEMP/ffmpeg-verify" scripts/verify-desktop-cli.sh "$PWD/artifact"

- name: Verify on glibc 2.28
run: |
docker run --rm -v "$PWD:/src:ro" \
almalinux:8@sha256:8b469a3a78515e8a18ea8fc727e6a3679e1d0c5ba6f58d5b30be3d0d9b86cffe \
bash -ec '
dnf upgrade -y --security
dnf install -y python3.12 libstdc++ zlib xz-libs
python3.12 /src/tests/desktop_cli/verify_media.py \
--ffmpeg /src/artifact/ffmpeg --ffprobe /src/artifact/ffprobe \
--work-dir /tmp/verify --target linux-${{ matrix.arch }}
'

- name: Upload desktop assets
uses: actions/upload-artifact@v4
with:
name: release-desktop-linux-${{ matrix.arch }}
path: |
${{ env.FFMPEG_WORKSPACE }}/dist/desktop/linux-${{ matrix.arch }}/ffmpeg.tar.gz
${{ env.FFMPEG_WORKSPACE }}/dist/desktop/linux-${{ matrix.arch }}/ffmpeg.tar.gz.sha256
${{ env.FFMPEG_WORKSPACE }}/dist/desktop/linux-${{ matrix.arch }}/ffmpeg.tar.gz.manifest.env
if-no-files-found: error
40 changes: 2 additions & 38 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,44 +117,8 @@ jobs:
if-no-files-found: error

desktop-linux:
name: Desktop Linux ${{ matrix.arch }}
strategy:
fail-fast: false
matrix:
include:
- { arch: x64, runner: ubuntu-22.04 }
- { arch: arm64, runner: ubuntu-22.04-arm }
runs-on: ${{ matrix.runner }}
timeout-minutes: 120

steps:
- uses: actions/checkout@v4

- name: Install host tools and libraries
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
autoconf automake binutils curl g++ git libtool make nasm pkg-config ripgrep \
meson ninja-build python3 xz-utils zlib1g-dev

- name: Build desktop CLI
run: scripts/build-desktop-cli.sh desktop-linux-${{ matrix.arch }}

- name: Verify desktop CLI
run: |
mkdir -p artifact
tar -xzf "$FFMPEG_WORKSPACE/dist/desktop/linux-${{ matrix.arch }}/ffmpeg.tar.gz" -C artifact
scripts/verify-desktop-cli.sh "$PWD/artifact"

- name: Upload desktop assets
uses: actions/upload-artifact@v4
with:
name: release-desktop-linux-${{ matrix.arch }}
path: |
${{ env.FFMPEG_WORKSPACE }}/dist/desktop/linux-${{ matrix.arch }}/ffmpeg.tar.gz
${{ env.FFMPEG_WORKSPACE }}/dist/desktop/linux-${{ matrix.arch }}/ffmpeg.tar.gz.sha256
${{ env.FFMPEG_WORKSPACE }}/dist/desktop/linux-${{ matrix.arch }}/ffmpeg.tar.gz.manifest.env
if-no-files-found: error
name: Desktop Linux
uses: ./.github/workflows/desktop-linux.yml

desktop-macos-universal:
name: Desktop macOS universal
Expand Down
22 changes: 21 additions & 1 deletion scripts/build-desktop-cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,18 @@ build_one_desktop() {
local extra_cflags=""
local extra_ldflags=""
local ffmpeg_cross_flags=()
if [ "$DESKTOP_OS" = "linux" ]; then
local bzip2_src="$target_root/bzip2-$BZIP2_VERSION"
local bzip2_archive="$DOWNLOADS_ROOT/bzip2-$BZIP2_VERSION.tar.gz"
curl -fL "https://sourceware.org/pub/bzip2/bzip2-$BZIP2_VERSION.tar.gz" -o "$bzip2_archive"
verify_sha256 "$bzip2_archive" "$BZIP2_SHA256"
tar -xf "$bzip2_archive" -C "$target_root"
extra_cflags="-fstack-protector-strong -D_FORTIFY_SOURCE=2 -I$bzip2_src"
extra_ldflags="-L$bzip2_src -Wl,-z,relro,-z,now"
make -C "$bzip2_src" -j"$JOBS" libbz2.a \
CC="$cc" AR="$ar" RANLIB="$ranlib" CFLAGS="-O2 -fPIC $extra_cflags"
ffmpeg_cross_flags+=(--enable-pic --extra-ldexeflags=-pie --enable-bzlib --enable-lzma --disable-xlib)
fi
if [ "$DESKTOP_OS" = "darwin" ]; then
export MACOSX_DEPLOYMENT_TARGET="$DESKTOP_MACOS_MIN_VERSION"
extra_cflags="-arch $DESKTOP_ARCH"
Expand Down Expand Up @@ -263,10 +275,18 @@ case "$target" in
;;
*)
archive="$out/ffmpeg.tar.gz"
tar -C "$out" -czf "$archive" ffmpeg ffprobe dav1d-COPYING
files=(ffmpeg ffprobe dav1d-COPYING)
if [[ "$target" == desktop-linux-* ]]; then
cp "$BUILD_ROOT/$target/bzip2-$BZIP2_VERSION/LICENSE" "$out/bzip2-LICENSE"
files+=(bzip2-LICENSE)
fi
tar -C "$out" -czf "$archive" "${files[@]}"
;;
esac
sha256_file "$archive" > "$archive.sha256"
write_manifest "$archive.manifest.env" "TARGET=$target" "ARTIFACT=$archive" \
"DAV1D_VERSION=$DAV1D_VERSION" "DAV1D_SHA256=$DAV1D_SHA256"
if [[ "$target" == desktop-linux-* ]]; then
printf 'BZIP2_VERSION=%s\nBZIP2_SHA256=%s\n' "$BZIP2_VERSION" "$BZIP2_SHA256" >> "$archive.manifest.env"
fi
log "built desktop artifact $archive"
40 changes: 17 additions & 23 deletions scripts/verify-desktop-cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,37 +55,31 @@ fi

if command -v ldd >/dev/null 2>&1 && [ "$(uname -s)" = "Linux" ]; then
ldd "$ffmpeg" > "$WORK_ROOT/desktop-ffmpeg-ldd.txt"
if rg -q 'lib(x264|zimg|dav1d)' "$WORK_ROOT/desktop-ffmpeg-ldd.txt"; then
die "desktop ffmpeg must link pinned x264/zimg/dav1d statically"
if rg -q 'lib(x264|zimg|dav1d|bz2)' "$WORK_ROOT/desktop-ffmpeg-ldd.txt"; then
die "desktop ffmpeg must link pinned x264/zimg/dav1d/bzip2 statically"
fi
fi

if command -v objdump >/dev/null 2>&1 && [ "$(uname -s)" = "Linux" ]; then
if [ "$(uname -s)" = "Linux" ]; then
require_cmd readelf
for binary in "$ffmpeg" "$ffprobe"; do
glibc_report="$WORK_ROOT/$(basename "$binary")-glibc-symbols.txt"
objdump -T "$binary" | rg -o 'GLIBC_[0-9]+\.[0-9]+' | sort -Vu > "$glibc_report" || true
python3 - "$binary" "$glibc_report" "$DESKTOP_LINUX_MAX_GLIBC" <<'PY'
report="$WORK_ROOT/$(basename "$binary")-elf.txt"
LC_ALL=C readelf --wide --version-info "$binary" > "$report"
python3 - "$binary" "$report" "$DESKTOP_LINUX_MAX_GLIBC" <<'PYTHON'
import re
import sys
from pathlib import Path

binary, report, max_allowed = sys.argv[1:]
binary, report, maximum = sys.argv[1:]
text = Path(report).read_text(encoding="utf-8")

def parse(version):
major, minor = version.split(".", 1)
return int(major), int(minor)
def numeric(value):
return tuple(map(int, value.split(".")))

with open(report, encoding="utf-8") as handle:
versions = sorted(
{line.strip().removeprefix("GLIBC_") for line in handle if line.strip()},
key=parse,
)
if not versions:
raise SystemExit(0)
highest = versions[-1]
if parse(highest) > parse(max_allowed):
raise SystemExit(
f"{binary} requires GLIBC_{highest}; max allowed is GLIBC_{max_allowed}"
)
PY
versions = re.findall(r"\bGLIBC_([0-9.]+)", text)
if not versions or max(map(numeric, versions)) > numeric(maximum):
raise SystemExit(f"{binary}: missing or unsupported GLIBC versions; maximum is {maximum}")
PYTHON
done
fi

Expand Down
5 changes: 4 additions & 1 deletion versions.env
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ DAV1D_VERSION=1.5.4
DAV1D_URL=https://downloads.videolan.org/pub/videolan/dav1d/1.5.4/dav1d-1.5.4.tar.xz
DAV1D_SHA256=686616b7c69eb88d44459391ab25cac13b6647a3b288835c5784e71c1514a5c5

BZIP2_VERSION=1.0.8
BZIP2_SHA256=ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269

ANDROID_API=26
ANDROID_NDK_VERSION=28.2.13676358
IOS_MIN_VERSION=14.0
XCODE_VERSION=26.2
DESKTOP_LINUX_MAX_GLIBC=2.35
DESKTOP_LINUX_MAX_GLIBC=2.28
DESKTOP_MACOS_MIN_VERSION=13.3

MOBILE_TARGETS="android-arm64 android-armv7 ios-device-arm64 ios-sim-arm64"
Expand Down
Loading