Isolate manual artifact validation without package publication

This commit is contained in:
geruipu committed 2026-10-05 13:09:17 +08:00
1 parent 98976747c3
commit d02f1f0b55
75 files changed
+3895 -634

No files matched your search

+60
View File
@@ -0,0 +1,60 @@
# Zig cross compilation for SkiaSharp 3 / 4
All nine native targets use Zig 0.14.1 from Linux: linux-x64, linux-arm64,
linux-musl-x64, linux-musl-arm64, win-x64, win-x86, win-arm64, osx-x64, osx-arm64.
Windows uses the GNU ABI, without MSVC. macOS uses a checksum-pinned real SDK,
without Xcode. AvaloniaNative 11/12 also compiles with Zig on Linux.
## Local evidence (2026-10-04)
| Check | Result |
| --- | --- |
| 3.119.2, 3.119.4, 4.150.3, 4.150.5, 4.153.1 × nine GN configurations | 45 passed; these are configuration checks |
| All five versions, Windows x64 Skia/SkiaSharp/HarfBuzz compilation and executable link | Passed |
| 3.119.4 Windows x86 Skia and stdcall thunks | Compilation and raster/EGL links passed; fixed ANGLE archives reused |
| 3.119.4 Linux x64 | All six archives and both links passed; raster/UTF-8 execution passed |
| 3.119.4 Linux ARM64 | Three Skia archives and raster link passed; raster/UTF-8 execution passed under QEMU |
| 4.153.1 macOS ARM64 | Three Skia archives and raster executable link passed |
| AvaloniaNative 11.3.14 / 12.1.0, both macOS architectures | Four full compilations and SDK libc++ executable links passed |
Exact scope is recorded in `recent-version-validation.json`. Earlier baseline
results are retained separately. The raster probe checks 64 pixels and UTF-8
buffer ingestion; it does not prove complete font shaping or GPU operation.
There is no local Docker daemon or Windows/macOS runtime. The complete Debian
image, five releases × nine full builds, NativeAOT consumer applications and
actual Actions/NuGet publication have not been verified locally. Local builds
used the Linux host and pinned cross tools, not a running Debian container.
## Repeatable inputs and failure policy
`Dockerfile` pins Debian 12 by digest, apt by snapshot and depot_tools by commit.
`Dockerfile.cross-probe` is the production cross image despite its historical
name. It pins Zig, the macOS SDK, WinRT headers, availability runtime and Linux
sysroot packages by checksum. SDK extraction supports pinned Debian Python 3.11.
`zig-toolchain-image.yml` builds/reuses GHCR images by recipe digest and passes
an immutable image digest to downstream builds. Repository package write
permission is required. Source profiles pin SkiaSharp, Skia and ANGLE commits.
The existing exact per-target source/build cache has no fallback restores;
ccache additionally checks compiler contents. Cold downloads remain necessary.
`build-cross.py` adapts declared GN capabilities, rejects unknown compiler flags,
checks static targets, builds six archives and links raster and EGL/GLES probes.
`package-zig.py` requires archive hashes and successful links before packaging.
Windows x86 gets generated stdcall thunks. Captured Zig runtime libraries are
included for consumer linking. A successful C link does not establish NativeAOT
compatibility; the release workflow gates publication on consumer OS tests.
## Run
Use the `zig-recent-regression` manual Action for recent-version full matrices.
Use `static-graphics-zig-cross-debian12` for one pinned release and nine RIDs.
For already synced sources, run `build/linux-toolchain/build-cross.py --help`;
`--configure-only` configures without compiling, while `--component skia` checks
only the three Skia libraries and their executable link.
This common driver supports the tested source revisions. Future compiler,
SDK, GN or source changes can still require deliberate updates. Daily releases
fail closed and publish only after all required jobs pass. SkiaSharp 2 is frozen
and excluded from the new regression/release tracks.
+36
View File
@@ -0,0 +1,36 @@
# Multi-architecture index; deliberately update together with the snapshot/cache key.
FROM debian:bookworm-slim@sha256:3783cc01769c7b2b1b83a5c5ad96c815348e28ed7da68e2e3687004faa906251
ARG DEBIAN_SNAPSHOT=20260901T000000Z
ARG DEPOT_TOOLS_REVISION=8a5434051036b32412a2ecb10c213a72e3f3ccb9
ENV DEBIAN_FRONTEND=noninteractive \
DEPOT_TOOLS_UPDATE=0 \
DEPOT_TOOLS_REVISION=${DEPOT_TOOLS_REVISION} \
LLVM_AR=llvm-ar-16 \
BUILD_JOBS=4
# HTTP bootstrap uses Debian's signed Release metadata. Do not disable signature checks.
RUN rm -f /etc/apt/sources.list.d/debian.sources \
&& printf 'deb [check-valid-until=no] http://snapshot.debian.org/archive/debian/%s bookworm main\ndeb [check-valid-until=no] http://snapshot.debian.org/archive/debian-security/%s bookworm-security main\n' "$DEBIAN_SNAPSHOT" "$DEBIAN_SNAPSHOT" > /etc/apt/sources.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates git curl python3 python3-six python3-requests python3-httplib2 \
build-essential ccache clang-16 lld-16 llvm-16 libclang-rt-16-dev ninja-build \
pkg-config cmake binutils file unzip xz-utils bzip2 patch \
libfontconfig1-dev libglib2.0-dev libgl1-mesa-dev libpci-dev \
libx11-dev libxcb1-dev libxext-dev libwayland-dev libexpat1-dev libicu72 libssl3 \
&& for tool in clang clang++ llvm-ar llvm-ranlib llvm-nm; do \
ln -s "/usr/bin/$tool-16" "/usr/local/bin/$tool"; \
done \
&& mkdir -p /opt/staticlink \
&& dpkg-query -W > /opt/staticlink/packages.lock \
&& rm -rf /var/lib/apt/lists/*
# Store the pinned checkout inside the image so the runner never selects depot_tools HEAD.
RUN git init /opt/depot_tools \
&& git -C /opt/depot_tools remote add origin https://chromium.googlesource.com/chromium/tools/depot_tools.git \
&& git -C /opt/depot_tools fetch --depth 1 origin "$DEPOT_TOOLS_REVISION" \
&& git -C /opt/depot_tools checkout --detach FETCH_HEAD
ENV DEPOT_TOOLS_DIR=/opt/depot_tools
WORKDIR /src
CMD ["bash"]
@@ -0,0 +1,57 @@
# Build this local base from Dockerfile first; it contains the pinned Debian toolchain.
ARG TOOLCHAIN_IMAGE=staticlink-debian12:probe-base
FROM mcr.microsoft.com/dotnet/sdk:10.0.302@sha256:72dd743782f2ae7e5476fd64f6a460045e3998dc862218b80e6944cba79a01b0 AS dotnet10
FROM mcr.microsoft.com/dotnet/sdk:8.0.416@sha256:8b5eece40d8a8050c09332eab1e65563fd4c928c5881e9e72bca7a4b0339f881 AS dotnet8
FROM ${TOOLCHAIN_IMAGE}
ARG TARGETARCH
RUN case "$TARGETARCH" in \
amd64) zig_arch=x86_64; zig_sha=24aeeec8af16c381934a6cd7d95c807a8cb2cf7df9fa40d359aa884195c4716c ;; \
arm64) zig_arch=aarch64; zig_sha=f7a654acc967864f7a050ddacfaa778c7504a0eca8d2b678839c21eea47c992b ;; \
*) echo "Unsupported host architecture: $TARGETARCH" >&2; exit 1 ;; \
esac \
&& curl --fail --location --retry 3 \
"https://ziglang.org/download/0.14.1/zig-$zig_arch-linux-0.14.1.tar.xz" -o /tmp/zig.tar.xz \
&& printf '%s /tmp/zig.tar.xz\n' "$zig_sha" | sha256sum --check \
&& mkdir /opt/zig \
&& tar -xJf /tmp/zig.tar.xz -C /opt/zig --strip-components=1 \
&& ln -s /opt/zig/zig /usr/local/bin/zig \
&& rm /tmp/zig.tar.xz
ARG MACOS_SDK_SHA256=c15cf0f3f17d714d1aa5a642da8e118db53d79429eb015771ba816aa7c6c1cbd
# Architecture-independent MinGW WinRT headers supplement Zig's SDK. Extract
# files only: do not install Ubuntu binaries or change Debian package resolution.
RUN curl --fail --location --retry 3 \
https://snapshot.ubuntu.com/ubuntu/20260828T000000Z/pool/universe/m/mingw-w64/mingw-w64-common_11.0.1-3build1_all.deb \
-o /tmp/mingw.deb \
&& printf '%s /tmp/mingw.deb\n' \
4a42fd30fbc3838c58c929d8a4882682fc12408bb7a0e6cafa913c0f0a57c187 | sha256sum --check \
&& mkdir /opt/mingw && dpkg-deb --extract /tmp/mingw.deb /opt/mingw \
&& rm /tmp/mingw.deb
RUN curl --fail --location --retry 3 \
https://github.com/joseluisq/macosx-sdks/releases/download/15.5/MacOSX15.5.sdk.tar.xz \
-o /tmp/macos-sdk.tar.xz \
&& printf '%s /tmp/macos-sdk.tar.xz\n' "$MACOS_SDK_SHA256" | sha256sum --check \
&& mkdir /opt/macos-sdk \
&& tar -xJf /tmp/macos-sdk.tar.xz -C /opt/macos-sdk \
&& rm /tmp/macos-sdk.tar.xz
RUN mkdir -p /opt/staticlink \
&& curl --fail --location --retry 3 \
https://raw.githubusercontent.com/llvm/llvm-project/llvmorg-19.1.7/compiler-rt/lib/builtins/os_version_check.c \
-o /opt/staticlink/os_version_check.c \
&& printf '%s /opt/staticlink/os_version_check.c\n' \
bc0b9f10e8d1a1ac5905d710f1c9fead23878e31233748d580393edc4e3bfc18 | sha256sum --check
COPY *.py smoke-*.c sources.lock.json cross-toolchain.lock.json *.gn.in /opt/staticlink/
COPY patches/ /opt/staticlink/patches/
COPY versions/ /opt/staticlink/versions/
ENTRYPOINT ["python3", "/opt/staticlink/probe-cross.py"]
COPY --from=dotnet8 /usr/share/dotnet /opt/dotnet
COPY --from=dotnet10 /usr/share/dotnet /opt/dotnet
ENV DOTNET_ROOT=/opt/dotnet PATH=/opt/dotnet:${PATH}
COPY fetch-linux-sysroots.py linux-sysroots*.lock.json /opt/staticlink/
RUN python3 /opt/staticlink/fetch-linux-sysroots.py --output /opt/sysroots \
--locks /opt/staticlink/linux-sysroots.lock.json /opt/staticlink/linux-sysroots-musl.lock.json
+20
View File
@@ -0,0 +1,20 @@
# Debian 12 Zig cross toolchain
The production native-build path is the pinned Debian 12 image plus Zig 0.14.1,
covering all nine GNU Linux, musl Linux, Windows and macOS targets. musl uses
checksum-locked target sysroots inside the same Debian image.
Read [CROSS-COMPILE.md](CROSS-COMPILE.md) for current build commands, exact local
validation scope and remaining Docker/runtime/NativeAOT verification. Read
[DAILY-RELEASE.md](../../DAILY-RELEASE.md) for daily 3/4 release configuration.
`Dockerfile` pins the base digest, apt snapshot and source-preparation tools.
`Dockerfile.cross-probe` adds Zig, macOS SDK, Windows headers, target Linux SDKs
and .NET SDKs. The historical filename is retained for existing references.
`zig-toolchain-image.yml` reuses recipe-tagged GHCR images and downstream jobs
pull their immutable digest. Source locks and archive/link manifests provide
traceability. No complete local Docker image build has been run.
Legacy platform helper scripts are retained for reference; production graphics
Actions now delegate to the common Zig cross-build workflow. SkiaSharp 2 remains
outside the new daily tracks.
+23
View File
@@ -0,0 +1,23 @@
target_os = "linux"
target_cpu = "@CPU@"
is_debug = false
is_component_build = false
is_clang = true
treat_warnings_as_errors = false
use_custom_libcxx = false
use_custom_libcxx_for_host = false
use_sysroot = false
use_lld = false
use_thin_lto = false
symbol_level = 0
angle_build_tests = false
build_angle_deqp_tests = false
angle_enable_swiftshader = false
angle_enable_vulkan = false
angle_enable_wgpu = false
clang_use_chrome_plugins = false
enable_rust = false
clang_version = "19"
# Chromium UI/ATK is not part of the standalone ANGLE library targets.
use_glib = false
+21
View File
@@ -0,0 +1,21 @@
target_os = "mac"
target_cpu = "@CPU@"
is_debug = false
is_component_build = false
is_clang = true
treat_warnings_as_errors = false
use_custom_libcxx = false
use_custom_libcxx_for_host = false
use_sysroot = false
use_lld = false
use_thin_lto = false
symbol_level = 0
angle_build_tests = false
build_angle_deqp_tests = false
angle_enable_swiftshader = false
angle_enable_vulkan = false
angle_enable_wgpu = false
clang_use_chrome_plugins = false
enable_rust = false
use_system_xcode = true
clang_version = "19"
+25
View File
@@ -0,0 +1,25 @@
target_os = "win"
target_cpu = "@CPU@"
is_debug = false
is_component_build = false
is_clang = true
treat_warnings_as_errors = false
use_custom_libcxx = false
use_custom_libcxx_for_host = false
use_sysroot = false
use_lld = false
use_thin_lto = false
symbol_level = 0
angle_build_tests = false
build_angle_deqp_tests = false
angle_enable_swiftshader = false
angle_enable_vulkan = false
angle_enable_wgpu = false
clang_use_chrome_plugins = false
enable_rust = false
visual_studio_version = "2022"
windows_sdk_version = "10.0.22621.0"
clang_version = "19"
use_clang_modules = false
angle_copy_compiler_dll = false
@@ -0,0 +1,43 @@
#!/usr/bin/env python3
"""Build Avalonia's pinned macOS native sources with Zig on Linux."""
import argparse,subprocess,re,json,os,hashlib
from pathlib import Path
p=argparse.ArgumentParser();p.add_argument('--source',type=Path,required=True);p.add_argument('--rid',choices=['osx-x64','osx-arm64'],required=True);p.add_argument('--sdk',type=Path,required=True);p.add_argument('--zig',default='zig');p.add_argument('--output',type=Path,required=True);p.add_argument('--work',type=Path,required=True);a=p.parse_args()
a.source=a.source.resolve();a.output=a.output.resolve();a.work=a.work.resolve();a.output.mkdir(parents=True,exist_ok=True);a.work.mkdir(parents=True,exist_ok=True)
repo=Path(__file__).resolve().parents[2]
tools=a.work/'tools'
subprocess.run(['python3',str(repo/'build/linux-toolchain/zig-cross.py'),'--zig',a.zig,'--target',a.rid,'--sdk',str(a.sdk),'--output',str(tools)],check=True)
descriptor=tools/'toolchain.json'
config=json.loads(descriptor.read_text());config['target']=config['target'].split('-macos.')[0]+'-macos.12.0.0';descriptor.write_text(json.dumps(config,indent=2)+'\n')
native=a.source/'native/Avalonia.Native';project=native/'src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj'
headers=native/'inc'
if not (headers/'avalonia-native.h').is_file():
header_project=native/'Avalonia.Native.macOS.proj'
if header_project.is_file():
subprocess.run(['dotnet','build',str(header_project),'-t:GenerateMicroComItems'],cwd=a.source,check=True)
else:
subprocess.run(['bash',str(native/'generate-headers.sh')],cwd=a.source,check=True)
# Match the authoritative Xcode Sources build phases, rather than guessing every .mm in the repo.
project_text=project.read_text()
names=set(re.findall(r'/\* (.+?\.(?:mm|m|cpp|cc|c)) in Sources \*/',project_text))
file_flags={}
for name,flags in re.findall(r'/\* (.+?\.(?:mm|m|cpp|cc|c)) in Sources \*/[^\n]*COMPILER_FLAGS = \"([^\"]+)\"',project_text):
import shlex
file_flags[name]=shlex.split(flags)
if not names:raise SystemExit('No authoritative Xcode source list found')
objects=[];source_hashes={}
for name in sorted(names):
matches=list(native.rglob(name))
if len(matches)!=1:raise SystemExit('Ambiguous or missing Xcode source '+name+': '+str(matches))
source=matches[0];obj=a.work/(hashlib.sha256(str(source.relative_to(native)).encode()).hexdigest()+'.o')
command=[str(tools/('cc' if source.suffix in ('.c','.m') else 'cxx')),'-O2','-fPIC','-fblocks','-mmacosx-version-min=12.0','-I'+str(headers),'-I'+str(native/'src/OSX'),'-I'+str(native/'src'),'-c',str(source),'-o',str(obj)]
if source.suffix in ('.mm','.m'):command+=['-fobjc-arc']
if source.suffix in ('.mm','.cpp','.cc'):command+=['-std=c++17']
command+=file_flags.get(name,[])
subprocess.run(command,check=True);objects.append(obj);source_hashes[str(source.relative_to(native))]=hashlib.sha256(source.read_bytes()).hexdigest()
subprocess.run([str(tools/'ar'),'rcs',str(a.output/'libAvaloniaNative.a'),*map(str,objects)],check=True)
# The macOS font pre-initializer is compiled by the same cross compiler.
env=dict(os.environ,RID=a.rid,OUTPUT_DIR=str(a.output),CC=str(tools/'cc'),STATICLINK_ZIG_CROSS='1')
subprocess.run(['bash',str(repo/'scripts/build-macos-font-preinit.sh')],env=env,check=True)
commit=subprocess.check_output(['git','-C',str(a.source),'rev-parse','HEAD'],text=True).strip()
(a.output/'avalonia-native-build.json').write_text(json.dumps({'source_commit':commit,'rid':a.rid,'toolchain':json.loads((tools/'toolchain.json').read_text()),'sources':source_hashes,'validation':'compiled archive; macOS AOT/runtime validation runs separately'},indent=2)+'\n')
+242
View File
@@ -0,0 +1,242 @@
#!/usr/bin/env python3
"""Build pinned, already dependency-synced SkiaSharp/ANGLE sources from Linux."""
import argparse
import hashlib
import json
import os
from pathlib import Path
import platform
import shutil
import subprocess
import sys
from skia_compat import archive, configure, parse_args, repair_xps, repair_skcms
HERE = Path(__file__).resolve().parent
def run(args, cwd=None, env=None):
print('+', ' '.join(map(str, args)), flush=True)
subprocess.run(list(map(str, args)), cwd=cwd, env=env, check=True)
def patch(source, filename):
path = HERE / 'patches' / filename
cmd = ['git', '-C', str(source), 'apply']
if subprocess.run(cmd + ['--reverse', '--check', str(path)], capture_output=True).returncode == 0:
return
run(cmd + ['--check', path])
run(cmd + [path])
def main():
p = argparse.ArgumentParser(description=__doc__)
p.add_argument('--target', choices=['linux-x64', 'linux-arm64', 'linux-musl-x64', 'linux-musl-arm64', 'win-x64', 'win-x86', 'win-arm64', 'osx-x64', 'osx-arm64'], required=True)
p.add_argument('--sources-manifest', type=Path, help='cross-sources.json from prepare-cross-sources.sh')
p.add_argument('--source-lock', type=Path, help='Exact version profile; defaults to sources.lock.json')
p.add_argument('--skia', type=Path, help='SkiaSharp externals/skia, with its pinned dependencies synced')
p.add_argument('--angle', type=Path, help='ANGLE source with pinned DEPS synced, including tools/win')
p.add_argument('--angle-gn', type=Path, help='GN from the pinned ANGLE DEPS')
p.add_argument('--zig', default='zig')
p.add_argument('--sdk', type=Path, default=Path('/opt/macos-sdk/MacOSX15.5.sdk'))
p.add_argument('--mingw-headers', type=Path, default=Path('/opt/mingw/usr/share/mingw-w64/include'))
p.add_argument('--availability-source', type=Path, default=Path('/opt/staticlink/os_version_check.c'))
p.add_argument('--linux-sysroots', type=Path, default=Path('/opt/sysroots'))
p.add_argument('--linux-headers', type=Path, default=Path('/opt/staticlink/linux-headers'))
p.add_argument('--work', type=Path, required=True)
p.add_argument('--output', type=Path, required=True)
p.add_argument('--jobs', type=int, default=4)
p.add_argument('--configure-only', action='store_true')
p.add_argument('--component', choices=['all', 'skia'], default='all', help='Build Skia alone when validating a new SkiaSharp release')
a = p.parse_args()
if a.sources_manifest:
sources = json.loads(a.sources_manifest.read_text())
if a.source_lock is None and sources.get('source_lock'):
a.source_lock = Path(sources['source_lock'])
for name in ('skia', 'angle', 'angle_gn'):
if getattr(a, name) is None:
setattr(a, name, Path(sources[name]))
if any(getattr(a, name) is None for name in ('skia', 'angle', 'angle_gn')):
p.error('Provide --sources-manifest or all of --skia, --angle and --angle-gn')
if platform.system() != 'Linux' or a.jobs < 1:
p.error('Requires Linux and positive --jobs')
for name in ('skia', 'angle', 'angle_gn', 'sdk', 'work', 'output', 'availability_source', 'mingw_headers'):
setattr(a, name, getattr(a, name).resolve())
lock = json.loads((a.source_lock or HERE / 'sources.lock.json').read_text())
for src, key in ((a.skia, 'skia_revision'), (a.angle, 'angle_revision')):
revision = subprocess.check_output(['git', '-C', str(src), 'rev-parse', 'HEAD'], text=True).strip()
if revision != lock[key]:
raise SystemExit(f'{src}: expected {lock[key]}, got {revision}; update the lock and revalidate first')
if 'skiasharp_build("SkiaSharp")' not in (a.skia / 'BUILD.gn').read_text():
raise SystemExit('--skia must be the SkiaSharp-patched Skia source, not vanilla Google Skia')
a.work.mkdir(parents=True, exist_ok=True)
a.output.mkdir(parents=True, exist_ok=True)
windows = a.target.startswith('win')
mac = a.target.startswith('osx')
linux = a.target.startswith('linux')
cpu = a.target.rsplit('-', 1)[1]
os_name = 'win' if windows else ('mac' if mac else 'linux')
if windows and not (a.mingw_headers / 'windows.ui.composition.h').is_file():
raise SystemExit('Windows ANGLE requires --mingw-headers containing the pinned WinRT headers')
recipe = hashlib.sha256()
for path in sorted(HERE.rglob('*')):
if path.is_file() and (path.suffix in ('.py', '.in', '.patch', '.c') or path.name in ('cross-toolchain.lock.json', 'linux-sysroots.lock.json', 'linux-sysroots-musl.lock.json')):
recipe.update(str(path.relative_to(HERE)).encode())
recipe.update(path.read_bytes())
variant = hashlib.sha256((json.dumps(lock, sort_keys=True) + recipe.hexdigest()).encode()).hexdigest()[:16]
shared = {'angle_revision': lock['angle_revision'], 'recipe': recipe.hexdigest(), 'toolchain': json.loads((HERE / 'cross-toolchain.lock.json').read_text())}
angle_variant = hashlib.sha256(json.dumps(shared, sort_keys=True).encode()).hexdigest()[:16]
tools = a.work / angle_variant / a.target
host_cpu = 'arm64' if platform.machine() == 'aarch64' else 'x64'
host_tools = a.work / angle_variant / ('linux-' + host_cpu)
for target, output in ((a.target, tools), ('linux-' + host_cpu, host_tools)):
command = [sys.executable, HERE / 'zig-cross.py', '--zig', a.zig, '--target', target,
'--output', output, '--sdk', a.sdk, '--mingw-headers', a.mingw_headers]
if target.startswith('linux'):
command += ['--linux-sysroot', a.linux_sysroots / target, '--linux-headers', a.linux_headers]
run(command)
config = json.loads((tools / 'toolchain.json').read_text())
zig = config['zig']
zig_lib = Path(json.loads(subprocess.check_output([zig, 'env'], text=True))['lib_dir'])
print('skcms Clang compatibility:', repair_skcms(a.skia), flush=True)
if windows:
print('XPS compatibility:', repair_xps(a.skia), flush=True)
# First apply the project's static ANGLE target patch if necessary.
if 'angle_static_library("libANGLE_static")' not in (a.angle / 'BUILD.gn').read_text():
patch(a.angle, 'angle-static-targets.patch')
for filename in ('BUILDCONFIG.gn-zig.patch', 'BUILD.gn-zig.patch',
'sdk_info-linux.patch', 'find_sdk-linux.patch', 'gcc-toolchain-objc.patch'):
patch(a.angle, filename)
run([sys.executable, a.angle / 'build/util/lastchange.py', '-o', a.angle / 'build/util/LASTCHANGE'], cwd=a.angle)
# Separate runtime paths prevent architectures from sharing an incompatible cache.
clang = tools / 'clang'
runtime = clang / 'lib/clang/19/lib' / ('windows' if windows else ('darwin' if mac else 'linux')) / (
'clang_rt.builtins-' + {'x64': 'x86_64', 'x86': 'i386', 'arm64': 'aarch64'}[cpu] + '.lib'
if windows else ('libclang_rt.osx.a' if mac else 'libclang_rt.builtins-' + ('x86_64' if cpu == 'x64' else 'aarch64') + '.a'))
runtime.parent.mkdir(parents=True, exist_ok=True)
run([zig, 'build-lib', zig_lib / 'compiler_rt.zig', '-target', config['target'],
'-O', 'ReleaseFast', '-fPIC', '-femit-bin=' + str(runtime)])
if linux:
for runtime_cpu, runtime_target in ((cpu, config['target']), (host_cpu, json.loads((host_tools / 'toolchain.json').read_text())['target'])):
triple = 'x86_64-unknown-linux-gnu' if runtime_cpu == 'x64' else 'aarch64-unknown-linux-gnu'
alias = clang / 'lib/clang/19/lib' / triple / 'libclang_rt.builtins.a'
alias.parent.mkdir(parents=True, exist_ok=True)
run([zig, 'build-lib', zig_lib / 'compiler_rt.zig', '-target', runtime_target,
'-O', 'ReleaseFast', '-fPIC', '-femit-bin=' + str(alias)])
availability = None
if mac:
if hashlib.sha256(a.availability_source.read_bytes()).hexdigest() != 'bc0b9f10e8d1a1ac5905d710f1c9fead23878e31233748d580393edc4e3bfc18':
raise SystemExit('LLVM availability source checksum mismatch')
availability = tools / 'os_version_check.o'
run([tools / 'cc', '-c', a.availability_source, '-o', availability])
run([tools / 'ar', 'rcs', runtime, availability])
env = os.environ.copy()
env['PATH'] = str(tools) + os.pathsep + env['PATH']
env['CCACHE_BASEDIR'] = str(a.skia)
env['CCACHE_NOHASHDIR'] = 'true'
env['CCACHE_COMPILERCHECK'] = 'content'
env['STATICLINK_MACOS_SDK'] = str(a.sdk)
env['STATICLINK_DARWIN_TOOLS'] = str(tools)
skia_out = a.skia / 'out' / ('staticlink-zig-' + a.target + '-' + variant)
angle_out = a.angle / 'out' / ('staticlink-zig-' + a.target + '-' + angle_variant)
for out in (skia_out, angle_out):
out.mkdir(parents=True, exist_ok=True)
skia_args = (HERE / ('skia-' + os_name + '.gn.in')).read_text().replace('@CPU@', cpu)
if mac:
skia_args += f'min_macos_version = "{"11.0" if cpu == "arm64" else "10.13"}"\n'
skia_args += f'xcode_sysroot = {json.dumps(str(a.sdk))}\n'
for name in ('cc', 'cxx', 'ar'):
skia_args += name + ' = ' + json.dumps(str(tools / name)) + '\n'
if linux:
for key in ('cc', 'cxx', 'ar'):
skia_args = skia_args.replace('@' + key.upper() + '@', str(tools / key))
capabilities = configure(a.skia, skia_out, parse_args(skia_args), a.skia / 'bin/gn', env)
for target in ('skia', 'SkiaSharp', 'HarfBuzzSharp'):
description = json.loads(subprocess.check_output([str(a.skia / 'bin/gn'), 'desc', str(skia_out.relative_to(a.skia)),
'//:' + target, '--format=json'], cwd=a.skia, env=env, text=True))
kind = next(iter(description.values()))['type']
if kind != 'static_library':
raise SystemExit(f'{target} is {kind}; expected static_library')
if windows:
# Upstream Skia fixes Windows to the MSVC rules; retain its graph and
# replace compiler/archive commands explicitly with the GNU adapters.
path = skia_out / 'toolchain.ninja'
body = path.read_text()
index = body.index('subninja ')
rules = ''
for name, flags in (('cc', 'cflags_c'), ('cxx', 'cflags_cc')):
rules += f'rule {name}\n command = {tools / name} -MD -MF ${{out}}.d ${{defines}} ${{include_dirs}} ${{cflags}} ${{{flags}}} -c ${{in}} -o ${{out}}\n depfile = ${{out}}.d\n deps = gcc\n'
rules += f'rule alink\n command = {tools / "ar"} rcs ${{out}} @${{out}}.rsp\n rspfile = ${{out}}.rsp\n rspfile_content = ${{in_newline}}\n'
rules += 'rule stamp\n command = touch ${out}\nrule copy\n command = cp ${in} ${out}\nrule asm\n command = false\n'
path.write_text(rules + '\n' + body[index:])
sdk_link = angle_out / 'sdk/xcode_links/MacOSX15.5.sdk'
if mac:
sdk_link.parent.mkdir(parents=True, exist_ok=True)
if sdk_link.is_symlink():
sdk_link.unlink()
sdk_link.symlink_to(a.sdk)
# Each architecture gets an independent toolchain file; concurrent builds
# do not rewrite another target's generated GN toolchain.
toolchain_dir = a.angle / ('staticlink_zig_' + a.target.replace('-', '_') + '_' + angle_variant)
toolchain_dir.mkdir(exist_ok=True)
text = 'import("//build/toolchain/gcc_toolchain.gni")\n'
for name, folder, target_os, target_cpu in (('target', tools, os_name, cpu), ('host', host_tools, 'linux', host_cpu)):
text += f'gcc_toolchain("{name}") {{\n'
for var in ('cc', 'cxx', 'ar'):
text += ' ' + var + ' = ' + json.dumps(str(folder / var)) + '\n'
text += f' ld = cxx\n nm = "nm"\n readelf = "readelf"\n toolchain_args = {{ current_os = "{target_os}" current_cpu = "{target_cpu}" is_clang = true use_remoteexec = false }}\n}}\n'
(toolchain_dir / 'BUILD.gn').write_text(text)
angle_args = (HERE / ('angle-' + os_name + '.gn.in')).read_text().replace('@CPU@', cpu)
angle_args += f'custom_toolchain = "//{toolchain_dir.name}:target"\nhost_toolchain = "//{toolchain_dir.name}:host"\n'
angle_args += 'clang_base_path = ' + json.dumps(str(clang)) + '\n'
if linux:
angle_args += 'pkg_config = ' + json.dumps(str(tools / 'pkg-config')) + '\n'
angle_args += 'host_pkg_config = ' + json.dumps(str(host_tools / 'pkg-config')) + '\n'
if windows:
# These mandatory GN metadata paths refer to the real MinGW headers.
# The SDK/version strings satisfy GN; MSVC/Windows SDK are not used.
for name, path in (('visual_studio_path', Path(zig).parent), ('wdk_path', Path(zig).parent),
('windows_sdk_path', zig_lib / 'libc/include/any-windows-any')):
angle_args += name + ' = ' + json.dumps(str(path)) + '\n'
(angle_out / 'args.gn').write_text(angle_args)
run([a.angle_gn, 'gen', angle_out.relative_to(a.angle)], cwd=a.angle, env=env)
if a.configure_only:
print(f'Configured {lock["skiasharp_version"]} {a.target}: all three Skia targets are static libraries')
return
run(['ninja', '-C', skia_out, '-j', a.jobs, 'skia', 'SkiaSharp', 'HarfBuzzSharp'], env=env)
if a.component == 'all':
run(['ninja', '-C', angle_out, '-j', a.jobs, 'libANGLE_static', 'libGLESv2_static', 'libEGL_static'], env=env)
if availability:
run([tools / 'ar', 'rcs', archive(skia_out, 'skia'), availability])
files = [(archive(skia_out, name), name)
for name in ('skia', 'SkiaSharp', 'HarfBuzzSharp')]
if a.component == 'all':
files += [(angle_out / ('obj/lib' + name + '_static.a'), name) for name in ('ANGLE', 'GLESv2', 'EGL')]
manifest = dict(target=a.target, sources=lock, toolchain=config, archives={})
manifest['build_variant'] = variant
manifest['skia_capabilities'] = capabilities
if linux:
manifest['linux_sdk_packages'] = json.loads((HERE / ('linux-sysroots-musl.lock.json' if 'musl' in a.target else 'linux-sysroots.lock.json')).read_text())[a.target]
manifest['toolchain_inputs'] = json.loads((HERE / 'cross-toolchain.lock.json').read_text())
manifest['gn_sha256'] = {str(path): hashlib.sha256(path.read_bytes()).hexdigest()
for path in (a.skia / 'bin/gn', a.angle_gn)}
manifest['recipe_sha256'] = {str(path.relative_to(HERE)): hashlib.sha256(path.read_bytes()).hexdigest()
for path in sorted(HERE.rglob('*')) if path.is_file() and (path.suffix in ('.py', '.in', '.patch', '.c') or path.name in ('cross-toolchain.lock.json', 'linux-sysroots.lock.json', 'linux-sysroots-musl.lock.json'))}
packages = Path('/opt/staticlink/packages.lock')
if packages.is_file():
shutil.copy2(packages, a.output / 'toolchain-packages.lock')
manifest['packages_sha256'] = hashlib.sha256(packages.read_bytes()).hexdigest()
for source, name in files:
dest = a.output / ('lib' + name + '.a')
shutil.copy2(source, dest)
manifest['archives'][dest.name] = hashlib.sha256(dest.read_bytes()).hexdigest()
run([sys.executable, HERE / 'link-cross.py', '--toolchain', tools, '--skia', a.skia,
'--angle', a.angle, '--libraries', a.output, '--output', a.output / 'link-tests', '--component', a.component])
if a.target == 'win-x86':
run([sys.executable, HERE / 'x86-thunks.py', '--source', a.skia.parent.parent,
'--toolchain', tools, '--libraries', a.output])
manifest['link_tests'] = 'passed; target runtime tests still required'
(a.output / 'cross-build.json').write_text(json.dumps(manifest, indent=2) + '\n')
if __name__ == '__main__':
main()
@@ -0,0 +1,10 @@
{
"zig_version": "0.14.1",
"macos_sdk_version": "15.5",
"macos_sdk_sha256": "c15cf0f3f17d714d1aa5a642da8e118db53d79429eb015771ba816aa7c6c1cbd",
"mingw_headers_version": "11.0.1-3build1",
"mingw_package_sha256": "4a42fd30fbc3838c58c929d8a4882682fc12408bb7a0e6cafa913c0f0a57c187",
"llvm_availability_revision": "llvmorg-19.1.7",
"llvm_availability_sha256": "bc0b9f10e8d1a1ac5905d710f1c9fead23878e31233748d580393edc4e3bfc18",
"angle_gn_revision": "e331ddb6e93389abfc75c611690bb82f5274029e"
}
@@ -0,0 +1,39 @@
#!/usr/bin/env python3
"""Materialize target SDK libraries from immutable, checksum-locked packages."""
import argparse,json,hashlib,urllib.request,tarfile,subprocess
from pathlib import Path
p=argparse.ArgumentParser();p.add_argument('--output',type=Path,required=True);p.add_argument('--locks',type=Path,nargs='+',required=True);a=p.parse_args()
for lock in a.locks:
for rid,packages in json.loads(lock.read_text()).items():
dest=a.output/rid;dest.mkdir(parents=True,exist_ok=True)
for package in packages:
with urllib.request.urlopen(package['url'],timeout=90) as response:data=response.read()
if hashlib.sha256(data).hexdigest()!=package['sha256']:raise SystemExit('SDK checksum mismatch: '+package['name'])
path=a.output/(rid+'-'+Path(package['url']).name);path.write_bytes(data)
if path.suffix=='.deb':subprocess.run(['dpkg-deb','--extract',str(path),str(dest)],check=True)
else:
with tarfile.open(path,mode='r:gz',ignore_zeros=True) as tar:
members=[m for m in tar.getmembers() if m.name.startswith(('lib/','usr/lib/','usr/include/','etc/fonts/'))]
for m in members:
if m.issym() and m.linkname.startswith('/'):
import posixpath
m.linkname=posixpath.relpath(m.linkname.lstrip('/'),posixpath.dirname(m.name))
# Debian 12's pinned Python 3.11 has no extraction-filter API.
# Validate paths and links explicitly before extracting locked APK files.
root=dest.resolve()
for m in members:
target=(root/m.name).resolve()
if not target.is_relative_to(root):raise SystemExit('Unsafe SDK archive path: '+m.name)
if not (m.isfile() or m.isdir() or m.issym() or m.islnk()):raise SystemExit('Unsupported SDK archive entry: '+m.name)
if m.issym() or m.islnk():
link=(target.parent/m.linkname if m.issym() else root/m.linkname).resolve()
if not link.is_relative_to(root):raise SystemExit('Unsafe SDK archive link: '+m.name)
tar.extractall(dest,members=members)
path.unlink()
print(rid,package['name'],package['version'],flush=True)
# Copy only platform headers; never replace Zig's target libc headers with the host's.
import shutil
headers=a.output.parent/'staticlink/linux-headers';headers.mkdir(parents=True,exist_ok=True)
for name in ('fontconfig','X11','xcb','GL','KHR','EGL','freetype2','libdrm'):
src=a.output/'linux-x64/usr/include'/name
if src.is_dir():shutil.copytree(src,headers/name,dirs_exist_ok=True,symlinks=True)
+100
View File
@@ -0,0 +1,100 @@
#!/usr/bin/env python3
"""Link raster/HarfBuzz and EGL/GLES executables against cross-built archives."""
import argparse
import json
from pathlib import Path
import subprocess
import re
HERE = Path(__file__).resolve().parent
def main():
p = argparse.ArgumentParser(description=__doc__)
p.add_argument('--toolchain', type=Path, required=True)
p.add_argument('--skia', type=Path, required=True)
p.add_argument('--angle', type=Path, required=True)
p.add_argument('--libraries', type=Path, required=True)
p.add_argument('--output', type=Path, required=True)
p.add_argument('--component', choices=['all', 'skia'], default='all')
a = p.parse_args()
config = json.loads((a.toolchain / 'toolchain.json').read_text())
windows = 'windows' in config['target']
a.output.mkdir(parents=True, exist_ok=True)
target = config['target']
flags = []
mac = 'macos' in target
linux = 'linux' in target
if mac:
# ANGLE's pinned Chromium build has a macOS 13 deployment minimum.
target = target.split('-macos.')[0] + '-macos.13.0'
sdk = config['sdk']
flags = ['-isysroot', sdk, '-L' + sdk + '/usr/lib', '-F' + sdk + '/System/Library/Frameworks']
for name in (('raster', 'angle') if a.component == 'all' else ('raster',)):
obj = a.output / ('smoke-' + name + '.o')
includes = [a.skia, a.skia / 'third_party/externals/harfbuzz/src', a.angle / 'include']
command = [str(a.toolchain / 'cc')]
if name == 'angle':
command.extend(('-DANGLE_STATIC=1', '-DKHRONOS_STATIC'))
else:
header = (a.skia / 'include/core/SkMilestone.h').read_text()
match = re.search(r'^\s*#define\s+SK_MILESTONE\s+(\d+)', header, re.MULTILINE)
if not match:
raise SystemExit('Cannot discover the Skia milestone; inspect the new source layout')
command.append('-DSTATICLINK_EXPECTED_MILESTONE=' + match[1])
command += ['-I' + str(path) for path in includes]
command += ['-c', str(HERE / ('smoke-' + name + '.c')), '-o', str(obj)]
subprocess.run(command, check=True)
libs = ('SkiaSharp', 'skia', 'HarfBuzzSharp') if name == 'raster' else ('EGL', 'GLESv2', 'ANGLE')
command = [config['zig'], 'c++', '-target', target, '-O2', *flags, str(obj)]
command += [str(a.libraries / ('lib' + library + '.a')) for library in libs]
if windows:
command += ['-l' + lib for lib in ('dwrite', 'gdi32', 'ole32', 'oleaut32', 'user32', 'uuid',
'windowscodecs', 'dxguid', 'dxgi', 'd3d11', 'd3d9', 'dwmapi', 'shlwapi', 'setupapi', 'version', 'advapi32', 'api-ms-win-core-synch-l1-2-0')]
elif mac:
for framework in ('CoreFoundation', 'CoreGraphics', 'CoreText', 'Foundation', 'AppKit',
'Metal', 'QuartzCore', 'OpenGL', 'IOKit', 'IOSurface'):
command += ['-framework', framework]
command += ['-lobjc']
availability = a.toolchain / 'os_version_check.o'
if availability.is_file():
command.append(str(availability))
elif linux:
sysroot = Path(config.get('linux_sysroot') or '/')
for path in (sysroot / 'usr/lib', sysroot / 'lib', sysroot / 'usr/lib' / ('x86_64-linux-gnu' if target.startswith('x86_64') else 'aarch64-linux-gnu')):
if path.is_dir():
command += ['-L' + str(path)]
command += ['-lfontconfig', '-ldl', '-lm', '-lpthread'] if name == 'raster' else ['-lX11', '-lXext', '-lxcb', '-lwayland-client', '-lwayland-egl', '-lffi', '-ldl', '-lm', '-lpthread']
command += ['-v']
command += ['-o', str(a.output / ('smoke-' + name + ('.exe' if windows else '')))]
result = subprocess.run(command, capture_output=True, text=True)
print(result.stdout, end='')
print(result.stderr, end='')
result.check_returncode()
# Keep the exact runtime archives chosen by this Zig target. AOT consumes
# these without substituting the consumer machine's C++ toolchain.
import shlex, shutil
runtimes = {}
project_archives = {path.resolve() for path in a.libraries.glob('lib*.a')}
for line in (result.stdout + '\n' + result.stderr).splitlines():
try:
tokens = shlex.split(line)
except ValueError:
continue
for token in tokens:
path = Path(token)
if path.suffix in ('.a', '.lib') and path.is_file() and path.resolve() not in project_archives and not path.resolve().is_relative_to(a.libraries.resolve()):
dest = a.libraries / 'zig-runtime' / path.name
dest.parent.mkdir(exist_ok=True)
shutil.copy2(path, dest)
runtimes[path.name] = str(path)
descriptor = a.libraries / 'zig-runtime' / 'inputs.json'
if descriptor.exists():
runtimes = dict(json.loads(descriptor.read_text()), **runtimes)
descriptor.parent.mkdir(exist_ok=True)
descriptor.write_text(json.dumps(runtimes, indent=2) + '\n')
print('Executable link tests passed. Run them on the target OS to validate behavior.')
if __name__ == '__main__':
main()
@@ -0,0 +1,474 @@
{
"linux-musl-x64": [
{
"name": "brotli-dev",
"version": "1.2.0-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/brotli-dev-1.2.0-r0.apk",
"sha256": "f61bd37140c76a22e97ad9d7461becda5d41526bbee1a8bc2523edad5ae6f35e"
},
{
"name": "brotli-libs",
"version": "1.2.0-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/brotli-libs-1.2.0-r0.apk",
"sha256": "09fbf1ddf0c71c6c4ab7bc12aef3452d8ace5adeab10c4c30214fc70f5e0e087"
},
{
"name": "bzip2-dev",
"version": "1.0.8-r6",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/bzip2-dev-1.0.8-r6.apk",
"sha256": "59a73f8712a9c0c16553a759149ee5ecf87a6160ef021aeb922ddb0c0b3a695b"
},
{
"name": "expat",
"version": "2.8.5-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/expat-2.8.5-r0.apk",
"sha256": "19f3d19d7deb82e357a70cb30b38dd81fa1cbecdb7e0a834071e993d5df18246"
},
{
"name": "expat-dev",
"version": "2.8.5-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/expat-dev-2.8.5-r0.apk",
"sha256": "5a31977673fbdacf195d372114501c06b18eb1f24553c99b92e47e0e24478f9e"
},
{
"name": "fontconfig",
"version": "2.17.1-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/fontconfig-2.17.1-r0.apk",
"sha256": "f44cea53076f18428dad0c27c75ca717ebfc3d2f0f4c8d4428ce70b62e25adf1"
},
{
"name": "fontconfig-dev",
"version": "2.17.1-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/fontconfig-dev-2.17.1-r0.apk",
"sha256": "e819dd0eb3f2a2a4f802a16911959e1232b323c4e2db9ce020c3d52e9bfd5053"
},
{
"name": "freetype",
"version": "2.14.3-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/freetype-2.14.3-r0.apk",
"sha256": "670c9922ab4eb9df65c0e4ad7839bbe3f486016fc1fb637c46d657b74d99a24f"
},
{
"name": "freetype-dev",
"version": "2.14.3-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/freetype-dev-2.14.3-r0.apk",
"sha256": "85a90244c039722c409996e5e5e65d4751664984ed1843a00c5d751577627972"
},
{
"name": "libbsd",
"version": "0.12.2-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libbsd-0.12.2-r0.apk",
"sha256": "1252092dea853063252bbdaf9fa604819055b004ba3114b88b842fbfe44659e9"
},
{
"name": "libbz2",
"version": "1.0.8-r6",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libbz2-1.0.8-r6.apk",
"sha256": "9995840a76ac97ec006259391b7a81b73b73c5cf2f462bf12bb2250afbf665b9"
},
{
"name": "libexpat",
"version": "2.8.5-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libexpat-2.8.5-r0.apk",
"sha256": "5216046085b92da88a6b107dbbb558f69d49c347a6335291fcf199ebd1670a8f"
},
{
"name": "libffi",
"version": "3.5.2-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libffi-3.5.2-r0.apk",
"sha256": "0b3473a1468bed5fbb913a1ffa121e253080b21b013fe47e0300bd7e85224e76"
},
{
"name": "libffi-dev",
"version": "3.5.2-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libffi-dev-3.5.2-r0.apk",
"sha256": "737a9109fc4a763465cc117ca20edd18d4ea3fe9ed6f717251aa744b8ebbaba6"
},
{
"name": "libmd",
"version": "1.1.0-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libmd-1.1.0-r0.apk",
"sha256": "704446100fb39f2699d848d97f09463dd6fdd35f3a1acb038483712e1e37f766"
},
{
"name": "libpng",
"version": "1.6.59-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libpng-1.6.59-r0.apk",
"sha256": "148a10e3d6419f787b16edbc2d0bb19d12a2a078225baaa416c895c14f47fc1e"
},
{
"name": "libpng-dev",
"version": "1.6.59-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libpng-dev-1.6.59-r0.apk",
"sha256": "01b89d3cea124fed78359b71f77e4d545de6e3163077167947e6adf84bdcb595"
},
{
"name": "libx11",
"version": "1.8.12-r1",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libx11-1.8.12-r1.apk",
"sha256": "cbc478a642226812ab13688bfe9ec69c86cf0e8e037dba7cfd055e8d7741f30c"
},
{
"name": "libx11-dev",
"version": "1.8.12-r1",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libx11-dev-1.8.12-r1.apk",
"sha256": "91eac12015dffbeb06b2755eae52722b1740018d775db33fbe68abc353b951df"
},
{
"name": "libxau",
"version": "1.0.12-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libxau-1.0.12-r0.apk",
"sha256": "61ee983ec9d47821cae9b3e1c8245a5b0b228361839be9b596a42c817b691a9f"
},
{
"name": "libxau-dev",
"version": "1.0.12-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libxau-dev-1.0.12-r0.apk",
"sha256": "2af8a78f1deaf398e96964f17d5640e3448fc5e935392e3550283e8d7c54a6cc"
},
{
"name": "libxcb",
"version": "1.17.0-r1",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libxcb-1.17.0-r1.apk",
"sha256": "f73934506edfdcb6895f04e313481ca48592ac4cec59cdb8fc073a7681bfbd31"
},
{
"name": "libxcb-dev",
"version": "1.17.0-r1",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libxcb-dev-1.17.0-r1.apk",
"sha256": "8735d97a346eae3999a599e49eb533481478d0ef9466e6e5a5453dd1e3ae8f3d"
},
{
"name": "libxdmcp",
"version": "1.1.5-r1",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libxdmcp-1.1.5-r1.apk",
"sha256": "f134d28babb070834066aa716c303768ed0ede32ac086f3dfbd8cbbac62380ee"
},
{
"name": "libxdmcp-dev",
"version": "1.1.5-r1",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libxdmcp-dev-1.1.5-r1.apk",
"sha256": "d8a304762ea4295287ef1adf9d93d64f04bdfc4e845b453698b3276b12e8fc10"
},
{
"name": "libxext",
"version": "1.3.6-r2",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libxext-1.3.6-r2.apk",
"sha256": "404beb855daf09fdb8d15f177a3608da62825a44497a805675a186171c04eb6c"
},
{
"name": "libxext-dev",
"version": "1.3.6-r2",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libxext-dev-1.3.6-r2.apk",
"sha256": "ebb6262372a918a6bee4ff2137dacdb1fa13be78d0e3544a082d6530ce8e05b6"
},
{
"name": "libxml2",
"version": "2.13.9-r1",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/libxml2-2.13.9-r1.apk",
"sha256": "1af363248efb54914993bbd516c89878c2b5b0c53be0c78bb43d5a3e9a8ceda6"
},
{
"name": "mesa-dev",
"version": "25.2.7-r1",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/mesa-dev-25.2.7-r1.apk",
"sha256": "da17f767ae27fc8ff9a958ff82d217ee3a890d888b43e6a62171a402b48156a1"
},
{
"name": "musl",
"version": "1.2.5-r23",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/musl-1.2.5-r23.apk",
"sha256": "4f3c4a7bf9f51d2c91007e333b17459362ffd881b4a343e8da07b6c50c4f4a0d"
},
{
"name": "wayland-dev",
"version": "1.24.0-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/wayland-dev-1.24.0-r0.apk",
"sha256": "5afcb3e3c414d2c0e602bc9ef1b4868fd7df9e53aec55f3f722ce4897019f014"
},
{
"name": "wayland-libs-client",
"version": "1.24.0-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/wayland-libs-client-1.24.0-r0.apk",
"sha256": "020313c601f85a9e91d1ae0d01e9f1e9905d1127b78dce9c278a75cfd52416d2"
},
{
"name": "wayland-libs-cursor",
"version": "1.24.0-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/wayland-libs-cursor-1.24.0-r0.apk",
"sha256": "e87fb03656132b550182b019b7f3218f336ff9637dc574ef0f22a0ad148f8577"
},
{
"name": "wayland-libs-egl",
"version": "1.24.0-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/wayland-libs-egl-1.24.0-r0.apk",
"sha256": "2d9165a79e7e779b52dd203959f64eb8f7caad460f3e6d76097efc432e115936"
},
{
"name": "wayland-libs-server",
"version": "1.24.0-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/wayland-libs-server-1.24.0-r0.apk",
"sha256": "c30fd5c6f081732670e7dd69316df73cb3939b8c53237314ca1ec3f991b2a1f7"
},
{
"name": "xorgproto",
"version": "2024.1-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/xorgproto-2024.1-r0.apk",
"sha256": "96e2b99a0227d301170ae840c37693d65c767dd0a15a1243ced45325850ad424"
},
{
"name": "xz-libs",
"version": "5.8.4-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/xz-libs-5.8.4-r0.apk",
"sha256": "3c8cc415e88c2a097543d9ee828081ec1905e7d0f57a319c8896269b0e00a672"
},
{
"name": "zlib",
"version": "1.3.2-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/zlib-1.3.2-r0.apk",
"sha256": "f56dea63692059bd65854bb179b7551971a441000b0d98c5b031291ca0450b56"
},
{
"name": "zlib-dev",
"version": "1.3.2-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/zlib-dev-1.3.2-r0.apk",
"sha256": "c811e48ea401e05479a74d93f8ac820bbb6af44b2adf0335769316e5cc2b72c4"
}
],
"linux-musl-arm64": [
{
"name": "brotli-dev",
"version": "1.2.0-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/brotli-dev-1.2.0-r0.apk",
"sha256": "012c9917e3a3f37efbb255fdff240d4fe0ee83a2e4e5d7511eddcce57a2daa30"
},
{
"name": "brotli-libs",
"version": "1.2.0-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/brotli-libs-1.2.0-r0.apk",
"sha256": "c8a9113b0007d40291e55cfc196744b64004253707e37b3c07e188166fb2d0a0"
},
{
"name": "bzip2-dev",
"version": "1.0.8-r6",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/bzip2-dev-1.0.8-r6.apk",
"sha256": "69d79bb497c25e81fce8695653f448666c08bc8b28fa51506b74b38946a0a03a"
},
{
"name": "expat",
"version": "2.8.5-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/expat-2.8.5-r0.apk",
"sha256": "b5b520d2bd7a89e8fbad6a59667f70d4656326dd8a4df84c3e5ef4b5c0056243"
},
{
"name": "expat-dev",
"version": "2.8.5-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/expat-dev-2.8.5-r0.apk",
"sha256": "2aad86f9f50aeb5b3c7a0e4022693dd810f51ec9c7a28037f3d2e71dbd9ecb1e"
},
{
"name": "fontconfig",
"version": "2.17.1-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/fontconfig-2.17.1-r0.apk",
"sha256": "38e815b8f898482e3c8111ac158208ba0a6a9aa13dbef49ccc36b36df77c793e"
},
{
"name": "fontconfig-dev",
"version": "2.17.1-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/fontconfig-dev-2.17.1-r0.apk",
"sha256": "5661ba91c9da743151b333a69b05f467f5c4145395f3d54567e7e9999aa8d842"
},
{
"name": "freetype",
"version": "2.14.3-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/freetype-2.14.3-r0.apk",
"sha256": "b1012afa50bdebe872fab255b1c6db8c2c05b0dc4fc274c48d714e1887401b4e"
},
{
"name": "freetype-dev",
"version": "2.14.3-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/freetype-dev-2.14.3-r0.apk",
"sha256": "cd8d91f81c9477f0f76fd8db8158237fa99b1e0f73f6ec6e929bfc46b076b51d"
},
{
"name": "libbsd",
"version": "0.12.2-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libbsd-0.12.2-r0.apk",
"sha256": "358715f27bfe492dcb11f3589c8f106c37071780f55adafc52b2c5cfd3771e4d"
},
{
"name": "libbz2",
"version": "1.0.8-r6",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libbz2-1.0.8-r6.apk",
"sha256": "ccd478f4d5346a25911d4ee977690e2695e0ca3acf3e6b1a8c1300b2f4311e2f"
},
{
"name": "libexpat",
"version": "2.8.5-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libexpat-2.8.5-r0.apk",
"sha256": "18e5a4f1715dd9fee420d250d14be9e59936352929085939f33da01c3fbde28d"
},
{
"name": "libffi",
"version": "3.5.2-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libffi-3.5.2-r0.apk",
"sha256": "ebf430b246a6b1167350431e2af59a09f4edbc42dc3e03f3b9d74800ba5f9e7f"
},
{
"name": "libffi-dev",
"version": "3.5.2-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libffi-dev-3.5.2-r0.apk",
"sha256": "96830dcf534e196258838122fcaae6582ea02c957413a31e53a86ae403db0478"
},
{
"name": "libmd",
"version": "1.1.0-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libmd-1.1.0-r0.apk",
"sha256": "8818536cdc38dd3c252d6c6915f65ddd49390aa209cc7f70b87c446adedf820c"
},
{
"name": "libpng",
"version": "1.6.59-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libpng-1.6.59-r0.apk",
"sha256": "087102199da459dd8985c118a67d6d6c463de6798f243424feb239d1087b1064"
},
{
"name": "libpng-dev",
"version": "1.6.59-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libpng-dev-1.6.59-r0.apk",
"sha256": "9f7a8ceb60638786dd675ccc526668516a8ca4df4b54daa05f526df12f76c7bd"
},
{
"name": "libx11",
"version": "1.8.12-r1",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libx11-1.8.12-r1.apk",
"sha256": "7f53f6f26293abac468b9563f2a90bc9a34306ec8a677af23d01d7455e3db943"
},
{
"name": "libx11-dev",
"version": "1.8.12-r1",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libx11-dev-1.8.12-r1.apk",
"sha256": "114785b13b6df10d7997e9e8e12bf95fd5f0e6644fd420fa84dcfc0956cdecb9"
},
{
"name": "libxau",
"version": "1.0.12-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libxau-1.0.12-r0.apk",
"sha256": "ddfad479041b53e5f57a2fdfac12454993ae3937f6f893d67cd98cbd63abfcf0"
},
{
"name": "libxau-dev",
"version": "1.0.12-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libxau-dev-1.0.12-r0.apk",
"sha256": "bed89cb8971efccf37f0a77d6cddcd31f122a322d04fc75117cddb48804c2290"
},
{
"name": "libxcb",
"version": "1.17.0-r1",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libxcb-1.17.0-r1.apk",
"sha256": "8609cadcd7af03c1aade3663fdf3bbe27e4180fe0edbe98d3f12f0ae6e95aedc"
},
{
"name": "libxcb-dev",
"version": "1.17.0-r1",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libxcb-dev-1.17.0-r1.apk",
"sha256": "f6d1488df536002017c10a435caa32f9527ec9ad5aa86cbab639cde4258a2b67"
},
{
"name": "libxdmcp",
"version": "1.1.5-r1",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libxdmcp-1.1.5-r1.apk",
"sha256": "f95a668a5b8888aadbee24e8ffb30f60e4d40cdf8ef61b35383e7ecf49182c66"
},
{
"name": "libxdmcp-dev",
"version": "1.1.5-r1",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libxdmcp-dev-1.1.5-r1.apk",
"sha256": "fa1dd28326caf9e3299bf36a94fa5d62c6f448588044fcf95ddcf2bcaabd9aff"
},
{
"name": "libxext",
"version": "1.3.6-r2",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libxext-1.3.6-r2.apk",
"sha256": "bb7e84c1d38e5dcdfdb56e543394469f9c884cb13e09f5e07986863a9bea62e7"
},
{
"name": "libxext-dev",
"version": "1.3.6-r2",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libxext-dev-1.3.6-r2.apk",
"sha256": "9b70dc8e575dbc28feed289a4336bc181cc7327886364aefe4bb3bb81a98c49b"
},
{
"name": "libxml2",
"version": "2.13.9-r1",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/libxml2-2.13.9-r1.apk",
"sha256": "91d3e730edbd5214c501696725e7af9a93e12a9dd6a296e719dca2f3de0697d5"
},
{
"name": "mesa-dev",
"version": "25.2.7-r1",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/mesa-dev-25.2.7-r1.apk",
"sha256": "a9759357562a1365b35b01a2be05cc33ec3ab0f3a1c1bd079a0b68e4c29ef129"
},
{
"name": "musl",
"version": "1.2.5-r23",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/musl-1.2.5-r23.apk",
"sha256": "6a3edd924ead1fad88a69e28c5775809af3026b322f58428001cd02fedc5299e"
},
{
"name": "wayland-dev",
"version": "1.24.0-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/wayland-dev-1.24.0-r0.apk",
"sha256": "681397cc91e05bb6cc63af4b37a59aa510aaab37539c9e6629d7fbfbcb1f0e57"
},
{
"name": "wayland-libs-client",
"version": "1.24.0-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/wayland-libs-client-1.24.0-r0.apk",
"sha256": "47634dcc2befcae378f9f60681d2af1864db85e57f65e11a3557a43f77911073"
},
{
"name": "wayland-libs-cursor",
"version": "1.24.0-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/wayland-libs-cursor-1.24.0-r0.apk",
"sha256": "a6f8e01ec409b183693169af006d1edc8b673af801bd540820fdb7808cb5e27b"
},
{
"name": "wayland-libs-egl",
"version": "1.24.0-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/wayland-libs-egl-1.24.0-r0.apk",
"sha256": "4f2ae7b94f0b6c95dae885c0c24ac59eea5fd2b7a4680cec43dd8366c86564d2"
},
{
"name": "wayland-libs-server",
"version": "1.24.0-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/wayland-libs-server-1.24.0-r0.apk",
"sha256": "c6bc1243dd337ba638834cd1e7a5ccfd10b6e2315e63af02f441bff581c35c66"
},
{
"name": "xorgproto",
"version": "2024.1-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/xorgproto-2024.1-r0.apk",
"sha256": "8d53e4b89f3067a4d24f7645127b100a4d46a567eccb82428fe5256c17316b0d"
},
{
"name": "xz-libs",
"version": "5.8.4-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/xz-libs-5.8.4-r0.apk",
"sha256": "55cec0880e1d06049147cd295a7c8a2909a668fc58a00c187741f3a16c25c55d"
},
{
"name": "zlib",
"version": "1.3.2-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/zlib-1.3.2-r0.apk",
"sha256": "ecda4cc94fd18f90182f1d3a615889df5e0db9cf78926d11627dd23e06d2e6e8"
},
{
"name": "zlib-dev",
"version": "1.3.2-r0",
"url": "https://dl-cdn.alpinelinux.org/alpine/v3.23/main/aarch64/zlib-dev-1.3.2-r0.apk",
"sha256": "18a7f594ad7439629cb5889e4f0ad71075dd9f0cd4729a0461ba1501e21bc583"
}
]
}
@@ -0,0 +1,594 @@
{
"linux-x64": [
{
"name": "libbrotli-dev",
"version": "1.0.9-2+b6",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/b/brotli/libbrotli-dev_1.0.9-2+b6_amd64.deb",
"sha256": "932de11d4d9caee3300319b2fdf6ca505ca739706be48737df5e40ee90ccb6ca"
},
{
"name": "libbrotli1",
"version": "1.0.9-2+b6",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/b/brotli/libbrotli1_1.0.9-2+b6_amd64.deb",
"sha256": "563b4caec1aa5e876bd3355b36e7a38e1484baf5a293b48d1e8bd22db786e4d7"
},
{
"name": "libbsd0",
"version": "0.11.7-2",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libb/libbsd/libbsd0_0.11.7-2_amd64.deb",
"sha256": "bb31cc8b40f962a85b2cec970f7f79cc704a1ae4bad24257a822055404b2c60b"
},
{
"name": "libbz2-1.0",
"version": "1.0.8-5+b1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/b/bzip2/libbz2-1.0_1.0.8-5+b1_amd64.deb",
"sha256": "54149da3f44b22d523b26b692033b84503d822cc5122fed606ea69cc83ca5aeb"
},
{
"name": "libbz2-dev",
"version": "1.0.8-5+b1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/b/bzip2/libbz2-dev_1.0.8-5+b1_amd64.deb",
"sha256": "df7204e188f7514ceae9c6f57c6c8b25ce8a642746fe284c6e89122ef26b7e57"
},
{
"name": "libc6",
"version": "2.36-9+deb12u14",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/g/glibc/libc6_2.36-9+deb12u14_amd64.deb",
"sha256": "ba4f88f73dbc3ae9055f3c20f4523bfdbaf1ad13ff95e258924f77d20b4fbedf"
},
{
"name": "libegl-dev",
"version": "1.6.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libg/libglvnd/libegl-dev_1.6.0-1_amd64.deb",
"sha256": "0ec9bffb024527dfb61eaeae44966e2b5b3114b3dc315b4117b0df95b1c96ef8"
},
{
"name": "libegl1",
"version": "1.6.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libg/libglvnd/libegl1_1.6.0-1_amd64.deb",
"sha256": "fe4d8b39f6e6fe1a32ab1efd85893553eaa9cf3866aa668ccf355f585b37d523"
},
{
"name": "libexpat1",
"version": "2.5.0-1+deb12u2",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/e/expat/libexpat1_2.5.0-1+deb12u2_amd64.deb",
"sha256": "2255e62fc22a86d2c544b8a3f516da9aee19383ad5742722ab4ce7f66a30dbc8"
},
{
"name": "libexpat1-dev",
"version": "2.5.0-1+deb12u2",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/e/expat/libexpat1-dev_2.5.0-1+deb12u2_amd64.deb",
"sha256": "757279c1ce56ca88ca519e4c01cffd94e8480ce936f53fe9b0d61dc1bab20394"
},
{
"name": "libffi-dev",
"version": "3.4.4-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libf/libffi/libffi-dev_3.4.4-1_amd64.deb",
"sha256": "89fb890aee5148f4d308a46cd8980a54fd44135f068f05b38a6ad06800bf6df3"
},
{
"name": "libffi8",
"version": "3.4.4-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libf/libffi/libffi8_3.4.4-1_amd64.deb",
"sha256": "6d9f6c25c30efccce6d4bceaa48ea86c329a3432abb360a141f76ac223a4c34a"
},
{
"name": "libfontconfig-dev",
"version": "2.14.1-4",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/f/fontconfig/libfontconfig-dev_2.14.1-4_amd64.deb",
"sha256": "74f4bbde5795e4fb4c453308bd0eb8ef45d7ade3cf11b3c18394f9e2c15d28df"
},
{
"name": "libfontconfig1",
"version": "2.14.1-4",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/f/fontconfig/libfontconfig1_2.14.1-4_amd64.deb",
"sha256": "16ee38d374e064f534116dc442b086ef26f9831f1c0af7e5fb4fe4512e700649"
},
{
"name": "libfreetype-dev",
"version": "2.12.1+dfsg-5+deb12u4",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/f/freetype/libfreetype-dev_2.12.1+dfsg-5+deb12u4_amd64.deb",
"sha256": "5fa327ae78e645cff5a2aadad92ca3640abc5cee7ad5368d7551bea8930202af"
},
{
"name": "libfreetype6",
"version": "2.12.1+dfsg-5+deb12u4",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/f/freetype/libfreetype6_2.12.1+dfsg-5+deb12u4_amd64.deb",
"sha256": "8043e479f73f29992d652e3f9dfe8b17f9780c7ea6330afe379ec5f9f188ac44"
},
{
"name": "libgl-dev",
"version": "1.6.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libg/libglvnd/libgl-dev_1.6.0-1_amd64.deb",
"sha256": "ebc12df48ae53924e114d9358ef3da4306d7ef8f7179300af52f1faef8b5db3e"
},
{
"name": "libgl1",
"version": "1.6.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libg/libglvnd/libgl1_1.6.0-1_amd64.deb",
"sha256": "6f89b1702c48e9a2437bb3c1ffac8e1ab2d828fc28b3d14b2eecd4cc19b2c790"
},
{
"name": "libglvnd0",
"version": "1.6.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libg/libglvnd/libglvnd0_1.6.0-1_amd64.deb",
"sha256": "b6da5b153dd62d8b5e5fbe25242db1fc05c068707c365db49abda8c2427c75f8"
},
{
"name": "libglx0",
"version": "1.6.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libg/libglvnd/libglx0_1.6.0-1_amd64.deb",
"sha256": "95f568df73dedf43ae66834a75502112e0d4f3ad7124f3dbfa790b739383b896"
},
{
"name": "libmd0",
"version": "1.0.4-2",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libm/libmd/libmd0_1.0.4-2_amd64.deb",
"sha256": "03539fd30c509e27101d13a56e52eda9062bdf1aefe337c07ab56def25a13eab"
},
{
"name": "libpng-dev",
"version": "1.6.39-2+deb12u5",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libp/libpng1.6/libpng-dev_1.6.39-2+deb12u5_amd64.deb",
"sha256": "25649c413d02092ae7b1093a3c3ee54cbd2d4fdb0a0494787e434ccf0905903f"
},
{
"name": "libpng16-16",
"version": "1.6.39-2+deb12u5",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libp/libpng1.6/libpng16-16_1.6.39-2+deb12u5_amd64.deb",
"sha256": "a56d64bfaa9da12aafb83347909e62e6fd5fd251e6b34c194065911a30359978"
},
{
"name": "libpthread-stubs0-dev",
"version": "0.4-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libp/libpthread-stubs/libpthread-stubs0-dev_0.4-1_amd64.deb",
"sha256": "54632f160e1e8a43656a87195a547391038c4ca0f53291b849cd4457ba5dfde9"
},
{
"name": "libuuid1",
"version": "2.38.1-5+deb12u3",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/u/util-linux/libuuid1_2.38.1-5+deb12u3_amd64.deb",
"sha256": "5fff398321da62d28a842bcbabd193d72ae21724962c029dc32b1dc6b2deaeaf"
},
{
"name": "libwayland-client0",
"version": "1.21.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/w/wayland/libwayland-client0_1.21.0-1_amd64.deb",
"sha256": "1f002d028b8b79eec9847c636d8886d10dfe8c884cc2bebe18086b1391c5a28d"
},
{
"name": "libwayland-cursor0",
"version": "1.21.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/w/wayland/libwayland-cursor0_1.21.0-1_amd64.deb",
"sha256": "0b684467ec795024fcaae99ea4384959cc4052b2da5adec38c9b76dfed9bcf41"
},
{
"name": "libwayland-dev",
"version": "1.21.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/w/wayland/libwayland-dev_1.21.0-1_amd64.deb",
"sha256": "063ac40e71069a1a92c2be32799f4a2d234f3d361ba98cea2e3137a7ab6804d1"
},
{
"name": "libwayland-egl1",
"version": "1.21.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/w/wayland/libwayland-egl1_1.21.0-1_amd64.deb",
"sha256": "cb4225f0e15e00a3570d4cbc288c87ff477d73e741c3f1c5a6d47cf350d45378"
},
{
"name": "libwayland-server0",
"version": "1.21.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/w/wayland/libwayland-server0_1.21.0-1_amd64.deb",
"sha256": "df0396221d7b794496a687ec61fae82b6465648bc0ab6501ba0a5ed7f56eb8d6"
},
{
"name": "libx11-6",
"version": "2:1.8.4-2+deb12u2",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libx11/libx11-6_1.8.4-2+deb12u2_amd64.deb",
"sha256": "d88c973e79fd9b65838d77624142952757e47a6eb1a58602acf0911cf35989f4"
},
{
"name": "libx11-dev",
"version": "2:1.8.4-2+deb12u2",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libx11/libx11-dev_1.8.4-2+deb12u2_amd64.deb",
"sha256": "8493220d4309af1907a1f2f6eeb204c8103dafcc368394fbc4a0858c28612ff9"
},
{
"name": "libx11-xcb1",
"version": "2:1.8.4-2+deb12u2",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libx11/libx11-xcb1_1.8.4-2+deb12u2_amd64.deb",
"sha256": "f5da45e1d881a793250a96613f28c471a248877f1a0f18a5c90e2a620a76c898"
},
{
"name": "libxau-dev",
"version": "1:1.0.9-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxau/libxau-dev_1.0.9-1_amd64.deb",
"sha256": "d1a7f5d484e0879b3b2e8d512894744505e53d078712ce65903fef2ecfd824bb"
},
{
"name": "libxau6",
"version": "1:1.0.9-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxau/libxau6_1.0.9-1_amd64.deb",
"sha256": "679db1c4579ec7c61079adeaae8528adeb2e4bf5465baa6c56233b995d714750"
},
{
"name": "libxcb1",
"version": "1.15-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxcb/libxcb1_1.15-1_amd64.deb",
"sha256": "fdc61332a3892168f3cc9cfa1fe9cf11a91dc3e0acacbc47cbc50ebaa234cc71"
},
{
"name": "libxcb1-dev",
"version": "1.15-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxcb/libxcb1-dev_1.15-1_amd64.deb",
"sha256": "c078c024114fdada06d3158af1771d7ed8763ab434cfbcbe6a334aa8a9cae358"
},
{
"name": "libxdmcp-dev",
"version": "1:1.1.2-3",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxdmcp/libxdmcp-dev_1.1.2-3_amd64.deb",
"sha256": "c6733e5f6463afd261998e408be6eb37f24ce0a64b63bed50a87ddb18ebc1699"
},
{
"name": "libxdmcp6",
"version": "1:1.1.2-3",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxdmcp/libxdmcp6_1.1.2-3_amd64.deb",
"sha256": "ecb8536f5fb34543b55bb9dc5f5b14c9dbb4150a7bddb3f2287b7cab6e9d25ef"
},
{
"name": "libxext-dev",
"version": "2:1.3.4-1+b1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxext/libxext-dev_1.3.4-1+b1_amd64.deb",
"sha256": "591456aba90eeed7a1c1b044d469fd7704bf7d83af9dc574bbe2efc4a2fd1dba"
},
{
"name": "libxext6",
"version": "2:1.3.4-1+b1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxext/libxext6_1.3.4-1+b1_amd64.deb",
"sha256": "504b7be9d7df4f6f4519e8dd4d6f9d03a9fb911a78530fa23a692fba3058cba6"
},
{
"name": "libxfixes3",
"version": "1:6.0.0-2",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxfixes/libxfixes3_6.0.0-2_amd64.deb",
"sha256": "1cd616396ff2ecae77e6e8b5b7695d414f0146de2d147837a2a02165f99e1a2c"
},
{
"name": "libxi6",
"version": "2:1.8-1+b1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxi/libxi6_1.8-1+b1_amd64.deb",
"sha256": "6c2fb5f241b311788990122c6e693915867cd8ed9d6da2e3524aec7ed3cdb4c0"
},
{
"name": "libxrandr2",
"version": "2:1.5.2-2+b1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxrandr/libxrandr2_1.5.2-2+b1_amd64.deb",
"sha256": "e2e10b672085ddf1d294cd689ed21bde5899325fd13626c2614b7d7b2d49a808"
},
{
"name": "libxrender1",
"version": "1:0.9.10-1.1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxrender/libxrender1_0.9.10-1.1_amd64.deb",
"sha256": "b2a6d160578f359220101947c8d67059b44704a251e688de1d0b744fefedfd1a"
},
{
"name": "x11proto-dev",
"version": "2022.1-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/x/xorgproto/x11proto-dev_2022.1-1_all.deb",
"sha256": "3cab66a6591774188a568f9b54c4e7956f18da76e0e0fc4a779db5f6bcc3f148"
},
{
"name": "xtrans-dev",
"version": "1.4.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/x/xtrans/xtrans-dev_1.4.0-1_all.deb",
"sha256": "9ce1af9464faee0c679348dd11cdf63934c12e734a64e0903692b0cb5af38e06"
},
{
"name": "zlib1g",
"version": "1:1.2.13.dfsg-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/z/zlib/zlib1g_1.2.13.dfsg-1_amd64.deb",
"sha256": "d7dd1d1411fedf27f5e27650a6eff20ef294077b568f4c8c5e51466dc7c08ce4"
},
{
"name": "zlib1g-dev",
"version": "1:1.2.13.dfsg-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/z/zlib/zlib1g-dev_1.2.13.dfsg-1_amd64.deb",
"sha256": "f9ce531f60cbd5df37996af9370e0171be96902a17ec2bdbd8d62038c354094f"
}
],
"linux-arm64": [
{
"name": "libbrotli-dev",
"version": "1.0.9-2+b6",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/b/brotli/libbrotli-dev_1.0.9-2+b6_arm64.deb",
"sha256": "68f334eb61694c2e5ca756174d111109f72193d1e3c14a25a65833c6dfcd98b7"
},
{
"name": "libbrotli1",
"version": "1.0.9-2+b6",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/b/brotli/libbrotli1_1.0.9-2+b6_arm64.deb",
"sha256": "3137de7f71952e710ee9f0df05026b3c6f463be9369a502d57c7696732f1ed22"
},
{
"name": "libbsd0",
"version": "0.11.7-2",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libb/libbsd/libbsd0_0.11.7-2_arm64.deb",
"sha256": "ef00f132ddd268ee67d756998723ee18543db27ab34930c0a9f1cff75cf55382"
},
{
"name": "libbz2-1.0",
"version": "1.0.8-5+b1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/b/bzip2/libbz2-1.0_1.0.8-5+b1_arm64.deb",
"sha256": "d3a96ece03326498b39ff093a76800dfcbcb1d4049d6ae6e9f6fa1aa7a590ad6"
},
{
"name": "libbz2-dev",
"version": "1.0.8-5+b1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/b/bzip2/libbz2-dev_1.0.8-5+b1_arm64.deb",
"sha256": "c9827ab40420f1259b1a10983978ec8de87c11fc1a6b3c192adea1c4c490754f"
},
{
"name": "libc6",
"version": "2.36-9+deb12u14",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/g/glibc/libc6_2.36-9+deb12u14_arm64.deb",
"sha256": "01f4330719fd4f65580e16ea5a0527f372fca750e8f588d26deaf09f2d3b1cf4"
},
{
"name": "libegl-dev",
"version": "1.6.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libg/libglvnd/libegl-dev_1.6.0-1_arm64.deb",
"sha256": "8a3004f892785a5fa4c9f969c116f567a36d1c8e9b3d5fd0403055151e36c7d3"
},
{
"name": "libegl1",
"version": "1.6.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libg/libglvnd/libegl1_1.6.0-1_arm64.deb",
"sha256": "707097a275155c600e2e9251c4ee7cdfdb2d8f50a678a850a2526a7bc9664166"
},
{
"name": "libexpat1",
"version": "2.5.0-1+deb12u2",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/e/expat/libexpat1_2.5.0-1+deb12u2_arm64.deb",
"sha256": "8dc1976735acf825e3a922d82f171e20feec7394da2b8c616091983e38706275"
},
{
"name": "libexpat1-dev",
"version": "2.5.0-1+deb12u2",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/e/expat/libexpat1-dev_2.5.0-1+deb12u2_arm64.deb",
"sha256": "9987e4aa214b0ec23fc2ba6a99b8f10d2dc68f2de347722215ae3f960802e3d3"
},
{
"name": "libffi-dev",
"version": "3.4.4-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libf/libffi/libffi-dev_3.4.4-1_arm64.deb",
"sha256": "8ff6335f76752ef8659762435d0d88129ef0090a587520853238809bd10ef392"
},
{
"name": "libffi8",
"version": "3.4.4-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libf/libffi/libffi8_3.4.4-1_arm64.deb",
"sha256": "80b5c36177dc0e29d531c7eddbed3cc7355cb490e49f8cfa5959572d161f27b3"
},
{
"name": "libfontconfig-dev",
"version": "2.14.1-4",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/f/fontconfig/libfontconfig-dev_2.14.1-4_arm64.deb",
"sha256": "7da35e69d4f43b337aa9508da8e9089de80e75285141be3d7bec1055a0501aa4"
},
{
"name": "libfontconfig1",
"version": "2.14.1-4",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/f/fontconfig/libfontconfig1_2.14.1-4_arm64.deb",
"sha256": "4836d9deca824883f0de33d4f8f3718ba776c6e7c80cd7c418b5a0f86c009b9e"
},
{
"name": "libfreetype-dev",
"version": "2.12.1+dfsg-5+deb12u4",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/f/freetype/libfreetype-dev_2.12.1+dfsg-5+deb12u4_arm64.deb",
"sha256": "4e5057ac9107c69c0f49f4a8989056a7c37184c94c73ee48ba7023c5fb118db7"
},
{
"name": "libfreetype6",
"version": "2.12.1+dfsg-5+deb12u4",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/f/freetype/libfreetype6_2.12.1+dfsg-5+deb12u4_arm64.deb",
"sha256": "b8d32e54ebc9020637f8fa16b6afa64a5731e40845a6e01880d38d6f632237c9"
},
{
"name": "libgl-dev",
"version": "1.6.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libg/libglvnd/libgl-dev_1.6.0-1_arm64.deb",
"sha256": "56add9e710c072cf56504beed50a639f9f7c64f4e31e66958fa65a566084888c"
},
{
"name": "libgl1",
"version": "1.6.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libg/libglvnd/libgl1_1.6.0-1_arm64.deb",
"sha256": "f4043ab47f52325973d2b608514b3469b055b65c744861c7f378755a32e799d6"
},
{
"name": "libglvnd0",
"version": "1.6.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libg/libglvnd/libglvnd0_1.6.0-1_arm64.deb",
"sha256": "d5063205fab5322ee686f33f87c6315b3fcd1335ea4e7bc8202b48ed4f9c9e83"
},
{
"name": "libglx0",
"version": "1.6.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libg/libglvnd/libglx0_1.6.0-1_arm64.deb",
"sha256": "523f9b71f75e48ae605d8ef298a4b03ade26ade9a808a85329a3bd82a54b9b0d"
},
{
"name": "libmd0",
"version": "1.0.4-2",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libm/libmd/libmd0_1.0.4-2_arm64.deb",
"sha256": "99a8c7dd591fae9fb37d8bf8dfdffa850e207fa405b3198c5b24711a5f972381"
},
{
"name": "libpng-dev",
"version": "1.6.39-2+deb12u5",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libp/libpng1.6/libpng-dev_1.6.39-2+deb12u5_arm64.deb",
"sha256": "f02dc017801713dfd11aaa7e72d705f747570e029fd242c29af072d64474ddfc"
},
{
"name": "libpng16-16",
"version": "1.6.39-2+deb12u5",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libp/libpng1.6/libpng16-16_1.6.39-2+deb12u5_arm64.deb",
"sha256": "69aba3963ddfb11b98e5bf4b0d022f76b797436568884b10f2da32e0f4b8c2dd"
},
{
"name": "libpthread-stubs0-dev",
"version": "0.4-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libp/libpthread-stubs/libpthread-stubs0-dev_0.4-1_arm64.deb",
"sha256": "acd58ed5d26d3f4d4b0856ebec6bc43f9c4357601a532eee0d2de839a8b8952e"
},
{
"name": "libuuid1",
"version": "2.38.1-5+deb12u3",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/u/util-linux/libuuid1_2.38.1-5+deb12u3_arm64.deb",
"sha256": "3b2d19df0f3190108cf54228c4cfc822226c06d8f3615a5ab16a7dffb1f58aed"
},
{
"name": "libwayland-client0",
"version": "1.21.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/w/wayland/libwayland-client0_1.21.0-1_arm64.deb",
"sha256": "ae390cc04c2eb1de90b9a6373505b22c730ada5e72daa50c507b7f99c12faf06"
},
{
"name": "libwayland-cursor0",
"version": "1.21.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/w/wayland/libwayland-cursor0_1.21.0-1_arm64.deb",
"sha256": "8c8d1a3942bc3fc9dd3ea7c679c1a314e59cdaaa700883d54d1bb3ec89db256b"
},
{
"name": "libwayland-dev",
"version": "1.21.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/w/wayland/libwayland-dev_1.21.0-1_arm64.deb",
"sha256": "932405c58195d299495230792e374ad304adadf3d3ffdc07eda3466b756adc33"
},
{
"name": "libwayland-egl1",
"version": "1.21.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/w/wayland/libwayland-egl1_1.21.0-1_arm64.deb",
"sha256": "c08124a4d9af24f058b45c88867a84697882e755ea94965795d152fe26fe57c9"
},
{
"name": "libwayland-server0",
"version": "1.21.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/w/wayland/libwayland-server0_1.21.0-1_arm64.deb",
"sha256": "4d99e7e0503fdaa999e67d47d8612c0465e775eafa47819573da50bdb09064f2"
},
{
"name": "libx11-6",
"version": "2:1.8.4-2+deb12u2",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libx11/libx11-6_1.8.4-2+deb12u2_arm64.deb",
"sha256": "d1d533e983582282a9ea82c87ac5ce715a9b67bd6d1acbd2439a11c63c36549b"
},
{
"name": "libx11-dev",
"version": "2:1.8.4-2+deb12u2",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libx11/libx11-dev_1.8.4-2+deb12u2_arm64.deb",
"sha256": "34bfc833561de983cfb4475523fedc13abb4faee14a876300de659591779add8"
},
{
"name": "libx11-xcb1",
"version": "2:1.8.4-2+deb12u2",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libx11/libx11-xcb1_1.8.4-2+deb12u2_arm64.deb",
"sha256": "21c7e6f19909bb1e02bb3c2089789791858c54d37e86cef9d7872782c1cb711e"
},
{
"name": "libxau-dev",
"version": "1:1.0.9-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxau/libxau-dev_1.0.9-1_arm64.deb",
"sha256": "21db3761a8f388fc83707c00fac645d4332737a859dd727571e1e6ede003b048"
},
{
"name": "libxau6",
"version": "1:1.0.9-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxau/libxau6_1.0.9-1_arm64.deb",
"sha256": "36c2bf400641a80521093771dc2562c903df4065f9eb03add50d90564337ea6c"
},
{
"name": "libxcb1",
"version": "1.15-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxcb/libxcb1_1.15-1_arm64.deb",
"sha256": "041d9a68415c3ccf3ce8f4f8b88e4bbfb5dc1f0d97013c6ef8423e620ea50f84"
},
{
"name": "libxcb1-dev",
"version": "1.15-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxcb/libxcb1-dev_1.15-1_arm64.deb",
"sha256": "87b5c3f1bb130727df68295ecfaadc305ee10c150afeb1a183e95b9150e18db5"
},
{
"name": "libxdmcp-dev",
"version": "1:1.1.2-3",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxdmcp/libxdmcp-dev_1.1.2-3_arm64.deb",
"sha256": "6fd0bc51f3a4e6b7f944f24f15524a4c4ba68a4b0aa136c18bdb96a2d36988f2"
},
{
"name": "libxdmcp6",
"version": "1:1.1.2-3",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxdmcp/libxdmcp6_1.1.2-3_arm64.deb",
"sha256": "e92569ac33247261aa09adfadc34ced3994ac301cf8b58de415a2d5dbf15ccfc"
},
{
"name": "libxext-dev",
"version": "2:1.3.4-1+b1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxext/libxext-dev_1.3.4-1+b1_arm64.deb",
"sha256": "07f5e3efeba9564071885b2d0d2ba277692fa309a9f05ef862688af0022b1fcf"
},
{
"name": "libxext6",
"version": "2:1.3.4-1+b1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxext/libxext6_1.3.4-1+b1_arm64.deb",
"sha256": "5e9c0ad606eb4674c645fe8e0e64330c47d2729f7a59ed569848610efd5d5b62"
},
{
"name": "libxfixes3",
"version": "1:6.0.0-2",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxfixes/libxfixes3_6.0.0-2_arm64.deb",
"sha256": "d47bda8fed01b19b41d503e2df05d9166c58e30e2376f2f8784ceb7a834befe6"
},
{
"name": "libxi6",
"version": "2:1.8-1+b1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxi/libxi6_1.8-1+b1_arm64.deb",
"sha256": "b26383c9929d8bfba051eee22301e064d17039ed022bbf31990feb0d7a03b36c"
},
{
"name": "libxrandr2",
"version": "2:1.5.2-2+b1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxrandr/libxrandr2_1.5.2-2+b1_arm64.deb",
"sha256": "f0bc7f79fee182caae176652fdb1bf349d13b9591b10ad4dc1c896521da8e49f"
},
{
"name": "libxrender1",
"version": "1:0.9.10-1.1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/libx/libxrender/libxrender1_0.9.10-1.1_arm64.deb",
"sha256": "f260193deb4eaf0b410a1c61e1f84804366ee3372b8bad9f38005f7dbcd89aae"
},
{
"name": "x11proto-dev",
"version": "2022.1-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/x/xorgproto/x11proto-dev_2022.1-1_all.deb",
"sha256": "3cab66a6591774188a568f9b54c4e7956f18da76e0e0fc4a779db5f6bcc3f148"
},
{
"name": "xtrans-dev",
"version": "1.4.0-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/x/xtrans/xtrans-dev_1.4.0-1_all.deb",
"sha256": "9ce1af9464faee0c679348dd11cdf63934c12e734a64e0903692b0cb5af38e06"
},
{
"name": "zlib1g",
"version": "1:1.2.13.dfsg-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/z/zlib/zlib1g_1.2.13.dfsg-1_arm64.deb",
"sha256": "52b8b8a145bbe1956bba82034f77022cbef0c3d0885c9e32d9817a7932fe1913"
},
{
"name": "zlib1g-dev",
"version": "1:1.2.13.dfsg-1",
"url": "https://snapshot.debian.org/archive/debian/20260901T000000Z/pool/main/z/zlib/zlib1g-dev_1.2.13.dfsg-1_arm64.deb",
"sha256": "afb60f0bae432f2f0edfe2d674e99c1a13a147c9aa2b52f2f23e3df19ece76f5"
}
]
}
@@ -0,0 +1,103 @@
{
"tested_date_utc": "2026-10-04",
"host": "Ubuntu 24.04 Linux x64",
"zig_version": "0.14.1",
"sources": {
"skiasharp_version": "4.150.1",
"skiasharp_revision": "c3e4f4c20e1f23ab74d31a8838a5bd6dc55365f2",
"angle_branch": "7922",
"angle_revision": "7e08726e32026a0bbabd6ec8a1a90f5ab533ed66",
"skia_revision": "0aa2d542e833ffd1d4d1b68a5152375e7f65ce11"
},
"target_runtime_tested": false,
"docker_build_tested": false,
"cold_source_preparation_tested": false,
"avalonia_nativeaot_tested": false,
"targets": {
"win-x64": {
"six_archives_compiled": true,
"raster_harfbuzz_link": "passed",
"egl_gles_link": "passed",
"archives_sha256": {
"libANGLE.a": "9b4af0208fef7773dc91f684cdf676b156f48eb40821c99eb55b531f4b262214",
"libEGL.a": "dc1d8568d8d3bab0d5e6956f97db88a1d3c5887a5f2437dfd29fa5abb2a48c97",
"libGLESv2.a": "a78c019c732a356691b849d8f632dab9f1c3254452ef98fc3ed963fd33e7049c",
"libHarfBuzzSharp.a": "71602aa223348bc34f754438bd2f9b90ba025547c8305b0ad45e23fbd4d0a882",
"libSkiaSharp.a": "3aa2b79953dfcd3b8dde7996701c3a29878e61fb589a6398f0cccacd1c33f4f2",
"libskia.a": "40418692d55d26e55f1882f8386ce341410a0712ae1691d47a26b3033bd7e9a8"
},
"executables_sha256": {
"smoke-angle.exe": "bc54570c5f9cdca0a28e2f9ceb2bdb1a118cabfdf6516557d1d31fd777a7d4c5",
"smoke-raster.exe": "289f963e2180bd12cdca298b931451ebc7698bef71930318899adc4505fbccef"
}
},
"win-x86": {
"six_archives_compiled": true,
"raster_harfbuzz_link": "passed",
"egl_gles_link": "passed",
"archives_sha256": {
"libANGLE.a": "27f715956b9625ffca27ebb10e4135d173ed03970745c257fe6437fd8db23daf",
"libEGL.a": "ddab449877aa244333f43c4a79705d3c1347c5cfae778c46ca707cd78e9ed8ed",
"libGLESv2.a": "adf90968b2a8984c9bceefbbce1edacb1a06038fdc9b2bfc962e9227a9c947bd",
"libHarfBuzzSharp.a": "8483f2e5cc92561884163f317f496a2e4b6b61242774176fe8b6370bbc54c695",
"libSkiaSharp.a": "565c25b03b4f574a7db5dca98327b5f7b8eea07c1f0dab5e09d6c731ad71fd29",
"libskia.a": "97e086493216fef2d372f555c62c2fbaf28e4d6a61398ec37334164408bcc31f"
},
"executables_sha256": {
"smoke-angle.exe": "5e3a6a7951f038fa1e1a9889e8f3212de285a9464b4b722700da259b1bb9e7bb",
"smoke-raster.exe": "9b1b4dbc3686caa89ae03cb19c5d29b3cde16ab8c0381f7c1c8b339a8f5169e5"
}
},
"win-arm64": {
"six_archives_compiled": true,
"raster_harfbuzz_link": "passed",
"egl_gles_link": "passed",
"archives_sha256": {
"libANGLE.a": "d496f595573d62e64ad1fad9339f64249ddd3904d37146ad3d1e1c58b032d797",
"libEGL.a": "8f87692e53a3843eb8131e51f0cbc03c7eef02039d22cc25348ecacbc12028d7",
"libGLESv2.a": "cea510c2d0bbed66bd67d0070953408da23a39a0e5a3be959ed4cec6069973cb",
"libHarfBuzzSharp.a": "662f4174d0bc0ee0760fdeacebb7ce8f187118b524239a745058547d4c25ca10",
"libSkiaSharp.a": "17d4ed43351f0b97b6c816de41a3e2469dd42d4df42acc6201fd30a75b8e25df",
"libskia.a": "52d4b8ec673881d4beb729580eac867696ca5fda4ad4c2a498f33cd8b915c76b"
},
"executables_sha256": {
"smoke-angle.exe": "68367ceba8053f75b841d0e2b7ab6bc8f613836b91ebd13e463fe6d261b245a9",
"smoke-raster.exe": "ce758159e371ae94504ae1502dbe26034ea1c3789f33f71a0f65640991578dfb"
}
},
"osx-x64": {
"six_archives_compiled": true,
"raster_harfbuzz_link": "passed",
"egl_gles_link": "passed",
"archives_sha256": {
"libANGLE.a": "353b6ad07961f94cdbde8f7901fc924fbb50600156da8194ec7dd5d9c9d96115",
"libEGL.a": "6ea3c6d73e1f6a3785fdd941c37e50c7d00f3f5c136edf648f27243e5698d517",
"libGLESv2.a": "e3bbb289e2be771c498eae0c4037e3d9058a0a52e100dd5b6622de42f00ecb7c",
"libHarfBuzzSharp.a": "c80b4156937b0a63ff649d7ef9ee520e342ee6f6d556a65a42e37095e91e1157",
"libSkiaSharp.a": "2a1e5d7d7737921cdb6a9679630fb3068ce1d2eecd7300ec7747898bb8132d39",
"libskia.a": "8062a85f7f5ded8f67c19db06b42c6792a526d5856c4bae467fb46d182992315"
},
"executables_sha256": {
"smoke-angle": "1930720daf83d6a63268427b5c1a700a46fa6cf8edd93821133224fb1d456522",
"smoke-raster": "6cb98cb854b52f94339eb225422d511b6e11abc9e5299658b455352f332139c4"
}
},
"osx-arm64": {
"six_archives_compiled": true,
"raster_harfbuzz_link": "passed",
"egl_gles_link": "passed",
"archives_sha256": {
"libANGLE.a": "3459ece2b66c8cbb096bf20016a40d4d463224ff7a0b4e29cab44c578daf1665",
"libEGL.a": "6011625f7ac8bf467e3135588a9a30e472f55fec6de3834b1b472deed4627d15",
"libGLESv2.a": "2c4e990ddc67f98abcc09401fa5541386cbe80458581c6fd621fd379a8541835",
"libHarfBuzzSharp.a": "3802662600cca36985997d24187c3bc06e1a20c258fc260778eecd34a5d791f9",
"libSkiaSharp.a": "e5bf6468713228ab9386d6f31f6556aed98a9cbc307b4be1fbbd61644f97658b",
"libskia.a": "44e3515fdf0f09c8621b35c37c23d4441d34a831d42b88391811ad8fdff710da"
},
"executables_sha256": {
"smoke-angle": "f19386a0d04af9a89f8ec70df6f3a1205747cfc2761efd86c4e781bcf0818018",
"smoke-raster": "954dde21bf79234fa0abc30b6e5307c88558996b7777f0d459693a3588b1cc43"
}
}
}
}
@@ -0,0 +1,56 @@
{
"date_utc": "2026-10-04",
"compiler": "Zig 0.14.1 / Clang 19",
"cross_configuration_checks": {
"2.88.9/win-x64": 0,
"2.88.9/win-x86": 0,
"2.88.9/win-arm64": 0,
"2.88.9/osx-x64": 0,
"2.88.9/osx-arm64": 0,
"3.119.1/win-x64": 0,
"3.119.1/win-x86": 0,
"3.119.1/win-arm64": 0,
"3.119.1/osx-x64": 0,
"3.119.1/osx-arm64": 0,
"4.150.1/win-x64": 0,
"4.150.1/win-x86": 0,
"4.150.1/win-arm64": 0,
"4.150.1/osx-x64": 0,
"4.150.1/osx-arm64": 0
},
"native_linux_configuration_checks": {
"2.88.9/x64": "passed",
"2.88.9/arm64": "passed",
"3.119.1/x64": "passed",
"3.119.1/arm64": "passed",
"4.150.1/x64": "passed",
"4.150.1/arm64": "passed"
},
"new_full_build_checks": {
"2.88.9": {
"target": "win-x64",
"three_archives": "passed",
"raster_harfbuzz_executable_link": "passed",
"sha256": {
"libskia.a": "d972f868e4910cee774d592b09e3e52f65657ec3b10a1c38c26e6625e998196e",
"libSkiaSharp.a": "e7f22c39ce570fa74988e13a288e00646cf1b08e0be82e60a6b589bab149a8fd",
"libHarfBuzzSharp.a": "e7e117c25a16f9770f0953a260441d920b5a1e27b8c52457429f03ddacbe8855",
"smoke-raster.exe": "6a8ab77adc1444933757f702aa4dab10716a60a284ffa4777745493443909f9d"
}
},
"3.119.1": {
"target": "win-x64",
"three_archives": "passed",
"raster_harfbuzz_executable_link": "passed",
"sha256": {
"libskia.a": "d895266910b2fc8a6a72d56715ddd0b50e1e9752b184d3b99a31b8ca6614451a",
"libSkiaSharp.a": "544685511adf5b29eac2df771ef5088ba271fb570614671d0bde68e841ac3b32",
"libHarfBuzzSharp.a": "6ac05af0bb31b42af86f003e4eb70db4c4eeb021b5a438282bbd182db0dba100",
"smoke-raster.exe": "80cfda94712bd1df0671ce96fb27a174053451557d99ab542f148ac45a951532"
}
}
},
"runtime_tests": false,
"docker_cold_build_tested": false,
"4.150.1": "Previous five-target full archive/link checks are in local-cross-validation.json; updated win-x64 link test also passed."
}
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env python3
"""Export verified Zig archives in the layout consumed by the NuGet package."""
import argparse,json,shutil,hashlib
from pathlib import Path
p=argparse.ArgumentParser();p.add_argument('--input',type=Path,required=True);p.add_argument('--output',type=Path,required=True);p.add_argument('--rid',required=True)
a=p.parse_args();manifest=json.loads((a.input/'cross-build.json').read_text())
if manifest['target']!=a.rid or not manifest.get('link_tests','').startswith('passed'):
raise SystemExit('Only successfully linked target archives may be packaged')
names={'libskia.a':'skia.lib','libSkiaSharp.a':'SkiaSharp.lib','libHarfBuzzSharp.a':'libHarfBuzzSharp.lib','libANGLE.a':'libANGLE_static.lib','libGLESv2.a':'libGLESv2_static.lib','libEGL.a':'libEGL_static.lib'} if a.rid.startswith('win') else {'libskia.a':'libskia.a','libSkiaSharp.a':'libSkiaSharp.a','libHarfBuzzSharp.a':'libHarfBuzzSharp.a','libANGLE.a':'libANGLE_static.a','libGLESv2.a':'libGLESv2_static.a','libEGL.a':'libEGL_static.a'}
a.output.mkdir(parents=True,exist_ok=True)
for source,destination in names.items():
path=a.input/source
if hashlib.sha256(path.read_bytes()).hexdigest()!=manifest['archives'][source]:raise SystemExit('Archive checksum mismatch: '+source)
shutil.copy2(path,a.output/destination)
runtime=a.input/'zig-runtime'
if not runtime.is_dir() or not [p for p in runtime.iterdir() if p.suffix in ('.a','.lib')]:raise SystemExit('Zig C++/compiler runtime archives were not captured')
(a.output/'zig-runtime').mkdir(exist_ok=True)
for path in runtime.iterdir():
if path.suffix not in ('.a','.lib'):continue
dest=path.stem+'.lib' if a.rid.startswith('win') else path.name
shutil.copy2(path,a.output/'zig-runtime'/dest)
if a.rid=='win-x86':
path=a.input/'skia_x86_stdcall_thunks.lib'
if not path.is_file():raise SystemExit('x86 stdcall thunks are required')
shutil.copy2(path,a.output/path.name)
shutil.copy2(a.input/'cross-build.json',a.output/'zig-build.json')
print('Packaged',a.rid)
@@ -0,0 +1,2 @@
# Unified diffs contain space-prefixed empty context lines.
*.patch -whitespace
@@ -0,0 +1,28 @@
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -427,7 +427,8 @@
ldflags = [ "-Wl,--build-id" ]
}
-_use_copy_compiler_dll = angle_has_build && is_win
+declare_args() { angle_copy_compiler_dll = true }
+_use_copy_compiler_dll = angle_has_build && is_win && angle_copy_compiler_dll
if (_use_copy_compiler_dll) {
copy("copy_compiler_dll") {
@@ -1534,6 +1535,7 @@
}
angle_static_library("libGLESv2_static") {
+ complete_static_lib = true
sources = libglesv2_sources
public_deps = [ ":libGLESv2_thin_static" ]
@@ -1652,6 +1654,7 @@
}
libEGL_template("libEGL_static") {
+ complete_static_lib = true
target_type = "angle_static_library"
public_configs = [ ":angle_static_config" ]
deps = [ ":libGLESv2_static" ]
@@ -0,0 +1,20 @@
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -584,7 +584,7 @@
}
if (!defined(use_libcxx_modules)) {
- use_libcxx_modules = is_clang
+ use_libcxx_modules = is_clang && !(is_win && host_os == "linux")
}
if (filter_include(
@@ -715,7 +715,7 @@
}
if (!defined(use_libcxx_modules)) {
- use_libcxx_modules = is_clang
+ use_libcxx_modules = is_clang && !(is_win && host_os == "linux")
}
if (filter_include(
@@ -0,0 +1,64 @@
diff --git a/DEPS b/DEPS
index 8ba99a6..1a5e1a5 100644
--- a/DEPS
+++ b/DEPS
@@ -768,9 +768,4 @@ deps = {
},
- 'third_party/catapult': {
- 'url': Var('chromium_git') + '/catapult.git' + '@' + Var('catapult_revision'),
- 'condition': 'not build_with_chromium',
- },
-
# Cherry is a dEQP/VK-GL-CTS management GUI written in Go. We use it for viewing test results.
'third_party/cherry': {
@@ -795,9 +790,4 @@ deps = {
- 'third_party/dawn': {
- 'url': Var('dawn_git') + '/dawn.git' + '@' + Var('dawn_revision'),
- 'condition': 'checkout_angle_dawn_deps and not build_with_chromium'
- },
-
'third_party/depot_tools': {
'url': Var('chromium_git') + '/chromium/tools/depot_tools.git@94e89b10b92cc9d6e58fc8d1b6474b7d29e8a114',
@@ -875,9 +865,4 @@ deps = {
},
- 'third_party/llvm/src': {
- 'url': Var('chromium_git') + '/external/github.com/llvm/llvm-project@67790d3fb06b184b7be9c4d3e36ab01f0ac4198e',
- 'condition': 'checkout_angle_cl_deps and not build_with_chromium',
- },
-
'third_party/llvm-build/Release+Asserts': {
'dep_type': 'gcs',
@@ -1217,9 +1202,4 @@ deps = {
},
- 'third_party/SwiftShader': {
- 'url': Var('swiftshader_git') + '/SwiftShader@f3e464b1e56795940f826a972b39e19bd9f6ac6c',
- 'condition': 'not build_with_chromium',
- },
-
'third_party/turbine/cipd': {
'packages': [
@@ -1233,8 +1213,4 @@ deps = {
},
- 'third_party/VK-GL-CTS/src': {
- 'url': Var('chromium_git') + '/external/github.com/KhronosGroup/VK-GL-CTS' + '@' + Var('vk_gl_cts_revision'),
- },
-
'third_party/vulkan-deps': {
'url': Var('chromium_git') + '/vulkan-deps@f2b9fece7c6772c09379b3a6938dbcd2573f2a3e',
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index 710bba9..33d4a64 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -881,5 +881,5 @@ const TConstantUnion *TIntermAggregate::getConstantValue() const
angle::base::CheckedNumeric<size_t> checkedArraySize = elementSize;
checkedArraySize *= getOutermostArraySize();
- constArray = new TConstantUnion[checkedArraySize.ValueOrDie()];
+ constArray = new TConstantUnion[static_cast<size_t>(checkedArraySize.ValueOrDie())];
size_t elementOffset = 0u;
@@ -0,0 +1,21 @@
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1523,7 +1523,18 @@
public_deps = [ ":libANGLE" ]
}
+angle_static_library("libANGLE_static") {
+ complete_static_lib = true
+ public_deps = [ ":libANGLE" ]
+}
+
+angle_static_library("libANGLE_with_capture_static") {
+ complete_static_lib = true
+ public_deps = [ ":libANGLE_with_capture" ]
+}
+
angle_static_library("libGLESv2_static") {
+
sources = libglesv2_sources
public_deps = [ ":libGLESv2_thin_static" ]
}
@@ -0,0 +1,15 @@
--- a/build/mac/find_sdk.py
+++ b/build/mac/find_sdk.py
@@ -1,3 +1,12 @@
+import os,sys,json
+if sys.platform == 'linux' and os.environ.get('STATICLINK_MACOS_SDK'):
+ sdk=os.environ['STATICLINK_MACOS_SDK']
+ if '--print_sdk_path' in sys.argv:print('//'+str(__import__('pathlib').Path.cwd().relative_to(__import__('pathlib').Path(__file__).resolve().parents[2]))+'/sdk/xcode_links/MacOSX15.5.sdk')
+ if '--print_bin_path' in sys.argv:print(os.environ['STATICLINK_DARWIN_TOOLS'])
+ if '--print_sdk_build' in sys.argv:print('24F74')
+ print('15.5')
+ sys.exit(0)
+
#!/usr/bin/env python3
# Copyright 2012 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
@@ -0,0 +1,38 @@
--- a/build/toolchain/gcc_toolchain.gni
+++ b/build/toolchain/gcc_toolchain.gni
@@ -369,6 +369,35 @@
outputs = [ output ]
}
+ if (current_os == "mac") {
+ tool("objc") {
+ output = "$object_subdir/{{source_name_part}}.o"
+ depfile = "$output.d"
+ precompiled_header_type = "gcc"
+
+ # {{output}} may contain .dwo file, so use $output instead of {{output}}
+ # in command.
+ command = "$coverage_wrapper$cc $md -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_objc}}${extra_cppflags}${extra_cflags}${module_name_flag} -c {{source}} -o $output"
+ depsformat = "gcc"
+ description = "OBJC {{output}}"
+ outputs = [ output ]
+ }
+
+ tool("objcxx") {
+ output = "$object_subdir/{{source_name_part}}.o"
+ depfile = "$output.d"
+ precompiled_header_type = "gcc"
+
+ # {{output}} may contain .dwo file, so use $output instead of {{output}}
+ # in command.
+ command = "$coverage_wrapper$cxx $md -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_objcc}}${extra_cppflags}${extra_cxxflags} {{module_deps}}${module_name_flag} -c {{source}} -o $output"
+ depsformat = "gcc"
+ description = "OBJCXX {{output}}"
+ outputs = [ output ]
+ }
+
+ }
+
tool("cxx_module") {
depfile = "{{output}}.d"
@@ -0,0 +1,14 @@
--- a/build/config/apple/sdk_info.py
+++ b/build/config/apple/sdk_info.py
@@ -1,3 +1,11 @@
+import os,sys,json
+if sys.platform == 'linux' and os.environ.get('STATICLINK_MACOS_SDK'):
+ sdk=os.environ['STATICLINK_MACOS_SDK']
+ sdk='//'+str(__import__('pathlib').Path.cwd().relative_to(__import__('pathlib').Path(__file__).resolve().parents[3]))+'/sdk/xcode_links/MacOSX15.5.sdk'
+ values={'xcode_version':'1640','xcode_version_int':1640,'xcode_build':'16F6','sdk_path':sdk,'sdk_version':'15.5','sdk_build':'24F74','sdk_platform_path':sdk,'toolchains_path':os.environ['STATICLINK_DARWIN_TOOLS']}
+ for k,v in values.items():print(k+'='+json.dumps(v))
+ sys.exit(0)
+
#!/usr/bin/env python3
# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
@@ -0,0 +1,11 @@
--- a/src/xps/SkXPSDevice.cpp
+++ b/src/xps/SkXPSDevice.cpp
@@ -337,7 +337,7 @@
return true;
}
-static HRESULT subset_typeface(const SkXPSDevice::TypefaceUse& current) {
+HRESULT subset_typeface(const SkXPSDevice::TypefaceUse& current) {
//The CreateFontPackage API is only supported on desktop, not in UWP
#if defined(SK_WINUWP) || defined(SK_BUILD_FOR_WINRT) || defined(SK_BUILD_FOR_NANOSERVER)
return E_NOTIMPL;
+81
View File
@@ -0,0 +1,81 @@
#!/usr/bin/env python3
"""Compile target objects and SDK API probes; this does not build release libraries."""
import argparse
import json
import pathlib
import subprocess
import tempfile
TARGETS = (
"x86-windows-gnu", "x86_64-windows-gnu", "aarch64-windows-gnu",
"x86-windows-msvc", "x86_64-windows-msvc", "aarch64-windows-msvc",
"x86_64-macos", "aarch64-macos",
)
SOURCES = {
"plain": "int answer(void) { return 42; }\n",
"cpp": '#include <string>\nextern "C" int answer(void) { std::string s="test"; return int(s.size()); }\n',
"windows": '''#include <windows.h>
#include <dwrite_3.h>
#include <xpsobjectmodel.h>
// These call shapes are required by Skia 4.150.1's DirectWrite paint backend.
HRESULT paint_child(IDWritePaintReader* reader, DWRITE_PAINT_ELEMENT* element) {
return reader->MoveToFirstChild(element);
}
void paint_color(IDWritePaintReader* reader, DWRITE_COLOR_F color) {
reader->SetTextColor(color);
}
''',
"macos": '''#include <ApplicationServices/ApplicationServices.h>
#import <Metal/Metal.h>
int answer(void) { return sizeof(CFIndex); }
''',
}
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--zig", default="zig")
parser.add_argument("--output", type=pathlib.Path, required=True)
parser.add_argument("--target", choices=TARGETS, action="append")
parser.add_argument("--macos-sdk", type=pathlib.Path)
parser.add_argument("--windows-sdk", type=pathlib.Path,
help="An xwin splat containing crt/include and sdk/include")
args = parser.parse_args()
output = args.output.resolve()
output.mkdir(parents=True, exist_ok=True)
version = subprocess.check_output([args.zig, "version"], text=True).strip()
results = {"zig_version": version, "targets": {}}
with tempfile.TemporaryDirectory(prefix="staticlink-probe-") as temporary:
source_dir = pathlib.Path(temporary)
for name, source in SOURCES.items():
suffix = ".mm" if name == "macos" else ".cpp"
(source_dir / (name + suffix)).write_text(source)
for target in args.target or TARGETS:
destination = output / target
destination.mkdir(exist_ok=True)
flags = []
if "macos" in target and args.macos_sdk:
sdk = args.macos_sdk.resolve()
flags += ["-isysroot", str(sdk), "-F", str(sdk / "System/Library/Frameworks")]
if target.endswith("windows-msvc") and args.windows_sdk:
sdk = args.windows_sdk.resolve()
for include in ("crt/include", "sdk/include/ucrt", "sdk/include/shared", "sdk/include/um"):
flags += ["-isystem", str(sdk / include)]
target_results = {}
for name in ("plain", "cpp", "windows" if "windows" in target else "macos"):
suffix = ".mm" if name == "macos" else ".cpp"
command = [args.zig, "c++", "-target", target, "-std=c++20", *flags,
"-c", str(source_dir / (name + suffix)),
"-o", str(destination / (name + ".o"))]
result = subprocess.run(command, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, text=True)
(destination / (name + ".log")).write_text(result.stdout)
target_results[name] = {"exit_code": result.returncode, "command": command}
print(target, name, "PASS" if result.returncode == 0 else "FAIL", flush=True)
results["targets"][target] = target_results
(output / "results.json").write_text(json.dumps(results, indent=2) + "\n")
return int(any(test["exit_code"] for tests in results["targets"].values() for test in tests.values()))
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,68 @@
{
"date": "2026-10-04",
"zig": "0.14.1",
"versions": [
"3.119.2",
"3.119.4",
"4.150.3",
"4.150.5",
"4.153.1"
],
"configuration": {
"passed": 45,
"targets_per_version": 9,
"full_build": false
},
"full_skia_build_and_executable_link": {
"win-x64": [
"3.119.2",
"3.119.4",
"4.150.3",
"4.150.5",
"4.153.1"
],
"win-x86": [
"3.119.4"
],
"linux-x64": [
"3.119.4"
],
"linux-arm64": [
"3.119.4"
],
"osx-arm64": [
"4.153.1"
]
},
"angle": {
"linux-x64": "3.119.4: six archives compiled and both executable links passed",
"win-x86": "3.119.4: fixed ANGLE archives reused; both executable links passed"
},
"execution": {
"linux-x64": "64 raster pixels and 2 UTF-8 codepoints passed",
"linux-arm64": "same raster/UTF-8 test passed under QEMU",
"gpu": "not validated; Linux ANGLE probe lacked a display"
},
"avalonia_native": {
"versions": [
"11.3.14",
"12.1.0"
],
"targets": [
"osx-x64",
"osx-arm64"
],
"compilation": "all four passed",
"executable_link": "all four passed against macOS SDK system libc++",
"execution": "not run"
},
"not_validated": [
"complete Debian Docker image build",
"all five releases full nine-RID build",
"Windows/macOS runtime",
"full NativeAOT application",
"GitHub Actions execution",
"NuGet publication"
],
"environment_note": "Local builds ran on the Linux host with pinned cross tools, not inside Docker. Disk exhaustion required resumptions; it is not recorded as source incompatibility."
}
+30
View File
@@ -0,0 +1,30 @@
target_os = "linux"
target_cpu = "@CPU@"
is_official_build = true
is_static_skiasharp = true
skia_enable_tools = false
skia_enable_ganesh = true
skia_enable_pdf = false
skia_enable_skottie = false
skia_use_dng_sdk = false
skia_use_fontconfig = true
skia_use_freetype = true
skia_use_harfbuzz = false
skia_use_icu = false
skia_use_piex = false
skia_use_sfntly = false
skia_use_system_expat = false
skia_use_system_freetype2 = false
skia_use_system_libjpeg_turbo = false
skia_use_system_libpng = false
skia_use_system_libwebp = false
skia_use_system_zlib = false
skia_use_vulkan = false
skia_use_xps = false
extra_cflags_cc = [ "-frtti", "-pthread" ]
cc = "@CC@"
cxx = "@CXX@"
ar = "@AR@"
extra_cflags = [ "-DSKIA_C_DLL", "-DHAVE_SYSCALL_GETRANDOM", "-DXML_DEV_URANDOM" ]
# Standalone SkiaSharp excludes the Chromium PartitionAlloc dependency.
skia_use_partition_alloc = false
+27
View File
@@ -0,0 +1,27 @@
target_os = "mac"
target_cpu = "@CPU@"
is_official_build = true
is_static_skiasharp = true
skia_enable_tools = false
skia_enable_ganesh = true
skia_use_metal = true
skia_enable_pdf = false
skia_enable_skottie = false
skia_use_dng_sdk = false
skia_use_fontconfig = false
skia_use_freetype = false
skia_use_harfbuzz = false
skia_use_icu = false
skia_use_piex = false
skia_use_sfntly = false
skia_use_system_expat = false
skia_use_system_libjpeg_turbo = false
skia_use_system_libpng = false
skia_use_system_libwebp = false
skia_use_system_zlib = false
skia_use_vulkan = false
skia_use_xps = false
extra_cflags = [ "-DSKIA_C_DLL" ]
extra_cflags_cc = [ "-frtti" ]
# Standalone SkiaSharp excludes the Chromium PartitionAlloc dependency.
skia_use_partition_alloc = false
+28
View File
@@ -0,0 +1,28 @@
target_os = "win"
target_cpu = "@CPU@"
is_official_build = true
is_static_skiasharp = true
is_clang = true
skia_enable_tools = false
skia_enable_ganesh = true
skia_enable_pdf = false
skia_enable_skottie = false
skia_use_dng_sdk = false
skia_use_fontconfig = false
skia_use_freetype = false
skia_use_harfbuzz = false
skia_use_icu = false
skia_use_piex = false
skia_use_sfntly = false
skia_use_system_expat = false
skia_use_system_freetype2 = false
skia_use_system_libjpeg_turbo = false
skia_use_system_libpng = false
skia_use_system_libwebp = false
skia_use_system_zlib = false
skia_use_vulkan = false
skia_use_xps = true
extra_cflags = [ "-DSKIA_C_DLL" ]
extra_cflags_cc = [ "/GR" ]
# Standalone SkiaSharp excludes the Chromium PartitionAlloc dependency.
skia_use_partition_alloc = false
+123
View File
@@ -0,0 +1,123 @@
"""Discover Skia GN capabilities; keep version policy out of the build driver."""
import json
from pathlib import Path
import re
import subprocess
def repair_xps(source):
path = source / 'src/xps/SkXPSDevice.cpp'
header = source / 'src/xps/SkXPSDevice.h'
if not path.exists() or not header.exists():
return 'absent'
text = path.read_text()
if not re.search(r'friend\s+HRESULT\s+subset_typeface\s*\(', header.read_text()):
return 'not-needed'
text, count = re.subn(r'(?m)^static HRESULT (subset_typeface\s*\()', r'HRESULT \1', text)
if count > 1:
raise RuntimeError('Ambiguous XPS helper declarations; inspect the new source layout')
if count:
path.write_text(text)
return 'repaired' if count else 'already-compatible'
def repair_skcms(source):
repaired = []
for relative in ('third_party/skcms/skcms.cc', 'modules/skcms/skcms.cc'):
path = source / relative
if not path.is_file():
continue
text = path.read_text()
def replace(match):
features = match[2]
if 'avx512f' in features.split(',') and 'evex512' not in features.split(','):
return match[1] + features + ',evex512' + match[3]
return match[0]
updated = re.sub(r'(#pragma clang attribute push\(__attribute__\(\(target\(")([^"]+)("\)\)\))', replace, text)
if updated != text:
path.write_text(updated)
repaired.append(relative)
# This changes only the AVX512-dispatched functions' Clang target attribute;
# the baseline CPU path and runtime dispatch remain unchanged.
return repaired
def configure(source, out, desired, gn, env):
# GN itself resolves imports, defaults and conditional declarations. Text
# searches alone can incorrectly report an option from an inactive branch.
# Apply the feature policy during discovery too: Skia's default tools build
# can otherwise demand test-only dependencies before we can list options.
bootstrap = dict(desired)
out.mkdir(parents=True, exist_ok=True)
def write(values):
(out / 'args.gn').write_text(''.join(f'{key} = {value}\n' for key, value in values.items()))
write(bootstrap)
subprocess.run([str(gn), 'gen', str(out.relative_to(source))],
cwd=source, env=env, check=True)
command = [str(gn), 'args', str(out.relative_to(source)), '--list', '--json']
result = subprocess.run(command, cwd=source, env=env, capture_output=True, text=True)
if result.returncode:
raise RuntimeError('Cannot discover Skia build arguments:\n' + result.stdout + result.stderr)
# Older GN emits warnings before the JSON array for unsupported bootstrap args.
match = re.search(r'(?m)^\[\s*\{', result.stdout)
if not match:
raise RuntimeError('GN did not return an argument list:\n' + result.stdout)
arguments = json.loads(result.stdout[match.start():])
available = {entry['name'] for entry in arguments}
values = {key: value for key, value in desired.items() if key in available}
if 'skia_enable_ganesh' in available:
values['skia_enable_ganesh'] = 'true'
elif 'skia_enable_gpu' in available:
values['skia_enable_gpu'] = 'true'
else:
raise RuntimeError('No known Skia GPU switch; refusing to silently change the graphics feature set')
required = {'target_os', 'target_cpu', 'is_static_skiasharp', 'extra_cflags', 'extra_cflags_cc'}
required |= {key for key in ('skia_use_metal', 'skia_use_xps') if desired.get(key) == 'true'}
missing = required - available
if missing:
raise RuntimeError('Skia source lacks required build capabilities: ' + ', '.join(sorted(missing)))
write(values)
subprocess.run([str(gn), 'gen', str(out.relative_to(source)), '--fail-on-unused-args'],
cwd=source, env=env, check=True)
report = {'available_arguments': sorted(available), 'selected_arguments': values,
'omitted_obsolete_arguments': sorted(set(desired) - available)}
(out / 'skia-capabilities.json').write_text(json.dumps(report, indent=2) + '\n')
return report
def parse_args(text):
# Values can include multiline lists, as used by the native Linux recipe.
assignments = list(re.finditer(r'(?m)^[ \t]*([A-Za-z_]\w*)[ \t]*=', text))
if not assignments:
raise ValueError('No GN assignments in build recipe')
return {match[1]: text[match.end():assignments[index + 1].start()
if index + 1 < len(assignments) else len(text)].strip()
for index, match in enumerate(assignments)}
def archive(source, name):
candidates = [source / (name + '.lib'), source / ('lib' + name + '.a'),
source / 'obj' / (name + '.lib'), source / 'obj' / ('lib' + name + '.a')]
matches = [path for path in candidates if path.is_file()]
if len(matches) != 1:
raise RuntimeError(f'Expected one archive for {name}; found {matches}')
return matches[0]
if __name__ == '__main__':
import argparse
import os
p = argparse.ArgumentParser(description='Configure native or cross Skia using its actual GN capabilities')
p.add_argument('--source', type=Path, required=True)
p.add_argument('--out', type=Path, required=True)
a = p.parse_args()
source, out = a.source.resolve(), a.out.resolve()
gn = source / ('bin/gn.exe' if os.name == 'nt' else 'bin/gn')
repair_xps(source)
desired = parse_args((out / 'args.gn').read_text())
compiler = desired.get('cc', 'clang-cl' if os.name == 'nt' else 'clang').strip('"')
version = subprocess.run([compiler, '--version'], capture_output=True, text=True, check=True)
match = re.search(r'clang version (\d+)', version.stdout)
if match and int(match[1]) >= 19:
repair_skcms(source)
configure(source, out, desired, gn, os.environ.copy())
+3
View File
@@ -0,0 +1,3 @@
#include <EGL/egl.h>
#include <GLES2/gl2.h>
int main(void) { EGLDisplay d = eglGetDisplay(EGL_DEFAULT_DISPLAY); EGLint a,b; if (!eglInitialize(d,&a,&b)) return 1; glClear(GL_COLOR_BUFFER_BIT); return eglTerminate(d) ? 0 : 2; }
+31
View File
@@ -0,0 +1,31 @@
#include <stdio.h>
#include <stdint.h>
#include "include/c/sk_general.h"
#include "include/c/sk_surface.h"
#include "include/c/sk_canvas.h"
#include "hb.h"
#ifndef STATICLINK_EXPECTED_MILESTONE
#error "Pass the milestone detected from this source tree"
#endif
int main(void) {
if (sk_version_get_milestone() != STATICLINK_EXPECTED_MILESTONE) return 1;
sk_imageinfo_t info = {NULL, 8, 8, RGBA_8888_SK_COLORTYPE, PREMUL_SK_ALPHATYPE};
sk_surface_t *surface = sk_surface_new_raster(&info, 0, NULL);
if (!surface) return 2;
sk_canvas_clear(sk_surface_get_canvas(surface), 0xff336699u);
uint8_t pixels[8*8*4];
if (!sk_surface_read_pixels(surface, &info, pixels, 8*4, 0, 0)) return 3;
for (int i=0; i<8*8; i++) {
if (pixels[i*4] != 0x33 || pixels[i*4+1] != 0x66 || pixels[i*4+2] != 0x99 || pixels[i*4+3] != 0xff) return 4;
}
sk_surface_unref(surface);
hb_buffer_t *buffer = hb_buffer_create();
hb_buffer_add_utf8(buffer, "A\xe4\xb8\xad", 4, 0, -1);
hb_buffer_guess_segment_properties(buffer);
unsigned length = 0;
hb_glyph_info_t *glyphs = hb_buffer_get_glyph_infos(buffer, &length);
if (length != 2 || glyphs[0].codepoint != 65 || glyphs[1].codepoint != 0x4e2d) return 5;
hb_buffer_destroy(buffer);
printf("PASS Skia=%s HarfBuzz=%s raster=64 pixels UTF8=2 codepoints\n", sk_version_get_string(), hb_version_string());
return 0;
}
+7
View File
@@ -0,0 +1,7 @@
{
"skiasharp_version": "4.150.1",
"skiasharp_revision": "c3e4f4c20e1f23ab74d31a8838a5bd6dc55365f2",
"angle_branch": "7922",
"angle_revision": "7e08726e32026a0bbabd6ec8a1a90f5ab533ed66",
"skia_revision": "0aa2d542e833ffd1d4d1b68a5152375e7f65ce11"
}
+89
View File
@@ -0,0 +1,89 @@
#!/usr/bin/env python3
"""Fetch pinned native cross-build dependencies without cloning Git history."""
import argparse
import ast
import json
import hashlib
from pathlib import Path
import re
import subprocess
import sys
# These dependencies correspond to features explicitly disabled by this recipe.
# Unknown/new dependencies stay enabled; do not infer a skip from their names.
DISABLED = {'dng_sdk', 'icu', 'dawn', 'angle2', 'swiftshader', 'emsdk'}
def evaluate(node, variables):
if isinstance(node, ast.Constant):
return node.value
if isinstance(node, ast.Dict):
return {evaluate(k, variables): evaluate(v, variables) for k, v in zip(node.keys, node.values)}
if isinstance(node, (ast.List, ast.Tuple)):
return [evaluate(n, variables) for n in node.elts]
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.Add):
return evaluate(node.left, variables) + evaluate(node.right, variables)
if isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and node.func.id == 'Var' and len(node.args) == 1:
return variables[evaluate(node.args[0], variables)]
raise ValueError('Unsupported DEPS expression: ' + ast.dump(node))
def dependencies(source):
values = {}
for node in ast.parse((source / 'DEPS').read_text()).body:
if isinstance(node, ast.Assign):
for name in node.targets:
if isinstance(name, ast.Name) and name.id in ('vars', 'deps'):
values[name.id] = evaluate(node.value, values.get('vars', {}))
if not values.get('deps'):
raise ValueError('No dependency map in DEPS')
return values['deps']
def main():
p = argparse.ArgumentParser(description=__doc__)
p.add_argument('--source', type=Path, required=True)
p.add_argument('--cache', type=Path, help='Immutable dependency checkouts shared across version profiles')
p.add_argument('--no-fetch-gn', action='store_true', help='Use an existing verified GN for a local test')
a = p.parse_args()
source = a.source.resolve()
records = {}
for relative, value in dependencies(source).items():
if not isinstance(value, str):
continue # GN/Ninja CIPD packages are handled by upstream fetch-gn.
if Path(relative).name in DISABLED:
continue
if '..' in Path(relative).parts:
raise ValueError('Dependency path escapes source: ' + relative)
link = source / relative
path = link.absolute()
if not path.is_relative_to(source):
raise ValueError('Dependency path escapes source: ' + relative)
url, revision = value.rsplit('@', 1)
if not re.fullmatch(r'[0-9a-f]{40}', revision):
raise ValueError('Dependency is not commit-pinned: ' + value)
if a.cache:
key = hashlib.sha256((url + '@' + revision).encode()).hexdigest()
cached = a.cache.resolve() / key
if link.is_symlink():
link.unlink()
if not link.exists():
link.parent.mkdir(parents=True, exist_ok=True)
link.symlink_to(cached, target_is_directory=True)
path = cached
if not (path / '.git').exists():
subprocess.run(['git', 'init', '-q', str(path)], check=True)
subprocess.run(['git', '-C', str(path), 'remote', 'add', 'origin', url], check=True)
current = subprocess.run(['git', '-C', str(path), 'rev-parse', 'HEAD'], capture_output=True, text=True)
if current.stdout.strip() != revision:
subprocess.run(['git', '-C', str(path), 'remote', 'set-url', 'origin', url], check=True)
subprocess.run(['git', '-C', str(path), 'fetch', '--depth=1', 'origin', revision], check=True)
subprocess.run(['git', '-C', str(path), 'checkout', '--detach', revision], check=True)
records[relative] = revision
if not a.no_fetch_gn:
subprocess.run([sys.executable, str(source / 'bin/fetch-gn')], cwd=source, check=True)
(source / 'native-cross-deps.json').write_text(json.dumps(records, indent=2) + '\n')
if __name__ == '__main__':
main()
@@ -0,0 +1,7 @@
{
"skiasharp_version": "2.88.9",
"skiasharp_revision": "9699cdf046a989423a5e5eca68e7fd813486d81c",
"angle_branch": "7922",
"angle_revision": "7e08726e32026a0bbabd6ec8a1a90f5ab533ed66",
"skia_revision": "4bed689c9c9eb77a120c6a9d54af6a572c85d1c2"
}
@@ -0,0 +1,7 @@
{
"skiasharp_version": "3.119.1",
"skiasharp_revision": "cc78b5933d23e6383db5d246e70db915770d55d6",
"angle_branch": "7922",
"angle_revision": "7e08726e32026a0bbabd6ec8a1a90f5ab533ed66",
"skia_revision": "40f75dc0051d141913c07c20d4c19590c7da0cb7"
}
@@ -0,0 +1,7 @@
{
"skiasharp_version": "3.119.2",
"skiasharp_revision": "2888c737ad016d584c74525e2d35db5097ea8576",
"angle_branch": "7922",
"angle_revision": "7e08726e32026a0bbabd6ec8a1a90f5ab533ed66",
"skia_revision": "927041a58f130e0dd0562ba86cb4170989ad39e9"
}
@@ -0,0 +1,7 @@
{
"skiasharp_version": "3.119.4",
"skiasharp_revision": "f568ac94dd768ef9a2f593537cfde2dd0d348ef5",
"angle_branch": "7922",
"angle_revision": "7e08726e32026a0bbabd6ec8a1a90f5ab533ed66",
"skia_revision": "7dbfc07dd33181f84e0958afb7ee805c6c769f0b"
}
@@ -0,0 +1,7 @@
{
"skiasharp_version": "4.150.1",
"skiasharp_revision": "c3e4f4c20e1f23ab74d31a8838a5bd6dc55365f2",
"angle_branch": "7922",
"angle_revision": "7e08726e32026a0bbabd6ec8a1a90f5ab533ed66",
"skia_revision": "0aa2d542e833ffd1d4d1b68a5152375e7f65ce11"
}
@@ -0,0 +1,7 @@
{
"skiasharp_version": "4.150.2",
"skiasharp_revision": "fd1fdd5239f826514651a4ada5d7bb3dcec2fb43",
"angle_branch": "7922",
"angle_revision": "7e08726e32026a0bbabd6ec8a1a90f5ab533ed66",
"skia_revision": "b70519562e2d26d3cf56286d3a13ca25152cfae4"
}
@@ -0,0 +1,7 @@
{
"skiasharp_version": "4.150.3",
"skiasharp_revision": "f8a404ff3375872d042404a29189ceb8e3001a41",
"angle_branch": "7922",
"angle_revision": "7e08726e32026a0bbabd6ec8a1a90f5ab533ed66",
"skia_revision": "eb86e4b3ee034085b62d3980b3d94629862441e6"
}
@@ -0,0 +1,7 @@
{
"skiasharp_version": "4.150.5",
"skiasharp_revision": "16f82682f756217654eb1a152cdb639e358b8976",
"angle_branch": "7922",
"angle_revision": "7e08726e32026a0bbabd6ec8a1a90f5ab533ed66",
"skia_revision": "579fa81eeed6906732e27b7d95149538584dd20b"
}
@@ -0,0 +1,7 @@
{
"skiasharp_version": "4.153.1",
"skiasharp_revision": "4783f51448f9b070dda4f87b83e941c9599e466e",
"angle_branch": "7922",
"angle_revision": "7e08726e32026a0bbabd6ec8a1a90f5ab533ed66",
"skia_revision": "45afab4f1f0921f3feb97f58cf89b136fffa85e6"
}
+69
View File
@@ -0,0 +1,69 @@
#!/usr/bin/env python3
"""Generate cdecl -> stdcall adapters using the pinned managed P/Invoke ABI."""
import argparse,re,subprocess,json
from pathlib import Path
p=argparse.ArgumentParser();p.add_argument('--source',type=Path,required=True);p.add_argument('--toolchain',type=Path,required=True);p.add_argument('--libraries',type=Path,required=True);a=p.parse_args()
files=[a.source/'binding/SkiaSharp/SkiaApi.generated.cs',a.source/'binding/HarfBuzzSharp/HarfBuzzApi.generated.cs']
text='\n'.join(x.read_text() if x.is_file() else subprocess.check_output(['git','-C',str(a.source),'show','HEAD:'+str(x.relative_to(a.source))],text=True) for x in files)
structs={}
# Generated structs use public fields; omit properties and methods.
for match in re.finditer(r'\bstruct\s+(\w+)\s*\{',text):
pos=match.end();depth=1;end=pos
while depth:
if text[end]=='{':depth+=1
if text[end]=='}':depth-=1
end+=1
block=text[pos:end-1]
structs[match[1]]=[m[1].strip() for m in re.finditer(r'^\s*public\s+(.+?)\s+\w+;\s*$',block,re.M)]
sizes={}
def layout(t):
t=re.sub(r'\b(?:ref|out|in|readonly)\b','',t).strip()
if '*' in t or t.endswith(('[]','Delegate')):return 4,4
if t in sizes:return sizes[t],4
if t in structs:raise KeyError(t)
if t in ['Int64','UInt64','long','ulong','Double','double']:return 8,4
if t in ['Int16','UInt16','short','ushort']:return 2,2
if t in ['Byte','SByte','byte','sbyte','Boolean','bool']:return 1,1
return 4,4 # enums and generated opaque pointer aliases
pending=set(structs)
while pending:
done=set()
for name in sorted(pending):
offset=0;align=1
try:
for t in structs[name]:
n,k=layout(t);offset=(offset+k-1)//k*k+n;align=max(align,k)
except KeyError:continue
sizes[name]=(offset+align-1)//align*align;done.add(name)
if not done:raise SystemExit('Unresolved managed struct layout: '+str(pending))
pending-=done
symbols=set()
for path in a.libraries.glob('lib*.a'):
result=subprocess.run(['nm','--defined-only',str(path)],capture_output=True,text=True,check=True)
symbols.update(re.findall(r'\bT\s+(_(?:sk|gr|hb)_\w+)\s*$',result.stdout,re.M))
thunks={}
def parameters(s):
result=[];depth=0;start=0
for i,c in enumerate(s):
if c in '[<(':depth+=1
elif c in ']> )'.replace(' ',''):depth-=1
elif c==',' and depth==0:result.append(s[start:i]);start=i+1
result.append(s[start:]);return [v.strip() for v in result if v.strip()]
for m in re.finditer(r'internal static (?:extern|partial)\s+.+?\s+((?:sk|gr|hb)_\w+)\s*\((.*?)\);',text,re.S):
symbol='_'+m[1]
if symbol not in symbols:continue
count=0
for param in parameters(m[2]):
param=re.sub(r'/\*.*?\*/|\[[^\]]+\]','',param).strip();typ=param.rsplit(' ',1)[0]
n,_=layout(typ);count+=(n+3)//4*4
thunks[symbol+'@'+str(count)]=(symbol,count)
if not thunks:raise SystemExit('No x86 exported APIs matched pinned managed bindings')
assembly=['.text','.set "@feat.00", 1']
for name,(symbol,count) in sorted(thunks.items()):
assembly+=['.globl "'+name+'"','"'+name+'":']+['pushl '+str(count)+'(%esp)']*(count//4)
assembly+=['calll '+symbol,'addl $'+str(count)+', %esp','retl $'+str(count)]
path=a.libraries/'skia_x86_stdcall_thunks.s';path.write_text('\n'.join(assembly)+'\n');obj=path.with_suffix('.o')
subprocess.run([str(a.toolchain/'cc'),'-c',str(path),'-o',str(obj)],check=True)
subprocess.run([str(a.toolchain/'ar'),'rcs',str(a.libraries/'skia_x86_stdcall_thunks.lib'),str(obj)],check=True)
(a.libraries/'x86-thunks.json').write_text(json.dumps({'count':len(thunks),'layouts':sizes,'thunks':thunks},indent=2)+'\n')
print('Generated',len(thunks),'x86 stdcall thunks')
+293
View File
@@ -0,0 +1,293 @@
#!/usr/bin/env python3
"""Pinned Zig compiler adapters for static-library cross-builds on Linux."""
import argparse
import hashlib
import json
import os
from pathlib import Path
import shlex
import shutil
import subprocess
import sys
import re
TARGETS = {
"linux-x64": "x86_64-linux-gnu.2.36.0", "linux-arm64": "aarch64-linux-gnu.2.36.0",
"linux-musl-x64": "x86_64-linux-musl", "linux-musl-arm64": "aarch64-linux-musl",
"win-x64": "x86_64-windows-gnu", "win-x86": "x86-windows-gnu",
"win-arm64": "aarch64-windows-gnu", "osx-x64": "x86_64-macos.10.13.0",
"osx-arm64": "aarch64-macos.11.0.0",
}
def mingw_overlay(zig_lib, output):
source = zig_lib / "libc/include/any-windows-any/dwrite_3.h"
text = source.read_text()
# Add only non-virtual overloads/default arguments. Keep IID, virtual order,
# virtual parameter types and C vtables exactly as supplied by MinGW.
for name in ("IDWritePaintReader", "IDWriteFontFace4"):
start = text.index(name + " : public")
end = text.index("#ifdef __CRT_UUID_DECL", start)
block = text[start:end]
if name == "IDWritePaintReader":
block = block.replace("UINT32 struct_size) = 0;",
"UINT32 struct_size = sizeof(DWRITE_PAINT_ELEMENT)) = 0;")
extra = """ HRESULT SetCurrentGlyph(UINT32 glyph, DWRITE_PAINT_ELEMENT *element,
D2D_RECT_F *clip, DWRITE_PAINT_ATTRIBUTES *attributes = 0) {
return SetCurrentGlyph(glyph, element, sizeof(DWRITE_PAINT_ELEMENT), clip, attributes);
}
HRESULT SetTextColor(const DWRITE_COLOR_F &color) { return SetTextColor(&color); }
"""
else:
extra = """ HRESULT GetGlyphImageFormats(UINT16 glyph, UINT32 first, UINT32 last,
DWRITE_GLYPH_IMAGE_FORMATS *formats) {
return GetGlyphImageFormats_(glyph, first, last, formats);
}
"""
index = block.rindex("};")
block = block[:index] + extra + block[index:]
text = text[:start] + block + text[end:]
output.mkdir(parents=True, exist_ok=True)
(output / "dwrite_3.h").write_text(text)
for name in ("XpsObjectModel.h", "ObjBase.h", "DispatcherQueue.h", "VersionHelpers.h", "T2EmbApi.h", "FontSub.h"):
alias = output / name
if alias.is_symlink():
alias.unlink()
alias.symlink_to(source.parent / name.lower())
return hashlib.sha256(source.read_bytes()).hexdigest()
def compiler(config, tool, incoming):
target = config["target"]
if "--version" in incoming and "linux-gnu." in target:
target = target.split("linux-gnu.")[0] + "linux-gnu"
windows = "windows" in target
args = ["-I" + config["include"]] if windows else [
"-isysroot", config["sdk"], "-idirafter", config["sdk"] + "/usr/include",
"-F", config["sdk"] + "/System/Library/Frameworks", "-Wno-elaborated-enum-base",
] if "macos" in target else []
if config.get('linux_abi_headers'):
args += ['-I' + config['linux_abi_headers']]
if config.get('linux_headers'):
args += ['-I' + config['linux_headers'], '-I' + config['linux_headers'] + '/freetype2']
if config.get('linux_sysroot') and '-c' not in incoming and '-o' in incoming:
root = Path(config['linux_sysroot'])
cpu = 'x86_64' if target.startswith('x86_64') else 'aarch64'
for path in (root / 'usr/lib' / (cpu + '-linux-gnu'), root / 'lib' / (cpu + '-linux-gnu'), root / 'usr/lib', root / 'lib'):
args += ['-L' + str(path)]
if 'linux' in target and '-c' not in incoming and '-o' in incoming:
args.append('-fuse-ld=lld')
if windows:
# Accept Windows header/Skia spellings such as __forceinline while
# retaining the GNU target ABI and leaving _MSC_VER undefined.
args.append("-fms-extensions")
if windows and config.get("mingw_headers"):
args.extend(("-idirafter", config["mingw_headers"]))
mapping = {
"/O2": "-O2", "/fp:precise": "-ffp-model=precise", "/std:c++20": "-std=c++20",
"/std:c11": "-std=c11", "/GR": "-frtti", "/GR-": "-fno-rtti", "/w": "-w",
"/Ob2": "-finline-functions", "/arch:AVX2": "-mcpu=x86_64_v3",
"/arch:AVX512": "-mcpu=x86_64_v4+evex512", "/TC": "-xc", "/TP": "-xc++",
"/Gy": "-ffunction-sections", "/Gw": "-fdata-sections",
"/Oy-": "-fno-omit-frame-pointer", "/guard:cf": "-mguard=cf",
"/W3": "-Wall",
"-march=x86-64-v3": "-mcpu=x86_64_v3", "-march=x86-64-v4": "-mcpu=x86_64_v4+evex512",
"-march=armv8-a+crc+crypto": "-mcpu=generic+crc+aes+sha2",
}
iterator = iter(incoming)
for flag in iterator:
if flag in ("-Wl,--fatal-warnings", "-Wl,--disable-new-dtags"):
continue
if flag in ("-o", "-MF", "-MT", "-MQ", "-I", "-isystem", "-isysroot", "-F", "-idirafter", "-include"):
args.extend((flag, next(iterator)))
continue
if flag in ("-target", "--target"):
next(iterator)
continue
if flag.startswith("--target="):
continue
if flag.startswith("/clang:"):
flag = flag[7:]
if flag.startswith(("-fdiagnostics-show-inlining-chain", "-fno-lifetime-dse",
"-fsanitize-ignore-for-ubsan-feature=", "-fmsc-version=")):
continue
if flag.startswith("/D"):
flag = "-D" + flag[2:]
if re.fullmatch(r"/std:(c\+\+\d+|c\d+)", flag):
flag = "-std=" + flag[5:]
if flag in ("/arch:SSE", "/arch:SSE2", "/arch:AVX"):
flag = {"/arch:SSE": "-msse", "/arch:SSE2": "-msse2", "/arch:AVX": "-mavx"}[flag]
if flag == "/W4":
args.extend(("-Wall", "-Wextra"))
continue
if flag in ("/bigobj", "/utf-8", "/Zc:inline", "/Zc:lambda", "/Zc:twoPhase", "/FS", "/MT"):
continue
if flag.startswith(("/wd", "/we")):
continue # MSVC diagnostic numbers have no GNU Clang equivalent.
if windows and flag.startswith("/") and flag not in mapping and not Path(flag).exists():
raise SystemExit("Unsupported MSVC option: " + flag)
if flag == '-stdlib=libstdc++':
flag = '-stdlib=libc++'
args.append(mapping.get(flag, flag))
if any(flag.startswith("-mavx512") for flag in args):
args.append("-mevex512")
if windows:
if "-DCRC32_SIMD_SSE42_PCLMUL" in args:
args.extend(("-msse4.2", "-mpclmul"))
if "-DADLER32_SIMD_SSSE3" in args:
args.append("-mssse3")
# Older MSVC GN rules express SSE dispatch through a macro: Clang needs
# matching CPU features on those units, never on ordinary baseline units.
if target.startswith(("x86", "i386")):
levels = {"SSE2": ["-msse2"], "SSE3": ["-msse3"], "SSSE3": ["-mssse3"],
"SSE41": ["-msse4.1"], "SSE42": ["-msse4.2", "-mcrc32"]}
for level, features in levels.items():
if "-DSK_CPU_SSE_LEVEL=SK_CPU_SSE_LEVEL_" + level in args:
args.extend(features)
return [config["zig"], "cc" if tool == "cc" else "c++", "-target", target, *args]
def execute(config, tool, incoming):
if tool in ("cc", "cxx"):
command = compiler(config, tool, incoming)
elif tool == "ar":
flags = [x.replace("rcsT", "rcs") for x in incoming if x not in ("/WX", "/ignore:4221", "-T", "--thin")]
command = [config["zig"], "ar"]
if "macos" in config["target"]:
command.append("--format=darwin")
command += flags
else:
output = None
inputs = []
iterator = iter(incoming)
for flag in iterator:
if flag in ("-static", "-no_warning_for_no_symbols"):
continue
if flag == "-o":
output = next(iterator)
elif flag == "-filelist":
inputs.extend(Path(next(iterator)).read_text().splitlines())
elif flag.startswith("@"):
inputs.extend(shlex.split(Path(flag[1:]).read_text()))
else:
inputs.append(flag)
if not output:
raise SystemExit("Darwin libtool adapter needs -o")
command = [config["zig"], "ar", "--format=darwin", "rcs", output, *inputs]
if tool in ('ar', 'libtool'):
# Never leave a truncated archive behind when disk/network/job failures
# interrupt archiving. GN response files contain a complete member list.
index = next((i for i, arg in enumerate(command[2:], 2)
if not arg.startswith('@') and Path(arg).suffix in ('.a', '.lib')), None)
if index is None:
raise SystemExit('Cannot identify archive output: ' + str(command))
dest = Path(command[index])
temporary = dest.with_name(dest.name + '.tmp-' + str(os.getpid()))
temporary.unlink(missing_ok=True)
objects = [x for x in command[index + 1:] if not x.startswith('-')]
if tool == 'ar' and dest.exists() and len(objects) == 1 and not objects[0].startswith('@'):
shutil.copy2(dest, temporary) # Explicit runtime/availability append.
command[index] = str(temporary)
try:
subprocess.run(command, check=True)
os.replace(temporary, dest)
finally:
temporary.unlink(missing_ok=True)
return
cache = shutil.which('ccache')
if tool in ('cc', 'cxx') and cache and os.environ.get('CCACHE_DIR') and '-c' in incoming:
os.environ['CCACHE_COMPILERTYPE'] = 'clang'
raw = str(Path(config['output']) / ('_cached-' + tool))
os.execv(cache, [cache, raw, *command[4:]])
os.execv(config["zig"], command)
def prepare(args):
zig = str(Path(shutil.which(args.zig) or args.zig).resolve())
version = subprocess.check_output([zig, "version"], text=True).strip()
if version != "0.14.1":
raise SystemExit("This adapter is verified with Zig 0.14.1; got " + version)
lib = Path(json.loads(subprocess.check_output([zig, "env"], text=True))["lib_dir"])
output = args.output.resolve()
output.mkdir(parents=True, exist_ok=True)
config = {"zig": zig, "target": TARGETS[args.target], "version": version}
if args.target.startswith("win"):
include = output / "include"
# Regeneration is idempotent; remove only the generated SDK case alias.
alias = include / "XpsObjectModel.h"
if alias.is_symlink():
alias.unlink()
config["mingw_header_sha256"] = mingw_overlay(lib, include)
config["include"] = str(include)
if args.mingw_headers:
config["mingw_headers"] = str(args.mingw_headers.resolve())
header = args.mingw_headers / "windows.ui.composition.h"
if header.is_file():
original = header.read_text()
text = original
# WIDL 11 omitted namespace qualification on these imported
# types. Use the real declarations already imported by the
# header; preserve interface UUIDs and method/vtable order.
for name in ("DirectXAlphaMode", "DirectXPixelFormat"):
text = text.replace("enum " + name, "enum ABI::Windows::Graphics::DirectX::" + name)
text = text.replace("struct Size", "struct ABI::Windows::Foundation::Size")
for name in ("Vector2", "Vector3", "Vector4", "Matrix3x2", "Matrix4x4", "Quaternion"):
text = text.replace("struct " + name, "struct ABI::Windows::Foundation::Numerics::" + name)
(include / header.name).write_text(text)
config["composition_header_sha256"] = hashlib.sha256(header.read_bytes()).hexdigest()
elif args.target.startswith("osx"):
if not args.sdk or not (args.sdk / "SDKSettings.json").is_file():
raise SystemExit("macOS target requires --sdk pointing to a macOS SDK")
config["sdk"] = str(args.sdk.resolve())
settings = args.sdk / "SDKSettings.json"
if json.loads(settings.read_text()).get("Version") != "15.5":
raise SystemExit("ANGLE metadata adapter is pinned to macOS SDK 15.5")
config["sdk_settings_sha256"] = hashlib.sha256(settings.read_bytes()).hexdigest()
if args.target.startswith('linux'):
config['linux_sysroot'] = str(args.linux_sysroot.resolve()) if args.linux_sysroot else ''
config['linux_headers'] = str(args.linux_headers.resolve()) if args.linux_headers else ''
config['output'] = str(output)
if args.target.startswith('linux'):
root = Path(config['linux_sysroot'])
abi = output / 'include-linux'
abi.mkdir(exist_ok=True)
cpu = 'x86_64' if config['target'].startswith('x86_64') else 'aarch64'
for name in ('ffi.h', 'ffitarget.h'):
for prefix in (root / 'usr/include' / (cpu + '-linux-gnu'), root / 'usr/include'):
src = prefix / name
if src.is_file():
(abi / name).write_bytes(src.read_bytes())
break
config['linux_abi_headers'] = str(abi)
pc = output / 'pkg-config'
dirs = [root / 'usr/lib' / (cpu + '-linux-gnu') / 'pkgconfig', root / 'usr/lib/pkgconfig', root / 'usr/share/pkgconfig']
pc.write_text('#!/bin/sh\nexport PKG_CONFIG_SYSROOT_DIR=' + shlex.quote(str(root)) + '\nexport PKG_CONFIG_LIBDIR=' + shlex.quote(':'.join(map(str, dirs))) + '\nexec /usr/bin/pkg-config "$@"\n')
pc.chmod(0o755)
for kind in ('cc', 'cxx'):
raw = output / ('_cached-' + kind)
mode = 'cc' if kind == 'cc' else 'c++'
raw.write_text('#!/bin/sh\nexec ' + shlex.quote(zig) + ' ' + mode + ' -target ' + shlex.quote(config['target']) + ' "$@"\n')
raw.chmod(0o755)
descriptor = output / "toolchain.json"
descriptor.write_text(json.dumps(config, indent=2) + "\n")
for tool in ("cc", "cxx", "ar", "libtool"):
executable = output / tool
executable.write_text("#!/bin/sh\nexec python3 " + shlex.quote(str(Path(__file__).resolve())) +
" run " + shlex.quote(str(descriptor)) + " " + tool + ' "$@"\n')
executable.chmod(0o755)
print(descriptor)
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "run":
execute(json.loads(Path(sys.argv[2]).read_text()), sys.argv[3], sys.argv[4:])
else:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--zig", default="zig")
parser.add_argument("--target", choices=TARGETS, required=True)
parser.add_argument("--sdk", type=Path)
parser.add_argument("--mingw-headers", type=Path, help="Pinned extra WinRT headers, after Zig's headers")
parser.add_argument("--linux-sysroot", type=Path)
parser.add_argument("--linux-headers", type=Path)
parser.add_argument("--output", type=Path, required=True)
prepare(parser.parse_args())