mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-11-05 17:07:50 +00:00
295 lines
13 KiB
YAML
295 lines
13 KiB
YAML
name: Nix Haskell builds
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
group:
|
|
description: Existing build groups to run
|
|
type: choice
|
|
required: true
|
|
default: all
|
|
options: [all, linux-static, android, windows]
|
|
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 }}${{ github.event_name == 'workflow_dispatch' && format('-{0}', inputs.group || 'all') || '' }}
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
plan:
|
|
name: Select Nix build groups
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 2
|
|
outputs:
|
|
matrix: ${{ steps.select.outputs.matrix }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: Select existing build groups
|
|
id: select
|
|
env:
|
|
# PRs and pushes always retain all seven build groups.
|
|
NIX_CI_GROUP: ${{ github.event_name == 'workflow_dispatch' && inputs.group || 'all' }}
|
|
shell: bash
|
|
run: |
|
|
python3 -B scripts/nix/test-ci-matrix.py
|
|
matrix=$(python3 scripts/nix/ci-matrix.py --group "$NIX_CI_GROUP")
|
|
printf 'matrix=%s\n' "$matrix" >> "$GITHUB_OUTPUT"
|
|
|
|
build:
|
|
needs: plan
|
|
name: ${{ matrix.system }} / ${{ matrix.target }} / pinned Haskell compiler
|
|
runs-on: ${{ matrix.runner }}
|
|
timeout-minutes: 360
|
|
strategy:
|
|
fail-fast: false
|
|
matrix: ${{ fromJSON(needs.plan.outputs.matrix) }}
|
|
env:
|
|
NIX_SYSTEM: ${{ matrix.system }}
|
|
NIX_TARGET: ${{ matrix.target }}
|
|
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=
|
|
# The pinned haskell.nix uses this scheduling marker for cross
|
|
# slices that need a real x86_64 host. This runner is native x86_64.
|
|
# The installer skips its defaults when this setting is present.
|
|
# Keep the CLI/flakes features and enable the marker's Nix feature.
|
|
experimental-features = nix-command flakes ${{ matrix.system == 'x86_64-linux' && 'recursive-nix' || '' }}
|
|
extra-system-features = ${{ matrix.system == 'x86_64-linux' && 'recursive-nix' || '' }}
|
|
|
|
- name: Show outputs from this checkout
|
|
run: make nix-list
|
|
|
|
- name: Check Android iserv overlay scope
|
|
if: ${{ matrix.target == 'android' }}
|
|
timeout-minutes: 1
|
|
run: |
|
|
nix eval --json --file scripts/nix/check-android-iserv-scope.nix
|
|
nix eval --json --file scripts/nix/check-android-pthread-scope.nix
|
|
|
|
- name: Check musl interpreter link policy scope
|
|
if: ${{ matrix.target == 'linux-static' }}
|
|
timeout-minutes: 1
|
|
run: |
|
|
nix eval --impure --json --file scripts/nix/check-musl-iserv-scope.nix \
|
|
--apply 'f: f { lib = (builtins.getFlake (toString ./.)).inputs.nixpkgs.lib; }'
|
|
nix eval --impure --json --file scripts/nix/check-musl-rts-scope.nix \
|
|
--apply 'f: f { lib = (builtins.getFlake (toString ./.)).inputs.nixpkgs.lib; }'
|
|
|
|
- name: Check scoped ELF COMDAT function coalescing
|
|
if: ${{ matrix.system == 'x86_64-linux' && matrix.target == 'linux-static' }}
|
|
timeout-minutes: 120
|
|
run: nix build .#checks.x86_64-linux.ghc-elf-comdat-functions --no-link -L --max-jobs 1 --timeout "$NIX_BUILD_TIMEOUT"
|
|
|
|
- name: Check Intel Setup failure selection
|
|
if: ${{ matrix.system == 'x86_64-darwin' && matrix.target == 'all' }}
|
|
timeout-minutes: 1
|
|
run: python3 -B scripts/nix/test-select-intel-setup.py
|
|
|
|
- name: Check native Linux GHC ELF section alignment
|
|
if: ${{ matrix.system == 'x86_64-linux' && matrix.target == 'native' }}
|
|
timeout-minutes: 120
|
|
run: nix build .#checks.x86_64-linux.ghc-elf-alignment --no-link -L --max-jobs 1 --timeout "$NIX_BUILD_TIMEOUT"
|
|
|
|
# Prepare only the exact TH component's direct inputs with the normal
|
|
# budget. Its own canonical build then gets five minutes, not two hours.
|
|
- name: Prepare canonical Windows TH inputs
|
|
id: windows_th_inputs
|
|
if: ${{ matrix.system == 'x86_64-linux' && matrix.target == 'windows' }}
|
|
timeout-minutes: 240
|
|
shell: bash
|
|
run: python3 scripts/nix/windows-th-gate.py prepare 2>&1 | tee windows-th-inputs.log
|
|
|
|
- name: Check canonical Windows TH component
|
|
id: windows_th_gate
|
|
if: ${{ matrix.system == 'x86_64-linux' && matrix.target == 'windows' }}
|
|
timeout-minutes: 6
|
|
shell: bash
|
|
run: python3 scripts/nix/windows-th-gate.py build 2>&1 | tee windows-th-gate.log
|
|
|
|
# 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
|
|
id: haskell_build
|
|
shell: bash
|
|
run: make nix-build 2>&1 | tee nix-build.log
|
|
|
|
- name: Check native Intel Darwin GHC info-table placement
|
|
if: ${{ matrix.system == 'x86_64-darwin' && matrix.target == 'all' }}
|
|
timeout-minutes: 10
|
|
run: nix build .#checks.x86_64-darwin.ghc-macho-info-tables --no-link -L --max-jobs 1 --timeout 300
|
|
|
|
- name: Trace failed canonical Windows TH component
|
|
id: windows_th_trace
|
|
if: ${{ failure() && matrix.system == 'x86_64-linux' && matrix.target == 'windows' && steps.windows_th_inputs.outcome == 'success' && steps.windows_th_gate.outcome == 'failure' && steps.windows_th_gate.outputs.attempted == 'true' }}
|
|
timeout-minutes: 15
|
|
shell: bash
|
|
run: |
|
|
timeout --kill-after=30s 840s nice -n 10 \
|
|
python3 scripts/nix/windows-th-gate.py trace 2>&1 | tee windows-th-trace.log
|
|
|
|
- name: Upload Windows TH gate and diagnostic
|
|
if: ${{ always() && matrix.system == 'x86_64-linux' && matrix.target == 'windows' }}
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: nix-windows-th-${{ github.sha }}
|
|
path: |
|
|
windows-th-gate.json
|
|
windows-th-inputs.log
|
|
windows-th-gate.log
|
|
windows-th-trace.log
|
|
if-no-files-found: warn
|
|
|
|
# Diagnose the same native library after failure. Keep the canonical
|
|
# failure and its flags intact; this is a separate diagnostic derivation.
|
|
- name: Trace native Linux GHC and capture faults after failure
|
|
id: ghc_phase_trace
|
|
if: ${{ failure() && matrix.system == 'x86_64-linux' && matrix.target == 'native' && steps.haskell_build.outcome == 'failure' }}
|
|
shell: bash
|
|
run: |
|
|
if [ -d "result-nix/$NIX_SYSTEM/lib:simplex-chat" ]; then
|
|
echo 'Native library already built; skipping its diagnostic trace.'
|
|
exit 0
|
|
fi
|
|
echo 'attempted=true' >> "$GITHUB_OUTPUT"
|
|
flake_ref="git+file://$GITHUB_WORKSPACE?rev=$(git rev-parse HEAD)"
|
|
original="(builtins.getFlake \"$flake_ref\").hydraJobs.x86_64-linux.\"lib:simplex-chat\""
|
|
export flake_ref original
|
|
timeout --kill-after=30s 7200s nice -n 10 bash -euo pipefail \
|
|
2>&1 <<'TRACE' | tee native-linux-ghc-phase-trace.log
|
|
debugger="(import ((builtins.getFlake \"$flake_ref\").inputs.nixpkgs) { system = \"x86_64-linux\"; }).gdb"
|
|
# Fetch the pinned debugger only from caches. Never compile it locally
|
|
# or remotely while diagnosing the already-failed application build.
|
|
nix build --expr "$debugger" --no-link --max-jobs 0 --builders '' \
|
|
--option external-builders '[]'
|
|
exec nix build \
|
|
--file scripts/nix/trace-native-ghc.nix --arg original "$original" \
|
|
--arg debugger "$debugger" \
|
|
--no-link -L --keep-failed --max-jobs 1 --timeout 7200
|
|
TRACE
|
|
|
|
- name: Upload native Linux GHC phase log
|
|
if: ${{ always() && steps.ghc_phase_trace.outputs.attempted == 'true' }}
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: nix-ghc-phase-trace-${{ matrix.system }}-${{ matrix.target }}-${{ github.sha }}
|
|
path: native-linux-ghc-phase-trace.log
|
|
if-no-files-found: warn
|
|
|
|
- name: Capture Intel Darwin ghc-boot Setup failure
|
|
id: intel_setup_trace
|
|
if: ${{ failure() && matrix.system == 'x86_64-darwin' && matrix.target == 'all' && steps.haskell_build.outcome == 'failure' }}
|
|
timeout-minutes: 120
|
|
shell: bash
|
|
run: |
|
|
# Compiler patches change this derivation. Select one actual failed
|
|
# component; trace-intel-setup.nix still checks its exact drvPath.
|
|
if ! expected_drv=$(python3 scripts/nix/select-intel-setup.py nix-build.log); then
|
|
exit 0
|
|
fi
|
|
echo 'attempted=true' >> "$GITHUB_OUTPUT"
|
|
export expected_drv
|
|
bash -euo pipefail 2>&1 <<'TRACE' | tee intel-setup-lldb-trace.log
|
|
lldb_path=$(xcrun --find lldb)
|
|
printf 'Intel Setup host debugger: %s\n' "$lldb_path"
|
|
"$lldb_path" --version
|
|
clang_path=$(xcrun --find clang)
|
|
sdk_path=$(xcrun --sdk macosx --show-sdk-path)
|
|
printf 'Intel Setup abort tracer compiler: %s\n' "$clang_path"
|
|
"$clang_path" --version
|
|
abort_tracer="$GITHUB_WORKSPACE/intel-setup-abort.dylib"
|
|
"$clang_path" -isysroot "$sdk_path" -arch x86_64 \
|
|
-std=c11 -Werror=vla -pedantic -Wall -Wextra -Werror \
|
|
-dynamiclib -O0 -g -fno-omit-frame-pointer \
|
|
scripts/nix/trace_intel_setup_abort.c -o "$abort_tracer"
|
|
flake_ref="git+file://$GITHUB_WORKSPACE?rev=$(git rev-parse HEAD)"
|
|
original=$(cat <<NIX
|
|
let
|
|
flake = builtins.getFlake "$flake_ref";
|
|
inherit (flake.inputs) haskellNix;
|
|
nativePackages = import (flake.outPath + "/scripts/nix/native-packages.nix") { inherit haskellNix; };
|
|
nativeCompilers = ((nativePackages "x86_64-darwin").appendOverlays [
|
|
(import (haskellNix + "/test/overlay.nix"))
|
|
]).haskell-nix.compiler;
|
|
in nativeCompilers.ghc914-sh.stage2Project.hsPkgs.ghc-boot.components.library
|
|
NIX
|
|
)
|
|
# The failed canonical build already produced this component's inputs.
|
|
# Hosted Intel denies LLDB attach even with a nonzero inferior PID.
|
|
# Use LLDB's Python runner without attempting a debug launch; invoke
|
|
# the unchanged Setup once with the abort tracer instead.
|
|
# Only this diagnostic permits host tool access outside the Nix sandbox.
|
|
exec nix build --file scripts/nix/trace-intel-setup.nix \
|
|
--arg original "$original" --argstr expectedDrv "$expected_drv" \
|
|
--argstr abortTracerPath "$abort_tracer" \
|
|
--argstr captureMode direct-abort \
|
|
--argstr lldbPath "$lldb_path" --option sandbox false \
|
|
--no-link -L --keep-failed --max-jobs 1 --timeout 7200
|
|
TRACE
|
|
|
|
- name: Upload Intel Darwin Setup diagnostic
|
|
if: ${{ always() && steps.intel_setup_trace.outputs.attempted == 'true' }}
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: nix-intel-setup-trace-${{ matrix.system }}-${{ matrix.target }}-${{ github.sha }}
|
|
path: intel-setup-lldb-trace.log
|
|
if-no-files-found: warn
|
|
|
|
- name: Check native CLI encryption and profile passwords
|
|
if: ${{ matrix.target == 'native' || matrix.target == 'all' }}
|
|
run: python3 scripts/nix/smoke-cli.py "result-nix/$NIX_SYSTEM/exe:simplex-chat/bin/simplex-chat"
|
|
|
|
- name: Collect library ZIPs and CLIs
|
|
shell: bash
|
|
run: |
|
|
mkdir -p artifacts
|
|
for output in result-nix/"$NIX_SYSTEM"/*; do
|
|
[ -d "$output" ] || continue
|
|
package_name=$(basename "$output")
|
|
destination="artifacts/${package_name//:/-}"
|
|
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 }}-${{ matrix.target }}-${{ github.sha }}
|
|
path: artifacts/
|
|
if-no-files-found: error
|