diff --git a/.github/workflows/build-ffmpeg.yml b/.github/workflows/build-ffmpeg.yml index 74c54710..bb9e9114 100644 --- a/.github/workflows/build-ffmpeg.yml +++ b/.github/workflows/build-ffmpeg.yml @@ -85,3 +85,42 @@ jobs: with: name: output-${{ matrix.os }} path: output/ + + cross-build: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ "ubuntu-24.04" ] + build: [ "manylinux_", "musllinux_" ] + # arch: [ "loongarch64", "ppc64le", "riscv64", "s390x" ] + arch: [ "ppc64le" ] + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 + with: + python-version: "3.13" + - uses: docker/setup-qemu-action@v3 + - name: Build FFmpeg + env: + CIBW_ARCHS: ${{ matrix.arch }} + CIBW_BEFORE_ALL_LINUX: ./scripts/install-static-clang.sh + CIBW_BEFORE_BUILD_LINUX: python scripts/build-ffmpeg.py /tmp/vendor --community + CIBW_BUILD: cp311-${{ matrix.build }}${{ matrix.arch }} + CIBW_ENVIRONMENT_LINUX: > + CC="/opt/clang/bin/clang" + CXX="/opt/clang/bin/clang++" + LDFLAGS="-fuse-ld=lld" + CIBW_ENVIRONMENT_PASS_LINUX: RUNNER_ARCH + CIBW_REPAIR_WHEEL_COMMAND_LINUX: LD_LIBRARY_PATH=/tmp/vendor/lib:$LD_LIBRARY_PATH auditwheel repair --exclude libmvec.so.1 --exclude libmvec-2.so --exclude libmvec.so --exclude libmvec -w {dest_dir} {wheel} + CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: delvewheel repair --add-path C:\cibw\vendor\bin -w {dest_dir} {wheel} + CIBW_TEST_COMMAND: python -c "import dummy" + run: | + pip install cibuildwheel delvewheel + cibuildwheel --output-dir output + rm -f output/*.whl + - name: Upload FFmpeg + uses: actions/upload-artifact@v6 + with: + name: output-${{ matrix.build }}${{ matrix.arch }} + path: output/ diff --git a/scripts/build-ffmpeg.py b/scripts/build-ffmpeg.py index f783ac81..77d00ded 100644 --- a/scripts/build-ffmpeg.py +++ b/scripts/build-ffmpeg.py @@ -274,17 +274,19 @@ def download_tars(packages: list[Package]) -> None: raise def make_tarball_name() -> str: - isArm64 = platform.machine() in {"arm64", "aarch64"} + machine = platform.machine().lower() + isArm64 = machine in {"arm64", "aarch64"} if sys.platform.startswith("win"): return "ffmpeg-windows-aarch64" if isArm64 else "ffmpeg-windows-x86_64" - elif sys.platform.startswith("linux"): - if is_musllinux: - return "ffmpeg-musllinux-aarch64" if isArm64 else "ffmpeg-musllinux-x86_64" - else: - return "ffmpeg-manylinux-aarch64" if isArm64 else "ffmpeg-manylinux-x86_64" + elif sys.platform.startswith("darwin"): return "ffmpeg-macos-arm64" if isArm64 else "ffmpeg-macos-x86_64" + + elif sys.platform.startswith("linux"): + prefix = "ffmpeg-musllinux-" if is_musllinux else "ffmpeg-manylinux-" + return prefix + machine + else: return "ffmpeg-unknown" @@ -403,6 +405,17 @@ def main(): ] ) + if plat == "Linux" and "RUNNER_ARCH" in os.environ: + ffmpeg_package.build_arguments.extend( + [ + "--enable-cross-compile", + "--target-os=linux", + "--arch=" + platform.machine().lower(), + "--cc=/opt/clang/bin/clang", + "--cxx=/opt/clang/bin/clang++", + ] + ) + ffmpeg_package.build_arguments.extend( [ "--disable-encoder=avui,dca,mlp,opus,s302m,sonic,sonic_ls,truehd,vorbis", diff --git a/scripts/cibuildpkg.py b/scripts/cibuildpkg.py index d6a1b959..c05e9eb2 100644 --- a/scripts/cibuildpkg.py +++ b/scripts/cibuildpkg.py @@ -226,6 +226,11 @@ def _build_with_autoconf(self, package: Package, for_builder: bool) -> None: configure_args += ["--target=x86_64-darwin20-gcc"] elif platform.system() == "Windows": configure_args += ["--target=x86_64-win64-gcc"] + elif platform.system() == "Linux": + if "RUNNER_ARCH" in os.environ: + prepend_env(env, "CFLAGS", "-pthread") + prepend_env(env, "CXXFLAGS", "-pthread") + prepend_env(env, "LDFLAGS", "-pthread") if package.name == "ffmpeg" and platform.system() == "Windows": prepend_env(env, "LDFLAGS", "-LC:/PROGRA~1/OpenSSL/lib") diff --git a/scripts/install-static-clang.sh b/scripts/install-static-clang.sh new file mode 100755 index 00000000..c84e494b --- /dev/null +++ b/scripts/install-static-clang.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +# Stop at any error, show all commands +set -exuo pipefail + +TOOLCHAIN_PATH=/opt/clang + +# Download static-clang +DEFAULT_ARCH="$(uname -m)" +if [ "${STATIC_CLANG_ARCH:-}" == "" ]; then + STATIC_CLANG_ARCH="${RUNNER_ARCH:-${DEFAULT_ARCH}}" +fi +case "${STATIC_CLANG_ARCH}" in + ARM64|aarch64|arm64|arm64/*) GO_ARCH=arm64;; + ARM|armv7l|armv8l|arm|arm/v7) GO_ARCH=arm;; # assume arm/v7 for arm + X64|x86_64|amd64|amd64/*) GO_ARCH=amd64;; + X86|i686|386) GO_ARCH=386;; + ppc64le) GO_ARCH=ppc64le;; + riscv64) GO_ARCH=riscv64;; + s390x) GO_ARCH=s390x;; + *) echo "No static-clang toolchain for ${CLANG_ARCH}">2; exit 1;; +esac +STATIC_CLANG_VERSION=21.1.8.1 +STATIC_CLANG_FILENAME="static-clang-linux-${GO_ARCH}.tar.xz" +STATIC_CLANG_URL="https://github.com/mayeut/static-clang-images/releases/download/v${STATIC_CLANG_VERSION}/${STATIC_CLANG_FILENAME}" +pushd /tmp +cat<<'EOF' | grep "${STATIC_CLANG_FILENAME}" > "${STATIC_CLANG_FILENAME}.sha256" +583980309e73fa753c0791e05deceac7cb06c5444956d61189f1d651941bcd8e static-clang-linux-386.tar.xz +f539f1fd24bcc07ecc220594022907865914236540091fbf189cb496a9a3751c static-clang-linux-amd64.tar.xz +d0c8b7fac4734cc8048fda3b1f33ccdf24d26f81a52df53348e5fa84ab4b203a static-clang-linux-arm.tar.xz +57fb9cf798b3a2c4b0f3c31c0b7fe3803b5319d2af075407e1aef0cd57882f65 static-clang-linux-arm64.tar.xz +5a2b296e9030d0320d9e4eac8859e5db0504cf1d4169981af233cb339292fa4c static-clang-linux-loong64.tar.xz +c8541b2d36f0fd8f13ddabe1292b6fb7550a742e76e0f1f70fb29fcee073be4a static-clang-linux-ppc64le.tar.xz +b311137f955b55139b02e8c1d7ec259628404a0563d136df7a817a33784bd2bf static-clang-linux-riscv64.tar.xz +de74fd8e5de244d36398684b2afa67add2311df6ccfa24f3c08a1d777ca814fa static-clang-linux-s390x.tar.xz +EOF +curl -fsSLO "${STATIC_CLANG_URL}" +sha256sum -c "${STATIC_CLANG_FILENAME}.sha256" +tar -C /opt -xf "${STATIC_CLANG_FILENAME}" +popd + +# configure target triple +case "${AUDITWHEEL_POLICY}-${AUDITWHEEL_ARCH}" in + manylinux*-armv7l) TARGET_TRIPLE=armv7-unknown-linux-gnueabihf;; + musllinux*-armv7l) TARGET_TRIPLE=armv7-alpine-linux-musleabihf;; + manylinux*-ppc64le) TARGET_TRIPLE=powerpc64le-unknown-linux-gnu;; + musllinux*-ppc64le) TARGET_TRIPLE=powerpc64le-alpine-linux-musl;; + manylinux*-*) TARGET_TRIPLE=${AUDITWHEEL_ARCH}-unknown-linux-gnu;; + musllinux*-*) TARGET_TRIPLE=${AUDITWHEEL_ARCH}-alpine-linux-musl;; +esac +case "${AUDITWHEEL_POLICY}-${AUDITWHEEL_ARCH}" in + *-riscv64) M_ARCH="-march=rv64gc";; + *-x86_64) M_ARCH="-march=x86-64";; + *-armv7l) M_ARCH="-march=armv7a";; + manylinux*-i686) M_ARCH="-march=k8 -mtune=generic";; # same as gcc manylinux2014 / manylinux_2_28 + musllinux*-i686) M_ARCH="-march=pentium-m -mtune=generic";; # same as gcc musllinux_1_2 +esac +GCC_TRIPLE=$(gcc -dumpmachine) + +cat<"${TOOLCHAIN_PATH}/bin/${AUDITWHEEL_PLAT}.cfg" + -target ${TARGET_TRIPLE} + ${M_ARCH:-} + --gcc-toolchain=${DEVTOOLSET_ROOTPATH:-}/usr + --gcc-triple=${GCC_TRIPLE} +EOF + +cat<"${TOOLCHAIN_PATH}/bin/clang.cfg" + @${AUDITWHEEL_PLAT}.cfg +EOF + +cat<"${TOOLCHAIN_PATH}/bin/clang++.cfg" + @${AUDITWHEEL_PLAT}.cfg +EOF + +cat<"${TOOLCHAIN_PATH}/bin/clang-cpp.cfg" + @${AUDITWHEEL_PLAT}.cfg +EOF + +# override entrypoint to add the toolchain to PATH +mv /usr/local/bin/manylinux-entrypoint /usr/local/bin/manylinux-entrypoint-org +cat</usr/local/bin/manylinux-entrypoint +#!/bin/bash + +set -eu + +export PATH="${TOOLCHAIN_PATH}/bin:\${PATH}" +exec /usr/local/bin/manylinux-entrypoint-org "\$@" +EOF + +chmod +x /usr/local/bin/manylinux-entrypoint