#!/usr/bin/env bash # This script builds ffmpeg for macOS using osxcross. # This script is heavly influenced by: # https://github.com/FFmpeg/FFmpeg/blob/ea3d24bbe3c58b171e55fe2151fc7ffaca3ab3d2/configure # https://github.com/GerardSoleCa/macports-ports/blob/6f646dfaeb58ccb4a8b877df1ae4eecc4650fac7/multimedia/ffmpeg-upstream/Portfile # https://github.com/arthenica/ffmpeg-kit/blob/47f85fa9ea3f8c34f3c817b87d8667b61b87d0bc/scripts/apple/ffmpeg.sh # https://github.com/zimbatm/ffmpeg-static/blob/3206c0d74cd129c2ddfc3e928dcd3ea317d54857/build.sh set -euox pipefail if [ "$#" -ne 2 ]; then echo "Usage: $0 " >&2 exit 1 fi if [ -z "$MACOSX_DEPLOYMENT_TARGET" ]; then echo "You must set MACOSX_DEPLOYMENT_TARGET first." >&2 exit 1 fi ARCH="$1" MACOS_VERSION="$2" set -- # Clear command line arguments if [ "$ARCH" = "x86_64" ]; then TARGET_CPU="x86_64" TARGET_ARCH="x86_64" set -- --enable-x86asm elif [ "$ARCH" = "aarch64" ]; then TARGET_CPU="armv8" TARGET_ARCH="aarch64" set -- --enable-neon --enable-asm else echo "Unsupported architecture: $ARCH" >&2 exit 1 fi # Get darwin version and build compiler triple DARWIN_VERSION="$(basename "$(realpath "$(command -v "oa64-clang")")" | awk -F- '{print $3}')" TRIPLE="${ARCH}-apple-${DARWIN_VERSION}" # Check macOS clang exists if ! CC="$(command -v "${TRIPLE}-clang" 2>/dev/null)"; then echo "${TRIPLE}-clang not found" >&2 exit 1 fi export CC # Get osxcross root directory _osxcross_root="$(dirname "$(dirname "$CC")")" # Check macports root exists _macports_root="${_osxcross_root}/macports/pkgs/opt/local" if ! [ -d "$_macports_root" ]; then echo "macports root not found: $_macports_root" >&2 exit 1 fi # Check SDK exists _sdk="${_osxcross_root}/SDK/MacOSX${MACOS_VERSION}.sdk" if ! [ -d "$_sdk" ]; then echo "Invalid MacOS version: $MACOS_VERSION" >&2 exit 1 fi # Gather all SDK libs _skd_libs="$( while IFS= read -r -d '' _lib; do _lib="${_lib#"${_sdk}/usr/lib/"}" _lib="${_lib%.*}" printf '%s.dylib\n' "$_lib" done < <(find "${_sdk}/usr/lib" \( -name '*.tbd' -o -name '*.dylib' \) -print0) \ | sort -u )" # Change cwd to the script directory (which should be ffmpeg source root) CDPATH='' cd -- "$(dirname -- "$0")" # Save FFmpeg version FFMPEG_VERSION="$(xargs printf '%s' "/${_framework}/Versions/Current/Resources/Info.plist" CFBundleDevelopmentRegion English CFBundleExecutable FFMpeg CFBundleGetInfoString FFMpeg ${FFMPEG_VERSION} CFBundleIdentifier com.spacedrive.ffmpeg CFBundleInfoDictionaryVersion 6.0 CFBundleName FFMpeg CFBundlePackageType FMWK CFBundleShortVersionString ${FFMPEG_VERSION} CFBundleSignature ???? CFBundleVersion ${FFMPEG_VERSION} EOF # Process FFMpeg libraries to be compatible with the Framework structure cd "$TARGET_DIR/lib" # Move all symlinks of ffmpeg libraries to Framework while IFS= read -r -d '' _lib; do # Copy symlinks to the output directory cp -Ppv "$_lib" "/${_framework}/Libraries/${_lib#./}" rm "$_lib" done < <(find . -type l -print0) # Populate queue with ffmpeg libraries set -- # Clear command line arguments while IFS= read -r -d '' _lib; do set -- "$@" "${_lib#./}" done < <(find . -name '*.dylib' -print0) # Copy all symlinks of libheif libraries to Framework while IFS= read -r -d '' _lib; do # Copy symlinks to the output directory cp -Ppv "$_lib" "/${_framework}/Libraries/${_lib#"${_macports_root}/lib/"}" done < <(find "${_macports_root}/lib" -type l \( -name 'libheif.*' -a -name '*.dylib' \) -print0) # Copy libheif to cwd and add it to queue while IFS= read -r -d '' _lib; do _lib_rel="${_lib#"${_macports_root}/lib/"}" cp -Lpv "$_lib" "./${_lib_rel}" set -- "$@" "${_lib_rel}" done < <(find "${_macports_root}/lib" -type f \( -name 'libheif.*' -a -name '*.dylib' \) -print0) while [ $# -gt 0 ]; do # Loop through each of the library's dependencies for _dep in $("${TRIPLE}-otool" -L "$1" | tail -n+2 | awk '{print $1}'); do case "$_dep" in # FFMpeg inter dependency "${TARGET_DIR}/lib/"*) _linker_path="@loader_path/${_dep#"${TARGET_DIR}/lib/"}" ;; # Macports dependency (/opt/local/lib means it was installed by Macports) /opt/local/lib/*) _dep_rel="${_dep#/opt/local/lib/}" # Check if the macports dependency is already included in the macOS SDK if [ -n "$(comm -12 <(printf "%s" "$_dep_rel") <(printf "%s" "$_skd_libs"))" ]; then # Relink libs already included in macOS SDK _linker_path="/usr/lib/${_dep_rel}" else _linker_path="@loader_path/${_dep_rel}" if ! [ -e "${_macports_root}/lib/${_dep_rel}" ]; then echo "Missing macports dependency: ${_dep_rel}" exit 1 elif ! { [ -f "$_dep_rel" ] || [ -e "/${_framework}/Libraries/${_dep_rel}" ]; }; then # Copy dependency to the current directory if this is the first time we see it cp -Lpv "${_macports_root}/lib/${_dep_rel}" "./${_dep_rel}" # Add it to the queue to have it's own dependencies processed set -- "$@" "$_dep_rel" fi fi ;; *) # Ignore system libraries continue ;; esac # Change the dependency linker path to make it compatible with an .app bundle "${TRIPLE}-install_name_tool" -change "$_dep" "$_linker_path" "$1" done # Update the library's own id "${TRIPLE}-install_name_tool" -id "@executable_path/../Frameworks/${_framework}/Libraries/${1}" "$1" # Copy the library to framework cp -Lpv "$1" "/${_framework}/Libraries/${1}" # Remove library from queue shift done # Copy all libheif headers to framework cp -av "${_macports_root}/include/libheif" "/${_framework}/Headers/" # Copy all FFMPEG headers to framework cp -av "${TARGET_DIR}/include/"* "/${_framework}/Headers/"