use-sccache.sh 6.07 KB
Newer Older
1
#!/bin/bash
2
# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
4
5
6
7
8
9
# SPDX-License-Identifier: Apache-2.0

set -euo pipefail

# sccache management script
# This script handles sccache installation, environment setup, and statistics display

10
SCCACHE_VERSION="v0.14.0"
11
12
13
14
15
16
17
18


usage() {
    cat << EOF
Usage: $0 [COMMAND] [OPTIONS]

Commands:
    install         Install sccache binary (requires ARCH_ALT environment variable)
19
    setup-env       Print export statements to configure sccache for compilation
20
21
22
    show-stats      Display sccache statistics with optional build name
    help            Show this help message

23
24
25
26
27
28
29
30
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])

31
32
33
34
35
36
37
38
39
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
40
41
    eval \$($0 setup-env)          # autotools / Meson
    eval \$($0 setup-env cmake)    # CMake builds
42
43
44
45
46
    $0 show-stats "UCX"
EOF
}

install_sccache() {
47
48
49
50
51
52
53
54
55
56
57
58
59
    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*
60
    fi
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

    # 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

88
89
90
    echo "sccache installed successfully"
}

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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'
}

125
126
show_stats() {
    if command -v sccache >/dev/null 2>&1; then
Nate Mailhot's avatar
Nate Mailhot committed
127
128
129
130
        # Generate timestamp in ISO 8601 format
        local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

        # Output human-readable text format first
131
132
        echo "=== sccache statistics AFTER $1 ==="
        sccache --show-stats
Nate Mailhot's avatar
Nate Mailhot committed
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
        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 ==="
148
149
150
151
152
153
154
155
156
157
    else
        echo "sccache is not available"
    fi
}

main() {
    case "${1:-help}" in
        install)
            install_sccache
            ;;
158
159
160
        setup-env)
            shift
            setup_env "$@"
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
            ;;
        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 "$@"