diff --git a/.github/workflows/release-libpdfium.yml b/.github/workflows/release-libpdfium.yml index 894acfa12..059493d99 100644 --- a/.github/workflows/release-libpdfium.yml +++ b/.github/workflows/release-libpdfium.yml @@ -14,7 +14,7 @@ on: default: false permissions: - contents: read + contents: write jobs: source-tests: @@ -57,15 +57,27 @@ jobs: fail-fast: false matrix: include: + # Linux & Wasm - { target: linux-x64, runner: ubuntu-24.04 } - { target: linux-arm64, runner: ubuntu-24.04 } - { target: linuxmusl-x64, runner: ubuntu-24.04 } - { target: linuxmusl-arm64, runner: ubuntu-24.04 } - { target: wasm32, runner: ubuntu-24.04 } + # Darwin (macOS) - { target: darwin-arm64, runner: macos-15 } - { target: darwin-x64, runner: macos-15 } + # Windows - { target: win32-x64, runner: windows-2022 } - { target: win32-arm64, runner: windows-2022 } + # Android + - { target: arm64-v8a, runner: ubuntu-24.04 } + - { target: armeabi-v7a, runner: ubuntu-24.04 } + - { target: x86, runner: ubuntu-24.04 } + - { target: x86_64, runner: ubuntu-24.04 } + # iOS + - { target: ios-arm64, runner: macos-15 } + - { target: ios-simulator-arm64, runner: macos-15 } + - { target: ios-simulator-x64, runner: macos-15 } env: DEPOT_TOOLS_WIN_TOOLCHAIN: 0 EMSDK_VERSION: 3.1.72 @@ -132,7 +144,7 @@ jobs: - name: Select Xcode if: runner.os == 'macOS' shell: bash - run: sudo xcode-select -s "/Applications/Xcode_26.0.app" + run: sudo xcode-select -s "/Applications/Xcode_16.1.app" - name: Install Windows deps if: runner.os == 'Windows' shell: pwsh @@ -161,10 +173,64 @@ jobs: name: libembedpdf-pdf-runtime-${{ matrix.target }} path: out/embedpdf-runtime-artifacts/*.tar.gz + ios-universal: + name: Build ios-arm64_x86_64-simulator + needs: build + runs-on: macos-15 + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ inputs.ref || github.ref_name }} + - uses: actions/download-artifact@v6 + with: + name: libembedpdf-pdf-runtime-ios-simulator-arm64 + path: artifacts/ios-simulator-arm64 + - uses: actions/download-artifact@v6 + with: + name: libembedpdf-pdf-runtime-ios-simulator-x64 + path: artifacts/ios-simulator-x64 + - name: Combine iOS simulator libraries + shell: bash + run: | + mkdir -p out/ios-universal/lib + + # Unpack + mkdir -p staging/arm64 staging/x64 + tar -xzf artifacts/ios-simulator-arm64/*.tar.gz -C staging/arm64 + tar -xzf artifacts/ios-simulator-x64/*.tar.gz -C staging/x64 + + # Combine with lipo + lipo -create staging/arm64/lib/libpdfium.a staging/x64/lib/libpdfium.a -output out/ios-universal/lib/libpdfium.a + + # Copy headers and other files from one of them + mkdir -p out/ios-universal/include out/ios-universal/LICENSES + cp -R staging/arm64/include/. out/ios-universal/include/ + cp -R staging/arm64/LICENSES/. out/ios-universal/LICENSES/ + cp staging/arm64/args.gn out/ios-universal/args.gn + + # Write metadata + cat > out/ios-universal/BUILD-METADATA.json <&2 exit 1 diff --git a/scripts/embedpdf-runtime/build-target.sh b/scripts/embedpdf-runtime/build-target.sh index 032663536..dd1b305ef 100755 --- a/scripts/embedpdf-runtime/build-target.sh +++ b/scripts/embedpdf-runtime/build-target.sh @@ -57,6 +57,44 @@ case "$TARGET" in GN_TARGET_CPU="arm64" PDF_IS_COMPLETE_LIB=false ;; + android-arm64 | arm64-v8a) + GN_TARGET_OS="android" + GN_TARGET_CPU="arm64" + PDF_IS_COMPLETE_LIB=false + ;; + android-arm | armeabi-v7a) + GN_TARGET_OS="android" + GN_TARGET_CPU="arm" + PDF_IS_COMPLETE_LIB=false + ;; + android-x64 | x86_64) + GN_TARGET_OS="android" + GN_TARGET_CPU="x64" + PDF_IS_COMPLETE_LIB=false + ;; + android-x86 | x86) + GN_TARGET_OS="android" + GN_TARGET_CPU="x86" + PDF_IS_COMPLETE_LIB=false + ;; + ios-arm64) + GN_TARGET_OS="ios" + GN_TARGET_CPU="arm64" + PDF_IS_COMPLETE_LIB=true + EXTRA_ARGS=$'\nios_enable_code_signing=false\ntarget_environment="device"' + ;; + ios-simulator-arm64) + GN_TARGET_OS="ios" + GN_TARGET_CPU="arm64" + PDF_IS_COMPLETE_LIB=true + EXTRA_ARGS=$'\nios_enable_code_signing=false\nuse_ios_simulator=true\ntarget_environment="simulator"' + ;; + ios-simulator-x64) + GN_TARGET_OS="ios" + GN_TARGET_CPU="x64" + PDF_IS_COMPLETE_LIB=true + EXTRA_ARGS=$'\nios_enable_code_signing=false\nuse_ios_simulator=true\ntarget_environment="simulator"' + ;; *) echo "unknown target: $TARGET" >&2 exit 1 @@ -68,12 +106,22 @@ PDF_RUNTIME_TARGET_OS_LIST="${PDF_RUNTIME_TARGET_OS_LIST:-$GN_TARGET_OS}" \ "$SOURCE_DIR/scripts/embedpdf-runtime/apply-patches.sh" "$TARGET" -if [[ "$TARGET" == linux-* ]]; then - ( - cd "$SOURCE_DIR" - build/install-build-deps.sh --no-prompt - build/linux/sysroot_scripts/install-sysroot.py "--arch=$GN_TARGET_CPU" - ) +if [[ "$(uname)" == "Linux" ]]; then + if [[ "$TARGET" == linux-* || "$TARGET" == android-* || "$TARGET" == arm64-v8a || "$TARGET" == armeabi-v7a || "$TARGET" == x86 || "$TARGET" == x86_64 ]]; then + ( + cd "$SOURCE_DIR" + if [[ "$TARGET" == android-* || "$TARGET" == arm64-v8a || "$TARGET" == armeabi-v7a || "$TARGET" == x86 || "$TARGET" == x86_64 ]]; then + # For android, we might need --android but it's often slow and interactive. + # Most runners have what's needed. Let's try without --android first but keep the base linux deps. + build/install-build-deps.sh --no-prompt --no-arm --no-chromeos-fonts + else + build/install-build-deps.sh --no-prompt + fi + if [[ "$GN_TARGET_OS" == "linux" ]]; then + build/linux/sysroot_scripts/install-sysroot.py "--arch=$GN_TARGET_CPU" + fi + ) + fi fi OUT="$SOURCE_DIR/out/embedpdf-runtime/$TARGET" diff --git a/scripts/embedpdf-runtime/package-ios-simulator-universal.sh b/scripts/embedpdf-runtime/package-ios-simulator-universal.sh new file mode 100755 index 000000000..17798573c --- /dev/null +++ b/scripts/embedpdf-runtime/package-ios-simulator-universal.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +set -euo pipefail + +SOURCE_DIR="${PDF_RUNTIME_SOURCE_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}" +ARTIFACT_DIR="${PDF_RUNTIME_ARTIFACT_DIR:-$SOURCE_DIR/out/embedpdf-runtime-artifacts}" + +# This script combines ios-simulator-arm64 and ios-simulator-x64 into a single +# universal library and packages it. It expects that both targets have already +# been built and packaged with package-target.sh. + +STAGING="$SOURCE_DIR/out/embedpdf-runtime-staging/ios-simulator-universal" +mkdir -p "$STAGING" + +# Find the latest artifacts for both targets +ARM64_ARTIFACT=$(ls -t "$ARTIFACT_DIR"/libembedpdf-pdf-runtime-ios-simulator-arm64-*.tar.gz 2>/dev/null | head -n 1 || true) +X64_ARTIFACT=$(ls -t "$ARTIFACT_DIR"/libembedpdf-pdf-runtime-ios-simulator-x64-*.tar.gz 2>/dev/null | head -n 1 || true) + +if [[ -z "$ARM64_ARTIFACT" || -z "$X64_ARTIFACT" ]]; then + echo "Error: Missing required artifacts for ios-simulator-arm64 and/or ios-simulator-x64" >&2 + exit 1 +fi + +echo "Combining artifacts:" +echo " $ARM64_ARTIFACT" +echo " $X64_ARTIFACT" + +TMP_ARM64="$STAGING/arm64" +TMP_X64="$STAGING/x64" +mkdir -p "$TMP_ARM64" "$TMP_X64" + +tar -xzf "$ARM64_ARTIFACT" -C "$TMP_ARM64" +tar -xzf "$X64_ARTIFACT" -C "$TMP_X64" + +# Combine with lipo +mkdir -p "$STAGING/lib" +lipo -create "$TMP_ARM64/lib/libpdfium.a" "$TMP_X64/lib/libpdfium.a" -output "$STAGING/lib/libpdfium.a" + +# Copy headers and other metadata from arm64 (they should be identical) +cp -R "$TMP_ARM64/include" "$STAGING/include" +cp "$TMP_ARM64/args.gn" "$STAGING/args.gn" +if [[ -d "$TMP_ARM64/LICENSES" ]]; then + cp -R "$TMP_ARM64/LICENSES" "$STAGING/LICENSES" +fi + +# Write metadata +cat > "$STAGING/BUILD-METADATA.json" <&2 + echo "test-target.sh only supports host-native and cross-buildable targets: darwin-arm64, darwin-x64, linux-x64, linux-arm64, android-*, ios-*" >&2 exit 1 ;; esac @@ -47,11 +78,19 @@ PDF_RUNTIME_TARGET_OS_LIST="${PDF_RUNTIME_TARGET_OS_LIST:-$GN_TARGET_OS}" \ "$SOURCE_DIR/scripts/embedpdf-runtime/apply-patches.sh" "$TARGET" -if [[ "$TARGET" == linux-* ]]; then +if [[ "$TARGET" == linux-* || "$TARGET" == android-* || "$TARGET" == arm64-v8a || "$TARGET" == armeabi-v7a || "$TARGET" == x86 || "$TARGET" == x86_64 ]]; then ( cd "$SOURCE_DIR" - build/install-build-deps.sh --no-prompt - build/linux/sysroot_scripts/install-sysroot.py "--arch=$GN_TARGET_CPU" + if [[ "$TARGET" == android-* || "$TARGET" == arm64-v8a || "$TARGET" == armeabi-v7a || "$TARGET" == x86 || "$TARGET" == x86_64 ]]; then + # For android, we might need --android but it's often slow and interactive. + # Most runners have what's needed. Let's try without --android first but keep the base linux deps. + build/install-build-deps.sh --no-prompt --no-arm --no-chromeos-fonts + else + build/install-build-deps.sh --no-prompt + fi + if [[ "$GN_TARGET_OS" == "linux" ]]; then + build/linux/sysroot_scripts/install-sysroot.py "--arch=$GN_TARGET_CPU" + fi ) fi @@ -114,6 +153,12 @@ run_gtest() { cmd+=("${extra_gtest_args[@]}") fi + if [[ "$GN_TARGET_OS" == "android" || "$GN_TARGET_OS" == "ios" ]]; then + echo "=== building $binary (execution skipped on $GN_TARGET_OS) ===" + # We already built it with ninja, so we just exit here. + return 0 + fi + echo "=== running $binary ===" "${cmd[@]}" 2>&1 | tee "$log" } diff --git a/scripts/embedpdf-runtime/unapply-patches.sh b/scripts/embedpdf-runtime/unapply-patches.sh index db023858b..4ec5d0972 100755 --- a/scripts/embedpdf-runtime/unapply-patches.sh +++ b/scripts/embedpdf-runtime/unapply-patches.sh @@ -65,6 +65,8 @@ reverse_patch_file "$SOURCE_DIR/build" "$PATCH_DIR/win/build.patch" reverse_patch_file "$SOURCE_DIR/build" "$PATCH_DIR/mac/build.patch" reverse_patch_file "$SOURCE_DIR/build" "$PATCH_DIR/wasm/build.patch" reverse_patch_file "$SOURCE_DIR/build" "$PATCH_DIR/musl/build.patch" +reverse_patch_file "$SOURCE_DIR/build" "$PATCH_DIR/android/build.patch" +reverse_patch_file "$SOURCE_DIR/third_party/libjpeg_turbo" "$PATCH_DIR/ios/libjpeg_turbo.patch" reverse_patch_file "$SOURCE_DIR" "$PATCH_DIR/musl/pdfium.patch" reverse_patch_file "$SOURCE_DIR" "$PATCH_DIR/shared-library.patch" diff --git a/testing/test.gni b/testing/test.gni index 6ad2c2d4a..25d500ec9 100644 --- a/testing/test.gni +++ b/testing/test.gni @@ -11,6 +11,10 @@ # Variable: # use_raw_android_executable: Use executable() rather than android_apk(). # use_native_activity: Test implements ANativeActivity_onCreate(). +declare_args() { + ios_automatically_manage_certs = true +} + template("test") { if (is_android) { import("//build/config/android/config.gni")