#!/bin/bash # Build the pinned x264 H.264 encoder the worker will run for video (SMA-172): one static arm64 command-line program. # # x264 is GPL-2.0-or-later, the first GPL component Smally would ship. It is a separate program that the worker starts # with a command line and talks to through pipes and files: it is never linked into Smally or into any of its libraries, # and nothing else is linked into it except L-SMASH (ISC) for MP4 output and the system C library. See THIRD_PARTY.md, # RELEASING.md step 1 and ThirdParty/StaticCodecNotices/x264-0.165.3222/SOURCE-OFFER.md. # # What is built, and what is left out on purpose: # * x264 stable branch, commit b35605ace3ddf7c1a5d67a2eb553f034aef41d55 (2025-06-08, "r3222", core 165), from the # archive VideoLAN's GitLab serves for that commit, pinned by SHA-256. # * L-SMASH 2.14.5 (the last release, ISC licence), built as a static library and linked in, so that # `x264 --output file.mp4` works. Pinned by SHA-256 too. # * 8-bit, 4:2:0 only (`--bit-depth=8 --chroma-format=420`), the only kind of H.264 Smally writes. # * no ffmpeg (libavformat, libswscale), no ffms, no GPAC, no AviSynth, no OpenCL: the input is raw y4m on stdin. # * no shared library, no Homebrew: the tool chain is /usr/bin and the Xcode command-line tools, and the finished file # is checked to link nothing but /usr/lib/libSystem.B.dylib. # * arm64 only: Smally is Apple Silicon only (scripts/bundle.py builds a personal arm64 app). # # The one edit to the source: the archive has no git history, so x264's version.sh would print "core 165" with no # revision. This script replaces version.sh by a fixed one that prints the revision the pinned commit has upstream # (3222, the same string Homebrew's build of that commit reports). Nothing else in the source is touched, and # `__DATE__` is fixed so that the build date does not move the bytes. # # Usage: build-x264.sh OUTPUT_DIR writes OUTPUT_DIR/Helpers/x264 # Sources are read from the directory $SMALLY_X264_SOURCES names when it holds the archives (found by file name), else # downloaded from the upstream URLs. Prints the file SHA-256 and the signature-independent digest; ThirdParty/StaticCodecNotices/ # x264-0.165.3222/manifest.json pins them and scripts/x264_pin.py refuses any other build. set -euo pipefail X264_VERSION=0.165.3222 X264_COMMIT=b35605ace3ddf7c1a5d67a2eb553f034aef41d55 X264_SHA256=cd71a7515b0e9a012e1ac9b1f8415bebcaf6fc97d4db32286642ac4c0fbe24f9 X264_URL="https://code.videolan.org/videolan/x264/-/archive/$X264_COMMIT/x264-$X264_COMMIT.tar.gz" LSMASH_VERSION=2.14.5 LSMASH_SHA256=e6f7c31de684f4b89ee27e5cd6262bf96f2a5b117ba938d2d606cf6220f05935 LSMASH_URL="https://github.com/l-smash/l-smash/archive/refs/tags/v$LSMASH_VERSION.tar.gz" MIN_MACOS=14.0 OUT=${1:?usage: build-x264.sh OUTPUT_DIR} HERE=$(cd "$(dirname "$0")" && pwd) SOURCES=${SMALLY_X264_SOURCES:-} SCRATCH=$(mktemp -d "${TMPDIR:-/tmp}/x264-build.XXXXXX") trap 'rm -rf "$SCRATCH"' EXIT # Nothing from a package manager can reach the build: a fixed PATH, no pkg-config, no Homebrew prefix. export PATH=/usr/bin:/bin:/usr/sbin:/sbin unset CPATH LIBRARY_PATH PKG_CONFIG_PATH PKG_CONFIG_LIBDIR CFLAGS LDFLAGS CPPFLAGS [ "$(uname -m)" = arm64 ] || { echo "x264 is built on Apple Silicon only" >&2; exit 1; } fetch() { # url sha256 cached-name local file="$SCRATCH/$3" if [ -n "$SOURCES" ] && [ -f "$SOURCES/$3" ]; then cp "$SOURCES/$3" "$file"; else curl --fail --silent --show-error --location "$1" -o "$file"; fi echo "$2 $file" | shasum -a 256 --check --status || { echo "$3 does not match its pinned SHA-256" >&2; exit 1; } tar -xzf "$file" -C "$SCRATCH" } fetch "$LSMASH_URL" "$LSMASH_SHA256" "lsmash-$LSMASH_VERSION.tar.gz" fetch "$X264_URL" "$X264_SHA256" "x264-$X264_COMMIT.tar.gz" # Reproducible: no build directory in the objects, no debug map, archive members without dates, no build date. export ZERO_AR_DATE=1 PREFIX="$SCRATCH/prefix" MAP="-ffile-prefix-map=$SCRATCH=/x264" TARGET="-arch arm64 -mmacosx-version-min=$MIN_MACOS" # L-SMASH: the library and its header only. Its configure has no --disable-shared: static is its default. cd "$SCRATCH/l-smash-$LSMASH_VERSION" ./configure --prefix="$PREFIX" --cc=clang --extra-cflags="$TARGET $MAP" >/dev/null # (its makefile prints harmless BSD-sed complaints about a shared-library version script this build never makes) make -j"$(sysctl -n hw.ncpu)" lib >"$SCRATCH/lsmash-make.log" 2>&1 || { cat "$SCRATCH/lsmash-make.log" >&2; exit 1; } make install-lib >/dev/null 2>&1 # x264 itself. cd "$SCRATCH/x264-$X264_COMMIT" cat > version.sh <<'EOF' #!/bin/sh # Replaced by scripts/build-x264.sh: the source archive carries no git history. Upstream revision of the pinned commit. echo '#define X264_REV 3222' echo '#define X264_REV_DIFF 0' echo '#define X264_VERSION " r3222 b35605a"' echo '#define X264_POINTVER "0.165.3222 b35605a"' EOF ./configure --prefix="$SCRATCH/x264-install" --cc=clang --enable-static --bit-depth=8 --chroma-format=420 \ --disable-opencl --disable-avs --disable-swscale --disable-lavf --disable-ffms --disable-gpac \ --extra-cflags="$TARGET $MAP -I$PREFIX/include -Wno-builtin-macro-redefined -D__DATE__=\\\"1970-01-01\\\"" \ --extra-asflags="$TARGET" \ --extra-ldflags="$TARGET -Wl,-S -L$PREFIX/lib" >"$SCRATCH/configure.log" grep -q '^mp4: *lsmash$' "$SCRATCH/configure.log" || { echo "MP4 output through L-SMASH was not enabled" >&2; cat "$SCRATCH/configure.log" >&2; exit 1; } grep -q '^bit depth: *8$' "$SCRATCH/configure.log" || { echo "not an 8-bit build" >&2; exit 1; } make -j"$(sysctl -n hw.ncpu)" x264 >/dev/null 2>&1 mkdir -p "$OUT/Helpers" rm -f "$OUT/Helpers/x264" cp x264 "$OUT/Helpers/x264" chmod 755 "$OUT/Helpers/x264" codesign --force --sign - "$OUT/Helpers/x264" # One executable, arm64, nothing from a package manager, no dynamic library beyond the system's. [ "$(lipo -archs "$OUT/Helpers/x264")" = arm64 ] || { echo "the build is not arm64 only" >&2; exit 1; } if otool -L "$OUT/Helpers/x264" | tail -n +2 | awk '{print $1}' | grep -v -x '/usr/lib/libSystem.B.dylib'; then echo "x264 links something other than the system C library" >&2 exit 1 fi if strings -a "$OUT/Helpers/x264" | grep -E '/opt/homebrew|/usr/local/(lib|Cellar)'; then echo "x264 names a package manager path" >&2 exit 1 fi # --version lists every optional input library the program was built with; only L-SMASH may appear. if "$OUT/Helpers/x264" --version | grep -i -E 'lavf|libav|ffms|swscale|gpac|avs'; then echo "x264 was built with an input library it must not have" >&2 exit 1 fi "$OUT/Helpers/x264" --version shasum -a 256 "$OUT/Helpers/x264" python3 "$HERE/x264_pin.py" --digests "$OUT"