Full Code of mozilla/sccache for AI

main 8d6cab9ee935 cached
182 files
1.9 MB
463.7k tokens
2294 symbols
1 requests
Download .txt
Showing preview only (1,995K chars total). Download the full file or copy to clipboard to get everything.
Repository: mozilla/sccache
Branch: main
Commit: 8d6cab9ee935
Files: 182
Total size: 1.9 MB

Directory structure:
gitextract__oh_a4dj/

├── .envrc
├── .github/
│   ├── actions/
│   │   ├── artifact_failure/
│   │   │   └── action.yml
│   │   ├── nvcc-toolchain/
│   │   │   ├── action.yml
│   │   │   ├── install-cuda.ps1
│   │   │   └── install-cuda.sh
│   │   └── rust-toolchain/
│   │       └── action.yml
│   ├── codecov.yml
│   ├── dependabot.yml
│   └── workflows/
│       ├── benchmarks.yml
│       ├── ci.yml
│       ├── close-snap.yml
│       ├── integration-tests.yml
│       └── snap.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .rustfmt.toml
├── .taplo.toml
├── CODE_OF_CONDUCT.md
├── Cargo.toml
├── LICENSE
├── README.md
├── benches/
│   └── sccache_bench.rs
├── docs/
│   ├── Architecture.md
│   ├── Azure.md
│   ├── COS.md
│   ├── Caching.md
│   ├── Configuration.md
│   ├── Distributed.md
│   ├── DistributedFreeBSD.md
│   ├── DistributedQuickstart.md
│   ├── GHA.md
│   ├── Gcs.md
│   ├── Jenkins.md
│   ├── Local.md
│   ├── Memcached.md
│   ├── OSS.md
│   ├── Redis.md
│   ├── Releasing.md
│   ├── ResponseFiles.md
│   ├── Rust.md
│   ├── S3.md
│   ├── Webdav.md
│   └── Xcode.md
├── flake.nix
├── scripts/
│   ├── extratest.sh
│   └── freebsd-ci-test.sh
├── snap/
│   └── snapcraft.yaml
├── src/
│   ├── bin/
│   │   └── sccache-dist/
│   │       ├── build.rs
│   │       ├── build_freebsd.rs
│   │       ├── cmdline/
│   │       │   ├── mod.rs
│   │       │   └── parse.rs
│   │       ├── main.rs
│   │       └── token_check.rs
│   ├── cache/
│   │   ├── azure.rs
│   │   ├── cache.rs
│   │   ├── cache_io.rs
│   │   ├── cos.rs
│   │   ├── disk.rs
│   │   ├── gcs.rs
│   │   ├── gha.rs
│   │   ├── http_client.rs
│   │   ├── lazy_disk_cache.rs
│   │   ├── memcached.rs
│   │   ├── mod.rs
│   │   ├── oss.rs
│   │   ├── readonly.rs
│   │   ├── redis.rs
│   │   ├── s3.rs
│   │   ├── utils.rs
│   │   └── webdav.rs
│   ├── client.rs
│   ├── cmdline.rs
│   ├── commands.rs
│   ├── compiler/
│   │   ├── args.rs
│   │   ├── c.rs
│   │   ├── cicc.rs
│   │   ├── clang.rs
│   │   ├── compiler.rs
│   │   ├── counted_array.rs
│   │   ├── cudafe.rs
│   │   ├── diab.rs
│   │   ├── gcc.rs
│   │   ├── mod.rs
│   │   ├── msvc.rs
│   │   ├── nvcc.rs
│   │   ├── nvhpc.rs
│   │   ├── preprocessor_cache.rs
│   │   ├── ptxas.rs
│   │   ├── rust.rs
│   │   └── tasking_vx.rs
│   ├── config.rs
│   ├── dist/
│   │   ├── cache.rs
│   │   ├── client_auth.rs
│   │   ├── http.rs
│   │   ├── mod.rs
│   │   ├── pkg.rs
│   │   └── test.rs
│   ├── errors.rs
│   ├── jobserver.rs
│   ├── lib.rs
│   ├── lru_disk_cache/
│   │   ├── lru_cache.rs
│   │   └── mod.rs
│   ├── main.rs
│   ├── mock_command.rs
│   ├── net.rs
│   ├── protocol.rs
│   ├── server.rs
│   ├── test/
│   │   ├── mock_storage.rs
│   │   ├── mod.rs
│   │   ├── tests.rs
│   │   └── utils.rs
│   └── util.rs
└── tests/
    ├── cache_hit_rate.rs
    ├── cmake-modules/
    │   ├── CMakeLists.txt
    │   ├── main.cpp
    │   └── mymodule.cppm
    ├── dist.rs
    ├── harness/
    │   ├── Dockerfile.sccache-dist
    │   └── mod.rs
    ├── helpers/
    │   └── mod.rs
    ├── integration/
    │   ├── Makefile
    │   ├── README.md
    │   ├── autotools/
    │   │   ├── Makefile.am
    │   │   ├── configure.ac
    │   │   └── main.cpp
    │   ├── basedirs-autotools/
    │   │   ├── Makefile.am
    │   │   ├── configure.ac
    │   │   ├── include/
    │   │   │   └── myheader.h
    │   │   └── main.cpp
    │   ├── cmake/
    │   │   ├── CMakeLists.txt
    │   │   └── main.cpp
    │   ├── cmake-hip/
    │   │   ├── CMakeLists.txt
    │   │   └── vectoradd_hip.cpp
    │   ├── docker-compose.yml
    │   ├── msvc/
    │   │   ├── args.rsp
    │   │   └── foo.cpp
    │   ├── msvc-preprocessing/
    │   │   ├── args.rsp
    │   │   └── foo.cpp
    │   ├── randomize_readdir/
    │   │   ├── Cargo.toml
    │   │   └── src/
    │   │       └── lib.rs
    │   ├── scripts/
    │   │   ├── test-autotools.sh
    │   │   ├── test-backend.sh
    │   │   ├── test-basedirs.sh
    │   │   ├── test-clang.sh
    │   │   ├── test-cmake.sh
    │   │   ├── test-coverage.sh
    │   │   ├── test-gcc.sh
    │   │   └── test-zstd.sh
    │   ├── test_intel_asm.s
    │   ├── test_intel_asm_to_preproc.S
    │   ├── webdav-config.yaml
    │   └── xcode/
    │       ├── main.cpp
    │       ├── sccache.xcconfig
    │       └── xcode-test.xcodeproj/
    │           └── project.pbxproj
    ├── logging.rs
    ├── msvc-msbuild/
    │   ├── .gitignore
    │   ├── MsbuildCpp.vcxproj
    │   ├── test_bar.cpp
    │   ├── test_baz.cpp
    │   └── test_foo.cpp
    ├── oauth.rs
    ├── sccache_args.rs
    ├── sccache_cargo.rs
    ├── sccache_rustc.rs
    ├── system.rs
    ├── test-crate/
    │   ├── Cargo.toml
    │   └── src/
    │       ├── bin.rs
    │       └── lib.rs
    ├── test.c
    ├── test.c.gcc-13.2.0-preproc
    ├── test_a.cu
    ├── test_a.hip
    ├── test_b.cu
    ├── test_b.hip
    ├── test_c.cu
    ├── test_c.hip
    ├── test_clang_multicall.c
    ├── test_err.c
    ├── test_macro_expansion.c
    ├── test_whitespace.c
    ├── test_whitespace_alt.c
    └── test_with_define.c

================================================
FILE CONTENTS
================================================

================================================
FILE: .envrc
================================================
if has nix; then
  if ! has nix_direnv_version || ! nix_direnv_version 3.1.0; then
    source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.1.0/direnvrc" "sha256-yMJ2OVMzrFaDPn7q8nCBZFRYpL/f0RcHzhmw/i6btJM="
  fi

  use flake
fi

source_env_if_exists .envrc.local


================================================
FILE: .github/actions/artifact_failure/action.yml
================================================
name: "Upload failure Artifacts"
description: "Upload failure Artifacts"
inputs:
  name:
    description: ""
    required: true
runs:
  using: "composite"
  steps:
    - name: pack failure artifacts
      shell: bash
      run: |
        echo "Current running processes"
        ps uax
        echo "Processes that access current dir"
        lsof +D `pwd` || true
        killall sccache || true
        killall sccache-dist || true
        # possible temp dirs for either linux or windows
        cp "${TMP:-${TEMP:-${TMPDIR:-/tmp}}}"/sccache_*.txt . 2>/dev/null || true
        mkdir -p target
        tar --exclude='target' \
            --exclude='docs' \
            --exclude='bins' \
            --exclude='.git' \
            -zcf target/failure-${{ inputs.name }}.tar.gz .
    - uses: actions/upload-artifact@v4
      with:
        name: ${{ inputs.name }}
        path: target/failure-${{ inputs.name }}.tar.gz


================================================
FILE: .github/actions/nvcc-toolchain/action.yml
================================================
name: nvcc-toolchain
inputs:
  cuda-version:
    description: CUDA Toolkit version
    required: true

runs:
  using: composite
  steps:
    - if: runner.os == 'Linux'
      shell: bash
      run: .github/actions/nvcc-toolchain/install-cuda.sh ${{ inputs.cuda-version }}

    - if: runner.os == 'Windows'
      shell: powershell
      run: .\.github\actions\nvcc-toolchain\install-cuda.ps1 -cudaVersion ${{ inputs.cuda-version }}


================================================
FILE: .github/actions/nvcc-toolchain/install-cuda.ps1
================================================
Param(
    [Parameter(Mandatory=$false)]
    [string]
    $cudaVersion="12.8.0"
)

# Use System.Version to tokenize version
$version = [Version]$cudaVersion

$major = $version.Major
$minor = $version.Minor
$build = $version.Build

# Minimum build is 0, not -1 as default in case "12.5" is passed
if ($build -lt 0) {
    $build = 0
}

# mmb == major minor build
$mmbVersionTag = "${major}.${minor}.${build}"
# mm = major minor
$mmVersionTag = "${major}.${minor}"

$cudaVersionUrl = "https://developer.download.nvidia.com/compute/cuda/${mmbVersionTag}/network_installers/cuda_${mmbVersionTag}_windows_network.exe"

###
# `cuda_${mmbVersionTag}_windows_network.exe` name only valid back to CUDA v11.5.1.
# Before that it was named `cuda_${mmbVersionTag}_win10_network.exe`:
# * https://developer.download.nvidia.com/compute/cuda/11.5.1/network_installers/cuda_11.5.1_windows_network.exe
# * https://developer.download.nvidia.com/compute/cuda/11.5.0/network_installers/cuda_11.5.0_win10_network.exe
###

if ([version]$mmbVersionTag -le "11.5.0") {
    $cudaVersionUrl = "https://developer.download.nvidia.com/compute/cuda/${mmbVersionTag}/network_installers/cuda_${mmbVersionTag}_win10_network.exe"
}

$cudaComponents =
    "nvcc_$mmVersionTag",
    "curand_$mmVersionTag",
    "curand_dev_$mmVersionTag",
    "cudart_$mmVersionTag",
    "cupti_$mmVersionTag",
    "nvrtc_$mmVersionTag",
    "nvrtc_dev_$mmVersionTag",
    "nvml_dev_$mmVersionTag",
    "nvtx_$mmVersionTag"

Invoke-WebRequest -Uri "$cudaVersionUrl" -OutFile "./cuda_network.exe" -UseBasicParsing
Start-Process -Wait -PassThru -FilePath .\cuda_network.exe -ArgumentList "-s $cudaComponents"

$ENV:PATH="$ENV:PATH;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v$mmVersionTag\bin"
$ENV:CUDA_PATH="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v$mmVersionTag"

$PATH_STR="PATH=$ENV:PATH"
$PATH_STR | Out-File -Append $ENV:GITHUB_ENV

$CUDA_PATH_STR="CUDA_PATH=$ENV:CUDA_PATH"
$CUDA_PATH_STR | Out-File -Append $ENV:GITHUB_ENV

Remove-Item .\cuda_network.exe


================================================
FILE: .github/actions/nvcc-toolchain/install-cuda.sh
================================================
#! /usr/bin/env bash
set -eu

export DEBIAN_FRONTEND=noninteractive

get_cuda_deb() {
    local deb="$(                                 \
        wget --no-hsts -q -O- "${1}/Packages"     \
    | grep -P "^Filename: \./${2}(.*)\.deb$"      \
    | sort -Vr | head -n1 | cut -d' ' -f2         \
    )";
    if [ -z "$deb" ]; then
        echo "Error: No matching .deb found for '${1}' and '${2}'" >&2
        return 1
    fi
    wget --no-hsts -q -O "/tmp/${deb#./}" "${1}/${deb#./}";
    echo -n "/tmp/${deb#./}";
}

VERSION="$1";

NVARCH="$(uname -p)";

if test "$NVARCH" = aarch64; then
    NVARCH="sbsa";
fi

OSNAME="$(
    . /etc/os-release;
    major="$(cut -d'.' -f1 <<< "${VERSION_ID}")";
    minor="$(cut -d'.' -f2 <<< "${VERSION_ID}")";
    echo "$ID$((major - (major % 2)))${minor}";
)";

CUDA_HOME="/usr/local/cuda";

cuda_repo_base="https://developer.download.nvidia.com/compute/cuda/repos";
cuda_repo="${cuda_repo_base}/${OSNAME}/${NVARCH}";

cuda_ver="$VERSION";
cuda_ver="$(grep -Po '^[0-9]+\.[0-9]+' <<< "${cuda_ver}")";
cuda_ver="${cuda_ver/./-}";

if ! dpkg -s cuda-keyring; then
    sudo apt-get install -y --no-install-recommends   \
        "$(get_cuda_deb "${cuda_repo}" cuda-keyring)" \
        ;
fi

PKGS=();
PKGS+=("cuda-toolkit-${cuda_ver}");

sudo apt-get update;
sudo apt-get install -y --no-install-recommends "${PKGS[@]}";

if ! test -L "${CUDA_HOME}"; then
    # Create /usr/local/cuda symlink
    sudo ln -s "${CUDA_HOME}-${cuda_ver}" "${CUDA_HOME}";
fi

export PATH="$PATH:$CUDA_HOME/bin"

which -a nvcc
nvcc --version

cat <<EOF | tee -a "$GITHUB_ENV"
CUDA_HOME=$CUDA_HOME
CUDA_PATH=$CUDA_HOME
PATH=$PATH
EOF

rm /tmp/*.deb


================================================
FILE: .github/actions/rust-toolchain/action.yml
================================================
name: rust-toolchain
inputs:
  toolchain:
    description: |
      Rust toolchain name.
      See https://rust-lang.github.io/rustup/concepts/toolchains.html#toolchain-specification
    required: false
  target:
    description: Target triple to install for this toolchain
    required: false
  components:
    description: Space-separated list of components to be additionally installed for a new toolchain
    required: false

runs:
  using: composite
  steps:
    - shell: bash
      run: |
        set -x
        rustup override set ${{ inputs.toolchain || 'stable' }}
        ${{ inputs.target && format('rustup target add {0}', inputs.target) }}
        ${{ inputs.components && format('rustup component add {0}', inputs.components) }}
        cargo --version
        rustc --version


================================================
FILE: .github/codecov.yml
================================================
coverage:
  status:
    project:
      default:
        threshold: 0.2%

================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: "cargo"
    directory: "/"
    schedule:
      interval: weekly 
    open-pull-requests-limit: 8
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: weekly
    open-pull-requests-limit: 5


================================================
FILE: .github/workflows/benchmarks.yml
================================================
name: Benchmarks

# spell-checker:ignore codspeed dtolnay Swatinem

on:
  pull_request:
  push:
    branches:
      - '*'

permissions:
  contents: read # to fetch code (actions/checkout)

# End the current execution if there is a new changeset in the PR.
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

jobs:
  benchmarks:
    name: Run ${{ matrix.mode }} benchmarks (CodSpeed)
    runs-on: ubuntu-latest
    strategy:
      matrix:
        mode:
          - simulation
          - memory
    steps:
      - uses: actions/checkout@v6
        with:
          persist-credentials: false

      - uses: dtolnay/rust-toolchain@stable

      - uses: Swatinem/rust-cache@v2

      - name: Install cargo-codspeed
        shell: bash
        run: cargo install cargo-codspeed --locked

      - name: Build benchmarks
        shell: bash
        run: cargo codspeed build

      - name: Run benchmarks
        uses: CodSpeedHQ/action@v4
        env:
          CODSPEED_LOG: debug
        with:
          mode: ${{ matrix.mode }}
          run: cargo codspeed run > /dev/null
          token: ${{ secrets.CODSPEED_TOKEN }}


================================================
FILE: .github/workflows/ci.yml
================================================
name: ci
on: [ push, pull_request ]

jobs:
  lint:
    name: ${{ matrix.component }} ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    timeout-minutes: 15
    strategy:
      fail-fast: false
      matrix:
        os: [ ubuntu-latest, macOS-latest, windows-latest ]
        component: [ clippy ]
        include:
          - component: rustfmt
            cargo_cmd: fmt -- --check
            os: ubuntu-latest
          - component: clippy
            cargo_cmd: clippy --locked --all-targets -- -D warnings -A unknown-lints -A clippy::type_complexity -A clippy::new-without-default
    steps:
      - name: Clone repository
        uses: actions/checkout@v5

      - name: Install rust
        uses: ./.github/actions/rust-toolchain
        with:
          components: ${{ matrix.component }}
          # Oldest supported version, keep in sync with README.md
          toolchain: "1.85.0"

      - name: clippy version
        run: cargo clippy --version
        if: ${{ matrix.component == 'clippy' }}

      - name: Check
        run: cargo ${{ matrix.cargo_cmd }}

  check_features:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        feature: [ azure, gcs, gha, memcached, redis, s3, webdav ]
    steps:
      - name: Clone repository
        uses: actions/checkout@v5

      - name: Check feature ${{ matrix.feature }}
        run: cargo check --no-default-features --features ${{ matrix.feature }}

  toml_format:
    runs-on: ubuntu-latest
    steps:
      - name: Clone repository
        uses: actions/checkout@v5

      - name: Check
        run: npx --yes @taplo/cli fmt --check



  test:
    name: test ${{ matrix.os }} rust ${{ matrix.rustc || 'stable' }} ${{ matrix.extra_desc }}
    runs-on: ${{ matrix.os }}
    continue-on-error: ${{ matrix.allow_failure || false }}
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-22.04
            # Oldest supported version, keep in sync with README.md
            rustc: "1.85.0"
            extra_desc: dist-tests
            extra_args: --no-default-features --features=dist-tests test_dist_ -- --test-threads 1
          - os: ubuntu-22.04
            rustc: stable
            extra_desc: dist-server
            extra_args: --features=dist-server
          - os: ubuntu-22.04
            rustc: stable
          - os: ubuntu-22.04
            rustc: beta
          - os: ubuntu-22.04
            rustc: nightly
            allow_failure: true
            extra_args: --features=unstable
          - os: ubuntu-22.04
            extra_desc: no-default-features
            extra_args: --no-default-features
            allow_failure: true
          - os: ubuntu-22.04
            cuda: "11.8"
            extra_desc: cuda11.8
          - os: ubuntu-24.04
            cuda: "12.8"
            # Oldest supported version, keep in sync with README.md
            rustc: "1.85.0"
            extra_desc: cuda12.8
          # # M1 CPU
          - os: macos-14
          - os: macos-15-intel
          - os: windows-2022
            cuda: "12.8"
            # Oldest supported version, keep in sync with README.md
            rustc: "1.85.0"
            extra_args: --no-fail-fast
            notest_cuda_compilers: clang++
            extra_desc: cuda12.8
          - os: windows-2022
            cuda: "12.8"
            rustc: nightly
            allow_failure: true
            extra_args: --features=unstable
            notest_cuda_compilers: clang++
            extra_desc: cuda12.8
          - os: windows-2022
            cuda: "12.8"
            rustc: beta
            notest_cuda_compilers: clang++
            extra_desc: cuda12.8
            no_coverage: true
    env:
      RUST_BACKTRACE: 1
      COVERAGE_REPORT_DIR: "target/debug"
      COVERAGE_REPORT_FILE: "target/debug/lcov.info"
      BINARY_DIR: "target/debug"
      GRCOV_IGNORE_OPTION: '--ignore build.rs --ignore "/*" --ignore "[a-zA-Z]:/*"'
      GRCOV_EXCLUDE_OPTION: '--excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()"'
      NOTEST_CUDA_COMPILERS: ${{ matrix.notest_cuda_compilers || '' }}
      CARGO_PROFILE_DEV_DEBUG: '0' # save disk space
    steps:
      - if: ${{ contains(matrix.os, 'windows') }}
        uses: ilammy/msvc-dev-cmd@v1

      - name: Clone repository
        uses: actions/checkout@v5

      - name: Install rust
        uses: ./.github/actions/rust-toolchain
        with:
          toolchain: ${{ matrix.rustc }}
          components: llvm-tools-preview

      - if: ${{ contains(matrix.os, 'ubuntu') }}
        name: Install gcc & clang for tests
        env:
          DEBIAN_FRONTEND: noninteractive
        run: |
          set -x
          # Conflicts with clang-cuda
          if dpkg -s gcc-14 >/dev/null 2>&1; then
            sudo apt remove -y gcc-14 g++-14
            sudo apt autoremove -y
          fi
          sudo apt install -y --no-install-recommends gcc clang
          echo 'gcc version:'
          gcc --version
          echo 'clang version:'
          clang --version

      - if: ${{ matrix.cuda != '' && (runner.os == 'Linux' || runner.os == 'Windows') }}
        name: Install nvcc
        uses: ./.github/actions/nvcc-toolchain
        with:
          cuda-version: ${{ matrix.cuda }}

      - name: "`grcov` ~ install"
        if: ${{ ! matrix.no_coverage }}
        shell: bash
        run: |
          GRCOV_VERSION="0.10.7"
          if [[ "$RUNNER_OS" == "Windows" ]]; then
            TARGET="x86_64-pc-windows-msvc"
            EXT="zip"
          elif [[ "$RUNNER_OS" == "macOS" && "$RUNNER_ARCH" == "ARM64" ]]; then
            TARGET="aarch64-apple-darwin"
            EXT="tar.bz2"
          elif [[ "$RUNNER_OS" == "macOS" ]]; then
            TARGET="x86_64-apple-darwin"
            EXT="tar.bz2"
          else
            TARGET="x86_64-unknown-linux-musl"
            EXT="tar.bz2"
          fi
          URL="https://github.com/mozilla/grcov/releases/download/v${GRCOV_VERSION}/grcov-${TARGET}.${EXT}"
          curl -sL "$URL" -o "grcov.${EXT}"
          if [[ "$EXT" == "zip" ]]; then
            unzip -q "grcov.${EXT}" -d "$HOME/.cargo/bin/"
          else
            tar -xjf "grcov.${EXT}" -C "$HOME/.cargo/bin/"
          fi

      - name: Create config for testing
        if: ${{ ! matrix.no_coverage }}
        run: |
          mkdir -p .cargo
          echo '[env]
          LLVM_PROFILE_FILE = { value = "target/debug/coverage/default-%p-%8m.profraw", relative = true }' >> .cargo/config.toml

      - if: ${{ matrix.cuda != '' && runner.os == 'Linux' }}
        name: Free disk space for CUDA tests
        run: |
          sudo apt clean
          sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android /usr/local/share/boost /usr/share/swift /var/lib/apt/lists/*

      - name: Execute tests
        run: cargo test --locked --lib --bins --tests ${{ matrix.extra_args }}
        env:
          CARGO_INCREMENTAL: "0"
          RUSTC_WRAPPER: ""
          RUSTFLAGS: "-Cinstrument-coverage -Ccodegen-units=1 -Copt-level=0 -Coverflow-checks=off"

      - name: Upload failure
        if: failure()
        uses: ./.github/actions/artifact_failure
        with:
          name: test-${{ matrix.os }}-${{ matrix.rustc || 'stable' }}-${{ matrix.extra_desc }}

  # coverage:
      - name: Display coverage files
        if: ${{ ! matrix.no_coverage }}
        shell: bash
        run:
          grcov . -s . --binary-path $BINARY_DIR --output-type files $GRCOV_IGNORE_OPTION $GRCOV_EXCLUDE_OPTION | sort --unique

      - name: Generate coverage data (via `grcov`)
        if: ${{ ! matrix.no_coverage }}
        id: coverage
        shell: bash
        run: |
          mkdir -p "${COVERAGE_REPORT_DIR}"
          grcov . -s . --binary-path $BINARY_DIR --output-type lcov --output-path "${COVERAGE_REPORT_FILE}" --branch $GRCOV_IGNORE_OPTION $GRCOV_EXCLUDE_OPTION
          echo "report=${COVERAGE_REPORT_FILE}" >> $GITHUB_OUTPUT

      - name: Upload coverage results (to Codecov.io)
        if: ${{ ! matrix.no_coverage }}
        uses: codecov/codecov-action@v5
        with:
          files: ${{ steps.coverage.outputs.report }}
          ## flags: IntegrationTests, UnitTests, ${{ steps.vars.outputs.CODECOV_FLAGS }}
          flags: ${{ steps.vars.outputs.CODECOV_FLAGS }}
          name: codecov-umbrella-${{ matrix.os }}-rust_${{ matrix.rustc || 'stable' }}-${{ matrix.extra_desc }}
          fail_ci_if_error: true
          # verbose: true
        env:
          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}



  build:
    name: build ${{ matrix.binary || 'sccache' }} ${{ matrix.target }}
    runs-on: ${{ matrix.os }}
    container: ${{ fromJson(matrix.container || '{"image":null}') }}
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-22.04
            target: x86_64-unknown-linux-musl
            container: '{"image": "messense/rust-musl-cross:x86_64-musl"}'
          - os: ubuntu-22.04
            target: s390x-unknown-linux-musl
            container: '{"image": "messense/rust-musl-cross:s390x-musl"}'
            lto: "false"
          - os: ubuntu-22.04
            target: s390x-unknown-linux-gnu
          - os: ubuntu-22.04
            target: riscv64gc-unknown-linux-musl
            container: '{"image": "messense/rust-musl-cross:riscv64gc-musl"}'
            lto: "false"
          - os: ubuntu-22.04
            binary: sccache-dist
            extra_args: --no-default-features --features="dist-server"
            target: x86_64-unknown-linux-musl
            container: '{"image": "messense/rust-musl-cross:x86_64-musl"}'
          - os: ubuntu-22.04
            target: aarch64-unknown-linux-musl
            container: '{"image": "messense/rust-musl-cross:aarch64-musl"}'
          - os: ubuntu-22.04
            target: armv7-unknown-linux-musleabi
            container: '{"image": "messense/rust-musl-cross:armv7-musleabi"}'
          - os: ubuntu-22.04
            target: i686-unknown-linux-musl
            container: '{"image": "messense/rust-musl-cross:i686-musl"}'
          - os: macos-14
            target: aarch64-apple-darwin
            macosx_deployment_target: 11.0
          - os: macos-15-intel
            target: x86_64-apple-darwin
            macosx_deployment_target: 11.0
          - os: windows-2022
            target: x86_64-pc-windows-msvc
            rustflags: -Ctarget-feature=+crt-static
          - os: windows-2022
            target: aarch64-pc-windows-msvc
            rustflags: -Ctarget-feature=+crt-static
    steps:
      - name: Clone repository
        uses: actions/checkout@v5

      - name: Install rust
        uses: ./.github/actions/rust-toolchain
        with:
          toolchain: ${{ matrix.target == 'aarch64-apple-darwin' && 'beta' || 'stable' }}
          target: ${{ matrix.target }}
        if: ${{ !matrix.container }}

      - name: Install s390x cross-compilation toolchain
        if: ${{ matrix.target == 's390x-unknown-linux-gnu' }}
        run: |
          sudo apt-get update
          sudo apt-get install -y gcc-s390x-linux-gnu g++-s390x-linux-gnu
          mkdir -p .cargo
          cat >> .cargo/config.toml <<EOF
          [target.s390x-unknown-linux-gnu]
          linker = "s390x-linux-gnu-gcc"
          EOF

      - name: Install rust-src for s390x-musl
        if: ${{ matrix.target == 's390x-unknown-linux-musl' }}
        run: |
          # Remove corrupted nightly toolchain if it exists
          rustup toolchain uninstall nightly || true
          # Clean up any leftover files
          rm -rf ~/.rustup/toolchains/nightly-* || true
          # Install fresh nightly with minimal profile
          rustup toolchain install nightly --profile minimal
          rustup component add rust-src --toolchain nightly

      - name: fix build openssl error on s390x
        if: ${{  matrix.target  == 's390x-unknown-linux-musl' }}
        run: |
          # see https://github.com/openssl/openssl/issues/27323
          echo CFLAGS="-march=z10 -mzarch" >> $GITHUB_ENV
          echo CXXFLAGS="$CFLAGS" >> $GITHUB_ENV
          echo RUSTFLAGS="-C target-cpu=z10" >> $GITHUB_ENV

      - name: Build (s390x-musl with build-std)
        if: ${{ matrix.target == 's390x-unknown-linux-musl' }}
        run: cargo +nightly build --locked --release --bin ${{ matrix.binary || 'sccache' }} --target ${{ matrix.target }} --features=openssl/vendored ${{ matrix.extra_args }} -Zbuild-std
        env:
          MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx_deployment_target }}
          DEVELOPER_DIR: ${{ matrix.developer_dir }}
          SDKROOT: ${{ matrix.sdkroot }}
          RUSTFLAGS: ${{ env.RUSTFLAGS || matrix.rustflags }}
          CARGO_PROFILE_RELEASE_LTO: ${{ matrix.lto || 'true' }}

      - name: Build
        if: ${{ matrix.target != 's390x-unknown-linux-musl' }}
        run: cargo build --locked --release --bin ${{ matrix.binary || 'sccache' }} --target ${{ matrix.target }} --features=openssl/vendored ${{ matrix.extra_args }}
        env:
          MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx_deployment_target }}
          DEVELOPER_DIR: ${{ matrix.developer_dir }}
          SDKROOT: ${{ matrix.sdkroot }}
          RUSTFLAGS: ${{ env.RUSTFLAGS || matrix.rustflags }}
          CARGO_PROFILE_RELEASE_LTO: ${{ matrix.lto || 'true' }}

      # Workaround for the lack of substring() function in github actions expressions.
      - name: Id
        id: id
        shell: bash
        run: echo "id=${ID#refs/tags/}" >> $GITHUB_OUTPUT
        env:
          ID: ${{ startsWith(github.ref, 'refs/tags/') && github.ref || github.sha }}

      - name: Upload artifacts
        uses: actions/upload-artifact@v7
        with:
          name: ${{ matrix.binary || 'sccache' }}-${{ steps.id.outputs.id }}-${{ matrix.target }}
          path: target/${{ matrix.target }}/release/${{ matrix.binary || 'sccache' }}${{ endsWith(matrix.target, '-msvc') && '.exe' || '' }}
          if-no-files-found: error


  test_freebsd:
    name: test freebsd-15.0 rust stable
    runs-on: ${{ matrix.job.os }}
    timeout-minutes: 70
    strategy:
      fail-fast: false
      matrix:
        job:
          - { os: ubuntu-22.04 }
    steps:
      - uses: actions/checkout@v5
      - name: Prepare, build and test
        uses: vmactions/freebsd-vm@v1
        with:
          mem: 8192
          usesh: true
          sync: rsync
          copyback: false
          prepare: pkg install -y ca_root_nss curl gmake gtar pot sudo
          run: |
            #####################################################################################
            ###  Prepare, build, and test
            #####################################################################################
            ###  based on ref: <https://github.com/rust-lang/rustup/pull/2783>
            ###  and on ref: <https://github.com/uutils/coreutils/commit/86c610a84b8b6c>
            ###  * NOTE: All steps need to be run in this block, otherwise, we are operating back
            ###    on the mac host.
            set -exo pipefail
            #
            ### Basic user setup ################################################################
            TEST_USER=tester
            TEST_USER_HOME="/opt/$TEST_USER"
            REPO_NAME=${GITHUB_WORKSPACE##*/}
            WORKSPACE_PARENT="/home/runner/work/${REPO_NAME}"
            WORKSPACE="${WORKSPACE_PARENT}/${REPO_NAME}"
            export WORKSPACE
            #
            mkdir -p "$TEST_USER_HOME"
            pw adduser -n "$TEST_USER" -d "$TEST_USER_HOME" -c "Tester" -h -
            chown -R "$TEST_USER":"$TEST_USER" "$TEST_USER_HOME"
            chown -R "$TEST_USER":"$TEST_USER" "/$WORKSPACE_PARENT"/
            cat > /usr/local/etc/sudoers.d/wheel<<EOF
            $TEST_USER ALL=(ALL) NOPASSWD: ALL
            EOF
            #
            ### Install rust stable from rustup  ################################################
            su "$TEST_USER" -c "/bin/sh -exo pipefail" <<"EOH"
            whoami
            echo "$HOME"
            fetch -o /tmp/rustup.sh https://sh.rustup.rs
            sh /tmp/rustup.sh -y --profile=minimal
            ### Run tests #######################################################################
            . "$HOME/.cargo/env"
            "$WORKSPACE/scripts/freebsd-ci-test.sh"
            EOH
            # end
      - name: Upload failure
        if: failure()
        uses: ./.github/actions/artifact_failure
        with:
          name: test-freebsd-15.0-stable

  release:
    name: release
    runs-on: ubuntu-latest
    needs: [ build, lint, test ]
    if: ${{ startsWith(github.ref, 'refs/tags/') }}
    steps:
      - name: Clone repository
        uses: actions/checkout@v5

      - name: Check versions
        run: |
          tag_name=${GITHUB_REF#refs/tags/}
          v=$(grep -m 1 "^version" Cargo.toml|sed -e "s|version = \"\(.*\)\"|\1|")
          if ! echo $tag_name|grep -q $v; then
             echo "Mistmatch of the version:"
             echo "Cargo.toml says $v while the tag is $tag_name"
             exit 2
          fi

      - name: Get artifacts
        uses: actions/download-artifact@v8

      - name: Create release assets
        run: |
          for d in sccache-*; do
            chmod +x "$d/sccache"*
            cp README.md LICENSE "$d/"
            tar -zcvf "$d.tar.gz" "$d"
            echo -n "$(shasum -ba 256 "$d.tar.gz" | cut -d " " -f 1)" > "$d.tar.gz.sha256"
            if [[ $d =~ sccache-.*-pc-windows-.* ]]; then
              zip -r "$d.zip" "$d"
              echo -n "$(shasum -ba 256 "$d.zip" | cut -d " " -f 1)" > "$d.zip.sha256"
            fi
          done

      - name: Create release
        run: |
          sudo apt-get update && sudo apt-get install -y hub
          tag_name=${GITHUB_REF#refs/tags/}
          for f in sccache-*.tar.gz* sccache-*.zip*; do
              if [[ -f "$f" ]]; then
                files="$files -a $f";
              fi
          done
          hub release create -d -m $tag_name $tag_name $files
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .github/workflows/close-snap.yml
================================================
name: Close Snaps

on:
  pull_request:
    types: [closed]

jobs:
  close:
    runs-on: ubuntu-latest

    timeout-minutes: 5

    steps:
    - name: Close obsolete channels
      uses: canonical/actions/close-snap@release
      continue-on-error: true
      with:
        channel: edge/pr${{ github.event.number }}
        snapcraft-token: ${{ secrets.SNAPCRAFT_TOKEN }}


================================================
FILE: .github/workflows/integration-tests.yml
================================================
name: integration-tests
on: [ push, pull_request ]

env:
  RUST_BACKTRACE: full
  RUST_LOG: debug
  SCCACHE_PATH: /home/runner/.cargo/bin/sccache
  ACTIONS_CACHE_SERVICE_V2: on

jobs:
  build:
    runs-on: ubuntu-24.04
    steps:
      - name: Clone repository
        uses: actions/checkout@v5

      - name: Install rust
        uses: ./.github/actions/rust-toolchain
        with:
          toolchain: "stable"

      - name: Build
        run: |
          cargo build --all-features

      - uses: actions/upload-artifact@v7
        with:
          name: integration-tests
          path: ./target/debug/sccache

  integration-tests:
    runs-on: ubuntu-24.04
    strategy:
      matrix:
        type: [backends, tools]

    steps:
      - name: Clone repository
        uses: actions/checkout@v5

      - name: Test
        run: cd tests/integration && WITH_COVERAGE=1 make test-${{ matrix.type }}

      - name: Build report
        run: |
          cd tests/integration
          WITH_COVERAGE=1 make coverage-report
          echo "Coverage files:"
          ls ../../target/integration-coverage/profraw -l
          echo "Coverage report:"
          ls ../../target/integration-coverage/reports/lcov.info -l

      - name: Upload coverage results (to Codecov.io)
        uses: codecov/codecov-action@v5
        with:
          files: target/integration-coverage/reports/lcov.info
          name: codecov-umbrella-integration-${{ matrix.type }}
          fail_ci_if_error: true
          # verbose: true
        env:
          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

  gha:
    runs-on: ubuntu-24.04
    needs: build

    env:
      SCCACHE_GHA_ENABLED: "on"
      RUSTC_WRAPPER: /home/runner/.cargo/bin/sccache

    steps:
      - name: Clone repository
        uses: actions/checkout@v5

      - name: Configure Cache Env
        uses: actions/github-script@v8
        with:
          script: |
            core.exportVariable('ACTIONS_RESULTS_URL', process.env.ACTIONS_RESULTS_URL || '');
            core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');

      - name: Install rust
        uses: ./.github/actions/rust-toolchain
        with:
          toolchain: "stable"

      - uses: actions/download-artifact@v8
        with:
          name: integration-tests
          path: /home/runner/.cargo/bin/
      - name: Chmod for binary
        run: chmod +x ${SCCACHE_PATH}

      - name: Test
        run: cargo clean && cargo build

      - name: Output
        run: |
          ${SCCACHE_PATH} --show-stats

          ${SCCACHE_PATH} --show-stats | grep gha

      - name: Test Twice for Cache Read
        run: cargo clean && cargo build

      - name: Output
        run: |
          ${SCCACHE_PATH} --show-stats

          ${SCCACHE_PATH} --show-stats | grep -e "Cache hits\s*[1-9]"

  test-mock-msvc:
    runs-on: windows-2022
    env:
      TARGET: x86_64-pc-windows-msvc
      SCCACHE_EXE: ${{ github.workspace }}\\target\\x86_64-pc-windows-msvc\\debug\\sccache.exe
      SCCACHE_LOG: "debug"
      SCCACHE_ERROR_LOG: "${{ github.workspace }}\\server_log.txt"

    steps:
      - uses: ilammy/msvc-dev-cmd@v1

      - name: Clone repository
        uses: actions/checkout@v5

      - name: Install rust
        uses: ./.github/actions/rust-toolchain
        with:
          toolchain: "stable"
          target: $TARGET

      - name: Build
        run: cargo build --bin sccache --target $env:TARGET --features=vendored-openssl

      - name: Compile MSVC (no cache)
        shell: bash
        working-directory: ./tests/integration/msvc
        run: |
          cl "@args.rsp"
          test -e ./foo.o || { echo "No compiler output found"; exit -1; }

      - name: Start Server
        shell: bash
        run: $SCCACHE_EXE --start-server

      - name: Compile - Cache Miss
        shell: bash
        working-directory: ./tests/integration/msvc
        run: |
          rm ./foo.o || true
          $SCCACHE_EXE "$(where cl.exe)" -c "@args.rsp"
          $SCCACHE_EXE --show-stats
          $SCCACHE_EXE --show-stats | grep -e "Cache misses\s*[1-9]"
          test -e ./foo.o || { echo "No compiler output found"; exit -1; }
          test -e ./foo.o.json || { echo "No dependency list found"; exit -1; }

      - name: Compile - Cache Hit
        shell: bash
        working-directory: ./tests/integration/msvc
        run: |
          rm ./foo.o || true
          $SCCACHE_EXE "$(where cl.exe)" -c "@args.rsp"
          $SCCACHE_EXE --show-stats
          $SCCACHE_EXE --show-stats | grep -e "Cache hits\s*[1-9]"
          test -e ./foo.o || { echo "No compiler output found"; exit -1; }
          test -e ./foo.o.json || { echo "No dependency list found"; exit -1; }

      - name: Compile - Preprocessing Compiler Bug
        shell: bash
        working-directory: ./tests/integration/msvc-preprocessing
        run: |
          $SCCACHE_EXE "$(where cl.exe)" -c "@args.rsp"
          $SCCACHE_EXE --show-stats

      - name: Prepare - MSBuild support
        shell: bash
        working-directory: ./tests/msvc-msbuild
        # Force stop server to drop compiler cache - need to test showInclude prefix detection
        run: |
          $SCCACHE_EXE --stop-server
          mkdir -p compiler
          cp $SCCACHE_EXE compiler/cl.exe

      - name: Compile - MSBuild support
        working-directory: ./tests/msvc-msbuild
        run: msbuild MsbuildCpp.vcxproj -property:Configuration=Release -property:Platform=x64 "-property:SolutionDir=${{ github.workspace }}/tests/msvc-msbuild/"

      - name: Stop Server
        if: success() || failure()
        shell: bash
        run: $SCCACHE_EXE --stop-server

      - name: Show Server Log
        if: success() || failure()
        shell: bash
        run: cat "$SCCACHE_ERROR_LOG"

  hip:
    # Probably wouldn't matter anyway since we run in a container, but staying
    # close to the version is better than not.
    runs-on: ubuntu-24.04
    needs: build
    container:
      image: rocm/dev-ubuntu-24.04:6.3

    env:
      # SCCACHE_GHA_ENABLED: "on"
      ROCM_PATH: "/opt/rocm"
      RANDOMIZE_READDIR_LOG: "/tmp/readdir.log"

    steps:
      - name: Clone repository
        uses: actions/checkout@v5

      # I don't want to break the cache during testing. Will turn on after I
      # make sure it's working.
      #
      # - name: Configure Cache Env
      #   uses: actions/github-script@v8
      #   with:
      #     script: |
      #       core.exportVariable('ACTIONS_RESULTS_URL', process.env.ACTIONS_RESULTS_URL || '');
      #       core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '')

      # - name: Configure ROCm Env
      #   uses: actions/github-script@v8
      #   with:
      #     script: |
      #       core.exportVariable('ROCM_PATH', process.env.ROCM_PATH || '');

      - name: Install dependencies
        shell: bash
        run: |
          ## Install dependencies
          sudo apt-get update
          sudo apt-get install -y cmake curl
          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain none -y
          echo "$HOME/.cargo/bin" >> $GITHUB_PATH

      - name: Install rust
        uses: ./.github/actions/rust-toolchain
        with:
          toolchain: "stable"

      - name: Build & setup librandomize_readdir
        run: |
          cargo build -p randomize_readdir

      - uses: actions/download-artifact@v8
        with:
          name: integration-tests
          path: /home/runner/.cargo/bin/
      - name: Chmod for binary
        run: chmod +x ${SCCACHE_PATH}

      # Ensure that HIPCC isn't already borken
      - name: Sanity Check
        run: |
          export LD_PRELOAD=$PWD/target/debug/librandomize_readdir.so
          hipcc -o vectoradd_hip --offload-arch=gfx900 tests/integration/cmake-hip/vectoradd_hip.cpp

      - name: Test
        run: |
          export LD_PRELOAD=$PWD/target/debug/librandomize_readdir.so
          rm "$RANDOMIZE_READDIR_LOG".*
          cmake -B build -S tests/integration/cmake-hip -DCMAKE_HIP_COMPILER_LAUNCHER=${SCCACHE_PATH} -DCMAKE_HIP_ARCHITECTURES=gfx900
          cmake --build build
          if ! grep -q bitcode "$RANDOMIZE_READDIR_LOG".*; then
            echo "amdgcn bitcode not accessed, is librandomize_readdir properly set up?"
            exit 1
          fi

      - name: Output
        run: |
          export LD_PRELOAD=$PWD/target/debug/librandomize_readdir.so
          ${SCCACHE_PATH} --show-stats

      - name: Test Twice for Cache Read
        run: |
          export LD_PRELOAD=$PWD/target/debug/librandomize_readdir.so
          rm "$RANDOMIZE_READDIR_LOG".*
          rm -rf build
          cmake -B build -S tests/integration/cmake-hip -DCMAKE_HIP_COMPILER_LAUNCHER=${SCCACHE_PATH} -DCMAKE_HIP_ARCHITECTURES=gfx900
          cmake --build build
          if ! grep -q bitcode "$RANDOMIZE_READDIR_LOG".*; then
            echo "amdgcn bitcode not accessed, is librandomize_readdir properly set up?"
            exit 1
          fi

      - name: Output
        run: |
          export LD_PRELOAD=$PWD/target/debug/librandomize_readdir.so
          ${SCCACHE_PATH} --show-stats
          ${SCCACHE_PATH} --show-stats | grep -e "Cache hits\s*[1-9]"

  cmake-modules:
    runs-on: ubuntu-24.04
    needs: build

    env:
      SCCACHE_GHA_ENABLED: "on"
      LLVM_VERSION: "19"

    steps:
      - uses: actions/checkout@v5

      - name: Configure Cache Env
        uses: actions/github-script@v8
        with:
          script: |
            core.exportVariable('ACTIONS_RESULTS_URL', process.env.ACTIONS_RESULTS_URL || '');
            core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '')

      - uses: actions/download-artifact@v8
        with:
          name: integration-tests
          path: /home/runner/.cargo/bin/
      - name: Chmod for binary
        run: chmod +x ${SCCACHE_PATH}

      - name: Install dependencies
        shell: bash
        run: |
          wget https://apt.llvm.org/llvm.sh
          chmod +x llvm.sh
          sudo ./llvm.sh "${LLVM_VERSION}"
          sudo apt-get update
          sudo apt-get install -y ninja-build
          pip install cmake

      - name: Test
        run: |
          cd `pwd`/tests/cmake-modules/
          cmake -B build -G Ninja \
            -DCMAKE_C_COMPILER=clang-${LLVM_VERSION} \
            -DCMAKE_CXX_COMPILER=clang++-${LLVM_VERSION} \
            -DCMAKE_C_COMPILER_LAUNCHER=${SCCACHE_PATH} \
            -DCMAKE_CXX_COMPILER_LAUNCHER=${SCCACHE_PATH}
          cmake --build build

      - name: Output
        run: |
          ${SCCACHE_PATH} --show-stats

      - name: Test Twice for Cache Read
        run: |
          cd `pwd`/tests/cmake-modules/
          rm -rf build
          cmake -B build -G Ninja \
            -DCMAKE_C_COMPILER=clang-${LLVM_VERSION} \
            -DCMAKE_CXX_COMPILER=clang++-${LLVM_VERSION} \
            -DCMAKE_C_COMPILER_LAUNCHER=${SCCACHE_PATH} \
            -DCMAKE_CXX_COMPILER_LAUNCHER=${SCCACHE_PATH}
          cmake --build build

      - name: Output
        run: |
          ${SCCACHE_PATH} --show-stats

          ${SCCACHE_PATH} --show-stats | grep -e "Cache hits\s*[1-9]"

  xcode:
    runs-on: macos-latest
    env:
      SCCACHE_PATH: target/debug/sccache
    steps:
      - name: Clone repository
        uses: actions/checkout@v5

      - name: Install rust
        uses: ./.github/actions/rust-toolchain
        with:
          toolchain: "stable"

      - name: Build sccache
        run: |
          cargo build

      - name: Start server
        run: ${SCCACHE_PATH} --start-server

      - name: Test compile xcode
        working-directory: tests/integration/xcode
        run: |
          xcodebuild -version
          xcodebuild -xcconfig sccache.xcconfig

      - name: Output
        run: |
          ${SCCACHE_PATH} --show-stats

      - name: Test compile xcode cached
        working-directory: tests/integration/xcode
        run: |
          xcodebuild clean
          xcodebuild -xcconfig sccache.xcconfig

      - name: Output
        run: |
          ${SCCACHE_PATH} --show-stats
          ${SCCACHE_PATH} --show-stats | grep -e "Cache hits\s*[1-9]"


================================================
FILE: .github/workflows/snap.yml
================================================
name: Snap

on:
  pull_request:
    types: [opened, synchronize, reopened, ready_for_review]

jobs:
  Snap:
    runs-on: ubuntu-latest

    timeout-minutes: 45

    steps:
    - name: Check out code
      uses: actions/checkout@v5
      with:
        fetch-depth: 0  # needed for version determination

    - name: Build and publish the snap
      uses: canonical/actions/build-snap@release
      with:
        snapcraft-channel: edge
        review-opts: --allow-classic
        snapcraft-token: ${{ secrets.SNAPCRAFT_TOKEN }}
        publish: ${{ github.event_name == 'pull_request' && github.repository == github.event.pull_request.head.repo.full_name }}
        publish-channel: edge/pr${{ github.event.number }}


================================================
FILE: .gitignore
================================================
target
*~

*.log
.cargo
*.pyc

# snapcraft artifacts
/parts
/prime
/snap/.snapcraft
/stage
/*.snap

# Ignore lockfiles of test crates used in the integration tests
tests/**/Cargo.lock

# VSCode Workspace files
**.code-workspace

.direnv/
result
.vscode/settings.json


================================================
FILE: .pre-commit-config.yaml
================================================
repos:
-   repo: local
    hooks:
    -   id: rust-linting
        name: Rust linting
        description: Run cargo fmt on files included in the commit.
        entry: cargo +nightly fmt --
        pass_filenames: true
        types: [file, rust]
        language: system
    -   id: rust-clippy
        name: Rust clippy
        description: Run cargo clippy on files included in the commit.
        entry: cargo +nightly clippy --workspace --all-targets --all-features --
        pass_filenames: false
        types: [file, rust]
        language: system


================================================
FILE: .rustfmt.toml
================================================
# Should match package.edition from Cargo.toml
edition = "2024"


================================================
FILE: .taplo.toml
================================================
include = ["Cargo.toml", "**/*.toml"]

[formatting]
# Align consecutive entries vertically.
align_entries = false
# Append trailing commas for multi-line arrays.
array_trailing_comma = true
# Expand arrays to multiple lines that exceed the maximum column width.
array_auto_expand = true
# Collapse arrays that don't exceed the maximum column width and don't contain comments.
array_auto_collapse = true
# Omit white space padding from single-line arrays
compact_arrays = true
# Omit white space padding from the start and end of inline tables.
compact_inline_tables = false
# Maximum column width in characters, affects array expansion and collapse, this doesn't take whitespace into account.
# Note that this is not set in stone, and works on a best-effort basis.
column_width = 80
# Indent based on tables and arrays of tables and their subtables, subtables out of order are not indented.
indent_tables = false
# The substring that is used for indentation, should be tabs or spaces (but technically can be anything).
indent_string = '  '
# Add trailing newline at the end of the file if not present.
trailing_newline = true
# Alphabetically reorder keys that are not separated by empty lines.
reorder_keys = true
# Maximum amount of allowed consecutive blank lines. This does not affect the whitespace at the end of the document, as it is always stripped.
allowed_blank_lines = 1
# Use CRLF for line endings.
crlf = false


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Community Participation Guidelines

This repository is governed by Mozilla's code of conduct and etiquette guidelines. 
For more details, please read the
[Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/). 

## How to Report
For more information on how to report violations of the Community Participation Guidelines, please read our '[How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' page.

<!--
## Project Specific Etiquette

In some cases, there will be additional project etiquette i.e.: (https://bugzilla.mozilla.org/page.cgi?id=etiquette.html).
Please update for your project.
-->


================================================
FILE: Cargo.toml
================================================
[package]
# Should match .rustfmt.toml
edition = "2024"
name = "sccache"
rust-version = "1.85.0"
version = "0.14.0"

categories = ["command-line-utilities", "development-tools::build-utils"]
description = "Sccache is a ccache-like tool. It is used as a compiler wrapper and avoids compilation when possible. Sccache has the capability to utilize caching in remote storage environments, including various cloud storage options, or alternatively, in local storage."
keywords = ["ccache"]
license = "Apache-2.0"
readme = "README.md"
repository = "https://github.com/mozilla/sccache/"

[[bin]]
name = "sccache"

[[bin]]
name = "sccache-dist"
required-features = ["dist-server"]

[profile.test]
debug = false # save disk space

[profile.release]
codegen-units = 1
lto = true
strip = true

[dependencies]
anyhow = { version = "1.0", features = ["backtrace"] }
ar = "0.9"
async-trait = "0.1"
backon = { version = "1", default-features = false, features = [
  "std-blocking-sleep",
] }
base64 = "0.21"
bincode = "1"
blake3 = "1"
byteorder = "1.5"
bytes = "1"
chrono = "0.4"
clap = { version = "4.5.13", features = ["derive", "env", "wrap_help"] }
directories = "6.0"
encoding_rs = "0.8"
env_logger = "0.11"
filetime = "0.2"
flate2 = { version = "1.0", optional = true, default-features = false, features = [
  "rust_backend",
] }
fs-err = "3"
futures = "0.3"
gzp = { version = "2", default-features = false, features = ["deflate_rust"] }
http = "1.0"
http-body-util = { version = "0.1", optional = true }
hyper = { version = "1.1", optional = true, features = ["server", "http1"] }
hyper-util = { version = "0.1.3", optional = true, features = [
  "tokio",
  "server",
] }
itertools = "0.14"
jobserver = "0.1"
jwt = { package = "jsonwebtoken", version = "9", optional = true }
libc = "0.2.153"
linked-hash-map = "0.5"
log = "0.4"
memchr = "2"
memmap2 = "0.9.4"
mime = "0.3"
number_prefix = "0.4"
object = "0.37"
opendal = { version = "0.55.0", optional = true, default-features = false }
openssl = { version = "0.10.75", optional = true }
rand = "0.8.4"
regex = "1.10.3"
reqsign = { version = "0.18.0", optional = true }
reqwest = { version = "0.12", features = [
  "json",
  "blocking",
  "stream",
  "rustls-tls",
  "rustls-tls-native-roots",
  "trust-dns",
], optional = true }
semver = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = ">=1.0, <1.0.147" # zmij (used in 1.0.147+) requires Rust 1.84+
sha2 = { version = "0.10.8", optional = true }
shlex = "1.3.0"
strip-ansi-escapes = "0.2"
tar = "0.4.40"
tempfile = "3"
tokio = { version = "1", features = [
  "rt-multi-thread",
  "io-util",
  "time",
  "net",
  "process",
  "macros",
] }
tokio-serde = "0.9"
tokio-util = { version = "0.7", features = ["codec", "io"] }
toml = "0.9"
tower-service = "0.3"
typed-path = "0.12.0"
url = { version = "2", optional = true }
uuid = { version = "1.9", features = ["v4"] }
walkdir = "2"
# by default which pulls in an outdated failure version
which = { version = "6", default-features = false }
zip = { version = "0.6", default-features = false }
zstd = "0.13"

# dist-server only
nix = { version = "0.30.0", optional = true, features = [
  "mount",
  "user",
  "sched",
  "signal",
  "process",
] }
rouille = { version = "3.6", optional = true, default-features = false, features = [
  "ssl",
] }
syslog = { version = "7", optional = true }
version-compare = { version = "0.1.1", optional = true }

[dev-dependencies]
assert_cmd = "2.0.13"
cc = "1.0"
chrono = "0.4.42"
divan = { package = "codspeed-divan-compat", version = "4" }
filetime = "0.2"
predicates = "=3.1.0"
serial_test = "3.1"
temp-env = "0.3.6"
test-case = "3.3.1"
thirtyfour = "0.36"

[target.'cfg(unix)'.dependencies]
daemonix = "0.1"

[target.'cfg(not(target_os = "freebsd"))'.dependencies.libmount]
optional = true
version = "0.1.15"

[target.'cfg(windows)'.dependencies.windows-sys]
features = [
  "Win32_Foundation",
  "Win32_Globalization",
  "Win32_Storage_FileSystem",
  "Win32_System_Threading",
  "Win32_System_Console",
  "Win32_Security",
]
version = "0.52"

[features]
all = [
  "dist-client",
  "redis",
  "s3",
  "memcached",
  "gcs",
  "azure",
  "gha",
  "webdav",
  "oss",
  "cos",
]
azure = ["opendal/services-azblob", "reqsign", "reqwest"]
cos = ["opendal/services-cos", "reqsign", "reqwest"]
default = ["all"]
gcs = ["opendal/services-gcs", "reqsign", "url", "reqwest"]
gha = ["opendal/services-ghac", "reqwest"]
memcached = ["opendal/services-memcached"]
native-zlib = []
oss = ["opendal/services-oss", "reqsign", "reqwest"]
redis = ["url", "opendal/services-redis"]
s3 = ["opendal/services-s3", "reqsign", "reqwest"]
webdav = ["opendal/services-webdav", "reqwest"]
# Enable features that will build a vendored version of openssl and
# statically linked with it, instead of linking against the system-wide openssl
# dynamically or statically.
vendored-openssl = ["openssl?/vendored", "reqwest?/native-tls-vendored"]
# Enable features that require unstable features of Nightly Rust.
unstable = []
# Enables distributed support in the sccache client
dist-client = [
  "flate2",
  "hyper",
  "http-body-util",
  "hyper-util",
  "reqwest",
  "url",
  "sha2",
]
# Enables the sccache-dist binary
dist-server = [
  "jwt",
  "flate2",
  "libmount",
  "nix",
  "openssl",
  "reqwest",
  "rouille",
  "syslog",
  "version-compare",
]
# Enables dist tests with external requirements
dist-tests = ["dist-client", "dist-server"]

[workspace]
exclude = ["tests/test-crate"]
members = ["tests/integration/randomize_readdir"]

[[bench]]
harness = false
name = "sccache_bench"
test = false

[lints]
workspace = true

[workspace.lints.clippy]
cloned_instead_of_copied = "warn"
cloned_ref_to_slice_refs = "warn"
explicit_into_iter_loop = "warn"
from_iter_instead_of_collect = "warn"
implicit_clone = "warn"
manual_string_new = "warn"
ptr_as_ptr = "warn"
ref_option = "warn"
semicolon_if_nothing_returned = "warn"
unnecessary_semicolon = "warn"


================================================
FILE: LICENSE
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
[![Build Status](https://github.com/mozilla/sccache/workflows/ci/badge.svg)](https://github.com/mozilla/sccache/actions?query=workflow%3Aci)
[![Crates.io](https://img.shields.io/crates/v/sccache.svg)](https://crates.io/crates/sccache)
[![Matrix](https://img.shields.io/matrix/sccache:mozilla.org)](https://chat.mozilla.org/#/room/#sccache:mozilla.org)
![Crates.io](https://img.shields.io/crates/l/sccache)
[![dependency status](https://deps.rs/repo/github/mozilla/sccache/status.svg)](https://deps.rs/repo/github/mozilla/sccache)

[![CodeCov](https://codecov.io/gh/mozilla/sccache/branch/main/graph/badge.svg)](https://codecov.io/gh/mozilla/sccache)


sccache - Shared Compilation Cache
==================================

sccache is a [ccache](https://ccache.dev/)-like compiler caching tool. It is used as a compiler wrapper and avoids compilation when possible, storing cached results either on [local disk](docs/Local.md) or in one of [several cloud storage backends](#storage-options).

sccache includes support for caching the compilation of Assembler, C/C++ code, [Rust](docs/Rust.md), as well as NVIDIA's CUDA using [nvcc](https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html), and [clang](https://llvm.org/docs/CompileCudaWithLLVM.html), [AMD's ROCm HIP](https://rocm.docs.amd.com/projects/HIP/en/latest/index.html).

sccache also provides [icecream](https://github.com/icecc/icecream)-style distributed compilation (automatic packaging of local toolchains) for all supported compilers (including Rust). The distributed compilation system includes several security features that icecream lacks such as authentication, transport layer encryption, and sandboxed compiler execution on build servers. See [the distributed quickstart](docs/DistributedQuickstart.md) guide for more information.

sccache is also available as a [GitHub Actions](https://github.com/marketplace/actions/sccache-action) to facilitate the deployment using GitHub Actions cache.

---

Table of Contents (ToC)
=======================

* [Installation](#installation)
* [Usage](#usage)
* [Build Requirements](#build-requirements)
* [Build](#build)
* [Separating caches between invocations](#separating-caches-between-invocations)
* [Overwriting the cache](#overwriting-the-cache)
* [Debugging](#debugging)
* [Interaction with GNU `make` jobserver](#interaction-with-gnu-make-jobserver)
* [Known Caveats](#known-caveats)
* [Storage Options](#storage-options)
  * [Local](docs/Local.md)
  * [S3](docs/S3.md)
  * [R2](docs/S3.md#R2)
  * [Redis](docs/Redis.md)
  * [Memcached](docs/Memcached.md)
  * [Google Cloud Storage](docs/Gcs.md)
  * [Azure](docs/Azure.md)
  * [GitHub Actions](docs/GHA.md)
  * [WebDAV (Ccache/Bazel/Gradle compatible)](docs/Webdav.md)
  * [Alibaba OSS](docs/OSS.md)
  * [Tencent Cloud Object Storage](docs/COS.md)

---

## Installation

There are prebuilt x86-64 binaries available for Windows, Linux (a portable binary compiled against musl), and macOS [on the releases page](https://github.com/mozilla/sccache/releases/latest). Several package managers also include sccache packages, you can install the latest release from source using cargo, or build directly from a source checkout.

### macOS

On macOS sccache can be installed via [Homebrew](https://brew.sh/):

```bash
brew install sccache
```

or via [MacPorts](https://www.macports.org/):

```bash
sudo port install sccache
```

### Windows

On Windows, sccache can be installed via [scoop](https://scoop.sh/):

```
scoop install sccache
```
or `winget`:

```
winget install Mozilla.sccache
```

### Via cargo

If you have a Rust toolchain installed you can install sccache using cargo. **Note that this will compile sccache from source which is fairly resource-intensive. For CI purposes you should use prebuilt binary packages.**


```bash
cargo install sccache --locked
```

### With Nix

Sccache is available in nixpkgs, so if you don't need the latest version you can use that:

```nix
buildInputs = [ pkgs.sccache ];
```

We also provide a flake with an overlay for getting the latest version:

```nix
{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    sccache = {
      url = "github:mozilla/sccache";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { self, nixpkgs, sccache, ... }:
    let
      system = "x86_64-linux";
      pkgs = import nixpkgs {
        inherit system;
        overlays = [ sccache.overlays.default ];
      };
    in {
      devShells.${system}.default = pkgs.mkShell {
        buildInputs = [ pkgs.sccache ];
      };
    };
}
```

Or use it directly from the flake without the overlay:

```bash
nix run github:mozilla/sccache -- --help
nix shell github:mozilla/sccache
```

---

Usage
-----

Running sccache is like running ccache: prefix your compilation commands with it, like so:

```bash
sccache gcc -o foo.o -c foo.c
```

If you want to use sccache for caching Rust builds you can define `build.rustc-wrapper` in the
[cargo configuration file](https://doc.rust-lang.org/cargo/reference/config.html).  For example, you can set it globally
in `$HOME/.cargo/config.toml` by adding:

```toml
[build]
rustc-wrapper = "/path/to/sccache"
```

Note that you need to use cargo 1.40 or newer for this to work.

Alternatively you can use the environment variable `RUSTC_WRAPPER`:

```bash
export RUSTC_WRAPPER=/path/to/sccache
cargo build
```

sccache supports gcc, clang, MSVC, rustc, [NVCC](https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html), [NVC++](https://docs.nvidia.com/hpc-sdk//compilers/hpc-compilers-user-guide/index.html), [hipcc](https://rocm.docs.amd.com/projects/HIP/en/latest/index.html), and [Wind River's diab compiler](https://www.windriver.com/products/development-tools/#diab_compiler). Both gcc and msvc support Response Files, read more about their implementation [here](docs/ResponseFiles.md).

If you don't [specify otherwise](#storage-options), sccache will use a local disk cache.

sccache works using a client-server model, where the server runs locally on the same machine as the client. The client-server model allows the server to be more efficient by keeping some state in memory. The sccache command will spawn a server process if one is not already running, or you can run `sccache --start-server` to start the background server process without performing any compilation.

By default sccache server will listen on `127.0.0.1:4226`, you can specify environment variable `SCCACHE_SERVER_PORT` to use a different port or `SCCACHE_SERVER_UDS` to listen on unix domain socket. Abstract unix socket is also supported as long as the path is escaped following the [format](https://doc.rust-lang.org/std/ascii/fn.escape_default.html). For example:

```
% env SCCACHE_SERVER_UDS=$HOME/sccache.sock sccache --start-server # unix socket
% env SCCACHE_SERVER_UDS=\\x00sccache.sock sccache --start-server # abstract unix socket
```

You can run `sccache --stop-server` to terminate the server. It will also terminate after (by default) 10 minutes of inactivity.

Running `sccache --show-stats` will print a summary of cache statistics.

Some notes about using `sccache` with [Jenkins](https://jenkins.io) are [here](docs/Jenkins.md).

To use sccache with cmake, provide the following command line arguments to cmake 3.4 or newer:

```
-DCMAKE_C_COMPILER_LAUNCHER=sccache
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache
```

The process for using sccache with MSVC and cmake, depends on which version of cmake you're using. **For versions of cmake 3.24 and earlier**, to generate PDB files for debugging with MSVC, you can use the [`/Z7` option](https://docs.microsoft.com/en-us/cpp/build/reference/z7-zi-zi-debug-information-format?view=msvc-160). Alternatively, the `/Zi` option together with `/Fd` can work if `/Fd` names a different PDB file name for each object file created. Note that CMake sets `/Zi` by default, so if you use CMake, you can use `/Z7` by adding code like this in your CMakeLists.txt:

```cmake
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
  string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
  string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
  string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
  string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
  string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
  string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
endif()
```

By default, sccache will fail your build if it fails to successfully communicate with its associated server. To have sccache instead gracefully failover to the local compiler without stopping, set the environment variable `SCCACHE_IGNORE_SERVER_IO_ERROR=1`.

**For versions of cmake 3.25 and later**, to compile with MSVC, you have to use the new `CMAKE_MSVC_DEBUG_INFORMATION_FORMAT` option, meant to configure the `-Z7` flag.  Additionally, you must set the cmake policy number 0141 to the NEW setting:
```cmake
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:Embedded>")
cmake_policy(SET CMP0141 NEW)
```

Example configuration where we automatically look for `sccache` in the `PATH`:
```cmake
find_program(SCCACHE sccache REQUIRED)

set(CMAKE_C_COMPILER_LAUNCHER ${SCCACHE})
set(CMAKE_CXX_COMPILER_LAUNCHER ${SCCACHE})
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:Embedded>")
cmake_policy(SET CMP0141 NEW)
```

Alternatively, if configuring cmake with MSVC on the command line, assuming that sccache is on the default search path:

```
cmake -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=Embedded -DCMAKE_POLICY_CMP0141=NEW [...]
```

And you can build code as usual without any additional flags in the command line, which is useful for IDEs.


---

Build Requirements
------------------

sccache is a [Rust](https://www.rust-lang.org/) program. Building it requires `cargo` (and thus`rustc`). sccache currently requires **Rust 1.85.0**. We recommend you install Rust via [Rustup](https://rustup.rs/).

Build
-----

If you are building sccache for non-development purposes make sure you use `cargo build --release` to get optimized binaries:

```bash
cargo build --release [--no-default-features --features=s3|redis|gcs|memcached|azure|gha|webdav|oss|cos]
```

The list of features can be found in the `Cargo.toml` file, `[features]` section.

By default, `sccache` builds with support for all storage backends, but individual backends may be disabled by resetting the list of features and enabling all the other backends. Refer the [Cargo Documentation](http://doc.crates.io/manifest.html#the-features-section) for details on how to select features with Cargo.

### Building portable binaries

When building with the `dist-server` feature, `sccache` will depend on OpenSSL, which can be an annoyance if you want to distribute portable binaries. It is possible to statically link against OpenSSL using the `openssl/vendored` feature.

#### Linux

Build with `cargo` and use `ldd` to check that the resulting binary does not depend on OpenSSL anymore.

#### macOS

Build with `cargo` and use `otool -L` to check that the resulting binary does not depend on OpenSSL anymore.

#### Windows

On Windows, the binary might also depend on a few MSVC CRT DLLs that are not available on older Windows versions.

It is possible to statically link against the CRT using a `.cargo/config.toml` file with the following contents.

```toml
[target.x86_64-pc-windows-msvc]
rustflags = ["-Ctarget-feature=+crt-static"]
```

Build with `cargo` and use `dumpbin /dependents` to check that the resulting binary does not depend on MSVC CRT DLLs anymore.

When statically linking with OpenSSL, you will need Perl available in your `$PATH`.

---

Separating caches between invocations
-------------------------------------

In situations where several different compilation invocations
should not reuse the cached results from each other,
one can set `SCCACHE_C_CUSTOM_CACHE_BUSTER` to a unique value
that'll be mixed into the hash.
`MACOSX_DEPLOYMENT_TARGET` and `IPHONEOS_DEPLOYMENT_TARGET` variables
already exhibit such reuse-suppression behaviour.
There are currently no such variables for compiling Rust.

---

Overwriting the cache
---------------------

In situations where the cache contains broken build artifacts, it can be necessary to overwrite the contents in the cache. That can be achieved by setting the `SCCACHE_RECACHE` environment variable.

---

Debugging
---------

You can set the `SCCACHE_ERROR_LOG` environment variable to a path and set `SCCACHE_LOG` to get the server process to redirect its logging there (including the output of unhandled panics, since the server sets `RUST_BACKTRACE=1` internally).

    SCCACHE_ERROR_LOG=/tmp/sccache_log.txt SCCACHE_LOG=debug sccache

You can also set these environment variables for your build system, for example

    SCCACHE_ERROR_LOG=/tmp/sccache_log.txt SCCACHE_LOG=debug cmake --build /path/to/cmake/build/directory

Alternatively, if you are compiling locally, you can run the server manually in foreground mode by running `SCCACHE_START_SERVER=1 SCCACHE_NO_DAEMON=1 sccache`, and send logging to stderr by setting the [`SCCACHE_LOG` environment variable](https://docs.rs/env_logger/0.7.1/env_logger/#enabling-logging) for example. This method is not suitable for CI services because you need to compile in another shell at the same time.

    SCCACHE_LOG=debug SCCACHE_START_SERVER=1 SCCACHE_NO_DAEMON=1 sccache

---

Interaction with GNU `make` jobserver
-------------------------------------

sccache provides support for a [GNU make jobserver](https://www.gnu.org/software/make/manual/html_node/Job-Slots.html). When the server is started from a process that provides a jobserver, sccache will use that jobserver and provide it to any processes it spawns. (If you are running sccache from a GNU make recipe, you will need to prefix the command with `+` to get this behavior.) If the sccache server is started without a jobserver present it will create its own with the number of slots equal to the number of available CPU cores.

This is most useful when using sccache for Rust compilation, as rustc supports using a jobserver for parallel codegen, so this ensures that rustc will not overwhelm the system with codegen tasks. Cargo implements its own jobserver ([see the information on `NUM_JOBS` in the cargo documentation](https://doc.rust-lang.org/stable/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts)) for rustc to use, so using sccache for Rust compilation in cargo via `RUSTC_WRAPPER` should do the right thing automatically.

---

Normalizing Paths with `SCCACHE_BASEDIRS`
-----------------------------------------

By default, sccache requires absolute paths to match for cache hits. To enable cache sharing across different build directories, you can set `SCCACHE_BASEDIRS` to strip a base directory from paths before hashing:

```bash
export SCCACHE_BASEDIRS=/home/user/project
```

You can also specify multiple base directories by separating them by `;` on Windows hosts and by `:` on any other operating system. When multiple directories are provided, the longest matching prefix is used:

```bash
export SCCACHE_BASEDIRS="/home/user/project:/home/user/workspace"
```

Path matching is **case-insensitive** on Windows and **case-sensitive** on other operating systems.

This is similar to ccache's `CCACHE_BASEDIR` and helps when:
* Building the same project from different directories
* Sharing cache between CI jobs with different checkout paths
* Multiple developers working with different username paths
* Working with multiple project checkouts simultaneously

**Note:** Only absolute paths are supported. Relative paths will prevent server from starting.

You can also configure this in the sccache config file:

```toml
# Single directory
basedirs = ["/home/user/project"]

# Or multiple directories
basedirs = ["/home/user/project", "/home/user/workspace"]
```

---

Known Caveats
-------------

### General

* By default, absolute paths to files must match to get a cache hit. To work around this, use `SCCACHE_BASEDIRS` (see above) to normalize paths before hashing.

### Rust

* Crates that invoke the system linker cannot be cached. This includes `bin`, `dylib`, `cdylib`, and `proc-macro` crates. You may be able to improve compilation time of large `bin` crates by converting them to a `lib` crate with a thin `bin` wrapper.
* Incrementally compiled crates cannot be cached. By default, in the debug profile Cargo will use incremental compilation for workspace members and path dependencies. [You can disable incremental compilation.](https://doc.rust-lang.org/cargo/reference/profiles.html#incremental)

[More details on Rust caveats](/docs/Rust.md)

### C++20 Modules

sccache has partial support for C++20 named modules when using **Clang**. The following flags are supported:

* `-fmodule-file=<path>` and `-fmodule-file=<name>=<path>` - importing precompiled module interfaces
* `-fmodule-output=<path>` - generating module interface output alongside object files
* `--precompile` - compiling module interface units
* `-fmodules-reduced-bmi` - generating reduced BMI files

The following module-related flags are **not supported** and will bypass the cache:

* `-fmodules` and `-fcxx-modules` - Clang header modules (not C++20 named modules)
* `-fprebuilt-implicit-modules` and `-fprebuilt-module-path` - implicit module discovery

**GCC** and **MSVC** C++20 modules are not yet supported. Compilations using `-fmodules-ts` (GCC) or `/interface`, `/ifcOutput`, etc. (MSVC) will bypass the cache.

### User Agent

* Requests sent to your storage option of choice will have a user agent header indicating the current sccache version, e.g. `sccache/0.8.2`.

Storage Options
---------------

* [Local](docs/Local.md)
* [S3](docs/S3.md)
* [R2](docs/S3.md#R2)
* [Redis](docs/Redis.md)
* [Memcached](docs/Memcached.md)
* [Google Cloud Storage](docs/Gcs.md)
* [Azure](docs/Azure.md)
* [GitHub Actions](docs/GHA.md)
* [WebDAV (Ccache/Bazel/Gradle compatible)](docs/Webdav.md)
* [Alibaba OSS](docs/OSS.md)
* [Tencent Cloud Object Storage](docs/COS.md)


================================================
FILE: benches/sccache_bench.rs
================================================
// Copyright 2025 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Benchmarks for sccache's performance-critical operations.
//!
//! These benchmarks focus on the key operations that affect cache performance:
//! - Hash computation (BLAKE3) for cache keys
//! - Time macro detection for preprocessor cache mode
//! - LRU cache operations

use divan::{Bencher, black_box};
use sccache::cache::{CacheRead, CacheWrite};
use sccache::lru_disk_cache::LruCache;
use sccache::util::{Digest, TimeMacroFinder, normalize_win_path, strip_basedirs};
use std::io::Cursor;

// =============================================================================
// Helper Functions
// =============================================================================

/// Generate test data of specified size
fn generate_test_data(size: usize) -> Vec<u8> {
    let mut data = Vec::with_capacity(size);
    let pattern = b"int main() { return 0; }\n";
    while data.len() < size {
        let remaining = size - data.len();
        let to_copy = remaining.min(pattern.len());
        data.extend_from_slice(&pattern[..to_copy]);
    }
    data
}

/// Generate preprocessor output with C code patterns
fn generate_preprocessor_output(num_lines: usize) -> Vec<u8> {
    let mut data = Vec::new();
    let code_lines = [
        "#include <stdio.h>\n",
        "int variable_name_123 = 42;\n",
        "void function_call(int x, int y) {\n",
        "    return x + y;\n",
        "}\n",
        "// This is a comment line\n",
        "#define MACRO_NAME value\n",
        "struct MyStruct { int field; };\n",
        "extern \"C\" void c_function();\n",
        "template<typename T> class Container {};\n",
    ];

    for i in 0..num_lines {
        let line = code_lines[i % code_lines.len()];
        data.extend_from_slice(line.as_bytes());
    }
    data
}

/// Generate data with time macros embedded
fn generate_data_with_time_macros(size: usize) -> Vec<u8> {
    let mut data = Vec::with_capacity(size);
    let pattern = b"const char* build_time = __TIME__;\nconst char* build_date = __DATE__;\n";

    while data.len() < size {
        let remaining = size - data.len();
        let to_copy = remaining.min(pattern.len());
        data.extend_from_slice(&pattern[..to_copy]);
    }
    data
}

// =============================================================================
// Hash Computation Benchmarks
// =============================================================================

/// Benchmark hashing large data (typical preprocessor output ~4MB)
#[divan::bench]
fn hash_large_data(bencher: Bencher) {
    let data = generate_test_data(4 * 1024 * 1024); // 4MB

    bencher.bench(|| {
        let cursor = Cursor::new(black_box(&data));
        black_box(Digest::reader_sync(cursor).unwrap())
    });
}

// =============================================================================
// Time Macro Finder Benchmarks
// =============================================================================

/// Benchmark time macro detection on data without macros (~1MB)
#[divan::bench]
fn time_macro_finder_no_macros(bencher: Bencher) {
    let data = generate_test_data(1024 * 1024); // 1MB

    bencher.bench(|| {
        let cursor = Cursor::new(black_box(&data));
        black_box(Digest::reader_sync_time_macros(cursor).unwrap())
    });
}

/// Benchmark time macro detection on data with __TIME__ and __DATE__
#[divan::bench]
fn time_macro_finder_with_macros(bencher: Bencher) {
    let data = generate_data_with_time_macros(1024 * 1024); // 1MB

    bencher.bench(|| {
        let cursor = Cursor::new(black_box(&data));
        black_box(Digest::reader_sync_time_macros(cursor).unwrap())
    });
}

/// Benchmark TimeMacroFinder with chunked input (simulates real file reading)
#[divan::bench]
fn time_macro_finder_chunked(bencher: Bencher) {
    let chunk_size = 128 * 1024;
    let total_size = chunk_size * 8; // 1MB total
    let data = generate_test_data(total_size);

    bencher.bench(|| {
        let mut finder = TimeMacroFinder::new();
        for chunk in data.chunks(chunk_size) {
            finder.find_time_macros(black_box(chunk));
        }
        black_box(finder.found_time_macros())
    });
}

// =============================================================================
// LRU Cache Benchmarks
// =============================================================================

/// Benchmark LRU cache insertions
#[divan::bench]
fn lru_cache_insert(bencher: Bencher) {
    let num_entries = 5000;

    bencher
        .with_inputs(|| {
            let cache: LruCache<String, u64> = LruCache::new(num_entries as u64 * 2);
            let keys: Vec<String> = (0..num_entries).map(|i| format!("key_{:08x}", i)).collect();
            (cache, keys)
        })
        .bench_values(|(mut cache, keys)| {
            for (i, key) in keys.into_iter().enumerate() {
                cache.insert(key, i as u64);
            }
            black_box(cache)
        });
}

/// Benchmark LRU cache lookups (cache hits)
#[divan::bench]
fn lru_cache_get_hit(bencher: Bencher) {
    let num_entries = 5000;
    let keys: Vec<String> = (0..num_entries).map(|i| format!("key_{:08x}", i)).collect();

    bencher
        .with_inputs(|| {
            let mut cache: LruCache<String, u64> = LruCache::new(num_entries as u64 * 2);
            for (i, key) in keys.iter().enumerate() {
                cache.insert(key.clone(), i as u64);
            }
            cache
        })
        .bench_values(|mut cache| {
            for key in &keys {
                black_box(cache.get(key));
            }
            black_box(cache)
        });
}

/// Benchmark LRU cache eviction under pressure
#[divan::bench]
fn lru_cache_eviction(bencher: Bencher) {
    let cache_size = 2000;

    bencher
        .with_inputs(|| {
            let cache: LruCache<String, u64> = LruCache::new(cache_size as u64);
            // Generate more keys than cache can hold
            let keys: Vec<String> = (0..cache_size * 3)
                .map(|i| format!("key_{:08x}", i))
                .collect();
            (cache, keys)
        })
        .bench_values(|(mut cache, keys)| {
            for (i, key) in keys.into_iter().enumerate() {
                cache.insert(key, i as u64);
            }
            black_box(cache)
        });
}

/// Benchmark LRU cache mixed workload (insert, get, remove)
#[divan::bench]
fn lru_cache_mixed_workload(bencher: Bencher) {
    let num_ops = 3000;

    bencher
        .with_inputs(|| {
            let cache: LruCache<String, u64> = LruCache::new(num_ops as u64);
            let keys: Vec<String> = (0..num_ops).map(|i| format!("key_{:08x}", i)).collect();
            (cache, keys)
        })
        .bench_values(|(mut cache, keys)| {
            // Insert half
            for (i, key) in keys.iter().take(num_ops / 2).enumerate() {
                cache.insert(key.clone(), i as u64);
            }
            // Get some
            for key in keys.iter().take(num_ops / 4) {
                black_box(cache.get(key));
            }
            // Remove some
            for key in keys.iter().take(num_ops / 8) {
                cache.remove(key);
            }
            // Insert more
            for (i, key) in keys.iter().skip(num_ops / 2).enumerate() {
                cache.insert(key.clone(), i as u64);
            }
            black_box(cache)
        });
}

// =============================================================================
// Cache Key Generation Benchmark
// =============================================================================

/// Simulate the hash_key function behavior
fn simulate_hash_key(
    compiler_digest: &str,
    language: &str,
    arguments: &[&str],
    extra_hashes: &[&str],
    env_vars: &[(&str, &str)],
    preprocessor_output: &[u8],
    plusplus: bool,
) -> String {
    let mut m = Digest::new();
    m.update(compiler_digest.as_bytes());
    m.update(&[plusplus as u8]);
    m.update(b"1"); // CACHE_VERSION simulation
    m.update(language.as_bytes());

    for arg in arguments {
        m.update(arg.as_bytes());
    }

    for hash in extra_hashes {
        m.update(hash.as_bytes());
    }

    for (var, val) in env_vars {
        m.update(var.as_bytes());
        m.update(b"=");
        m.update(val.as_bytes());
    }

    m.update(preprocessor_output);
    m.finish()
}

/// Benchmark cache key generation with typical C++ compilation
#[divan::bench]
fn cache_key_generation(bencher: Bencher) {
    let compiler_digest = "abc123def456789012345678901234567890123456789012345678901234";
    let language = "c++";
    let arguments = vec![
        "-O2",
        "-Wall",
        "-Wextra",
        "-I/usr/include",
        "-I/usr/local/include",
        "-I/usr/include/c++/11",
        "-DNDEBUG",
        "-std=c++17",
        "-fPIC",
        "-march=native",
        "-mtune=native",
        "-fno-exceptions",
        "-fno-rtti",
    ];
    let extra_hashes = vec!["pch_hash_abc123", "module_hash_def456"];
    let env_vars = vec![
        ("LANG", "en_US.UTF-8"),
        ("LC_ALL", "C"),
        ("CPLUS_INCLUDE_PATH", "/opt/custom/include"),
    ];
    let preprocessor_output = generate_preprocessor_output(2000); // ~100KB

    bencher.bench(|| {
        black_box(simulate_hash_key(
            compiler_digest,
            language,
            &arguments,
            &extra_hashes,
            &env_vars,
            &preprocessor_output,
            true,
        ))
    });
}

// =============================================================================
// Cache Artifact Serialization Benchmarks
// =============================================================================

/// Generate realistic object file data
fn generate_object_file(size: usize) -> Vec<u8> {
    // Simulate binary object file with varied byte patterns
    let mut data = Vec::with_capacity(size);
    for i in 0..size {
        data.push(((i * 7) % 256) as u8);
    }
    data
}

/// Benchmark creating a cache entry with typical compilation artifacts
#[divan::bench]
fn cache_entry_create_small(bencher: Bencher) {
    let obj_data = generate_object_file(50 * 1024); // 50KB object file
    let stdout_data = b"compilation successful\n";
    let stderr_data = b"";

    bencher.bench(|| {
        let mut entry = CacheWrite::new();
        let mut cursor = Cursor::new(black_box(&obj_data));
        entry
            .put_object("output.o", &mut cursor, Some(0o644))
            .unwrap();
        entry.put_stdout(black_box(stdout_data)).unwrap();
        entry.put_stderr(black_box(stderr_data)).unwrap();
        black_box(entry)
    });
}

/// Benchmark creating a cache entry with larger artifacts
#[divan::bench]
fn cache_entry_create_large(bencher: Bencher) {
    let obj_data = generate_object_file(2 * 1024 * 1024); // 2MB object file
    let stdout_data = b"compilation successful\n";
    let stderr_data = b"warning: unused variable\n";

    bencher.bench(|| {
        let mut entry = CacheWrite::new();
        let mut cursor = Cursor::new(black_box(&obj_data));
        entry
            .put_object("output.o", &mut cursor, Some(0o644))
            .unwrap();
        entry.put_stdout(black_box(stdout_data)).unwrap();
        entry.put_stderr(black_box(stderr_data)).unwrap();
        black_box(entry)
    });
}

/// Benchmark cache entry round-trip (write → finish → read)
#[divan::bench]
fn cache_entry_roundtrip_small(bencher: Bencher) {
    let obj_data = generate_object_file(100 * 1024); // 100KB

    bencher.bench(|| {
        // Create and finish entry
        let mut entry = CacheWrite::new();
        let mut cursor = Cursor::new(black_box(&obj_data));
        entry
            .put_object("output.o", &mut cursor, Some(0o644))
            .unwrap();
        entry.put_stdout(b"success\n").unwrap();
        let bytes = entry.finish().unwrap();

        // Read it back
        let cursor = Cursor::new(bytes);
        let mut reader = CacheRead::from(cursor).unwrap();
        let mut output = Vec::new();
        reader.get_object("output.o", &mut output).unwrap();
        let stdout = reader.get_stdout();
        black_box((output, stdout))
    });
}

/// Benchmark cache entry round-trip with larger data
#[divan::bench]
fn cache_entry_roundtrip_large(bencher: Bencher) {
    let obj_data = generate_object_file(1024 * 1024); // 1MB

    bencher.bench(|| {
        // Create and finish entry
        let mut entry = CacheWrite::new();
        let mut cursor = Cursor::new(black_box(&obj_data));
        entry
            .put_object("output.o", &mut cursor, Some(0o644))
            .unwrap();
        entry.put_stdout(b"compilation successful\n").unwrap();
        entry.put_stderr(b"warning: something\n").unwrap();
        let bytes = entry.finish().unwrap();

        // Read it back
        let cursor = Cursor::new(bytes);
        let mut reader = CacheRead::from(cursor).unwrap();
        let mut output = Vec::new();
        reader.get_object("output.o", &mut output).unwrap();
        let stdout = reader.get_stdout();
        let stderr = reader.get_stderr();
        black_box((output, stdout, stderr))
    });
}

/// Benchmark creating multiple cache entries (simulates multi-file compilation)
#[divan::bench]
fn cache_entry_batch_create(bencher: Bencher) {
    // Simulate compiling 50 small files
    let num_files = 50;
    let obj_data = generate_object_file(30 * 1024); // 30KB each

    bencher.bench(|| {
        for i in 0..num_files {
            let mut entry = CacheWrite::new();
            let mut cursor = Cursor::new(black_box(&obj_data));
            entry
                .put_object(&format!("output{}.o", i), &mut cursor, Some(0o644))
                .unwrap();
            entry.put_stdout(b"success\n").unwrap();
            let _bytes = entry.finish().unwrap();
            black_box(_bytes);
        }
    });
}

/// Benchmark full round-trip for multiple cache entries
#[divan::bench]
fn cache_entry_batch_roundtrip(bencher: Bencher) {
    // Simulate cache miss then cache hit for 20 files
    let num_files = 20;
    let obj_data = generate_object_file(50 * 1024); // 50KB each

    bencher.bench(|| {
        let mut entries_data: Vec<Vec<u8>> = Vec::new();

        // Cache miss: create all entries
        for i in 0..num_files {
            let mut entry = CacheWrite::new();
            let mut cursor = Cursor::new(black_box(&obj_data));
            entry
                .put_object(&format!("output{}.o", i), &mut cursor, Some(0o644))
                .unwrap();
            entry.put_stdout(b"success\n").unwrap();
            entries_data.push(entry.finish().unwrap());
        }

        // Cache hit: read all entries back
        for (i, bytes) in entries_data.into_iter().enumerate() {
            let cursor = Cursor::new(bytes);
            let mut reader = CacheRead::from(cursor).unwrap();
            let mut output = Vec::new();
            reader
                .get_object(&format!("output{}.o", i), &mut output)
                .unwrap();
            black_box(output);
        }
    });
}

// =============================================================================
// Hash Computation Scenarios Benchmarks
// =============================================================================

/// Benchmark hashing typical header file content
#[divan::bench]
fn hash_header_file(bencher: Bencher) {
    // Simulate a typical header file (~50KB)
    let header_content = generate_preprocessor_output(1000); // ~50KB

    bencher.bench(|| {
        let cursor = Cursor::new(black_box(&header_content));
        black_box(Digest::reader_sync(cursor).unwrap())
    });
}

/// Benchmark hashing multiple input files (parallel compilation simulation)
#[divan::bench]
fn hash_multiple_files(bencher: Bencher) {
    // Simulate hashing 10 different source files
    let files: Vec<Vec<u8>> = (0..10)
        .map(|i| {
            let mut data = generate_preprocessor_output(200); // ~10KB each
            data.extend_from_slice(format!("// File {}\n", i).as_bytes());
            data
        })
        .collect();

    bencher.bench(|| {
        for file_data in &files {
            let cursor = Cursor::new(black_box(file_data));
            black_box(Digest::reader_sync(cursor).unwrap());
        }
    });
}

// =============================================================================
// Build Workflow Simulation Benchmarks
// =============================================================================

/// Benchmark initial build (all cache misses)
#[divan::bench]
fn build_workflow_initial(bencher: Bencher) {
    // Simulate initial build of 30 files
    let num_files = 30;
    let obj_data = generate_object_file(40 * 1024); // 40KB each

    bencher.bench(|| {
        for i in 0..num_files {
            // Hash compiler + flags + source
            let mut digest = Digest::new();
            digest.update(b"gcc-11.2.0");
            digest.update(b"-O2");
            digest.update(format!("source_{}.c", i).as_bytes());
            let _key = digest.finish();

            // Create cache entry
            let mut entry = CacheWrite::new();
            let mut cursor = Cursor::new(black_box(&obj_data));
            entry
                .put_object(&format!("output{}.o", i), &mut cursor, Some(0o644))
                .unwrap();
            entry.put_stdout(b"success\n").unwrap();
            let _bytes = entry.finish().unwrap();
            black_box(_bytes);
        }
    });
}

/// Benchmark full rebuild (all cache hits)
#[divan::bench]
fn build_workflow_rebuild(bencher: Bencher) {
    // Simulate rebuild where all files are cached
    let num_files = 30;
    let obj_data = generate_object_file(40 * 1024);

    // Pre-create cache entries
    let cache_entries: Vec<Vec<u8>> = (0..num_files)
        .map(|i| {
            let mut entry = CacheWrite::new();
            let mut cursor = Cursor::new(&obj_data);
            entry
                .put_object(&format!("output{}.o", i), &mut cursor, Some(0o644))
                .unwrap();
            entry.put_stdout(b"success\n").unwrap();
            entry.finish().unwrap()
        })
        .collect();

    bencher.bench(|| {
        for (i, cached_bytes) in cache_entries.iter().enumerate() {
            // Hash compiler + flags + source (same as before)
            let mut digest = Digest::new();
            digest.update(b"gcc-11.2.0");
            digest.update(b"-O2");
            digest.update(format!("source_{}.c", i).as_bytes());
            let _key = digest.finish();

            // Retrieve from cache
            let cursor = Cursor::new(cached_bytes.clone());
            let mut reader = CacheRead::from(cursor).unwrap();
            let mut output = Vec::new();
            reader
                .get_object(&format!("output{}.o", i), &mut output)
                .unwrap();
            black_box(output);
        }
    });
}

/// Benchmark incremental build (90% hits, 10% misses)
#[divan::bench]
fn build_workflow_incremental(bencher: Bencher) {
    let num_files = 30;
    let changed_files = 3; // 10% of files changed
    let obj_data = generate_object_file(40 * 1024);

    // Pre-create cache entries for unchanged files
    let cache_entries: Vec<Vec<u8>> = (0..num_files)
        .map(|i| {
            let mut entry = CacheWrite::new();
            let mut cursor = Cursor::new(&obj_data);
            entry
                .put_object(&format!("output{}.o", i), &mut cursor, Some(0o644))
                .unwrap();
            entry.put_stdout(b"success\n").unwrap();
            entry.finish().unwrap()
        })
        .collect();

    bencher.bench(|| {
        for (i, cache_entry) in cache_entries.iter().enumerate() {
            // Hash compiler + flags + source
            let mut digest = Digest::new();
            digest.update(b"gcc-11.2.0");
            digest.update(b"-O2");
            digest.update(format!("source_{}.c", i).as_bytes());
            let _key = digest.finish();

            if i < changed_files {
                // Cache miss: recompile
                let mut entry = CacheWrite::new();
                let mut cursor = Cursor::new(black_box(&obj_data));
                entry
                    .put_object(&format!("output{}.o", i), &mut cursor, Some(0o644))
                    .unwrap();
                entry.put_stdout(b"success\n").unwrap();
                let _bytes = entry.finish().unwrap();
                black_box(_bytes);
            } else {
                // Cache hit: retrieve
                let cursor = Cursor::new(cache_entry.clone());
                let mut reader = CacheRead::from(cursor).unwrap();
                let mut output = Vec::new();
                reader
                    .get_object(&format!("output{}.o", i), &mut output)
                    .unwrap();
                black_box(output);
            }
        }
    });
}

// =============================================================================
// Compression Characteristics Benchmarks
// =============================================================================

/// Generate highly compressible data (simulates debug builds with padding)
fn generate_compressible_data(size: usize) -> Vec<u8> {
    let mut data = Vec::with_capacity(size);
    let pattern = b"\x00\x00\x00\x00\x90\x90\x90\x90"; // Common in binaries
    while data.len() < size {
        data.extend_from_slice(pattern);
    }
    data.truncate(size);
    data
}

/// Generate incompressible data (simulates optimized builds)
fn generate_incompressible_data(size: usize) -> Vec<u8> {
    let mut data = Vec::with_capacity(size);
    for i in 0..size {
        // Use a more varied pattern that compresses poorly
        data.push(((i * 31 + i / 7) % 256) as u8);
    }
    data
}

/// Benchmark cache entry with highly compressible data
#[divan::bench]
fn compression_high_compressibility(bencher: Bencher) {
    let obj_data = generate_compressible_data(500 * 1024); // 500KB

    bencher.bench(|| {
        let mut entry = CacheWrite::new();
        let mut cursor = Cursor::new(black_box(&obj_data));
        entry
            .put_object("output.o", &mut cursor, Some(0o644))
            .unwrap();
        entry.put_stdout(b"success\n").unwrap();
        black_box(entry.finish().unwrap())
    });
}

/// Benchmark cache entry with incompressible data
#[divan::bench]
fn compression_low_compressibility(bencher: Bencher) {
    let obj_data = generate_incompressible_data(500 * 1024); // 500KB

    bencher.bench(|| {
        let mut entry = CacheWrite::new();
        let mut cursor = Cursor::new(black_box(&obj_data));
        entry
            .put_object("output.o", &mut cursor, Some(0o644))
            .unwrap();
        entry.put_stdout(b"success\n").unwrap();
        black_box(entry.finish().unwrap())
    });
}

/// Benchmark decompression of highly compressed data
#[divan::bench]
fn decompression_high_ratio(bencher: Bencher) {
    let obj_data = generate_compressible_data(500 * 1024);

    // Pre-create compressed entry
    let mut entry = CacheWrite::new();
    let mut cursor = Cursor::new(&obj_data);
    entry
        .put_object("output.o", &mut cursor, Some(0o644))
        .unwrap();
    let compressed = entry.finish().unwrap();

    bencher.bench(|| {
        let cursor = Cursor::new(black_box(compressed.clone()));
        let mut reader = CacheRead::from(cursor).unwrap();
        let mut output = Vec::new();
        reader.get_object("output.o", &mut output).unwrap();
        black_box(output)
    });
}

/// Benchmark decompression of low-ratio compressed data
#[divan::bench]
fn decompression_low_ratio(bencher: Bencher) {
    let obj_data = generate_incompressible_data(500 * 1024);

    // Pre-create compressed entry
    let mut entry = CacheWrite::new();
    let mut cursor = Cursor::new(&obj_data);
    entry
        .put_object("output.o", &mut cursor, Some(0o644))
        .unwrap();
    let compressed = entry.finish().unwrap();

    bencher.bench(|| {
        let cursor = Cursor::new(black_box(compressed.clone()));
        let mut reader = CacheRead::from(cursor).unwrap();
        let mut output = Vec::new();
        reader.get_object("output.o", &mut output).unwrap();
        black_box(output)
    });
}

// =============================================================================
// Realistic LRU Cache Access Pattern Benchmarks
// =============================================================================

/// Benchmark LRU cache with hot/cold access pattern (80/20 rule)
#[divan::bench]
fn lru_hotcold_access_pattern(bencher: Bencher) {
    let total_keys = 1000;
    let hot_keys = 200; // 20% of keys get 80% of accesses

    bencher
        .with_inputs(|| {
            let mut cache: LruCache<String, u64> = LruCache::new((total_keys * 2) as u64);
            // Populate cache
            for i in 0..total_keys {
                cache.insert(format!("key_{:08x}", i), i as u64);
            }
            let keys: Vec<String> = (0..total_keys).map(|i| format!("key_{:08x}", i)).collect();
            (cache, keys)
        })
        .bench_values(|(mut cache, keys)| {
            // Access pattern: 80% accesses to 20% of keys
            for i in 0..400 {
                let key_idx = if i % 5 < 4 {
                    // 80% of the time, access hot keys
                    i % hot_keys
                } else {
                    // 20% of the time, access cold keys
                    hot_keys + (i % (total_keys - hot_keys))
                };
                black_box(cache.get(&keys[key_idx]));
            }
            black_box(cache)
        });
}

/// Benchmark LRU cache with sequential scan pattern
#[divan::bench]
fn lru_sequential_scan_pattern(bencher: Bencher) {
    let num_keys = 1500;

    bencher
        .with_inputs(|| {
            let mut cache: LruCache<String, u64> = LruCache::new((num_keys * 2) as u64);
            for i in 0..num_keys {
                cache.insert(format!("key_{:08x}", i), i as u64);
            }
            let keys: Vec<String> = (0..num_keys).map(|i| format!("key_{:08x}", i)).collect();
            (cache, keys)
        })
        .bench_values(|(mut cache, keys)| {
            // Sequential access pattern (like iterating through all compilation units)
            for key in &keys {
                black_box(cache.get(key));
            }
            black_box(cache)
        });
}

/// Benchmark LRU cache under pressure with realistic eviction
#[divan::bench]
fn lru_realistic_eviction_pressure(bencher: Bencher) {
    let cache_capacity = 500;
    let num_operations = 700; // More than capacity

    bencher
        .with_inputs(|| {
            let cache: LruCache<String, Vec<u8>> = LruCache::new(cache_capacity as u64);
            // Simulate realistic cache entry sizes (10KB each)
            let entry_data = vec![0u8; 10 * 1024];
            (cache, entry_data)
        })
        .bench_values(|(mut cache, entry_data)| {
            // Insert more than capacity, causing evictions
            for i in 0..num_operations {
                cache.insert(format!("key_{:08x}", i), entry_data.clone());
            }
            black_box(cache)
        });
}

// =============================================================================
// Path Normalization Benchmarks
// =============================================================================

/// Generate a realistic Windows path for benchmarking
fn generate_win_path(depth: usize) -> Vec<u8> {
    let mut path = b"C:\\Users\\Developer\\Projects\\".to_vec();
    for i in 0..depth {
        path.extend_from_slice(format!("SubDir{}\\", i).as_bytes());
    }
    path.extend_from_slice(b"source_file.cpp");
    path
}

/// Generate preprocessor output with embedded paths
fn generate_preprocessor_output_with_paths(num_includes: usize, basedir: &[u8]) -> Vec<u8> {
    let mut data = Vec::new();
    for i in 0..num_includes {
        data.extend_from_slice(b"# 1 \"");
        data.extend_from_slice(basedir);
        data.extend_from_slice(format!("src/module{}/file{}.c\"\n", i % 10, i).as_bytes());
        data.extend_from_slice(b"int function_");
        data.extend_from_slice(format!("{}", i).as_bytes());
        data.extend_from_slice(b"() { return 0; }\n");
    }
    data
}

/// Benchmark normalize_win_path with typical path
#[divan::bench]
fn normalize_win_path_typical(bencher: Bencher) {
    let path = generate_win_path(5);

    bencher.bench(|| black_box(normalize_win_path(black_box(&path))));
}

/// Benchmark strip_basedirs with typical preprocessor output
#[divan::bench]
fn strip_basedirs_typical(bencher: Bencher) {
    let basedir = b"/home/user/project/".to_vec();
    let output = generate_preprocessor_output_with_paths(500, &basedir);

    bencher.bench(|| {
        black_box(strip_basedirs(
            black_box(&output),
            black_box(std::slice::from_ref(&basedir)),
        ))
    });
}

/// Benchmark strip_basedirs with multiple basedirs
#[divan::bench]
fn strip_basedirs_multiple(bencher: Bencher) {
    let basedirs = vec![
        b"/home/user/project/".to_vec(),
        b"/usr/include/".to_vec(),
        b"/opt/toolchain/include/".to_vec(),
    ];
    let mut output = Vec::new();
    for i in 0..500 {
        let basedir = &basedirs[i % basedirs.len()];
        output.extend_from_slice(b"# 1 \"");
        output.extend_from_slice(basedir);
        output.extend_from_slice(format!("file{}.h\"\n", i).as_bytes());
    }

    bencher.bench(|| black_box(strip_basedirs(black_box(&output), black_box(&basedirs))));
}

fn main() {
    divan::main();
}


================================================
FILE: docs/Architecture.md
================================================
# Sccache high level architecture

This schema shows at high level how sccache works.


```mermaid
  flowchart LR
      id1[[Environment variables]] --> hash
      id2[[Compiler binary]] --> hash
      id3[[Compiler arguments]] --> hash
      id5[[Files]] --> |  | hash
      Compile --> Upload
      Storage[(Storage)] --> | yes | Download
      hash([hash]) --> | exists? | Storage
      Storage --> | no | Compile
      Upload --> Storage
```


For more details about hash generation works, see [the caching documentation](Caching.md).



================================================
FILE: docs/Azure.md
================================================
# Azure

To use Azure Blob Storage, you'll need your Azure connection string and an _existing_ Blob Storage container name.  Set the `SCCACHE_AZURE_CONNECTION_STRING`
environment variable to your connection string, and `SCCACHE_AZURE_BLOB_CONTAINER` to the name of the container to use.  Note that sccache will not create
the container for you - you'll need to do that yourself.

You can also define a prefix that will be prepended to the keys of all cache objects created and read within the container, effectively creating a scope. To do that use the `SCCACHE_AZURE_KEY_PREFIX` environment variable. This can be useful when sharing a bucket with another application.

**Important:** The environment variables are only taken into account when the server starts, i.e. only on the first run.


================================================
FILE: docs/COS.md
================================================
# COS

If you want to use _Tencent Cloud Object Storage_ (aka COS) for the sccache cache, you need to set the `SCCACHE_COS_BUCKET` environment variable to the name of the COS bucket to use.

You **must** specify the endpoint URL using the `SCCACHE_COS_ENDPOINT` environment variable. More details are at [COS endpoints](https://www.tencentcloud.com/document/product/436/6224).

You can also define a prefix that will be prepended to the keys of all cache objects created and read within the COS bucket, effectively creating a scope. To do that use the `SCCACHE_COS_KEY_PREFIX` environment variable. This can be useful when sharing a bucket with another application.

## Credentials

Sccache is able to load credentials from environment variables: `TENCENTCLOUD_SECRET_ID` and `TENCENTCLOUD_SECRET_KEY`. More details about the access of COS bucket can be found at the [introduction page](https://www.tencentcloud.com/document/product/436/7751).


================================================
FILE: docs/Caching.md
================================================
# How caching works

To know if the storage contains the artifact we need, we are
computing some hashes to make sure the input is the same.

Because the configuration and environment matter, the hash
computation takes a few parameters into account.

## How hash keys are computed.

### Rust

We generate a blake3 digest for each file compiled.
In parallel, we also take into account in the hash:
* Path to the rustc executable
* Host triple for this rustc
* Path to the rustc sysroot
* digests of all the shared libraries in rustc's $sysroot/lib
* A shared, caching reader for rlib dependencies (for dist-client)
* Parsed arguments from the rustc invocation
  
See https://github.com/mozilla/sccache/blob/8567bbe2ba493153e76177c1f9a6f98cc7ba419f/src/compiler/rust.rs#L122 for the full list

### C/C++ compiler

For C/C++, the hash is generated with a blake3 digest of the preprocessed
file (-E with gcc/clang). For compilations that specify multiple `-arch` flags,
these flags are rewritten to their corresponding preprocessor defines to allow
pre-processing the file (e.g `-arch x86_64` is rewritten to `-D__X86_64__=1`),
this can be enabled by setting the environment variable
`SCCACHE_CACHE_MULTIARCH` but is disabled by default as it may not work in all
cases.

We also take into account in the hash:
* Hash of the compiler binary
* Programming language
* Flag required to compile for the given language
* File in which to generate dependencies.
* Commandline arguments for dependency generation
* Commandline arguments for the preprocessor
* Commandline arguments specifying the architecture to compile for
* Extra files that need to have their contents hashed
* Whether the compilation is generating profiling or coverage data
* Color mode
* Environment variables

See https://github.com/mozilla/sccache/blob/8567bbe2ba493153e76177c1f9a6f98cc7ba419f/src/compiler/c.rs#L84

### C/C++ preprocessor

In "preprocessor cache mode", [explained in the local doc](Local.md), an
extra key is computed to cache the preprocessor output itself. It is very close
to the C/C++ compiler one, but with additional elements:

* The path of the input file
* The hash of the input file

Note that some compiler options can disable preprocessor cache mode. As of this
writing, only `-Xpreprocessor` and `-Wp,*` do.


================================================
FILE: docs/Configuration.md
================================================
# Available Configuration Options

## file

```toml
# If specified, wait this long for the server to start up.
server_startup_timeout_ms = 10000

# Base directories to strip from source paths during cache key
# computation.
#
# Similar to ccache's CCACHE_BASEDIR, but supports multiple paths.
#
# 'basedirs' enables cache hits across different absolute root
# paths when compiling the same source code, such as between
# parallel checkouts of the same project, Git worktrees, or different
# users in a shared environment.
# When multiple matching paths are provided, the longest prefix
# is used.
#
# Path matching is case-insensitive on Windows and case-sensitive on other OSes.
#
# Example:
#   basedir = ["/home/user/project"] results in the path prefix rewrite:
#   "/home/user/project/src/main.c" -> "src/main.c"
basedirs = ["/home/user/project"]
# basedirs = ["/home/user/project", "/home/user/workspace"]

[dist]
# where to find the scheduler
scheduler_url = "http://1.2.3.4:10600"
# a set of prepackaged toolchains
toolchains = []
# the maximum size of the toolchain cache in bytes
toolchain_cache_size = 5368709120
cache_dir = "/home/user/.cache/sccache-dist-client"

[dist.auth]
type = "token"
token = "secrettoken"


#[cache.azure]
# Azure Storage connection string (see <https://docs.azure.cn/en-us/storage/common/storage-configure-connection-string>)
connection_string = "BlobEndpoint=https://example.blob.core.windows.net/;SharedAccessSignature=..."
# Name of container
container = "my_container_name"
# Optional string to prepend to each blob storage key
key_prefix = ""

[cache.disk]
dir = "/tmp/.cache/sccache"
size = 7516192768 # 7 GiBytes

# See the local docs on more explanations about this mode
[cache.disk.preprocessor_cache_mode]
# Whether to use the preprocessor cache mode
use_preprocessor_cache_mode = true
# Whether to use file times to check for changes
file_stat_matches = true
# Whether to also use ctime (file status change) time to check for changes
use_ctime_for_stat = true
# Whether to ignore `__TIME__` when caching
ignore_time_macros = false
# Whether to skip (meaning not cache, only hash) system headers
skip_system_headers = false
# Whether hash the current working directory
hash_working_directory = true

[cache.gcs]
# optional oauth url
oauth_url = "..."
# optional deprecated url
deprecated_url = "..."
rw_mode = "READ_ONLY"
# rw_mode = "READ_WRITE"
cred_path = "/psst/secret/cred"
bucket = "bucket"
key_prefix = "prefix"

[cache.gha]
url = "http://localhost"
token = "secret"
cache_to = "sccache-latest"
cache_from = "sccache-"

[cache.memcached]
# Deprecated alias for `endpoint`
# url = "127.0.0.1:11211"
endpoint = "tcp://127.0.0.1:11211"
# Username and password for authentication
username = "user"
password = "passwd"
# Entry expiration time in seconds. Default is 86400 (24 hours)
expiration = 3600
key_prefix = "/custom/prefix/if/need"

[cache.redis]
# Deprecated, use `endpoint` instead
url = "redis://user:passwd@1.2.3.4:6379/?db=1"
## Refer to the `opendal` documentation for more information about Redis endpoint
# Single-node endpoint. Mutually exclusive with `cluster_endpoints`
endpoint = "redis://127.0.0.1:6379"
# Multiple-node list of endpoints (cluster mode). Mutually exclusive with `endpoint`
cluster_endpoints = "redis://10.0.0.1:6379,redis://10.0.0.2:6379"
username = "user"
password = "passwd"
# Database number to use. Default is 0
db = 1
# Entry expiration time in seconds. Default is 0 (never expire)
expiration = 3600
key_prefix = "/custom/prefix/if/need"

[cache.s3]
bucket = "name"
endpoint = "s3-us-east-1.amazonaws.com"
use_ssl = true
key_prefix = "s3prefix"
server_side_encryption = false

[cache.webdav]
endpoint = "http://192.168.10.42:80/some/webdav.php"
key_prefix = "/custom/webdav/subfolder/if/need"
# Basic HTTP authentication credentials.
username = "alice"
password = "secret12"
# Mutually exclusive with username & password. Bearer token value
token = "token123"

[cache.oss]
bucket = "name"
endpoint = "oss-us-east-1.aliyuncs.com"
key_prefix = "ossprefix"
no_credentials = true

[cache.cos]
bucket = "name"
endpoint = "cos.na-siliconvalley.myqcloud.com"
key_prefix = "cosprefix"
```

sccache looks for its configuration file at the path indicated by env variable `SCCACHE_CONF`.

If no such env variable is set, sccache looks at default locations as below:
- Linux: `~/.config/sccache/config`
- macOS: `~/Library/Application Support/Mozilla.sccache/config`
- Windows: `%APPDATA%\Mozilla\sccache\config\config`

The latest `cache.XXX` entries may be found here: https://github.com/mozilla/sccache/blob/ffe3070f77ef3301c8ff718316e4ab017ec83042/src/config.rs#L300.

## env

Whatever is set by a file based configuration, it is overruled by the env
configuration variables

Note that some env variables may need sccache server restart to take effect.

### misc

* `SCCACHE_ALLOW_CORE_DUMPS` to enable core dumps by the server
* `SCCACHE_CONF` configuration file path
* `SCCACHE_BASEDIRS` base directory (or directories) to strip from paths for cache key computation. This is similar to ccache's `CCACHE_BASEDIR` and enables cache hits across different absolute paths when compiling the same source code. Multiple directories can be separated by `;` on Windows hosts and by `:` on any other operating system. When multiple directories are specified, the longest matching prefix is used. Path matching is **case-insensitive** on Windows and **case-sensitive** on other operating systems. Environment variable takes precedence over file configuration. Only absolute paths are supported; relative paths will cause an error and prevent the server from start.
* `SCCACHE_CACHED_CONF`
* `SCCACHE_IDLE_TIMEOUT` how long the local daemon process waits for more client requests before exiting, in seconds. Set to `0` to run sccache permanently
* `SCCACHE_STARTUP_NOTIFY` specify a path to a socket which will be used for server completion notification
* `SCCACHE_MAX_FRAME_LENGTH` how much data can be transferred between client and server
* `SCCACHE_NO_DAEMON` set to `1` to disable putting the server to the background
* `SCCACHE_CACHE_MULTIARCH` to disable caching of multi architecture builds.
* `SCCACHE_CACHE_ZSTD_LEVEL` to set zstd compression level of cache. the range is `1-22` and default is `3`.
  - For example, in `10`, it have about 0.9x size with about 1.6x time than default `3` (tested with compiling sccache code)
  - This option will only applied to newly compressed cache and don't affect existing cache.
  - If you want to be apply to all cache, you should reset cache and make new cache.
* `SCCACHE_LOG_MILLIS` when set (to any value), enables millisecond precision timestamps in log output instead of the default second precision.
* `SCCACHE_ERROR_LOG` path to a file where sccache will log errors
* `SCCACHE_LOG` log level, accepting standard env_logger values, see [env_logger documentation](https://docs.rs/env_logger/latest/env_logger/#enabling-logging) for details

### cache configs

#### disk (local)

* `SCCACHE_DIR` local on disk artifact cache directory
* `SCCACHE_CACHE_SIZE` maximum size of the local on disk cache i.e. `2G` - default is 10G
* `SCCACHE_DIRECT` enable/disable preprocessor caching (see [the local doc](Local.md))
* `SCCACHE_LOCAL_RW_MODE` the mode that the cache will operate in (`READ_ONLY` or `READ_WRITE`)

#### s3 compatible

* `SCCACHE_BUCKET` s3 bucket to be used
* `SCCACHE_ENDPOINT` s3 endpoint
* `SCCACHE_REGION` s3 region, required if using AWS S3
* `SCCACHE_S3_USE_SSL` s3 endpoint requires TLS, set this to `true`
* `SCCACHE_S3_KEY_PREFIX` s3 key prefix (optional)

The endpoint used then becomes `${SCCACHE_BUCKET}.s3-{SCCACHE_REGION}.amazonaws.com`.
If you are not using the default endpoint and `SCCACHE_REGION` is undefined, it
will default to `us-east-1`.

#### cloudflare r2

* `SCCACHE_BUCKET` is the name of your R2 bucket.
* `SCCACHE_ENDPOINT` must follow the format of `https://<ACCOUNT_ID>.r2.cloudflarestorage.com`. Note that the `https://` must be included. Your account ID can be found [here](https://developers.cloudflare.com/fundamentals/get-started/basic-tasks/find-account-and-zone-ids/).
* `SCCACHE_REGION` should be set to `auto`.
* `SCCACHE_S3_KEY_PREFIX` s3 key prefix (optional).

#### redis

* `SCCACHE_REDIS` full redis url, including auth and access token/passwd (deprecated).
* `SCCACHE_REDIS_ENDPOINT` redis url without auth and access token/passwd - single node configuration.
* `SCCACHE_REDIS_CLUSTER_ENDPOINTS` redis cluster urls, separated by comma - shared cluster configuration.
* `SCCACHE_REDIS_USERNAME` redis username (optional).
* `SCCACHE_REDIS_PASSWORD` redis password (optional).
* `SCCACHE_REDIS_DB` redis database (optional, default is 0).
* `SCCACHE_REDIS_EXPIRATION` / `SCCACHE_REDIS_TTL` ttl for redis cache, don't set for default behavior.
* `SCCACHE_REDIS_KEY_PREFIX` key prefix (optional).

The full url appears then as `redis://user:passwd@1.2.3.4:6379/?db=1`.

#### memcached

* `SCCACHE_MEMCACHED` is a deprecated alias for `SCCACHE_MEMCACHED_ENDPOINT`.
* `SCCACHE_MEMCACHED_ENDPOINT` memcached url.
* `SCCACHE_MEMCACHED_USERNAME` memcached username (optional).
* `SCCACHE_MEMCACHED_PASSWORD` memcached password (optional).
* `SCCACHE_MEMCACHED_EXPIRATION` ttl for memcached cache, don't set for default behavior.
* `SCCACHE_MEMCACHED_KEY_PREFIX` key prefix (optional).

#### gcs

* `SCCACHE_GCS_BUCKET`
* `SCCACHE_GCS_CREDENTIALS_URL`
* `SCCACHE_GCS_KEY_PATH`
* `SCCACHE_GCS_RW_MODE`

#### azure

* `SCCACHE_AZURE_CONNECTION_STRING`
* `SCCACHE_AZURE_BLOB_CONTAINER`
* `SCCACHE_AZURE_KEY_PREFIX`

#### gha

* `SCCACHE_GHA_CACHE_URL` / `ACTIONS_RESULTS_URL` GitHub Actions cache API URL
* `SCCACHE_GHA_RUNTIME_TOKEN` / `ACTIONS_RUNTIME_TOKEN` GitHub Actions access token
* `SCCACHE_GHA_CACHE_TO` cache key to write
* `SCCACHE_GHA_CACHE_FROM` comma separated list of cache keys to read from

#### webdav

* `SCCACHE_WEBDAV_ENDPOINT` a webdav service endpoint to store cache, such as `http://127.0.0.1:8080/my/webdav.php`.
* `SCCACHE_WEBDAV_KEY_PREFIX` specify the key prefix (subfolder) of cache (optional).
* `SCCACHE_WEBDAV_USERNAME` a username to authenticate with webdav service (optional).
* `SCCACHE_WEBDAV_PASSWORD` a password to authenticate with webdav service (optional).
* `SCCACHE_WEBDAV_TOKEN` a token to authenticate with webdav service (optional) - may be used instead of login & password.

#### OSS

* `SCCACHE_OSS_BUCKET`
* `SCCACHE_OSS_ENDPOINT`
* `SCCACHE_OSS_KEY_PREFIX`
* `ALIBABA_CLOUD_ACCESS_KEY_ID`
* `ALIBABA_CLOUD_ACCESS_KEY_SECRET`
* `SCCACHE_OSS_NO_CREDENTIALS`

#### Tencent Cloud Object Storage (COS)

* `SCCACHE_COS_BUCKET`
* `SCCACHE_COS_ENDPOINT`
* `SCCACHE_COS_KEY_PREFIX`
* `TENCENTCLOUD_SECRET_ID`
* `TENCENTCLOUD_SECRET_KEY`


================================================
FILE: docs/Distributed.md
================================================
# Distributed sccache

Background:

 - You should read about JSON Web Tokens - https://jwt.io/.
   - HS256 in short: you can sign a piece of (typically unencrypted)
     data with a key. Verification involves signing the data again
     with the same key and comparing the result. As a result, if you
     want two parties to verify each others messages, the key must be
     shared beforehand.
 - Secure token's referenced below should be generated with a CSPRNG
   (your OS random number generator should suffice).
   For example, on Linux this is accessible with: `openssl rand -hex 64`.
 - When relying on random number generators (for generating keys or
   tokens), be aware that a lack of entropy is possible in cloud or
   virtualized environments in some scenarios.

## Overview

Distributed sccache consists of three parts:

 - the client, an sccache binary that wishes to perform a compilation on
   remote machines
 - the scheduler (`sccache-dist` binary), responsible for deciding where
   a compilation job should run
 - the server (`sccache-dist` binary), responsible for actually executing
   a build

All servers are required to be a 64-bit Linux or a FreeBSD install. Clients
may request compilation from Linux, Windows or macOS. Linux compilations will
attempt to automatically package the compiler in use, while Windows and macOS
users will need to specify a toolchain for cross-compilation ahead of time.

## Communication

The HTTP implementation of sccache has the following API, where all HTTP body content is encoded using [`bincode`](http://docs.rs/bincode):

 - scheduler
   - `POST /api/v1/scheduler/alloc_job`
      - Called by a client to submit a compilation request.
      - Returns information on where the job is allocated it should run.
   - `GET /api/v1/scheduler/server_certificate`
      - Called by a client to retrieve the (dynamically created) HTTPS
        certificate for a server, for use in communication with that server.
      - Returns a digest and PEM for the temporary server HTTPS certificate.
   - `POST /api/v1/scheduler/heartbeat_server`
      - Called (repeatedly) by servers to register as available for jobs.
   - `POST /api/v1/scheduler/job_state`
      - Called by servers to inform the scheduler of the state of the job.
   - `GET /api/v1/scheduler/status`
      - Returns information about the scheduler.
 - `server`
   - `POST /api/v1/distserver/assign_job`
      - Called by the scheduler to inform of a new job being assigned to this server.
      - Returns whether the toolchain is already on the server or needs submitting.
   - `POST /api/v1/distserver/submit_toolchain`
      - Called by the client to submit a toolchain.
   - `POST /api/v1/distserver/run_job`
      - Called by the client to run a job.
      - Returns the compilation stdout along with files created.

There are three axes of security in this setup:

1. Can the scheduler trust the servers?
2. Is the client permitted to submit and run jobs?
3. Can third parties see and/or modify traffic?

### Server Trust

If a server is malicious, they can return malicious compilation output to a user.
To protect against this, servers must be authenticated to the scheduler. You have three
means for doing this, and the scheduler and all servers must use the same mechanism.

Once a server has registered itself using the selected authentication, the scheduler
will trust the registered server address and use it for builds.

#### JWT HS256 (preferred)

This method uses secret key to create a per-IP-and-port token for each server.
Acquiring a token will only allow participation as a server if the attacker can
additionally impersonate the IP and port the token was generated for.

You *must* keep the secret key safe.

*To use it*:

Create a scheduler key with `sccache-dist auth generate-jwt-hs256-key` (which will
use your OS random number generator) and put it in your scheduler config file as
follows:

```
server_auth = { type = "jwt_hs256", secret_key = "YOUR_KEY_HERE" }
```

Now generate a token for the server, giving the IP and port the scheduler and clients can
connect to the server on (address `192.168.1.10:10501` here):

```
sccache-dist auth generate-jwt-hs256-server-token \
    --secret-key YOUR_KEY_HERE \
    --server 192.168.1.10:10501
```

*or:*

```
sccache-dist auth generate-jwt-hs256-server-token \
    --config /path/to/scheduler-config.toml \
    --server 192.168.1.10:10501
```

This will output a token (you can examine it with https://jwt.io if you're
curious) that you should add to your server config file as follows:

```
scheduler_auth = { type = "jwt_token", token = "YOUR_TOKEN_HERE" }
```

Done!

#### Token

This method simply shares a token between the scheduler and all servers. A token
leak from anywhere allows any attacker to participate as a server.

*To use it*:

Choose a 'secure token' you can share between your scheduler and all servers. The token must be a valid HTTP header value.

Put the following in your scheduler config file:

```
server_auth = { type = "token", token = "YOUR_TOKEN_HERE" }
```

Put the following in your server config file:

```
scheduler_auth = { type = "token", token = "YOUR_TOKEN_HERE" }
```

Done!

#### Insecure (bad idea)

*This route is not recommended*

This method uses a hardcoded token that effectively disables authentication and
provides no security at all.

*To use it*:

Put the following in your scheduler config file:

```
server_auth = { type = "DANGEROUSLY_INSECURE" }
```

Put the following in your server config file:

```
scheduler_auth = { type = "DANGEROUSLY_INSECURE" }
```

Done!

### Client Trust

If a client is malicious, they can cause a DoS of distributed sccache servers or
explore ways to escape the build sandbox. To protect against this, clients must
be authenticated.

Each client will use an authentication token for the initial job allocation request
to the scheduler. A successful allocation will return a job token that is used
to authorise requests to the appropriate server for that specific job.

This job token is a JWT HS256 token of the job id, signed with a server key.
The key for each server is randomly generated on server startup and given to
the scheduler during registration. This means that the server can verify users
without either a) adding client authentication to every server or b) needing
secret transfer between scheduler and server on every job allocation.

#### OAuth2

This is a group of similar methods for achieving the same thing - the client
retrieves a token from an OAuth2 service, and then submits it to the scheduler
which has a few different options for performing validation on that token.

*To use it*:

Put one of the following settings in your scheduler config file to determine how
the scheduler will validate tokens from the client:

```
# Use the known settings for Mozilla OAuth2 token validation
client_auth = { type = "mozilla" }

# Will forward the valid JWT token onto another URL in the `Bearer` header, with a
# success response indicating the token is valid. Optional `cache_secs` how long
# to cache successful authentication for.
client_auth = { type = "proxy_token", url = "...", cache_secs = 60 }
```

Additionally, each client should set up an OAuth2 configuration in the with one of
the following settings (as appropriate for your OAuth service):

```
# Use the known settings for Mozilla OAuth2 authentication
auth = { type = "mozilla" }

# Use the Authorization Code with PKCE flow. This requires a client id,
# an initial authorize URL (which may have parameters like 'audience' depending
# on your service) and the URL for retrieving a token after the browser flow.
auth = { type = "oauth2_code_grant_pkce", client_id = "...", auth_url = "...", token_url = "..." }

# Use the Implicit flow (typically not recommended due to security issues). This requires
# a client id and an authorize URL (which may have parameters like 'audience' depending
# on your service).
auth = { type = "oauth2_implicit", client_id = "...", auth_url = "..." }
```

The client should then run `sccache --dist-auth` and follow the instructions to retrieve
a token. This will be automatically cached locally for the token expiry period (manual
revalidation will be necessary after expiry).

#### Token

This method simply shares a token between the scheduler and all clients. A token
leak from anywhere allows any attacker to participate as a client.

*To use it*:

Choose a 'secure token' you can share between your scheduler and all clients. The token must be a valid HTTP header value.

Put the following in your scheduler config file:

```
client_auth = { type = "token", token = "YOUR_TOKEN_HERE" }
```

Put the following in your client config file:

```
auth = { type = "token", token = "YOUR_TOKEN_HERE" }
```

Done!

#### Insecure (bad idea)

*This route is not recommended*

This method uses a hardcoded token that effectively disables authentication and
provides no security at all.

*To use it*:

Put the following in your scheduler config file:

```
client_auth = { type = "DANGEROUSLY_INSECURE" }
```

Remove any `auth =` setting under the `[dist]` heading in your client config file
(it will default to this insecure mode).

Done!

### Eavesdropping and Tampering Protection

If third parties can see traffic to the servers, source code can be leaked. If third
parties can modify traffic to and from the servers or the scheduler, they can cause
the client to receive malicious compiled objects.

Securing communication with the scheduler is the responsibility of the sccache cluster
administrator - it is recommended to put a webserver with a HTTPS certificate in front
of the scheduler and instruct clients to configure their `scheduler_url` with the
appropriate `https://` address. The scheduler will verify the server's IP in this
configuration by inspecting the `X-Real-IP` header's value, if present. The webserver
used in this case should be configured to set this header to the appropriate value.

Securing communication with the server is performed automatically - HTTPS certificates
are generated dynamically on server startup and communicated to the scheduler during
the heartbeat. If a client does not have the appropriate certificate for communicating
securely with a server (after receiving a job allocation from the scheduler), the
certificate will be requested from the scheduler.

## Configuration

Use the `--config` argument to pass the path to its configuration file to `sccache-dist`.


### scheduler.toml

```toml
# The socket address the scheduler will listen on. It's strongly recommended
# to listen on localhost and put a HTTPS server in front of it.
public_addr = "127.0.0.1:10600"

[client_auth]
type = "token"
token = "my client token"

[server_auth]
type = "jwt_hs256"
secret_key = "my secret key"
```


#### [client_auth]

The `[client_auth]` section can be one of (sorted by authentication method):
```toml
# OAuth2
[client_auth]
type = "mozilla"

client_auth = { type = "proxy_token", url = "...", cache_secs = 60 }

# JWT
[client_auth]
type = "jwt_validate"
audience = "audience"
issuer = "issuer"
jwks_url = "..."

# Token
[client_auth]
type = "token"
token = "preshared token"

# None
[client_auth]
type = "DANGEROUSLY_INSECURE"
```


#### [server_auth]

The `[server_auth]` section can be can be one of:
```toml
[server_auth]
type = "jwt_hs256"
secret_key = "my secret key"

[server_auth]
type = "token"
token = "preshared token"

[server_auth]
type = "DANGEROUSLY_INSECURE"
```

### server.toml


```toml
# This is where client toolchains will be stored.
cache_dir = "/tmp/toolchains"
# The maximum size of the toolchain cache, in bytes.
# If unspecified the default is 10GB.
#toolchain_cache_size = 10737418240
# A public IP address and port that clients will use to connect to this builder.
public_addr = "192.168.1.1:10501"
# The socket address the builder will listen on. Falls back to public_addr.
#bind_address = "0.0.0.0:10501"
# The URL used to connect to the scheduler (should use https, given an ideal
# setup of a HTTPS server in front of the scheduler)
scheduler_url = "https://192.168.1.1"

[builder]
type = "overlay"
# The directory under which a sandboxed filesystem will be created for builds.
build_dir = "/tmp/build"
# The path to the bubblewrap version 0.3.0+ `bwrap` binary.
bwrap_path = "/usr/bin/bwrap"

[scheduler_auth]
type = "jwt_token"
# This will be generated by the `generate-jwt-hs256-server-token` command or
# provided by an administrator of the sccache cluster.
token = "my server's token"
```


#### [builder]

The `[builder]` section can be can be one of:
```toml
[builder]
type = "docker"

[builder]
type = "overlay"
# The directory under which a sandboxed filesystem will be created for builds.
build_dir = "/tmp/build"
# The path to the bubblewrap version 0.3.0+ `bwrap` binary.
bwrap_path = "/usr/bin/bwrap"

[builder]
type = "pot"
# Pot filesystem root
#pot_fs_root = "/opt/pot"
# Reference pot cloned when creating containers
#clone_from = "sccache-template"
# Command to invoke when calling pot
#pot_cmd = "pot"
# Arguments passed to `pot clone` command
#pot_clone_args = ["-i", "lo0|127.0.0.2"]

```


#### [scheduler_auth]

The `[scheduler_auth]` section can be can be one of:
```toml
[scheduler_auth]
type = "jwt_token"
token = "my server's token"

[scheduler_auth]
type = "token"
token = "preshared token"

[scheduler_auth]
type = "DANGEROUSLY_INSECURE"
```


# Building the Distributed Server Binaries

Until these binaries [are included in releases](https://github.com/mozilla/sccache/issues/393) I've put together a Docker container that can be used to easily build a release binary:
```
docker run -ti --rm -v $PWD:/sccache luser/sccache-musl-build:0.1 /bin/bash -c "cd /sccache; cargo build --release --target x86_64-unknown-linux-musl --features=dist-server && strip target/x86_64-unknown-linux-musl/release/sccache-dist && cd target/x86_64-unknown-linux-musl/release/ && tar czf sccache-dist.tar.gz sccache-dist"
```


================================================
FILE: docs/DistributedFreeBSD.md
================================================
Distributed sccache on FreeBSD
==============================

Please read the [the distributed quickstart](DistributedQuickstart.md)
guide first.

Build and install from source
-----------------------------

```
cargo install --features="dist-client,dist-server" --path=.
```

Configure a FreeBSD build server
--------------------------------

On FreeBSD, the build server requires [pot](https://github.com/bsdpot/pot)
to sandbox execution:

```sh
pkg install pot
```

It's up to the user to create the reference pot that serves as a template
to clone from when instantiating image and build containers, e.g.:

```sh
pot create -p sccache-template -N alias -i "lo0|127.0.0.2" -t single -b 15.0
pot set-cmd -p sccache-template -c /usr/bin/true
pot set-attr -p sccache-template -A no-rc-script -V YES
pot snapshot -p sccache-template
```

Then, a server.conf like the one below is created, making use of the `pot`
builder type (commented out options show defaults):

```toml
# This is where client toolchains will be stored.
cache_dir = "/tmp/toolchains"
# The maximum size of the toolchain cache, in bytes.
# If unspecified the default is 10GB.
# toolchain_cache_size = 10737418240
# A public IP address and port that clients will use to connect to this builder.
public_addr = "192.168.1.1:10501"
# The URL used to connect to the scheduler (should use https, given an ideal
# setup of a HTTPS server in front of the scheduler)
scheduler_url = "https://192.168.1.1"

[builder]
type = "pot"
# Pot filesystem root
#pot_fs_root = "/opt/pot"
# Reference pot cloned when creating containers
#clone_from = "sccache-template"
# Command to invoke when calling pot
#pot_cmd = "pot"
# Arguments passed to `pot clone` command
#pot_clone_args = ["-i", "lo0|127.0.0.2"]

[scheduler_auth]
type = "jwt_token"
# This will be generated by calling
# `sccache-dist auth generate-jwt-hs256-server-token` or
# provided by an administrator of the sccache cluster.
token = "my server's token"
```

FreeBSD as a build client
-------------------------

On a FreeBSD client, make sure to add the right toolchains to
`~/.config/sccache/config`:

```toml
[dist]
# The URL used to connect to the scheduler (should use https, given an ideal
# setup of a HTTPS server in front of the scheduler)
scheduler_url = "http://127.0.0.1:10600"
# Used for mapping local toolchains to remote cross-compile toolchains. Empty in
# this example where the client and build server are both Linux.
#toolchains = []
# Size of the local toolchain cache, in bytes (5GB here, 10GB if unspecified).
toolchain_cache_size = 5368709120
cache_dir = "/home/user/.cache/sccache-dist-client"

[dist.auth]
type = "token"
# This should match the `client_auth` section of the scheduler config
# and was generated by calling `sccache-dist auth generate-jwt-hs256-key`
token = "my client token"

[[dist.toolchains]]
type = "path_override"
compiler_executable = "/usr/bin/cc"
archive = "/path/to/empty.tar.gz"
archive_compiler_executable = "/usr/bin/cc"

[[dist.toolchains]]
type = "path_override"
compiler_executable = "/usr/local/bin/rustc"
archive = "/path/to/rust-toolchain.tgz"
archive_compiler_executable = "/usr/local/bin/rustc"
```

Creating toolchain archives
---------------------------

The toolchain files from the examples above can be created like this:

```sh
pkg install gtar
gtar cvf - --files-from /dev/null | gzip >empty.tar.gz
pkg info -lq rust | gtar -cf - -T - | gzip >rust-toolchain.tgz
```

This just creates an empty file for the system compiler (as it is
included in the pot image anyway) and the toolchain for rustc is
created from the rust package installed on the system.

See [the distributed quickstart](DistributedQuickstart.md) guide for
instructions how to create other C toolchains using icecc-create-env.

Note: We use `gtar` (GNU tar) here, as the [flate2](
https://github.com/rust-lang/flate2-rs) crate has issues processing
sparse files created with `bsdtar`.

Cargo invocation example
------------------------

```sh
RUSTC_WRAPPER=~/.cargo/bin/sccache \
cargo build
```


================================================
FILE: docs/DistributedQuickstart.md
================================================
sccache distributed compilation quickstart
==========================================

This is a quick start guide to getting distributed compilation working with sccache. This guide primarily covers Linux clients.
macOS and Windows clients are supported but have seen significantly less testing.

Get sccache binaries
--------------------

Either [install pre-built sccache binaries](https://github.com/mozilla/sccache#installation), or build sccache locally with the `dist-client` and `dist-server` features enabled:
```
cargo build --release --features="dist-client dist-server"
```

The `target/release/sccache` binary will be used on the client, and the `target/release/sccache-dist` binary will be used on the scheduler and build server.

If you're only planning to use the client, it is enabled by default, so just `cargo install sccache` should do the trick.

Configure a scheduler
---------------------

If you're adding a server to a cluster that has already been set up, skip ahead to [configuring a build server](#configure-a-build-server).

The scheduler is a daemon that manages compile request from clients and parcels them out to build servers. You only need one of these per sccache setup. Currently only Linux is supported for running the scheduler.

Create a scheduler.conf file to configure client/server authentication. A minimal example looks like:
```toml
# The socket address the scheduler will listen on. It's strongly recommended
# to listen on localhost and put a HTTPS server in front of it.
public_addr = "127.0.0.1:10600"

[client_auth]
type = "token"
token = "my client token" # Must be a valid HTTP header value.

[server_auth]
type = "jwt_hs256"
secret_key = "my secret key"
```

Mozilla build servers will typically require clients to be authenticated with the
[Mozilla identity system](https://github.com/mozilla-iam/mozilla-iam).

To configure for scheduler for this, the `client_auth` section should be as follows
so any client tokens are validated with the Mozilla service:

```
[client_auth]
type = "mozilla"
required_groups = ["group_name"]
```

Where `group_name` is a Mozilla LDAP group. Users will be required to belong to this group to successfully authenticate with the scheduler.

Start the scheduler by running:
```
sccache-dist scheduler --config scheduler.conf
```

Like the local server, the scheduler process will daemonize itself unless `SCCACHE_NO_DAEMON=1` is set. If the scheduler fails to start you may need to set `SCCACHE_LOG=trace` when starting it to get useful diagnostics.

Configure a build server
------------------------

A build server communicates with the scheduler and executes compiles requested by clients. Only Linux is supported for running a build server, but executing cross-compile requests from macOS/Windows clients is supported. You can also run a build server on FreeBSD, please see [distributed sccache on FreeBSD](DistributedFreeBSD.md).

The build server requires [bubblewrap](https://github.com/projectatomic/bubblewrap) to sandbox execution, at least version 0.3.0. Verify your version of bubblewrap *before* attempting to run the server. On Ubuntu 18.10+ you can `apt install bubblewrap` to install it. If you build from source you will need to first install your distro's equivalent of the `libcap-dev` package.

Create a server.conf file to configure authentication, storage locations, network addresses and the path to bubblewrap. A minimal example looks like:
```toml
# This is where client toolchains will be stored.
cache_dir = "/tmp/toolchains"
# The maximum size of the toolchain cache, in bytes.
# If unspecified the default is 10GB.
# toolchain_cache_size = 10737418240
# A public IP address and port that clients will use to connect to this builder.
public_addr = "192.168.1.1:10501"
# The URL used to connect to the scheduler (should use https, given an ideal
# setup of a HTTPS server in front of the scheduler)
scheduler_url = "https://192.168.1.1"

[builder]
type = "overlay"
# The directory under which a sandboxed filesystem will be created for builds.
build_dir = "/tmp/build"
# The path to the bubblewrap version 0.3.0+ `bwrap` binary.
bwrap_path = "/usr/bin/bwrap"

[scheduler_auth]
type = "jwt_token"
# This will be generated by the `generate-jwt-hs256-server-token` command or
# provided by an administrator of the sccache cluster.
token = "my server's token"
```

Due to bubblewrap requirements currently the build server *must* be run as root. Start the build server by running:
```
sudo sccache-dist server --config server.conf
```

As with the scheduler, if the build server fails to start you may need to set `SCCACHE_LOG=trace` to get useful diagnostics.

Configure a client
------------------

A client uses `sccache` to wrap compile commands, communicates with the scheduler to find available build servers, and communicates with build servers to execute the compiles and receive the results.

Clients that are not targeting linux64 require the `icecc-create-env` script or should be provided with an archive. `icecc-create-env` is part of `icecream` for packaging toolchains. You can install icecream to get this script (`apt install icecc` on Ubuntu), or download it from the git repository and place it in your `PATH`: `curl https://raw.githubusercontent.com/icecc/icecream/master/client/icecc-create-env.in > icecc-create-env && chmod +x icecc-create-env`. See [using custom toolchains](#using-custom-toolchains).

Create a client config file in `~/.config/sccache/config` (on Linux), `~/Library/Application Support/Mozilla.sccache/config` (on macOS), or `%APPDATA%\Mozilla\sccache\config\config` (on Windows). A minimal example looks like:
```toml
[dist]
# The URL used to connect to the scheduler (should use https, given an ideal
# setup of a HTTPS server in front of the scheduler)
scheduler_url = "https://192.168.1.1"
# Used for mapping local toolchains to remote cross-compile toolchains. Empty in
# this example where the client and build server are both Linux.
toolchains = []
# Size of the local toolchain cache, in bytes (5GB here, 10GB if unspecified).
toolchain_cache_size = 5368709120

[dist.auth]
type = "token"
# This should match the `client_auth` section of the scheduler config.
token = "my client token" # Must be a valid HTTP header value.
```

Clients using Mozilla build servers should configure their `dist.auth` section as follows:

```
[dist.auth]
type = "mozilla"
```

And retrieve a token from the Mozilla identity service by running `sccache --dist-auth`
and following the instructions. Completing this process will retrieve and cache a token
valid for 7 days.

Make sure to run `sccache --stop-server` and `sccache --start-server` if sccache was
running before changing the configuration.

You can check the status with `sccache --dist-status`, it should say something like:

```
$ sccache --dist-status
{"SchedulerStatus":["https://sccache1.corpdmz.ber3.mozilla.com/",{"num_servers":3,"num_cpus":56,"in_progress":24}]}
```

Using custom toolchains
-----------------------

Since Windows and macOS cannot automatically package toolchains, it is important to be
able to manually specify toolchains for distribution. This functionality is also available
on Linux.

Using custom toolchains involves adding a `dist.toolchains` section to your client config
file (you can add it multiple times to specify multiple toolchains).

On Linux and macOS:

```
[[dist.toolchains]]
type = "path_override"
compiler_executable = "/home/me/.mozbuild/clang/bin/clang"
archive = "/home/me/.mozbuild/toolchains/33d92fcd79ffef6e-clang-dist-toolchain.tar.gz"
archive_compiler_executable = "/builds/worker/toolchains/clang/bin/clang"
```

On Windows:

```
[[dist.toolchains]]
type = "path_override"
compiler_executable = "C:/clang/bin\\clang-cl.exe"
archive = "C:/toolchains/33d92fcd79ffef6e-clang-dist-toolchain.tar.gz"
archive_compiler_executable = "/builds/worker/toolchains/clang/bin/clang"
```

Where:
 - `compiler_executable` identifies the path that sccache will match against to activate
   this configuration (you need to be careful on Windows - paths can have slashes in both
   directions, and you may need to escape backslashes, as in the example)
 - `archive` is the gzip-compressed tar archive containing the compiler toolchain to distribute
   when `compiler_executable` is matched
 - `archive_compiler_executable` is the path within the archive the distributed
   compilation should invoke

A toolchain archive should be a Gzip compressed TAR archive, containing a filesystem
sufficient to run the compiler without relying on any external files. If you have archives
compatible with icecream (created with `icecc-create-env`, like
[these ones](https://github.com/jyavenard/mozilla-icecream) for macOS), they should also work
with sccache. To create a Windows toolchain, it is recommended that you download the [Clang
binaries for Ubuntu 16.04](http://releases.llvm.org/download.html) and extract them,
package up the toolchain using the extracted `bin/clang` file (requires
[PR #321](https://github.com/mozilla/sccache/pull/321)) and then insert `bin/clang-cl` at
the appropriate path as a symlink to the `bin/clang` binary.

Considerations when distributing from macOS
-------------------------------------------

When distributing from a macOS client, additional flags and configuration
may be required:

- An explicit target should be passed to the compiler, for instance by adding
  `--target=x86_64-apple-darwin16.0.0` to your build system's `CFLAGS`.
- An explicit toolchain archive will need to be configured, as described above.
  In case rust is being cached, the same version of `rustc` will need to be used
  for local compiles as is found in the distributed archive.
- The client config will be read from `~/Library/Application Support/Mozilla.sccache/config`,
  not `~/.config/sccache/config`.
- Some cross compilers may not understand some intrinsics used in more recent macOS
  SDKs. The 10.11 SDK is known to work.

Making a build server start at boot time
----------------------------------------

It is very easy with a systemd service to spawn the server on boot.

You can create a service file like `/etc/systemd/system/sccache-server.service`
with the following contents:

```ini
[Unit]
Description=sccache-dist server
Wants=network-online.target
After=network-online.target

[Service]
ExecStart=/path/to/sccache-dist server --config /path/to/server.conf

[Install]
WantedBy=multi-user.target
```

**Note** that if the `sccache-dist` binary is in a user's home directory, and
you're in a distro with SELinux enabled (like Fedora), you may need to use an
`ExecStart` line like:

```ini
ExecStart=/bin/bash -c "/home/<user>/path/to/sccache-dist server --config /home/<user>/path/to/server.conf"
```

This is because SELinux by default prevents services from running binaries in
home directories, for some reason. Using a shell works around that. An
alternative would be to move the `sccache-dist` binary to somewhere like
`/usr/local/bin`, but then you need to remember to update it manually.

After creating that file, you can ensure it's working and enable it by default
like:

```
# systemctl daemon-reload
# systemctl start sccache-server
# systemctl status # And check it's fine.
# systemctl enable sccache-server # This enables the service on boot
```


================================================
FILE: docs/GHA.md
================================================
# GitHub Actions

To use the [GitHub Actions cache](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows), you need to set `SCCACHE_GHA_ENABLED` to `on` to enable it.

By changing `SCCACHE_GHA_VERSION`, we can purge all the cache.

This cache type will need tokens like `ACTIONS_RESULTS_URL` and `ACTIONS_RUNTIME_TOKEN` to work. You can set these environmental variables using the following step in a GitHub Actions workflow.

```yaml
- name: Configure sccache
  uses: actions/github-script@v7
  with:
    script: |
      core.exportVariable('ACTIONS_RESULTS_URL', process.env.ACTIONS_RESULTS_URL || '');
      core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
```

## Behavior

In case sccache reaches the rate limit of the service, the build will continue, but the storage might not be performed.


================================================
FILE: docs/Gcs.md
================================================
# Google Cloud Storage

To use [Google Cloud Storage](https://cloud.google.com/storage/), you need to set
the `SCCACHE_GCS_BUCKET` environment variable to the name of the GCS bucket.

By default, SCCACHE on GCS will be read-only. To change this, set `SCCACHE_GCS_RW_MODE`
to either `READ_ONLY` or `READ_WRITE`.

You can also define a prefix that will be prepended to the keys of all cache objects
created and read within the GCS bucket, effectively creating a scope. To do that
use the `SCCACHE_GCS_KEY_PREFIX` environment variable. This can be useful when
sharing a bucket with another application.

## Credentials

Sccache is able to load credentials from various sources. Including:

- User Input: If `SCCACHE_GCS_KEY_PATH` has been set, we will load from this file
  first.
  - Service accounts JSONs
  - External accounts JSONs
- [Task Cluster](https://taskcluster.net/): If `SCCACHE_GCS_CREDENTIALS_URL` has
  been set, we will load token from this url first.
- Static: `GOOGLE_APPLICATION_CREDENTIALS`
- Well-known locations:
  - Windows: `%APPDATA%\gcloud\application_default_credentials.json`
  - macOS/Linux:
    - `$XDG_CONFIG_HOME/gcloud/application_default_credentials.json`
    - `$HOME/.config/gcloud/application_default_credentials.json`
- VM Metadata: Fetch token will the specified service account.

### Service accounts

To create such account, in GCP, go in `APIs and Services` => `Cloud Storage` =>
`Create credentials` => `Service account`. Then, once created, click on the account
then `Keys` => `Add key` => `Create new key`. Select the JSON format and here it
is. This JSON file is what `SCCACHE_GCS_KEY_PATH` expects.

The service account needs `Storage Object Admin` permissions on the bucket
(otherwise, sccache will fail with a simple `Permission denied`).

### External accounts

Such accounts require creating a [Workload Identity Pool and Workload Identity Provider].
This approach allows the environment (Azure, Aws, or other OIDC providers like Github)
to create a temporary service account grant without having to share a service account
JSON, which can be pretty powerful. An example on how to create such accounts is
[Google's guide on how to use it with Github].

After generating the external account JSON file, you may pass its path to `SCCACHE_GCS_KEY_PATH`.

Service accounts used by the pool must have `Storage Object Admin` permissions on
bucket as well.

## Verifying it works

To verify that it works, run:

```
export SCCACHE_GCS_BUCKET=<bucket name in GCP>
export SCCACHE_GCS_KEY_PATH=secret-gcp-storage.json
./sccache --show-stats
# you should see
[...]
Cache location                  GCS, bucket: Bucket(name=<bucket name in GCP>), key_prefix: (none)
```

## Deprecation

`SCCACHE_GCS_OAUTH_URL` have been deprecated and not supported, please use `SCCACHE_GCS_SERVICE_ACCOUNT` instead.

[Workload Identity Pool and Workload Identity Provider]: https://cloud.google.com/iam/docs/manage-workload-identity-pools-providers
[Google's guide on how to use it with Github]: https://cloud.google.com/blog/products/identity-security/enabling-keyless-authentication-from-github-actions


================================================
FILE: docs/Jenkins.md
================================================
sccache on Jenkins
==================

When using `sccache` on [Jenkins](https://jenkins.io) one has to know about how to deal with the sccache server process.
Unless specified otherwise, sccache uses port `4226`. On invocation, sccache tries to connect to a sccache server
instance on this port. If no server is running, a new instance is spawned. Jenkins tries to kill *all* spawned processes
once a job is finished.  This results in broken builds when two run in parallel and the first one who spawned the server
is finished and the server is killed. The other job way be in contact with the server (e.g waiting for a cache response)
and fail.

One option to solve this problem is to spawn a always running sccache server process by setting `SCCACHE_IDLE_TIMEOUT`
to `0` and start the server beside Jenkins as a system service. This implies that all jobs use the same sccache
configuration and share the statistics.

If a per-jobs sccache configuration is needed or preferred (e.g place a local disc cache in `$WORKSPACE`) the [Port
allocator plugin](https://wiki.jenkins.io/display/JENKINS/Port+Allocator+Plugin) does a good job. It assigns a free and
unique port number to a job by exporting a variable. Naming this variable `SCCACHE_SERVER_PORT` is enough to make the
job spawn it's own sccache server that is save to terminate upon job termination. This approach has the advantage that
each job (with a dedicated server instance) maintains it's own statistics that might be interesting upon job
finalization.


================================================
FILE: docs/Local.md
================================================
# Local

sccache defaults to using local disk storage. You can set the `SCCACHE_DIR` environment variable to change the disk cache location. By default it will use a sensible location for the current platform: `~/.cache/sccache` on Linux, `%LOCALAPPDATA%\Mozilla\sccache` on Windows, and `~/Library/Caches/Mozilla.sccache` on MacOS.

The default cache size is 10 gigabytes. To change this, set `SCCACHE_CACHE_SIZE`, for example `SCCACHE_CACHE_SIZE="1G"`.

The local storage only supports a single sccache server at a time. Multiple concurrent servers will race and cause spurious build failures.

## Preprocessor cache mode

This is inspired by [ccache's direct mode](https://ccache.dev/manual/3.7.9.html#_the_direct_mode) and works roughly the same.
It adds a cache that allows to skip preprocessing when compiling C/C++. This can make it much faster to return compilation results
from cache since preprocessing is a major expense for these.

Preprocessor cache mode is controlled by a configuration option which is true by default, as well as additional conditions described below.

To ensure that the cached preprocessor results for a source file correspond to the un-preprocessed inputs, sccache needs
to remember, among other things, all files included by the source file. sccache also needs to recognize
when "external factors" may change the results, such as system time if the `__TIME__` macro is used
in a source file. How conservative sccache is about some of these external factors is configurable, see below.

Preprocessor cache mode will be disabled in any of the following cases:

- Not compiling C or C++
- The configuration option is false
- Not using GCC or Clang
- Not using local storage for the cache
- Any of the compiler options `-MP`, `-Xpreprocessor`, `-Wp,` are present
- The modification time of one of the header files is too new (avoids a race condition)
- Certain strings such as `__DATE__`, `__TIME__`, `__TIMESTAMP__` are present in the source code,
  indicating that the preprocessor result may change based on external factors

The preprocessor cache may silently produce stale results in any of the following cases:

- When a source file was compiled and its results were cached, a header file would have been included if it existed, but it did
  not exist at the time. sccache does not know about such files, so it cannot invalidate the result if the header file later exists.
- A macro such as `__TIME__` (etc) is used in the source code and `ignore_time_macros` is enabled
- There are other external factors influencing the preprocessing result that sccache does not know about

Configuration options and their default values:

- `use_preprocessor_cache_mode`: `true`. Whether to use preprocessor cache mode. This can be overridden for an sccache invocation by setting the environment variable `SCCACHE_DIRECT` to `true`/`on`/`1` or `false`/`off`/`0`.
- `file_stat_matches`: `false`. If false, only compare header files by hashing their contents. If true, will use size + ctime + mtime to check whether a file has changed. See other flags below for more control over this behavior.
- `use_ctime_for_stat`: `true`. If true, uses the ctime (file status change on UNIX, creation time on Windows) to check that a file has/hasn't changed. Can be useful to disable when backdating modification times in a controlled manner.

- `ignore_time_macros`: `false`. If true, ignore `__DATE__`, `__TIME__` and `__TIMESTAMP__` being present in the source code. Will speed up preprocessor cache mode, but can produce stale results.

- `skip_system_headers`: `false`. If true, the preprocessor cache will only add the paths of included system headers to the cache key but ignore the headers' contents.

- `hash_working_directory`: `true`. If true, will add the current working directory to the cache key to distinguish two compilations from different directories.

See where to write the config in [the configuration doc](Configuration.md).

## Read-only cache mode

By default, the local cache operates in read/write mode. The `SCCACHE_LOCAL_RW_MODE` environment variable can be set to `READ_ONLY` (or `READ_WRITE`) to modify this behavior.

You can use read-only mode to prevent sccache from writing new cache items to the disk. This can be useful, for example, if you want to use items that have already been cached, but not add new ones to the cache. 

Note that this feature is only effective if you already have items in your cache. Using this option on an empty cache will cause sccache to simply do nothing, just add overhead.


================================================
FILE: docs/Memcached.md
================================================
# Memcached

Set `SCCACHE_MEMCACHED_ENDPOINT` to a [Memcached](https://memcached.org/) url in format `tcp://<hostname>:<port> ...` to store the cache in a Memcached instance.

`SCCACHE_MEMCACHED` is a deprecated alias for `SCCACHE_MEMCACHED_ENDPOINT` for unifying the variable name with other remote storages.

Set `SCCACHE_MEMCACHED_USERNAME` and `SCCACHE_MEMCACHED_PASSWORD` if you want to authenticate to Memcached.

Set `SCCACHE_MEMCACHED_EXPIRATION` to the default expiration seconds of memcached. The default value is `86400` (1 day) and can up to `2592000` (30 days). Set this value to `0` will disable the expiration. memcached will purge the cache entry while it exceed 30 days or meets LRU rules.

Set `SCCACHE_MEMCACHED_KEY_PREFIX` if you want to prefix all cache keys. This can be
useful when sharing a Memcached instance with another application or cache.


================================================
FILE: docs/OSS.md
================================================
# OSS

If you want to use _Object Storage Service_ (aka OSS) by Alibaba for the sccache cache, you need to set the `SCCACHE_OSS_BUCKET` environment variable to the name of the OSS bucket to use.

You **must** specify the endpoint URL using the `SCCACHE_OSS_ENDPOINT` environment variable. More details about [OSS endpoints](https://www.alibabacloud.com/help/en/oss/user-guide/regions-and-endpoints).

You can also define a prefix that will be prepended to the keys of all cache objects created and read within the OSS bucket, effectively creating a scope. To do that use the `SCCACHE_OSS_KEY_PREFIX` environment variable. This can be useful when sharing a bucket with another application.

## Credentials

Sccache is able to load credentials from environment variables: `ALIBABA_CLOUD_ACCESS_KEY_ID` and `ALIBABA_CLOUD_ACCESS_KEY_SECRET`.

Alternatively, the `SCCACHE_OSS_NO_CREDENTIALS` environment variable can be set to use public readonly access to the OSS bucket, without the need for credentials. Valid values for this environment variable are `true`, `1`, `false`, and `0`. This can be useful for implementing a readonly cache for pull requests, which typically cannot be given access to credentials for security reasons.


================================================
FILE: docs/Redis.md
================================================
# Redis

If you want to use [Redis](https://redis.io/) storage for the sccache cache, you need to set the `SCCACHE_REDIS_ENDPOINT` with the single-node redis URL.
If you want to use a Redis cluster, set `SCCACHE_REDIS_CLUSTER_ENDPOINTS` instead of `SCCACHE_REDIS_ENDPOINT` with the comma-separated list of redis node URLs.

Redis endpoint URL format can be found in the [OpenDAL source code](https://github.com/apache/opendal/blob/5f1d5d1d61ed28f63d4955538b33a4d582feebef/core/src/services/redis/backend.rs#L268-L307). Some valid examples:
* `redis://127.0.0.1:6379` or `tcp://127.0.0.1:6379` or `127.0.0.1:6379` - TCP-based Redis connection (non-secure)
* `rediss://@1.2.3.4:6379` - TLS-based Redis connection over TCP (secure)
* `unix:///tmp/redis.sock` or `redis+unix:///tmp/redis.sock` - Unix socket-based Redis connection

Redis can be configured as a LRU (least recently used) cache with a fixed maximum cache size. Set `maxmemory` and `maxmemory-policy` according to the [Redis documentation](https://redis.io/topics/lru-cache). The `allkeys-lru` policy which discards the *least recently accessed or modified* key fits well for the sccache use case.

Redis over TLS is supported. Use the [`rediss://`](https://www.iana.org/assignments/uri-schemes/prov/rediss) url scheme (note `rediss` vs `redis`). Append `#insecure` the url to disable hostname verification and accept self-signed certificates (dangerous!). Note that this also disables [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication).

If you want to authenticate to Redis, set `SCCACHE_REDIS_USERNAME` and `SCCACHE_REDIS_PASSWORD` to the username and password accordingly.

`SCCACHE_REDIS_DB` is the database number to use. Default is 0.

Set `SCCACHE_REDIS_EXPIRATION` in seconds if you don't want your cache to live forever. This will override the default behavior of redis.

`SCCACHE_REDIS_TTL` is a deprecated synonym for `SCCACHE_REDIS_EXPIRATION`.

Set `SCCACHE_REDIS_KEY_PREFIX` if you want to prefix all cache keys. This can be
useful when sharing a Redis instance with another application or cache.

`SCCACHE_REDIS` is deprecated for security reasons, use `SCCACHE_REDIS_ENDPOINT` instead. See mozilla/sccache#2083 for details.
If you really want to use `SCCACHE_REDIS`, you should URL in format `redis://[[<username>]:<passwd>@]<hostname>[:port][/?db=<db>]`.

## Deprecated API Examples

Use the local Redis instance with no password:
```sh
SCCACHE_REDIS=redis://localhost
```

Use the local Redis instance on port `6379` with password `qwerty`:
```sh
SCCACHE_REDIS=redis://:qwerty@localhost:6379
```

Use the `192.168.1.10` Redis instance on port `6380` with username `alice`, password `qwerty123` and database `12` via TLS connection:
```sh
SCCACHE_REDIS=rediss://alice:qwerty123@192.168.1.10:6380/?db=12
```


================================================
FILE: docs/Releasing.md
================================================
# Sccache Release Process

Most of the sccache release process is automated. The [github workflow](https://github.com/mozilla/sccache/actions?query=workflow%3Aci) contains builds for all supported platforms, as well as a release job that is triggered by pushing a new tag to the repository. That job will upload the resulting binary packages to [the GitHub releases page](https://github.com/mozilla/sccache/releases) on the repository.

# Producing a release

We use [`cargo-release`](https://crates.io/crates/cargo-release) to produce releases, since it encapsulates the steps of bumping the version number, creating and pushing a new tag, and releasing to [crates.io](https://crates.io/crates/sccache). You can install it with `cargo install cargo-release`, then simply run `cargo release` in an sccache checkout to do the work. Note that it supports a `--dry-run` option you can use to preview what it will run.

## Things to be aware of

1. You must have authenticated to crates.io using `cargo login` to publish the sccache create there.
2. cargo will not allow publishing a create if there are crates in the `[patch]` section in `Cargo.toml`.


================================================
FILE: docs/ResponseFiles.md
================================================
# Response Files

Response files are a way for compilers to accept arguments that would otherwise overflow the character limit in the command line. [On Windows in particular](https://learn.microsoft.com/en-us/troubleshoot/windows-client/shell-experience/command-line-string-limitation), the character limit per command is 8191 characters. These files can contain additional options that the compiler will read and process as if they were provided in the original command. Each compiler that supports response files has different formats/expectations and implementations. Support for response files are also re-implemented per compiler by sccache so it can cache compilations accurately. There is currently support for response files on the gcc and msvc implementations in sccache.

## GCC

As defined by the [gcc docs](https://gcc.gnu.org/onlinedocs/gcc-4.6.3/gcc/Overall-Options.html#Overall-Options):

1. Options in a response file are inserted in-place in the original command line. If the file does not exist or cannot be read, the option will be treated literally, and not removed.
2. Options in a response file are separated by whitespace.
3. Single or double quotes can be used to include whitespace in an option.
4. Any character (including a backslash) may be included by prefixing the character to be included with a backslash (e.g. `\\`, `\?`, `\@`, etc).
5. The response file may itself contain additional @file options; any such options will be processed recursively.

Implementation details:
- The gcc implementation in sccache supports all of these **except** #3. If a response file contains **any** quotations (`"` or `'`), the @file arg is treated literally and not removed (and its content not processed).
- Additionally, sccache will not expand concatenated arguments such as `-include@foo` (see [#150](https://github.com/mozilla/sccache/issues/150#issuecomment-318586953) for more on this).
- Recursive files are processed depth-first; when an @file option is encountered, its contents are read and each option is evaluated in-place before continuing to options following the @file.

## MSVC

Per the [MSVC docs](https://learn.microsoft.com/en-us/cpp/build/reference/cl-command-files?view=msvc-170):

1. The contents of a response file are inserted in-place in the original command.
2. Response files can contain multiple lines of options, but each option must begin and end on the same line.
3. Backslashes (`\`) cannot be used to combine options across multiple lines.
4. The `/link` directive has special treatment:
    1. Entering an @file: if the `/link` option is provided prior to an `@file` in the command line, the `/link` directive does not affect any options within the `@file`.
    2. Newlines: A `/link` directive provided in an `@file` on one line does not affect the next line.
    3. Exiting an @file: A `/link` directive on the final line of a response file does not affect options following the `@file` option in the command line.
5. A response file cannot contain additional `@file` options, they are not recursive. (found in a [separate doc](https://learn.microsoft.com/en-us/cpp/build/reference/at-specify-a-compiler-response-file?view=msvc-170))
6. (implied) options can be wrapped in double-quotes (`"`), which allows whitespace to be preserved within the option

The msvc implementation in sccache supports all of these **except** #4, because sccache doesn't accept the `/link` directive. 

Additionally, because `msbuild` generates response files using an encoding other than `utf-8`, all text files under the [WHATWG encoding standard](https://encoding.spec.whatwg.org/) are supported. This includes both `utf-8` and `utf-16`.


================================================
FILE: docs/Rust.md
================================================
sccache includes support for caching Rust compilation. This includes many caveats, and is primarily focused on caching rustc invocations as produced by cargo. A (possibly-incomplete) list follows:
* `--emit` is required.
* `--crate-name` is required.
* Only `link`, `metadata` and `dep-info` are supported as `--emit` values, and `link` must be present.
* `--out-dir` is required.
* `-o file` is not supported.
* Compilation from stdin is not supported, a source file must be provided.
* Values from `env!` require Rust >= 1.46 to be tracked in caching.
* Procedural macros that read files from the filesystem may not be cached properly

If you are using Rust 1.18 or later, you can ask cargo to wrap all compilation with sccache by setting `RUSTC_WRAPPER=sccache` in your build environment.


================================================
FILE: docs/S3.md
================================================
# S3

If you want to use S3 storage for the sccache cache, you need to set the following environment variables:

- `SCCACHE_BUCKET` with the name of the S3 bucket to use;
- `SCCACHE_REGION` with the S3 region. If you have set `SCCACHE_ENDPOINT`, you can set `SCCACHE_REGION` to `auto`;
- Optionally, `SCCACHE_ENDPOINT=<ip>:<port>` with a custom URL of a server you want a use, such as MinIO or DigitalOcean storage.
- `SCCACHE_S3_ENABLE_VIRTUAL_HOST_STYLE` to `true` if you are using a custom endpoint that supports virtual host style addressing. This is required for S3 transfer acceleration and some S3-compatible storage services. If you are using AWS S3, you can leave this unset.

If your endpoint requires HTTPS/TLS, set `SCCACHE_S3_USE_SSL=true`. If you don't need a secure network layer, HTTP (`SCCACHE_S3_USE_SSL=false`) might be better for performance.

Enable server-side encryption with s3 managed key (SSE-S3), set `SCCACHE_S3_SERVER_SIDE_ENCRYPTION=true`.  
More details about encryption [here](https://opendal.apache.org/docs/services/s3/#server-side-encryption) and documentation [here](https://docs.rs/opendal/latest/opendal/services/struct.S3.html#method.server_side_encryption_with_s3_key).

You can also define a prefix that will be prepended to the keys of all cache objects created and read within the S3 bucket, effectively creating a scope. To do that use the `SCCACHE_S3_KEY_PREFIX` environment variable. This can be useful when sharing a bucket with another application.

# R2

Cloudflare R2 is an S3-compatible object storage and works with the same configuration options as above. To use R2, you **must** define `SCCACHE_ENDPOINT`, otherwise sccache will default to AWS as the endpoint to hit. R2 also requires endpoint connections to be secure, therefore `https://` either needs to be included in `SCCACHE_ENDPOINT` or `SCCACHE_S3_USE_SSL=true` can be used, if the protocol is omitted. There are no regions in R2, so `SCCACHE_REGION` must point to `auto`. The below environment variables are recommended.

- `SCCACHE_BUCKET` is the name of your R2 bucket.
- `SCCACHE_ENDPOINT` should follow the format of `https://<ACCOUNT_ID>.r2.cloudflarestorage.com`. It is recommended that `https://` be included in this env var. Your account ID can be found [here](https://developers.cloudflare.com/fundamentals/get-started/basic-tasks/find-account-and-zone-ids/).
- `SCCACHE_REGION` should be set to `auto`.

## Credentials

Sccache is able to load credentials from various sources. Including:

- Static: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
- Profile: `~/.aws/credentials` and `~/.aws/config`. The AWS_PROFILE environment variable can be used to select a specific profile if multiple profiles are available.
- EC2 Metadata Services: Via [IMDSv2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html).
- AssumeRole: assume role with the role specified by `AWS_ROLE_ARN`.
- AssumeRoleWithWebIdentity: assume role with web webIdentity specified by `AWS_ROLE_ARN` and `AWS_WEB_IDENTITY_TOKEN_FILE`.

Alternatively, the `SCCACHE_S3_NO_CREDENTIALS` environment variable can be set to use public readonly access to the S3 bucket, without the need for credentials. Valid values for this environment variable are `true`, `1`, `false`, and `0`. This can be useful for implementing a readonly cache for pull requests, which typically cannot be given access to credentials for security reasons.


================================================
FILE: docs/Webdav.md
================================================
# WebDAV

Users can configure sccache to cache incremental build artifacts in a remote WebDAV service.
The following services all expose a WebDAV interface and can be used as a backend:

- [Ccache HTTP storage backend](https://ccache.dev/manual/4.7.4.html#_http_storage_backend)
- [Bazel Remote Caching](https://bazel.build/remote/caching).
- [Gradle Build Cache](https://docs.gradle.org/current/userguide/build_cache.html)

Set `SCCACHE_WEBDAV_ENDPOINT` to an appropriate webdav service endpoint to enable remote caching.
Set `SCCACHE_WEBDAV_KEY_PREFIX` to specify the key prefix of cache.

## Credentials

Sccache is able to load credentials from the following sources:

- Set `SCCACHE_WEBDAV_USERNAME`/`SCCACHE_WEBDAV_PASSWORD` to specify the username/password pair for basic authentication.
- Set `SCCACHE_WEBDAV_TOKEN` to specify the token value for bearer token authentication.


================================================
FILE: docs/Xcode.md
================================================
# Using `sccache` with Xcode

It is possible to use `sccache` with Xcode with some setup.

### Running the daemon
Before building, you need to run the daemon outside of Xcode. This needs to be done because if `sccache` invocation happens to implicitly start the server daemon, the Xcode build will hang on the `sccache` invocation, waiting for the process to idle timeout.

You can do this in another terminal windows by calling
```sh
SCCACHE_LOG=info SCCACHE_START_SERVER=1 SCCACHE_NO_DAEMON=1 sccache
```

Or by setting it up in a `launchd` configuration, perhaps as `~/Library/LaunchAgents/sccache.plist` (note the paths in the plist):
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>sccache.server</string>
    <key>ProgramArguments</key>
    <array>
      <string>/path/to/sccache</string>
    </array>
    <key>EnvironmentVariables</key>
    <dict>
        <key>SCCACHE_START_SERVER</key>
        <string>1</string>
        <key>SCCACHE_NO_DAEMON</key>
        <string>1</string>
        <key>SCCACHE_IDLE_TIMEOUT</key>
        <string>0</string>
        <key>SCCACHE_LOG</key>
        <string>info</string>
    </dict>

    <key>StandardOutPath</key>
    <string>/tmp/sccache.log</string>
    <key>StandardErrorPath</key>
    <string>/tmp/sccache.log</string>

  </dict>
</plist>
```

### Setting it up for `xcodebuild`

Xcode seems to support barely documented `C_COMPILER_LAUNCHER` attribute, for 
having a custom launcher program.

Then you can invoke `xcodebuild` like so
```sh
xcodebuild C_COMPILER_LAUNCHER=sccache
           CLANG_ENABLE_MODULES=NO
           COMPILER_INDEX_STORE_ENABLE=NO
           CLANG_USE_RESPONSE_FILE=NO
```
Where the additional arguments are for disabling some features that `sccache` can't cache currently.

These build settings can also be put in a xcconfig file, like `sccache.xcconfig`
```
C_COMPILER_LAUNCHER=sccache
CLANG_ENABLE_MODULES=NO
COMPILER_INDEX_STORE_ENABLE=NO
CLANG_USE_RESPONSE_FILE=NO
```
Which can then be invoked with
```sh
xcodebuild -xcconfig sccache.xcconfig
```


### Setting it up for `cmake` Xcode generator
While `cmake` has the convenient `CMAKE_<LANG>_COMPILER_LAUNCHER` for prepending tools like `sccache`, it is not supported for the Xcode generator.

But you can configuring it directly with something like
```cmake

# This bit before the first `project()`, as the COMPILER_LAUNCHER variables are read in then
if(DEFINED CCACHE)
    find_program(CCACHE_EXE ${CCACHE} REQUIRED)
    if(NOT CMAKE_GENERATOR STREQUAL "Xcode")
        # Support for other generators should work with these
        set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_EXE}")
        set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_EXE}")
    else()
        # And this should work for Xcode generator
        set(CMAKE_XCODE_ATTRIBUTE_C_COMPILER_LAUNCHER ${CCACHE_EXE})
        set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES "NO")
        set(CMAKE_XCODE_ATTRIBUTE_COMPILER_INDEX_STORE_ENABLE "NO")
        set(CMAKE_XCODE_ATTRIBUTE_CLANG_USE_RESPONSE_FILE "NO")
    endif()
endif()
```
Then configuring with `-DCCACHE=sccache` should work on all generators.





================================================
FILE: flake.nix
================================================
{
  description = "sccache development environment and package";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = {
    self,
    nixpkgs,
    flake-utils,
  }: let
    cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml);
    version = cargoToml.package.version;

    mkSccache = {
      final,
      pname,
      features ? [],
      description,
    }:
      final.rustPlatform.buildRustPackage {
        pname = pname;
        inherit version;

        src = ./.;

        cargoLock = {
          lockFile = ./Cargo.lock;
        };

        nativeBuildInputs = [final.pkg-config];
        buildInputs = [final.openssl];

        cargoBuildFlags =
          if features != []
          then [
            "--features"
            (builtins.concatStringsSep "," features)
          ]
          else [];

        doCheck = false;

        meta = with final.lib; {
          description = description;
          homepage = "https://github.com/mozilla/sccache";
          changelog = "https://github.com/mozilla/sccache/releases/tag/v${version}";
          license = licenses.asl20;
          mainProgram = "sccache";
        };
      };
  in
    flake-utils.lib.eachSystem
    [
      "x86_64-linux"
      "aarch64-linux"
      "x86_64-darwin"
      "aarch64-darwin"
      "i686-linux"
    ]
    (
      system: let
        pkgs = import nixpkgs {
          inherit system;
          overlays = [self.overlays.default];
        };
      in {
        packages = {
          default = pkgs.sccache;
          sccache = pkgs.sccache;
          sccache-dist = pkgs.sccache-dist;
        };

        devShells.default = pkgs.mkShell {
          name = "sccache-dev";

          buildInputs = with pkgs; [
            rustup
            openssl
            pkg-config
            gcc
          ];
        };

        formatter = pkgs.alejandra;
      }
    )
    // {
      overlays.default = final: prev: {
        sccache = mkSccache {
          inherit final;
          pname = "sccache";
          description = "Ccache with Cloud Storage";
        };
        sccache-dist = mkSccache {
          inherit final;
          pname = "sccache-dist";
          features = [
            "dist-client"
            "dist-server"
          ];
          description = "Ccache with Cloud Storage and Distributed Compilation";
        };
      };
    };
}


================================================
FILE: scripts/extratest.sh
================================================
#!/bin/sh
set -o errexit
set -o pipefail
set -o nounset
set -o xtrace

#CARGO="cargo --color=always"
CARGO="cargo"

gnutarget=x86_64-unknown-linux-gnu
wintarget=x86_64-pc-windows-gnu

gnutarget() {
    unset OPENSSL_DIR
    export OPENSSL_STATIC=1
    target=$gnutarget
}
wintarget() {
    export OPENSSL_DIR=$(pwd)/openssl-win
    export OPENSSL_STATIC=1
    target=$wintarget
}

# all-windows doesn't work as redis-rs build.rs has issues (checks for cfg!(unix))

if [ "$1" = checkall ]; then
    $CARGO check --target $target --all-targets --features 'all dist-client dist-server dist-tests'
    $CARGO check --target $target --all-targets --features 'all dist-client dist-server'
    $CARGO check --target $target --all-targets --features 'all dist-client dist-tests'
    $CARGO check --target $target --all-targets --features 'all dist-server dist-tests'
    $CARGO check --target $target --all-targets --features 'all dist-client'
    $CARGO check --target $target --all-targets --features 'all dist-server'
    $CARGO check --target $target --all-targets --features 'all dist-tests'
    $CARGO check --target $target --all-targets --features 'all'
    $CARGO check --target $target --all-targets --features 'dist-client dist-server dist-tests'
    $CARGO check --target $target --all-targets --features 'dist-client dist-server'
    $CARGO check --target $target --all-targets --features 'dist-client dist-tests'
    $CARGO check --target $target --all-targets --features 'dist-server dist-tests'
    $CARGO check --target $target --all-targets --features 'dist-client'
    $CARGO check --target $target --all-targets --features 'dist-server'
    $CARGO check --target $target --all-targets --features 'dist-tests'
    $CARGO check --target $target --all-targets --features ''
    $CARGO check --target $target --all-targets --no-default-features --features 'all dist-client dist-server dist-tests'
    $CARGO check --target $target --all-targets --no-default-features --features 'all dist-client dist-server'
    $CARGO check --target $target --all-targets --no-default-features --features 'all dist-client dist-tests'
    $CARGO check --target $target --all-targets --no-default-features --features 'all dist-server dist-tests'
    $CARGO check --target $target --all-targets --no-default-features --features 'all dist-client'
    $CARGO check --target $target --all-targets --no-default-features --features 'all dist-server'
    $CARGO check --target $target --all-targets --no-default-features --features 'all dist-tests'
    $CARGO check --target $target --all-targets --no-default-features --features 'all'
    $CARGO check --target $target --all-targets --no-default-features --features 'dist-client dist-server dist-tests'
    $CARGO check --target $target --all-targets --no-default-features --features 'dist-client dist-server'
    $CARGO check --target $target --all-targets --no-default-features --features 'dist-client dist-tests'
    $CARGO check --target $target --all-targets --no-default-features --features 'dist-server dist-tests'
    $CARGO check --target $target --all-targets --no-default-features --features 'dist-client'
    $CARGO check --target $target --all-targets --no-default-features --features 'dist-server'
    $CARGO check --target $target --all-targets --no-default-features --features 'dist-tests'
    $CARGO check --target $target --all-targets --no-default-features --features ''
    wintarget
    $CARGO check --target $target --all-targets --features 'dist-client'
    #$CARGO check --target $target --all-targets --features 'all-windows dist-client'
    #$CARGO check --target $target --all-targets --features 'all-windows'
    $CARGO check --target $target --all-targets --features ''


elif [ "$1" = test ]; then
    # Musl tests segfault due to https://github.com/mozilla/sccache/issues/256#issuecomment-399254715
    gnutarget
    VERBOSE=
    NOCAPTURE=
    NORUN=
    TESTTHREADS=
    #VERBOSE="--verbose"
    #NORUN=--no-run
    #NOCAPTURE=--nocapture
    TESTTHREADS="--test-threads 1"

    # Since integration tests start up the sccache server they must be run sequentially. This only matters
    # if you have multiple test functions in one file.

    set +x
    if ! which docker; then
        printf "WARNING: =====\n\ndocker not present, some tests will fail\n\n=====\n\n\n\n\n"
        sleep 5
    fi
    if ! which icecc-create-env; then
        printf "WARNING: =====\n\nicecc-create-env not present, some tests will fail\n\n=====\n\n\n\n\n"
        sleep 5
    fi
    set -x

    RUST_BACKTRACE=1 $CARGO test $NORUN --target $target --features 'all dist-client dist-server dist-tests' $VERBOSE -- $NOCAPTURE $TESTTHREADS test_dist_nobuilder

else
    echo invalid command
    exit 1
fi


================================================
FILE: scripts/freebsd-ci-test.sh
================================================
#!/bin/sh

# This script contains CI tests for FreeBSD, testing
#
# - cargo build & cargo test
# - configure and start sccache-dist and scheduler
# - test distributed compile
# - test that the cache is used
#
# It creates a temporary test pool backed by a
# file (using mdconfig) and does a full configuration
# of pot.
#
# After running it copies the sccache log file into
# the repo's root directory. It also does a full
# cleanup (removal of all temporary files, test pool
# etc.) after each run. This can be prevented by
# setting FREEBSD_CI_NOCLEAN in the environment:
#
#     FREEBSD_CI_NOCLEAN=1 scripts/freebsd-ci-test.sh
#
# When running in a loop, time and bandwidth can be
# saved by placing FreeBSD distribution files in
# $HOME/.potcache
#
#     mkdir $HOME/.potcache
#     fetch -o $HOME/.potcache/15.0-RELEASE_base.txz \
#     https://ftp.freebsd.org/pub/FreeBSD/releases/amd64/15.0-RELEASE/base.txz
#
# This script can be run from a github action. When run locally, make
# sure to install the required packages:
#
#     pkg install -y ca-root-nss curl gmake gtar pot sudo
#

# shellcheck disable=SC3040
set -eo pipefail

init()
{
	base=$(realpath "$(dirname "$0")"/..)
	OS_VERSION="$(freebsd-version | awk -F- '{print $1}')"
	PUB_INTF="$(netstat -4rn | grep default | awk '{ print $4}')"
	TEST_TMPDIR=$(mktemp -d "/tmp/sccache_freebsd.XXXXXXX") || exit 1
	chmod g+r "$TEST_TMPDIR"
	export XDG_CONFIG_HOME="$TEST_TMPDIR/.config"
	mkdir -p "$XDG_CONFIG_HOME"
	export SCCACHE_DIR="$TEST_TMPDIR/.cache"
	killall sccache 2>/dev/null || true
	killall sccache-dist 2>/dev/null || true
	export RUST_LOG_STYLE=never
}

output_env_info()
{
	echo "## user"
	whoami
	echo "## environment"
	env | sort
	echo "## network"
	ifconfig
	echo "## tooling info"
	cargo -V
	rustc -V
	curl --version
	# See https://github.com/bsdpot/pot/pull/253
	pot version || true
	gtar --version
	echo "## installed packages"
	pkg info
}

build_and_test_project()
{
	echo "#### building sccache (cargo)"
	cd "$base"
	FAULT=0
	export RUSTFLAGS="-C debuginfo=0"
	cargo build --features "dist-client,dist-server" || FAULT=1
	echo "#### testing sccache (cargo)"
	cargo test --features "dist-client,dist-server" -- \
	  --test-threads 1 || FAULT=1
	unset RUSTFLAGS
	if [ "$FAULT" -eq 0 ]; then
		# save build time by avoiding "cargo install"
		cp -a target/debug/sccache target/debug/sccache-dist \
		  "$HOME/.cargo/bin/."
	fi
	if [ $FAULT -ne 0 ]; then return 1; fi
}

prepare_and_run_sccache_dist()
{
	echo "#### preparing sccache-dist"
	SECRET_KEY="$(sccache-dist auth generate-jwt-hs256-key)"
	CLIENT_AUTH_KEY="$(sccache-dist auth generate-jwt-hs256-key)"
	# create scheduler.conf
	cat >"$TEST_TMPDIR"/scheduler.conf <<-EOF
	public_addr = "127.0.0.1:10600"
	[client_auth]
	type = "token"
	token = "$CLIENT_AUTH_KEY"
	[server_auth]
	type = "jwt_hs256"
	secret_key = "$SECRET_KEY"
	EOF
	SERVER_TOKEN="$(sccache-dist auth generate-jwt-hs256-server-token \
	  --config="$TEST_TMPDIR"/scheduler.conf \
	  --server="127.0.0.1:10501")"

	# Create server.conf
	cat >"$TEST_TMPDIR"/server.conf <<-EOF
	cache_dir = "$TEST_TMPDIR/toolchains"
	public_addr = "127.0.0.1:10501"
	scheduler_url = "http://127.0.0.1:10600"
	[builder]
	type = "pot"
	pot_fs_root = "$TEST_TMPDIR/pot"
	[scheduler_auth]
	type = "jwt_token"
	token = "$SERVER_TOKEN"
	EOF

	# create sccache client config
	TC="$(rustup toolchain list | grep default | awk '{ print $1 }')"
	RUSTC_PATH="$HOME/.rustup/toolchains/$TC/bin/rustc"
	mkdir -p "$XDG_CONFIG_HOME/sccache"
	cat >"$XDG_CONFIG_HOME/sccache/config" <<-EOF
	[dist]
	scheduler_url = "http://127.0.0.1:10600"
	toolchain_cache_size = 5368709120
	cache_dir = "$HOME/.cache/sccache-dist-client"
	[dist.auth]
	type = "token"
	token = "$CLIENT_AUTH_KEY"
	[[dist.toolchains]]
	type = "path_override"
	compiler_executable = "/usr/bin/cc"
	archive = "$TEST_TMPDIR/empty.tar.gz"
	archive_compiler_executable = "/usr/bin/cc"
	[[dist.toolchains]]
	type = "path_override"
	compiler_executable = "$RUSTC_PATH"
	archive = "$TEST_TMPDIR/rust-toolchain.tgz"
	archive_compiler_executable = "$RUSTC_PATH"
	EOF

	echo "Creating toolchain tarballs"
	gtar cvf - --files-from /dev/null | \
	  gzip -n >"$TEST_TMPDIR/empty.tar.gz"
	gtar cf - --sort=name --mtime='2022-06-28 17:35Z' "$HOME/.rustup"  | \
	  gzip -n >"$TEST_TMPDIR/rust-toolchain.tgz"

	echo "Starting scheduler"
	sccache-dist scheduler --config "$TEST_TMPDIR"/scheduler.conf
}

prepare_zpool()
{
	echo "#### preparing zpool"
	sudo dd if=/dev/zero of="$TEST_TMPDIR/zfs1" bs=1 count=1 seek=3G
	MDUNIT=$(sudo mdconfig -a -n -t vnode -S 4096 -f "$TEST_TMPDIR/zfs1")
	zdev="/dev/md$MDUNIT"
	sudo zpool create -f potpool "$zdev"
}

prepare_pot()
{
	echo "#### preparing pot"
	sudo sysrc -f /usr/local/etc/pot/pot.conf POT_ZFS_ROOT=potpool/pot
	sudo sysrc -f /usr/local/etc/pot/pot.conf POT_EXTIF="$PUB_INTF"
	sudo sysrc -f /usr/local/etc/pot/pot.conf POT_TMP="$TEST_TMPDIR"
	sudo sysrc -f /usr/local/etc/pot/pot.conf \
	  POT_FS_ROOT="$TEST_TMPDIR/pot"
	sudo sysrc -f /usr/local/etc/pot/pot.conf POT_GROUP=wheel
	sudo pot init -f ""
	sudo pot version
	sudo cp "$HOME"/.potcache/*.txz /var/cache/pot 2>/dev/null || true
	sudo pot create -p sccache-template -N alias -i "lo0|127.0.0.2" \
	  -t single -b "$OS_VERSION"
	sudo pot set-cmd -p sccache-template -c /usr/bin/true
	sudo pot set-attr -p sccache-template -A no-rc-script -V YES
	sudo pot snapshot -p sccache-template
}

start_build_server()
{
	echo "#### starting build-server (as root)"
	SCCACHE_DIST_LOG=debug RUST_LOG=info sudo \
	  "$HOME"/.cargo/bin/sccache-dist server \
	  --config "$TEST_TMPDIR"/server.conf &
}

wait_for_build_server()
{
	echo "#### waiting for build server to become available"
	count=0
	while [ "$(sockstat -q4l -p 10501 | wc -l | xargs)" -eq "0" ]; do
		count=$(( count + 1 ))
		if [ $count -gt 60 ]; then
			2>&1 echo "Build server did not become available"
			return 1
		fi
		sleep 5
	done
}

create_build_test_project()
{
	echo "#### create and build test project"
	cd "$TEST_TMPDIR"
	cargo init buildtest
	cd buildtest
	echo 'c
Download .txt
gitextract__oh_a4dj/

├── .envrc
├── .github/
│   ├── actions/
│   │   ├── artifact_failure/
│   │   │   └── action.yml
│   │   ├── nvcc-toolchain/
│   │   │   ├── action.yml
│   │   │   ├── install-cuda.ps1
│   │   │   └── install-cuda.sh
│   │   └── rust-toolchain/
│   │       └── action.yml
│   ├── codecov.yml
│   ├── dependabot.yml
│   └── workflows/
│       ├── benchmarks.yml
│       ├── ci.yml
│       ├── close-snap.yml
│       ├── integration-tests.yml
│       └── snap.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .rustfmt.toml
├── .taplo.toml
├── CODE_OF_CONDUCT.md
├── Cargo.toml
├── LICENSE
├── README.md
├── benches/
│   └── sccache_bench.rs
├── docs/
│   ├── Architecture.md
│   ├── Azure.md
│   ├── COS.md
│   ├── Caching.md
│   ├── Configuration.md
│   ├── Distributed.md
│   ├── DistributedFreeBSD.md
│   ├── DistributedQuickstart.md
│   ├── GHA.md
│   ├── Gcs.md
│   ├── Jenkins.md
│   ├── Local.md
│   ├── Memcached.md
│   ├── OSS.md
│   ├── Redis.md
│   ├── Releasing.md
│   ├── ResponseFiles.md
│   ├── Rust.md
│   ├── S3.md
│   ├── Webdav.md
│   └── Xcode.md
├── flake.nix
├── scripts/
│   ├── extratest.sh
│   └── freebsd-ci-test.sh
├── snap/
│   └── snapcraft.yaml
├── src/
│   ├── bin/
│   │   └── sccache-dist/
│   │       ├── build.rs
│   │       ├── build_freebsd.rs
│   │       ├── cmdline/
│   │       │   ├── mod.rs
│   │       │   └── parse.rs
│   │       ├── main.rs
│   │       └── token_check.rs
│   ├── cache/
│   │   ├── azure.rs
│   │   ├── cache.rs
│   │   ├── cache_io.rs
│   │   ├── cos.rs
│   │   ├── disk.rs
│   │   ├── gcs.rs
│   │   ├── gha.rs
│   │   ├── http_client.rs
│   │   ├── lazy_disk_cache.rs
│   │   ├── memcached.rs
│   │   ├── mod.rs
│   │   ├── oss.rs
│   │   ├── readonly.rs
│   │   ├── redis.rs
│   │   ├── s3.rs
│   │   ├── utils.rs
│   │   └── webdav.rs
│   ├── client.rs
│   ├── cmdline.rs
│   ├── commands.rs
│   ├── compiler/
│   │   ├── args.rs
│   │   ├── c.rs
│   │   ├── cicc.rs
│   │   ├── clang.rs
│   │   ├── compiler.rs
│   │   ├── counted_array.rs
│   │   ├── cudafe.rs
│   │   ├── diab.rs
│   │   ├── gcc.rs
│   │   ├── mod.rs
│   │   ├── msvc.rs
│   │   ├── nvcc.rs
│   │   ├── nvhpc.rs
│   │   ├── preprocessor_cache.rs
│   │   ├── ptxas.rs
│   │   ├── rust.rs
│   │   └── tasking_vx.rs
│   ├── config.rs
│   ├── dist/
│   │   ├── cache.rs
│   │   ├── client_auth.rs
│   │   ├── http.rs
│   │   ├── mod.rs
│   │   ├── pkg.rs
│   │   └── test.rs
│   ├── errors.rs
│   ├── jobserver.rs
│   ├── lib.rs
│   ├── lru_disk_cache/
│   │   ├── lru_cache.rs
│   │   └── mod.rs
│   ├── main.rs
│   ├── mock_command.rs
│   ├── net.rs
│   ├── protocol.rs
│   ├── server.rs
│   ├── test/
│   │   ├── mock_storage.rs
│   │   ├── mod.rs
│   │   ├── tests.rs
│   │   └── utils.rs
│   └── util.rs
└── tests/
    ├── cache_hit_rate.rs
    ├── cmake-modules/
    │   ├── CMakeLists.txt
    │   ├── main.cpp
    │   └── mymodule.cppm
    ├── dist.rs
    ├── harness/
    │   ├── Dockerfile.sccache-dist
    │   └── mod.rs
    ├── helpers/
    │   └── mod.rs
    ├── integration/
    │   ├── Makefile
    │   ├── README.md
    │   ├── autotools/
    │   │   ├── Makefile.am
    │   │   ├── configure.ac
    │   │   └── main.cpp
    │   ├── basedirs-autotools/
    │   │   ├── Makefile.am
    │   │   ├── configure.ac
    │   │   ├── include/
    │   │   │   └── myheader.h
    │   │   └── main.cpp
    │   ├── cmake/
    │   │   ├── CMakeLists.txt
    │   │   └── main.cpp
    │   ├── cmake-hip/
    │   │   ├── CMakeLists.txt
    │   │   └── vectoradd_hip.cpp
    │   ├── docker-compose.yml
    │   ├── msvc/
    │   │   ├── args.rsp
    │   │   └── foo.cpp
    │   ├── msvc-preprocessing/
    │   │   ├── args.rsp
    │   │   └── foo.cpp
    │   ├── randomize_readdir/
    │   │   ├── Cargo.toml
    │   │   └── src/
    │   │       └── lib.rs
    │   ├── scripts/
    │   │   ├── test-autotools.sh
    │   │   ├── test-backend.sh
    │   │   ├── test-basedirs.sh
    │   │   ├── test-clang.sh
    │   │   ├── test-cmake.sh
    │   │   ├── test-coverage.sh
    │   │   ├── test-gcc.sh
    │   │   └── test-zstd.sh
    │   ├── test_intel_asm.s
    │   ├── test_intel_asm_to_preproc.S
    │   ├── webdav-config.yaml
    │   └── xcode/
    │       ├── main.cpp
    │       ├── sccache.xcconfig
    │       └── xcode-test.xcodeproj/
    │           └── project.pbxproj
    ├── logging.rs
    ├── msvc-msbuild/
    │   ├── .gitignore
    │   ├── MsbuildCpp.vcxproj
    │   ├── test_bar.cpp
    │   ├── test_baz.cpp
    │   └── test_foo.cpp
    ├── oauth.rs
    ├── sccache_args.rs
    ├── sccache_cargo.rs
    ├── sccache_rustc.rs
    ├── system.rs
    ├── test-crate/
    │   ├── Cargo.toml
    │   └── src/
    │       ├── bin.rs
    │       └── lib.rs
    ├── test.c
    ├── test.c.gcc-13.2.0-preproc
    ├── test_a.cu
    ├── test_a.hip
    ├── test_b.cu
    ├── test_b.hip
    ├── test_c.cu
    ├── test_c.hip
    ├── test_clang_multicall.c
    ├── test_err.c
    ├── test_macro_expansion.c
    ├── test_whitespace.c
    ├── test_whitespace_alt.c
    └── test_with_define.c
Download .txt
SYMBOL INDEX (2294 symbols across 93 files)

FILE: benches/sccache_bench.rs
  function generate_test_data (line 33) | fn generate_test_data(size: usize) -> Vec<u8> {
  function generate_preprocessor_output (line 45) | fn generate_preprocessor_output(num_lines: usize) -> Vec<u8> {
  function generate_data_with_time_macros (line 68) | fn generate_data_with_time_macros(size: usize) -> Vec<u8> {
  function hash_large_data (line 86) | fn hash_large_data(bencher: Bencher) {
  function time_macro_finder_no_macros (line 101) | fn time_macro_finder_no_macros(bencher: Bencher) {
  function time_macro_finder_with_macros (line 112) | fn time_macro_finder_with_macros(bencher: Bencher) {
  function time_macro_finder_chunked (line 123) | fn time_macro_finder_chunked(bencher: Bencher) {
  function lru_cache_insert (line 143) | fn lru_cache_insert(bencher: Bencher) {
  function lru_cache_get_hit (line 162) | fn lru_cache_get_hit(bencher: Bencher) {
  function lru_cache_eviction (line 184) | fn lru_cache_eviction(bencher: Bencher) {
  function lru_cache_mixed_workload (line 206) | fn lru_cache_mixed_workload(bencher: Bencher) {
  function simulate_hash_key (line 241) | fn simulate_hash_key(
  function cache_key_generation (line 276) | fn cache_key_generation(bencher: Bencher) {
  function generate_object_file (line 320) | fn generate_object_file(size: usize) -> Vec<u8> {
  function cache_entry_create_small (line 331) | fn cache_entry_create_small(bencher: Bencher) {
  function cache_entry_create_large (line 350) | fn cache_entry_create_large(bencher: Bencher) {
  function cache_entry_roundtrip_small (line 369) | fn cache_entry_roundtrip_small(bencher: Bencher) {
  function cache_entry_roundtrip_large (line 394) | fn cache_entry_roundtrip_large(bencher: Bencher) {
  function cache_entry_batch_create (line 421) | fn cache_entry_batch_create(bencher: Bencher) {
  function cache_entry_batch_roundtrip (line 442) | fn cache_entry_batch_roundtrip(bencher: Bencher) {
  function hash_header_file (line 480) | fn hash_header_file(bencher: Bencher) {
  function hash_multiple_files (line 492) | fn hash_multiple_files(bencher: Bencher) {
  function build_workflow_initial (line 516) | fn build_workflow_initial(bencher: Bencher) {
  function build_workflow_rebuild (line 545) | fn build_workflow_rebuild(bencher: Bencher) {
  function build_workflow_incremental (line 586) | fn build_workflow_incremental(bencher: Bencher) {
  function generate_compressible_data (line 642) | fn generate_compressible_data(size: usize) -> Vec<u8> {
  function generate_incompressible_data (line 653) | fn generate_incompressible_data(size: usize) -> Vec<u8> {
  function compression_high_compressibility (line 664) | fn compression_high_compressibility(bencher: Bencher) {
  function compression_low_compressibility (line 680) | fn compression_low_compressibility(bencher: Bencher) {
  function decompression_high_ratio (line 696) | fn decompression_high_ratio(bencher: Bencher) {
  function decompression_low_ratio (line 718) | fn decompression_low_ratio(bencher: Bencher) {
  function lru_hotcold_access_pattern (line 744) | fn lru_hotcold_access_pattern(bencher: Bencher) {
  function lru_sequential_scan_pattern (line 776) | fn lru_sequential_scan_pattern(bencher: Bencher) {
  function lru_realistic_eviction_pressure (line 799) | fn lru_realistic_eviction_pressure(bencher: Bencher) {
  function generate_win_path (line 824) | fn generate_win_path(depth: usize) -> Vec<u8> {
  function generate_preprocessor_output_with_paths (line 834) | fn generate_preprocessor_output_with_paths(num_includes: usize, basedir:...
  function normalize_win_path_typical (line 849) | fn normalize_win_path_typical(bencher: Bencher) {
  function strip_basedirs_typical (line 857) | fn strip_basedirs_typical(bencher: Bencher) {
  function strip_basedirs_multiple (line 871) | fn strip_basedirs_multiple(bencher: Bencher) {
  function main (line 888) | fn main() {

FILE: src/bin/sccache-dist/build.rs
  type CommandExt (line 33) | trait CommandExt {
    method check_stdout_trim (line 34) | fn check_stdout_trim(&mut self) -> Result<String>;
    method check_piped (line 35) | fn check_piped(&mut self, pipe: &mut dyn FnMut(&mut ChildStdin) -> Res...
    method check_run (line 36) | fn check_run(&mut self) -> Result<()>;
    method check_stdout_trim (line 40) | fn check_stdout_trim(&mut self) -> Result<String> {
    method check_piped (line 48) | fn check_piped(&mut self, pipe: &mut dyn FnMut(&mut ChildStdin) -> Res...
    method check_run (line 63) | fn check_run(&mut self) -> Result<()> {
  function check_output (line 69) | fn check_output(output: &Output) -> Result<()> {
  function join_suffix (line 81) | fn join_suffix<P: AsRef<Path>>(path: &Path, suffix: P) -> PathBuf {
  type OverlaySpec (line 91) | struct OverlaySpec {
  type DeflatedToolchain (line 97) | struct DeflatedToolchain {
  type OverlayBuilder (line 103) | pub struct OverlayBuilder {
    method new (line 110) | pub fn new(bubblewrap: PathBuf, dir: PathBuf) -> Result<Self> {
    method cleanup (line 164) | fn cleanup(&self) -> Result<()> {
    method prepare_overlay_dirs (line 171) | fn prepare_overlay_dirs(
    method perform_build (line 257) | fn perform_build(
    method finish_overlay (line 424) | fn finish_overlay(&self, _tc: &Toolchain, overlay: OverlaySpec) {
  method run_build (line 442) | fn run_build(
  constant BASE_DOCKER_IMAGE (line 463) | const BASE_DOCKER_IMAGE: &str = "aidanhs/busybox";
  constant DOCKER_SHELL_INIT (line 467) | const DOCKER_SHELL_INIT: &str = "while true; do /busybox sleep 365d && /...
  function docker_diff (line 470) | fn docker_diff(cid: &str) -> Result<String> {
  function docker_rm (line 478) | fn docker_rm(cid: &str) -> Result<()> {
  type DockerBuilder (line 485) | pub struct DockerBuilder {
    method new (line 494) | pub fn new() -> Result<Self> {
    method cleanup (line 507) | fn cleanup(&self) -> Result<()> {
    method get_container (line 577) | fn get_container(&self, tc: &Toolchain, tccache: &Mutex<TcCache>) -> R...
    method clean_container (line 604) | fn clean_container(&self, cid: &str) -> Result<()> {
    method finish_container (line 669) | fn finish_container(&self, tc: &Toolchain, cid: String) {
    method make_image (line 698) | fn make_image(tc: &Toolchain, tccache: &Mutex<TcCache>) -> Result<Stri...
    method start_container (line 741) | fn start_container(image: &str) -> Result<String> {
    method perform_build (line 756) | fn perform_build(
  method run_build (line 855) | fn run_build(

FILE: src/bin/sccache-dist/build_freebsd.rs
  type CommandExt (line 30) | trait CommandExt {
    method check_stdout_trim (line 31) | fn check_stdout_trim(&mut self) -> Result<String>;
    method check_piped (line 32) | fn check_piped(&mut self, pipe: &mut dyn FnMut(&mut ChildStdin) -> Res...
    method check_run (line 33) | fn check_run(&mut self) -> Result<()>;
    method check_stdout_trim (line 37) | fn check_stdout_trim(&mut self) -> Result<String> {
    method check_piped (line 45) | fn check_piped(&mut self, pipe: &mut dyn FnMut(&mut ChildStdin) -> Res...
    method check_run (line 60) | fn check_run(&mut self) -> Result<()> {
  function check_output (line 66) | fn check_output(output: &Output) -> Result<()> {
  function pot_rm (line 79) | fn pot_rm(cid: &str, pot_cmd: &PathBuf) -> Result<()> {
  type PotBuilder (line 87) | pub struct PotBuilder {
    method new (line 102) | pub fn new(
    method cleanup (line 125) | fn cleanup(&self) -> Result<()> {
    method get_container (line 149) | fn get_container(&self, tc: &Toolchain, tccache: &Mutex<TcCache>) -> R...
    method clean_container (line 183) | fn clean_container(cid: &str) -> Result<()> {
    method finish_container (line 203) | fn finish_container(
    method make_image (line 235) | fn make_image(
    method start_container (line 280) | fn start_container(
    method perform_build (line 305) | fn perform_build(
  method run_build (line 402) | fn run_build(

FILE: src/bin/sccache-dist/cmdline/mod.rs
  type Command (line 23) | pub enum Command {
  type AuthSubcommand (line 30) | pub enum AuthSubcommand {

FILE: src/bin/sccache-dist/cmdline/parse.rs
  type TokenLength (line 26) | struct TokenLength(usize);
    method as_bytes (line 29) | fn as_bytes(&self) -> usize {
    method from_bits (line 33) | fn from_bits(bits: &str) -> anyhow::Result<Self> {
    method fmt (line 51) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  type LogLevel (line 57) | enum LogLevel {
  type Err (line 66) | type Err = anyhow::Error;
  method from_str (line 68) | fn from_str(s: &str) -> Result<Self, Self::Err> {
  function from (line 83) | fn from(log_level: LogLevel) -> Self {
  function flag_infer_long (line 94) | fn flag_infer_long(name: &'static str) -> Arg {
  function get_clap_command (line 98) | fn get_clap_command() -> ClapCommand {
  function check_init_syslog (line 170) | fn check_init_syslog(name: &str, log_level: LogLevel) {
  function try_parse_from (line 176) | pub fn try_parse_from(
  constant EXE (line 271) | const EXE: &str = "sccache-dist";
  function auth_generate_shared_tokens_bits (line 273) | fn auth_generate_shared_tokens_bits(bit_val: &'static str) -> Vec<&'stat...
  function auth_generate_jwt_hs256_server_token (line 277) | fn auth_generate_jwt_hs256_server_token(subcommand_args: &[&'static str]...
  function debug_assert (line 284) | fn debug_assert() {
  function missing_required_subcommands_fails (line 289) | fn missing_required_subcommands_fails() {
  function invalid_token_bits_fails (line 298) | fn invalid_token_bits_fails() {
  function auth_generate_server_token_needs_key_source (line 308) | fn auth_generate_server_token_needs_key_source() {
  function assert_args_parse_to_auth (line 321) | fn assert_args_parse_to_auth(args: Vec<&'static str>, ideal_auth: AuthSu...
  function auth_generate_jwt_hs256_key_good (line 329) | fn auth_generate_jwt_hs256_key_good() {
  function auth_generate_jwt_hs256_server_token_good (line 336) | fn auth_generate_jwt_hs256_server_token_good() {
  function auth_generate_shared_token_good (line 353) | fn auth_generate_shared_token_good() {

FILE: src/bin/sccache-dist/main.rs
  constant INSECURE_DIST_SERVER_TOKEN (line 36) | pub const INSECURE_DIST_SERVER_TOKEN: &str = "dangerously_insecure_server";
  function main (line 42) | fn main() {
  function main (line 51) | fn main() {
  function create_server_token (line 95) | fn create_server_token(server_id: ServerId, auth_token: &str) -> String {
  function check_server_token (line 98) | fn check_server_token(server_token: &str, auth_token: &str) -> Option<Se...
  type ServerJwt (line 109) | struct ServerJwt {
  function create_jwt_server_token (line 113) | fn create_jwt_server_token(
  function dangerous_insecure_extract_jwt_server_token (line 121) | fn dangerous_insecure_extract_jwt_server_token(server_token: &str) -> Re...
  function check_jwt_server_token (line 134) | fn check_jwt_server_token(
  function run (line 145) | fn run(command: Command) -> Result<i32> {
  function init_logging (line 313) | fn init_logging() {
  constant MAX_PER_CORE_LOAD (line 330) | const MAX_PER_CORE_LOAD: f64 = 2f64;
  constant SERVER_REMEMBER_ERROR_TIMEOUT (line 331) | const SERVER_REMEMBER_ERROR_TIMEOUT: Duration = Duration::from_secs(300);
  constant UNCLAIMED_PENDING_TIMEOUT (line 332) | const UNCLAIMED_PENDING_TIMEOUT: Duration = Duration::from_secs(300);
  constant UNCLAIMED_READY_TIMEOUT (line 333) | const UNCLAIMED_READY_TIMEOUT: Duration = Duration::from_secs(60);
  type JobDetail (line 336) | struct JobDetail {
  type Scheduler (line 343) | pub struct Scheduler {
    method new (line 365) | pub fn new() -> Self {
    method prune_servers (line 373) | fn prune_servers(
  type ServerDetails (line 352) | struct ServerDetails {
  method default (line 415) | fn default() -> Self {
  function load_weight (line 420) | fn load_weight(job_count: usize, core_count: usize) -> f64 {
  method handle_alloc_job (line 435) | fn handle_alloc_job(
  method handle_heartbeat_server (line 574) | fn handle_heartbeat_server(
  method handle_update_job_state (line 683) | fn handle_update_job_state(
  method handle_status (line 736) | fn handle_status(&self) -> Result<SchedulerStatusResult> {
  type Server (line 751) | pub struct Server {
    method new (line 758) | pub fn new(
  method handle_assign_job (line 774) | fn handle_assign_job(&self, job_id: JobId, tc: Toolchain) -> Result<Assi...
  method handle_submit_toolchain (line 794) | fn handle_submit_toolchain(
  method handle_run_job (line 821) | fn handle_run_job(

FILE: src/bin/sccache-dist/token_check.rs
  type Jwks (line 13) | pub struct Jwks {
  type Jwk (line 18) | pub struct Jwk {
    method to_der_pkcs1 (line 27) | pub fn to_der_pkcs1(&self) -> Result<Vec<u8>> {
  type EqCheck (line 53) | pub struct EqCheck {
    method new (line 71) | pub fn new(s: String) -> Self {
  method check (line 58) | fn check(&self, token: &str) -> StdResult<(), ClientVisibleMsg> {
  type ProxyTokenCheck (line 78) | pub struct ProxyTokenCheck {
    method new (line 99) | pub fn new(url: String, cache_secs: Option<u64>) -> Self {
    method check_token_with_forwarding (line 109) | fn check_token_with_forwarding(&self, token: &str) -> Result<()> {
  method check (line 85) | fn check(&self, token: &str) -> StdResult<(), ClientVisibleMsg> {
  type ValidJWTCheck (line 143) | pub struct ValidJWTCheck {
    method new (line 164) | pub fn new(audience: String, issuer: String, jwks_url: &str) -> Result...
    method check_jwt_validity (line 183) | fn check_jwt_validity(&self, token: &str) -> Result<()> {
  method check (line 150) | fn check(&self, token: &str) -> StdResult<(), ClientVisibleMsg> {

FILE: src/cache/azure.rs
  type AzureBlobCache (line 25) | pub struct AzureBlobCache;
    method build (line 28) | pub fn build(connection_string: &str, container: &str, key_prefix: &st...

FILE: src/cache/cache.rs
  type Storage (line 60) | pub trait Storage: Send + Sync {
    method get (line 68) | async fn get(&self, key: &str) -> Result<Cache>;
    method put (line 74) | async fn put(&self, key: &str, entry: CacheWrite) -> Result<Duration>;
    method check (line 88) | async fn check(&self) -> Result<CacheMode> {
    method location (line 93) | fn location(&self) -> String;
    method cache_type_name (line 97) | fn cache_type_name(&self) -> &'static str {
    method current_size (line 102) | async fn current_size(&self) -> Result<Option<u64>>;
    method max_size (line 105) | async fn max_size(&self) -> Result<Option<u64>>;
    method preprocessor_cache_mode_config (line 108) | fn preprocessor_cache_mode_config(&self) -> PreprocessorCacheModeConfig {
    method basedirs (line 113) | fn basedirs(&self) -> &[Vec<u8>] {
    method get_preprocessor_cache_entry (line 119) | async fn get_preprocessor_cache_entry(
    method put_preprocessor_cache_entry (line 128) | async fn put_preprocessor_cache_entry(
    method get (line 185) | async fn get(&self, key: &str) -> Result<Cache> {
    method put (line 199) | async fn put(&self, key: &str, entry: CacheWrite) -> Result<Duration> {
    method check (line 209) | async fn check(&self) -> Result<CacheMode> {
    method location (line 255) | fn location(&self) -> String {
    method cache_type_name (line 265) | fn cache_type_name(&self) -> &'static str {
    method current_size (line 271) | async fn current_size(&self) -> Result<Option<u64>> {
    method max_size (line 275) | async fn max_size(&self) -> Result<Option<u64>> {
    method basedirs (line 279) | fn basedirs(&self) -> &[Vec<u8>] {
  type RemoteStorage (line 149) | pub struct RemoteStorage {
    method new (line 166) | pub fn new(operator: opendal::Operator, basedirs: Vec<Vec<u8>>) -> Self {
  function build_single_cache (line 297) | pub fn build_single_cache(
  function storage_from_config (line 492) | pub fn storage_from_config(
  function test_read_write_mode_local (line 535) | fn test_read_write_mode_local() {
  function test_operator_storage_s3_with_basedirs (line 602) | fn test_operator_storage_s3_with_basedirs() {
  function test_operator_storage_redis_with_basedirs (line 627) | fn test_operator_storage_redis_with_basedirs() {

FILE: src/cache/cache_io.rs
  type FileObjectSource (line 25) | pub struct FileObjectSource {
  type Cache (line 36) | pub enum Cache {
    method fmt (line 48) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  type CacheMode (line 60) | pub enum CacheMode {
  type ReadSeek (line 68) | pub trait ReadSeek: Read + Seek + Send {}
  type CacheRead (line 73) | pub struct CacheRead {
    method from (line 91) | pub fn from<R>(reader: R) -> Result<CacheRead>
    method get_object (line 102) | pub fn get_object<T>(&mut self, name: &str, to: &mut T) -> Result<Opti...
    method get_stdout (line 116) | pub fn get_stdout(&mut self) -> Vec<u8> {
    method get_stderr (line 121) | pub fn get_stderr(&mut self) -> Vec<u8> {
    method get_bytes (line 125) | fn get_bytes(&mut self, name: &str) -> Vec<u8> {
    method extract_objects (line 131) | pub async fn extract_objects<T>(
  type DecompressionFailure (line 79) | pub struct DecompressionFailure;
    method fmt (line 82) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  type CacheWrite (line 173) | pub struct CacheWrite {
    method new (line 179) | pub fn new() -> CacheWrite {
    method from_objects (line 186) | pub async fn from_objects<T>(objects: T, pool: &tokio::runtime::Handle...
    method put_object (line 218) | pub fn put_object<T>(&mut self, name: &str, from: &mut T, mode: Option...
    method put_stdout (line 242) | pub fn put_stdout(&mut self, bytes: &[u8]) -> Result<()> {
    method put_stderr (line 246) | pub fn put_stderr(&mut self, bytes: &[u8]) -> Result<()> {
    method put_bytes (line 250) | fn put_bytes(&mut self, name: &str, bytes: &[u8]) -> Result<()> {
    method finish (line 259) | pub fn finish(self) -> Result<Vec<u8>> {
  method default (line 267) | fn default() -> Self {

FILE: src/cache/cos.rs
  type COSCache (line 21) | pub struct COSCache;
    method build (line 25) | pub fn build(bucket: &str, key_prefix: &str, endpoint: Option<&str>) -...

FILE: src/cache/disk.rs
  type DiskCache (line 32) | pub struct DiskCache {
    method new (line 45) | pub fn new<T: AsRef<OsStr>>(
  function make_key_path (line 73) | fn make_key_path(key: &str) -> PathBuf {
  method get (line 79) | async fn get(&self, key: &str) -> Result<Cache> {
  method put (line 105) | async fn put(&self, key: &str, entry: CacheWrite) -> Result<Duration> {
  method check (line 133) | async fn check(&self) -> Result<CacheMode> {
  method location (line 137) | fn location(&self) -> String {
  method cache_type_name (line 141) | fn cache_type_name(&self) -> &'static str {
  method current_size (line 145) | async fn current_size(&self) -> Result<Option<u64>> {
  method max_size (line 148) | async fn max_size(&self) -> Result<Option<u64>> {
  method preprocessor_cache_mode_config (line 151) | fn preprocessor_cache_mode_config(&self) -> PreprocessorCacheModeConfig {
  method basedirs (line 154) | fn basedirs(&self) -> &[Vec<u8>] {
  method get_preprocessor_cache_entry (line 157) | async fn get_preprocessor_cache_entry(&self, key: &str) -> Result<Option...
  method put_preprocessor_cache_entry (line 167) | async fn put_preprocessor_cache_entry(
  function test_disk_cache_type_name (line 199) | fn test_disk_cache_type_name() {

FILE: src/cache/gcs.rs
  function rw_to_scope (line 29) | fn rw_to_scope(mode: CacheMode) -> &'static str {
  type GCSCache (line 37) | pub struct GCSCache;
    method build (line 41) | pub fn build(
  function fetch_taskcluster_token (line 93) | async fn fetch_taskcluster_token(url: &str, scope: &str) -> Result<Strin...
  type TaskClusterToken (line 115) | struct TaskClusterToken {

FILE: src/cache/gha.rs
  type GHACache (line 25) | pub struct GHACache;
    method build (line 28) | pub fn build(version: &str) -> Result<Operator> {

FILE: src/cache/http_client.rs
  function set_user_agent (line 5) | pub fn set_user_agent() -> HttpClient {

FILE: src/cache/lazy_disk_cache.rs
  type LazyDiskCache (line 18) | pub enum LazyDiskCache {
    method get_or_init (line 24) | pub fn get_or_init(&mut self) -> Result<&mut LruDiskCache> {
    method get (line 34) | pub fn get(&mut self) -> Option<&mut LruDiskCache> {
    method capacity (line 41) | pub fn capacity(&self) -> u64 {
    method path (line 48) | pub fn path(&self) -> &Path {

FILE: src/cache/memcached.rs
  type MemcachedCache (line 25) | pub struct MemcachedCache;
    method build (line 28) | pub fn build(

FILE: src/cache/oss.rs
  type OSSCache (line 21) | pub struct OSSCache;
    method build (line 25) | pub fn build(

FILE: src/cache/readonly.rs
  type ReadOnlyStorage (line 23) | pub struct ReadOnlyStorage(pub Arc<dyn Storage>);
  method get (line 27) | async fn get(&self, key: &str) -> Result<Cache> {
  method put (line 35) | async fn put(&self, _key: &str, _entry: CacheWrite) -> Result<Duration> {
  method check (line 42) | async fn check(&self) -> Result<CacheMode> {
  method location (line 47) | fn location(&self) -> String {
  method cache_type_name (line 52) | fn cache_type_name(&self) -> &'static str {
  method current_size (line 57) | async fn current_size(&self) -> Result<Option<u64>> {
  method max_size (line 62) | async fn max_size(&self) -> Result<Option<u64>> {
  method preprocessor_cache_mode_config (line 67) | fn preprocessor_cache_mode_config(&self) -> PreprocessorCacheModeConfig {
  method basedirs (line 72) | fn basedirs(&self) -> &[Vec<u8>] {
  method get_preprocessor_cache_entry (line 79) | async fn get_preprocessor_cache_entry(
  method put_preprocessor_cache_entry (line 89) | async fn put_preprocessor_cache_entry(
  function readonly_storage_is_readonly (line 106) | fn readonly_storage_is_readonly() {
  function readonly_storage_forwards_preprocessor_cache_mode_config (line 115) | fn readonly_storage_forwards_preprocessor_cache_mode_config() {
  function readonly_storage_forwards_basedirs (line 134) | fn readonly_storage_forwards_basedirs() {
  function readonly_storage_put_err (line 168) | fn readonly_storage_put_err() {
  function readonly_storage_forwards_cache_type_name (line 197) | fn readonly_storage_forwards_cache_type_name() {

FILE: src/cache/redis.rs
  type RedisCache (line 25) | pub struct RedisCache;
    method build_from_url (line 29) | pub fn build_from_url(url: &str, key_prefix: &str, ttl: u64) -> Result...
    method build_single (line 57) | pub fn build_single(
    method build_cluster (line 71) | pub fn build_cluster(
    method build_common (line 84) | fn build_common(

FILE: src/cache/s3.rs
  type S3Cache (line 21) | pub struct S3Cache {
    method new (line 33) | pub fn new(bucket: String, key_prefix: String, no_credentials: bool) -...
    method with_region (line 45) | pub fn with_region(mut self, region: Option<String>) -> Self {
    method with_endpoint (line 49) | pub fn with_endpoint(mut self, endpoint: Option<String>) -> Self {
    method with_use_ssl (line 53) | pub fn with_use_ssl(mut self, use_ssl: Option<bool>) -> Self {
    method with_server_side_encryption (line 57) | pub fn with_server_side_encryption(mut self, server_side_encryption: O...
    method with_enable_virtual_host_style (line 61) | pub fn with_enable_virtual_host_style(
    method build (line 68) | pub fn build(self) -> Result<Operator> {
  function endpoint_resolver (line 109) | fn endpoint_resolver(endpoint: &str, use_ssl: Option<bool>) -> Result<St...
  function test_endpoint_resolver (line 140) | fn test_endpoint_resolver() -> Result<()> {

FILE: src/cache/utils.rs
  function normalize_key (line 20) | pub(in crate::cache) fn normalize_key(key: &str) -> String {
  function get_file_mode (line 25) | pub(in crate::cache) fn get_file_mode(file: &fs::File) -> Result<Option<...
  function get_file_mode (line 32) | pub(in crate::cache) fn get_file_mode(_file: &fs::File) -> Result<Option...
  function set_file_mode (line 37) | pub(in crate::cache) fn set_file_mode(path: &Path, mode: u32) -> Result<...
  function set_file_mode (line 47) | pub(in crate::cache) fn set_file_mode(_path: &Path, _mode: u32) -> Resul...
  function test_normalize_key (line 56) | fn test_normalize_key() {

FILE: src/cache/webdav.rs
  type WebdavCache (line 21) | pub struct WebdavCache;
    method build (line 25) | pub fn build(

FILE: src/client.rs
  type ServerConnection (line 24) | pub struct ServerConnection {
    method new (line 33) | pub fn new(conn: Box<dyn Connection>) -> io::Result<ServerConnection> {
    method request (line 42) | pub fn request(&mut self, request: Request) -> Result<Response> {
    method read_one_response (line 50) | pub fn read_one_response(&mut self) -> Result<Response> {
  function connect_to_server (line 66) | pub fn connect_to_server(addr: &crate::net::SocketAddr) -> io::Result<Se...
  function connect_with_retry (line 75) | pub fn connect_with_retry(addr: &crate::net::SocketAddr) -> io::Result<S...

FILE: src/cmdline.rs
  constant ENV_VAR_INTERNAL_START_SERVER (line 23) | const ENV_VAR_INTERNAL_START_SERVER: &str = "SCCACHE_START_SERVER";
  type StatsFormat (line 26) | pub enum StatsFormat {
    method as_str (line 33) | fn as_str(&self) -> &'static str {
  type Err (line 42) | type Err = anyhow::Error;
  method from_str (line 44) | fn from_str(s: &str) -> anyhow::Result<Self> {
  type Command (line 54) | pub enum Command {
  function flag_infer_long_and_short (line 85) | fn flag_infer_long_and_short(name: &'static str) -> Arg {
  function flag_infer_long (line 89) | fn flag_infer_long(name: &'static str) -> Arg {
  function get_clap_command (line 94) | fn get_clap_command() -> clap::Command {
  function try_parse (line 187) | pub fn try_parse() -> Result<Command> {

FILE: src/commands.rs
  constant DEFAULT_PORT (line 46) | pub const DEFAULT_PORT: u16 = 4226;
  constant SERVER_STARTUP_TIMEOUT (line 49) | const SERVER_STARTUP_TIMEOUT: Duration = Duration::from_millis(10000);
  function get_addr (line 52) | fn get_addr() -> crate::net::SocketAddr {
  function ignore_all_server_io_errors (line 67) | fn ignore_all_server_io_errors() -> bool {
  function read_server_startup_status (line 74) | async fn read_server_startup_status<R: AsyncReadExt + Unpin>(
  function run_server_process (line 91) | fn run_server_process(startup_timeout: Option<Duration>) -> Result<Serve...
  function redirect_stderr (line 130) | fn redirect_stderr(f: File) {
  function redirect_stderr (line 140) | fn redirect_stderr(f: File) {
  function create_error_log (line 150) | fn create_error_log() -> Result<File> {
  function redirect_error_log (line 169) | fn redirect_error_log(f: File) -> Result<()> {
  function run_server_process (line 177) | fn run_server_process(startup_timeout: Option<Duration>) -> Result<Serve...
  function connect_or_start_server (line 303) | fn connect_or_start_server(
  function request_zero_stats (line 343) | pub fn request_zero_stats(mut conn: ServerConnection) -> Result<()> {
  function request_stats (line 356) | pub fn request_stats(mut conn: ServerConnection) -> Result<ServerInfo> {
  function request_dist_status (line 369) | pub fn request_dist_status(mut conn: ServerConnection) -> Result<DistInf...
  function request_shutdown (line 382) | pub fn request_shutdown(mut conn: ServerConnection) -> Result<ServerInfo> {
  function request_compile (line 396) | fn request_compile<W, X, Y>(
  function status_signal (line 429) | fn status_signal(status: process::ExitStatus) -> Option<i32> {
  function status_signal (line 436) | fn status_signal(_status: process::ExitStatus) -> Option<i32> {
  function handle_compile_finished (line 442) | fn handle_compile_finished(
  function handle_compile_response (line 507) | fn handle_compile_response<T>(
  function do_compile (line 592) | pub fn do_compile<T>(
  function run_command (line 616) | pub fn run_command(cmd: Command) -> Result<i32> {

FILE: src/compiler/args.rs
  type ArgParseResult (line 10) | pub type ArgParseResult<T> = StdResult<T, ArgParseError>;
  type ArgToStringResult (line 11) | pub type ArgToStringResult = StdResult<String, ArgToStringError>;
  type PathTransformerFn (line 12) | pub type PathTransformerFn<'a> = &'a mut dyn FnMut(&Path) -> Option<Stri...
  type ArgParseError (line 15) | pub enum ArgParseError {
  method fmt (line 22) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  method cause (line 33) | fn cause(&self) -> Option<&dyn Error> {
  type ArgToStringError (line 39) | pub enum ArgToStringError {
  method fmt (line 45) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  method source (line 59) | fn source(&self) -> Option<&(dyn Error + 'static)> {
  type Delimiter (line 64) | pub type Delimiter = Option<u8>;
  type Argument (line 73) | pub enum Argument<T> {
  type ArgDisposition (line 87) | pub enum ArgDisposition {
  type NormalizedDisposition (line 98) | pub enum NormalizedDisposition {
  function normalize (line 106) | pub fn normalize(self, disposition: NormalizedDisposition) -> Self {
  function to_os_string (line 121) | pub fn to_os_string(&self) -> OsString {
  function flag_str (line 128) | pub fn flag_str(&self) -> Option<&'static str> {
  function get_data (line 135) | pub fn get_data(&self) -> Option<&T> {
  function iter_os_strings (line 144) | pub fn iter_os_strings(&self) -> Iter<'_, T> {
  function iter_strings (line 153) | pub fn iter_strings<F: FnMut(&Path) -> Option<String>>(
  type Iter (line 165) | pub struct Iter<'a, T> {
  type Item (line 171) | type Item = OsString;
  method next (line 173) | fn next(&mut self) -> Option<Self::Item> {
  type IterStrings (line 214) | pub struct IterStrings<'a, T, F> {
  type Item (line 222) | type Item = ArgToStringResult;
  method next (line 224) | fn next(&mut self) -> Option<Self::Item> {
  type ArgumentValue (line 319) | pub trait ArgumentValue: IntoArg + Clone + Debug {}
  type FromArg (line 323) | pub trait FromArg: Sized {
    method process (line 324) | fn process(arg: OsString) -> ArgParseResult<Self>;
    method process (line 333) | fn process(arg: OsString) -> ArgParseResult<Self> {
    method process (line 338) | fn process(arg: OsString) -> ArgParseResult<Self> {
    method process (line 343) | fn process(arg: OsString) -> ArgParseResult<Self> {
  type IntoArg (line 327) | pub trait IntoArg: Sized {
    method into_arg_os_string (line 328) | fn into_arg_os_string(self) -> OsString;
    method into_arg_string (line 329) | fn into_arg_string(self, transformer: PathTransformerFn<'_>) -> ArgToS...
    method into_arg_os_string (line 349) | fn into_arg_os_string(self) -> OsString {
    method into_arg_string (line 352) | fn into_arg_string(self, _transformer: PathTransformerFn<'_>) -> ArgTo...
    method into_arg_os_string (line 357) | fn into_arg_os_string(self) -> OsString {
    method into_arg_string (line 360) | fn into_arg_string(self, transformer: PathTransformerFn<'_>) -> ArgToS...
    method into_arg_os_string (line 365) | fn into_arg_os_string(self) -> OsString {
    method into_arg_string (line 368) | fn into_arg_string(self, _transformer: PathTransformerFn<'_>) -> ArgTo...
    method into_arg_os_string (line 373) | fn into_arg_os_string(self) -> OsString {
    method into_arg_string (line 376) | fn into_arg_string(self, _transformer: PathTransformerFn<'_>) -> ArgTo...
  function split_os_string_arg (line 381) | pub fn split_os_string_arg(val: OsString, split: &str) -> ArgParseResult...
  type ArgInfo (line 392) | pub enum ArgInfo<T> {
  function process (line 409) | fn process<F>(self, arg: &str, get_next_arg: F) -> ArgParseResult<Argume...
  function cmp (line 465) | fn cmp(&self, arg: &str) -> Ordering {
  function flag_str (line 485) | fn flag_str(&self) -> &'static str {
  function bsearch (line 496) | fn bsearch<K, T, F>(key: K, items: &[T], cmp: F) -> Option<&T>
  type SearchableArgInfo (line 524) | pub trait SearchableArgInfo<T> {
    method search (line 525) | fn search(&self, key: &str) -> Option<&ArgInfo<T>>;
    method check (line 528) | fn check(&self) -> bool;
  function search (line 534) | fn search(&self, key: &str) -> Option<&ArgInfo<T>> {
  function check (line 539) | fn check(&self) -> bool {
  function search (line 552) | fn search(&self, key: &str) -> Option<&ArgInfo<T>> {
  function check (line 568) | fn check(&self) -> bool {
  type ArgsIter (line 574) | pub struct ArgsIter<I, T, S>
  function new (line 593) | pub fn new(arguments: I, arg_info: S) -> Self {
  function with_double_dashes (line 604) | pub fn with_double_dashes(mut self) -> Self {
  type Item (line 616) | type Item = ArgParseResult<Argument<T>>;
  method next (line 618) | fn next(&mut self) -> Option<Self::Item> {
  function test_arginfo_cmp (line 735) | fn test_arginfo_cmp() {
  function test_arginfo_process (line 801) | fn test_arginfo_process() {
  function test_bsearch (line 872) | fn test_bsearch() {
  function test_multi_search (line 928) | fn test_multi_search() {
  function test_argsiter (line 949) | fn test_argsiter() {
  function test_argument_into_iter (line 1031) | fn test_argument_into_iter() {
  function test_arginfo_process_take_concat_arg_delim_doesnt_crash (line 1065) | fn test_arginfo_process_take_concat_arg_delim_doesnt_crash() {
  function test_arginfo_process_flag (line 1075) | fn test_arginfo_process_flag() {
  function test_arginfo_process_take_arg (line 1081) | fn test_arginfo_process_take_arg() {
  function test_arginfo_process_take_concat_arg (line 1089) | fn test_arginfo_process_take_concat_arg() {
  function test_arginfo_process_take_concat_arg_delim (line 1097) | fn test_arginfo_process_take_concat_arg_delim() {
  function test_arginfo_process_take_maybe_concat_arg (line 1105) | fn test_arginfo_process_take_maybe_concat_arg() {
  function test_arginfo_process_take_maybe_concat_arg_delim (line 1113) | fn test_arginfo_process_take_maybe_concat_arg_delim() {
  function test_args_iter_unsorted (line 1121) | fn test_args_iter_unsorted() {
  function test_args_iter_unsorted_2 (line 1128) | fn test_args_iter_unsorted_2() {
  function test_args_iter_no_conflict (line 1134) | fn test_args_iter_no_conflict() {

FILE: src/compiler/c.rs
  type CCompiler (line 52) | pub struct CCompiler<I>
  type CCompilerHasher (line 63) | pub struct CCompilerHasher<I>
  type ArtifactDescriptor (line 75) | pub struct ArtifactDescriptor {
  type ParsedArguments (line 85) | pub struct ParsedArguments {
    method output_pretty (line 125) | pub fn output_pretty(&self) -> Cow<'_, str> {
  type CCompilation (line 135) | struct CCompilation<I: CCompilerImpl> {
  type CCompilerKind (line 148) | pub enum CCompilerKind {
  type CCompilerImpl (line 173) | pub trait CCompilerImpl: Clone + fmt::Debug + Send + Sync + 'static {
    method kind (line 175) | fn kind(&self) -> CCompilerKind;
    method plusplus (line 177) | fn plusplus(&self) -> bool;
    method version (line 179) | fn version(&self) -> Option<String>;
    method parse_arguments (line 181) | fn parse_arguments(
    method preprocess (line 189) | async fn preprocess<T>(
    method generate_compile_commands (line 204) | fn generate_compile_commands<T>(
  function new (line 225) | pub async fn new(
  function extract_rocm_arg (line 248) | fn extract_rocm_arg(args: &ParsedArguments, flag: &str) -> Option<PathBu...
  function extract_rocm_env (line 257) | fn extract_rocm_env(env_vars: &[(OsString, OsString)], name: &str) -> Op...
  function search_hip_device_libs (line 267) | fn search_hip_device_libs(
  function kind (line 302) | fn kind(&self) -> CompilerKind {
  function get_toolchain_packager (line 306) | fn get_toolchain_packager(&self) -> Box<dyn pkg::ToolchainPackager> {
  function parse_arguments (line 312) | fn parse_arguments(
  function box_clone (line 357) | fn box_clone(&self) -> Box<dyn Compiler<T>> {
  function generate_hash_key (line 368) | async fn generate_hash_key(
  function color_mode (line 684) | fn color_mode(&self) -> ColorMode {
  function output_pretty (line 688) | fn output_pretty(&self) -> Cow<'_, str> {
  function box_clone (line 692) | fn box_clone(&self) -> Box<dyn CompilerHasher<T>> {
  function language (line 696) | fn language(&self) -> Language {
  constant PRAGMA_GCC_PCH_PREPROCESS (line 701) | const PRAGMA_GCC_PCH_PREPROCESS: &[u8] = b"pragma GCC pch_preprocess";
  constant HASH_31_COMMAND_LINE_NEWLINE (line 702) | const HASH_31_COMMAND_LINE_NEWLINE: &[u8] = b"# 31 \"<command-line>\"\n";
  constant HASH_32_COMMAND_LINE_2_NEWLINE (line 703) | const HASH_32_COMMAND_LINE_2_NEWLINE: &[u8] = b"# 32 \"<command-line>\" ...
  constant INCBIN_DIRECTIVE (line 704) | const INCBIN_DIRECTIVE: &[u8] = b".incbin";
  function process_preprocessed_file (line 708) | fn process_preprocessed_file(
  type PreprocessedLineAction (line 825) | type PreprocessedLineAction = ControlFlow<(usize, usize, bool), (usize, ...
  function process_preprocessor_line (line 828) | fn process_preprocessor_line(
  function normalize_path (line 959) | pub fn normalize_path(path: &Path) -> PathBuf {
  type PreprocessorFileMetadata (line 990) | struct PreprocessorFileMetadata {
    method from (line 998) | fn from(meta: std::fs::Metadata) -> Self {
  type PreprocessorFSAbstraction (line 1013) | trait PreprocessorFSAbstraction {
    method metadata (line 1014) | fn metadata(&self, path: impl AsRef<Path>) -> io::Result<PreprocessorF...
    method open (line 1018) | fn open(&self, path: impl AsRef<Path>) -> io::Result<Box<dyn std::io::...
    method metadata (line 1881) | fn metadata(&self, path: impl AsRef<Path>) -> io::Result<PreprocessorF...
    method open (line 1885) | fn open(&self, path: impl AsRef<Path>) -> io::Result<Box<dyn std::io::...
    method metadata (line 1897) | fn metadata(&self, path: impl AsRef<Path>) -> io::Result<PreprocessorF...
    method open (line 1908) | fn open(&self, path: impl AsRef<Path>) -> io::Result<Box<dyn std::io::...
  type StandardFsAbstraction (line 1024) | struct StandardFsAbstraction;
  function remember_include_file (line 1032) | fn remember_include_file(
  function include_is_too_new (line 1156) | fn include_is_too_new(
  constant PREPROCESSING_SKIPPED_COMPILE_POISON (line 1187) | const PREPROCESSING_SKIPPED_COMPILE_POISON: &[u8] = b"([{SCCACHE -*-* IN...
  function generate_compile_commands (line 1190) | fn generate_compile_commands(
  function into_dist_packagers (line 1210) | fn into_dist_packagers(
  function is_locally_preprocessed (line 1240) | fn is_locally_preprocessed(&self) -> bool {
  function outputs (line 1244) | fn outputs<'a>(&'a self) -> Box<dyn Iterator<Item = FileObjectSource> + ...
  type CInputsPackager (line 1259) | struct CInputsPackager {
    method write_inputs (line 1269) | fn write_inputs(self: Box<Self>, wtr: &mut dyn io::Write) -> Result<di...
  type CToolchainPackager (line 1328) | struct CToolchainPackager {
    method write_pkg (line 1336) | fn write_pkg(self: Box<Self>, f: fs::File) -> Result<()> {
  constant CACHE_VERSION (line 1449) | pub const CACHE_VERSION: &[u8] = b"12";
  type HashKeyParams (line 1489) | pub struct HashKeyParams<'a> {
  function new (line 1510) | pub fn new(
  function with_extra_hashes (line 1529) | pub fn with_extra_hashes(mut self, extra_hashes: &'a [String]) -> Self {
  function with_env_vars (line 1535) | pub fn with_env_vars(mut self, env_vars: &'a [(OsString, OsString)]) -> ...
  function with_plusplus (line 1541) | pub fn with_plusplus(mut self, plusplus: bool) -> Self {
  function with_basedirs (line 1547) | pub fn with_basedirs(mut self, basedirs: &'a [Vec<u8>]) -> Self {
  function compute (line 1560) | pub fn compute(&self) -> String {
  function test_same_content (line 1598) | fn test_same_content() {
  function test_plusplus_differs (line 1606) | fn test_plusplus_differs() {
  function test_header_differs (line 1616) | fn test_header_differs() {
  function test_plusplus_header_differs (line 1624) | fn test_plusplus_header_differs() {
  function test_hash_key_executable_contents_differs (line 1636) | fn test_hash_key_executable_contents_differs() {
  function test_hash_key_args_differs (line 1644) | fn test_hash_key_args_differs() {
  function test_hash_key_preprocessed_content_differs (line 1661) | fn test_hash_key_preprocessed_content_differs() {
  function test_hash_key_env_var_differs (line 1669) | fn test_hash_key_env_var_differs() {
  function test_extra_hash_data (line 1690) | fn test_extra_hash_data() {
  function test_hash_key_basedirs (line 1703) | fn test_hash_key_basedirs() {
  function test_language_from_file_name (line 1765) | fn test_language_from_file_name() {
  function test_language_from_file_name_none (line 1816) | fn test_language_from_file_name_none() {
  function test_process_preprocessed_file (line 1835) | fn test_process_preprocessed_file() {
  type PanicFs (line 1878) | struct PanicFs;
  type TestFs (line 1891) | struct TestFs {
  function do_single_preprocessor_line_call (line 1921) | fn do_single_preprocessor_line_call(
  function test_process_preprocessor_line_simple (line 1956) | fn test_process_preprocessor_line_simple() {
  function test_test_helpers (line 2033) | fn test_test_helpers() {
  function test_process_preprocessor_line_fs_access (line 2083) | fn test_process_preprocessor_line_fs_access() {

FILE: src/compiler/cicc.rs
  type Cicc (line 40) | pub struct Cicc {
  method kind (line 46) | fn kind(&self) -> CCompilerKind {
  method plusplus (line 49) | fn plusplus(&self) -> bool {
  method version (line 52) | fn version(&self) -> Option<String> {
  method parse_arguments (line 55) | fn parse_arguments(
  method preprocess (line 64) | async fn preprocess<T>(
  method generate_compile_commands (line 80) | fn generate_compile_commands<T>(
  function parse_arguments (line 104) | pub fn parse_arguments<S>(
  function preprocess (line 238) | pub async fn preprocess(cwd: &Path, parsed_args: &ParsedArguments) -> Re...
  function generate_compile_commands (line 254) | pub fn generate_compile_commands(

FILE: src/compiler/clang.rs
  type Clang (line 40) | pub struct Clang {
    method is_minversion (line 50) | fn is_minversion(&self, major: u64) -> bool {
  method kind (line 84) | fn kind(&self) -> CCompilerKind {
  method plusplus (line 87) | fn plusplus(&self) -> bool {
  method version (line 90) | fn version(&self) -> Option<String> {
  method parse_arguments (line 93) | fn parse_arguments(
  method preprocess (line 109) | async fn preprocess<T>(
  method generate_compile_commands (line 150) | fn generate_compile_commands<T>(
  function language_to_clang_arg (line 182) | pub fn language_to_clang_arg(lang: Language) -> Option<&'static str> {
  function resolve_profile_use_path (line 247) | pub(crate) fn resolve_profile_use_path(arg: &Path, cwd: &Path) -> PathBuf {
  function parse_arguments_ (line 279) | fn parse_arguments_(arguments: Vec<String>) -> CompilerArguments<ParsedA...
  function test_is_minversion (line 299) | fn test_is_minversion() {
  function test_parse_arguments_simple (line 335) | fn test_parse_arguments_simple() {
  function test_parse_arguments_values (line 354) | fn test_parse_arguments_values() {
  function test_parse_arguments_cuda (line 387) | fn test_parse_arguments_cuda() {
  function test_parse_arguments_cuda_flags (line 406) | fn test_parse_arguments_cuda_flags() {
  function test_parse_arguments_hip (line 461) | fn test_parse_arguments_hip() {
  function test_parse_arguments_hip_flags (line 480) | fn test_parse_arguments_hip_flags() {
  function test_parse_arguments_hip_paths (line 531) | fn test_parse_arguments_hip_paths() {
  function test_parse_arguments_hip_unhash_parallel_jobs (line 593) | fn test_parse_arguments_hip_unhash_parallel_jobs() {
  function test_dependent_lib (line 615) | fn test_dependent_lib() {
  function test_parse_arguments_others (line 640) | fn test_parse_arguments_others() {
  function test_gcodeview (line 654) | fn test_gcodeview() {
  function test_emit_pch (line 659) | fn test_emit_pch() {
  function test_parse_clang_short_dependency_arguments_can_be_separated (line 695) | fn test_parse_clang_short_dependency_arguments_can_be_separated() {
  function test_parse_arguments_clangmodules (line 715) | fn test_parse_arguments_clangmodules() {
  function test_parse_xclang_invalid (line 727) | fn test_parse_xclang_invalid() {
  function test_parse_xclang_load (line 756) | fn test_parse_xclang_load() {
  function test_parse_xclang_add_plugin (line 779) | fn test_parse_xclang_add_plugin() {
  function test_parse_xclang_llvm_stuff (line 797) | fn test_parse_xclang_llvm_stuff() {
  function test_parse_xclang_fexperimental_assignment_tracking (line 824) | fn test_parse_xclang_fexperimental_assignment_tracking() {
  function test_parse_xclang_plugin_arg_blink_gc_plugin (line 854) | fn test_parse_xclang_plugin_arg_blink_gc_plugin() {
  function test_parse_xclang_plugin_arg_find_bad_constructs (line 885) | fn test_parse_xclang_plugin_arg_find_bad_constructs() {
  function test_parse_xclang_verify (line 916) | fn test_parse_xclang_verify() {
  function test_parse_xclang_no_opaque_pointers (line 922) | fn test_parse_xclang_no_opaque_pointers() {
  function test_parse_xclang_fno_pch_timestamp (line 935) | fn test_parse_xclang_fno_pch_timestamp() {
  function test_parse_xclang_use_ctor_homing (line 948) | fn test_parse_xclang_use_ctor_homing() {
  function test_parse_xclang_mconstructor_aliases_all (line 954) | fn test_parse_xclang_mconstructor_aliases_all() {
  function test_parse_xclang_mrelax_all (line 967) | fn test_parse_xclang_mrelax_all() {
  function test_parse_fplugin (line 973) | fn test_parse_fplugin() {
  function test_parse_fplugin_concatenated (line 984) | fn test_parse_fplugin_concatenated() {
  function test_parse_fsanitize_blacklist (line 995) | fn test_parse_fsanitize_blacklist() {
  function test_parse_fsanitize_ignorelist (line 1011) | fn test_parse_fsanitize_ignorelist() {
  function test_parse_color_diags (line 1027) | fn test_parse_color_diags() {
  function test_parse_arguments_profile_instr_use (line 1039) | fn test_parse_arguments_profile_instr_use() {
  function test_parse_arguments_profile_use (line 1055) | fn test_parse_arguments_profile_use() {
  function test_parse_arguments_profile_use_with_directory (line 1066) | fn test_parse_arguments_profile_use_with_directory() {
  function test_parse_arguments_profile_use_with_no_argument (line 1077) | fn test_parse_arguments_profile_use_with_no_argument() {
  function test_parse_arguments_pgo_cancellation (line 1088) | fn test_parse_arguments_pgo_cancellation() {
  function test_parse_arguments_cxx20_modules_unsupported (line 1139) | fn test_parse_arguments_cxx20_modules_unsupported() {
  function test_parse_arguments_cxx20_module_precompile (line 1166) | fn test_parse_arguments_cxx20_module_precompile() {
  function test_parse_arguments_cxx20_module_fmodule_file (line 1192) | fn test_parse_arguments_cxx20_module_fmodule_file() {
  function test_parse_arguments_cxx20_module_fmodule_file_with_name (line 1204) | fn test_parse_arguments_cxx20_module_fmodule_file_with_name() {
  function test_parse_arguments_cxx20_module_fmodule_output (line 1229) | fn test_parse_arguments_cxx20_module_fmodule_output() {
  function test_parse_arguments_cxx20_module_fmodule_output_implicit_path (line 1260) | fn test_parse_arguments_cxx20_module_fmodule_output_implicit_path() {
  function test_parse_arguments_cxx20_module_fmodules_reduced_bmi (line 1284) | fn test_parse_arguments_cxx20_module_fmodules_reduced_bmi() {
  function test_parse_arguments_cxx20_module_combined_flags (line 1302) | fn test_parse_arguments_cxx20_module_combined_flags() {
  function test_compile_clang_cuda_does_not_dist_compile (line 1330) | fn test_compile_clang_cuda_does_not_dist_compile() {

FILE: src/compiler/compiler.rs
  constant CAN_DIST_DYLIBS (line 69) | pub const CAN_DIST_DYLIBS: bool = true;
  constant CAN_DIST_DYLIBS (line 77) | pub const CAN_DIST_DYLIBS: bool = false;
  type CompileCommand (line 80) | pub trait CompileCommand<T>: Send + Sync + 'static
    method execute (line 84) | async fn execute(
    method get_executable (line 90) | fn get_executable(&self) -> PathBuf;
    method get_arguments (line 91) | fn get_arguments(&self) -> Vec<OsString>;
    method get_env_vars (line 92) | fn get_env_vars(&self) -> Vec<(OsString, OsString)>;
    method get_cwd (line 93) | fn get_cwd(&self) -> PathBuf;
  type CCompileCommand (line 97) | pub struct CCompileCommand<I>
  function new (line 109) | pub fn new<T>(cmd: I) -> Box<dyn CompileCommand<T>>
  function get_executable (line 123) | fn get_executable(&self) -> PathBuf {
  function get_arguments (line 126) | fn get_arguments(&self) -> Vec<OsString> {
  function get_env_vars (line 129) | fn get_env_vars(&self) -> Vec<(OsString, OsString)> {
  function get_cwd (line 132) | fn get_cwd(&self) -> PathBuf {
  function execute (line 136) | async fn execute(
  type CompileCommandImpl (line 146) | pub trait CompileCommandImpl: Send + Sync + 'static {
    method get_executable (line 147) | fn get_executable(&self) -> PathBuf;
    method get_arguments (line 148) | fn get_arguments(&self) -> Vec<OsString>;
    method get_env_vars (line 149) | fn get_env_vars(&self) -> Vec<(OsString, OsString)>;
    method get_cwd (line 150) | fn get_cwd(&self) -> PathBuf;
    method execute (line 152) | async fn execute<T>(
    method get_executable (line 171) | fn get_executable(&self) -> PathBuf {
    method get_arguments (line 174) | fn get_arguments(&self) -> Vec<OsString> {
    method get_env_vars (line 177) | fn get_env_vars(&self) -> Vec<(OsString, OsString)> {
    method get_cwd (line 180) | fn get_cwd(&self) -> PathBuf {
    method execute (line 184) | async fn execute<T>(
  type SingleCompileCommand (line 162) | pub struct SingleCompileCommand {
  type CompilerKind (line 211) | pub enum CompilerKind {
    method lang_kind (line 383) | pub fn lang_kind(&self, lang: &Language) -> String {
    method lang_comp_kind (line 409) | pub fn lang_comp_kind(&self, lang: &Language) -> String {
  constant EXPECTED_LANGUAGE_COUNT (line 221) | const EXPECTED_LANGUAGE_COUNT: usize = 21;
  type Language (line 224) | pub enum Language {
    method from_file_name (line 250) | pub fn from_file_name(file: &Path) -> Option<Self> {
    method as_str (line 282) | pub fn as_str(self) -> &'static str {
    method needs_c_preprocessing (line 307) | pub fn needs_c_preprocessing(self) -> bool {
    method is_c_like_header (line 319) | pub fn is_c_like_header(self) -> bool {
    method to_c_preprocessed_language (line 330) | pub fn to_c_preprocessed_language(self) -> Option<Language> {
    method to_compiler_arg (line 342) | fn to_compiler_arg(self, cuda_arg: &'static str) -> Option<&'static st...
    method to_gcc_arg (line 371) | pub fn to_gcc_arg(self) -> Option<&'static str> {
    method to_clang_arg (line 377) | pub fn to_clang_arg(self) -> Option<&'static str> {
  type DistPackagers (line 428) | pub type DistPackagers = (
  type CacheLookupResult (line 434) | enum CacheLookupResult {
  type Compiler (line 440) | pub trait Compiler<T>: Send + Sync + 'static
    method kind (line 445) | fn kind(&self) -> CompilerKind;
    method get_toolchain_packager (line 448) | fn get_toolchain_packager(&self) -> Box<dyn pkg::ToolchainPackager>;
    method parse_arguments (line 450) | fn parse_arguments(
    method box_clone (line 456) | fn box_clone(&self) -> Box<dyn Compiler<T>>;
  method clone (line 460) | fn clone(&self) -> Box<dyn Compiler<T>> {
  type CompilerProxy (line 465) | pub trait CompilerProxy<T>: Send + Sync + 'static
    method resolve_proxied_executable (line 474) | fn resolve_proxied_executable(
    method box_clone (line 482) | fn box_clone(&self) -> Box<dyn CompilerProxy<T>>;
  method clone (line 486) | fn clone(&self) -> Box<dyn CompilerProxy<T>> {
  type CompilerHasher (line 494) | pub trait CompilerHasher<T>: fmt::Debug + Send + 'static
    method generate_hash_key (line 502) | async fn generate_hash_key(
    method color_mode (line 515) | fn color_mode(&self) -> ColorMode;
    method get_cached_or_compile (line 520) | async fn get_cached_or_compile(
    method output_pretty (line 816) | fn output_pretty(&self) -> Cow<'_, str>;
    method box_clone (line 818) | fn box_clone(&self) -> Box<dyn CompilerHasher<T>>;
    method language (line 820) | fn language(&self) -> Language;
  function dist_or_local_compile (line 824) | async fn dist_or_local_compile<T>(
  function dist_or_local_compile (line 849) | async fn dist_or_local_compile<T>(
  method clone (line 1077) | fn clone(&self) -> Box<dyn CompilerHasher<T>> {
  type Compilation (line 1083) | pub trait Compilation<T>: Send
    method generate_compile_commands (line 1089) | fn generate_compile_commands(
    method into_dist_packagers (line 1101) | fn into_dist_packagers(
    method is_locally_preprocessed (line 1106) | fn is_locally_preprocessed(&self) -> bool {
    method outputs (line 1114) | fn outputs<'a>(&'a self) -> Box<dyn Iterator<Item = FileObjectSource> ...
  type OutputsRewriter (line 1118) | pub trait OutputsRewriter: Send {
    method handle_outputs (line 1120) | fn handle_outputs(
    method handle_outputs (line 1132) | fn handle_outputs(
  type NoopOutputsRewriter (line 1129) | pub struct NoopOutputsRewriter;
  type HashResult (line 1143) | pub struct HashResult<T>
  type CompilerArguments (line 1157) | pub enum CompilerArguments<T> {
  type DistType (line 1186) | pub enum DistType {
  type MissType (line 1197) | pub enum MissType {
  type CacheWriteInfo (line 1211) | pub struct CacheWriteInfo {
  type CompileResult (line 1217) | pub enum CompileResult {
    method fmt (line 1251) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    method eq (line 1273) | fn eq(&self, other: &CompileResult) -> bool {
  type ColorMode (line 1242) | pub enum ColorMode {
  type Cacheable (line 1292) | pub enum Cacheable {
  type CacheControl (line 1299) | pub enum CacheControl {
  function write_temp_file (line 1317) | pub async fn write_temp_file(
  function is_rustc_like (line 1336) | fn is_rustc_like<P: AsRef<Path>>(p: P) -> bool {
  function is_nvidia_cudafe (line 1347) | fn is_nvidia_cudafe<P: AsRef<Path>>(p: P) -> bool {
  function is_nvidia_cicc (line 1358) | fn is_nvidia_cicc<P: AsRef<Path>>(p: P) -> bool {
  function is_nvidia_ptxas (line 1369) | fn is_nvidia_ptxas<P: AsRef<Path>>(p: P) -> bool {
  function is_known_c_compiler (line 1382) | fn is_known_c_compiler<P: AsRef<Path>>(p: P) -> bool {
  function detect_compiler (line 1404) | async fn detect_compiler<T>(
  function resolve_rust_compiler (line 1512) | async fn resolve_rust_compiler<T>(
  function detect_c_compiler (line 1639) | async fn detect_c_compiler<T, P>(
  function get_compiler_info (line 1876) | pub async fn get_compiler_info<T>(
  function test_c_preprocessing_consistent (line 1909) | fn test_c_preprocessing_consistent() {
  function test_detect_compiler_kind_gcc (line 1973) | fn test_detect_compiler_kind_gcc() {
  function test_detect_compiler_kind_clang (line 1998) | fn test_detect_compiler_kind_clang() {
  function test_detect_compiler_must_be_clang (line 2023) | fn test_detect_compiler_must_be_clang() {
  function test_detect_compiler_vv_clang (line 2041) | fn test_detect_compiler_vv_clang() {
  function test_detect_compiler_kind_msvc (line 2062) | fn test_detect_compiler_kind_msvc() {
  function test_detect_compiler_kind_nvcc (line 2101) | fn test_detect_compiler_kind_nvcc() {
  function test_detect_compiler_kind_nvhpc (line 2119) | fn test_detect_compiler_kind_nvhpc() {
  function test_detect_compiler_kind_rustc (line 2137) | fn test_detect_compiler_kind_rustc() {
  function test_is_rustc_like (line 2155) | fn test_is_rustc_like() {
  function populate_rustc_command_mock (line 2170) | fn populate_rustc_command_mock(
  function test_detect_compiler_kind_rustc_workspace_wrapper (line 2198) | fn test_detect_compiler_kind_rustc_workspace_wrapper() {
  function test_detect_compiler_kind_diab (line 2260) | fn test_detect_compiler_kind_diab() {
  function test_detect_compiler_kind_unknown (line 2278) | fn test_detect_compiler_kind_unknown() {
  function test_detect_compiler_kind_process_fail (line 2304) | fn test_detect_compiler_kind_process_fail() {
  function test_compiler_version_affects_hash (line 2328) | fn test_compiler_version_affects_hash(preprocessor_cache_mode: bool) {
  function test_common_args_affects_hash (line 2385) | fn test_common_args_affects_hash(preprocessor_cache_mode: bool) {
  function test_preprocessed_file_works_without_preprocessor_call (line 2456) | fn test_preprocessed_file_works_without_preprocessor_call(preprocessor_c...
  function test_get_compiler_info (line 2518) | fn test_get_compiler_info() {
  function test_compiler_get_cached_or_compile (line 2539) | fn test_compiler_get_cached_or_compile(preprocessor_cache_mode: bool) {
  function test_compiler_get_cached_or_compile_dist (line 2670) | fn test_compiler_get_cached_or_compile_dist(preprocessor_cache_mode: boo...
  function test_compiler_get_cached_or_compile_cache_error (line 2801) | fn test_compiler_get_cached_or_compile_cache_error(preprocessor_cache_mo...
  function test_compiler_get_cached_or_compile_cache_get_timing (line 2890) | fn test_compiler_get_cached_or_compile_cache_get_timing(preprocessor_cac...
  function test_compiler_get_cached_or_compile_force_recache (line 2974) | fn test_compiler_get_cached_or_compile_force_recache(preprocessor_cache_...
  function test_compiler_get_cached_or_compile_preprocessor_error (line 3104) | fn test_compiler_get_cached_or_compile_preprocessor_error(preprocessor_c...
  function test_compiler_get_cached_or_compile_dist_error (line 3195) | fn test_compiler_get_cached_or_compile_dist_error(preprocessor_cache_mod...
  type ErrorPutToolchainClient (line 3326) | pub struct ErrorPutToolchainClient;
    method new (line 3329) | pub fn new() -> Arc<dyn dist::Client> {
    method do_alloc_job (line 3335) | async fn do_alloc_job(&self, _: Toolchain) -> Result<AllocJobResult> {
    method do_get_status (line 3338) | async fn do_get_status(&self) -> Result<SchedulerStatusResult> {
    method do_submit_toolchain (line 3341) | async fn do_submit_toolchain(
    method do_run_job (line 3348) | async fn do_run_job(
    method put_toolchain (line 3357) | async fn put_toolchain(
    method rewrite_includes_only (line 3365) | fn rewrite_includes_only(&self) -> bool {
    method get_custom_toolchain (line 3368) | fn get_custom_toolchain(&self, _exe: &Path) -> Option<PathBuf> {
  type ErrorAllocJobClient (line 3373) | pub struct ErrorAllocJobClient {
    method new (line 3378) | pub fn new() -> Arc<dyn dist::Client> {
    method do_alloc_job (line 3388) | async fn do_alloc_job(&self, tc: Toolchain) -> Result<AllocJobResult> {
    method do_get_status (line 3392) | async fn do_get_status(&self) -> Result<SchedulerStatusResult> {
    method do_submit_toolchain (line 3395) | async fn do_submit_toolchain(
    method do_run_job (line 3402) | async fn do_run_job(
    method put_toolchain (line 3411) | async fn put_toolchain(
    method rewrite_includes_only (line 3419) | fn rewrite_includes_only(&self) -> bool {
    method get_custom_toolchain (line 3422) | fn get_custom_toolchain(&self, _exe: &Path) -> Option<PathBuf> {
  type ErrorSubmitToolchainClient (line 3427) | pub struct ErrorSubmitToolchainClient {
    method new (line 3433) | pub fn new() -> Arc<dyn dist::Client> {
    method do_alloc_job (line 3445) | async fn do_alloc_job(&self, tc: Toolchain) -> Result<AllocJobResult> {
    method do_get_status (line 3461) | async fn do_get_status(&self) -> Result<SchedulerStatusResult> {
    method do_submit_toolchain (line 3464) | async fn do_submit_toolchain(
    method do_run_job (line 3473) | async fn do_run_job(
    method put_toolchain (line 3482) | async fn put_toolchain(
    method rewrite_includes_only (line 3490) | fn rewrite_includes_only(&self) -> bool {
    method get_custom_toolchain (line 3493) | fn get_custom_toolchain(&self, _exe: &Path) -> Option<PathBuf> {
  type ErrorRunJobClient (line 3498) | pub struct ErrorRunJobClient {
    method new (line 3504) | pub fn new() -> Arc<dyn dist::Client> {
    method do_alloc_job (line 3516) | async fn do_alloc_job(&self, tc: Toolchain) -> Result<AllocJobResult> {
    method do_get_status (line 3532) | async fn do_get_status(&self) -> Result<SchedulerStatusResult> {
    method do_submit_toolchain (line 3535) | async fn do_submit_toolchain(
    method do_run_job (line 3544) | async fn do_run_job(
    method put_toolchain (line 3555) | async fn put_toolchain(
    method rewrite_includes_only (line 3569) | fn rewrite_includes_only(&self) -> bool {
    method get_custom_toolchain (line 3572) | fn get_custom_toolchain(&self, _exe: &Path) -> Option<PathBuf> {
  type OneshotClient (line 3577) | pub struct OneshotClient {
    method new (line 3585) | pub fn new(code: i32, stdout: Vec<u8>, stderr: Vec<u8>) -> Arc<dyn dis...
    method do_alloc_job (line 3598) | async fn do_alloc_job(&self, tc: Toolchain) -> Result<AllocJobResult> {
    method do_get_status (line 3615) | async fn do_get_status(&self) -> Result<SchedulerStatusResult> {
    method do_submit_toolchain (line 3618) | async fn do_submit_toolchain(
    method do_run_job (line 3628) | async fn do_run_job(
    method put_toolchain (line 3654) | async fn put_toolchain(
    method rewrite_includes_only (line 3668) | fn rewrite_includes_only(&self) -> bool {
    method get_custom_toolchain (line 3671) | fn get_custom_toolchain(&self, _exe: &Path) -> Option<PathBuf> {

FILE: src/compiler/counted_array.rs
  function counted_array_macro (line 27) | fn counted_array_macro() {

FILE: src/compiler/cudafe.rs
  type CudaFE (line 41) | pub struct CudaFE {
  method kind (line 47) | fn kind(&self) -> CCompilerKind {
  method plusplus (line 50) | fn plusplus(&self) -> bool {
  method version (line 53) | fn version(&self) -> Option<String> {
  method parse_arguments (line 56) | fn parse_arguments(
  method preprocess (line 65) | async fn preprocess<T>(
  method generate_compile_commands (line 81) | fn generate_compile_commands<T>(
  function generate_compile_commands (line 105) | pub fn generate_compile_commands(

FILE: src/compiler/diab.rs
  type Diab (line 40) | pub struct Diab {
  method kind (line 46) | fn kind(&self) -> CCompilerKind {
  method plusplus (line 49) | fn plusplus(&self) -> bool {
  method version (line 52) | fn version(&self) -> Option<String> {
  method parse_arguments (line 55) | fn parse_arguments(
  method preprocess (line 65) | async fn preprocess<T>(
  method generate_compile_commands (line 82) | fn generate_compile_commands<T>(
  function parse_arguments (line 174) | pub fn parse_arguments<S>(
  function preprocess (line 322) | pub async fn preprocess<T>(
  function generate_compile_commands (line 349) | pub fn generate_compile_commands(
  type ExpandAtArgs (line 386) | pub struct ExpandAtArgs<'a> {
  function new (line 392) | pub fn new(cwd: &'a Path, args: &[OsString]) -> Self {
  type Item (line 401) | type Item = OsString;
  method next (line 403) | fn next(&mut self) -> Option<OsString> {
  function parse_arguments_ (line 471) | fn parse_arguments_(arguments: Vec<String>) -> CompilerArguments<ParsedA...
  function test_parse_arguments_simple (line 477) | fn test_parse_arguments_simple() {
  function test_parse_arguments_default_name (line 509) | fn test_parse_arguments_default_name() {
  function test_parse_arguments_extra (line 541) | fn test_parse_arguments_extra() {
  function test_parse_arguments_values (line 573) | fn test_parse_arguments_values() {
  function test_parse_arguments_preprocessor_args (line 607) | fn test_parse_arguments_preprocessor_args() {
  function test_parse_arguments_empty_args (line 657) | fn test_parse_arguments_empty_args() {
  function test_parse_arguments_not_compile (line 662) | fn test_parse_arguments_not_compile() {
  function test_parse_arguments_too_many_inputs (line 670) | fn test_parse_arguments_too_many_inputs() {
  function test_parse_arguments_link (line 678) | fn test_parse_arguments_link() {
  function test_parse_dry_run (line 686) | fn test_parse_dry_run() {
  function test_at_signs (line 699) | fn test_at_signs() {
  function test_at_signs_file_not_readable (line 709) | fn test_at_signs_file_not_readable() {
  function test_at_signs_file (line 723) | fn test_at_signs_file() {
  function test_compile_simple (line 763) | fn test_compile_simple() {

FILE: src/compiler/gcc.rs
  type Gcc (line 39) | pub struct Gcc {
  method kind (line 46) | fn kind(&self) -> CCompilerKind {
  method plusplus (line 49) | fn plusplus(&self) -> bool {
  method version (line 52) | fn version(&self) -> Option<String> {
  method parse_arguments (line 55) | fn parse_arguments(
  method preprocess (line 65) | async fn preprocess<T>(
  method generate_compile_commands (line 99) | fn generate_compile_commands<T>(
  constant ARCH_FLAG (line 178) | const ARCH_FLAG: &str = "-arch";
  function parse_arguments (line 281) | pub fn parse_arguments<S>(
  function module_artifact_descriptor (line 772) | fn module_artifact_descriptor(
  function language_to_gcc_arg (line 799) | pub fn language_to_gcc_arg(lang: Language) -> Option<&'static str> {
  function preprocess_cmd (line 804) | fn preprocess_cmd<F, T>(
  function preprocess (line 887) | pub async fn preprocess<F, T>(
  function generate_compile_commands (line 923) | pub fn generate_compile_commands<F>(
  type ExpandIncludeFile (line 1056) | pub struct ExpandIncludeFile<'a> {
  function new (line 1062) | pub fn new(cwd: &'a Path, args: &[OsString]) -> Self {
  type Item (line 1071) | type Item = OsString;
  method next (line 1073) | fn next(&mut self) -> Option<OsString> {
  function parse_arguments_ (line 1136) | fn parse_arguments_(
  function parse_arguments_clang (line 1144) | fn parse_arguments_clang(
  function test_parse_arguments_simple (line 1159) | fn test_parse_arguments_simple() {
  function test_parse_arguments_default_name (line 1193) | fn test_parse_arguments_default_name() {
  function test_parse_arguments_default_outputdir (line 1225) | fn test_parse_arguments_default_outputdir() {
  function test_parse_arguments_objc_header_language (line 1244) | fn test_parse_arguments_objc_header_language() {
  function test_parse_arguments_split_dwarf (line 1278) | fn test_parse_arguments_split_dwarf() {
  function test_parse_arguments_linker_options (line 1323) | fn test_parse_arguments_linker_options() {
  function test_parse_arguments_coverage_outputs_gcno (line 1367) | fn test_parse_arguments_coverage_outputs_gcno() {
  function test_parse_arguments_test_coverage_outputs_gcno (line 1408) | fn test_parse_arguments_test_coverage_outputs_gcno() {
  function test_parse_arguments_profile_generate (line 1449) | fn test_parse_arguments_profile_generate() {
  function test_parse_arguments_extra (line 1483) | fn test_parse_arguments_extra() {
  function test_parse_arguments_values (line 1515) | fn test_parse_arguments_values() {
  function test_parse_arguments_preprocessor_args (line 1549) | fn test_parse_arguments_preprocessor_args() {
  function test_parse_arguments_unhashed (line 1601) | fn test_parse_arguments_unhashed() {
  function test_parse_arguments_double_dash (line 1620) | fn test_parse_arguments_double_dash() {
  function test_parse_arguments_too_hard (line 1679) | fn test_parse_arguments_too_hard() {
  function test_parse_arguments_explicit_dep_target (line 1704) | fn test_parse_arguments_explicit_dep_target() {
  function test_parse_arguments_explicit_dep_target_needed (line 1745) | fn test_parse_arguments_explicit_dep_target_needed() {
  function test_parse_arguments_explicit_mq_dep_target_needed (line 1791) | fn test_parse_arguments_explicit_mq_dep_target_needed() {
  function test_parse_arguments_diagnostics_color (line 1837) | fn test_parse_arguments_diagnostics_color() {
  function color_mode_preprocess (line 1854) | fn color_mode_preprocess() {
  function test_preprocess_cmd_rewrites_archs (line 1865) | fn test_preprocess_cmd_rewrites_archs() {
  function test_preprocess_cmd_doesnt_rewrite_single_arch (line 1902) | fn test_preprocess_cmd_doesnt_rewrite_single_arch() {
  function test_preprocess_double_dash_input (line 1937) | fn test_preprocess_double_dash_input() {
  function pedantic_default (line 1963) | fn pedantic_default() {
  function pedantic_std (line 1989) | fn pedantic_std() {
  function pedantic_gnu (line 2015) | fn pedantic_gnu() {
  function test_parse_arguments_dep_target_needed (line 2041) | fn test_parse_arguments_dep_target_needed() {
  function test_parse_arguments_dep_target_and_file_needed (line 2085) | fn test_parse_arguments_dep_target_and_file_needed() {
  function test_parse_arguments_empty_args (line 2120) | fn test_parse_arguments_empty_args() {
  function test_parse_arguments_not_compile (line 2128) | fn test_parse_arguments_not_compile() {
  function test_parse_arguments_too_many_inputs_single (line 2136) | fn test_parse_arguments_too_many_inputs_single() {
  function test_parse_arguments_too_many_inputs_multiple (line 2144) | fn test_parse_arguments_too_many_inputs_multiple() {
  function test_parse_arguments_link (line 2158) | fn test_parse_arguments_link() {
  function test_parse_arguments_pgo (line 2169) | fn test_parse_arguments_pgo() {
  function test_parse_arguments_cxx20_modules_unsupported (line 2187) | fn test_parse_arguments_cxx20_modules_unsupported() {
  function test_parse_arguments_response_file (line 2210) | fn test_parse_arguments_response_file() {
  function test_parse_index_store_path (line 2222) | fn test_parse_index_store_path() {
  function test_parse_arguments_multiarch_cache_disabled (line 2240) | fn test_parse_arguments_multiarch_cache_disabled() {
  function test_parse_arguments_multiple_arch (line 2258) | fn test_parse_arguments_multiple_arch() {
  function at_signs (line 2316) | fn at_signs() {
  function test_compile_simple (line 2360) | fn test_compile_simple() {
  function test_compile_simple_verbose_short (line 2421) | fn test_compile_simple_verbose_short() {
  function test_compile_simple_verbose_long (line 2480) | fn test_compile_simple_verbose_long() {
  function test_compile_double_dash_input (line 2539) | fn test_compile_double_dash_input() {
  function test_parse_arguments_plusplus (line 2564) | fn test_parse_arguments_plusplus() {
  function test_pch_explicit (line 2598) | fn test_pch_explicit() {
  function test_pch_implicit (line 2623) | fn test_pch_implicit() {
  function test_pch_generic (line 2648) | fn test_pch_generic() {
  function test_too_hard_for_preprocessor_cache_mode (line 2673) | fn test_too_hard_for_preprocessor_cache_mode() {

FILE: src/compiler/msvc.rs
  type Msvc (line 40) | pub struct Msvc {
  method kind (line 49) | fn kind(&self) -> CCompilerKind {
  method plusplus (line 52) | fn plusplus(&self) -> bool {
  method version (line 55) | fn version(&self) -> Option<String> {
  method parse_arguments (line 58) | fn parse_arguments(
  method preprocess (line 68) | async fn preprocess<T>(
  method generate_compile_commands (line 96) | fn generate_compile_commands<T>(
  function from_local_codepage (line 121) | fn from_local_codepage(multi_byte_str: &[u8]) -> io::Result<String> {
  function from_local_codepage (line 127) | pub fn from_local_codepage(multi_byte_str: &[u8]) -> io::Result<String> {
  function detect_showincludes_prefix (line 170) | pub async fn detect_showincludes_prefix<T>(
  function parse_arguments (line 517) | pub fn parse_arguments(
  function normpath (line 898) | fn normpath(path: &str) -> String {
  function normpath (line 928) | fn normpath(path: &str) -> String {
  function preprocess_cmd (line 933) | pub fn preprocess_cmd<T>(
  function preprocess (line 991) | pub async fn preprocess<T>(
  function generate_compile_commands (line 1088) | fn generate_compile_commands(
  type ExpandIncludeFile (line 1214) | struct ExpandIncludeFile<'a> {
  function new (line 1227) | pub fn new(cwd: &'a Path, args: &[OsString]) -> Self {
  type Item (line 1238) | type Item = OsString;
  method next (line 1240) | fn next(&mut self) -> Option<OsString> {
  function read_text (line 1279) | fn read_text<R>(reader: &mut R) -> io::Result<String>
  type SplitMsvcResponseFileArgs (line 1323) | struct SplitMsvcResponseFileArgs<'a> {
  function from (line 1333) | fn from(file_content: &'a T) -> Self {
  function append_backslashes_to (line 1343) | fn append_backslashes_to(target: &mut String, count: &mut usize, step: u...
  type Item (line 1352) | type Item = String;
  method next (line 1354) | fn next(&mut self) -> Option<String> {
  function parse_arguments (line 1432) | fn parse_arguments(arguments: Vec<OsString>) -> CompilerArguments<Parsed...
  function parse_arguments_clang (line 1436) | fn parse_arguments_clang(arguments: Vec<OsString>) -> CompilerArguments<...
  function test_detect_showincludes_prefix (line 1441) | fn test_detect_showincludes_prefix() {
  function test_parse_arguments_simple (line 1464) | fn test_parse_arguments_simple() {
  function test_cpp_parse_arguments_collects_type_library_headers (line 1498) | fn test_cpp_parse_arguments_collects_type_library_headers() {
  function test_c_parse_arguments_does_not_collect_type_library_headers (line 1538) | fn test_c_parse_arguments_does_not_collect_type_library_headers() {
  function test_parse_compile_flag (line 1564) | fn test_parse_compile_flag() {
  function test_parse_arguments_default_name (line 1598) | fn test_parse_arguments_default_name() {
  function test_parse_arguments_double_dash (line 1630) | fn test_parse_arguments_double_dash() {
  function parse_argument_slashes (line 1689) | fn parse_argument_slashes() {
  function parse_deps_arguments (line 1721) | fn parse_deps_arguments() {
  function test_parse_arguments_clang_passthrough (line 1773) | fn test_parse_arguments_clang_passthrough() {
  function test_parse_arguments_extra (line 1833) | fn test_parse_arguments_extra() {
  function test_parse_arguments_values (line 1865) | fn test_parse_arguments_values() {
  function parse_argument_output_file_trailing_backslash (line 1910) | fn parse_argument_output_file_trailing_backslash() {
  function parse_argument_output_file_trailing_slash_multi_extension (line 1943) | fn parse_argument_output_file_trailing_slash_multi_extension() {
  function test_parse_arguments_pdb (line 1975) | fn test_parse_arguments_pdb() {
  function test_parse_arguments_pdb_no_extension (line 2014) | fn test_parse_arguments_pdb_no_extension() {
  function test_parse_arguments_pdb_with_extension (line 2054) | fn test_parse_arguments_pdb_with_extension() {
  function test_parse_arguments_pdb_custom_extension (line 2094) | fn test_parse_arguments_pdb_custom_extension() {
  function test_parse_arguments_pdb_path_with_extension (line 2134) | fn test_parse_arguments_pdb_path_with_extension() {
  function test_parse_arguments_external_include (line 2174) | fn test_parse_arguments_external_include() {
  function test_parse_arguments_external_warning_suppression_forward_slashes (line 2225) | fn test_parse_arguments_external_warning_suppression_forward_slashes() {
  function test_parse_arguments_empty_args (line 2271) | fn test_parse_arguments_empty_args() {
  function test_parse_arguments_not_compile (line 2276) | fn test_parse_arguments_not_compile() {
  function test_parse_arguments_passthrough (line 2284) | fn test_parse_arguments_passthrough() {
  function test_parse_arguments_too_many_inputs_single (line 2328) | fn test_parse_arguments_too_many_inputs_single() {
  function test_parse_arguments_too_many_inputs_multiple (line 2336) | fn test_parse_arguments_too_many_inputs_multiple() {
  function test_parse_arguments_unsupported (line 2347) | fn test_parse_arguments_unsupported() {
  function test_parse_arguments_cxx20_modules_unsupported (line 2375) | fn test_parse_arguments_cxx20_modules_unsupported() {
  function test_responsefile_missing (line 2458) | fn test_responsefile_missing() {
  function test_responsefile_absolute_path (line 2466) | fn test_responsefile_absolute_path() {
  function test_responsefile_relative_path (line 2508) | fn test_responsefile_relative_path() {
  function test_responsefile_with_quotes (line 2556) | fn test_responsefile_with_quotes() {
  function test_responsefile_multiline (line 2598) | fn test_responsefile_multiline() {
  function test_responsefile_multiline_cr (line 2640) | fn test_responsefile_multiline_cr() {
  function test_responsefile_encoding_utf16le (line 2682) | fn test_responsefile_encoding_utf16le() {
  function test_responsefile_encoding_win1252 (line 2731) | fn test_responsefile_encoding_win1252() {
  function test_parse_arguments_missing_pdb (line 2779) | fn test_parse_arguments_missing_pdb() {
  function test_parse_arguments_missing_edit_and_continue_pdb (line 2787) | fn test_parse_arguments_missing_edit_and_continue_pdb() {
  function test_preprocess_double_dash_input (line 2795) | fn test_preprocess_double_dash_input() {
  function test_compile_simple (line 2811) | fn test_compile_simple() {
  function test_compile_double_dash_input (line 2869) | fn test_compile_double_dash_input() {
  function test_compile_not_cacheable_pdb (line 2891) | fn test_compile_not_cacheable_pdb() {
  function test_parse_fsanitize_blacklist (line 2959) | fn test_parse_fsanitize_blacklist() {
  function local_oem_codepage_conversions (line 2984) | fn local_oem_codepage_conversions() {

FILE: src/compiler/nvcc.rs
  type NvccHostCompiler (line 51) | pub enum NvccHostCompiler {
  type Nvcc (line 58) | pub struct Nvcc {
  method kind (line 66) | fn kind(&self) -> CCompilerKind {
  method plusplus (line 69) | fn plusplus(&self) -> bool {
  method version (line 72) | fn version(&self) -> Option<String> {
  method parse_arguments (line 85) | fn parse_arguments(
  method preprocess (line 155) | async fn preprocess<T>(
  method generate_compile_commands (line 277) | fn generate_compile_commands<T>(
  function generate_compile_commands (line 301) | pub fn generate_compile_commands(
  type NvccCompileCommand (line 485) | pub struct NvccCompileCommand {
  method get_executable (line 500) | fn get_executable(&self) -> PathBuf {
  method get_arguments (line 503) | fn get_arguments(&self) -> Vec<OsString> {
  method get_env_vars (line 506) | fn get_env_vars(&self) -> Vec<(OsString, OsString)> {
  method get_cwd (line 509) | fn get_cwd(&self) -> PathBuf {
  method execute (line 513) | async fn execute<T>(
  type NvccGeneratedSubcommand (line 622) | pub struct NvccGeneratedSubcommand {
  function group_nvcc_subcommands_by_compilation_stage (line 631) | async fn group_nvcc_subcommands_by_compilation_stage<T>(
  function select_nvcc_subcommands (line 915) | async fn select_nvcc_subcommands<T, F>(
  function select_valid_dryrun_lines (line 1025) | fn select_valid_dryrun_lines(re: &Regex, line: &str) -> Result<String> {
  function fold_env_vars_or_split_into_exe_and_args (line 1035) | fn fold_env_vars_or_split_into_exe_and_args(
  function remap_generated_filenames (line 1123) | fn remap_generated_filenames(
  function run_nvcc_subcommands_group (line 1227) | async fn run_nvcc_subcommands_group<T>(
  function aggregate_output (line 1336) | fn aggregate_output(lhs: process::Output, rhs: process::Output) -> proce...
  function error_to_output (line 1347) | fn error_to_output(err: Error) -> process::Output {
  function compile_result_to_output (line 1358) | fn compile_result_to_output(exe: &Path, res: protocol::CompileFinished) ...
  function status_to_code (line 1383) | fn status_to_code(res: process::ExitStatus) -> ExitStatusValue {
  function status_to_code (line 1392) | fn status_to_code(res: process::ExitStatus) -> ExitStatusValue {
  function parse_arguments_gcc (line 1487) | fn parse_arguments_gcc(arguments: Vec<String>) -> CompilerArguments<Pars...
  function parse_arguments_msvc (line 1496) | fn parse_arguments_msvc(arguments: Vec<String>) -> CompilerArguments<Par...
  function parse_arguments_nvc (line 1505) | fn parse_arguments_nvc(arguments: Vec<String>) -> CompilerArguments<Pars...
  function test_parse_arguments_simple_c (line 1541) | fn test_parse_arguments_simple_c() {
  function test_parse_arguments_simple_cu_gcc (line 1560) | fn test_parse_arguments_simple_cu_gcc() {
  function test_parse_arguments_simple_cu_nvc (line 1579) | fn test_parse_arguments_simple_cu_nvc() {
  function test_parse_arguments_simple_cu_msvc (line 1597) | fn test_parse_arguments_simple_cu_msvc() {
  function test_parse_arguments_ccbin_no_path (line 1616) | fn test_parse_arguments_ccbin_no_path() {
  function test_parse_arguments_ccbin_dir (line 1635) | fn test_parse_arguments_ccbin_dir() {
  function test_parse_threads_argument_simple_cu (line 1654) | fn test_parse_threads_argument_simple_cu() {
  function test_parse_arguments_simple_c_as_cu (line 1687) | fn test_parse_arguments_simple_c_as_cu() {
  function test_parse_arguments_dc_compile_flag (line 1706) | fn test_parse_arguments_dc_compile_flag() {
  function test_parse_arguments_fatbin_compile_flag (line 1726) | fn test_parse_arguments_fatbin_compile_flag() {
  function test_parse_arguments_cubin_compile_flag (line 1746) | fn test_parse_arguments_cubin_compile_flag() {
  function test_parse_arguments_values (line 1766) | fn test_parse_arguments_values() {
  function test_parse_md_mt_flags_cu (line 1813) | fn test_parse_md_mt_flags_cu() {
  function test_parse_generate_code_flags (line 1846) | fn test_parse_generate_code_flags() {
  function test_parse_pass_to_host_flags (line 1876) | fn test_parse_pass_to_host_flags() {
  function test_parse_no_capturing_of_xcompiler (line 1930) | fn test_parse_no_capturing_of_xcompiler() {
  function test_parse_dlink_is_not_compilation (line 1966) | fn test_parse_dlink_is_not_compilation() {
  function test_parse_cant_cache_flags (line 1992) | fn test_parse_cant_cache_flags() {

FILE: src/compiler/nvhpc.rs
  type Nvhpc (line 41) | pub struct Nvhpc {
  method kind (line 49) | fn kind(&self) -> CCompilerKind {
  method plusplus (line 52) | fn plusplus(&self) -> bool {
  method version (line 55) | fn version(&self) -> Option<String> {
  method parse_arguments (line 58) | fn parse_arguments(
  method preprocess (line 74) | async fn preprocess<T>(
  method generate_compile_commands (line 160) | fn generate_compile_commands<T>(
  function parse_arguments_ (line 236) | fn parse_arguments_(arguments: Vec<String>) -> CompilerArguments<ParsedA...
  function test_parse_arguments_simple_c (line 255) | fn test_parse_arguments_simple_c() {
  function test_parse_arguments_simple_cxx (line 274) | fn test_parse_arguments_simple_cxx() {
  function test_parse_arguments_values (line 293) | fn test_parse_arguments_values() {
  function test_parse_md_mt_flags_cxx (line 339) | fn test_parse_md_mt_flags_cxx() {
  function test_parse_generate_code_flags (line 372) | fn test_parse_generate_code_flags() {
  function test_parse_cant_cache_flags (line 400) | fn test_parse_cant_cache_flags() {

FILE: src/compiler/preprocessor_cache.rs
  constant FORMAT_VERSION (line 44) | const FORMAT_VERSION: u8 = 0;
  constant MAX_PREPROCESSOR_CACHE_ENTRIES (line 45) | const MAX_PREPROCESSOR_CACHE_ENTRIES: usize = 100;
  constant MAX_PREPROCESSOR_CACHE_FILE_INFO_ENTRIES (line 46) | const MAX_PREPROCESSOR_CACHE_FILE_INFO_ENTRIES: usize = 10000;
  type PreprocessorCacheEntry (line 49) | pub struct PreprocessorCacheEntry {
    method new (line 61) | pub fn new() -> Self {
    method read (line 66) | pub fn read(contents: &[u8]) -> Result<Self, Error> {
    method serialize_to (line 80) | pub fn serialize_to(&self, mut buf: impl Write) -> Result<(), Error> {
    method add_result (line 92) | pub fn add_result(
    method lookup_result_digest (line 177) | pub fn lookup_result_digest(
    method result_matches (line 193) | fn result_matches(
  function preprocessor_cache_entry_hash_key (line 375) | pub fn preprocessor_cache_entry_hash_key(
  type IncludeEntry (line 442) | pub struct IncludeEntry {
  type Error (line 456) | pub enum Error {
    method from (line 463) | fn from(e: std::io::Error) -> Self {
    method from (line 469) | fn from(e: bincode::Error) -> Self {
    method fmt (line 475) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  function test_find_time_macros_empty_file (line 496) | fn test_find_time_macros_empty_file() {
  function test_find_time_macros_small_file_no_match (line 503) | fn test_find_time_macros_small_file_no_match() {
  function test_find_time_macros_small_file_match (line 510) | fn test_find_time_macros_small_file_match() {
  function test_find_time_macros_small_file_match_multiple (line 532) | fn test_find_time_macros_small_file_match_multiple() {
  function test_find_time_macros_large_file_no_match (line 542) | fn test_find_time_macros_large_file_no_match() {
  function test_find_time_macros_large_file_match_no_overlap (line 552) | fn test_find_time_macros_large_file_match_no_overlap() {
  function test_find_time_macros_large_file_match_overlap (line 562) | fn test_find_time_macros_large_file_match_overlap() {
  function test_find_time_macros_large_file_match_overlap_multiple_pages (line 595) | fn test_find_time_macros_large_file_match_overlap_multiple_pages() {
  function test_find_time_macros_large_file_match_overlap_multiple_pages_tiny (line 610) | fn test_find_time_macros_large_file_match_overlap_multiple_pages_tiny() {
  function test_find_time_macros_ghost_pattern (line 629) | fn test_find_time_macros_ghost_pattern() {
  function test_preprocessor_cache_entry_hash_key_basedirs (line 643) | fn test_preprocessor_cache_entry_hash_key_basedirs() {

FILE: src/compiler/ptxas.rs
  type Ptxas (line 41) | pub struct Ptxas {
  method kind (line 47) | fn kind(&self) -> CCompilerKind {
  method plusplus (line 50) | fn plusplus(&self) -> bool {
  method version (line 53) | fn version(&self) -> Option<String> {
  method parse_arguments (line 56) | fn parse_arguments(
  method preprocess (line 65) | async fn preprocess<T>(
  method generate_compile_commands (line 81) | fn generate_compile_commands<T>(

FILE: src/compiler/rust.rs
  constant RLIB_PREFIX (line 66) | const RLIB_PREFIX: &str = "lib";
  constant RLIB_EXTENSION (line 68) | const RLIB_EXTENSION: &str = "rlib";
  constant RMETA_EXTENSION (line 71) | const RMETA_EXTENSION: &str = "rmeta";
  constant BINS_DIR (line 75) | const BINS_DIR: &str = "bin";
  constant LIBS_DIR (line 79) | const LIBS_DIR: &str = "lib";
  constant LIBS_DIR (line 83) | const LIBS_DIR: &str = "bin";
  type Rust (line 87) | pub struct Rust {
    method new (line 405) | pub async fn new<T>(
    method kind (line 513) | fn kind(&self) -> CompilerKind {
    method get_toolchain_packager (line 517) | fn get_toolchain_packager(&self) -> Box<dyn pkg::ToolchainPackager> {
    method parse_arguments (line 533) | fn parse_arguments(
    method box_clone (line 557) | fn box_clone(&self) -> Box<dyn Compiler<T>> {
  type RustHasher (line 121) | pub struct RustHasher {
    method generate_hash_key (line 1328) | async fn generate_hash_key(
    method color_mode (line 1688) | fn color_mode(&self) -> ColorMode {
    method output_pretty (line 1692) | fn output_pretty(&self) -> Cow<'_, str> {
    method box_clone (line 1696) | fn box_clone(&self) -> Box<dyn CompilerHasher<T>> {
    method language (line 1700) | fn language(&self) -> Language {
  type RustupProxy (line 141) | pub struct RustupProxy {
    method resolve_proxied_executable (line 566) | fn resolve_proxied_executable(
    method box_clone (line 607) | fn box_clone(&self) -> Box<dyn CompilerProxy<T>> {
    method new (line 613) | pub fn new<P>(proxy_executable: P) -> Result<Self>
    method find_proxy_executable (line 621) | pub async fn find_proxy_executable<T>(
  type ParsedArguments (line 146) | pub struct ParsedArguments {
  type RustCompilation (line 196) | pub struct RustCompilation {
    method generate_compile_commands (line 1706) | fn generate_compile_commands(
    method into_dist_packagers (line 1855) | fn into_dist_packagers(
    method outputs (line 1888) | fn outputs<'a>(&'a self) -> Box<dyn Iterator<Item = FileObjectSource> ...
  type CrateTypes (line 228) | pub struct CrateTypes {
  constant CACHE_VERSION (line 238) | const CACHE_VERSION: &[u8] = b"6";
  function get_source_files_and_env_deps (line 241) | async fn get_source_files_and_env_deps<T>(
  function parse_dep_file (line 297) | fn parse_dep_file<T, U>(file: T, cwd: U) -> Result<(Vec<PathBuf>, Vec<(O...
  function parse_dep_info (line 308) | fn parse_dep_info<T>(dep_info: &str, cwd: T) -> Vec<PathBuf>
  function parse_env_dep_info (line 359) | fn parse_env_dep_info(dep_info: &str) -> Vec<(OsString, OsString)> {
  function get_compiler_outputs (line 374) | async fn get_compiler_outputs<T>(
  type ArgCrateTypes (line 749) | struct ArgCrateTypes {
  method process (line 755) | fn process(arg: OsString) -> ArgParseResult<Self> {
  method into_arg_os_string (line 777) | fn into_arg_os_string(self) -> OsString {
  method into_arg_string (line 793) | fn into_arg_string(self, _transformer: PathTransformerFn<'_>) -> ArgToSt...
  type ArgLinkLibrary (line 812) | struct ArgLinkLibrary {
  method process (line 817) | fn process(arg: OsString) -> ArgParseResult<Self> {
  method into_arg_os_string (line 827) | fn into_arg_os_string(self) -> OsString {
  method into_arg_string (line 831) | fn into_arg_string(self, _transformer: PathTransformerFn<'_>) -> ArgToSt...
  type ArgLinkPath (line 838) | struct ArgLinkPath {
  method process (line 843) | fn process(arg: OsString) -> ArgParseResult<Self> {
  method into_arg_os_string (line 856) | fn into_arg_os_string(self) -> OsString {
  method into_arg_string (line 860) | fn into_arg_string(self, transformer: PathTransformerFn<'_>) -> ArgToStr...
  type ArgCodegen (line 867) | struct ArgCodegen {
  method process (line 872) | fn process(arg: OsString) -> ArgParseResult<Self> {
  method into_arg_os_string (line 878) | fn into_arg_os_string(self) -> OsString {
  method into_arg_string (line 886) | fn into_arg_string(self, transformer: PathTransformerFn<'_>) -> ArgToStr...
  type ArgUnstable (line 897) | struct ArgUnstable {
  method process (line 902) | fn process(arg: OsString) -> ArgParseResult<Self> {
  method into_arg_os_string (line 908) | fn into_arg_os_string(self) -> OsString {
  method into_arg_string (line 916) | fn into_arg_string(self, transformer: PathTransformerFn<'_>) -> ArgToStr...
  type ArgExtern (line 927) | struct ArgExtern {
  method process (line 932) | fn process(arg: OsString) -> ArgParseResult<Self> {
  method into_arg_os_string (line 944) | fn into_arg_os_string(self) -> OsString {
  method into_arg_string (line 948) | fn into_arg_string(self, transformer: PathTransformerFn<'_>) -> ArgToStr...
  type ArgTarget (line 955) | enum ArgTarget {
  method process (line 961) | fn process(arg: OsString) -> ArgParseResult<Self> {
  method into_arg_os_string (line 987) | fn into_arg_os_string(self) -> OsString {
  method into_arg_string (line 994) | fn into_arg_string(self, transformer: PathTransformerFn<'_>) -> ArgToStr...
  function parse_arguments (line 1068) | fn parse_arguments(arguments: &[OsString], cwd: &Path) -> CompilerArgume...
  function get_path_mappings (line 1901) | fn get_path_mappings(
  type RustInputsPackager (line 1908) | struct RustInputsPackager {
    method write_inputs (line 2013) | fn write_inputs(self: Box<Self>, wtr: &mut dyn io::Write) -> Result<di...
  function can_trim_this (line 1918) | fn can_trim_this(input_path: &Path) -> bool {
  function test_can_trim_this (line 1934) | fn test_can_trim_this() {
  function maybe_add_cargo_toml (line 1953) | fn maybe_add_cargo_toml(input_path: &Path, verify: bool) -> Option<PathB...
  function test_maybe_add_cargo_toml (line 1977) | fn test_maybe_add_cargo_toml() {
  type RustToolchainPackager (line 2208) | struct RustToolchainPackager {
    method write_pkg (line 2215) | fn write_pkg(self: Box<Self>, f: fs::File) -> Result<()> {
  type RustOutputsRewriter (line 2240) | struct RustOutputsRewriter {
  method handle_outputs (line 2246) | fn handle_outputs(
  function test_rust_outputs_rewriter (line 2305) | fn test_rust_outputs_rewriter() {
  type RlibDepsDetail (line 2361) | struct RlibDepsDetail {
  type DepsSize (line 2367) | struct DepsSize;
    type Measure (line 2370) | type Measure = usize;
    method measure (line 2371) | fn measure<Q: ?Sized>(&self, _k: &Q, v: &RlibDepsDetail) -> usize
  type RlibDepReader (line 2393) | struct RlibDepReader {
    method new_with_check (line 2401) | fn new_with_check(executable: PathBuf, env_vars: &[(OsString, OsString...
    method get_rustc_version (line 2464) | fn get_rustc_version(
    method parse_rustc_version (line 2493) | fn parse_rustc_version(stdout: &[u8]) -> Result<Version> {
    method get_correct_ls_arg (line 2506) | fn get_correct_ls_arg(version: Version) -> String {
    method discover_rlib_deps (line 2514) | fn discover_rlib_deps(
  function parse_rustc_z_ls (line 2594) | fn parse_rustc_z_ls(stdout: &str) -> Result<Vec<&str>> {
  function _parse_arguments (line 2670) | fn _parse_arguments(arguments: &[String]) -> CompilerArguments<ParsedArg...
  constant TEST_RUSTC_VERSION (line 2694) | const TEST_RUSTC_VERSION: &str = r#"
  function test_parse_arguments_simple (line 2706) | fn test_parse_arguments_simple() {
  function test_parse_arguments_incremental (line 2875) | fn test_parse_arguments_incremental() {
  function test_parse_arguments_dep_info_no_extra_filename (line 2904) | fn test_parse_arguments_dep_info_no_extra_filename() {
  function test_parse_arguments_native_libs (line 2919) | fn test_parse_arguments_native_libs() {
  function test_parse_arguments_non_rlib_crate (line 2962) | fn test_parse_arguments_non_rlib_crate() {
  function test_parse_arguments_color (line 3032) | fn test_parse_arguments_color() {
  function test_parse_arguments_multiple_inputs (line 3087) | fn test_parse_arguments_multiple_inputs() {
  function test_get_compiler_outputs (line 3117) | fn test_get_compiler_outputs() {
  function test_get_compiler_outputs_fail (line 3136) | fn test_get_compiler_outputs_fail() {
  function test_parse_dep_info (line 3153) | fn test_parse_dep_info() {
  function test_parse_dep_info_with_escaped_spaces (line 3169) | fn test_parse_dep_info_with_escaped_spaces() {
  function test_parse_dep_info_cwd (line 3181) | fn test_parse_dep_info_cwd() {
  function test_parse_dep_info_abs_paths (line 3203) | fn test_parse_dep_info_abs_paths() {
  function test_parse_dep_info_cwd (line 3220) | fn test_parse_dep_info_cwd() {
  function test_parse_dep_info_abs_paths (line 3246) | fn test_parse_dep_info_abs_paths() {
  function test_parse_rustc_z_ls_pre_1_55 (line 3261) | fn test_parse_rustc_z_ls_pre_1_55() {
  function test_parse_rustc_z_ls_post_1_55 (line 3280) | fn test_parse_rustc_z_ls_post_1_55() {
  function test_rlib_dep_reader_call (line 3305) | fn test_rlib_dep_reader_call() {
  function test_rlib_dep_reader_parse_rustc_version (line 3331) | fn test_rlib_dep_reader_parse_rustc_version() {
  function test_rlib_dep_reader_get_correct_ls_arg (line 3345) | fn test_rlib_dep_reader_get_correct_ls_arg() {
  function mock_dep_info (line 3380) | fn mock_dep_info(creator: &Arc<Mutex<MockCommandCreator>>, dep_srcs: &[&...
  function mock_file_names (line 3407) | fn mock_file_names(creator: &Arc<Mutex<MockCommandCreator>>, filenames: ...
  function test_generate_hash_key (line 3421) | fn test_generate_hash_key(preprocessor_cache_mode: bool) {
  function hash_key (line 3554) | fn hash_key<F>(
  function nothing (line 3615) | fn nothing(_path: &Path) -> Result<()> {
  function test_equal_hashes_externs (line 3621) | fn test_equal_hashes_externs(preprocessor_cache_mode: bool) {
  function test_equal_hashes_link_paths (line 3678) | fn test_equal_hashes_link_paths(preprocessor_cache_mode: bool) {
  function test_equal_hashes_ignored_args (line 3728) | fn test_equal_hashes_ignored_args(preprocessor_cache_mode: bool) {
  function test_equal_hashes_ignored_check_cfg_arg (line 3783) | fn test_equal_hashes_ignored_check_cfg_arg(preprocessor_cache_mode: bool) {
  function test_equal_hashes_cfg_features (line 3831) | fn test_equal_hashes_cfg_features(preprocessor_cache_mode: bool) {
  function test_parse_unstable_profile_flag (line 3880) | fn test_parse_unstable_profile_flag() {
  function test_parse_remap_path_prefix (line 3913) | fn test_parse_remap_path_prefix() {
  function test_parse_target (line 3941) | fn test_parse_target() {

FILE: src/compiler/tasking_vx.rs
  type TaskingVX (line 42) | pub struct TaskingVX;
  method kind (line 46) | fn kind(&self) -> CCompilerKind {
  method plusplus (line 50) | fn plusplus(&self) -> bool {
  method version (line 54) | fn version(&self) -> Option<String> {
  method parse_arguments (line 58) | fn parse_arguments(
  method preprocess (line 67) | async fn preprocess<T>(
  method generate_compile_commands (line 93) | fn generate_compile_commands<T>(
  function parse_arguments (line 169) | fn parse_arguments<S>(
  function preprocess (line 300) | async fn preprocess<T>(
  function generate_compile_commands (line 362) | fn generate_compile_commands(
  function parse_arguments_ (line 412) | fn parse_arguments_(arguments: Vec<String>) -> CompilerArguments<ParsedA...
  function test_parse_arguments_simple (line 418) | fn test_parse_arguments_simple() {
  function test_parse_arguments_default_name (line 450) | fn test_parse_arguments_default_name() {
  function test_parse_arguments_extra (line 482) | fn test_parse_arguments_extra() {
  function test_parse_arguments_values (line 514) | fn test_parse_arguments_values() {
  function test_parse_arguments_preprocessor_args (line 548) | fn test_parse_arguments_preprocessor_args() {
  function test_parse_arguments_explicit_dep_target (line 591) | fn test_parse_arguments_explicit_dep_target() {
  function test_parse_arguments_implicit_dep_target (line 625) | fn test_parse_arguments_implicit_dep_target() {
  function test_parse_arguments_empty_args (line 659) | fn test_parse_arguments_empty_args() {
  function test_parse_arguments_not_compile (line 664) | fn test_parse_arguments_not_compile() {
  function test_parse_arguments_too_many_inputs (line 672) | fn test_parse_arguments_too_many_inputs() {
  function test_parse_arguments_link (line 680) | fn test_parse_arguments_link() {
  function test_parse_dry_run (line 688) | fn test_parse_dry_run() {
  function test_compile_simple (line 701) | fn test_compile_simple() {
  function test_cuda_threads_included_in_compile_command (line 755) | fn test_cuda_threads_included_in_compile_command() {

FILE: src/config.rs
  constant ORGANIZATION (line 43) | const ORGANIZATION: &str = "Mozilla";
  constant APP_NAME (line 44) | const APP_NAME: &str = "sccache";
  constant DIST_APP_NAME (line 45) | const DIST_APP_NAME: &str = "sccache-dist-client";
  constant TEN_GIGS (line 46) | const TEN_GIGS: u64 = 10 * 1024 * 1024 * 1024;
  constant INSECURE_DIST_CLIENT_TOKEN (line 48) | pub const INSECURE_DIST_CLIENT_TOKEN: &str = "dangerously_insecure_client";
  function default_disk_cache_dir (line 52) | pub fn default_disk_cache_dir() -> PathBuf {
  function default_dist_cache_dir (line 59) | pub fn default_dist_cache_dir() -> PathBuf {
  function default_disk_cache_size (line 66) | fn default_disk_cache_size() -> u64 {
  function default_toolchain_cache_size (line 69) | fn default_toolchain_cache_size() -> u64 {
  type StringOrU64Visitor (line 73) | struct StringOrU64Visitor;
    type Value (line 76) | type Value = u64;
    method expecting (line 78) | fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    method visit_str (line 82) | fn visit_str<E>(self, value: &str) -> StdResult<Self::Value, E>
    method visit_u64 (line 89) | fn visit_u64<E>(self, value: u64) -> StdResult<Self::Value, E>
    method visit_i64 (line 96) | fn visit_i64<E>(self, value: i64) -> StdResult<Self::Value, E>
  function deserialize_size_from_str (line 108) | fn deserialize_size_from_str<'de, D>(deserializer: D) -> StdResult<u64, ...
  function parse_size (line 115) | pub fn parse_size(val: &str) -> Option<u64> {
  type HTTPUrl (line 133) | pub struct HTTPUrl(reqwest::Url);
    method deserialize (line 145) | fn deserialize<D>(deserializer: D) -> StdResult<Self, D::Error>
    method from_url (line 175) | pub fn from_url(u: reqwest::Url) -> Self {
    method to_url (line 178) | pub fn to_url(&self) -> reqwest::Url {
  method serialize (line 136) | fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
  function parse_http_url (line 156) | fn parse_http_url(url: &str) -> Result<reqwest::Url> {
  type AzureCacheConfig (line 185) | pub struct AzureCacheConfig {
  type PreprocessorCacheModeConfig (line 195) | pub struct PreprocessorCacheModeConfig {
    method activated (line 234) | pub fn activated() -> Self {
  method default (line 220) | fn default() -> Self {
  type DiskCacheConfig (line 245) | pub struct DiskCacheConfig {
  method default (line 254) | fn default() -> Self {
  type CacheModeConfig (line 266) | pub enum CacheModeConfig {
  method from (line 274) | fn from(value: CacheModeConfig) -> Self {
  type GCSCacheConfig (line 284) | pub struct GCSCacheConfig {
  type GHACacheConfig (line 295) | pub struct GHACacheConfig {
  constant DEFAULT_MEMCACHED_CACHE_EXPIRATION (line 309) | const DEFAULT_MEMCACHED_CACHE_EXPIRATION: u32 = 86400;
  function default_memcached_cache_expiration (line 311) | fn default_memcached_cache_expiration() -> u32 {
  type MemcachedCacheConfig (line 317) | pub struct MemcachedCacheConfig {
  constant DEFAULT_REDIS_CACHE_TTL (line 343) | const DEFAULT_REDIS_CACHE_TTL: u64 = 0;
  constant DEFAULT_REDIS_DB (line 344) | pub const DEFAULT_REDIS_DB: u32 = 0;
  type RedisCacheConfig (line 347) | pub struct RedisCacheConfig {
  type WebdavCacheConfig (line 384) | pub struct WebdavCacheConfig {
  type S3CacheConfig (line 395) | pub struct S3CacheConfig {
  type OSSCacheConfig (line 409) | pub struct OSSCacheConfig {
  type COSCacheConfig (line 419) | pub struct COSCacheConfig {
  type CacheType (line 427) | pub enum CacheType {
  type CacheConfigs (line 441) | pub struct CacheConfigs {
    method into_fallback (line 457) | fn into_fallback(self) -> (Option<CacheType>, DiskCacheConfig) {
    method merge (line 488) | fn merge(&mut self, other: Self) {
  type DistToolchainConfig (line 538) | pub enum DistToolchainConfig {
  type DistAuth (line 551) | pub enum DistAuth {
    method deserialize (line 567) | fn deserialize<D>(deserializer: D) -> StdResult<Self, D::Error>
  method default (line 612) | fn default() -> Self {
  type DistConfig (line 622) | pub struct DistConfig {
  method default (line 636) | fn default() -> Self {
  type FileConfig (line 652) | pub struct FileConfig {
  function try_read_config_file (line 662) | pub fn try_read_config_file<T: DeserializeOwned>(path: &Path) -> Result<...
  type EnvConfig (line 693) | pub struct EnvConfig {
  function key_prefix_from_env_var (line 698) | fn key_prefix_from_env_var(env_var_name: &str) -> String {
  function number_from_env_var (line 708) | fn number_from_env_var<A: std::str::FromStr>(env_var_name: &str) -> Opti...
  function bool_from_env_var (line 720) | fn bool_from_env_var(env_var_name: &str) -> Result<Option<bool>> {
  function config_from_env (line 734) | fn config_from_env() -> Result<EnvConfig> {
  function config_file (line 1057) | fn config_file(env_var: &str, leaf: &str) -> PathBuf {
  type Config (line 1078) | pub struct Config {
    method load (line 1089) | pub fn load() -> Result<Self> {
    method from_env_and_file_configs (line 1100) | fn from_env_and_file_configs(env_conf: EnvConfig, file_conf: FileConfi...
  type CachedDistConfig (line 1184) | pub struct CachedDistConfig {
  type CachedFileConfig (line 1191) | pub struct CachedFileConfig {
  type CachedConfig (line 1196) | pub struct CachedConfig(());
    method load (line 1199) | pub fn load() -> Result<Self> {
    method reload (line 1208) | pub fn reload() -> Result<Self> {
    method with (line 1215) | pub fn with<F: FnOnce(&CachedFileConfig) -> T, T>(&self, f: F) -> T {
    method with_mut (line 1221) | pub fn with_mut<F: FnOnce(&mut CachedFileConfig)>(&self, f: F) -> Resu...
    method file_config_path (line 1232) | fn file_config_path() -> PathBuf {
    method load_file_config (line 1235) | fn load_file_config() -> Result<CachedFileConfig> {
    method save_file_config (line 1257) | fn save_file_config(c: &CachedFileConfig) -> Result<()> {
  type ClientAuth (line 1277) | pub enum ClientAuth {
  type ServerAuth (line 1298) | pub enum ServerAuth {
  type Config (line 1309) | pub struct Config {
    method load (line 1089) | pub fn load() -> Result<Self> {
    method from_env_and_file_configs (line 1100) | fn from_env_and_file_configs(env_conf: EnvConfig, file_conf: FileConfi...
  function from_path (line 1315) | pub fn from_path(conf_path: &Path) -> Result<Option<Config>> {
  constant TEN_GIGS (line 1329) | const TEN_GIGS: u64 = 10 * 1024 * 1024 * 1024;
  function default_toolchain_cache_size (line 1330) | fn default_toolchain_cache_size() -> u64 {
  constant DEFAULT_POT_CLONE_FROM (line 1334) | const DEFAULT_POT_CLONE_FROM: &str = "sccache-template";
  constant DEFAULT_POT_FS_ROOT (line 1335) | const DEFAULT_POT_FS_ROOT: &str = "/opt/pot";
  constant DEFAULT_POT_CMD (line 1336) | const DEFAULT_POT_CMD: &str = "pot";
  constant DEFAULT_POT_CLONE_ARGS (line 1337) | const DEFAULT_POT_CLONE_ARGS: &[&str] = &["-i", "lo0|127.0.0.2"];
  function default_pot_clone_from (line 1339) | fn default_pot_clone_from() -> String {
  function default_pot_fs_root (line 1343) | fn default_pot_fs_root() -> PathBuf {
  function default_pot_cmd (line 1347) | fn default_pot_cmd() -> PathBuf {
  function default_pot_clone_args (line 1351) | fn default_pot_clone_args() -> Vec<String> {
  type BuilderType (line 1361) | pub enum BuilderType {
  type SchedulerAuth (line 1385) | pub enum SchedulerAuth {
  type Config (line 1396) | pub struct Config {
    method load (line 1089) | pub fn load() -> Result<Self> {
    method from_env_and_file_configs (line 1100) | fn from_env_and_file_configs(env_conf: EnvConfig, file_conf: FileConfi...
  function from_path (line 1407) | pub fn from_path(conf_path: &Path) -> Result<Option<Config>> {
  function test_parse_size (line 1413) | fn test_parse_size() {
  function config_overrides (line 1425) | fn config_overrides() {
  function config_basedirs_overrides (line 1507) | fn config_basedirs_overrides() {
  function config_basedirs_overrides (line 1575) | fn config_basedirs_overrides() {
  function test_deserialize_basedirs (line 1657) | fn test_deserialize_basedirs() {
  function test_deserialize_basedirs_missing (line 1680) | fn test_deserialize_basedirs_missing() {
  function test_env_basedirs_single (line 1697) | fn test_env_basedirs_single() {
  function test_env_basedirs_single (line 1715) | fn test_env_basedirs_single() {
  function test_env_basedirs_multiple (line 1733) | fn test_env_basedirs_multiple() {
  function test_env_basedirs_multiple (line 1757) | fn test_env_basedirs_multiple() {
  function test_env_basedirs_with_spaces (line 1781) | fn test_env_basedirs_with_spaces() {
  function test_env_basedirs_with_spaces (line 1815) | fn test_env_basedirs_with_spaces() {
  function test_env_basedirs_empty_entries (line 1849) | fn test_env_basedirs_empty_entries() {
  function test_env_basedirs_empty_entries (line 1874) | fn test_env_basedirs_empty_entries() {
  function test_env_basedirs_not_set (line 1898) | fn test_env_basedirs_not_set() {
  function test_s3_no_credentials_conflict (line 1909) | fn test_s3_no_credentials_conflict() {
  function test_s3_no_credentials_invalid (line 1935) | fn test_s3_no_credentials_invalid() {
  function test_s3_no_credentials_valid_true (line 1957) | fn test_s3_no_credentials_valid_true() {
  function test_s3_no_credentials_valid_false (line 1986) | fn test_s3_no_credentials_valid_false() {
  function test_gcs_service_account (line 2016) | fn test_gcs_service_account() {
  function full_toml_parse (line 2048) | fn full_toml_parse() {
  function server_toml_parse (line 2228) | fn server_toml_parse() {
  function human_units_parse (line 2289) | fn human_units_parse() {
  function test_integration_config_normalizes_and_strips (line 2323) | fn test_integration_config_normalizes_and_strips() {
  function test_integration_normalized_path_with_double_slashes (line 2357) | fn test_integration_normalized_path_with_double_slashes() {
  function test_integration_windows_path_normalization (line 2386) | fn test_integration_windows_path_normalization() {
  function test_integration_cow_borrowed_when_no_match (line 2415) | fn test_integration_cow_borrowed_when_no_match() {
  function test_integration_cow_borrowed_when_empty_basedirs (line 2445) | fn test_integration_cow_borrowed_when_empty_basedirs() {
  function test_integration_multiple_basedirs_longest_match (line 2475) | fn test_integration_multiple_basedirs_longest_match() {
  function test_integration_paths_with_dots_normalized (line 2509) | fn test_integration_paths_with_dots_normalized() {
  function test_integration_windows_mixed_slashes (line 2539) | fn test_integration_windows_mixed_slashes() {
  function test_integration_env_variable_to_strip (line 2570) | fn test_integration_env_variable_to_strip() {

FILE: src/dist/cache.rs
  type CustomToolchain (line 30) | pub struct CustomToolchain {
  type ClientToolchains (line 36) | pub struct ClientToolchains {
    method new (line 58) | pub fn new(
    method get_toolchain (line 169) | pub fn get_toolchain(&self, tc: &Toolchain) -> Result<Option<fs::File>> {
    method put_toolchain (line 190) | pub fn put_toolchain(
    method get_custom_toolchain (line 224) | pub fn get_custom_toolchain(
    method weak_to_strong (line 273) | fn weak_to_strong(&self, weak_key: &str) -> Option<String> {
    method record_weak (line 280) | fn record_weak(&self, weak_key: String, key: String) -> Result<()> {
  type PanicToolchainPackager (line 299) | struct PanicToolchainPackager;
    method new (line 301) | fn new() -> Box<Self> {
    method write_pkg (line 307) | fn write_pkg(self: Box<Self>, _f: super::fs::File) -> crate::errors::R...
  function test_client_toolchains_custom (line 313) | fn test_client_toolchains_custom() {
  function test_client_toolchains_custom_multiuse_archive (line 344) | fn test_client_toolchains_custom_multiuse_archive() {
  function test_client_toolchains_nodist (line 405) | fn test_client_toolchains_nodist() {
  function test_client_toolchains_custom_nodist_conflict (line 432) | fn test_client_toolchains_custom_nodist_conflict() {
  type TcCache (line 460) | pub struct TcCache {
    method new (line 465) | pub fn new(cache_dir: &Path, cache_size: u64) -> Result<TcCache> {
    method contains_toolchain (line 472) | pub fn contains_toolchain(&self, tc: &Toolchain) -> bool {
    method insert_with (line 476) | pub fn insert_with<F: FnOnce(fs::File) -> io::Result<()>>(
    method get_file (line 492) | pub fn get_file(&mut self, tc: &Toolchain) -> LruResult<fs::File> {
    method get (line 496) | pub fn get(&mut self, tc: &Toolchain) -> LruResult<Box<dyn ReadSeek>> {
    method len (line 500) | pub fn len(&self) -> usize {
    method is_empty (line 504) | pub fn is_empty(&self) -> bool {
    method remove (line 508) | pub fn remove(&mut self, tc: &Toolchain) -> LruResult<()> {
    method insert_file (line 513) | fn insert_file(&mut self, path: &Path) -> Result<Toolchain> {
  function path_key (line 522) | fn path_key(path: &Path) -> Result<String> {
  function file_key (line 526) | fn file_key<R: Read>(rdr: R) -> Result<String> {
  function make_lru_key_path (line 530) | fn make_lru_key_path(key: &str) -> PathBuf {

FILE: src/dist/client_auth.rs
  constant VALID_PORTS (line 21) | pub const VALID_PORTS: &[u16] = &[12731, 32492, 56909];
  constant MIN_TOKEN_VALIDITY (line 23) | const MIN_TOKEN_VALIDITY: Duration = Duration::from_secs(2 * 24 * 60 * 60);
  constant MIN_TOKEN_VALIDITY_WARNING (line 24) | const MIN_TOKEN_VALIDITY_WARNING: &str = "two days";
  function query_pairs (line 26) | fn query_pairs(url: &str) -> Result<HashMap<String, String>> {
  function html_response (line 38) | fn html_response(body: &'static str) -> Response<Full<Bytes>> {
  function json_response (line 46) | fn json_response<T: Serialize>(data: &T) -> Result<Response<Full<Bytes>>> {
  constant REDIRECT_WITH_AUTH_JSON (line 56) | const REDIRECT_WITH_AUTH_JSON: &str = r##"<!doctype html>
  constant CLIENT_ID_PARAM (line 107) | const CLIENT_ID_PARAM: &str = "client_id";
  constant CODE_CHALLENGE_PARAM (line 108) | const CODE_CHALLENGE_PARAM: &str = "code_challenge";
  constant CODE_CHALLENGE_METHOD_PARAM (line 109) | const CODE_CHALLENGE_METHOD_PARAM: &str = "code_challenge_method";
  constant CODE_CHALLENGE_METHOD_VALUE (line 110) | const CODE_CHALLENGE_METHOD_VALUE: &str = "S256";
  constant REDIRECT_PARAM (line 111) | const REDIRECT_PARAM: &str = "redirect_uri";
  constant RESPONSE_TYPE_PARAM (line 112) | const RESPONSE_TYPE_PARAM: &str = "response_type";
  constant RESPONSE_TYPE_PARAM_VALUE (line 113) | const RESPONSE_TYPE_PARAM_VALUE: &str = "code";
  constant STATE_PARAM (line 114) | const STATE_PARAM: &str = "state";
  constant CODE_RESULT_PARAM (line 116) | const CODE_RESULT_PARAM: &str = "code";
  constant STATE_RESULT_PARAM (line 117) | const STATE_RESULT_PARAM: &str = "state";
  type TokenRequest (line 121) | struct TokenRequest<'a> {
  constant GRANT_TYPE_PARAM_VALUE (line 128) | const GRANT_TYPE_PARAM_VALUE: &str = "authorization_code";
  type TokenResponse (line 131) | struct TokenResponse {
  constant TOKEN_TYPE_RESULT_PARAM_VALUE (line 136) | const TOKEN_TYPE_RESULT_PARAM_VALUE: &str = "bearer";
  constant NUM_CODE_VERIFIER_BYTES (line 138) | const NUM_CODE_VERIFIER_BYTES: usize = 256 / 8;
  type State (line 140) | pub struct State {
  function generate_verifier_and_challenge (line 149) | pub fn generate_verifier_and_challenge() -> Result<(String, String)> {
  function finish_url (line 159) | pub fn finish_url(
  function handle_code_response (line 175) | fn handle_code_response(params: HashMap<String, String>) -> Result<(Stri...
  function handle_token_response (line 185) | fn handle_token_response(res: TokenResponse) -> Result<(String, Instant)> {
  constant SUCCESS_AFTER_REDIRECT (line 198) | const SUCCESS_AFTER_REDIRECT: &str = r##"<!doctype html>
  function serve (line 205) | pub fn serve(req: Request<hyper::body::Incoming>) -> Result<Response<Ful...
  function code_to_token (line 235) | pub fn code_to_token(
  constant CLIENT_ID_PARAM (line 295) | const CLIENT_ID_PARAM: &str = "client_id";
  constant REDIRECT_PARAM (line 296) | const REDIRECT_PARAM: &str = "redirect_uri";
  constant RESPONSE_TYPE_PARAM (line 297) | const RESPONSE_TYPE_PARAM: &str = "response_type";
  constant RESPONSE_TYPE_PARAM_VALUE (line 298) | const RESPONSE_TYPE_PARAM_VALUE: &str = "token";
  constant STATE_PARAM (line 299) | const STATE_PARAM: &str = "state";
  constant TOKEN_RESULT_PARAM (line 301) | const TOKEN_RESULT_PARAM: &str = "access_token";
  constant TOKEN_TYPE_RESULT_PARAM (line 302) | const TOKEN_TYPE_RESULT_PARAM: &str = "token_type";
  constant TOKEN_TYPE_RESULT_PARAM_VALUE (line 303) | const TOKEN_TYPE_RESULT_PARAM_VALUE: &str = "bearer";
  constant EXPIRES_IN_RESULT_PARAM (line 304) | const EXPIRES_IN_RESULT_PARAM: &str = "expires_in";
  constant STATE_RESULT_PARAM (line 305) | const STATE_RESULT_PARAM: &str = "state";
  type State (line 307) | pub struct State {
  function finish_url (line 316) | pub fn finish_url(client_id: &str, url: &mut Url, redirect_uri: &str, st...
  function handle_response (line 324) | fn handle_response(params: HashMap<String, String>) -> Result<(String, I...
  constant SAVE_AUTH_AFTER_REDIRECT (line 353) | const SAVE_AUTH_AFTER_REDIRECT: &str = r##"<!doctype html>
  function serve (line 382) | pub fn serve(req: Request<hyper::body::Incoming>) -> Result<Response<Ful...
  type HyperBuilderWrap (line 427) | struct HyperBuilderWrap {
    method try_bind (line 432) | pub async fn try_bind(addr: SocketAddr) -> io::Result<HyperBuilderWrap> {
    method serve (line 441) | async fn serve<F>(&mut self, sfn: F) -> io::Result<()>
    method local_addr (line 469) | pub fn local_addr(&self) -> SocketAddr {
  function error_code_response (line 475) | fn error_code_response<E>(uri: hyper::Uri, e: E) -> hyper::Result<Respon...
  function try_bind (line 495) | async fn try_bind() -> Result<HyperBuilderWrap> {
  function get_token_oauth2_code_grant_pkce (line 535) | pub fn get_token_oauth2_code_grant_pkce(
  function get_token_oauth2_implicit (line 593) | pub fn get_token_oauth2_implicit(client_id: &str, mut auth_url: Url) -> ...

FILE: src/dist/http.rs
  type ReqwestRequestBuilderExt (line 34) | pub trait ReqwestRequestBuilderExt: Sized {
    method bincode (line 35) | fn bincode<T: serde::Serialize + ?Sized>(self, bincode: &T) -> Result<...
    method bytes (line 36) | fn bytes(self, bytes: Vec<u8>) -> Self;
    method bincode (line 39) | fn bincode<T: serde::Serialize + ?Sized>(self, bincode: &T) -> Result<...
    method bytes (line 44) | fn bytes(self, bytes: Vec<u8>) -> Self {
    method bincode (line 54) | fn bincode<T: serde::Serialize + ?Sized>(self, bincode: &T) -> Result<...
    method bytes (line 59) | fn bytes(self, bytes: Vec<u8>) -> Self {
  function bincode_req_fut (line 70) | pub async fn bincode_req_fut<T: serde::de::DeserializeOwned + 'static>(
  type AllocJobHttpResponse (line 97) | pub enum AllocJobHttpResponse {
    method from_alloc_job_result (line 109) | pub fn from_alloc_job_result(
  type ServerCertificateHttpResponse (line 140) | pub struct ServerCertificateHttpResponse {
  type HeartbeatServerHttpRequest (line 148) | pub struct HeartbeatServerHttpRequest {
    method fmt (line 159) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  type RunJobHttpRequest (line 180) | pub struct RunJobHttpRequest {
  function scheduler_alloc_job (line 189) | pub fn scheduler_alloc_job(scheduler_url: &reqwest::Url) -> reqwest::Url {
  function scheduler_server_certificate (line 194) | pub fn scheduler_server_certificate(
  function scheduler_heartbeat_server (line 205) | pub fn scheduler_heartbeat_server(scheduler_url: &reqwest::Url) -> reqwe...
  function scheduler_job_state (line 210) | pub fn scheduler_job_state(scheduler_url: &reqwest::Url, job_id: JobId) ...
  function scheduler_status (line 215) | pub fn scheduler_status(scheduler_url: &reqwest::Url) -> reqwest::Url {
  function server_assign_job (line 221) | pub fn server_assign_job(server_id: ServerId, job_id: JobId) -> reqwest:...
  function server_submit_toolchain (line 229) | pub fn server_submit_toolchain(server_id: ServerId, job_id: JobId) -> re...
  function server_run_job (line 237) | pub fn server_run_job(server_id: ServerId, job_id: JobId) -> reqwest::Url {
  constant HEARTBEAT_INTERVAL (line 277) | const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(30);
  constant HEARTBEAT_ERROR_INTERVAL (line 278) | const HEARTBEAT_ERROR_INTERVAL: Duration = Duration::from_secs(10);
  constant HEARTBEAT_TIMEOUT (line 279) | pub const HEARTBEAT_TIMEOUT: Duration = Duration::from_secs(90);
  function bincode_req (line 281) | pub fn bincode_req<T: serde::de::DeserializeOwned + 'static>(
  function create_https_cert_and_privkey (line 303) | fn create_https_cert_and_privkey(addr: SocketAddr) -> Result<(Vec<u8>, V...
  type ClientVisibleMsg (line 385) | pub struct ClientVisibleMsg(String);
    method from_nonsensitive (line 387) | pub fn from_nonsensitive(s: String) -> Self {
  type ClientAuthCheck (line 392) | pub trait ClientAuthCheck: Send + Sync {
    method check (line 393) | fn check(&self, token: &str) -> StdResult<(), ClientVisibleMsg>;
  type ServerAuthCheck (line 395) | pub type ServerAuthCheck = Box<dyn Fn(&str) -> Option<ServerId> + Send +...
  constant JWT_KEY_LENGTH (line 397) | const JWT_KEY_LENGTH: usize = 256 / 8;
  type RouilleBincodeError (line 410) | pub enum RouilleBincodeError {
    method from (line 416) | fn from(err: bincode::Error) -> RouilleBincodeError {
    method source (line 421) | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
    method fmt (line 429) | fn fmt(
  function bincode_input (line 448) | fn bincode_input<O>(request: &rouille::Request) -> std::result::Result<O...
  type ErrJson (line 469) | pub struct ErrJson {
    method from_err (line 475) | fn from_err<E: ?Sized + std::error::Error>(err: &E) -> ErrJson {
    method into_data (line 483) | fn into_data(self) -> String {
  function make_401_with_body (line 521) | fn make_401_with_body(short_err: &str, body: ClientVisibleMsg) -> rouill...
  function make_401 (line 532) | fn make_401(short_err: &str) -> rouille::Response {
  function bearer_http_auth (line 535) | fn bearer_http_auth(request: &rouille::Request) -> Option<&str> {
  function bincode_response (line 549) | pub fn bincode_response<T>(content: &T) -> rouille::Response
  function prepare_response (line 569) | pub fn prepare_response<T>(request: &rouille::Request, content: &T) -> r...
  type JobJwt (line 599) | struct JobJwt {
  type JWTJobAuthorizer (line 605) | struct JWTJobAuthorizer {
    method new (line 609) | fn new(server_key: Vec<u8>) -> Box<Self> {
    method generate_token (line 614) | fn generate_token(&self, job_id: JobId) -> Result<String> {
    method verify_token (line 620) | fn verify_token(&self, job_id: JobId, token: &str) -> Result<()> {
  function test_job_token_verification (line 638) | fn test_job_token_verification() {
  type Scheduler (line 661) | pub struct Scheduler<S> {
  function new (line 671) | pub fn new(
  function start (line 685) | pub fn start(self) -> Result<Infallible> {
  type SchedulerRequester (line 864) | struct SchedulerRequester {
    method do_assign_job (line 869) | fn do_assign_job(
  type Server (line 883) | pub struct Server<S> {
  function new (line 899) | pub fn new(
  function start (line 926) | pub fn start(self) -> Result<Infallible> {
  type ServerRequester (line 1043) | struct ServerRequester {
    method do_update_job_state (line 1050) | fn do_update_job_state(
  constant REQUEST_TIMEOUT_SECS (line 1096) | const REQUEST_TIMEOUT_SECS: u64 = 1200;
  constant CONNECT_TIMEOUT_SECS (line 1097) | const CONNECT_TIMEOUT_SECS: u64 = 5;
  type Client (line 1099) | pub struct Client {
    method new (line 1111) | pub fn new(
    method update_certs (line 1144) | fn update_certs(
    method do_alloc_job (line 1178) | async fn do_alloc_job(&self, tc: Toolchain) -> Result<AllocJobResult> {
    method do_get_status (line 1238) | async fn do_get_status(&self) -> Result<SchedulerStatusResult> {
    method do_submit_toolchain (line 1245) | async fn do_submit_toolchain(
    method do_run_job (line 1265) | async fn do_run_job(
    method put_toolchain (line 1311) | async fn put_toolchain(
    method rewrite_includes_only (line 1328) | fn rewrite_includes_only(&self) -> bool {
    method get_custom_toolchain (line 1331) | fn get_custom_toolchain(&self, exe: &Path) -> Option<PathBuf> {

FILE: src/dist/mod.rs
  type ToolchainPackager (line 52) | pub trait ToolchainPackager {}
  type InputsPackager (line 53) | pub trait InputsPackager {}
  function take_prefix (line 62) | fn take_prefix<'a>(components: &'a mut Components<'_>) -> Option<PrefixC...
  function transform_prefix_component (line 75) | fn transform_prefix_component(pc: PrefixComponent<'_>) -> Option<String> {
  type PathTransformer (line 96) | pub struct PathTransformer {
    method new (line 101) | pub fn new() -> Self {
    method as_dist_abs (line 106) | pub fn as_dist_abs(&mut self, p: &Path) -> Option<String> {
    method as_dist (line 112) | pub fn as_dist(&mut self, p: &Path) -> Option<String> {
    method disk_mappings (line 157) | pub fn disk_mappings(&self) -> impl Iterator<Item = (PathBuf, String)> {
    method to_local (line 185) | pub fn to_local(&self, p: &str) -> Option<PathBuf> {
    method new (line 276) | pub fn new() -> Self {
    method as_dist_abs (line 279) | pub fn as_dist_abs(&mut self, p: &Path) -> Option<String> {
    method as_dist (line 285) | pub fn as_dist(&mut self, p: &Path) -> Option<String> {
    method disk_mappings (line 288) | pub fn disk_mappings(&self) -> impl Iterator<Item = (PathBuf, String)> {
    method to_local (line 291) | pub fn to_local(&self, p: &str) -> Option<PathBuf> {
  function test_basic (line 191) | fn test_basic() {
  function test_relative_paths (line 223) | fn test_relative_paths() {
  function test_verbatim_disks (line 231) | fn test_verbatim_disks() {
  function test_slash_directions (line 258) | fn test_slash_directions() {
  type PathTransformer (line 273) | pub struct PathTransformer;
    method new (line 101) | pub fn new() -> Self {
    method as_dist_abs (line 106) | pub fn as_dist_abs(&mut self, p: &Path) -> Option<String> {
    method as_dist (line 112) | pub fn as_dist(&mut self, p: &Path) -> Option<String> {
    method disk_mappings (line 157) | pub fn disk_mappings(&self) -> impl Iterator<Item = (PathBuf, String)> {
    method to_local (line 185) | pub fn to_local(&self, p: &str) -> Option<PathBuf> {
    method new (line 276) | pub fn new() -> Self {
    method as_dist_abs (line 279) | pub fn as_dist_abs(&mut self, p: &Path) -> Option<String> {
    method as_dist (line 285) | pub fn as_dist(&mut self, p: &Path) -> Option<String> {
    method disk_mappings (line 288) | pub fn disk_mappings(&self) -> impl Iterator<Item = (PathBuf, String)> {
    method to_local (line 291) | pub fn to_local(&self, p: &str) -> Option<PathBuf> {
  function osstrings_to_strings (line 297) | pub fn osstrings_to_strings(osstrings: &[OsString]) -> Option<Vec<String...
  function osstring_tuples_to_strings (line 304) | pub fn osstring_tuples_to_strings(
  function strings_to_osstrings (line 313) | pub fn strings_to_osstrings(strings: &[String]) -> Vec<OsString> {
  function try_compile_command_to_dist (line 321) | pub fn try_compile_command_to_dist(
  type Toolchain (line 349) | pub struct Toolchain {
  type JobId (line 355) | pub struct JobId(pub u64);
    method fmt (line 357) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  type Err (line 362) | type Err = <u64 as FromStr>::Err;
  method from_str (line 363) | fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
  type ServerId (line 369) | pub struct ServerId(SocketAddr);
    method new (line 371) | pub fn new(addr: SocketAddr) -> Self {
    method addr (line 374) | pub fn addr(&self) -> SocketAddr {
  type Err (line 379) | type Err = <SocketAddr as FromStr>::Err;
  method from_str (line 380) | fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
  type ServerNonce (line 386) | pub struct ServerNonce(u64);
    method new (line 388) | pub fn new() -> Self {
  type JobState (line 395) | pub enum JobState {
    method fmt (line 402) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  type CompileCommand (line 416) | pub struct CompileCommand {
  type ProcessOutput (line 428) | pub struct ProcessOutput {
    method try_from (line 435) | pub fn try_from(o: process::Output) -> Result<Self> {
    method fake_output (line 448) | pub fn fake_output(code: i32, stdout: Vec<u8>, stderr: Vec<u8>) -> Self {
  function exit_status (line 461) | fn exit_status(code: i32) -> process::ExitStatus {
  function exit_status (line 465) | fn exit_status(code: i32) -> process::ExitStatus {
  function from (line 471) | fn from(o: ProcessOutput) -> Self {
  type OutputData (line 483) | pub struct OutputData(Vec<u8>, u64);
    method try_from_reader (line 486) | pub fn try_from_reader<R: Read>(r: R) -> io::Result<Self> {
    method lens (line 494) | pub fn lens(&self) -> OutputDataLens {
    method into_reader (line 501) | pub fn into_reader(self) -> impl Read {
  type OutputDataLens (line 506) | pub struct OutputDataLens {
    method fmt (line 511) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  type JobAlloc (line 524) | pub struct JobAlloc {
  type AllocJobResult (line 531) | pub enum AllocJobResult {
  type AssignJobResult (line 545) | pub struct AssignJobResult {
  type UpdateJobStateResult (line 554) | pub enum UpdateJobStateResult {
  type HeartbeatServerResult (line 563) | pub struct HeartbeatServerResult {
  type RunJobResult (line 571) | pub enum RunJobResult {
  type JobComplete (line 577) | pub struct JobComplete {
  type SchedulerStatusResult (line 586) | pub struct SchedulerStatusResult {
  type SubmitToolchainResult (line 596) | pub enum SubmitToolchainResult {
  type BuildResult (line 606) | pub struct BuildResult {
  type ToolchainReader (line 618) | pub struct ToolchainReader<'a>(Box<dyn Read + 'a>);
  method read (line 620) | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
  type InputsReader (line 625) | pub struct InputsReader<'a>(Box<dyn Read + Send + 'a>);
  method read (line 627) | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
  type ExtResult (line 633) | type ExtResult<T, E> = ::std::result::Result<T, E>;
  type SchedulerOutgoing (line 636) | pub trait SchedulerOutgoing {
    method do_assign_job (line 638) | fn do_assign_job(
  type ServerOutgoing (line 648) | pub trait ServerOutgoing {
    method do_update_job_state (line 650) | fn do_update_job_state(&self, job_id: JobId, state: JobState) -> Resul...
  type JobAuthorizer (line 655) | pub trait JobAuthorizer: Send {
    method generate_token (line 656) | fn generate_token(&self, job_id: JobId) -> Result<String>;
    method verify_token (line 657) | fn verify_token(&self, job_id: JobId, token: &str) -> Result<()>;
  type SchedulerIncoming (line 661) | pub trait SchedulerIncoming: Send + Sync {
    method handle_alloc_job (line 663) | fn handle_alloc_job(
    method handle_heartbeat_server (line 669) | fn handle_heartbeat_server(
    method handle_update_job_state (line 677) | fn handle_update_job_state(
    method handle_status (line 684) | fn handle_status(&self) -> ExtResult<SchedulerStatusResult, Error>;
  type ServerIncoming (line 688) | pub trait ServerIncoming: Send + Sync {
    method handle_assign_job (line 690) | fn handle_assign_job(&self, job_id: JobId, tc: Toolchain) -> ExtResult...
    method handle_submit_toolchain (line 692) | fn handle_submit_toolchain(
    method handle_run_job (line 699) | fn handle_run_job(
  type BuilderIncoming (line 710) | pub trait BuilderIncoming: Send + Sync {
    method run_build (line 712) | fn run_build(
  type Client (line 724) | pub trait Client: Send + Sync {
    method do_alloc_job (line 726) | async fn do_alloc_job(&self, tc: Toolchain) -> Result<AllocJobResult>;
    method do_get_status (line 728) | async fn do_get_status(&self) -> Result<SchedulerStatusResult>;
    method do_submit_toolchain (line 730) | async fn do_submit_toolchain(
    method do_run_job (line 736) | async fn do_run_job(
    method put_toolchain (line 743) | async fn put_toolchain(
    method rewrite_includes_only (line 749) | fn rewrite_includes_only(&self) -> bool;
    method get_custom_toolchain (line 750) | fn get_custom_toolchain(&self, exe: &Path) -> Option<PathBuf>;

FILE: src/dist/pkg.rs
  type ToolchainPackager (line 26) | pub trait ToolchainPackager: Send {
    method write_pkg (line 27) | fn write_pkg(self: Box<Self>, f: fs::File) -> Result<()>;
    method write_pkg (line 49) | fn write_pkg(self: Box<Self>, _f: fs::File) -> Result<()> {
  type InputsPackager (line 30) | pub trait InputsPackager: Send {
    method write_inputs (line 31) | fn write_inputs(self: Box<Self>, wtr: &mut dyn io::Write) -> Result<di...
  type OutputsRepackager (line 34) | pub trait OutputsRepackager {
    method repackage_outputs (line 35) | fn repackage_outputs(self: Box<Self>, wtr: &mut dyn io::Write)
  type ToolchainPackageBuilder (line 68) | pub struct ToolchainPackageBuilder {
    method new (line 79) | pub fn new() -> Self {
    method add_common (line 87) | pub fn add_common(&mut self) -> Result<()> {
    method add_executable_and_deps (line 91) | pub fn add_executable_and_deps(&mut self, executable: PathBuf) -> Resu...
    method add_dir (line 113) | pub fn add_dir(&mut self, dir_path: PathBuf) -> Result<()> {
    method add_file (line 134) | pub fn add_file(&mut self, file_path: PathBuf) -> Result<()> {
    method add_dir_contents (line 147) | pub fn add_dir_contents(&mut self, dir_path: &Path) -> Result<()> {
    method into_compressed_tar (line 172) | pub fn into_compressed_tar<W: Write + Send + 'static>(self, writer: W)...
    method tarify_path (line 210) | fn tarify_path(&mut self, path: &Path) -> Result<PathBuf> {
  function tar_safe_path (line 220) | fn tar_safe_path(path: PathBuf) -> PathBuf {
  function find_ldd_libraries (line 247) | fn find_ldd_libraries(executable: &Path) -> Result<Vec<PathBuf>> {
  function parse_ldd_output (line 293) | fn parse_ldd_output(stdout: &str) -> Vec<PathBuf> {
  function test_ldd_parse (line 345) | fn test_ldd_parse() {
  function test_ldd_parse_static (line 371) | fn test_ldd_parse_static() {
  function test_ldd_parse_v2_30 (line 382) | fn test_ldd_parse_v2_30() {
  function make_tar_header (line 405) | pub fn make_tar_header(src: &Path, dest: &str) -> io::Result<tar::Header> {
  function simplify_path (line 453) | pub fn simplify_path(path: &Path) -> Result<PathBuf> {
  type SimplifyPath (line 460) | struct SimplifyPath<'a> {
  function simplify (line 465) | pub fn simplify(&mut self, path: &Path) -> Result<PathBuf> {

FILE: src/errors.rs
  type BadHttpStatusError (line 27) | pub struct BadHttpStatusError(pub hyper::StatusCode);
    method fmt (line 44) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  type HttpClientError (line 30) | pub struct HttpClientError(pub String);
    method fmt (line 50) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  type ProcessError (line 33) | pub struct ProcessError(pub process::Output);
    method fmt (line 56) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  type Result (line 61) | pub type Result<T> = anyhow::Result<T>;

FILE: src/jobserver.rs
  function discard_inherited_jobserver (line 37) | pub unsafe fn discard_inherited_jobserver() {
  type Client (line 74) | pub struct Client {
    method new (line 85) | pub fn new() -> Client {
    method new_num (line 89) | pub fn new_num(num: usize) -> Client {
    method _new (line 94) | fn _new(inner: jobserver::Client, inherited: bool) -> Client {
    method configure (line 119) | pub fn configure(&self, cmd: &mut Command) {
    method acquire (line 128) | pub async fn acquire(&self) -> Result<Acquired> {
  type Acquired (line 80) | pub struct Acquired {

FILE: src/lib.rs
  constant VERSION (line 58) | pub const VERSION: &str = env!("CARGO_PKG_VERSION");
  constant LOGGING_ENV (line 62) | pub const LOGGING_ENV: &str = "SCCACHE_LOG";
  function main (line 64) | pub fn main() {
  function init_logging (line 94) | fn init_logging() {

FILE: src/lru_disk_cache/lru_cache.rs
  type Meter (line 55) | pub trait Meter<K, V> {
    method measure (line 59) | fn measure<Q: ?Sized>(&self, key: &Q, value: &V) -> Self::Measure
  type Count (line 65) | pub struct Count;
    type Measure (line 69) | type Measure = ();
    method measure (line 72) | fn measure<Q: ?Sized>(&self, _: &Q, _: &V)
    method meter_add (line 138) | fn meter_add(&self, _current: (), _amount: ()) {}
    method meter_sub (line 139) | fn meter_sub(&self, _current: (), _amount: ()) {}
    method meter_size (line 140) | fn meter_size(&self, _current: ()) -> Option<u64> {
  type CountableMeter (line 81) | pub trait CountableMeter<K, V>: Meter<K, V> {
    method add (line 83) | fn add(&self, current: Self::Measure, amount: Self::Measure) -> Self::...
    method sub (line 85) | fn sub(&self, current: Self::Measure, amount: Self::Measure) -> Self::...
    method size (line 90) | fn size(&self, current: Self::Measure) -> Option<u64>;
  method add (line 98) | fn add(&self, current: Self::Measure, amount: Self::Measure) -> Self::Me...
  method sub (line 101) | fn sub(&self, current: Self::Measure, amount: Self::Measure) -> Self::Me...
  method size (line 104) | fn size(&self, current: Self::Measure) -> Option<u64> {
  type CountableMeterWithMeasure (line 109) | pub trait CountableMeterWithMeasure<K, V, M> {
    method meter_add (line 111) | fn meter_add(&self, current: M, amount: M) -> M;
    method meter_sub (line 113) | fn meter_sub(&self, current: M, amount: M) -> M;
    method meter_size (line 118) | fn meter_size(&self, current: M) -> Option<u64>;
  method meter_add (line 126) | fn meter_add(&self, current: usize, amount: usize) -> usize {
  method meter_sub (line 129) | fn meter_sub(&self, current: usize, amount: usize) -> usize {
  method meter_size (line 132) | fn meter_size(&self, current: usize) -> Option<u64> {
  type LruCache (line 147) | pub struct LruCache<K: Eq + Hash, V, S: BuildHasher = RandomState, M: Co...
  function new (line 164) | pub fn new(capacity: u64) -> Self {
  function with_meter (line 208) | pub fn with_meter(capacity: u64, meter: M) -> LruCache<K, V, RandomState...
  function with_hasher (line 220) | pub fn with_hasher(capacity: u64, hash_builder: S) -> LruCache<K, V, S, ...
  function get_mut (line 250) | pub fn get_mut<Q: Hash + Eq + ?Sized>(&mut self, k: &Q) -> Option<&mut V>
  function iter_mut (line 288) | pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
  function with_meter_and_hasher (line 296) | pub fn with_meter_and_hasher(capacity: u64, meter: M, hash_builder: S) -...
  function capacity (line 315) | pub fn capacity(&self) -> u64 {
  function contains_key (line 331) | pub fn contains_key<Q: Hash + Eq + ?Sized>(&self, key: &Q) -> bool
  function get (line 338) | pub fn get<Q: Hash + Eq + ?Sized>(&mut self, k: &Q) -> Option<&V>
  function insert (line 360) | pub fn insert(&mut self, k: K, v: V) -> Option<V> {
  function remove (line 391) | pub fn remove<Q: Hash + Eq + ?Sized>(&mut self, k: &Q) -> Option<V>
  function set_capacity (line 436) | pub fn set_capacity(&mut self, capacity: u64) {
  function remove_lru (line 459) | pub fn remove_lru(&mut self) -> Option<(K, V)> {
  function len (line 469) | pub fn len(&self) -> usize {
  function size (line 475) | pub fn size(&self) -> u64 {
  function is_empty (line 482) | pub fn is_empty(&self) -> bool {
  function clear (line 487) | pub fn clear(&mut self) {
  function iter (line 510) | pub fn iter(&self) -> Iter<'_, K, V> {
  function internal_iter_mut (line 514) | fn internal_iter_mut(&mut self) -> IterMut<'_, K, V> {
  function extend (line 522) | fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
  function fmt (line 532) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  type Item (line 540) | type Item = (K, V);
  type IntoIter (line 541) | type IntoIter = IntoIter<K, V>;
  method into_iter (line 543) | fn into_iter(self) -> IntoIter<K, V> {
  type Item (line 551) | type Item = (&'a K, &'a V);
  type IntoIter (line 552) | type IntoIter = Iter<'a, K, V>;
  method into_iter (line 553) | fn into_iter(self) -> Iter<'a, K, V> {
  type Item (line 561) | type Item = (&'a K, &'a mut V);
  type IntoIter (line 562) | type IntoIter = IterMut<'a, K, V>;
  method into_iter (line 563) | fn into_iter(self) -> IterMut<'a, K, V> {
  type IntoIter (line 592) | pub struct IntoIter<K, V>(linked_hash_map::IntoIter<K, V>);
  type Item (line 595) | type Item = (K, V);
  method next (line 597) | fn next(&mut self) -> Option<(K, V)> {
  method size_hint (line 601) | fn size_hint(&self) -> (usize, Option<usize>) {
  method next_back (line 607) | fn next_back(&mut self) -> Option<(K, V)> {
  method len (line 613) | fn len(&self) -> usize {
  type Iter (line 621) | pub struct Iter<'a, K, V>(linked_hash_map::Iter<'a, K, V>);
  method clone (line 624) | fn clone(&self) -> Iter<'a, K, V> {
  type Item (line 630) | type Item = (&'a K, &'a V);
  method next (line 631) | fn next(&mut self) -> Option<(&'a K, &'a V)> {
  method size_hint (line 634) | fn size_hint(&self) -> (usize, Option<usize>) {
  method next_back (line 640) | fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
  method len (line 646) | fn len(&self) -> usize {
  type IterMut (line 655) | pub struct IterMut<'a, K, V>(linked_hash_map::IterMut<'a, K, V>);
  type Item (line 658) | type Item = (&'a K, &'a mut V);
  method next (line 659) | fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
  method size_hint (line 662) | fn size_hint(&self) -> (usize, Option<usize>) {
  method next_back (line 668) | fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> {
  method len (line 674) | fn len(&self) -> usize {
  function test_put_and_get (line 685) | fn test_put_and_get() {
  function test_put_update (line 696) | fn test_put_update() {
  function test_contains_key (line 705) | fn test_contains_key() {
  function test_expire_lru (line 712) | fn test_expire_lru() {
  function test_pop (line 724) | fn test_pop() {
  function test_change_capacity (line 737) | fn test_change_capacity() {
  function test_debug (line 748) | fn test_debug() {
  function test_remove (line 765) | fn test_remove() {
  function test_clear (line 786) | fn test_clear() {
  function test_iter (line 797) | fn test_iter() {
  type VecLen (line 822) | struct VecLen;
    type Measure (line 825) | type Measure = usize;
    method measure (line 826) | fn measure<Q: ?Sized>(&self, _: &Q, v: &Vec<T>) -> usize
  function test_metered_cache (line 835) | fn test_metered_cache() {
  function test_metered_cache_reinsert_larger (line 851) | fn test_metered_cache_reinsert_larger() {
  function test_metered_cache_oversize (line 862) | fn test_metered_cache_oversize() {

FILE: src/lru_disk_cache/mod.rs
  constant TEMPFILE_PREFIX (line 23) | const TEMPFILE_PREFIX: &str = ".sccachetmp";
  type FileSize (line 25) | struct FileSize;
    type Measure (line 29) | type Measure = usize;
    method measure (line 30) | fn measure<Q: ?Sized>(&self, _: &Q, v: &u64) -> usize
  function get_all_files (line 40) | fn get_all_files<P: AsRef<Path>>(path: P) -> Box<dyn Iterator<Item = (Pa...
  type LruDiskCache (line 65) | pub struct LruDiskCache<S: BuildHasher = RandomState> {
    method new (line 143) | pub fn new<T>(path: T, size: u64) -> Result<Self>
    method size (line 157) | pub fn size(&self) -> u64 {
    method len (line 162) | pub fn len(&self) -> usize {
    method is_empty (line 166) | pub fn is_empty(&self) -> bool {
    method capacity (line 171) | pub fn capacity(&self) -> u64 {
    method path (line 176) | pub fn path(&self) -> &Path {
    method rel_to_abs_path (line 181) | fn rel_to_abs_path<K: AsRef<Path>>(&self, rel_path: K) -> PathBuf {
    method init (line 186) | fn init(mut self) -> Result<Self> {
    method can_store (line 213) | pub fn can_store(&self, size: u64) -> bool {
    method make_space (line 217) | fn make_space(&mut self, size: u64) -> Result<()> {
    method add_file (line 250) | fn add_file(&mut self, addfile_path: AddFile<'_>, size: u64) -> Result...
    method insert_by (line 260) | fn insert_by<K: AsRef<OsStr>, F: FnOnce(&Path) -> io::Result<()>>(
    method insert_with (line 293) | pub fn insert_with<K: AsRef<OsStr>, F: FnOnce(File) -> io::Result<()>>(
    method insert_bytes (line 302) | pub fn insert_bytes<K: AsRef<OsStr>>(&mut self, key: K, bytes: &[u8]) ...
    method insert_file (line 311) | pub fn insert_file<K: AsRef<OsStr>, P: AsRef<OsStr>>(&mut self, key: K...
    method prepare_add (line 327) | pub fn prepare_add<'a, K: AsRef<OsStr> + 'a>(
    method commit (line 345) | pub fn commit(&mut self, entry: LruDiskCacheAddEntry) -> Result<()> {
    method contains_key (line 371) | pub fn contains_key<K: AsRef<OsStr>>(&self, key: K) -> bool {
    method get_file (line 379) | pub fn get_file<K: AsRef<OsStr>>(&mut self, key: K) -> Result<File> {
    method get (line 396) | pub fn get<K: AsRef<OsStr>>(&mut self, key: K) -> Result<Box<dyn ReadS...
    method remove (line 401) | pub fn remove<K: AsRef<OsStr>>(&mut self, key: K) -> Result<()> {
  type Error (line 74) | pub enum Error {
    method fmt (line 84) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    method from (line 104) | fn from(e: io::Error) -> Error {
  method source (line 94) | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
  type Result (line 110) | pub type Result<T> = std::result::Result<T, Error>;
  type ReadSeek (line 113) | pub trait ReadSeek: Read + Seek + Send {}
  type AddFile (line 117) | enum AddFile<'a> {
  type LruDiskCacheAddEntry (line 122) | pub struct LruDiskCacheAddEntry {
    method as_file_mut (line 129) | pub fn as_file_mut(&mut self) -> &mut std::fs::File {
  type TestFixture (line 425) | struct TestFixture {
    method new (line 457) | pub fn new() -> TestFixture {
    method tmp (line 466) | pub fn tmp(&self) -> &Path {
    method create_file (line 470) | pub fn create_file<T: AsRef<Path>>(&self, path: T, size: usize) -> Pat...
  function create_file (line 430) | fn create_file<T: AsRef<Path>, F: FnOnce(File) -> io::Result<()>>(
  function set_mtime_back (line 443) | fn set_mtime_back<T: AsRef<Path>>(path: T, seconds: usize) {
  function read_all (line 450) | fn read_all<R: Read>(r: &mut R) -> io::Result<Vec<u8>> {
  function test_empty_dir (line 479) | fn test_empty_dir() {
  function test_missing_root (line 485) | fn test_missing_root() {
  function test_some_existing_files (line 491) | fn test_some_existing_files() {
  function test_existing_file_too_large (line 501) | fn test_existing_file_too_large() {
  function test_existing_files_lru_mtime (line 514) | fn test_existing_files_lru_mtime() {
  function test_insert_bytes (line 529) | fn test_insert_bytes() {
  function test_insert_bytes_exact (line 545) | fn test_insert_bytes_exact() {
  function test_add_get_lru (line 558) | fn test_add_get_lru() {
  function test_insert_bytes_too_large (line 601) | fn test_insert_bytes_too_large() {
  function test_insert_file (line 611) | fn test_insert_file() {
  function test_prepare_and_commit (line 638) | fn test_prepare_and_commit() {
  function test_remove (line 701) | fn test_remove() {

FILE: src/main.rs
  function main (line 17) | fn main() {

FILE: src/mock_command.rs
  type CommandChild (line 63) | pub trait CommandChild {
    method take_stdin (line 72) | fn take_stdin(&mut self) -> Option<Self::I>;
    method take_stdout (line 74) | fn take_stdout(&mut self) -> Option<Self::O>;
    method take_stderr (line 76) | fn take_stderr(&mut self) -> Option<Self::E>;
    method wait (line 78) | async fn wait(self) -> io::Result<ExitStatus>;
    method wait_with_output (line 80) | async fn wait_with_output(self) -> io::Result<Output>;
    type I (line 151) | type I = ChildStdin;
    type O (line 152) | type O = ChildStdout;
    type E (line 153) | type E = ChildStderr;
    method take_stdin (line 155) | fn take_stdin(&mut self) -> Option<ChildStdin> {
    method take_stdout (line 158) | fn take_stdout(&mut self) -> Option<ChildStdout> {
    method take_stderr (line 161) | fn take_stderr(&mut self) -> Option<ChildStderr> {
    method wait (line 165) | async fn wait(self) -> io::Result<ExitStatus> {
    method wait_with_output (line 172) | async fn wait_with_output(self) -> io::Result<Output> {
    type I (line 371) | type I = io::Cursor<Vec<u8>>;
    type O (line 372) | type O = io::Cursor<Vec<u8>>;
    type E (line 373) | type E = io::Cursor<Vec<u8>>;
    method take_stdin (line 375) | fn take_stdin(&mut self) -> Option<io::Cursor<Vec<u8>>> {
    method take_stdout (line 378) | fn take_stdout(&mut self) -> Option<io::Cursor<Vec<u8>>> {
    method take_stderr (line 381) | fn take_stderr(&mut self) -> Option<io::Cursor<Vec<u8>>> {
    method wait (line 385) | async fn wait(mut self) -> io::Result<ExitStatus> {
    method wait_with_output (line 389) | async fn wait_with_output(self) -> io::Result<Output> {
  type RunCommand (line 85) | pub trait RunCommand: fmt::Debug + Send {
    method arg (line 90) | fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self;
    method args (line 92) | fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut Self;
    method env (line 94) | fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
    method envs (line 99) | fn envs<I, K, V>(&mut self, vars: I) -> &mut Self
    method env_clear (line 105) | fn env_clear(&mut self) -> &mut Self;
    method current_dir (line 107) | fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Self;
    method stdin (line 109) | fn stdin(&mut self, cfg: Stdio) -> &mut Self;
    method stdout (line 111) | fn stdout(&mut self, cfg: Stdio) -> &mut Self;
    method stderr (line 113) | fn stderr(&mut self, cfg: Stdio) -> &mut Self;
    method spawn (line 115) | async fn spawn(&mut self) -> Result<Self::C>;
    type C (line 201) | type C = Child;
    method arg (line 203) | fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut AsyncCommand {
    method args (line 207) | fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut AsyncCommand {
    method env (line 211) | fn env<K, V>(&mut self, key: K, val: V) -> &mut AsyncCommand
    method envs (line 219) | fn envs<I, K, V>(&mut self, vars: I) -> &mut Self
    method env_clear (line 228) | fn env_clear(&mut self) -> &mut AsyncCommand {
    method current_dir (line 232) | fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut AsyncCommand {
    method stdin (line 237) | fn stdin(&mut self, cfg: Stdio) -> &mut AsyncCommand {
    method stdout (line 241) | fn stdout(&mut self, cfg: Stdio) -> &mut AsyncCommand {
    method stderr (line 245) | fn stderr(&mut self, cfg: Stdio) -> &mut AsyncCommand {
    method spawn (line 249) | async fn spawn(&mut self) -> Result<Child> {
    type C (line 429) | type C = MockChild;
    method arg (line 431) | fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut MockCommand {
    method args (line 435) | fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut MockCommand {
    method env (line 439) | fn env<K, V>(&mut self, _key: K, _val: V) -> &mut MockCommand
    method envs (line 446) | fn envs<I, K, V>(&mut self, _vars: I) -> &mut Self
    method env_clear (line 454) | fn env_clear(&mut self) -> &mut MockCommand {
    method current_dir (line 457) | fn current_dir<P: AsRef<Path>>(&mut self, _dir: P) -> &mut MockCommand {
    method stdin (line 461) | fn stdin(&mut self, _cfg: Stdio) -> &mut MockCommand {
    method stdout (line 464) | fn stdout(&mut self, _cfg: Stdio) -> &mut MockCommand {
    method stderr (line 467) | fn stderr(&mut self, _cfg: Stdio) -> &mut MockCommand {
    method spawn (line 470) | async fn spawn(&mut self) -> Result<MockChild> {
  type CommandCreator (line 123) | pub trait CommandCreator {
    method new (line 128) | fn new(client: &Client) -> Self;
    method new_command (line 131) | fn new_command<S: AsRef<OsStr>>(&mut self, program: S) -> Self::Cmd;
    type Cmd (line 283) | type Cmd = AsyncCommand;
    method new (line 285) | fn new(client: &Client) -> ProcessCommandCreator {
    method new_command (line 291) | fn new_command<S: AsRef<OsStr>>(&mut self, program: S) -> AsyncCommand {
    type Cmd (line 504) | type Cmd = MockCommand;
    method new (line 506) | fn new(_client: &Client) -> MockCommandCreator {
    method new_command (line 512) | fn new_command<S: AsRef<OsStr>>(&mut self, _program: S) -> MockCommand {
  type CommandCreatorSync (line 135) | pub trait CommandCreatorSync: Clone + Send + Sync + 'static {
    method new (line 138) | fn new(client: &Client) -> Self;
    method new_command_sync (line 140) | fn new_command_sync<S: AsRef<OsStr>>(&mut self, program: S) -> Self::Cmd;
    type Cmd (line 298) | type Cmd = AsyncCommand;
    method new (line 300) | fn new(client: &Client) -> ProcessCommandCreator {
    method new_command_sync (line 304) | fn new_command_sync<S: AsRef<OsStr>>(&mut self, program: S) -> AsyncCo...
    type Cmd (line 527) | type Cmd = T::Cmd;
    method new (line 529) | fn new(client: &Client) -> Arc<Mutex<T>> {
    method new_command_sync (line 533) | fn new_command_sync<S: AsRef<OsStr>>(&mut self, program: S) -> T::Cmd {
  type Child (line 143) | pub struct Child {
  type AsyncCommand (line 180) | pub struct AsyncCommand {
    method new (line 186) | pub fn new<S: AsRef<OsStr>>(program: S, jobserver: Client) -> AsyncCom...
    method inner (line 193) | fn inner(&mut self) -> &mut Command {
    method fmt (line 270) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  type ProcessCommandCreator (line 277) | pub struct ProcessCommandCreator {
  type ExitStatusValue (line 316) | pub type ExitStatusValue = i32;
  type ExitStatusValue (line 318) | pub type ExitStatusValue = u32;
  function exit_status (line 321) | pub fn exit_status(v: ExitStatusValue) -> ExitStatus {
  type MockChild (line 328) | pub struct MockChild {
    method new (line 344) | pub fn new<T: AsRef<[u8]>, U: AsRef<[u8]>>(
    method with_error (line 359) | pub fn with_error(err: io::Error) -> MockChild {
  type ChildOrCall (line 405) | pub enum ChildOrCall {
    method fmt (line 411) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  type MockCommand (line 422) | pub struct MockCommand {
  type MockCommandCreator (line 480) | pub struct MockCommandCreator {
    method next_command_spawns (line 488) | pub fn next_command_spawns(&mut self, child: Result<MockChild>) {
    method next_command_calls (line 495) | pub fn next_command_calls<C>(&mut self, call: C)
  function spawn_command (line 549) | fn spawn_command<T: CommandCreator, S: AsRef<OsStr>>(
  function spawn_wait_command (line 556) | fn spawn_wait_command<T: CommandCreator, S: AsRef<OsStr>>(
  function spawn_output_command (line 563) | fn spawn_output_command<T: CommandCreator, S: AsRef<OsStr>>(
  function spawn_on_thread (line 570) | fn spawn_on_thread<T: CommandCreatorSync + Send + 'static>(
  function test_mock_command_wait (line 592) | fn test_mock_command_wait() {
  function test_unexpected_new_command (line 607) | fn test_unexpected_new_command() {
  function test_mock_command_output (line 616) | fn test_mock_command_output() {
  function test_mock_command_calls (line 627) | fn test_mock_command_calls() {
  function test_mock_spawn_error (line 638) | fn test_mock_spawn_error() {
  function test_mock_wait_error (line 647) | fn test_mock_wait_error() {
  function test_mock_command_sync (line 656) | fn test_mock_command_sync() {

FILE: src/net.rs
  type SocketAddr (line 26) | pub enum SocketAddr {
    method fmt (line 36) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    method with_port (line 50) | pub fn with_port(port: u16) -> Self {
    method as_net (line 55) | pub fn as_net(&self) -> Option<&std::net::SocketAddr> {
    method parse_uds (line 67) | pub fn parse_uds(s: &str) -> std::io::Result<Self> {
    method is_unix_path (line 82) | pub fn is_unix_path(&self) -> bool {
    method is_unix_path (line 87) | pub fn is_unix_path(&self) -> bool {
  type Acceptor (line 93) | pub trait Acceptor {
    method accept (line 96) | fn accept(&self) -> impl Future<Output = tokio::io::Result<Self::Socke...
    method local_addr (line 97) | fn local_addr(&self) -> tokio::io::Result<Option<SocketAddr>>;
    type Socket (line 101) | type Socket = tokio::net::TcpStream;
    method accept (line 104) | fn accept(&self) -> impl Future<Output = tokio::io::Result<Self::Socke...
    method local_addr (line 109) | fn local_addr(&self) -> tokio::io::Result<Option<SocketAddr>> {
    type Socket (line 154) | type Socket = tokio::net::UnixStream;
    method accept (line 157) | fn accept(&self) -> impl Future<Output = tokio::io::Result<Self::Socke...
    method local_addr (line 162) | fn local_addr(&self) -> tokio::io::Result<Option<SocketAddr>> {
  type Connection (line 115) | pub trait Connection: std::io::Read + std::io::Write {
    method try_clone (line 116) | fn try_clone(&self) -> std::io::Result<Box<dyn Connection>>;
    method try_clone (line 121) | fn try_clone(&self) -> std::io::Result<Box<dyn Connection>> {
    method try_clone (line 179) | fn try_clone(&self) -> std::io::Result<Box<dyn Connection>> {
  function connect (line 129) | pub fn connect(addr: &SocketAddr) -> std::io::Result<Box<dyn Connection>> {

FILE: src/protocol.rs
  type Request (line 8) | pub enum Request {
  type Response (line 23) | pub enum Response {
  type CompileResponse (line 40) | pub enum CompileResponse {
  type CompileFinished (line 51) | pub struct CompileFinished {
  type Compile (line 66) | pub struct Compile {

FILE: src/server.rs
  constant DEFAULT_IDLE_TIMEOUT (line 75) | const DEFAULT_IDLE_TIMEOUT: u64 = 600;
  constant DIST_CLIENT_RECREATE_TIMEOUT (line 80) | const DIST_CLIENT_RECREATE_TIMEOUT: Duration = Duration::from_secs(30);
  type ServerStartup (line 84) | pub enum ServerStartup {
  function get_idle_timeout (line 96) | fn get_idle_timeout() -> u64 {
  function notify_server_startup_internal (line 104) | fn notify_server_startup_internal<W: Write>(mut w: W, status: ServerStar...
  function notify_server_startup (line 109) | fn notify_server_startup(name: Option<&OsString>, status: ServerStartup)...
  function notify_server_startup (line 121) | fn notify_server_startup(name: Option<&OsString>, status: ServerStartup)...
  function get_signal (line 133) | fn get_signal(status: ExitStatus) -> i32 {
  function get_signal (line 138) | fn get_signal(_status: ExitStatus) -> i32 {
  type DistClientContainer (line 142) | pub struct DistClientContainer {
    method new (line 176) | fn new(config: &Config, _: &tokio::runtime::Handle) -> Self {
    method new_disabled (line 185) | pub fn new_disabled() -> Self {
    method new_with_state (line 190) | pub fn new_with_state(_: DistClientState) -> Self {
    method reset_state (line 194) | pub async fn reset_state(&self) {}
    method get_status (line 196) | pub async fn get_status(&self) -> DistInfo {
    method get_client (line 200) | async fn get_client(&self) -> Result<Option<Arc<dyn dist::Client>>> {
    method new (line 207) | fn new(config: &Config, pool: &tokio::runtime::Handle) -> Self {
    method new_with_state (line 225) | pub fn new_with_state(state: DistClientState) -> Self {
    method new_disabled (line 231) | pub fn new_disabled() -> Self {
    method reset_state (line 237) | pub async fn reset_state(&self) {
    method get_status (line 254) | pub async fn get_status(&self) -> DistInfo {
    method get_client (line 286) | async fn get_client(&self) -> Result<Option<Arc<dyn dist::Client>>> {
    method maybe_recreate_state (line 310) | async fn maybe_recreate_state(state: &mut DistClientState) {
    method create_state (line 325) | async fn create_state(config: DistClientConfig) -> DistClientState {
    method get_cached_config_auth_token (line 411) | fn get_cached_config_auth_token(auth_url: &str) -> Result<String> {
  type DistClientConfig (line 149) | pub struct DistClientConfig {
  type DistClientState (line 163) | pub enum DistClientState {
  function start_server (line 430) | pub fn start_server(config: &Config, addr: &crate::net::SocketAddr) -> R...
  type SccacheServer (line 571) | pub struct SccacheServer<A: crate::net::Acceptor, C: CommandCreatorSync ...
  function new (line 581) | pub fn new(
  function with_listener (line 602) | pub fn with_listener(
  function set_idle_timeout (line 628) | pub fn set_idle_timeout(&mut self, timeout: Duration) {
  function set_storage (line 634) | pub fn set_storage(&mut self, storage: Arc<dyn Storage>) {
  function pool (line 640) | pub fn pool(&self) -> &tokio::runtime::Handle {
  function command_creator (line 646) | pub fn command_creator(&self) -> &C {
  function local_addr (line 652) | pub fn local_addr(&self) -> Option<crate::net::SocketAddr> {
  function run (line 661) | pub fn run<F>(self, shutdown: F) -> io::Result<()>
  type CompilerProxyMap (line 754) | type CompilerProxyMap<C> = HashMap<PathBuf, (Box<dyn CompilerProxy<C>>, ...
  type CompilerMap (line 755) | type CompilerMap<C> = HashMap<PathBuf, Option<CompilerCacheEntry<C>>>;
  type CompilerCacheEntry (line 758) | struct CompilerCacheEntry<C> {
  function new (line 768) | fn new(
  type SccacheService (line 782) | pub struct SccacheService<C>
  type SccacheRequest (line 828) | type SccacheRequest = Message<Request, Body<()>>;
  type SccacheResponse (line 829) | type SccacheResponse = Message<Response, Pin<Box<dyn Future<Output = Res...
  type ServerMessage (line 836) | pub enum ServerMessage {
  type Response (line 847) | type Response = SccacheResponse;
  type Error (line 848) | type Error = Error;
  type Future (line 849) | type Future = Pin<Box<dyn Future<Output = Result<Self::Response>> + Send...
    type Output (line 2162) | type Output = ();
    method poll (line 2164) | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
  function call (line 851) | fn call(&mut self, req: SccacheRequest) -> Self::Future {
  function poll_ready (line 905) | fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<()>> {
  function new (line 917) | pub fn new(
  function mock_with_storage (line 938) | pub fn mock_with_storage(
  function mock_with_dist_client (line 960) | pub fn mock_with_dist_client(
  function bind (line 994) | fn bind<T>(self, socket: T) -> impl Future<Output = Result<()>> + Send +...
  function get_dist_status (line 1041) | async fn get_dist_status(&self) -> Result<DistInfo> {
  function get_info (line 1046) | async fn get_info(&self) -> Result<ServerInfo> {
  function zero_stats (line 1052) | async fn zero_stats(&self) {
  function handle_compile (line 1061) | async fn handle_compile(&self, compile: Compile) -> Result<SccacheRespon...
  function compiler_info (line 1076) | pub async fn compiler_info(
  function check_compiler (line 1233) | async fn check_compiler(
  function start_compile_task (line 1295) | pub async fn start_compile_task(
  type PerLanguageCount (line 1549) | pub struct PerLanguageCount {
    method increment (line 1555) | fn increment(&mut self, kind: &CompilerKind, lang: &Language) {
    method all (line 1565) | pub fn all(&self) -> u64 {
    method get (line 1569) | pub fn get(&self, key: &str) -> Option<&u64> {
    method get_adv (line 1573) | pub fn get_adv(&self, key: &str) -> Option<&u64> {
    method new (line 1577) | pub fn new() -> PerLanguageCount {
  type ServerStats (line 1584) | pub struct ServerStats {
    method print (line 1699) | fn print<T: ServerStatsWriter>(&self, writer: &mut T, advanced: bool) ...
    method set_percentage_stats (line 1866) | fn set_percentage_stats(&self, stats_vec: &mut Vec<(String, String, us...
  type ServerInfo (line 1634) | pub struct ServerInfo {
    method new (line 1933) | pub async fn new(stats: ServerStats, storage: Option<&dyn Storage>) ->...
    method print (line 1971) | pub fn print(&self, advanced: bool) {
  type DistInfo (line 1646) | pub enum DistInfo {
  method default (line 1655) | fn default() -> ServerStats {
  type ServerStatsWriter (line 1683) | pub trait ServerStatsWriter {
    method write (line 1684) | fn write(&mut self, text: &str);
    method write (line 1690) | fn write(&mut self, text: &str) {
    method write (line 2275) | fn write(&mut self, text: &str) {
  type StdoutServerStatsWriter (line 1687) | pub struct StdoutServerStatsWriter;
  function set_percentage_stat (line 1918) | fn set_percentage_stat(
  type Frame (line 2031) | enum Frame<R, R1> {
  type Body (line 2036) | struct Body<R> {
  type Item (line 2041) | type Item = Result<R>;
  function poll_next (line 2042) | fn poll_next(
  type Message (line 2050) | enum Message<R, B> {
  function into_inner (line 2056) | fn into_inner(self) -> R {
  type BincodeCodec (line 2064) | struct BincodeCodec;
    type Error (line 2069) | type Error = Error;
    method serialize (line 2071) | fn serialize(self: Pin<&mut Self>, item: &T) -> std::result::Result<By...
    type Error (line 2082) | type Error = Error;
    method deserialize (line 2084) | fn deserialize(self: Pin<&mut Self>, buf: &BytesMut) -> std::result::R...
  type SccacheTransport (line 2105) | struct SccacheTransport<I: AsyncRead + AsyncWrite + Unpin> {
  type Item (line 2122) | type Item = Result<Message<Request, Body<()>>>;
  method poll_next (line 2124) | fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Opt...
  type Error (line 2132) | type Error = Error;
  function poll_ready (line 2134) | fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Re...
  function start_send (line 2138) | fn start_send(mut self: Pin<&mut Self>, item: Frame<Response, Response>)...
  function poll_flush (line 2146) | fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Re...
  function poll_close (line 2150) | fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Re...
  type ShutdownOrInactive (line 2155) | struct ShutdownOrInactive {
  type WaitUntilZero (line 2188) | struct WaitUntilZero {
    method new (line 2212) | fn new() -> (WaitUntilZero, ActiveInfo) {
    type Output (line 2220) | type Output = ();
    method poll (line 2222) | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> std::task::Poll...
  type ActiveInfo (line 2194) | pub struct ActiveInfo {
  type Info (line 2198) | struct Info {
  method drop (line 2203) | fn drop(&mut self) {
  function waits_until_zero (line 2235) | fn waits_until_zero() {
  type StringWriter (line 2258) | struct StringWriter {
    method new (line 2263) | fn new() -> StringWriter {
    method get_output (line 2269) | fn get_output(self) -> String {
  function test_print_cache_hits_rate_default_server_stats (line 2281) | fn test_print_cache_hits_rate_default_server_stats() {
  function test_print_cache_hits_rate_server_stats (line 2293) | fn test_print_cache_hits_rate_server_stats() {
  function test_print_cache_hits_rate_advanced_server_stats (line 2326) | fn test_print_cache_hits_rate_advanced_server_stats() {
  function test_print_deterministic_hits (line 2361) | fn test_print_deterministic_hits() {

FILE: src/test/mock_storage.rs
  type MockStorage (line 26) | pub struct MockStorage {
    method new (line 35) | pub(crate) fn new(delay: Option<Duration>, preprocessor_cache_mode: bo...
    method next_get (line 46) | pub(crate) fn next_get(&self, res: Result<Cache>) {
  method get (line 53) | async fn get(&self, _key: &str) -> Result<Cache> {
  method put (line 61) | async fn put(&self, _key: &str, _entry: CacheWrite) -> Result<Duration> {
  method location (line 69) | fn location(&self) -> String {
  method current_size (line 72) | async fn current_size(&self) -> Result<Option<u64>> {
  method max_size (line 75) | async fn max_size(&self) -> Result<Option<u64>> {
  method preprocessor_cache_mode_config (line 78) | fn preprocessor_cache_mode_config(&self) -> PreprocessorCacheModeConfig {

FILE: src/test/tests.rs
  type ServerOptions (line 42) | struct ServerOptions {
  function run_server_thread (line 57) | fn run_server_thread<T>(
  function test_server_shutdown (line 111) | fn test_server_shutdown() {
  function test_server_shutdown_no_idle (line 124) | fn test_server_shutdown_no_idle() {
  function test_server_idle_timeout (line 141) | fn test_server_idle_timeout() {
  function test_server_stats (line 159) | fn test_server_stats() {
  function test_server_unsupported_compiler (line 176) | fn test_server_unsupported_compiler() {
  function test_server_compile (line 226) | fn test_server_compile() {
  function test_server_port_in_use (line 302) | fn test_server_port_in_use() {

FILE: src/test/utils.rs
  function new_creator (line 85) | pub fn new_creator() -> Arc<Mutex<MockCommandCreator>> {
  function next_command (line 90) | pub fn next_command(creator: &Arc<Mutex<MockCommandCreator>>, child: Res...
  function next_command_calls (line 94) | pub fn next_command_calls<C: Fn(&[OsString]) -> Result<MockChild> + Send...
  function find_sccache_binary (line 102) | pub fn find_sccache_binary() -> PathBuf {
  type TestFixture (line 120) | pub struct TestFixture {
    method new (line 202) | pub fn new() -> TestFixture {
    method touch (line 225) | pub fn touch(&self, path: &str) -> io::Result<PathBuf> {
    method mk_bin (line 230) | pub fn mk_bin(&self, path: &str) -> io::Result<PathBuf> {
  constant SUBDIRS (line 129) | pub const SUBDIRS: &[&str] = &["a", "b", "c"];
  constant BIN_NAME (line 130) | pub const BIN_NAME: &str = "bin";
  function create_file (line 132) | pub fn create_file<F>(dir: &Path, path: &str, fill_contents: F) -> io::R...
  function touch (line 144) | pub fn touch(dir: &Path, path: &str) -> io::Result<PathBuf> {
  function mk_bin_contents (line 149) | pub fn mk_bin_contents<F: FnOnce(File) -> io::Result<()>>(
  function mk_bin (line 169) | pub fn mk_bin(dir: &Path, path: &str) -> io::Result<PathBuf> {
  function mk_bin_contents (line 175) | pub fn mk_bin_contents<F: FnOnce(File) -> io::Result<()>>(
  function mk_bin (line 191) | pub fn mk_bin(dir: &Path, path: &str) -> io::Result<PathBuf> {
  function single_threaded_runtime (line 235) | pub fn single_threaded_runtime() -> tokio::runtime::Runtime {
  type Waiter (line 247) | pub(crate) trait Waiter<R> {
    method wait (line 248) | fn wait(self) -> R;
  method wait (line 255) | fn wait(self) -> O {
  function test_map_contains_ok (line 262) | fn test_map_contains_ok() {
  function test_map_contains_extra_key (line 271) | fn test_map_contains_extra_key() {
  function test_map_contains_missing_key (line 280) | fn test_map_contains_missing_key() {
  function test_map_contains_wrong_value (line 288) | fn test_map_contains_wrong_value() {

FILE: src/util.rs
  constant BASE64_URL_SAFE_ENGINE (line 37) | pub const BASE64_URL_SAFE_ENGINE: base64::engine::GeneralPurpose =
  constant HASH_BUFFER_SIZE (line 40) | pub const HASH_BUFFER_SIZE: usize = 128 * 1024;
  type Digest (line 43) | pub struct Digest {
    method new (line 48) | pub fn new() -> Digest {
    method file (line 56) | pub async fn file<T>(path: T, pool: &tokio::runtime::Handle) -> Result...
    method reader_sync (line 64) | pub fn reader_sync<R: Read>(reader: R) -> Result<String> {
    method reader_sync_with (line 70) | pub fn reader_sync_with<R: Read, F: FnMut(&[u8])>(mut reader: R, mut e...
    method reader_sync_time_macros (line 89) | pub fn reader_sync_time_macros<R: Read>(reader: R) -> Result<(String, ...
    method reader (line 100) | pub async fn reader(path: PathBuf, pool: &tokio::runtime::Handle) -> R...
    method update (line 109) | pub fn update(&mut self, bytes: &[u8]) {
    method delimiter (line 113) | pub fn delimiter(&mut self, name: &[u8]) {
    method finish (line 119) | pub fn finish(self) -> String {
  method default (line 125) | fn default() -> Self {
  constant MAX_HAYSTACK_LEN (line 131) | const MAX_HAYSTACK_LEN: usize = b"__TIMESTAMP__".len();
  constant MAX_TIME_MACRO_HAYSTACK_LEN (line 134) | pub const MAX_TIME_MACRO_HAYSTACK_LEN: usize = MAX_HAYSTACK_LEN;
  type TimeMacroFinder (line 142) | pub struct TimeMacroFinder {
    method find_time_macros (line 196) | pub fn find_time_macros(&mut self, visit: &[u8]) {
    method find_macros (line 268) | fn find_macros(&self, buffer: &[u8]) {
    method found_time_macros (line 287) | pub fn found_time_macros(&self) -> bool {
    method found_time (line 291) | pub fn found_time(&self) -> bool {
    method found_date (line 295) | pub fn found_date(&self) -> bool {
    method found_timestamp (line 299) | pub fn found_timestamp(&self) -> bool {
    method new (line 303) | pub fn new() -> Self {
  function hex (line 308) | pub fn hex(bytes: &[u8]) -> String {
  function hash_all (line 326) | pub async fn hash_all(files: &[PathBuf], pool: &tokio::runtime::Handle) ...
  function hash_all_archives (line 346) | pub async fn hash_all_archives(
  function hash_regular_archive (line 391) | fn hash_regular_archive(m: &mut Digest, data: &[u8]) -> Result<()> {
  function fmt_duration_as_secs (line 402) | pub fn fmt_duration_as_secs(duration: &Duration) -> String {
  function wait_with_input_output (line 410) | async fn wait_with_input_output<T>(mut child: T, input: Option<Vec<u8>>)...
  function run_input_output (line 472) | pub async fn run_input_output<C>(mut command: C, input: Option<Vec<u8>>)...
  function write_length_prefixed_bincode (line 499) | pub fn write_length_prefixed_bincode<W, S>(mut writer: W, data: S) -> Re...
  type OsStrExt (line 513) | pub trait OsStrExt {
    method starts_with (line 514) | fn starts_with(&self, s: &str) -> bool;
    method split_prefix (line 515) | fn split_prefix(&self, s: &str) -> Option<OsString>;
    method starts_with (line 523) | fn starts_with(&self, s: &str) -> bool {
    method split_prefix (line 527) | fn split_prefix(&self, s: &str) -> Option<OsString> {
    method starts_with (line 542) | fn starts_with(&self, s: &str) -> bool {
    method split_prefix (line 580) | fn split_prefix(&self, s: &str) -> Option<OsString> {
  function encode_path (line 616) | pub fn encode_path(dst: &mut dyn Write, path: &Path) -> std::io::Result<...
  function encode_path (line 624) | pub fn encode_path(dst: &mut dyn Write, path: &Path) -> std::io::Result<...
  function decode_path (line 633) | pub fn decode_path(bytes: &[u8]) -> std::io::Result<PathBuf> {
  function decode_path (line 639) | pub fn decode_path(bytes: &[u8]) -> std::io::Result<PathBuf> {
  function wide_char_to_multi_byte (line 649) | pub fn wide_char_to_multi_byte(wide_char_str: &[u16]) -> std::io::Result...
  function multi_byte_to_wide_char (line 702) | pub fn multi_byte_to_wide_char(
  type Timestamp (line 744) | pub struct Timestamp {
    method from (line 753) | fn from(system_time: std::time::SystemTime) -> Self {
    method eq (line 793) | fn eq(&self, other: &SystemTime) -> bool {
    method new (line 799) | pub fn new(seconds: i64, nanoseconds: u32) -> Self {
  constant NSEC_PER_SEC (line 750) | const NSEC_PER_SEC: u32 = 1_000_000_000;
  type MetadataCtimeExt (line 808) | pub trait MetadataCtimeExt {
    method ctime_or_creation (line 809) | fn ctime_or_creation(&self) -> std::io::Result<Timestamp>;
    method ctime_or_creation (line 814) | fn ctime_or_creation(&self) -> std::io::Result<Timestamp> {
    method ctime_or_creation (line 822) | fn ctime_or_creation(&self) -> std::io::Result<Timestamp> {
  type HashToDigest (line 829) | pub struct HashToDigest<'a> {
  method write (line 834) | fn write(&mut self, bytes: &[u8]) {
  method finish (line 838) | fn finish(&self) -> u64 {
  function daemonize (line 845) | pub fn daemonize() -> Result<()> {
  function daemonize (line 932) | pub fn daemonize() -> Result<()> {
  function new_reqwest_blocking_client (line 947) | pub fn new_reqwest_blocking_client() -> reqwest::blocking::Client {
  function unhex (line 954) | fn unhex(b: u8) -> std::io::Result<u8> {
  function ascii_unescape_default (line 967) | pub fn ascii_unescape_default(s: &[u8]) -> std::io::Result<Vec<u8>> {
  function num_cpus (line 1015) | pub fn num_cpus() -> usize {
  function strip_basedirs (line 1032) | pub fn strip_basedirs<'a>(preprocessor_output: &'a [u8], basedirs: &[Vec...
  function normalize_win_path (line 1119) | pub fn normalize_win_path(path: &[u8]) -> Vec<u8> {
  function resolve_compiler_avoiding_ccache (line 1191) | pub fn resolve_compiler_avoiding_ccache(
  function test_resolve_compiler_avoiding_ccache_filters_path (line 1256) | fn test_resolve_compiler_avoiding_ccache_filters_path() {
  function test_resolve_compiler_avoiding_ccache_no_path (line 1289) | fn test_resolve_compiler_avoiding_ccache_no_path() {
  function test_resolve_compiler_avoiding_ccache_skips_symlink_to_ccache (line 1304) | fn test_resolve_compiler_avoiding_ccache_skips_symlink_to_ccache() {
  function test_resolve_compiler_avoiding_ccache_absolute_path_unchanged (line 1337) | fn test_resolve_compiler_avoiding_ccache_absolute_path_unchanged() {
  function simple_starts_with (line 1354) | fn simple_starts_with() {
  function simple_strip_prefix (line 1369) | fn simple_strip_prefix() {
  function test_time_macro_short_read (line 1381) | fn test_time_macro_short_read() {
  function test_ascii_unescape_default (line 1460) | fn test_ascii_unescape_default() {
  function test_strip_basedir_simple (line 1502) | fn test_strip_basedir_simple() {
  function test_strip_basedir_empty (line 1524) | fn test_strip_basedir_empty() {
  function test_strip_basedir_not_at_boundary (line 1538) | fn test_strip_basedir_not_at_boundary() {
  function test_strip_basedir_trailing_slashes (line 1549) | fn test_strip_basedir_trailing_slashes() {
  function test_strip_basedirs_multiple (line 1566) | fn test_strip_basedirs_multiple() {
  function test_strip_basedir_windows_backslashes (line 1588) | fn test_strip_basedir_windows_backslashes() {
  function test_strip_basedir_windows_mixed_slashes (line 1607) | fn test_strip_basedir_windows_mixed_slashes() {
  function test_normalize_win_path_ascii (line 1629) | fn test_normalize_win_path_ascii() {
  function test_normalize_win_path_utf8 (line 1642) | fn test_normalize_win_path_utf8() {
  function test_normalize_win_path_mixed_ascii_utf8 (line 1664) | fn test_normalize_win_path_mixed_ascii_utf8() {
  function test_normalize_win_path_invalid_utf8 (line 1673) | fn test_normalize_win_path_invalid_utf8() {
  function test_normalize_win_path_incomplete_utf8 (line 1689) | fn test_normalize_win_path_incomplete_utf8() {
  function test_normalize_win_path_empty (line 1703) | fn test_normalize_win_path_empty() {

FILE: tests/cache_hit_rate.rs
  function test_cache_hit_rate (line 13) | fn test_cache_hit_rate() -> Result<()> {
  function test_adv_cache_hit_rate (line 68) | fn test_adv_cache_hit_rate() -> Result<()> {

FILE: tests/cmake-modules/main.cpp
  function main (line 5) | int main() {

FILE: tests/dist.rs
  function basic_compile (line 26) | fn basic_compile(tmpdir: &Path, sccache_cfg_path: &Path, sccache_cached_...
  function rust_compile (line 56) | fn rust_compile(tmpdir: &Path, sccache_cfg_path: &Path, sccache_cached_c...
  function dist_test_sccache_client_cfg (line 98) | pub fn dist_test_sccache_client_cfg(
  function test_dist_basic (line 110) | fn test_dist_basic() {
  function test_dist_restartedserver (line 143) | fn test_dist_restartedserver() {
  function test_dist_nobuilder (line 179) | fn test_dist_nobuilder() {
  type FailingServer (line 209) | struct FailingServer;
  method handle_assign_job (line 211) | fn handle_assign_job(&self, _job_id: JobId, _tc: Toolchain) -> Result<As...
  method handle_submit_toolchain (line 219) | fn handle_submit_toolchain(
  method handle_run_job (line 227) | fn handle_run_job(
  function test_dist_failingserver (line 244) | fn test_dist_failingserver() {
  function test_dist_cargo_build (line 277) | fn test_dist_cargo_build() {
  function test_dist_cargo_makeflags (line 311) | fn test_dist_cargo_makeflags() {
  function test_dist_preprocesspr_cache_bug_2173 (line 349) | fn test_dist_preprocesspr_cache_bug_2173() {
  function test_dist_toolchain (line 410) | fn test_dist_toolchain() {

FILE: tests/harness/mod.rs
  constant CONTAINER_NAME_PREFIX (line 30) | const CONTAINER_NAME_PREFIX: &str = "sccache_dist_test";
  constant DIST_IMAGE (line 31) | const DIST_IMAGE: &str = "sccache_dist_test_image";
  constant DIST_DOCKERFILE (line 32) | const DIST_DOCKERFILE: &str = include_str!("Dockerfile.sccache-dist");
  constant DIST_IMAGE_BWRAP_PATH (line 33) | const DIST_IMAGE_BWRAP_PATH: &str = "/usr/bin/bwrap";
  constant MAX_STARTUP_WAIT (line 34) | const MAX_STARTUP_WAIT: Duration = Duration::from_secs(5);
  constant DIST_CACHE_RELPATH (line 35) | const DIST_CACHE_RELPATH: &str = "client-dist-cache";
  constant DIST_SERVER_TOKEN (line 37) | const DIST_SERVER_TOKEN: &str = "THIS IS THE TEST TOKEN";
  constant CONFIGS_CONTAINER_PATH (line 39) | const CONFIGS_CONTAINER_PATH: &str = "/sccache-bits";
  constant BUILD_DIR_CONTAINER_PATH (line 40) | const BUILD_DIR_CONTAINER_PATH: &str = "/sccache-bits/build-dir";
  constant SCHEDULER_PORT (line 41) | const SCHEDULER_PORT: u16 = 10500;
  constant SERVER_PORT (line 42) | const SERVER_PORT: u16 = 12345;
  constant TC_CACHE_SIZE (line 44) | const TC_CACHE_SIZE: u64 = 1024 * 1024 * 1024;
  function start_local_daemon (line 46) | pub fn start_local_daemon(cfg_path: &Path, cached_cfg_path: &Path) {
  function stop_local_daemon (line 68) | pub fn stop_local_daemon() -> bool {
  function clear_cache_local_daemon (line 78) | pub fn clear_cache_local_daemon(tmpdir: &Path) -> bool {
  function get_stats (line 85) | pub fn get_stats<F: 'static + Fn(ServerInfo)>(f: F) {
  function zero_stats (line 100) | pub fn zero_stats() {
  function write_json_cfg (line 111) | pub fn write_json_cfg<T: Serialize>(path: &Path, filename: &str, content...
  function write_source (line 117) | pub fn write_source(path: &Path, filename: &str, contents: &str) {
  function init_cargo (line 123) | pub fn init_cargo(path: &Path, cargo_name: &str) -> PathBuf {
  function prune_command (line 131) | pub fn prune_command(mut cmd: Command) -> Command {
  function sccache_command (line 142) | pub fn sccache_command() -> Command {
  function cargo_command (line 146) | pub fn cargo_command() -> Command {
  function sccache_dist_path (line 151) | pub fn sccache_dist_path() -> PathBuf {
  function sccache_client_cfg (line 155) | pub fn sccache_client_cfg(
  function sccache_scheduler_cfg (line 199) | fn sccache_scheduler_cfg() -> sccache::config::scheduler::Config {
  function sccache_server_cfg (line 210) | fn sccache_server_cfg(
  function create_server_token (line 237) | fn create_server_token(server_id: ServerId, auth_token: &str) -> String {
  type ServerHandle (line 243) | pub enum ServerHandle {
  type DistSystem (line 249) | pub struct DistSystem {
    method new (line 260) | pub fn new(sccache_dist: &Path, tmpdir: &Path) -> Self {
    method add_scheduler (line 291) | pub fn add_scheduler(&mut self) {
    method add_server (line 366) | pub fn add_server(&mut self) -> ServerHandle {
    method add_custom_server (line 431) | pub fn add_custom_server<S: dist::ServerIncoming + 'static>(
    method restart_server (line 471) | pub fn restart_server(&mut self, handle: &ServerHandle) {
    method count_toolchains_on_server (line 487) | pub fn count_toolchains_on_server(&mut self, handle: &ServerHandle) ->...
    method wait_server_ready (line 512) | pub fn wait_server_ready(&mut self, handle: &ServerHandle) {
    method scheduler_url (line 540) | pub fn scheduler_url(&self) -> HTTPUrl {
    method scheduler_status (line 545) | fn scheduler_status(&self) -> SchedulerStatusResult {
  method drop (line 558) | fn drop(&mut self) {
  function make_container_name (line 692) | fn make_container_name(tag: &str) -> String {
  function check_output (line 701) | fn check_output(output: &Output) {
  function wait_for_http (line 714) | fn wait_for_http(url: HTTPUrl, interval: Duration, max_wait: Duration) {
  function wait_for (line 730) | fn wait_for<F: Fn() -> Result<(), String>>(f: F, interval: Duration, max...

FILE: tests/helpers/mod.rs
  type SccacheTest (line 40) | pub struct SccacheTest<'a> {
  function new (line 49) | pub fn new(additional_envs: Option<&[(&'static str, std::ffi::OsString)]...
  function show_stats (line 95) | pub fn show_stats(&self) -> assert_cmd::assert::AssertResult {
  function show_text_stats (line 104) | pub fn show_text_stats(&self, advanced: bool) -> assert_cmd::assert::Ass...
  method drop (line 121) | fn drop(&mut self) {
  function stop_sccache (line 126) | pub fn stop_sccache() -> Result<()> {
  function cargo_clean (line 138) | pub fn cargo_clean(test_info: &SccacheTest) -> Result<()> {

FILE: tests/integration/autotools/main.cpp
  function print_hello (line 3) | void print_hello() {

FILE: tests/integration/basedirs-autotools/include/myheader.h
  function std (line 7) | inline std::string get_message() {
  function calculate_sum (line 11) | inline int calculate_sum(int a, int b) {
  function print_header_info (line 15) | inline void print_header_info() {

FILE: tests/integration/basedirs-autotools/main.cpp
  function main (line 4) | int main() {

FILE: tests/integration/cmake-hip/vectoradd_hip.cpp
  function __global__ (line 42) | __global__ void
  function __kernel__ (line 60) | __kernel__ void vectoradd_float(float* a, const float* b, const float* c...
  function main (line 75) | int main() {

FILE: tests/integration/cmake/main.cpp
  function print_hello (line 3) | void print_hello() {

FILE: tests/integration/msvc-preprocessing/foo.cpp
  function main (line 19) | int main() {

FILE: tests/integration/msvc/foo.cpp
  function main (line 3) | int main() {

FILE: tests/integration/randomize_readdir/src/lib.rs
  type Opendir (line 61) | type Opendir = unsafe extern "C" fn(dirname: *const c_char) -> *mut DIR;
  type Fdopendir (line 62) | type Fdopendir = unsafe extern "C" fn(fd: c_int) -> *mut DIR;
  type Readdir (line 63) | type Readdir = unsafe extern "C" fn(dirp: *mut DIR) -> *mut dirent;
  type Readdir64 (line 64) | type Readdir64 = unsafe extern "C" fn(dirp: *mut DIR) -> *mut dirent64;
  type Closedir (line 65) | type Closedir = unsafe extern "C" fn(dirp: *mut DIR) -> c_int;
  type DirentIterator (line 67) | struct DirentIterator<Dirent> {
  type Item (line 73) | type Item = *mut Dirent;
  method next (line 75) | fn next(&mut self) -> Option<Self::Item> {
  type ReaddirState (line 86) | struct ReaddirState {
  type State (line 91) | struct State {
    method new_opendir (line 102) | fn new_opendir(&self, dirp: *mut DIR) {
    method wrapped_readdir_inner (line 112) | fn wrapped_readdir_inner<Dirent, GetIter, Readdir>(
    method wrapped_readdir (line 158) | fn wrapped_readdir(&self, dirp: *mut DIR) -> *mut dirent {
    method wrapped_readdir64 (line 166) | fn wrapped_readdir64(&self, dirp: *mut DIR) -> *mut dirent64 {
  function load_next (line 177) | fn load_next<Prototype: Copy>(name: &[u8]) -> Prototype {
  function init (line 191) | fn init() {
  function opendir (line 227) | pub unsafe extern "C" fn opendir(dirname: *const c_char) -> *mut DIR {
  function fdopendir (line 245) | pub extern "C" fn fdopendir(dirfd: c_int) -> *mut DIR {
  function readdir (line 259) | pub extern "C" fn readdir(dirp: *mut DIR) -> *mut dirent {
  function readdir64 (line 264) | pub extern "C" fn readdir64(dirp: *mut DIR) -> *mut dirent64 {
  function closedir (line 276) | pub unsafe extern "C" fn closedir(dirp: *mut DIR) -> c_int {

FILE: tests/integration/xcode/main.cpp
  function main (line 3) | int main(int argc, const char * argv[]) {

FILE: tests/logging.rs
  function sccache_bin (line 26) | fn sccache_bin() -> PathBuf {
  function test_log_timestamp_format_without_millis (line 32) | fn test_log_timestamp_format_without_millis() {
  function test_log_timestamp_format_with_millis (line 66) | fn test_log_timestamp_format_with_millis() {
  function test_log_millis_flag_with_various_values (line 93) | fn test_log_millis_flag_with_various_values() {

FILE: tests/msvc-msbuild/test_bar.cpp
  function bar (line 1) | int bar(int x) { return x; }

FILE: tests/msvc-msbuild/test_baz.cpp
  function baz (line 1) | int baz(int x) { return x; }

FILE: tests/msvc-msbuild/test_foo.cpp
  function foo (line 1) | int foo(int x) { return x; }

FILE: tests/oauth.rs
  constant LOCAL_AUTH_BASE_URL (line 12) | const LOCAL_AUTH_BASE_URL: &str = "http://localhost:12731/";
  constant USERNAME_SELECTOR (line 14) | const USERNAME_SELECTOR: &str = ".auth0-lock-input-email .auth0-lock-inp...
  constant PASSWORD_SELECTOR (line 15) | const PASSWORD_SELECTOR: &str = ".auth0-lock-input-password .auth0-lock-...
  constant LOGIN_SELECTOR (line 16) | const LOGIN_SELECTOR: &str = ".auth0-lock-submit";
  constant BROWSER_RETRY_WAIT (line 18) | const BROWSER_RETRY_WAIT: Duration = Duration::from_secs(1);
  constant BROWSER_MAX_WAIT (line 19) | const BROWSER_MAX_WAIT: Duration = Duration::from_secs(10);
  constant TEST_USERNAME (line 26) | const TEST_USERNAME: &str = "test@example.com";
  constant TEST_PASSWORD (line 27) | const TEST_PASSWORD: &str = "test1234";
  function generate_code_grant_pkce_auth_config (line 29) | fn generate_code_grant_pkce_auth_config() -> sccache::config::DistAuth {
  function generate_implicit_auth_config (line 38) | fn generate_implicit_auth_config() -> sccache::config::DistAuth {
  function config_with_dist_auth (line 47) | fn config_with_dist_auth(
  function sccache_command (line 66) | fn sccache_command() -> Command {
  function retry (line 70) | fn retry<F: FnMut() -> Option<T>, T>(interval: Duration, until: Duration...
  type DriverExt (line 82) | trait DriverExt {
    method wait_for_element (line 83) | async fn wait_for_element(&self, selector: &str) -> WebDriverResult<()>;
    method wait_on_url (line 84) | async fn wait_on_url<F: Fn(&str) -> bool>(&self, condition: F) -> WebD...
    method wait_for_element (line 87) | async fn wait_for_element(&self, selector: &str) -> WebDriverResult<()> {
    method wait_on_url (line 94) | async fn wait_on_url<F: Fn(&str) -> bool>(&self, condition: F) -> WebD...
  function auth0_login (line 107) | async fn auth0_login(driver: &WebDriver, email: &str, password: &str) {
  type SeleniumContainer (line 133) | struct SeleniumContainer {
    method new (line 149) | fn new() -> Self {
  function check_output (line 137) | fn check_output(output: &Output) {
  method drop (line 175) | fn drop(&mut self) {
  function test_auth (line 199) | async fn test_auth() {
  function test_auth_with_config (line 228) | async fn test_auth_with_config(dist_auth: sccache::config::DistAuth) {
  function login (line 281) | async fn login() {

FILE: tests/sccache_args.rs
  function test_gcp_arg_check (line 20) | fn test_gcp_arg_check() -> Result<()> {
  function test_s3_invalid_args (line 63) | fn test_s3_invalid_args() -> Result<()> {

FILE: tests/sccache_cargo.rs
  function test_rust_cargo_check (line 24) | fn test_rust_cargo_check() -> Result<()> {
  function test_rust_cargo_check_readonly (line 30) | fn test_rust_cargo_check_readonly() -> Result<()> {
  function test_rust_cargo_build (line 36) | fn test_rust_cargo_build() -> Result<()> {
  function test_rust_cargo_build_readonly (line 42) | fn test_rust_cargo_build_readonly() -> Result<()> {
  function test_run_log_no_perm (line 49) | fn test_run_log_no_perm() -> Result<()> {
  function test_run_log (line 65) | fn test_run_log() -> Result<()> {
  function test_rust_cargo_run_with_env_dep_parsing (line 89) | fn test_rust_cargo_run_with_env_dep_parsing() -> Result<()> {
  function test_rust_cargo_check_nightly (line 96) | fn test_rust_cargo_check_nightly() -> Result<()> {
  function test_rust_cargo_check_nightly_readonly (line 111) | fn test_rust_cargo_check_nightly_readonly() -> Result<()> {
  function test_rust_cargo_build_nightly (line 126) | fn test_rust_cargo_build_nightly() -> Result<()> {
  function test_rust_cargo_build_nightly_readonly (line 141) | fn test_rust_cargo_build_nightly_readonly() -> Result<()> {
  function test_rust_cargo_cmd (line 156) | fn test_rust_cargo_cmd(cmd: &str, test_info: SccacheTest) -> Result<()> {
  function restart_sccache (line 191) | fn restart_sccache(
  function test_rust_cargo_cmd_readonly (line 222) | fn test_rust_cargo_cmd_readonly(cmd: &str, test_info: SccacheTest) -> Re...
  function test_rust_cargo_env_dep (line 312) | fn test_rust_cargo_env_dep(test_info: SccacheTest) -> Result<()> {
  function test_rust_cargo_cmd_readonly_preemtive_block (line 352) | fn test_rust_cargo_cmd_readonly_preemtive_block() -> Result<()> {

FILE: tests/sccache_rustc.rs
  type StopServer (line 18) | struct StopServer;
  method drop (line 20) | fn drop(&mut self) {
  function test_symlinks (line 46) | fn test_symlinks() {
  function create_mock_rustc (line 74) | fn create_mock_rustc(dir: PathBuf) {
  function run_sccache (line 140) | fn run_sccache(root: &Path, path: &Path) {

FILE: tests/system.rs
  type Compiler (line 50) | struct Compiler {
  constant COMPILERS (line 58) | const COMPILERS: &[&str] = &["gcc", "clang", "clang++", "nvc", "nvc++"];
  constant COMPILERS (line 62) | const COMPILERS: &[&str] = &["clang", "clang++"];
  constant CUDA_COMPILERS (line 64) | const CUDA_COMPILERS: &[&str] = &["nvcc", "clang++"];
  function adv_key_kind (line 66) | fn adv_key_kind(lang: &str, compiler: &str) -> String {
  function compile_cmdline (line 96) | fn compile_cmdline<T: AsRef<OsStr>>(
  function compile_cuda_cmdline (line 118) | fn compile_cuda_cmdline<T: AsRef<OsStr>>(
  function compile_hip_cmdline (line 161) | fn compile_hip_cmdline<T: AsRef<OsStr>>(
  constant INPUT (line 184) | const INPUT: &str = "test.c";
  constant INPUT_CLANG_MULTICALL (line 185) | const INPUT_CLANG_MULTICALL: &str = "test_clang_multicall.c";
  constant INPUT_WITH_WHITESPACE (line 186) | const INPUT_WITH_WHITESPACE: &str = "test_whitespace.c";
  constant INPUT_WITH_WHITESPACE_ALT (line 187) | const INPUT_WITH_WHITESPACE_ALT: &str = "test_whitespace_alt.c";
  constant INPUT_ERR (line 188) | const INPUT_ERR: &str = "test_err.c";
  constant INPUT_MACRO_EXPANSION (line 189) | const INPUT_MACRO_EXPANSION: &str = "test_macro_expansion.c";
  constant INPUT_WITH_DEFINE (line 190) | const INPUT_WITH_DEFINE: &str = "test_with_define.c";
  constant INPUT_FOR_CUDA_A (line 191) | const INPUT_FOR_CUDA_A: &str = "test_a.cu";
  constant INPUT_FOR_CUDA_B (line 192) | const INPUT_FOR_CUDA_B: &str = "test_b.cu";
  constant INPUT_FOR_CUDA_C (line 193) | const INPUT_FOR_CUDA_C: &str = "test_c.cu";
  constant INPUT_FOR_HIP_A (line 194) | const INPUT_FOR_HIP_A: &str = "test_a.hip";
  constant INPUT_FOR_HIP_B (line 195) | const INPUT_FOR_HIP_B: &str = "test_b.hip";
  constant INPUT_FOR_HIP_C (line 196) | const INPUT_FOR_HIP_C: &str = "test_c.hip";
  constant OUTPUT (line 197) | const OUTPUT: &str = "test.o";
  function copy_to_tempdir (line 200) | fn copy_to_tempdir(inputs: &[&str], tempdir: &Path) {
  function test_basic_compile (line 216) | fn test_basic_compile(compiler: Compiler, tempdir: &Path) {
  function test_noncacheable_stats (line 268) | fn test_noncacheable_stats(compiler: Compiler, tempdir: &Path) {
  function test_msvc_deps (line 295) | fn test_msvc_deps(compiler: Compiler, tempdir: &Path) {
  function test_msvc_responsefile (line 326) | fn test_msvc_responsefile(compiler: Compiler, tempdir: &Path) {
  function test_gcc_mp_werror (line 353) | fn test_gcc_mp_werror(compiler: Compiler, tempdir: &Path) {
  function test_gcc_fprofile_generate_source_changes (line 378) | fn test_gcc_fprofile_generate_source_changes(compiler: Compiler, tempdir...
  function test_split_dwarf_object_generate_output_dir_changes (line 468) | fn test_split_dwarf_object_generate_output_dir_changes(compiler: Compile...
  function test_gcc_clang_no_warnings_from_macro_expansion (line 527) | fn test_gcc_clang_no_warnings_from_macro_expansion(compiler: Compiler, t...
  function test_compile_with_define (line 553) | fn test_compile_with_define(compiler: Compiler, tempdir: &Path) {
  function test_gcc_clang_depfile (line 579) | fn test_gcc_clang_depfile(compiler: Compiler, tempdir: &Path) {
  function run_sccache_command_tests (line 629) | fn run_sccache_command_tests(compiler: Compiler, tempdir: &Path, preproc...
  function test_nvcc_cuda_compiles (line 692) | fn test_nvcc_cuda_compiles(compiler: &Compiler, tempdir: &Path) {
  function test_nvcc_proper_lang_stat_tracking (line 1170) | fn test_nvcc_proper_lang_stat_tracking(compiler: Compiler, tempdir: &Pat...
  function run_sccache_nvcc_cuda_command_tests (line 1248) | fn run_sccache_nvcc_cuda_command_tests(compiler: Compiler, tempdir: &Pat...
  function test_clang_cuda_compiles (line 1253) | fn test_clang_cuda_compiles(compiler: &Compiler, tempdir: &Path) {
  function test_clang_proper_lang_stat_tracking (line 1348) | fn test_clang_proper_lang_stat_tracking(compiler: Compiler, tempdir: &Pa...
  function run_sccache_clang_cuda_command_tests (line 1421) | fn run_sccache_clang_cuda_command_tests(compiler: Compiler, tempdir: &Pa...
  function test_hip_compiles (line 1426) | fn test_hip_compiles(compiler: &Compiler, tempdir: &Path) {
  function test_hip_compiles_multi_targets (line 1523) | fn test_hip_compiles_multi_targets(compiler: &Compiler, tempdir: &Path) {
  function run_sccache_hip_command_tests (line 1622) | fn run_sccache_hip_command_tests(compiler: Compiler, tempdir: &Path) {
  function test_clang_multicall (line 1630) | fn test_clang_multicall(compiler: Compiler, tempdir: &Path) {
  function test_clang_cache_whitespace_normalization (line 1655) | fn test_clang_cache_whitespace_normalization(
  function find_compilers (line 1732) | fn find_compilers() -> Vec<Compiler> {
  function find_compilers (line 1749) | fn find_compilers() -> Vec<Compiler> {
  function find_cuda_compilers (line 1763) | fn find_cuda_compilers() -> Vec<Compiler> {
  function find_hip_compiler (line 1810) | fn find_hip_compiler() -> Option<Compiler> {
  function test_sccache_command (line 1846) | fn test_sccache_command(preprocessor_cache_mode: bool) {
  function test_stats_no_server (line 1878) | fn test_stats_no_server() {
  function test_cuda_sccache_command (line 1892) | fn test_cuda_sccache_command(preprocessor_cache_mode: bool) {
  function test_hip_sccache_command (line 1937) | fn test_hip_sccache_command(preprocessor_cache_mode: bool) {
  function test_symlinked_exe (line 1966) | fn test_symlinked_exe() {

FILE: tests/test-crate/src/bin.rs
  function main (line 3) | fn main() {

FILE: tests/test-crate/src/lib.rs
  function unused (line 1) | fn unused() {}
  function env_dep_test (line 3) | pub fn env_dep_test() {
  function it_works (line 10) | fn it_works() {

FILE: tests/test.c
  function foo (line 3) | void foo() {

FILE: tests/test_clang_multicall.c
  function main (line 6) | int main() {

FILE: tests/test_macro_expansion.c
  function bar (line 10) | void bar() { foo(0); }

FILE: tests/test_whitespace.c
  function main (line 3) | int main() {printf("Hello world!");return 0;}

FILE: tests/test_whitespace_alt.c
  function main (line 3) | int main()

FILE: tests/test_with_define.c
  function foo (line 7) | void foo() { printf("hello world\n"); }
Condensed preview — 182 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,057K chars).
[
  {
    "path": ".envrc",
    "chars": 284,
    "preview": "if has nix; then\n  if ! has nix_direnv_version || ! nix_direnv_version 3.1.0; then\n    source_url \"https://raw.githubuse"
  },
  {
    "path": ".github/actions/artifact_failure/action.yml",
    "chars": 922,
    "preview": "name: \"Upload failure Artifacts\"\ndescription: \"Upload failure Artifacts\"\ninputs:\n  name:\n    description: \"\"\n    require"
  },
  {
    "path": ".github/actions/nvcc-toolchain/action.yml",
    "chars": 430,
    "preview": "name: nvcc-toolchain\ninputs:\n  cuda-version:\n    description: CUDA Toolkit version\n    required: true\n\nruns:\n  using: co"
  },
  {
    "path": ".github/actions/nvcc-toolchain/install-cuda.ps1",
    "chars": 2027,
    "preview": "Param(\n    [Parameter(Mandatory=$false)]\n    [string]\n    $cudaVersion=\"12.8.0\"\n)\n\n# Use System.Version to tokenize vers"
  },
  {
    "path": ".github/actions/nvcc-toolchain/install-cuda.sh",
    "chars": 1658,
    "preview": "#! /usr/bin/env bash\nset -eu\n\nexport DEBIAN_FRONTEND=noninteractive\n\nget_cuda_deb() {\n    local deb=\"$(                 "
  },
  {
    "path": ".github/actions/rust-toolchain/action.yml",
    "chars": 790,
    "preview": "name: rust-toolchain\ninputs:\n  toolchain:\n    description: |\n      Rust toolchain name.\n      See https://rust-lang.gith"
  },
  {
    "path": ".github/codecov.yml",
    "chars": 75,
    "preview": "coverage:\r\n  status:\r\n    project:\r\n      default:\r\n        threshold: 0.2%"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 268,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: \"cargo\"\n    directory: \"/\"\n    schedule:\n      interval: weekly \n    open-pul"
  },
  {
    "path": ".github/workflows/benchmarks.yml",
    "chars": 1191,
    "preview": "name: Benchmarks\n\n# spell-checker:ignore codspeed dtolnay Swatinem\n\non:\n  pull_request:\n  push:\n    branches:\n      - '*"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 18143,
    "preview": "name: ci\non: [ push, pull_request ]\n\njobs:\n  lint:\n    name: ${{ matrix.component }} ${{ matrix.os }}\n    runs-on: ${{ m"
  },
  {
    "path": ".github/workflows/close-snap.yml",
    "chars": 372,
    "preview": "name: Close Snaps\n\non:\n  pull_request:\n    types: [closed]\n\njobs:\n  close:\n    runs-on: ubuntu-latest\n\n    timeout-minut"
  },
  {
    "path": ".github/workflows/integration-tests.yml",
    "chars": 12256,
    "preview": "name: integration-tests\non: [ push, pull_request ]\n\nenv:\n  RUST_BACKTRACE: full\n  RUST_LOG: debug\n  SCCACHE_PATH: /home/"
  },
  {
    "path": ".github/workflows/snap.yml",
    "chars": 717,
    "preview": "name: Snap\n\non:\n  pull_request:\n    types: [opened, synchronize, reopened, ready_for_review]\n\njobs:\n  Snap:\n    runs-on:"
  },
  {
    "path": ".gitignore",
    "chars": 267,
    "preview": "target\n*~\n\n*.log\n.cargo\n*.pyc\n\n# snapcraft artifacts\n/parts\n/prime\n/snap/.snapcraft\n/stage\n/*.snap\n\n# Ignore lockfiles o"
  },
  {
    "path": ".pre-commit-config.yaml",
    "chars": 558,
    "preview": "repos:\n-   repo: local\n    hooks:\n    -   id: rust-linting\n        name: Rust linting\n        description: Run cargo fmt"
  },
  {
    "path": ".rustfmt.toml",
    "chars": 64,
    "preview": "# Should match package.edition from Cargo.toml\nedition = \"2024\"\n"
  },
  {
    "path": ".taplo.toml",
    "chars": 1424,
    "preview": "include = [\"Cargo.toml\", \"**/*.toml\"]\n\n[formatting]\n# Align consecutive entries vertically.\nalign_entries = false\n# Appe"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 691,
    "preview": "# Community Participation Guidelines\n\nThis repository is governed by Mozilla's code of conduct and etiquette guidelines."
  },
  {
    "path": "Cargo.toml",
    "chars": 5921,
    "preview": "[package]\n# Should match .rustfmt.toml\nedition = \"2024\"\nname = \"sccache\"\nrust-version = \"1.85.0\"\nversion = \"0.14.0\"\n\ncat"
  },
  {
    "path": "LICENSE",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "README.md",
    "chars": 18438,
    "preview": "[![Build Status](https://github.com/mozilla/sccache/workflows/ci/badge.svg)](https://github.com/mozilla/sccache/actions?"
  },
  {
    "path": "benches/sccache_bench.rs",
    "chars": 30200,
    "preview": "// Copyright 2025 Mozilla\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this "
  },
  {
    "path": "docs/Architecture.md",
    "chars": 540,
    "preview": "# Sccache high level architecture\n\nThis schema shows at high level how sccache works.\n\n\n```mermaid\n  flowchart LR\n      "
  },
  {
    "path": "docs/Azure.md",
    "chars": 791,
    "preview": "# Azure\n\nTo use Azure Blob Storage, you'll need your Azure connection string and an _existing_ Blob Storage container na"
  },
  {
    "path": "docs/COS.md",
    "chars": 944,
    "preview": "# COS\n\nIf you want to use _Tencent Cloud Object Storage_ (aka COS) for the sccache cache, you need to set the `SCCACHE_C"
  },
  {
    "path": "docs/Caching.md",
    "chars": 2300,
    "preview": "# How caching works\n\nTo know if the storage contains the artifact we need, we are\ncomputing some hashes to make sure the"
  },
  {
    "path": "docs/Configuration.md",
    "chars": 10750,
    "preview": "# Available Configuration Options\n\n## file\n\n```toml\n# If specified, wait this long for the server to start up.\nserver_st"
  },
  {
    "path": "docs/Distributed.md",
    "chars": 13996,
    "preview": "# Distributed sccache\n\nBackground:\n\n - You should read about JSON Web Tokens - https://jwt.io/.\n   - HS256 in short: you"
  },
  {
    "path": "docs/DistributedFreeBSD.md",
    "chars": 4044,
    "preview": "Distributed sccache on FreeBSD\n==============================\n\nPlease read the [the distributed quickstart](DistributedQ"
  },
  {
    "path": "docs/DistributedQuickstart.md",
    "chars": 11320,
    "preview": "sccache distributed compilation quickstart\n==========================================\n\nThis is a quick start guide to ge"
  },
  {
    "path": "docs/GHA.md",
    "chars": 877,
    "preview": "# GitHub Actions\n\nTo use the [GitHub Actions cache](https://docs.github.com/en/actions/using-workflows/caching-dependenc"
  },
  {
    "path": "docs/Gcs.md",
    "chars": 3126,
    "preview": "# Google Cloud Storage\n\nTo use [Google Cloud Storage](https://cloud.google.com/storage/), you need to set\nthe `SCCACHE_G"
  },
  {
    "path": "docs/Jenkins.md",
    "chars": 1516,
    "preview": "sccache on Jenkins\n==================\n\nWhen using `sccache` on [Jenkins](https://jenkins.io) one has to know about how t"
  },
  {
    "path": "docs/Local.md",
    "chars": 4554,
    "preview": "# Local\n\nsccache defaults to using local disk storage. You can set the `SCCACHE_DIR` environment variable to change the "
  },
  {
    "path": "docs/Memcached.md",
    "chars": 869,
    "preview": "# Memcached\n\nSet `SCCACHE_MEMCACHED_ENDPOINT` to a [Memcached](https://memcached.org/) url in format `tcp://<hostname>:<"
  },
  {
    "path": "docs/OSS.md",
    "chars": 1229,
    "preview": "# OSS\n\nIf you want to use _Object Storage Service_ (aka OSS) by Alibaba for the sccache cache, you need to set the `SCCA"
  },
  {
    "path": "docs/Redis.md",
    "chars": 2794,
    "preview": "# Redis\n\nIf you want to use [Redis](https://redis.io/) storage for the sccache cache, you need to set the `SCCACHE_REDIS"
  },
  {
    "path": "docs/Releasing.md",
    "chars": 1149,
    "preview": "# Sccache Release Process\n\nMost of the sccache release process is automated. The [github workflow](https://github.com/mo"
  },
  {
    "path": "docs/ResponseFiles.md",
    "chars": 3673,
    "preview": "# Response Files\n\nResponse files are a way for compilers to accept arguments that would otherwise overflow the character"
  },
  {
    "path": "docs/Rust.md",
    "chars": 792,
    "preview": "sccache includes support for caching Rust compilation. This includes many caveats, and is primarily focused on caching r"
  },
  {
    "path": "docs/S3.md",
    "chars": 3456,
    "preview": "# S3\n\nIf you want to use S3 storage for the sccache cache, you need to set the following environment variables:\n\n- `SCCA"
  },
  {
    "path": "docs/Webdav.md",
    "chars": 884,
    "preview": "# WebDAV\n\nUsers can configure sccache to cache incremental build artifacts in a remote WebDAV service.\nThe following ser"
  },
  {
    "path": "docs/Xcode.md",
    "chars": 3257,
    "preview": "# Using `sccache` with Xcode\n\nIt is possible to use `sccache` with Xcode with some setup.\n\n### Running the daemon\nBefore"
  },
  {
    "path": "flake.nix",
    "chars": 2442,
    "preview": "{\n  description = \"sccache development environment and package\";\n\n  inputs = {\n    nixpkgs.url = \"github:NixOS/nixpkgs/n"
  },
  {
    "path": "scripts/extratest.sh",
    "chars": 4750,
    "preview": "#!/bin/sh\nset -o errexit\nset -o pipefail\nset -o nounset\nset -o xtrace\n\n#CARGO=\"cargo --color=always\"\nCARGO=\"cargo\"\n\ngnut"
  },
  {
    "path": "scripts/freebsd-ci-test.sh",
    "chars": 9443,
    "preview": "#!/bin/sh\n\n# This script contains CI tests for FreeBSD, testing\n#\n# - cargo build & cargo test\n# - configure and start s"
  },
  {
    "path": "snap/snapcraft.yaml",
    "chars": 1571,
    "preview": "name: sccache\nbase: core24\nadopt-info: sccache\n\nsummary: sccache is ccache with cloud storage\ndescription: |\n  sccache i"
  },
  {
    "path": "src/bin/sccache-dist/build.rs",
    "chars": 34878,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/bin/sccache-dist/build_freebsd.rs",
    "chars": 15821,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/bin/sccache-dist/cmdline/mod.rs",
    "chars": 1064,
    "preview": "// Copyright 2022 <LovecraftianHorror@pm.me>\n// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache Licens"
  },
  {
    "path": "src/bin/sccache-dist/cmdline/parse.rs",
    "chars": 13237,
    "preview": "// Copyright 2022 <LovecraftianHorror@pm.me>\n// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache Licens"
  },
  {
    "path": "src/bin/sccache-dist/main.rs",
    "chars": 31618,
    "preview": "#[macro_use]\nextern crate log;\n\nuse anyhow::{Context, Result, bail};\nuse base64::Engine;\nuse rand::{RngCore, rngs::OsRng"
  },
  {
    "path": "src/bin/sccache-dist/token_check.rs",
    "chars": 6954,
    "preview": "use anyhow::{Context, Result, bail};\nuse base64::Engine;\nuse sccache::dist::http::{ClientAuthCheck, ClientVisibleMsg};\nu"
  },
  {
    "path": "src/cache/azure.rs",
    "chars": 1281,
    "preview": "// Copyright 2018 Benjamin Bader\n// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2"
  },
  {
    "path": "src/cache/cache.rs",
    "chars": 21513,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/cache/cache_io.rs",
    "chars": 8885,
    "preview": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance wit"
  },
  {
    "path": "src/cache/cos.rs",
    "chars": 1274,
    "preview": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance wit"
  },
  {
    "path": "src/cache/disk.rs",
    "chars": 6859,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/cache/gcs.rs",
    "chars": 4164,
    "preview": "// Copyright 2017 Mozilla Foundation\n// Copyright 2017 Google Inc.\n//\n// Licensed under the Apache License, Version 2.0 "
  },
  {
    "path": "src/cache/gha.rs",
    "chars": 1660,
    "preview": "// Copyright 2022 Bitski Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use t"
  },
  {
    "path": "src/cache/http_client.rs",
    "chars": 365,
    "preview": "use opendal::raw::HttpClient;\nuse reqwest::ClientBuilder;\n\n/// Set the user agent (helps with monitoring on the server s"
  },
  {
    "path": "src/cache/lazy_disk_cache.rs",
    "chars": 1691,
    "preview": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance wit"
  },
  {
    "path": "src/cache/memcached.rs",
    "chars": 1563,
    "preview": "// Copyright 2016 Mozilla Foundation\n// Copyright 2017 David Michael Barr <b@rr-dav.id.au>\n//\n// Licensed under the Apac"
  },
  {
    "path": "src/cache/mod.rs",
    "chars": 1439,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/cache/oss.rs",
    "chars": 1566,
    "preview": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance wit"
  },
  {
    "path": "src/cache/readonly.rs",
    "chars": 7101,
    "preview": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance wit"
  },
  {
    "path": "src/cache/redis.rs",
    "chars": 3295,
    "preview": "// Copyright 2016 Mozilla Foundation\n// Copyright 2016 Felix Obenhuber <felix@obenhuber.de>\n//\n// Licensed under the Apa"
  },
  {
    "path": "src/cache/s3.rs",
    "chars": 6579,
    "preview": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance wit"
  },
  {
    "path": "src/cache/utils.rs",
    "chars": 1764,
    "preview": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance wit"
  },
  {
    "path": "src/cache/webdav.rs",
    "chars": 1486,
    "preview": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance wit"
  },
  {
    "path": "src/client.rs",
    "chars": 3547,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/cmdline.rs",
    "chars": 13163,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/commands.rs",
    "chars": 30137,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/compiler/args.rs",
    "chars": 39574,
    "preview": "use std::cmp::Ordering;\nuse std::error::Error;\nuse std::ffi::OsString;\nuse std::fmt::{self, Debug, Display};\nuse std::ma"
  },
  {
    "path": "src/compiler/c.rs",
    "chars": 78325,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/compiler/cicc.rs",
    "chars": 11529,
    "preview": "// Copyright 2016 Mozilla Foundation\n// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All "
  },
  {
    "path": "src/compiler/clang.rs",
    "chars": 42777,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/compiler/compiler.rs",
    "chars": 130971,
    "preview": "// Copyright 2016 Mozilla Foundation\n// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All "
  },
  {
    "path": "src/compiler/counted_array.rs",
    "chars": 822,
    "preview": "/// Helper macro to create fixed-length arrays without specifying a fixed size\n#[macro_export]\nmacro_rules! counted_arra"
  },
  {
    "path": "src/compiler/cudafe.rs",
    "chars": 6054,
    "preview": "// Copyright 2016 Mozilla Foundation\n// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All "
  },
  {
    "path": "src/compiler/diab.rs",
    "chars": 26614,
    "preview": "// Copyright 2018 Mozilla Foundation\n// Copyright 2018 Felix Obenhuber <felix@obenhuber.de>\n//\n// Licensed under the Apa"
  },
  {
    "path": "src/compiler/gcc.rs",
    "chars": 92612,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/compiler/mod.rs",
    "chars": 1015,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/compiler/msvc.rs",
    "chars": 106937,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/compiler/nvcc.rs",
    "chars": 75144,
    "preview": "// Copyright 2016 Mozilla Foundation\n// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All "
  },
  {
    "path": "src/compiler/nvhpc.rs",
    "chars": 13579,
    "preview": "// Copyright 2016 Mozilla Foundation\n// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All "
  },
  {
    "path": "src/compiler/preprocessor_cache.rs",
    "chars": 30396,
    "preview": "// Copyright 2023 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/compiler/ptxas.rs",
    "chars": 3413,
    "preview": "// Copyright 2016 Mozilla Foundation\n// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All "
  },
  {
    "path": "src/compiler/rust.rs",
    "chars": 136304,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/compiler/tasking_vx.rs",
    "chars": 26433,
    "preview": "// Copyright 2018 Mozilla Foundation\n// Copyright 2019 ESRLabs AG\n//\n// Licensed under the Apache License, Version 2.0 ("
  },
  {
    "path": "src/config.rs",
    "chars": 79915,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/dist/cache.rs",
    "chars": 21258,
    "preview": "use crate::dist::Toolchain;\nuse crate::lru_disk_cache::Result as LruResult;\nuse crate::lru_disk_cache::{LruDiskCache, Re"
  },
  {
    "path": "src/dist/client_auth.rs",
    "chars": 23178,
    "preview": "use bytes::Bytes;\nuse futures::channel::oneshot;\nuse http::StatusCode;\nuse http::header::{CONTENT_LENGTH, CONTENT_TYPE};"
  },
  {
    "path": "src/dist/http.rs",
    "chars": 54689,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/dist/mod.rs",
    "chars": 23046,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/dist/pkg.rs",
    "chars": 19675,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/dist/test.rs",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "src/errors.rs",
    "chars": 2041,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/jobserver.rs",
    "chars": 5512,
    "preview": "use std::io;\nuse std::process::Command;\nuse std::sync::Arc;\n\nuse futures::StreamExt;\nuse futures::channel::mpsc;\nuse fut"
  },
  {
    "path": "src/lib.rs",
    "chars": 2935,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/lru_disk_cache/lru_cache.rs",
    "chars": 25634,
    "preview": "// Copyright 2015 The Rust Project Developers. See the COPYRIGHT\n// file at the top-level directory of this distribution"
  },
  {
    "path": "src/lru_disk_cache/mod.rs",
    "chars": 25946,
    "preview": "pub mod lru_cache;\n\nuse fs::File;\nuse fs_err as fs;\nuse std::borrow::Borrow;\nuse std::boxed::Box;\nuse std::collections::"
  },
  {
    "path": "src/main.rs",
    "chars": 654,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/mock_command.rs",
    "chars": 21486,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/net.rs",
    "chars": 6303,
    "preview": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance wit"
  },
  {
    "path": "src/protocol.rs",
    "chars": 2575,
    "preview": "use crate::compiler::ColorMode;\nuse crate::server::{DistInfo, ServerInfo};\nuse serde::{Deserialize, Serialize};\nuse std:"
  },
  {
    "path": "src/server.rs",
    "chars": 86634,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/test/mock_storage.rs",
    "chars": 2755,
    "preview": "// Copyright 2017 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/test/mod.rs",
    "chars": 657,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/test/tests.rs",
    "chars": 11117,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/test/utils.rs",
    "chars": 7996,
    "preview": "// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "src/util.rs",
    "chars": 61067,
    "preview": "// Copyright 2017 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "tests/cache_hit_rate.rs",
    "chars": 3323,
    "preview": "pub mod helpers;\n\nuse std::process::Command;\n\nuse anyhow::Result;\nuse assert_cmd::assert::OutputAssertExt;\nuse helpers::"
  },
  {
    "path": "tests/cmake-modules/CMakeLists.txt",
    "chars": 393,
    "preview": "cmake_minimum_required(VERSION 3.28)\n\nproject(myproject LANGUAGES CXX)\n\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDAR"
  },
  {
    "path": "tests/cmake-modules/main.cpp",
    "chars": 135,
    "preview": "#include <stdio.h>\n\nimport mymodule;\n\nint main() {\n    print_hello_world();\n    printf(\"add(1, 2) = %d\\n\", add(1, 2));\n "
  },
  {
    "path": "tests/cmake-modules/mymodule.cppm",
    "chars": 190,
    "preview": "module;\n\n#include <iostream>\n\nexport module mymodule;\n\nexport void print_hello_world() {\n    std::cout << \"Hello, World!"
  },
  {
    "path": "tests/dist.rs",
    "chars": 16038,
    "preview": "#![cfg(all(feature = \"dist-client\", feature = \"dist-server\"))]\n\nextern crate assert_cmd;\nextern crate log;\nextern crate "
  },
  {
    "path": "tests/harness/Dockerfile.sccache-dist",
    "chars": 108,
    "preview": "FROM ubuntu:latest\nRUN apt-get update && \\\n    apt-get install -y libcap2 bubblewrap && \\\n    apt-get clean\n"
  },
  {
    "path": "tests/harness/mod.rs",
    "chars": 24499,
    "preview": "use fs_err as fs;\nuse log::trace;\n#[cfg(any(feature = \"dist-client\", feature = \"dist-server\"))]\nuse sccache::config::HTT"
  },
  {
    "path": "tests/helpers/mod.rs",
    "chars": 4737,
    "preview": "#![allow(clippy::result_large_err)]\n\nuse anyhow::{Context, Result};\nuse assert_cmd::assert::OutputAssertExt;\nuse chrono:"
  },
  {
    "path": "tests/integration/Makefile",
    "chars": 7520,
    "preview": ".PHONY: help clean $(addprefix test-,$(BACKENDS)) $(addprefix clean-,$(BACKENDS)) test-backends\n\nexport UID := $(shell i"
  },
  {
    "path": "tests/integration/README.md",
    "chars": 1272,
    "preview": "# sccache Integration Tests\n\nDocker Compose-based integration tests for sccache backends and compilers.\n\n## Prerequisite"
  },
  {
    "path": "tests/integration/autotools/Makefile.am",
    "chars": 68,
    "preview": "noinst_LIBRARIES = libmyproject.a\nlibmyproject_a_SOURCES = main.cpp\n"
  },
  {
    "path": "tests/integration/autotools/configure.ac",
    "chars": 197,
    "preview": "AC_INIT([myproject], [1.0])\nAM_INIT_AUTOMAKE([foreign subdir-objects])\nAC_CONFIG_SRCDIR([main.cpp])\nAC_CONFIG_HEADERS([c"
  },
  {
    "path": "tests/integration/autotools/main.cpp",
    "chars": 91,
    "preview": "#include <iostream>\n\nvoid print_hello() {\n    std::cout << \"Hello, World!\" << std::endl;\n}\n"
  },
  {
    "path": "tests/integration/basedirs-autotools/Makefile.am",
    "chars": 342,
    "preview": "noinst_LIBRARIES = libbasedirs.a\n# Use absolute path for source file - autoconf will substitute abs_srcdir and abs_build"
  },
  {
    "path": "tests/integration/basedirs-autotools/configure.ac",
    "chars": 312,
    "preview": "AC_INIT([basedirs-test], [1.0])\nAM_INIT_AUTOMAKE([foreign subdir-objects])\nAC_CONFIG_SRCDIR([main.cpp])\nAC_CONFIG_HEADER"
  },
  {
    "path": "tests/integration/basedirs-autotools/include/myheader.h",
    "chars": 333,
    "preview": "#ifndef MYHEADER_H\n#define MYHEADER_H\n\n#include <string>\n#include <iostream>\n\ninline std::string get_message() {\n    ret"
  },
  {
    "path": "tests/integration/basedirs-autotools/main.cpp",
    "chars": 261,
    "preview": "#include <iostream>\n#include \"myheader.h\"\n\nint main() {\n    std::cout << \"Main file: \" << __FILE__ << std::endl;\n    std"
  },
  {
    "path": "tests/integration/cmake/CMakeLists.txt",
    "chars": 111,
    "preview": "cmake_minimum_required(VERSION 3.10)\n\nproject(myproject LANGUAGES CXX)\n\nadd_library(myproject OBJECT main.cpp)\n"
  },
  {
    "path": "tests/integration/cmake/main.cpp",
    "chars": 91,
    "preview": "#include <iostream>\n\nvoid print_hello() {\n    std::cout << \"Hello, World!\" << std::endl;\n}\n"
  },
  {
    "path": "tests/integration/cmake-hip/CMakeLists.txt",
    "chars": 192,
    "preview": "cmake_minimum_required(VERSION 3.10)\n\nproject(myproject LANGUAGES CXX HIP)\n\nadd_library(vectoradd_hip vectoradd_hip.cpp)"
  },
  {
    "path": "tests/integration/cmake-hip/vectoradd_hip.cpp",
    "chars": 4015,
    "preview": "/*\nCopyright (c) 2015-2016 Advanced Micro Devices, Inc. All rights reserved.\n\nPermission is hereby granted, free of char"
  },
  {
    "path": "tests/integration/docker-compose.yml",
    "chars": 8355,
    "preview": "x-common-env: &common-env\n  RUST_BACKTRACE: full\n  RUSTC_WRAPPER: ${SCCACHE_PATH:-/sccache/target/debug/sccache}\n  RUST_"
  },
  {
    "path": "tests/integration/msvc/args.rsp",
    "chars": 47,
    "preview": "foo.cpp -Fofoo.o /sourceDependencies foo.o.json"
  },
  {
    "path": "tests/integration/msvc/foo.cpp",
    "chars": 81,
    "preview": "#include <iostream>\n\nint main() {\n  std::cout << \"Hello World!\\n\";\n  return 0;\n}\n"
  },
  {
    "path": "tests/integration/msvc-preprocessing/args.rsp",
    "chars": 30,
    "preview": "foo.cpp -Fofoo.o -W4 -WX -Wall"
  },
  {
    "path": "tests/integration/msvc-preprocessing/foo.cpp",
    "chars": 769,
    "preview": "// This tests sccache's ability to handle a known bug in cl.exe\n// More information: https://github.com/mozilla/sccache/"
  },
  {
    "path": "tests/integration/randomize_readdir/Cargo.toml",
    "chars": 192,
    "preview": "[package]\nedition = \"2021\"\nname = \"randomize_readdir\"\nversion = \"0.1.0\"\n\n[dependencies]\nctor = \"0.2\"\nlibc = \"0.2.99\"\nlog"
  },
  {
    "path": "tests/integration/randomize_readdir/src/lib.rs",
    "chars": 8801,
    "preview": "// Copyright 2024 Mozilla Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "tests/integration/scripts/test-autotools.sh",
    "chars": 1212,
    "preview": "#!/bin/bash\nset -euo pipefail\n\nSCCACHE=\"${SCCACHE_PATH:-/sccache/target/debug/sccache}\"\n\necho \"========================="
  },
  {
    "path": "tests/integration/scripts/test-backend.sh",
    "chars": 1740,
    "preview": "#!/bin/bash\nset -euo pipefail\n\nTEST_NAME=\"${TEST_NAME:-unknown}\"\nBACKEND_CHECK=\"${BACKEND_CHECK:-}\"\nSCCACHE=\"${SCCACHE_P"
  },
  {
    "path": "tests/integration/scripts/test-basedirs.sh",
    "chars": 4886,
    "preview": "#!/bin/bash\nset -euo pipefail\n\nSCCACHE=\"${SCCACHE_PATH:-/sccache/target/debug/sccache}\"\n\necho \"========================="
  },
  {
    "path": "tests/integration/scripts/test-clang.sh",
    "chars": 1522,
    "preview": "#!/bin/bash\nset -euo pipefail\n\nSCCACHE=\"${SCCACHE_PATH:-/sccache/target/debug/sccache}\"\nTEST_FILE=\"/sccache/tests/test_c"
  },
  {
    "path": "tests/integration/scripts/test-cmake.sh",
    "chars": 1349,
    "preview": "#!/bin/bash\nset -euo pipefail\n\nSCCACHE=\"${SCCACHE_PATH:-/sccache/target/debug/sccache}\"\n\necho \"========================="
  },
  {
    "path": "tests/integration/scripts/test-coverage.sh",
    "chars": 1313,
    "preview": "#!/bin/bash\nset -euo pipefail\n\nSCCACHE=\"${SCCACHE_PATH:-/sccache/target/debug/sccache}\"\nexport RUSTFLAGS=\"-Cinstrument-c"
  },
  {
    "path": "tests/integration/scripts/test-gcc.sh",
    "chars": 1508,
    "preview": "#!/bin/bash\nset -euo pipefail\n\nSCCACHE=\"${SCCACHE_PATH:-/sccache/target/debug/sccache}\"\nTEST_FILE=\"/sccache/tests/test_c"
  },
  {
    "path": "tests/integration/scripts/test-zstd.sh",
    "chars": 2466,
    "preview": "#!/bin/bash\nset -euo pipefail\n\nSCCACHE=\"${SCCACHE_PATH:-/sccache/target/debug/sccache}\"\n\necho \"========================="
  },
  {
    "path": "tests/integration/test_intel_asm.s",
    "chars": 367,
    "preview": ".data\n\nhello_str:\n    .string \"Hello, world!\\n\"\n\n\n    .set hello_str_length, . - hello_str - 1\n\n.text\n\n.globl  main\n\n.ty"
  },
  {
    "path": "tests/integration/test_intel_asm_to_preproc.S",
    "chars": 367,
    "preview": ".data\n\nhello_str:\n    .string \"Hello, world!\\n\"\n\n\n    .set hello_str_length, . - hello_str - 1\n\n.text\n\n.globl  main\n\n.ty"
  },
  {
    "path": "tests/integration/webdav-config.yaml",
    "chars": 104,
    "preview": "address: 0.0.0.0\nport: 8080\nprefix: /\n\nusers:\n  - username: bar\n    password: baz\n    permissions: CRUD\n"
  },
  {
    "path": "tests/integration/xcode/main.cpp",
    "chars": 109,
    "preview": "#include <iostream>\n\nint main(int argc, const char * argv[]) {\n\tstd::cout << \"Hello, World!\\n\";\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/integration/xcode/sccache.xcconfig",
    "chars": 132,
    "preview": "C_COMPILER_LAUNCHER=../../../target/debug/sccache\nCLANG_ENABLE_MODULES=NO\nCOMPILER_INDEX_STORE_ENABLE=NO\nCLANG_USE_RESPO"
  },
  {
    "path": "tests/integration/xcode/xcode-test.xcodeproj/project.pbxproj",
    "chars": 9238,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 63;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "tests/logging.rs",
    "chars": 4006,
    "preview": "// Tests for logging functionality.\n//\n// Copyright 2025 Mozilla Foundation\n//\n// Licensed under the Apache License, Ver"
  },
  {
    "path": "tests/msvc-msbuild/.gitignore",
    "chars": 32,
    "preview": "*\n!.gitignore\n!*.vcxproj\n!*.cpp\n"
  },
  {
    "path": "tests/msvc-msbuild/MsbuildCpp.vcxproj",
    "chars": 2415,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msb"
  },
  {
    "path": "tests/msvc-msbuild/test_bar.cpp",
    "chars": 29,
    "preview": "int bar(int x) { return x; }\n"
  },
  {
    "path": "tests/msvc-msbuild/test_baz.cpp",
    "chars": 29,
    "preview": "int baz(int x) { return x; }\n"
  },
  {
    "path": "tests/msvc-msbuild/test_foo.cpp",
    "chars": 29,
    "preview": "int foo(int x) { return x; }\n"
  },
  {
    "path": "tests/oauth.rs",
    "chars": 10236,
    "preview": "#![deny(rust_2018_idioms)]\n#![cfg(feature = \"dist-client\")]\n\nuse fs_err as fs;\nuse std::io::{self, Read, Write};\nuse std"
  },
  {
    "path": "tests/sccache_args.rs",
    "chars": 2135,
    "preview": "//! Tests for sccache args.\n//!\n//! Any copyright is dedicated to the Public Domain.\n//! http://creativecommons.org/publ"
  },
  {
    "path": "tests/sccache_cargo.rs",
    "chars": 12446,
    "preview": "//! System tests for compiling Rust code with cargo.\n//!\n//! Any copyright is dedicated to the Public Domain.\n//! http:/"
  },
  {
    "path": "tests/sccache_rustc.rs",
    "chars": 3869,
    "preview": "#![cfg(unix)]\n\nuse assert_cmd::Command;\nuse tempfile::tempdir;\n\nuse std::{\n    env::{consts::DLL_SUFFIX, var_os},\n    ff"
  },
  {
    "path": "tests/system.rs",
    "chars": 71719,
    "preview": "// System tests for compiling C code.\n//\n// Copyright 2016 Mozilla Foundation\n//\n// Licensed under the Apache License, V"
  },
  {
    "path": "tests/test-crate/Cargo.toml",
    "chars": 294,
    "preview": "[package]\nauthors = [\"Ted Mielczarek <ted@mielczarek.org>\"]\nname = \"test-crate\"\nversion = \"0.1.0\"\n\n[dependencies]\n# Arbi"
  },
  {
    "path": "tests/test-crate/src/bin.rs",
    "chars": 62,
    "preview": "extern crate mylib;\n\nfn main() {\n    mylib::env_dep_test();\n}\n"
  },
  {
    "path": "tests/test-crate/src/lib.rs",
    "chars": 189,
    "preview": "fn unused() {}\n\npub fn env_dep_test() {\n    println!(\"Env var: {}\", env!(\"TEST_ENV_VAR\"));\n}\n\n#[cfg(test)]\nmod tests {\n "
  },
  {
    "path": "tests/test.c",
    "chars": 62,
    "preview": "#include <stdio.h>\n\nvoid foo() {\n  printf(\"hello world\\n\");\n}\n"
  },
  {
    "path": "tests/test.c.gcc-13.2.0-preproc",
    "chars": 17967,
    "preview": "# 0 \"tests/test.c\"\n# 0 \"<built-in>\"\n# 0 \"<command-line>\"\n# 1 \"/usr/include/stdc-predef.h\" 1 3 4\n# 0 \"<command-line>\" 2\n#"
  },
  {
    "path": "tests/test_a.cu",
    "chars": 204,
    "preview": "\n#include <stdio.h>\n#include \"cuda_runtime.h\"\n\n__global__ void cuda_entry_point(int*, int*) {}\n__device__ void cuda_devi"
  },
  {
    "path": "tests/test_a.hip",
    "chars": 207,
    "preview": "\n#include <stdio.h>\n#include <hip/hip_runtime.h>\n\n__global__ void cuda_entry_point(int*, int*) {}\n__device__ void cuda_d"
  },
  {
    "path": "tests/test_b.cu",
    "chars": 204,
    "preview": "\n#include <stdio.h>\n#include \"cuda_runtime.h\"\n\n__global__ void cuda_entry_point(int*, int*) {}\n__device__ void cuda_devi"
  },
  {
    "path": "tests/test_b.hip",
    "chars": 207,
    "preview": "\n#include <stdio.h>\n#include <hip/hip_runtime.h>\n\n__global__ void cuda_entry_point(int*, int*) {}\n__device__ void cuda_d"
  },
  {
    "path": "tests/test_c.cu",
    "chars": 204,
    "preview": "\n#include <stdio.h>\n#include \"cuda_runtime.h\"\n\n__global__ void cuda_entry_point(int*, int*) {}\n__device__ void cuda_devi"
  },
  {
    "path": "tests/test_c.hip",
    "chars": 207,
    "preview": "\n#include <stdio.h>\n#include <hip/hip_runtime.h>\n\n__global__ void cuda_entry_point(int*, int*) {}\n__device__ void cuda_d"
  },
  {
    "path": "tests/test_clang_multicall.c",
    "chars": 209,
    "preview": "#include <iostream>\n\n// this is c++ code, but the extension is .c,\n// so clang doesn't change its behavior because of th"
  },
  {
    "path": "tests/test_err.c",
    "chars": 2,
    "preview": "x\n"
  },
  {
    "path": "tests/test_macro_expansion.c",
    "chars": 454,
    "preview": "#include <stdlib.h>\n\n#define foo(x)                                                                 \\\n  {               "
  },
  {
    "path": "tests/test_whitespace.c",
    "chars": 65,
    "preview": "#include <stdio.h>\n\nint main() {printf(\"Hello world!\");return 0;}"
  },
  {
    "path": "tests/test_whitespace_alt.c",
    "chars": 77,
    "preview": "#include <stdio.h>\n\nint main() \n\n\n{\n\n\n   printf(\"Hello world!\");\nreturn 0;\n}\n"
  },
  {
    "path": "tests/test_with_define.c",
    "chars": 144,
    "preview": "#include <stdio.h>\n\n#if !defined(SCCACHE_TEST_DEFINE)\n#error SCCACHE_TEST_DEFINE is not defined\n#endif\n\nvoid foo() { pri"
  }
]

About this extraction

This page contains the full source code of the mozilla/sccache GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 182 files (1.9 MB), approximately 463.7k tokens, and a symbol index with 2294 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!