open-standards/wai/quickstart/build-libwai.sh
Transaction Science 0833173ed6
Some checks failed
wai-app and Create / wai-app · does this change touch it (push) Successful in 17s
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Successful in 16s
joule-moq-room room service / joule-moq-room · does this change touch it (push) Successful in 36s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Successful in 39s
wai-audit collector and player integration / does this change touch it (push) Successful in 21s
WAI operation catalogue / does this change touch it (push) Successful in 21s
wai-ledger service / does this change touch it (push) Successful in 19s
wai-fleet service / does this change touch it (push) Successful in 20s
wai-quantum studio and desktop / does this change touch it (push) Successful in 21s
wai-quantum for JavaScript / does this change touch it (push) Successful in 22s
wai-sink-swift native sink package / does this change touch it (push) Successful in 21s
wai-sink-android native sink library / does this change touch it (push) Successful in 20s
WAI Studio / does this change touch it (push) Successful in 24s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Has been cancelled
WAI operation catalogue / the catalogue and every door · linux (push) Has been cancelled
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Has been cancelled
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Has been cancelled
joule-code conformance gate / joule-moq-relay, its own energy on a counter (macos) (push) Successful in 43s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Successful in 1m11s
wai-fleet service / service · macos (push) Successful in 1m2s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 1m28s
wai-ledger service / service · macos (push) Successful in 1m34s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Successful in 6m8s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 4m12s
WAI Studio / Studio in Chromium and Firefox · macos (push) Successful in 9m11s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 11m10s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Successful in 15m15s
wai release binaries build on Windows / the seven release binaries · windows (push) Successful in 16m54s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 10m27s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 11s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Successful in 49s
wai-audit collector and player integration / collector · linux (push) Successful in 1m33s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 57s
wai-ledger service / service · linux (push) Successful in 1m53s
wai-quantum for JavaScript / javascript · linux (push) Has been cancelled
WAI Studio / Studio in WebKit · linux (push) Has been cancelled
wai-quantum studio and desktop / desktop app · linux (push) Has been cancelled
wai-quantum studio and desktop / studio · browser (push) Has been cancelled
wai-fleet service / service · linux (push) Successful in 4m1s
joule-code conformance gate / Build + round-trip C1-C4 vectors (push) Successful in 5m4s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 2m46s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 7m20s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Has been cancelled
joule-moq-room room service / joule-moq-room, every target (push) Has been cancelled
joule-code conformance gate / joule-moq-relay, every target (push) Has been cancelled
joule-code conformance gate / joule-moq-ingest, every target (push) Has been cancelled
wai release: libwai for C, the Swift package by URL and checksum, the Android library published, and the relay's and room service's images
One release, four kinds of artefact, from wai-release.yml on a wai-v* tag:

- C: each Linux job attaches libwai-<version>-<triple>.tar.gz for x86_64- and
  aarch64-unknown-linux-gnu (wai/quickstart/build-libwai.sh): lib/libwai.a, the feature
  native_sink, built for the glibc target without crt-static; the committed include/wai.h;
  lib/pkgconfig/wai.pc, relocatable, its Libs naming rustc's native-static-libs. Static, so
  a program carries it and looks for nothing at run time. Before the attach: the header the
  build regenerates is the committed one, the library defines exactly the envelope's and the
  native sink's functions, and a C program compiles, links and runs against the archive
  through pkg-config (wai/quickstart/test/c-library.sh).
- Swift: Package.swift names WaiFFI by URL and checksum once a release has written them, and
  build/WaiFFI.xcframework while it is built there. The swift job attaches the zipped
  framework and wai-sink-swift-<version>.zip, the package naming it by download URL and
  SwiftPM checksum; scripts/check-release-package.sh resolves, builds and runs an
  application against it (before the attach through a mirror of the URL, after from the URL)
  and requires a wrong checksum to be refused. wai-sink-swift.yml runs the first on every
  change.
- Kotlin: maven-publish as science.transaction.wai:wai-sink:<version>, manifest package
  science.transaction.wai.sink (the Kotlin classes keep wai.sink). The android job checks
  the publication (scripts/check-publication.sh), attaches the AAR and publishes it to the
  forge's Maven registry; wai-sink-android.yml writes and checks it on every change.
- OCI: Containerfiles and check-image.sh for the relay and the room service (deploy/ beside
  each crate). The images job, on a runner labelled oci, builds and checks both and pushes
  them to the forge's container registry (wai/quickstart/release-images.sh, oci-push.py);
  an image that fails its check is not pushed.

The forge's job token reads the organisation's packages and cannot write them, so the Maven
publication and the images read the repository secret WAI_PACKAGES_TOKEN (scope
write:package). Every upload goes to the forge over the private network. The release body
names the new files.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-09 18:25:22 -05:00

122 lines
6.5 KiB
Shell
Executable file

#!/usr/bin/env bash
# libwai for C on Linux: the static library, wai.h and the pkg-config file wai.pc, for one target.
#
# bash wai/quickstart/build-libwai.sh <out-dir> [--target <triple>] [--version <v>]
#
# Builds wai/wai-rs's library, release and --locked, with the feature native_sink alone: the C
# interface of the envelope (pack, unpack and select, the WAI2 rendition table, an integer
# payload's declared cost) and of the native sink (extensions/native-sink.md §9), the interface the
# Swift package's WaiFFI.xcframework and the Android library carry. Pure Rust: it needs nothing but
# the C runtime. wai.h also declares the codec wrappers (src/ffi_codecs.rs, feature codecs) and the
# neural decoders (src/ffi_neural.rs, feature neural), which need codec and model libraries this
# library does not hold: its README says so, and the library is held below to exactly the
# functions of src/ffi.rs and src/ffi_sink.rs.
#
# The library is static, lib/libwai.a, for a glibc target (x86_64- or aarch64-unknown-linux-gnu),
# built without crt-static. A program that links it carries it: nothing of libwai is looked for at
# run time, and the C runtime's symbols bind when the program is linked, to the glibc it is linked
# against. wai.pc names it with the system libraries it needs (rustc's native-static-libs), so
# `pkg-config --libs wai` links it as it is; its prefix is the directory it is in (${pcfiledir}),
# so the archive works wherever it is unpacked.
#
# Writes <out-dir>/libwai-<version>-<triple>.tar.gz holding include/wai.h, lib/libwai.a,
# lib/pkgconfig/wai.pc, README.md and LICENSE, with <archive>.sha256 beside it. Before it packages:
# - the header the build generates (build.rs regenerates include/wai.h) is the committed one,
# byte for byte, so the archive's header is the repository's (run in a fresh target directory,
# as a release does, so the build script runs);
# - the header declares nothing but wai_* and WAI_* names, and every function it declares is one
# of the four files of the C interface; the library defines exactly the wai_* functions of
# src/ffi.rs and src/ffi_sink.rs (wai/quickstart/libwai_interface.py).
# Where the target is this machine's, wai/quickstart/test/c-library.sh then compiles a C program
# against the archive through pkg-config, links it and runs it.
set -euo pipefail
usage() { echo "usage: bash wai/quickstart/build-libwai.sh <out-dir> [--target <triple>] [--version <v>]" >&2; exit 2; }
die() { echo "build-libwai.sh: $*" >&2; exit 1; }
[ $# -ge 1 ] || usage
ROOT=$(cd "$(dirname "$0")/../.." && pwd)
RS="$ROOT/wai/wai-rs"
OUT=$(mkdir -p "$1" && cd "$1" && pwd); shift
TRIPLE="" VERSION=""
while [ $# -gt 0 ]; do
case "$1" in
--target) TRIPLE="$2"; shift 2 ;;
--version) VERSION="$2"; shift 2 ;;
*) usage ;;
esac
done
HOST=$(rustc -vV | sed -n 's/^host: //p')
TRIPLE=${TRIPLE:-$HOST}
case "$TRIPLE" in
x86_64-unknown-linux-gnu | aarch64-unknown-linux-gnu) ;;
*) echo "build-libwai.sh: $TRIPLE: the archive is built for x86_64- or aarch64-unknown-linux-gnu" >&2; exit 2 ;;
esac
case "${RUSTFLAGS:-} ${CARGO_ENCODED_RUSTFLAGS:-}" in
*crt-static*) die "RUSTFLAGS asks for crt-static: libwai.a is built against the dynamic C runtime" ;;
esac
VERSION=${VERSION:-$(sed -n 's/^version = "\(.*\)"$/\1/p' "$RS/Cargo.toml" | head -1)}
NAME="libwai-$VERSION-$TRIPLE"
FEATURES=(--no-default-features --features native_sink)
# A target directory of its own: wai also builds as a cdylib, so its rlib's file name carries no
# hash, and another feature set of the crate in the same directory would overwrite this one.
TD="${CARGO_TARGET_DIR:-$RS/target}/libwai-c"
STAGE=$(mktemp -d)
trap 'rm -rf "$STAGE"' EXIT
cp "$RS/include/wai.h" "$STAGE/wai.h.committed"
# rustc names the system libraries a static library needs when it links one
# (--print=native-static-libs); a build that compiles nothing prints nothing, so then the crate is
# compiled again.
build() {
( cd "$RS" && CARGO_TARGET_DIR="$TD" cargo rustc --locked --release --lib "${FEATURES[@]}" --target "$TRIPLE" \
-- --print=native-static-libs ) 2>&1 | tee "$STAGE/build.log" >&2
}
native_libs() { sed -n 's/^.*note: native-static-libs: //p' "$STAGE/build.log" | tail -1; }
build || die "the build of libwai failed"
NATIVE=$(native_libs)
if [ -z "$NATIVE" ]; then
( cd "$RS" && CARGO_TARGET_DIR="$TD" cargo clean --release --target "$TRIPLE" -p wai ) >&2
build || die "the build of libwai failed"
NATIVE=$(native_libs)
fi
[ -n "$NATIVE" ] || die "rustc named no native-static-libs for libwai.a"
LIB="$TD/$TRIPLE/release/libwai.a"
[ -f "$LIB" ] || die "no $LIB"
cmp -s "$STAGE/wai.h.committed" "$RS/include/wai.h" || {
diff -u "$STAGE/wai.h.committed" "$RS/include/wai.h" | head -60 >&2 || true
die "the build regenerated wai/wai-rs/include/wai.h and it is not the committed header: commit the regenerated one"
}
D="$STAGE/$NAME"
mkdir -p "$D/include" "$D/lib/pkgconfig"
cp "$RS/include/wai.h" "$D/include/wai.h"
# The library without its debugging sections (the standard library's among them): a program links
# the same code from it, and the symbols it links by are kept.
cp "$LIB" "$D/lib/libwai.a"
strip --strip-debug "$D/lib/libwai.a" || die "strip could not take the debugging sections out of libwai.a"
nm -g --defined-only "$D/lib/libwai.a" > "$STAGE/nm.txt" 2>/dev/null || die "nm could not read libwai.a"
python3 -I "$ROOT/wai/quickstart/libwai_interface.py" --root "$ROOT" --nm "$STAGE/nm.txt" >&2 \
|| die "the header or the library is not the C interface it should be"
cat > "$D/lib/pkgconfig/wai.pc" <<PC
prefix=\${pcfiledir}/../..
libdir=\${prefix}/lib
includedir=\${prefix}/include
Name: wai
Description: WAI's C interface: the envelope and the native sink (wai-rs, feature native_sink), static
URL: https://wai.transaction.science
Version: $VERSION
Cflags: -I\${includedir}
Libs: -L\${libdir} -lwai $NATIVE
PC
cp "$ROOT/wai/quickstart/libwai.md" "$D/README.md"
cp "$ROOT/wai/LICENSE" "$D/LICENSE"
chmod 644 "$D/include/wai.h" "$D/lib/libwai.a" "$D/lib/pkgconfig/wai.pc" "$D/README.md" "$D/LICENSE"
# The same bytes for the same inputs: sorted names, fixed owner and times.
tar --sort=name --owner=0 --group=0 --numeric-owner --mtime='2026-01-01 00:00Z' -C "$STAGE" -cf - "$NAME" | gzip -n -9 > "$OUT/$NAME.tar.gz"
( cd "$OUT" && sha256sum "$NAME.tar.gz" > "$NAME.tar.gz.sha256" )
echo "packaged $OUT/$NAME.tar.gz ($(cut -d' ' -f1 "$OUT/$NAME.tar.gz.sha256"), $(du -h "$OUT/$NAME.tar.gz" | cut -f1)); wai.pc links: -lwai $NATIVE"
if [ "$TRIPLE" = "$HOST" ]; then
bash "$ROOT/wai/quickstart/test/c-library.sh" "$OUT/$NAME.tar.gz"
fi