Notcurses-Native.git | scripts/ci/ | build-libvpx.sh edit


#!/usr/bin/env bash
# Build + install libvpx — Google's VP8 / VP9 codec. Linked into our
# source-built ffmpeg via --enable-libvpx so VP8/9 video decode has
# the same accelerated path users get on package-managed lanes.
#
# Honours $PREFIX (default /usr/local). Honours $MACOSX_DEPLOYMENT_TARGET
# on macOS — libvpx's configure passes it through to clang.
#
# Configure is a hand-rolled script (not autotools), with its own
# arch/CPU detection. nasm or yasm is needed on x86_64 for SIMD
# acceleration; libvpx tolerates either.
#
# Windows/MSYS2 is the one platform where this script has to diverge,
# and both divergences are imposed by upstream rather than chosen:
#
#   1. The target must be named explicitly. libvpx auto-detects it
#      from `$CC -dumpmachine` and its OS table only knows the strings
#      `x86_64*mingw32*` and `*mingw32*` (build/make/configure.sh
#      ~:839). UCRT64's gcc reports `x86_64-w64-mingw32` and lands on
#      x86_64-win64-gcc by luck; CLANGARM64's clang reports
#      `aarch64-w64-windows-gnu`, which matches nothing there, so
#      libvpx silently falls through to `generic-gnu` — a NEON-less
#      build with the wrong ABI assumptions that would still compile.
#      Naming the target removes the guesswork on both lanes.
#      `arm64-win64-gcc` is a first-class entry in 1.16.0's
#      all_platforms list (configure:109), so the arm64 lane is
#      supported upstream, not a hack.
#
#   2. Static only. libvpx's configure hard-refuses shared libraries
#      anywhere but ELF/OS-2/Darwin — "--enable-shared only supported
#      on ELF, OS/2, and Darwin for now" (configure:575). The escape
#      hatch one line above it is `enabled gnu`, and `gnu` is only set
#      for the literal `generic-gnu` toolchain, never for
#      `*-win64-gcc`, so there is no flag combination that produces a
#      libvpx DLL from this build system. We therefore build libvpx.a
#      and let ffmpeg absorb it into avcodec-<N>.dll; build-ffmpeg.sh
#      already passes --pkg-config-flags=--static, so pkgconf hands
#      ffmpeg vpx.pc's Libs plus Libs.private and the link resolves.
#      Two consequences worth knowing downstream: there is no
#      libvpx-*.dll to bundle on Windows, and the libvpx_vp8 /
#      libvpx_vp9 decoders that run-codec-probe.sh gates on live
#      inside avcodec itself. libvpx is BSD-3-Clause, so folding it
#      into an LGPL-2.1 shared library raises no licensing question.
#      (MSYS2's own mingw-w64-*-libvpx package does ship a
#      libvpx-1.dll — it is built through libvpx's separate CMake
#      build system, not this configure. Static suits us better
#      anyway: same decoders, one fewer DLL in the archive.)
set -euxo pipefail

# 1.16.0 — current stable (1.17.0 is still at -rc, and we don't ship
# release candidates).
VERSION='1.16.0'
URL="https://github.com/webmproject/libvpx/archive/refs/tags/v${VERSION}.tar.gz"
PREFIX="${PREFIX:-/usr/local}"
mkdir -p "$PREFIX"

JOBS="$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)"

cd /tmp
curl -fSL --retry 5 --retry-delay 10 -o libvpx.tar.gz "$URL"
tar -xzf libvpx.tar.gz
cd "libvpx-${VERSION}"

# Decoders are all we care about (notcurses doesn't encode video);
# disabling encoders would skip a chunk of unused build, but
# `--enable-vp8 --enable-vp9` enables encoder + decoder both — we
# keep them all on because the encoder objects add < 1 MB and
# disabling them risks subtle linker grief inside ffmpeg's
# --enable-libvpx check.
configure_args=(
    --prefix="$PREFIX"
    --libdir="$PREFIX/lib"
    --enable-pic
    --enable-vp8
    --enable-vp9
    --disable-examples
    --disable-tools
    --disable-docs
    --disable-unit-tests
    --disable-install-bins
    --disable-install-srcs
)

# Linkage + target selection. See the header for why Windows is the
# odd one out on both counts.
case "$(uname -s)" in
    MINGW*|MSYS*|CYGWIN*)
        case "${MSYSTEM_CARCH:-}" in
            x86_64)  vpx_target='x86_64-win64-gcc' ;;
            aarch64) vpx_target='arm64-win64-gcc'  ;;
            '')
                echo "❌ MSYSTEM_CARCH is unset inside an MSYS2 shell." >&2
                echo "   Refusing to let libvpx guess its target: on CLANGARM64" >&2
                echo "   the guess is 'generic-gnu', which builds but is wrong." >&2
                exit 1
                ;;
            *)
                echo "❌ Unhandled MSYSTEM_CARCH='$MSYSTEM_CARCH'." >&2
                echo "   Map it to a libvpx target from ./configure --help's" >&2
                echo "   platform list before adding that MSYS2 environment." >&2
                exit 1
                ;;
        esac
        configure_args+=( --target="$vpx_target" --disable-shared --enable-static )
        ;;
    *)
        configure_args+=( --enable-shared --disable-static )
        ;;
esac

./configure "${configure_args[@]}"
make -j"$JOBS"
make install

# libvpx's macOS build leaves the dylib's install_name as a bare
# leaf name (e.g. "libvpx.9.dylib") — no @rpath/ prefix, no
# absolute path. This is fine for direct linking + DT_NEEDED
# resolution via fallback paths, but breaks downstream
# dylibbundler when notcurses → dylibbundler tries to walk the
# dep tree. dylibbundler can't resolve a bare leaf name back to
# a file and dies with "Cannot resolve path libvpx.X.dylib"
# followed by an otool "can't open file" error. Patch the
# install_name to @rpath/<leaf> so dylibbundler can do its job.
# Linux dylibs don't have this concept (DT_SONAME is always a
# leaf-style name without prefix, and patchelf later handles
# rpath separately), so this fixup is macOS-only.
if [[ "$(uname -s)" == "Darwin" ]]; then
    for dylib in "$PREFIX/lib"/libvpx.*.dylib; do
        [[ -L "$dylib" ]] && continue
        leaf=$(basename "$dylib")
        install_name_tool -id "@rpath/$leaf" "$dylib"
        echo "  patched install_name: $dylib  ->  @rpath/$leaf"
    done
fi

PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig:${PKG_CONFIG_PATH:-}" \
    pkg-config --modversion vpx

cd /
rm -rf "/tmp/libvpx-${VERSION}" /tmp/libvpx.tar.gz