dynamo/container/use-sccache.sh

178 lines
6.1 KiB
Bash
Executable File

#!/bin/bash
# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
# sccache management script
# This script handles sccache installation, environment setup, and statistics display
SCCACHE_VERSION="v0.14.0"
usage() {
cat << EOF
Usage: $0 [COMMAND] [OPTIONS]
Commands:
install Install sccache binary (requires ARCH_ALT environment variable)
setup-env Print export statements to configure sccache for compilation
show-stats Display sccache statistics with optional build name
help Show this help message
setup-env modes:
setup-env Wraps CC/CXX with sccache + sets RUSTC_WRAPPER.
Works for autotools (make) and Meson builds.
setup-env cmake Also sets CMAKE_C/CXX/CUDA_COMPILER_LAUNCHER.
Use for CMake-based builds.
Usage: eval \$($0 setup-env [cmake])
Environment variables:
USE_SCCACHE Set to 'true' to enable sccache
SCCACHE_BUCKET S3 bucket name (fallback if not passed as parameter)
SCCACHE_REGION S3 region (fallback if not passed as parameter)
ARCH Architecture for S3 key prefix (fallback if not passed as parameter)
ARCH_ALT Alternative architecture name for downloads (e.g., x86_64, aarch64)
Examples:
ARCH_ALT=x86_64 $0 install
eval \$($0 setup-env) # autotools / Meson
eval \$($0 setup-env cmake) # CMake builds
$0 show-stats "UCX"
EOF
}
install_sccache() {
if command -v sccache >/dev/null 2>&1; then
echo "sccache already installed at $(command -v sccache), skipping download"
else
if [ -z "${ARCH_ALT:-}" ]; then
echo "Error: ARCH_ALT environment variable is required for sccache installation"
exit 1
fi
echo "Installing sccache ${SCCACHE_VERSION} for architecture ${ARCH_ALT}..."
wget --tries=3 --waitretry=5 \
"https://github.com/mozilla/sccache/releases/download/${SCCACHE_VERSION}/sccache-${SCCACHE_VERSION}-${ARCH_ALT}-unknown-linux-musl.tar.gz"
tar -xzf "sccache-${SCCACHE_VERSION}-${ARCH_ALT}-unknown-linux-musl.tar.gz"
mv "sccache-${SCCACHE_VERSION}-${ARCH_ALT}-unknown-linux-musl/sccache" /usr/local/bin/
rm -rf sccache*
fi
# Create compiler wrapper scripts for autotools/Meson compatibility.
# Autoconf breaks with CC="sccache gcc" (multi-word value), so we provide
# single-binary wrappers that autoconf sees as a regular compiler.
# The real compiler path is passed at runtime via SCCACHE_CC_REAL / SCCACHE_CXX_REAL.
cat > /usr/local/bin/sccache-cc <<'WRAPPER'
#!/bin/sh
# Only use sccache for pure compilations (-c flag).
# Autoconf tests the compiler with combined compile+link (no -c), and sccache
# can interfere with those tests. sccache only caches compilations anyway,
# so routing linking/other invocations directly to gcc loses nothing.
case " $* " in
*" -c "*) exec sccache "${SCCACHE_CC_REAL:-gcc}" "$@" ;;
*) exec "${SCCACHE_CC_REAL:-gcc}" "$@" ;;
esac
WRAPPER
chmod +x /usr/local/bin/sccache-cc
cat > /usr/local/bin/sccache-cxx <<'WRAPPER'
#!/bin/sh
case " $* " in
*" -c "*) exec sccache "${SCCACHE_CXX_REAL:-g++}" "$@" ;;
*) exec "${SCCACHE_CXX_REAL:-g++}" "$@" ;;
esac
WRAPPER
chmod +x /usr/local/bin/sccache-cxx
echo "sccache installed successfully"
}
setup_env() {
local mode="${1:-default}"
# Output a conditional block: only configure sccache if the server starts
# successfully. The server needs working S3 credentials (mounted via
# --mount=type=secret); if they're missing or invalid, we skip sccache
# entirely so the build continues with normal compilers.
#
# Use a per-step Unix domain socket so concurrent builds on the same
# buildkit worker don't collide on the default TCP port 4226.
echo 'export SCCACHE_SERVER_UDS="/tmp/sccache-$(mktemp -u XXXXXX).sock";'
echo 'if sccache --start-server; then'
echo ' export SCCACHE_IDLE_TIMEOUT=0;'
echo ' export RUSTC_WRAPPER="sccache";'
if [ "$mode" = "cmake" ]; then
echo ' export CMAKE_C_COMPILER_LAUNCHER="sccache";'
echo ' export CMAKE_CXX_COMPILER_LAUNCHER="sccache";'
echo ' export CMAKE_CUDA_COMPILER_LAUNCHER="sccache";'
else
# Wrapper scripts (installed during sccache install) route only pure
# compilations (-c flag) through sccache; linking goes directly to
# the real compiler so autoconf's link tests pass.
echo ' export SCCACHE_CC_REAL="${CC:-gcc}";'
echo ' export SCCACHE_CXX_REAL="${CXX:-g++}";'
echo ' export CC="/usr/local/bin/sccache-cc";'
echo ' export CXX="/usr/local/bin/sccache-cxx";'
fi
echo 'else'
echo ' echo "WARNING: sccache server failed to start, building without cache";'
echo 'fi'
}
show_stats() {
if command -v sccache >/dev/null 2>&1; then
# Generate timestamp in ISO 8601 format
local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# Output human-readable text format first
echo "=== sccache statistics AFTER $1 ==="
sccache --show-stats
echo ""
# Output JSON markers for deterministic parsing
echo "=== SCCACHE_JSON_BEGIN ==="
# Create JSON wrapper with section metadata
cat <<EOF
{
"section": "$1",
"timestamp": "$timestamp",
"sccache_stats": $(sccache --show-stats --stats-format json)
}
EOF
echo "=== SCCACHE_JSON_END ==="
else
echo "sccache is not available"
fi
}
main() {
case "${1:-help}" in
install)
install_sccache
;;
setup-env)
shift
setup_env "$@"
;;
show-stats)
shift # Remove the command from arguments
show_stats "$@" # Pass all remaining arguments
;;
help|--help|-h)
usage
;;
*)
echo "Unknown command: $1"
usage
exit 1
;;
esac
}
main "$@"