Add build-et-binaries workflow to compile the et client
Build the EternalTerminal `et` client in CI the way mosh-client is:
- build-et-binaries.yml builds et for linux x64/arm64, macOS universal
and windows x64, uploads artifacts, and optionally publishes them to a
dedicated binary repository on manual workflow_dispatch.
- scripts/build-et/{linux,macos,windows} compile et from upstream.
- .gitignore excludes the fetched binaries; resources/et/README.md
documents source provenance.
This commit is contained in:
222
.github/workflows/build-et-binaries.yml
vendored
Normal file
222
.github/workflows/build-et-binaries.yml
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
name: build-et-binaries
|
||||
|
||||
# Trigger philosophy (mirrors build-mosh-binaries.yml):
|
||||
# - Pushes that touch the et build pipeline + PRs run the matrix so we can
|
||||
# validate workflow / script changes without tagging. Artifacts upload as
|
||||
# workflow artifacts only; *no* release.
|
||||
# - Manual `workflow_dispatch` with `release_tag` publishes the binaries +
|
||||
# SHA256SUMS to the dedicated binary repository
|
||||
# (`binaricat/Netcatty-et-bin` by default).
|
||||
#
|
||||
# `paths` keeps unrelated commits (UI, bridges, etc) from rebuilding the et
|
||||
# binaries on every push.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
et_ref:
|
||||
description: "EternalTerminal git ref (tag/branch/commit) — see https://github.com/MisterTea/EternalTerminal"
|
||||
type: string
|
||||
default: "et-v6.2.10"
|
||||
release_tag:
|
||||
description: "Optional release tag to attach binaries to (e.g. et-bin-6.2.10-1). Empty = artifacts only."
|
||||
type: string
|
||||
default: ""
|
||||
release_repo:
|
||||
description: "Repository that stores et binary releases."
|
||||
type: string
|
||||
default: "binaricat/Netcatty-et-bin"
|
||||
push:
|
||||
branches:
|
||||
- "**"
|
||||
paths:
|
||||
- ".github/workflows/build-et-binaries.yml"
|
||||
- "electron-builder.config.cjs"
|
||||
- "package.json"
|
||||
- "scripts/build-et/**"
|
||||
- "scripts/fetch-et-binaries.cjs"
|
||||
- "scripts/et-extra-resources.cjs"
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/build-et-binaries.yml"
|
||||
- "electron-builder.config.cjs"
|
||||
- "package.json"
|
||||
- "scripts/build-et/**"
|
||||
- "scripts/fetch-et-binaries.cjs"
|
||||
- "scripts/et-extra-resources.cjs"
|
||||
|
||||
concurrency:
|
||||
group: build-et-binaries-${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
ET_REF: ${{ inputs.et_ref || 'et-v6.2.10' }}
|
||||
|
||||
jobs:
|
||||
# ------------------------------------------------------------------
|
||||
# Linux x64 (manylinux2014 / glibc 2.17, broad distro compatibility).
|
||||
# ------------------------------------------------------------------
|
||||
build-linux-x64:
|
||||
name: build-linux-x64
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build et (linux-x64)
|
||||
run: |
|
||||
docker run --rm \
|
||||
-e ET_REF="${ET_REF}" \
|
||||
-e OUT_DIR=/work/out \
|
||||
-e ARCH=x64 \
|
||||
-v "${GITHUB_WORKSPACE}:/work" \
|
||||
-w /work \
|
||||
quay.io/pypa/manylinux2014_x86_64 \
|
||||
bash scripts/build-et/build-linux.sh
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: et-linux-x64
|
||||
path: out/
|
||||
|
||||
build-linux-arm64:
|
||||
name: build-linux-arm64
|
||||
runs-on: ubuntu-24.04-arm
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build et (linux-arm64)
|
||||
run: |
|
||||
docker run --rm \
|
||||
-e ET_REF="${ET_REF}" \
|
||||
-e OUT_DIR=/work/out \
|
||||
-e ARCH=arm64 \
|
||||
-v "${GITHUB_WORKSPACE}:/work" \
|
||||
-w /work \
|
||||
quay.io/pypa/manylinux2014_aarch64 \
|
||||
bash scripts/build-et/build-linux.sh
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: et-linux-arm64
|
||||
path: out/
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# macOS universal2 (arm64 + x86_64 lipo). Min deployment target macOS 11.
|
||||
# ------------------------------------------------------------------
|
||||
build-macos-universal:
|
||||
name: build-macos-universal
|
||||
runs-on: macos-15
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build et (darwin-universal)
|
||||
env:
|
||||
ET_REF: ${{ env.ET_REF }}
|
||||
OUT_DIR: ${{ github.workspace }}/out
|
||||
MACOSX_DEPLOYMENT_TARGET: "11.0"
|
||||
run: bash scripts/build-et/build-macos.sh
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: et-darwin-universal
|
||||
path: out/
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Windows x64 — static MSVC build (no DLL bundle).
|
||||
# ------------------------------------------------------------------
|
||||
build-windows-x64:
|
||||
name: build-windows-x64
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install ninja
|
||||
run: choco install -y ninja
|
||||
- name: Set up MSVC developer command prompt
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: x64
|
||||
- name: Build et (win32-x64)
|
||||
env:
|
||||
ET_REF: ${{ env.ET_REF }}
|
||||
OUT_DIR: ${{ github.workspace }}\out
|
||||
shell: pwsh
|
||||
run: pwsh -File scripts/build-et/build-windows.ps1
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: et-win32-x64
|
||||
path: out/
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Windows arm64 — intentionally not built until a tested client exists.
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Aggregate + optional release to the dedicated binary repository.
|
||||
# ------------------------------------------------------------------
|
||||
release:
|
||||
name: release
|
||||
needs:
|
||||
- build-linux-x64
|
||||
- build-linux-arm64
|
||||
- build-macos-universal
|
||||
- build-windows-x64
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.release_tag != ''
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Stage release files
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p release
|
||||
for d in artifacts/*/; do
|
||||
find "$d" -maxdepth 1 -type f -exec cp {} release/ \;
|
||||
done
|
||||
(cd release && find . -maxdepth 1 -type f ! -name SHA256SUMS -printf '%P\n' | sort | xargs sha256sum > SHA256SUMS)
|
||||
ls -la release
|
||||
cat release/SHA256SUMS
|
||||
- name: Determine tag
|
||||
id: tag
|
||||
env:
|
||||
RELEASE_TAG: ${{ inputs.release_tag }}
|
||||
run: |
|
||||
tag="${RELEASE_TAG}"
|
||||
if [[ ! "$tag" =~ ^et-bin-[A-Za-z0-9._-]+$ ]]; then
|
||||
echo "Invalid et binary release tag: $tag" >&2
|
||||
exit 1
|
||||
fi
|
||||
printf 'name=%s\n' "$tag" >> "$GITHUB_OUTPUT"
|
||||
- name: Create / update release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.ET_BIN_RELEASE_TOKEN }}
|
||||
RELEASE_REPO: ${{ inputs.release_repo }}
|
||||
RELEASE_TAG: ${{ steps.tag.outputs.name }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ -z "${GH_TOKEN:-}" ]]; then
|
||||
echo "::error::ET_BIN_RELEASE_TOKEN is required to publish into ${RELEASE_REPO}."
|
||||
exit 1
|
||||
fi
|
||||
{
|
||||
printf '%s\n' 'Pre-built EternalTerminal `et` client binaries consumed by `scripts/fetch-et-binaries.cjs` during `npm run pack`.'
|
||||
printf 'Built from `MisterTea/EternalTerminal` upstream ref `%s`.\n\n' "${ET_REF}"
|
||||
printf 'Source workflow: %s/%s/actions/runs/%s\n' "${GITHUB_SERVER_URL}" "${GITHUB_REPOSITORY}" "${GITHUB_RUN_ID}"
|
||||
printf 'Source commit: `%s`\n\n' "${GITHUB_SHA}"
|
||||
printf '%s\n' 'All artifacts are Apache-2.0; see `resources/et/README.md` for source provenance.'
|
||||
} > release-notes.md
|
||||
if gh release view "${RELEASE_TAG}" --repo "${RELEASE_REPO}" >/dev/null 2>&1; then
|
||||
gh release edit "${RELEASE_TAG}" \
|
||||
--repo "${RELEASE_REPO}" \
|
||||
--title "${RELEASE_TAG}" \
|
||||
--notes-file release-notes.md
|
||||
gh release upload "${RELEASE_TAG}" release/* \
|
||||
--repo "${RELEASE_REPO}" \
|
||||
--clobber
|
||||
else
|
||||
gh release create "${RELEASE_TAG}" release/* \
|
||||
--repo "${RELEASE_REPO}" \
|
||||
--title "${RELEASE_TAG}" \
|
||||
--notes-file release-notes.md
|
||||
fi
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -73,3 +73,12 @@ build_with_vs2022.bat
|
||||
/resources/mosh/*/mosh-client-*-dlls/
|
||||
/resources/mosh/*/*.dll
|
||||
/resources/mosh/*/terminfo/
|
||||
|
||||
# Bundled EternalTerminal `et` client binaries fetched at pack time by
|
||||
# scripts/fetch-et-binaries.cjs. resources/et/README.md is committed; the
|
||||
# actual binaries (and any DLL bundle for dynamically-linked Windows builds)
|
||||
# are pulled from the dedicated et binary repository, never committed.
|
||||
/resources/et/*/et
|
||||
/resources/et/*/et.exe
|
||||
/resources/et/*/et-*-dlls/
|
||||
/resources/et/*/*.dll
|
||||
|
||||
81
resources/et/README.md
Normal file
81
resources/et/README.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Bundled EternalTerminal `et` client
|
||||
|
||||
This directory holds the EternalTerminal **client** binary (`et`) bundled
|
||||
with the Netcatty installer. Netcatty launches this bundled `et` directly
|
||||
(see `electron/bridges/terminalBridge/etSession.cjs`); `et` performs its
|
||||
own SSH bootstrap and EternalTerminal protocol handshake against the remote
|
||||
`etserver` / `etterminal`.
|
||||
|
||||
Unlike `mosh-client`, `et` is a pure network-transport client and does not
|
||||
render a terminal locally, so there is **no terminfo bundle** here — only the
|
||||
single `et` (`et.exe` on Windows) binary.
|
||||
|
||||
## How binaries land here
|
||||
|
||||
1. `.github/workflows/build-et-binaries.yml` builds `et` on relevant
|
||||
pushes/PRs, or on a manual `workflow_dispatch`. It uses
|
||||
`scripts/build-et/build-linux.sh` and `scripts/build-et/build-macos.sh`
|
||||
for Linux/macOS, and `scripts/build-et/build-windows.ps1` for Windows:
|
||||
|
||||
| target | provenance |
|
||||
|-------------------|------------------------------------------------------------------|
|
||||
| `linux-x64` | upstream source, manylinux2014, vcpkg static deps + glibc |
|
||||
| `linux-arm64` | upstream source, manylinux2014, vcpkg static deps + glibc |
|
||||
| `darwin-universal`| upstream source, lipo arm64 + x86_64, macOS system dylibs only |
|
||||
| `win32-x64` | upstream source, MSVC + vcpkg `x64-windows-static` (no DLLs) |
|
||||
| `win32-arm64` | (not built — add after a tested arm64 client is available) |
|
||||
|
||||
ET builds with CMake + Ninja + vcpkg
|
||||
(`cmake -DDISABLE_TELEMETRY=ON -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo`).
|
||||
|
||||
2. When manually dispatched with `release_tag`, that workflow publishes the
|
||||
binaries to the dedicated `binaricat/Netcatty-et-bin` repository. The
|
||||
release gets a tag like `et-bin-6.2.10-1`, with `SHA256SUMS` attached.
|
||||
|
||||
3. Release packaging runs `scripts/resolve-et-bin-release.cjs` before
|
||||
`npm run fetch:et`. It uses an explicit workflow input first, then the
|
||||
`ET_BIN_RELEASE` repository variable, then the latest non-draft
|
||||
`et-bin-*` GitHub Release from the dedicated binary repository. The fetch
|
||||
step pulls the binaries into `resources/et/<platform-arch>/`. For local
|
||||
packaging, set `ET_BIN_RELEASE` yourself before running the same fetch
|
||||
command. Override `ET_BIN_OWNER` / `ET_BIN_REPO` only when testing a
|
||||
different binary repository. `electron-builder.config.cjs` then copies the
|
||||
matching binary into `Resources/et/et[.exe]`.
|
||||
|
||||
Local dev uses the same binary path: `npm run dev` runs
|
||||
`npm run fetch:et:dev` first, which downloads the host platform's bundled
|
||||
`et` into this gitignored directory. Netcatty does not fall back to a
|
||||
system-installed `et`; if the bundled binary is missing, ET startup fails
|
||||
loudly instead of using whatever happens to be installed on the developer
|
||||
machine.
|
||||
|
||||
The directory is otherwise empty (binaries are gitignored).
|
||||
|
||||
## Licenses
|
||||
|
||||
- EternalTerminal is licensed under **Apache-2.0**
|
||||
(https://github.com/MisterTea/EternalTerminal).
|
||||
- Netcatty is **GPL-3.0**; Apache-2.0 is one-way compatible with GPL-3.0, so
|
||||
redistribution as part of the installer is permitted.
|
||||
- vcpkg-managed deps (boost Boost-License, libsodium ISC, protobuf
|
||||
BSD-3-Clause, gflags BSD-3-Clause) are compatible with GPL-3.0.
|
||||
|
||||
## Reproducible build
|
||||
|
||||
To reproduce the Linux binary locally:
|
||||
|
||||
```sh
|
||||
docker run --rm -v $PWD:/workspace -w /workspace \
|
||||
-e ET_REF=et-v6.2.10 -e ARCH=x64 -e OUT_DIR=/workspace/out \
|
||||
quay.io/pypa/manylinux2014_x86_64 \
|
||||
bash scripts/build-et/build-linux.sh
|
||||
```
|
||||
|
||||
For macOS the build needs an Xcode toolchain; see
|
||||
`scripts/build-et/build-macos.sh`. For Windows see
|
||||
`scripts/build-et/build-windows.ps1`.
|
||||
|
||||
## Roadmap
|
||||
|
||||
- Add Windows arm64 only after a tested standalone arm64 client is available.
|
||||
- Make `ET_REF` track upstream release tags automatically.
|
||||
155
scripts/build-et/build-linux.sh
Normal file
155
scripts/build-et/build-linux.sh
Normal file
@@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build a portable EternalTerminal `et` client inside manylinux2014.
|
||||
#
|
||||
# Inputs (env):
|
||||
# ET_REF — git ref of MisterTea/EternalTerminal to build (e.g. et-v6.2.10)
|
||||
# ARCH — x64 | arm64 (for output naming only; container is already that arch)
|
||||
# OUT_DIR — directory to write et-linux-<arch>.tar.gz + sha256
|
||||
#
|
||||
# Output:
|
||||
# $OUT_DIR/et-linux-<arch>.tar.gz (single `et` client binary)
|
||||
# $OUT_DIR/et-linux-<arch>.tar.gz.sha256
|
||||
#
|
||||
# Strategy: build inside manylinux2014 (glibc 2.17) for broad distro
|
||||
# compatibility. EternalTerminal vendors vcpkg under external/vcpkg and uses
|
||||
# manifest mode, so its third-party deps (protobuf, libsodium, openssl, ...)
|
||||
# are built as static archives by vcpkg's x64-linux / arm64-linux triplet.
|
||||
# The resulting `et` still depends on baseline Linux system libraries
|
||||
# (glibc family), compatible with virtually every distro since 2014.
|
||||
#
|
||||
# `et` is a pure network-transport client; it renders no terminal locally and
|
||||
# needs no terminfo database, so the bundle ships only the binary.
|
||||
set -euo pipefail
|
||||
|
||||
: "${ET_REF:?missing ET_REF}"
|
||||
: "${ARCH:?missing ARCH}"
|
||||
: "${OUT_DIR:?missing OUT_DIR}"
|
||||
|
||||
validate_et_ref() {
|
||||
if [[ ! "$ET_REF" =~ ^[A-Za-z0-9][A-Za-z0-9._/-]*$ ]] \
|
||||
|| [[ "$ET_REF" == *..* ]] \
|
||||
|| [[ "$ET_REF" == *@\{* ]] \
|
||||
|| [[ "$ET_REF" == */ ]] \
|
||||
|| [[ "$ET_REF" == *.lock ]]; then
|
||||
echo "ERROR: invalid ET_REF: $ET_REF" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
validate_et_ref
|
||||
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
# manylinux2014 ships a devtoolset gcc and git, but an old cmake/ninja.
|
||||
# Install modern cmake + ninja from PyPI (vcpkg requires cmake >= 3.x).
|
||||
yum install -y -q zip unzip tar curl perl-IPC-Cmd >/dev/null 2>&1 || true
|
||||
|
||||
# manylinux ships CPython interpreters under /opt/python/<tag>/bin but puts
|
||||
# none of them on PATH (a bare `python3` fails with 127). Prefer a known
|
||||
# *stable* cpXY: picking "newest" would grab pre-release builds such as
|
||||
# 3.15.0b1, which we don't want driving the cmake/ninja install.
|
||||
if ! command -v python3 >/dev/null 2>&1; then
|
||||
for tag in cp313 cp312 cp311 cp310; do
|
||||
if [ -x "/opt/python/$tag-$tag/bin/python3" ]; then
|
||||
export PATH="/opt/python/$tag-$tag/bin:$PATH"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
command -v python3 >/dev/null 2>&1 \
|
||||
|| { echo "ERROR: no stable python3 under /opt/python (manylinux layout changed?)" >&2; exit 1; }
|
||||
|
||||
python3 -m pip install --quiet --upgrade pip
|
||||
# Pin cmake < 4: ET's pinned vcpkg baseline and some ports don't configure
|
||||
# cleanly under cmake 4.x. ninja is unconstrained.
|
||||
python3 -m pip install --quiet "cmake>=3.25,<4" ninja
|
||||
export PATH="$(python3 -c 'import sysconfig,os;print(os.path.join(sysconfig.get_path("scripts")))'):$PATH"
|
||||
|
||||
cd "$WORK"
|
||||
|
||||
# Fetch EternalTerminal at the requested ref, with the vendored vcpkg
|
||||
# submodule. Branch names, tags, and commit SHAs all work.
|
||||
git init et
|
||||
git -C et remote add origin https://github.com/MisterTea/EternalTerminal.git
|
||||
git -C et fetch --depth 1 origin "$ET_REF"
|
||||
git -C et checkout --detach FETCH_HEAD
|
||||
git -C et submodule update --init --recursive --depth 1
|
||||
|
||||
# Drop sentry-native from the vcpkg manifest. We build with
|
||||
# -DDISABLE_TELEMETRY=ON, so ET's CMake never calls find_package(sentry) nor
|
||||
# links it; but vcpkg's manifest mode still force-builds every listed dep
|
||||
# during configure. sentry-native pulls in crashpad, is the heaviest dep, and
|
||||
# fails to build on arm64-linux — dropping it fixes arm64 and speeds up all.
|
||||
if ! grep -q '"sentry-native"' "$WORK/et/vcpkg.json"; then
|
||||
echo "ERROR: sentry-native not in vcpkg.json (ET manifest changed?)" >&2; exit 1
|
||||
fi
|
||||
grep -v '"sentry-native"' "$WORK/et/vcpkg.json" > "$WORK/et/vcpkg.json.tmp"
|
||||
mv "$WORK/et/vcpkg.json.tmp" "$WORK/et/vcpkg.json"
|
||||
|
||||
# Build only the Release halves of the vcpkg deps (skip the Debug pass) to
|
||||
# roughly halve build time. Overlay triplets mirror ET's chosen community
|
||||
# triplet but force release-only; selected via VCPKG_OVERLAY_TRIPLETS so the
|
||||
# vendored vcpkg tree stays untouched.
|
||||
OVERLAY="$WORK/vcpkg-overlay-triplets"
|
||||
mkdir -p "$OVERLAY"
|
||||
for t in x64-linux arm64-linux; do
|
||||
src=$(find "$WORK/et/external/vcpkg/triplets" -name "$t.cmake" | head -1)
|
||||
[ -n "$src" ] || { echo "ERROR: vcpkg triplet $t.cmake not found" >&2; exit 1; }
|
||||
cp "$src" "$OVERLAY/$t.cmake"
|
||||
echo 'set(VCPKG_BUILD_TYPE release)' >> "$OVERLAY/$t.cmake"
|
||||
done
|
||||
export VCPKG_OVERLAY_TRIPLETS="$OVERLAY"
|
||||
|
||||
# Bootstrap the vendored vcpkg so CMake's vcpkg toolchain can resolve the
|
||||
# manifest deps.
|
||||
( cd et && ./external/vcpkg/bootstrap-vcpkg.sh -disableMetrics )
|
||||
|
||||
BUILD_DIR="$WORK/et/build"
|
||||
# ET's CMake sets its own vcpkg toolchain + triplet (auto-detected from
|
||||
# uname -m); we supply only the generator + build type. DISABLE_TELEMETRY=ON
|
||||
# keeps ET from using Sentry, matching the manifest edit above.
|
||||
#
|
||||
# CMAKE_CXX_STANDARD_LIBRARIES=-lanl: ET (via cpp-httplib) references glibc's
|
||||
# async DNS resolver getaddrinfo_a / gai_* (which live in libanl), but ET's
|
||||
# link line omits -lanl, so linking `et` fails with "undefined reference to
|
||||
# getaddrinfo_a". STANDARD_LIBRARIES is appended after all other libraries —
|
||||
# exactly where the linker needs it to resolve those symbols.
|
||||
cmake -S "$WORK/et" -B "$BUILD_DIR" \
|
||||
-GNinja \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DDISABLE_TELEMETRY=ON \
|
||||
-DCMAKE_CXX_STANDARD_LIBRARIES=-lanl
|
||||
|
||||
cmake --build "$BUILD_DIR" --target et
|
||||
|
||||
BUNDLE_DIR="$WORK/linux-$ARCH-bundle"
|
||||
mkdir -p "$BUNDLE_DIR"
|
||||
OUT_BIN="$BUNDLE_DIR/et"
|
||||
cp "$BUILD_DIR/et" "$OUT_BIN"
|
||||
strip "$OUT_BIN"
|
||||
|
||||
echo "--- file ---"
|
||||
file "$OUT_BIN"
|
||||
echo "--- ldd ---"
|
||||
ldd "$OUT_BIN" || true
|
||||
echo "--- size ---"
|
||||
ls -lh "$OUT_BIN"
|
||||
|
||||
# Sanity check: must not link any non-system shared libraries. Allow only the
|
||||
# glibc runtime family and the ELF loader (matches the mosh build policy).
|
||||
ldd "$OUT_BIN" > "$WORK/ldd.txt" || true
|
||||
awk '
|
||||
/=>/ { print $1; next }
|
||||
/^[[:space:]]*\/.*ld-linux/ { print $1; next }
|
||||
' "$WORK/ldd.txt" > "$WORK/deps.txt"
|
||||
if grep -Ev '^(linux-vdso\.so\.1|lib(c|m|pthread|rt|dl|resolv|util|z|stdc\+\+|gcc_s|atomic|anl)\.so\.[0-9]+|/lib.*/ld-linux.*\.so\.[0-9]+|ld-linux.*\.so\.[0-9]+)$' "$WORK/deps.txt"; then
|
||||
echo "ERROR: et links a non-system shared library; static linking failed." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BUNDLE_TGZ="$OUT_DIR/et-linux-$ARCH.tar.gz"
|
||||
( cd "$BUNDLE_DIR" && tar -czf "$BUNDLE_TGZ" "et" )
|
||||
|
||||
( cd "$OUT_DIR" && sha256sum "et-linux-$ARCH.tar.gz" > "et-linux-$ARCH.tar.gz.sha256" )
|
||||
cat "$OUT_DIR/et-linux-$ARCH.tar.gz.sha256"
|
||||
115
scripts/build-et/build-macos.sh
Normal file
115
scripts/build-et/build-macos.sh
Normal file
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build a universal EternalTerminal `et` client on macOS (arm64 + x86_64).
|
||||
#
|
||||
# Inputs (env):
|
||||
# ET_REF — git ref of MisterTea/EternalTerminal to build (e.g. et-v6.2.10)
|
||||
# OUT_DIR — directory to write et-darwin-universal.tar.gz + sha256
|
||||
# MACOSX_DEPLOYMENT_TARGET — min macOS (default 11.0)
|
||||
#
|
||||
# Output:
|
||||
# $OUT_DIR/et-darwin-universal.tar.gz (single universal `et`)
|
||||
# $OUT_DIR/et-darwin-universal.tar.gz.sha256
|
||||
#
|
||||
# Builds each arch separately (vcpkg arm64-osx / x64-osx static triplets) and
|
||||
# lipo-combines the two `et` binaries. Links only macOS system dylibs.
|
||||
set -euo pipefail
|
||||
|
||||
: "${ET_REF:?missing ET_REF}"
|
||||
: "${OUT_DIR:?missing OUT_DIR}"
|
||||
export MACOSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET:-11.0}"
|
||||
|
||||
validate_et_ref() {
|
||||
if [[ ! "$ET_REF" =~ ^[A-Za-z0-9][A-Za-z0-9._/-]*$ ]] \
|
||||
|| [[ "$ET_REF" == *..* ]] \
|
||||
|| [[ "$ET_REF" == *@\{* ]] \
|
||||
|| [[ "$ET_REF" == */ ]] \
|
||||
|| [[ "$ET_REF" == *.lock ]]; then
|
||||
echo "ERROR: invalid ET_REF: $ET_REF" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
validate_et_ref
|
||||
|
||||
command -v ninja >/dev/null 2>&1 || brew install ninja
|
||||
command -v cmake >/dev/null 2>&1 || brew install cmake
|
||||
command -v autoconf >/dev/null 2>&1 || brew install automake autoconf libtool
|
||||
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
cd "$WORK"
|
||||
git init et
|
||||
git -C et remote add origin https://github.com/MisterTea/EternalTerminal.git
|
||||
git -C et fetch --depth 1 origin "$ET_REF"
|
||||
git -C et checkout --detach FETCH_HEAD
|
||||
git -C et submodule update --init --recursive --depth 1
|
||||
|
||||
# Drop sentry-native from the vcpkg manifest — see build-linux.sh for the
|
||||
# full rationale. -DDISABLE_TELEMETRY=ON means ET never references Sentry,
|
||||
# yet vcpkg's manifest would otherwise force-build it (and crashpad) anyway.
|
||||
if ! grep -q '"sentry-native"' "$WORK/et/vcpkg.json"; then
|
||||
echo "ERROR: sentry-native not in vcpkg.json (ET manifest changed?)" >&2; exit 1
|
||||
fi
|
||||
grep -v '"sentry-native"' "$WORK/et/vcpkg.json" > "$WORK/et/vcpkg.json.tmp"
|
||||
mv "$WORK/et/vcpkg.json.tmp" "$WORK/et/vcpkg.json"
|
||||
|
||||
# Release-only vcpkg deps (skip the Debug pass) to halve build time, via
|
||||
# overlay triplets that mirror the osx triplets but force release-only.
|
||||
OVERLAY="$WORK/vcpkg-overlay-triplets"
|
||||
mkdir -p "$OVERLAY"
|
||||
for t in arm64-osx x64-osx; do
|
||||
src=$(find "$WORK/et/external/vcpkg/triplets" -name "$t.cmake" | head -1)
|
||||
[ -n "$src" ] || { echo "ERROR: vcpkg triplet $t.cmake not found" >&2; exit 1; }
|
||||
cp "$src" "$OVERLAY/$t.cmake"
|
||||
echo 'set(VCPKG_BUILD_TYPE release)' >> "$OVERLAY/$t.cmake"
|
||||
done
|
||||
export VCPKG_OVERLAY_TRIPLETS="$OVERLAY"
|
||||
|
||||
( cd et && ./external/vcpkg/bootstrap-vcpkg.sh -disableMetrics )
|
||||
|
||||
build_arch() {
|
||||
local arch="$1" # arm64 | x86_64
|
||||
local triplet="$2" # arm64-osx | x64-osx
|
||||
local build_dir="$WORK/build-$arch"
|
||||
echo "=== building et for $arch ($triplet) ==="
|
||||
cmake -S "$WORK/et" -B "$build_dir" \
|
||||
-GNinja \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DDISABLE_TELEMETRY=ON \
|
||||
-DCMAKE_OSX_ARCHITECTURES="$arch" \
|
||||
-DVCPKG_TARGET_TRIPLET="$triplet"
|
||||
cmake --build "$build_dir" --target et
|
||||
echo "$build_dir/et"
|
||||
}
|
||||
|
||||
ARM_BIN=$(build_arch arm64 arm64-osx | tail -1)
|
||||
X64_BIN=$(build_arch x86_64 x64-osx | tail -1)
|
||||
|
||||
BUNDLE_DIR="$WORK/darwin-universal-bundle"
|
||||
mkdir -p "$BUNDLE_DIR"
|
||||
OUT_BIN="$BUNDLE_DIR/et"
|
||||
lipo -create -output "$OUT_BIN" "$ARM_BIN" "$X64_BIN"
|
||||
strip "$OUT_BIN" || true
|
||||
|
||||
echo "--- lipo info ---"
|
||||
lipo -info "$OUT_BIN"
|
||||
echo "--- otool -L ---"
|
||||
otool -L "$OUT_BIN" || true
|
||||
|
||||
# Sanity check: only macOS system dylibs (/usr/lib, /System/Library) allowed.
|
||||
# A universal binary makes `otool -L` print a "<path> (architecture X):"
|
||||
# header per slice; key off the "(compatibility version ...)" suffix that only
|
||||
# real dependency lines carry, so those per-arch headers aren't misread as a
|
||||
# non-system dylib (tail -n +2 only drops the first one).
|
||||
if otool -L "$OUT_BIN" | awk '/\(compatibility version/ {print $1}' \
|
||||
| grep -Ev '^(/usr/lib/|/System/Library/)' | grep -q .; then
|
||||
echo "ERROR: et links a non-system dylib; static linking failed." >&2
|
||||
otool -L "$OUT_BIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BUNDLE_TGZ="$OUT_DIR/et-darwin-universal.tar.gz"
|
||||
( cd "$BUNDLE_DIR" && tar -czf "$BUNDLE_TGZ" "et" )
|
||||
( cd "$OUT_DIR" && shasum -a 256 "et-darwin-universal.tar.gz" > "et-darwin-universal.tar.gz.sha256" )
|
||||
cat "$OUT_DIR/et-darwin-universal.tar.gz.sha256"
|
||||
105
scripts/build-et/build-windows.ps1
Normal file
105
scripts/build-et/build-windows.ps1
Normal file
@@ -0,0 +1,105 @@
|
||||
# Build a static EternalTerminal `et` client on Windows (x64, MSVC).
|
||||
#
|
||||
# Inputs (env):
|
||||
# ET_REF — git ref of MisterTea/EternalTerminal to build (e.g. et-v6.2.10)
|
||||
# OUT_DIR — directory to write et-win32-x64.tar.gz + sha256
|
||||
#
|
||||
# Output:
|
||||
# $OUT_DIR/et-win32-x64.tar.gz (single static et.exe, no DLLs)
|
||||
# $OUT_DIR/et-win32-x64.tar.gz.sha256
|
||||
#
|
||||
# Uses the vendored vcpkg x64-windows-static triplet so the produced et.exe
|
||||
# statically links the MSVC runtime and all third-party deps — no DLL bundle
|
||||
# is needed. Run from a Developer Command Prompt (ilammy/msvc-dev-cmd) so
|
||||
# cl.exe / ninja are on PATH.
|
||||
$ErrorActionPreference = "Stop"
|
||||
Set-StrictMode -Version Latest
|
||||
|
||||
if (-not $env:ET_REF) { throw "missing ET_REF" }
|
||||
if (-not $env:OUT_DIR) { throw "missing OUT_DIR" }
|
||||
|
||||
$etRef = $env:ET_REF
|
||||
if ($etRef -notmatch '^[A-Za-z0-9][A-Za-z0-9._/-]*$' -or $etRef -match '\.\.' -or $etRef -match '@\{' -or $etRef.EndsWith('/') -or $etRef.EndsWith('.lock')) {
|
||||
throw "invalid ET_REF: $etRef"
|
||||
}
|
||||
|
||||
# Root the build just under the drive root. vcpkg unpacks dependencies into
|
||||
# <work>\et\external_imported\vcpkg\buildtrees\... and libsodium's bundled
|
||||
# MSBuild project pulls sources via long "..\..\..\..\src\..." relative paths.
|
||||
# Rooted in %TEMP% (~60 chars) the unnormalized path exceeds Windows MAX_PATH
|
||||
# (260) and fails with "C1083: Cannot open source file". A short drive-root
|
||||
# (e.g. C:\et-XXXXXXXX) keeps every path comfortably under the limit.
|
||||
$work = "$env:SystemDrive\et-" + [System.Guid]::NewGuid().ToString("N").Substring(0, 8)
|
||||
if (Test-Path $work) { Remove-Item -Recurse -Force $work -ErrorAction SilentlyContinue }
|
||||
New-Item -ItemType Directory -Force -Path $work | Out-Null
|
||||
New-Item -ItemType Directory -Force -Path $env:OUT_DIR | Out-Null
|
||||
|
||||
try {
|
||||
$etDir = Join-Path $work "et"
|
||||
git init $etDir
|
||||
git -C $etDir remote add origin https://github.com/MisterTea/EternalTerminal.git
|
||||
git -C $etDir fetch --depth 1 origin $etRef
|
||||
git -C $etDir checkout --detach FETCH_HEAD
|
||||
git -C $etDir submodule update --init --recursive --depth 1
|
||||
|
||||
# Drop sentry-native from the vcpkg manifest. We configure with
|
||||
# -DDISABLE_TELEMETRY=ON so ET never references Sentry, but vcpkg's manifest
|
||||
# mode would still force-build it (and crashpad). Removing it avoids an
|
||||
# unused heavy dependency and speeds up the build.
|
||||
$manifest = Join-Path $etDir "vcpkg.json"
|
||||
if (-not (Select-String -Path $manifest -Pattern '"sentry-native"' -Quiet)) {
|
||||
throw "sentry-native not in vcpkg.json (ET manifest changed?)"
|
||||
}
|
||||
(Get-Content $manifest) | Where-Object { $_ -notmatch '"sentry-native"' } | Set-Content $manifest
|
||||
|
||||
# Build only the Release halves of the vcpkg deps (skip Debug) to roughly
|
||||
# halve build time, via an overlay triplet mirroring x64-windows-static but
|
||||
# forcing release-only.
|
||||
$overlay = Join-Path $work "vcpkg-overlay-triplets"
|
||||
New-Item -ItemType Directory -Force -Path $overlay | Out-Null
|
||||
$srcTriplet = Join-Path $etDir "external\vcpkg\triplets\x64-windows-static.cmake"
|
||||
if (-not (Test-Path $srcTriplet)) {
|
||||
$srcTriplet = Join-Path $etDir "external\vcpkg\triplets\community\x64-windows-static.cmake"
|
||||
}
|
||||
if (-not (Test-Path $srcTriplet)) { throw "vcpkg triplet x64-windows-static.cmake not found" }
|
||||
Copy-Item $srcTriplet (Join-Path $overlay "x64-windows-static.cmake")
|
||||
Add-Content -Path (Join-Path $overlay "x64-windows-static.cmake") -Value 'set(VCPKG_BUILD_TYPE release)'
|
||||
$env:VCPKG_OVERLAY_TRIPLETS = $overlay
|
||||
|
||||
& (Join-Path $etDir "external\vcpkg\bootstrap-vcpkg.bat") -disableMetrics
|
||||
|
||||
$buildDir = Join-Path $etDir "build"
|
||||
cmake -S $etDir -B $buildDir `
|
||||
-GNinja `
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo `
|
||||
-DDISABLE_TELEMETRY=ON `
|
||||
-DVCPKG_TARGET_TRIPLET=x64-windows-static
|
||||
if ($LASTEXITCODE -ne 0) { throw "cmake configure failed" }
|
||||
|
||||
cmake --build $buildDir --target et
|
||||
if ($LASTEXITCODE -ne 0) { throw "cmake build failed" }
|
||||
|
||||
$bundleDir = Join-Path $work "win32-x64-bundle"
|
||||
New-Item -ItemType Directory -Force -Path $bundleDir | Out-Null
|
||||
$srcExe = Join-Path $buildDir "et.exe"
|
||||
if (-not (Test-Path $srcExe)) { $srcExe = Join-Path $buildDir "RelWithDebInfo\et.exe" }
|
||||
Copy-Item $srcExe (Join-Path $bundleDir "et.exe")
|
||||
|
||||
# Report any non-system DLL imports (informational; a static build should
|
||||
# only import the in-box Windows DLLs).
|
||||
Write-Host "--- et.exe built ---"
|
||||
Get-Item (Join-Path $bundleDir "et.exe") | Format-List Name, Length
|
||||
|
||||
$tgz = Join-Path $env:OUT_DIR "et-win32-x64.tar.gz"
|
||||
# Windows ships bsdtar as tar.exe.
|
||||
tar -czf $tgz -C $bundleDir "et.exe"
|
||||
if ($LASTEXITCODE -ne 0) { throw "tar failed" }
|
||||
|
||||
$hash = (Get-FileHash -Algorithm SHA256 $tgz).Hash.ToLower()
|
||||
$sumLine = "$hash et-win32-x64.tar.gz"
|
||||
Set-Content -Path (Join-Path $env:OUT_DIR "et-win32-x64.tar.gz.sha256") -Value $sumLine -NoNewline
|
||||
Write-Host $sumLine
|
||||
}
|
||||
finally {
|
||||
Remove-Item -Recurse -Force $work -ErrorAction SilentlyContinue
|
||||
}
|
||||
Reference in New Issue
Block a user