diff --git a/.github/workflows/nuget-static-graphics.yml b/.github/workflows/nuget-static-graphics.yml index 1609538..cdcc9c6 100644 --- a/.github/workflows/nuget-static-graphics.yml +++ b/.github/workflows/nuget-static-graphics.yml @@ -18,7 +18,7 @@ on: - "staticlink-avalonia-v*" env: - SKIASHARP_VERSION: "3.119.2" + SKIASHARP_VERSION: "2.88.9" ANGLE_BRANCH: "7151" DOTNET_ALPINE_IMAGE: mcr.microsoft.com/dotnet/sdk:10.0-alpine @@ -49,6 +49,9 @@ jobs: run: | sudo apt-get update sudo apt-get install -y clang lld llvm g++ ninja-build pkg-config libfontconfig1-dev libglib2.0-dev libgl1-mesa-dev libpci-dev libx11-dev libxcb1-dev libxext-dev + if [ "${{ matrix.target_cpu }}" = "arm64" ]; then + sudo apt-get install -y generate-ninja + fi - name: Build Linux static graphics libraries if: ${{ !startsWith(matrix.rid, 'linux-musl-') }} @@ -75,7 +78,7 @@ jobs: "$DOTNET_ALPINE_IMAGE" \ sh -lc ' set -e - apk add --no-cache bash ca-certificates git python3 py3-httplib2 py3-pysocks py3-six clang compiler-rt lld llvm g++ ninja pkgconf fontconfig-dev glib-dev mesa-dev libx11-dev libxcb-dev libxext-dev pciutils-dev linux-headers perl curl tar xz patch gcompat libc6-compat + apk add --no-cache bash ca-certificates git python3 py3-httplib2 py3-pysocks py3-six clang compiler-rt lld llvm g++ gn ninja pkgconf fontconfig-dev glib-dev mesa-dev libx11-dev libxcb-dev libxext-dev pciutils-dev linux-headers perl curl tar xz patch gcompat libc6-compat python3 - <<'"'"'PY'"'"' import pathlib import httplib2 @@ -215,12 +218,6 @@ jobs: - rid: osx-arm64 runner: macos-15 avalonia_version: 11.3.14 - - rid: osx-x64 - runner: macos-14 - avalonia_version: 12.0.3 - - rid: osx-arm64 - runner: macos-15 - avalonia_version: 12.0.3 runs-on: ${{ matrix.runner }} env: RID: ${{ matrix.rid }} @@ -317,7 +314,7 @@ jobs: - name: Pack NuGet package run: | dotnet pack NuGet/StaticGraphics/StaticLink.Avalonia.csproj -c Release -o artifacts/nuget - for version in 11.3.14 12.0.3; do + for version in 11.3.14; do mkdir -p External/NativeStatic/osx-x64/native External/NativeStatic/osx-arm64/native cp External/AvaloniaNative/native-avalonia-$version-osx-x64/* External/NativeStatic/osx-x64/native/ cp External/AvaloniaNative/native-avalonia-$version-osx-arm64/* External/NativeStatic/osx-arm64/native/ @@ -385,14 +382,6 @@ jobs: runner: macos-15 avalonia_version: 11.3.14 native_version: 11.3.14.1 - - rid: osx-x64 - runner: macos-14 - avalonia_version: 12.0.3 - native_version: 12.0.3.1 - - rid: osx-arm64 - runner: macos-15 - avalonia_version: 12.0.3 - native_version: 12.0.3.1 runs-on: ${{ matrix.runner }} steps: - uses: actions/checkout@v4 diff --git a/NuGet/StaticGraphics/README.md b/NuGet/StaticGraphics/README.md index ac21f9c..24eb70c 100644 --- a/NuGet/StaticGraphics/README.md +++ b/NuGet/StaticGraphics/README.md @@ -11,7 +11,7 @@ dotnet add package StaticLink.Avalonia Or add it manually: ```xml - + ``` For macOS, also reference `StaticLink.Avalonia.Native`. This package is macOS-only and must match your Avalonia version because it contains `libAvaloniaNative.a`. diff --git a/NuGet/StaticGraphics/StaticLink.Avalonia.csproj b/NuGet/StaticGraphics/StaticLink.Avalonia.csproj index 86394a3..7828336 100644 --- a/NuGet/StaticGraphics/StaticLink.Avalonia.csproj +++ b/NuGet/StaticGraphics/StaticLink.Avalonia.csproj @@ -6,7 +6,7 @@ false false StaticLink.Avalonia - 3.119.2-7151.10 + 2.88.9-7151.10 greepar greepar Static SkiaSharp, HarfBuzzSharp, and ANGLE libraries for Avalonia NativeAOT single-file publishing. @@ -19,7 +19,7 @@ - + diff --git a/README.md b/README.md index ac21f9c..24eb70c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ dotnet add package StaticLink.Avalonia Or add it manually: ```xml - + ``` For macOS, also reference `StaticLink.Avalonia.Native`. This package is macOS-only and must match your Avalonia version because it contains `libAvaloniaNative.a`. diff --git a/scripts/build-linux-static-graphics.sh b/scripts/build-linux-static-graphics.sh index 9a621ca..40da8be 100755 --- a/scripts/build-linux-static-graphics.sh +++ b/scripts/build-linux-static-graphics.sh @@ -6,7 +6,7 @@ WORK_DIR="${WORK_DIR:-$ROOT_DIR/External/NativeStatic/.work}" TARGET_CPU="${TARGET_CPU:-x64}" RID="${RID:-linux-$TARGET_CPU}" OUTPUT_DIR="${OUTPUT_DIR:-$ROOT_DIR/External/NativeStatic/$RID}" -SKIASHARP_VERSION="${SKIASHARP_VERSION:-3.119.2}" +SKIASHARP_VERSION="${SKIASHARP_VERSION:-2.88.9}" ANGLE_BRANCH="${ANGLE_BRANCH:-7151}" BUILD_JOBS="${BUILD_JOBS:-$(nproc)}" ANGLE_PATCH_DIR="${ANGLE_PATCH_DIR:-$ROOT_DIR/External/NativeStatic/patches}" @@ -20,7 +20,7 @@ Usage: scripts/build-linux-static-graphics.sh [skia|angle|all] Environment: WORK_DIR Source/build cache directory. Default: External/NativeStatic/.work OUTPUT_DIR Final static library directory. Default: External/NativeStatic/linux-$TARGET_CPU - SKIASHARP_VERSION SkiaSharp release branch version. Default: 3.119.2 + SKIASHARP_VERSION SkiaSharp release branch version. Default: 2.88.9 ANGLE_BRANCH ANGLE chromium branch. Default: 7151 TARGET_CPU GN target_cpu. Default: x64. Supported: x64, arm64 RID Output RID. Default: linux-$TARGET_CPU @@ -61,8 +61,10 @@ ensure_depot_tools() { else git -C "$depot_dir" pull --ff-only fi - if is_musl_rid; then + if is_musl_rid || [[ "$TARGET_CPU" == "arm64" ]]; then initialize_depot_tools_system_python "$depot_dir" + fi + if is_musl_rid; then patch_depot_tools_python_deps "$depot_dir" fi export PATH="$python_bin_dir:$depot_dir:$PATH" @@ -180,6 +182,45 @@ sync_skia_deps() { fi } +resolve_skia_gn() { + local skia_dir="$1" + if [[ -x "$skia_dir/bin/gn" ]] && "$skia_dir/bin/gn" --version >/dev/null 2>&1; then + echo "$skia_dir/bin/gn" + return 0 + fi + if [[ -x /usr/bin/gn ]] && /usr/bin/gn --version >/dev/null 2>&1; then + echo /usr/bin/gn + return 0 + fi + if command -v gn >/dev/null 2>&1; then + command -v gn + return 0 + fi + echo "Missing runnable gn. Install generate-ninja/gn or provide a runnable $skia_dir/bin/gn." >&2 + return 1 +} + +patch_skia_2889_compat() { + local skia_dir="$1" + local parse_color="$skia_dir/src/utils/SkParseColor.cpp" + if [[ -f "$parse_color" ]] && ! grep -q '#include ' "$parse_color"; then + python3 - "$parse_color" <<'PY' +from pathlib import Path +import sys + +path = Path(sys.argv[1]) +text = path.read_text() +if '#include ' not in text: + marker = '#include \n' + if marker in text: + text = text.replace(marker, marker + '#include \n', 1) + else: + text = '#include \n' + text + path.write_text(text) +PY + fi +} + build_skia() { ensure_tools ensure_depot_tools @@ -188,6 +229,7 @@ build_skia() { sync_skia_deps "$src" local skia_dir="$src/externals/skia" + patch_skia_2889_compat "$skia_dir" local out_dir="$skia_dir/out/linux-static-$TARGET_CPU" mkdir -p "$out_dir" "$OUTPUT_DIR" @@ -227,7 +269,9 @@ extra_cflags_cc = [ "-frtti" ] extra_ldflags = [ "-static-libstdc++", "-static-libgcc" ] EOF_ARGS - (cd "$skia_dir" && "$skia_dir/bin/gn" gen "$out_dir") + local gn_cmd + gn_cmd="$(resolve_skia_gn "$skia_dir")" + (cd "$skia_dir" && "$gn_cmd" gen "$out_dir") ninja -C "$out_dir" -j "$BUILD_JOBS" skia SkiaSharp HarfBuzzSharp copy_first_existing "$OUTPUT_DIR/libskia.a" \ @@ -268,9 +312,18 @@ build_angle() { prepend_python_module_path six prepare_angle_gcs_artifacts "$src" fi + if use_angle_nohooks_sync; then + prepare_angle_gcs_artifacts "$src" + fi prepare_musl_clang_runtime prepare_musl_libstdcxx_headers - gclient sync -f -D -R + if use_angle_nohooks_sync; then + gclient sync -f -D -R --nohooks + patch_angle_system_gn_compat "$src" + python3 build/util/lastchange.py -o build/util/LASTCHANGE + else + gclient sync -f -D -R + fi local out_dir="$src/out/linux-static-$TARGET_CPU" local angle_is_clang="false" @@ -316,6 +369,24 @@ apply_angle_patches() { local build_patch="$ANGLE_PATCH_DIR/angle-chromium-$ANGLE_BRANCH.patch" local deps_patch="$ANGLE_PATCH_DIR/angle-chromium-$ANGLE_BRANCH-deps.patch" + if ! grep -q 'not_needed(\["exec_script_allowlist"\])' "$src/.gn"; then + python3 - "$src/.gn" <<'PY' +from pathlib import Path +import sys + +path = Path(sys.argv[1]) +text = path.read_text() +needle = 'exec_script_allowlist = angle_dotfile_settings.exec_script_allowlist +\n' +if needle in text and 'not_needed(["exec_script_allowlist"])' not in text: + end = text.find('\n\n', text.find(needle)) + if end != -1: + text = text[:end] + '\nnot_needed(["exec_script_allowlist"])' + text[end:] + else: + text += '\nnot_needed(["exec_script_allowlist"])\n' + path.write_text(text) +PY + fi + if ! git -C "$src" grep -q 'angle_static_library("libANGLE_static")' -- BUILD.gn; then python3 - "$src/BUILD.gn" <<'PY' import pathlib @@ -380,6 +451,27 @@ download_angle_gcs_artifact() { fi } +use_angle_nohooks_sync() { + ! is_musl_rid && [[ "$TARGET_CPU" == "arm64" ]] +} + +patch_angle_system_gn_compat() { + local src="$1" + local siso_gni="$src/build/toolchain/siso.gni" + if [[ -f "$siso_gni" ]] && grep -q 'path_exists(' "$siso_gni"; then + python3 - "$siso_gni" <<'PY' +from pathlib import Path +import re +import sys + +path = Path(sys.argv[1]) +text = path.read_text() +text = re.sub(r'(?/dev/null 2>&1; then + echo "$skia_dir/bin/gn" + return 0 + fi + if command -v gn >/dev/null 2>&1; then + command -v gn + return 0 + fi + echo "Missing runnable gn. Install Homebrew gn or provide a runnable $skia_dir/bin/gn." >&2 + return 1 +} + +patch_skia_2889_compat() { + local skia_dir="$1" + local parse_color="$skia_dir/src/utils/SkParseColor.cpp" + if [[ -f "$parse_color" ]] && ! grep -q '#include ' "$parse_color"; then + python3 - "$parse_color" <<'PY' +from pathlib import Path +import sys + +path = Path(sys.argv[1]) +text = path.read_text() +if '#include ' not in text: + marker = '#include \n' + if marker in text: + text = text.replace(marker, marker + '#include \n', 1) + else: + text = '#include \n' + text + path.write_text(text) +PY + fi + + local zutil="$skia_dir/third_party/externals/zlib/zutil.h" + if [[ -f "$zutil" ]] && grep -q 'define fdopen(fd,mode) NULL' "$zutil"; then + python3 - "$zutil" <<'PY' +from pathlib import Path +import sys + +path = Path(sys.argv[1]) +text = path.read_text() +text = text.replace('# define fdopen(fd,mode) NULL /* No fdopen() */\n', '') +path.write_text(text) +PY + fi + + local pngpriv="$skia_dir/third_party/externals/libpng/pngpriv.h" + if [[ -f "$pngpriv" ]] && grep -q '# include ' "$pngpriv"; then + python3 - "$pngpriv" <<'PY' +from pathlib import Path +import sys + +path = Path(sys.argv[1]) +text = path.read_text() +text = text.replace('# include \n', '') +path.write_text(text) +PY + fi + if [[ -f "$pngpriv" ]] && ! grep -q '#include ' "$pngpriv"; then + python3 - "$pngpriv" <<'PY' +from pathlib import Path +import sys + +path = Path(sys.argv[1]) +text = path.read_text() +marker = '#include "png.h"\n' +if '#include ' not in text: + if marker in text: + text = text.replace(marker, marker + '#include \n', 1) + else: + text = '#include \n' + text + path.write_text(text) +PY + fi + + local pngc="$skia_dir/third_party/externals/libpng/png.c" + if [[ -f "$pngc" ]] && ! grep -q '#include ' "$pngc"; then + python3 - "$pngc" <<'PY' +from pathlib import Path +import sys + +path = Path(sys.argv[1]) +text = path.read_text() +marker = '#include "pngpriv.h"\n' +if '#include ' not in text: + if marker in text: + text = text.replace(marker, marker + '#include \n', 1) + else: + text = '#include \n' + text + path.write_text(text) +PY + fi +} + sync_skiasharp() { local src="$WORK_DIR/SkiaSharp-$SKIASHARP_VERSION" if [[ ! -d "$src/.git" ]]; then @@ -106,8 +201,15 @@ build_skia() { if [[ ! -x "$skia_dir/bin/gn" ]]; then sync_skia_deps "$skia_dir" fi + patch_skia_2889_compat "$skia_dir" local out_dir="$skia_dir/out/mac-static-$TARGET_CPU" + local mac_arch + case "$TARGET_CPU" in + x64) mac_arch="x86_64" ;; + arm64) mac_arch="arm64" ;; + *) echo "Unsupported macOS TARGET_CPU: $TARGET_CPU" >&2; exit 1 ;; + esac mkdir -p "$out_dir" "$OUTPUT_DIR" cat >"$out_dir/args.gn" <