Skip to content

Build and Release XCFramework #8

Build and Release XCFramework

Build and Release XCFramework #8

name: Build and Release XCFramework
on:
push:
branches: [ main ]
tags:
- 'v*' # This will trigger the workflow on any tag starting with 'v'
pull_request:
branches: [ main ]
workflow_dispatch:
inputs:
release_version:
description: 'Release version (must start with "v", e.g., v0.1.6)'
required: false
default: ''
env:
OUTPUT_DIR: ${{ github.workspace }}/output
jobs:
build:
runs-on: macos-latest
strategy:
matrix:
config:
- { sdk: 'macosx', arch: 'arm64', platform: 'MacOSX' }
- { sdk: 'macosx', arch: 'x86_64', platform: 'MacOSX' }
- { sdk: 'iphoneos', arch: 'arm64', platform: 'iPhoneOS' }
- { sdk: 'iphonesimulator', arch: 'x86_64', platform: 'iPhoneSimulator' }
- { sdk: 'iphonesimulator', arch: 'arm64', platform: 'iPhoneSimulator' }
steps:
- uses: actions/checkout@v4
- name: Cache build results
uses: actions/cache@v4
id: cache
with:
path: ${{ env.OUTPUT_DIR }}
key: ${{ runner.os }}-build-${{ matrix.config.sdk }}-${{ matrix.config.arch }}-${{ hashFiles('**/*.c', '**/*.cpp', '**/*.h', '**/*.m', '**/*.mm') }}
- name: Set up Xcode
if: steps.cache.outputs.cache-hit != 'true'
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: Install autotools
if: steps.cache.outputs.cache-hit != 'true'
run: brew install autoconf automake libtool
- name: Setup build environment
if: steps.cache.outputs.cache-hit != 'true'
run: |
aclocal && autoconf && automake --add-missing
mkdir -p "$OUTPUT_DIR"
- name: Build for ${{ matrix.config.sdk }} ${{ matrix.config.arch }}
if: steps.cache.outputs.cache-hit != 'true'
run: |
./.github/actions/build_library.sh ${{ matrix.config.sdk }} ${{ matrix.config.arch }} ${{ matrix.config.platform }}
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: build-${{ matrix.config.sdk }}-${{ matrix.config.arch }}
path: ${{ env.OUTPUT_DIR }}
retention-days: 1
create-xcframework:
needs: build
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Download all build artifacts
uses: actions/download-artifact@v4
with:
path: ${{ env.OUTPUT_DIR }}
- name: List downloaded artifacts
run: |
echo "Contents of OUTPUT_DIR:"
ls -R ${{ env.OUTPUT_DIR }}
- name: Create fat libraries using lipo
run: |
mkdir -p "${OUTPUT_DIR}/fat"
declare -A ARCHITECTURES=(
["macos"]="arm64 x86_64"
["iphoneos"]="arm64"
["iphonesimulator"]="x86_64 arm64"
)
LIBRARIES=("libopencore-amrnb" "libopencore-amrwb")
for lib in "${LIBRARIES[@]}"; do
# For macOS
lipo -create $(for arch in ${ARCHITECTURES["macos"]}; do echo "${OUTPUT_DIR}/build-macosx-${arch}/macosx-${arch}-MacOSX/lib/${lib}.a"; done) \
-output "${OUTPUT_DIR}/fat/${lib}-macos.a"
# For iOS device
cp "${OUTPUT_DIR}/build-iphoneos-arm64/iphoneos-arm64-iPhoneOS/lib/${lib}.a" "${OUTPUT_DIR}/fat/${lib}-iphoneos.a"
# For iOS simulator
lipo -create $(for arch in ${ARCHITECTURES["iphonesimulator"]}; do echo "${OUTPUT_DIR}/build-iphonesimulator-${arch}/iphonesimulator-${arch}-iPhoneSimulator/lib/${lib}.a"; done) \
-output "${OUTPUT_DIR}/fat/${lib}-iphonesimulator.a"
done
- name: Create XCFrameworks
run: |
mkdir -p "${OUTPUT_DIR}/Headers/"
# For opencore-amrnb
rm -rf ${OUTPUT_DIR}/Headers/*
rm -rf ${OUTPUT_DIR}/opencore-amrnb.xcframework
cp -a amrnb/{interf_dec,interf_enc}.h ${OUTPUT_DIR}/Headers/
xcodebuild -create-xcframework \
-library ${OUTPUT_DIR}/fat/libopencore-amrnb-macos.a -headers ${OUTPUT_DIR}/Headers \
-library ${OUTPUT_DIR}/fat/libopencore-amrnb-iphoneos.a -headers ${OUTPUT_DIR}/Headers \
-library ${OUTPUT_DIR}/fat/libopencore-amrnb-iphonesimulator.a -headers ${OUTPUT_DIR}/Headers \
-output ${OUTPUT_DIR}/opencore-amrnb.xcframework
# For opencore-amrwb
rm -rf ${OUTPUT_DIR}/Headers/*
rm -rf ${OUTPUT_DIR}/opencore-amrwb.xcframework
cp -a amrwb/{dec_if,if_rom}.h ${OUTPUT_DIR}/Headers/
xcodebuild -create-xcframework \
-library ${OUTPUT_DIR}/fat/libopencore-amrwb-macos.a -headers ${OUTPUT_DIR}/Headers \
-library ${OUTPUT_DIR}/fat/libopencore-amrwb-iphoneos.a -headers ${OUTPUT_DIR}/Headers \
-library ${OUTPUT_DIR}/fat/libopencore-amrwb-iphonesimulator.a -headers ${OUTPUT_DIR}/Headers \
-output ${OUTPUT_DIR}/opencore-amrwb.xcframework
- name: Zip XCFrameworks
run: |
cd ${{ env.OUTPUT_DIR }}
for framework in *.xcframework; do
zip -r "${framework%.xcframework}.xcframework.zip" "$framework"
done
ls -la
- name: Upload XCFrameworks
uses: actions/upload-artifact@v4
with:
name: XCFrameworks
path: ${{ env.OUTPUT_DIR }}/*.xcframework.zip
if-no-files-found: error
release:
needs: create-xcframework
runs-on: ubuntu-latest
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
steps:
- name: Download XCFrameworks
uses: actions/download-artifact@v4
with:
name: XCFrameworks
- name: Determine Release Version
id: version
run: |
if [[ $GITHUB_REF == refs/tags/* ]]; then
VERSION=${GITHUB_REF#refs/tags/}
elif [[ "${{ github.event.inputs.release_version }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
VERSION=${{ github.event.inputs.release_version }}
else
echo "Error: Invalid version format. Must start with 'v' followed by semantic versioning."
exit 1
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Create Release and Upload XCFrameworks
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.version.outputs.version }}
name: Release ${{ steps.version.outputs.version }}
draft: false
prerelease: false
generate_release_notes: true
fail_on_unmatched_files: true
files: |
*.xcframework.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Check Release
run: |
echo "Checking release ${{ steps.version.outputs.version }}"
release_info=$(curl -sS -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
https://api.github.com/repos/${{ github.repository }}/releases/tags/${{ steps.version.outputs.version }})
echo "Release info:"
echo "$release_info" | jq '.'
assets=$(echo "$release_info" | jq -r '.assets[].name')
echo "Release assets:"
echo "$assets"