2025-12-09 07:47:17 +01:00
#!/usr/bin/env bash
set -euo pipefail
# Build a nomos-binaries.tar.gz for the specified platform.
#
2025-12-15 17:08:48 +01:00
# Usage: scripts/build-bundle.sh [--platform host|linux] [--output PATH] [--rev REV | --path DIR] [--features LIST] [--docker-platform PLATFORM]
# --platform Target platform for binaries (default: host)
# --output Output path for the tarball (default: .tmp/nomos-binaries-<platform>-<version>.tar.gz)
# --rev nomos-node git revision to build (overrides NOMOS_NODE_REV)
# --path Use local nomos-node checkout at DIR (skip fetch/checkout)
# --features Extra cargo features to enable (comma-separated); base always includes "testing"
2025-12-15 20:38:58 +01:00
# --docker-platform Docker platform for Linux bundle when running on non-Linux host (default: auto; linux/arm64 on Apple silicon Docker Desktop, else linux/amd64)
2025-12-13 05:59:28 +01:00
# Always run under bash; bail out if someone invokes via sh.
if [ -z " ${ BASH_VERSION :- } " ] ; then
exec bash " $0 " " $@ "
fi
2025-12-09 07:47:17 +01:00
usage( ) {
2025-12-15 17:08:48 +01:00
cat <<'USAGE'
2025-12-09 07:47:17 +01:00
Usage: scripts/build-bundle.sh [ --platform host| linux] [ --output PATH]
Options:
2025-12-15 17:08:48 +01:00
--platform Target platform for binaries ( default: host)
--output Output path for the tarball ( default: .tmp/nomos-binaries-<platform>-<version>.tar.gz)
--rev nomos-node git revision to build ( overrides NOMOS_NODE_REV)
--path Use local nomos-node checkout at DIR ( skip fetch/checkout)
--features Extra cargo features to enable ( comma-separated) ; base always includes "testing"
2025-12-15 20:38:58 +01:00
--docker-platform Docker platform for Linux bundle when running on non-Linux host ( default: auto; linux/arm64 on Apple silicon Docker Desktop, else linux/amd64)
2025-12-09 07:47:17 +01:00
Notes:
- For compose/k8s, use platform = linux. If running on macOS, this script will
run inside a Linux Docker container to produce Linux binaries.
2025-12-15 17:08:48 +01:00
- On Apple silicon, Docker defaults to linux/arm64; for compose/k8s you likely
want linux/amd64 ( the default here) . Override with --docker-platform.
2025-12-13 05:59:28 +01:00
- VERSION, NOMOS_NODE_REV, and optional NOMOS_NODE_PATH env vars are honored ( defaults align with run-examples.sh) .
2025-12-15 17:08:48 +01:00
USAGE
2025-12-09 07:47:17 +01:00
}
fail( ) { echo " $1 " >& 2; exit 1; }
if [ " ${ 1 :- } " = "-h" ] || [ " ${ 1 :- } " = "--help" ] ; then
2025-12-15 17:08:48 +01:00
usage
exit 0
2025-12-09 07:47:17 +01:00
fi
2025-12-15 17:08:48 +01:00
NOMOS_EXTRA_FEATURES = " ${ NOMOS_EXTRA_FEATURES :- } "
2025-12-09 07:47:17 +01:00
ROOT_DIR = " $( cd " $( dirname " ${ BASH_SOURCE [0] } " ) /.. " && pwd ) "
2025-12-09 15:38:33 +01:00
if [ -f " ${ ROOT_DIR } /versions.env " ] ; then
# shellcheck disable=SC1091
. " ${ ROOT_DIR } /versions.env "
2025-12-09 17:24:11 +01:00
else
echo "ERROR: versions.env missing; run from repo root or restore the file." >& 2
exit 1
2025-12-09 15:38:33 +01:00
fi
2025-12-10 10:33:51 +01:00
DEFAULT_VERSION = " ${ VERSION : ?Missing VERSION in versions.env } "
2025-12-13 05:59:28 +01:00
DEFAULT_NODE_REV = " ${ NOMOS_NODE_REV :- } "
DEFAULT_NODE_PATH = " ${ NOMOS_NODE_PATH :- } "
2025-12-09 07:47:17 +01:00
PLATFORM = "host"
OUTPUT = ""
2025-12-13 05:59:28 +01:00
REV_OVERRIDE = ""
PATH_OVERRIDE = ""
2025-12-15 20:38:58 +01:00
DOCKER_PLATFORM = " ${ NOMOS_BUNDLE_DOCKER_PLATFORM :- ${ NOMOS_BIN_PLATFORM :- } } "
2025-12-15 17:47:00 +01:00
BUNDLE_RUSTUP_TOOLCHAIN = " ${ BUNDLE_RUSTUP_TOOLCHAIN :- } "
if [ -z " ${ BUNDLE_RUSTUP_TOOLCHAIN } " ] && command -v rustup >/dev/null 2>& 1 && [ -f " ${ ROOT_DIR } /rust-toolchain.toml " ] ; then
BUNDLE_RUSTUP_TOOLCHAIN = " $( awk -F '\"' '/^[[:space:]]*channel[[:space:]]*=/{print $2; exit}' " ${ ROOT_DIR } /rust-toolchain.toml " ) "
fi
2025-12-13 05:59:28 +01:00
2025-12-15 20:38:58 +01:00
# Default Docker platform to the engine architecture when possible.
if [ -z " ${ DOCKER_PLATFORM } " ] && command -v docker >/dev/null 2>& 1; then
docker_arch = " $( docker version --format '{{.Server.Arch}}' 2>/dev/null || true ) "
case " ${ docker_arch } " in
arm64| aarch64) DOCKER_PLATFORM = "linux/arm64" ; ;
amd64| x86_64) DOCKER_PLATFORM = "linux/amd64" ; ;
*) DOCKER_PLATFORM = "linux/amd64" ; ;
esac
fi
DOCKER_PLATFORM = " ${ DOCKER_PLATFORM :- linux /amd64 } "
2025-12-13 05:59:28 +01:00
# To avoid confusing cache corruption errors inside the Dockerized Linux build,
# always start from a clean cargo registry/git cache for the cross-build.
rm -rf " ${ ROOT_DIR } /.tmp/cargo-linux/registry " " ${ ROOT_DIR } /.tmp/cargo-linux/git "
2025-12-09 07:47:17 +01:00
while [ " $# " -gt 0 ] ; do
case " $1 " in
2025-12-15 17:08:48 +01:00
--platform= *| -p= *) PLATFORM = " ${ 1 #*= } " ; shift ; ;
--platform| -p) PLATFORM = " ${ 2 :- } " ; shift 2 ; ;
--output= *| -o= *) OUTPUT = " ${ 1 #*= } " ; shift ; ;
--output| -o) OUTPUT = " ${ 2 :- } " ; shift 2 ; ;
--rev= *) REV_OVERRIDE = " ${ 1 #*= } " ; shift ; ;
--rev) REV_OVERRIDE = " ${ 2 :- } " ; shift 2 ; ;
--path= *) PATH_OVERRIDE = " ${ 1 #*= } " ; shift ; ;
--path) PATH_OVERRIDE = " ${ 2 :- } " ; shift 2 ; ;
--features= *) NOMOS_EXTRA_FEATURES = " ${ 1 #*= } " ; shift ; ;
--features) NOMOS_EXTRA_FEATURES = " ${ 2 :- } " ; shift 2 ; ;
--docker-platform= *) DOCKER_PLATFORM = " ${ 1 #*= } " ; shift ; ;
--docker-platform) DOCKER_PLATFORM = " ${ 2 :- } " ; shift 2 ; ;
2025-12-09 07:47:17 +01:00
*) fail " Unknown argument: $1 " ; ;
esac
done
case " $PLATFORM " in
host| linux) ; ;
*) fail "--platform must be host or linux" ; ;
esac
2025-12-10 10:33:51 +01:00
VERSION = " ${ DEFAULT_VERSION } "
2025-12-13 05:59:28 +01:00
if [ -n " ${ REV_OVERRIDE } " ] && [ -n " ${ PATH_OVERRIDE } " ] ; then
fail "Use either --rev or --path, not both"
fi
if [ -z " ${ REV_OVERRIDE } " ] && [ -z " ${ PATH_OVERRIDE } " ] && [ -z " ${ DEFAULT_NODE_REV } " ] && [ -z " ${ DEFAULT_NODE_PATH } " ] ; then
fail "Provide --rev, --path, or set NOMOS_NODE_REV/NOMOS_NODE_PATH in versions.env"
fi
NOMOS_NODE_REV = " ${ REV_OVERRIDE :- ${ DEFAULT_NODE_REV } } "
NOMOS_NODE_PATH = " ${ PATH_OVERRIDE :- ${ DEFAULT_NODE_PATH } } "
2025-12-09 15:38:33 +01:00
# Normalize OUTPUT to an absolute path under the workspace.
2025-12-09 07:47:17 +01:00
if [ -z " ${ OUTPUT } " ] ; then
OUTPUT = " ${ ROOT_DIR } /.tmp/nomos-binaries- ${ PLATFORM } - ${ VERSION } .tar.gz "
2025-12-09 15:38:33 +01:00
elif [ [ " ${ OUTPUT } " != /* ] ] ; then
OUTPUT = " ${ ROOT_DIR } / ${ OUTPUT #./ } "
2025-12-09 07:47:17 +01:00
fi
2025-12-09 16:31:45 +01:00
echo " Bundle output: ${ OUTPUT } "
2025-12-09 07:47:17 +01:00
if [ " $PLATFORM " = "linux" ] && [ " $( uname -s) " != "Linux" ] && [ -z " ${ BUNDLE_IN_CONTAINER :- } " ] ; then
if ! command -v docker >/dev/null 2>& 1; then
fail "Docker is required to build a Linux bundle from non-Linux host"
fi
2025-12-15 17:08:48 +01:00
if [ -z " ${ DOCKER_PLATFORM } " ] ; then
fail "--docker-platform must not be empty"
fi
2025-12-13 05:59:28 +01:00
NODE_PATH_ENV = " ${ NOMOS_NODE_PATH } "
EXTRA_MOUNTS = ( )
if [ -n " ${ NOMOS_NODE_PATH } " ] ; then
case " ${ NOMOS_NODE_PATH } " in
" ${ ROOT_DIR } " /*)
NODE_PATH_ENV = " /workspace ${ NOMOS_NODE_PATH # " ${ ROOT_DIR } " } "
; ;
/*)
NODE_PATH_ENV = "/external/nomos-node"
EXTRA_MOUNTS += ( "-v" " ${ NOMOS_NODE_PATH } : ${ NODE_PATH_ENV } " )
; ;
*)
fail "--path must be absolute when cross-building in Docker"
; ;
esac
fi
2025-12-15 17:08:48 +01:00
2025-12-09 07:47:17 +01:00
echo "==> Building Linux bundle inside Docker"
2025-12-09 15:38:33 +01:00
container_output = " /workspace ${ OUTPUT # " ${ ROOT_DIR } " } "
2025-12-09 07:47:17 +01:00
mkdir -p " ${ ROOT_DIR } /.tmp/cargo-linux " " ${ ROOT_DIR } /.tmp/nomos-node-linux-target "
2025-12-15 17:08:48 +01:00
2025-12-13 05:59:28 +01:00
FEATURES_ARGS = ( )
if [ -n " ${ NOMOS_EXTRA_FEATURES :- } " ] ; then
FEATURES_ARGS += ( --features " ${ NOMOS_EXTRA_FEATURES } " )
fi
2025-12-15 17:08:48 +01:00
SRC_ARGS = ( )
if [ -n " ${ NODE_PATH_ENV } " ] ; then
SRC_ARGS += ( --path " ${ NODE_PATH_ENV } " )
else
SRC_ARGS += ( --rev " ${ NOMOS_NODE_REV } " )
fi
docker run --rm --platform " ${ DOCKER_PLATFORM } " \
2025-12-09 07:47:17 +01:00
-e VERSION = " $VERSION " \
-e NOMOS_NODE_REV = " $NOMOS_NODE_REV " \
2025-12-13 05:59:28 +01:00
-e NOMOS_NODE_PATH = " $NODE_PATH_ENV " \
2025-12-09 13:27:04 +01:00
-e NOMOS_CIRCUITS = "/workspace/.tmp/nomos-circuits-linux" \
2025-12-09 13:30:29 +01:00
-e STACK_DIR = "/workspace/.tmp/nomos-circuits-linux" \
-e HOST_DIR = "/workspace/.tmp/nomos-circuits-linux" \
2025-12-13 05:59:28 +01:00
-e NOMOS_EXTRA_FEATURES = " ${ NOMOS_EXTRA_FEATURES :- } " \
2025-12-09 07:47:17 +01:00
-e BUNDLE_IN_CONTAINER = 1 \
-e CARGO_HOME = /workspace/.tmp/cargo-linux \
-e CARGO_TARGET_DIR = /workspace/.tmp/nomos-node-linux-target \
-v " ${ ROOT_DIR } /.tmp/cargo-linux " :/workspace/.tmp/cargo-linux \
-v " ${ ROOT_DIR } /.tmp/nomos-node-linux-target " :/workspace/.tmp/nomos-node-linux-target \
-v " $ROOT_DIR " :/workspace \
2025-12-13 05:59:28 +01:00
" ${ EXTRA_MOUNTS [@] } " \
2025-12-09 07:47:17 +01:00
-w /workspace \
rust:1.80-bullseye \
2025-12-15 17:08:48 +01:00
bash -c " apt-get update && apt-get install -y clang llvm-dev libclang-dev pkg-config cmake libssl-dev rsync libgmp10 libgmp-dev libgomp1 nasm && ./scripts/build-bundle.sh --platform linux --output \" ${ container_output } \" ${ SRC_ARGS [*] } ${ FEATURES_ARGS [*] } "
2025-12-09 07:47:17 +01:00
exit 0
fi
echo " ==> Preparing circuits (version ${ VERSION } ) "
2025-12-09 13:20:19 +01:00
if [ " $PLATFORM " = "host" ] ; then
CIRCUITS_DIR = " ${ ROOT_DIR } /.tmp/nomos-circuits-host "
NODE_TARGET = " ${ ROOT_DIR } /.tmp/nomos-node-host-target "
else
CIRCUITS_DIR = " ${ ROOT_DIR } /.tmp/nomos-circuits-linux "
NODE_TARGET = " ${ ROOT_DIR } /.tmp/nomos-node-linux-target "
fi
2025-12-15 17:08:48 +01:00
NODE_SRC_DEFAULT = " ${ ROOT_DIR } /.tmp/nomos-node- ${ PLATFORM } -src "
2025-12-13 05:59:28 +01:00
NODE_SRC = " ${ NOMOS_NODE_PATH :- ${ NODE_SRC_DEFAULT } } "
if [ -n " ${ NOMOS_NODE_PATH } " ] ; then
2025-12-15 17:08:48 +01:00
if [ ! -d " ${ NODE_SRC } " ] ; then
fail " NOMOS_NODE_PATH does not exist: ${ NODE_SRC } "
fi
2025-12-13 05:59:28 +01:00
rm -rf " ${ NODE_SRC_DEFAULT } "
if [ -d " ${ NODE_TARGET } " ] ; then
find " ${ NODE_TARGET } " -mindepth 1 -maxdepth 1 -exec rm -rf { } +
fi
NODE_TARGET = " ${ NODE_TARGET } -local "
fi
2025-12-15 17:08:48 +01:00
2025-12-09 13:20:19 +01:00
export NOMOS_CIRCUITS = " ${ CIRCUITS_DIR } "
2025-12-09 13:27:04 +01:00
mkdir -p " ${ ROOT_DIR } /.tmp " " ${ CIRCUITS_DIR } "
2025-12-13 05:59:28 +01:00
if [ -f " ${ CIRCUITS_DIR } / ${ KZG_FILE :- kzgrs_test_params } " ] ; then
echo " Circuits already present at ${ CIRCUITS_DIR } ; skipping download "
else
STACK_DIR = " ${ CIRCUITS_DIR } " HOST_DIR = " ${ CIRCUITS_DIR } " \
" ${ ROOT_DIR } /scripts/setup-circuits-stack.sh " " ${ VERSION } " </dev/null
fi
2025-12-09 07:47:17 +01:00
2025-12-09 13:20:19 +01:00
NODE_BIN = " ${ NODE_TARGET } /debug/nomos-node "
EXEC_BIN = " ${ NODE_TARGET } /debug/nomos-executor "
CLI_BIN = " ${ NODE_TARGET } /debug/nomos-cli "
2025-12-15 17:08:48 +01:00
2025-12-13 05:59:28 +01:00
FEATURES = "testing"
if [ -n " ${ NOMOS_EXTRA_FEATURES :- } " ] ; then
FEATURES = " ${ FEATURES } , ${ NOMOS_EXTRA_FEATURES } "
fi
2025-12-09 07:47:17 +01:00
2025-12-15 17:08:48 +01:00
echo " ==> Building binaries (platform= ${ PLATFORM } ) "
2025-12-09 13:20:19 +01:00
mkdir -p " ${ NODE_SRC } "
2025-12-15 17:08:48 +01:00
(
cd " ${ NODE_SRC } "
if [ -n " ${ NOMOS_NODE_PATH } " ] ; then
echo " Using local nomos-node checkout at ${ NODE_SRC } (no fetch/checkout) "
else
if [ ! -d " ${ NODE_SRC } /.git " ] ; then
git clone https://github.com/logos-co/nomos-node.git " ${ NODE_SRC } "
fi
2025-12-13 05:59:28 +01:00
git fetch --depth 1 origin " ${ NOMOS_NODE_REV } "
git checkout " ${ NOMOS_NODE_REV } "
git reset --hard
git clean -fdx
2025-12-15 17:08:48 +01:00
fi
2025-12-15 17:47:00 +01:00
if [ -n " ${ BUNDLE_RUSTUP_TOOLCHAIN } " ] ; then
RUSTFLAGS = '--cfg feature="pol-dev-mode"' NOMOS_CIRCUITS = " ${ CIRCUITS_DIR } " \
RUSTUP_TOOLCHAIN = " ${ BUNDLE_RUSTUP_TOOLCHAIN } " \
cargo build --features " ${ FEATURES } " \
-p nomos-node -p nomos-executor -p nomos-cli \
--target-dir " ${ NODE_TARGET } "
else
RUSTFLAGS = '--cfg feature="pol-dev-mode"' NOMOS_CIRCUITS = " ${ CIRCUITS_DIR } " \
cargo build --features " ${ FEATURES } " \
-p nomos-node -p nomos-executor -p nomos-cli \
--target-dir " ${ NODE_TARGET } "
fi
2025-12-09 07:47:17 +01:00
)
echo "==> Packaging bundle"
bundle_dir = " ${ ROOT_DIR } /.tmp/nomos-bundle "
rm -rf " ${ bundle_dir } "
mkdir -p " ${ bundle_dir } /artifacts/circuits "
2025-12-09 13:20:19 +01:00
cp -a " ${ CIRCUITS_DIR } /. " " ${ bundle_dir } /artifacts/circuits/ "
2025-12-09 07:47:17 +01:00
mkdir -p " ${ bundle_dir } /artifacts "
2025-12-09 13:20:19 +01:00
cp " ${ NODE_BIN } " " ${ bundle_dir } /artifacts/ "
cp " ${ EXEC_BIN } " " ${ bundle_dir } /artifacts/ "
cp " ${ CLI_BIN } " " ${ bundle_dir } /artifacts/ "
2025-12-15 17:08:48 +01:00
{
echo " nomos_node_path= ${ NOMOS_NODE_PATH :- } "
echo " nomos_node_rev= ${ NOMOS_NODE_REV :- } "
if [ -d " ${ NODE_SRC } /.git " ] && command -v git >/dev/null 2>& 1; then
echo " nomos_node_git_head= $( git -C " ${ NODE_SRC } " rev-parse HEAD 2>/dev/null || true ) "
fi
echo " platform= ${ PLATFORM } "
echo " features= ${ FEATURES } "
} > " ${ bundle_dir } /artifacts/nomos-bundle-meta.env "
2025-12-09 07:47:17 +01:00
mkdir -p " $( dirname " ${ OUTPUT } " ) "
2025-12-09 11:01:35 +01:00
if tar --help 2>/dev/null | grep -q -- '--no-mac-metadata' ; then
tar --no-mac-metadata --no-xattrs -czf " ${ OUTPUT } " -C " ${ bundle_dir } " artifacts
elif tar --help 2>/dev/null | grep -q -- '--no-xattrs' ; then
tar --no-xattrs -czf " ${ OUTPUT } " -C " ${ bundle_dir } " artifacts
else
tar -czf " ${ OUTPUT } " -C " ${ bundle_dir } " artifacts
fi
2025-12-09 07:47:17 +01:00
echo " Bundle created at ${ OUTPUT } "
2025-12-15 17:08:48 +01:00
2025-12-13 05:59:28 +01:00
if [ [ " ${ FEATURES } " = = *profiling* ] ] ; then
2025-12-15 17:08:48 +01:00
cat <<'EOF_PROF'
2025-12-13 05:59:28 +01:00
Profiling endpoints ( enabled by --features profiling) :
CPU pprof ( SVG) : curl "http://<node-host>:8722/debug/pprof/profile?seconds=15&format=svg" -o profile.svg
CPU pprof ( proto) : go tool pprof -http= :8080 "http://<node-host>:8722/debug/pprof/profile?seconds=15&format=proto"
2025-12-15 17:08:48 +01:00
EOF_PROF
2025-12-13 05:59:28 +01:00
fi