Build existing Haskell targets through one pinned Nix checkout

This commit is contained in:
Moritz Angermann committed 2026-10-15 15:54:50 +09:00
1 parent 3056b2f4b3
commit 238289fff7
9 files changed
+295 -15

No files matched your search

+94
View File
@@ -0,0 +1,94 @@
name: Nix Haskell builds
on:
workflow_dispatch:
push:
branches: [master, stable, build/stable-ghc-9.14]
paths:
- 'flake.*'
- '*.cabal'
- 'cabal.project*'
- 'src/**'
- 'apps/simplex-*/**'
- 'bots/**'
- 'scripts/nix/**'
- 'Makefile'
- '.github/workflows/nix.yml'
pull_request:
paths:
- 'flake.*'
- '*.cabal'
- 'cabal.project*'
- 'src/**'
- 'apps/simplex-*/**'
- 'bots/**'
- 'scripts/nix/**'
- 'Makefile'
- '.github/workflows/nix.yml'
permissions:
contents: read
concurrency:
group: nix-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
name: ${{ matrix.system }} / pinned Haskell compiler
runs-on: ${{ matrix.runner }}
timeout-minutes: 360
strategy:
fail-fast: false
matrix:
include:
- system: x86_64-linux
runner: ubuntu-24.04
- system: aarch64-linux
runner: ubuntu-24.04-arm
- system: aarch64-darwin
runner: macos-15
- system: x86_64-darwin
runner: macos-15-intel
env:
NIX_SYSTEM: ${{ matrix.system }}
NIX_BUILD_TIMEOUT: 7200
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: cachix/install-nix-action@v31
with:
github_access_token: ${{ secrets.GITHUB_TOKEN }}
extra_nix_config: |
extra-substituters = https://cache.iog.io https://cache.zw3rk.com
extra-trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= loony-tools:pr9m4BkM/5/eSTZlkQyRt57Jz7OMBxNSUiMC4FkcNfk=
- name: Show outputs from this checkout
run: make nix-list
# Use the compiler fork in flake.lock, including both Android ABIs.
# Stock GHC installed by ghcup is not interchangeable with this compiler.
- name: Build existing Haskell outputs
run: make nix-build
- name: Collect library ZIPs and CLIs
shell: bash
run: |
mkdir -p artifacts
for output in result-nix/"$NIX_SYSTEM"/*; do
[ -d "$output" ] || continue
destination="artifacts/$(basename "$output")"
mkdir -p "$destination"
find -L "$output" -maxdepth 1 -type f -name '*.zip' -exec cp {} "$destination/" \;
if [ -f "$output/bin/simplex-chat" ]; then
cp "$output/bin/simplex-chat" "$destination/"
fi
done
- uses: actions/upload-artifact@v4
with:
name: nix-${{ matrix.system }}-${{ github.sha }}
path: artifacts/
if-no-files-found: error
+1
View File
@@ -69,6 +69,7 @@ website/package/generated*
website/.nyc_output/
website/coverage/
result
result-nix/
# Ignore API documentation
website/api-docs/
+37
View File
@@ -0,0 +1,37 @@
.DEFAULT_GOAL := help
NIX_TARGET ?= all
NIX_ARGS ?=
export NIX_SYSTEM
export NIX_OUT_DIR
export NIX_BUILD_TIMEOUT
.PHONY: help nix-list nix-build nix-native nix-android nix-windows nix-linux-static nix-ios nix-darwin-libs
help: ## Show build commands.
@awk 'BEGIN { FS = ":.*## " } /^[a-zA-Z_-]+:.*## / { printf " %-20s %s\n", $$1, $$2 }' $(MAKEFILE_LIST)
# The flake lock selects the compiler; these targets never install a stock GHC.
nix-list: ## List selected Hydra outputs without building (NIX_TARGET=all).
@./scripts/nix/build.sh --list $(NIX_TARGET)
nix-build: ## Build the host's existing Hydra outputs (NIX_TARGET=all, NIX_ARGS=...).
./scripts/nix/build.sh $(NIX_TARGET) $(NIX_ARGS)
nix-native: ## Build the native Haskell library and CLI.
./scripts/nix/build.sh native $(NIX_ARGS)
nix-android: ## Build both Android ABIs and their support libraries on x86_64-linux.
./scripts/nix/build.sh android $(NIX_ARGS)
nix-windows: ## Cross-build the Windows library and CLI on x86_64-linux.
./scripts/nix/build.sh windows $(NIX_ARGS)
nix-linux-static: ## Cross-build the x86_64, i686, and aarch64 Linux static CLIs.
./scripts/nix/build.sh linux-static $(NIX_ARGS)
nix-ios: ## Build the iOS Haskell library ZIP on the selected Darwin host.
./scripts/nix/build.sh ios $(NIX_ARGS)
nix-darwin-libs: ## Build Swift JSON and tagged JSON library ZIPs on Darwin.
./scripts/nix/build.sh darwin-libs $(NIX_ARGS)
+4 -8
View File
@@ -5,7 +5,7 @@ set -eu
repo="https://github.com/simplex-chat/simplex-chat"
u="$USER"
tmp="$(mktemp -d -t)"
tmp="$(mktemp -d)"
folder="$tmp/simplex-chat"
nix_ver="nix-2.22.0"
@@ -105,13 +105,9 @@ build() {
sed -i.bak "s/android.version_code=.*/android.version_code=${vercode}/" "$folder/apps/multiplatform/gradle.properties"
for arch in $arches; do
if [ "$arch" = "armv7a" ]; then
android_simplex_lib="${folder}#hydraJobs.${arch}-android:lib:simplex-chat.x86_64-linux"
android_support_lib="${folder}#hydraJobs.${arch}-android:lib:support.x86_64-linux"
else
android_simplex_lib="${folder}#hydraJobs.x86_64-linux.${arch}-android:lib:simplex-chat"
android_support_lib="${folder}#hydraJobs.x86_64-linux.${arch}-android:lib:support"
fi
# Both ABIs use this checkout and the same compiler selected by flake.lock.
android_simplex_lib="${folder}#hydraJobs.x86_64-linux.${arch}-android:lib:simplex-chat"
android_support_lib="${folder}#hydraJobs.x86_64-linux.${arch}-android:lib:support"
android_simplex_lib_output="${PWD}/result/pkg-${arch}-android-libsimplex.zip"
android_support_lib_output="${PWD}/result/pkg-${arch}-android-libsupport.zip"
+1 -1
View File
@@ -9,7 +9,7 @@ function readlink() {
OS=linux
ARCH="$(uname -m)"
DATABASE_BACKEND="${1:-sqlite}"
GHC_VERSION=9.6.3
GHC_VERSION=$(ghc --numeric-version)
if [ "$ARCH" == "aarch64" ]; then
COMPOSE_ARCH=arm64
+1 -1
View File
@@ -5,7 +5,7 @@ set -e
OS=mac
ARCH="${1:-$(uname -m)}"
COMPOSE_ARCH=$ARCH
GHC_VERSION=9.6.3
GHC_VERSION=$(ghc --numeric-version)
DATABASE_BACKEND="${2:-sqlite}"
if [ "$ARCH" == "arm64" ]; then
+71 -1
View File
@@ -1,4 +1,74 @@
# Updating nix package config
# Haskell builds with Nix
The compiler and all cross-compilers come from the haskell.nix input pinned in
`flake.lock`. The `ghc914-sh` compiler is the stable-haskell fork, not the stock
GHC 9.14 release from GHCup. Use the same source checkout and lock file for every
platform; Android ARMv7 does not require a separate branch or tag.
Run these commands from the repository root:
```sh
make help
make nix-list # list this host's existing Hydra outputs
make nix-native # native library and CLI
make nix-android # ARM64 + ARMv7 libraries, on x86_64-linux
make nix-windows # Windows library and CLI, on x86_64-linux
make nix-linux-static # x86_64, i686, and ARM64 static Linux CLIs
make nix-build # all existing outputs for this build host
```
Each command builds this checkout, without cloning another branch. Output links
are placed under `result-nix/<build-system>/<package>`. ZIP filenames inside the
outputs retain the existing Hydra names. For example, the ARMv7 client library is
`result-nix/x86_64-linux/armv7a-android:lib:simplex-chat/pkg-armv7a-android-libsimplex.zip`.
Nix includes tracked working-tree changes; add new source files to Git before
building so they are included.
For a remote builder, select its build system explicitly. Nix must already have
that builder configured:
```sh
make nix-ios NIX_SYSTEM=aarch64-darwin
make nix-darwin-libs NIX_SYSTEM=x86_64-darwin
make nix-build NIX_SYSTEM=aarch64-linux
```
`nix-ios` produces the Haskell static-library ZIP. It does not run Xcode, sign an
iOS application, or upload to TestFlight. ARM64 device libraries and Intel
simulator libraries retain their separate outputs. The existing iOS preparation
scripts retag ARM64 archives with `mac2ios -s` when an Apple Silicon simulator is
needed.
`NIX_ARGS` passes additional options to `nix build`, and `NIX_OUT_DIR` changes the
output-link directory. Each derivation has a two-hour timeout by default; set
`NIX_BUILD_TIMEOUT` in seconds to change it. For a wall-clock limit on a local
batch, use `timeout` from the Nix development environment:
```sh
nix develop -c timeout 6h make nix-build
make nix-native NIX_ARGS=--dry-run
```
`.github/workflows/nix.yml` runs these same outputs on Linux ARM64/x86_64 and
Darwin ARM64/x86_64, with a six-hour job limit. It uploads the existing library ZIPs
and CLIs under an artifact named for the source SHA. Hydra continues to consume
the same `hydraJobs` attributes. The older application release workflow still
uses its existing GHCup/Docker compiler settings; migrating that packaging and
release path is separate from this Nix build lane.
To build both Android APK ABIs from the current checkout, preserving the same
compiler and source, use the existing builder's source/skip-checkout flags:
```sh
scripts/android/build-android.sh -sg VERSION_CODE
```
This command also needs the Android SDK, Gradle, and its other existing tools.
The APK reproduction script now checks out the supplied tag for both ABIs.
Historical releases that used a separate `-armv7a` tag must be reproduced with
their historical build scripts.
## Updating package hashes
1. Install `nix`, `gawk` and `jq`.
+85
View File
@@ -0,0 +1,85 @@
#!/usr/bin/env sh
set -eu
# Use this checkout and its lock file for every target, including cross builds.
repo_dir=$(CDPATH='' cd -- "$(dirname -- "$0")/../.." && pwd)
usage() {
cat <<'EOF'
Usage: scripts/nix/build.sh [--list] TARGET [nix build options...]
Targets: all, native, android, windows, linux-static, ios, darwin-libs
NIX_SYSTEM selects the build host (defaults to this machine's Nix system).
NIX_OUT_DIR selects the output links (defaults to result-nix in this checkout).
NIX_BUILD_TIMEOUT bounds each derivation in seconds (defaults to 7200).
--list prints the selected Hydra attributes without evaluating or building them.
EOF
}
list_only=false
if [ "${1:-}" = "--list" ]; then
list_only=true
shift
fi
case "${1:-}" in
''|-h|--help) usage; exit 0 ;;
esac
target=$1
shift
system=${NIX_SYSTEM:-}
if [ -z "$system" ]; then
case "$(uname -s):$(uname -m)" in
Linux:x86_64) system=x86_64-linux ;;
Linux:aarch64|Linux:arm64) system=aarch64-linux ;;
Darwin:x86_64) system=x86_64-darwin ;;
Darwin:arm64|Darwin:aarch64) system=aarch64-darwin ;;
*) echo 'Unsupported build host; set NIX_SYSTEM explicitly.' >&2; exit 1 ;;
esac
fi
case "$system" in
x86_64-linux|aarch64-linux|x86_64-darwin|aarch64-darwin) ;;
*) printf 'Unsupported NIX_SYSTEM: %s\n' "$system" >&2; exit 1 ;;
esac
packages=
add_native() {
packages="$packages lib:simplex-chat exe:simplex-chat"
}
add_android() {
packages="$packages aarch64-android:lib:simplex-chat aarch64-android:lib:support armv7a-android:lib:simplex-chat armv7a-android:lib:support"
}
add_windows() {
packages="$packages x86_64-windows:exe:simplex-chat x86_64-windows:lib:simplex-chat"
}
add_linux_static() {
packages="$packages x86_64-linux-static:exe:simplex-chat i686-linux-static:exe:simplex-chat aarch64-linux-static:exe:simplex-chat"
}
add_darwin_libs() {
packages="$packages $system-ios:lib:simplex-chat $system:lib:simplex-chat"
}
case "$target:$system" in
all:x86_64-linux) add_native; add_android; add_windows; add_linux_static ;;
all:aarch64-linux|native:*) add_native ;;
all:*-darwin) add_native; add_darwin_libs ;;
android:x86_64-linux) add_android ;;
windows:x86_64-linux) add_windows ;;
linux-static:x86_64-linux) add_linux_static ;;
ios:*-darwin) packages="$system-ios:lib:simplex-chat" ;;
darwin-libs:*-darwin) add_darwin_libs ;;
*) printf 'Target %s is not available on build host %s.\n' "$target" "$system" >&2; exit 1 ;;
esac
out_dir=${NIX_OUT_DIR:-$repo_dir/result-nix}
for package in $packages; do
attribute="hydraJobs.$system.$package"
if "$list_only"; then
printf '%s\n' "$attribute"
else
mkdir -p "$out_dir/$system"
nix build --print-build-logs --timeout "${NIX_BUILD_TIMEOUT:-7200}" \
--out-link "$out_dir/$system/$package" \
"$repo_dir#$attribute" "$@"
fi
done
@@ -245,10 +245,7 @@ Continue?'
# Build phase
for arch in $ARCHES; do
case "$arch" in
armv7a)
build_tag="${tag}-armv7a"
;;
aarch64)
aarch64|armv7a)
build_tag="${tag}"
;;
*)