#cache #sccache #lru-cache #compilation #disk #compiler #local

已删除 lru-disk-cache

磁盘上的LRU缓存

0.4.1 2020年12月22日
0.4.0 2020年2月24日
0.3.0 2019年6月26日
0.2.0 2018年1月30日
0.1.0 2017年7月25日

#62 in #lru-cache

Apache-2.0

49KB
975 代码行

Build Status Crates.io Matrix Crates.io dependency status

CodeCov

sccache - 共享编译缓存

sccache 是一个类似 ccache 的编译器缓存工具。它用作编译器包装器,并在可能的情况下避免编译,将缓存结果存储在本地磁盘或多个云存储后端之一中。

sccache 包括对缓存 C/C++ 代码、Rust、NVIDIA 的 CUDA(使用 nvcc)以及 clang)编译的支持。

sccache 还提供了所有支持的编译器(包括 Rust)的 icecream 风格的分布式编译(自动打包本地工具链)。分布式编译系统包括 icecream 缺少的几个安全功能,例如身份验证、传输层加密和在构建服务器上沙盒化的编译器执行。有关更多信息,请参阅 分布式快速入门指南

sccache 还可作为 GitHub Actions 使用,以简化使用 GitHub Actions 缓存部署。


目录


安装

在发布页面提供了可用于 Windows、Linux(针对 musl 编译的可移植二进制文件)和 macOS 的预构建 x86-64 二进制文件。几个软件包管理器也包含 sccache 软件包,您可以使用 cargo 从源代码安装最新版本,或直接从源代码签出构建。

macOS

在 macOS 上,您可以通过 Homebrew 安装 sccache

brew install sccache

或通过 MacPorts 安装

sudo port install sccache

Windows

在Windows上,可以通过 scoop 安装 sccache。

scoop install sccache

通过 cargo

如果你已经安装了Rust工具链,你可以使用 cargo 安装 sccache。**注意,这将从源代码编译 sccache,这需要相当多的资源。出于CI的目的,你应该使用预构建的二进制包。**

cargo install sccache --locked

用法

运行 sccache 的方式与运行 ccache 相似:在你的编译命令前加上它,例如

sccache gcc -o foo.o -c foo.c

如果你想在缓存Rust构建中使用 sccache,你可以在 cargo 配置文件 中定义 .rustc-wrapper。例如,你可以在 $HOME/.cargo/config.toml 中全局设置它,通过添加以下内容

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

请注意,你需要使用 1.40 或更高版本的 cargo 才能使其正常工作。

或者,你可以使用环境变量 RUSTC_WRAPPER

export RUSTC_WRAPPER=/path/to/sccache
cargo build

sccache 支持 gcc、clang、MSVC、rustc、NVCCNVC++Wind River 的 diab 编译器。gcc 和 msvc 都支持响应文件,关于它们实现的更多信息请参阅 这里

除非你指定其他方式,否则 sccache 将使用本地磁盘缓存。

sccache 使用客户端-服务器模型,其中服务器在客户端所在的同一台机器上本地运行。客户端-服务器模型允许服务器通过在内存中保持一些状态来提高效率。如果尚未运行,sccache 命令将启动一个服务器进程,或者你可以运行 sccache --start-server 来启动后台服务器进程而不执行任何编译。

你可以运行 sccache --stop-server 来终止服务器。默认情况下,在 10 分钟的无操作后,它也会终止。

运行 sccache --show-stats 将打印缓存统计摘要。

关于使用 sccacheJenkins 的注意事项请参阅 这里

要使用 sccache 与 cmake,向 cmake 3.4 或更高版本提供以下命令行参数

-DCMAKE_C_COMPILER_LAUNCHER=sccache
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache

使用 sccache 与 MSVC 和 cmake 的过程取决于你使用的 cmake 版本。**对于 3.24 及更早版本的 cmake**,要为使用 MSVC 进行调试生成 PDB 文件,可以使用 /Z7 选项。或者,可以使用 /Zi 选项与 /Fd 一起使用,如果 /Fd 为每个创建的对象文件指定不同的 PDB 文件名。请注意,CMake 默认设置 /Zi,因此如果你使用 CMake,你可以通过在 CMakeLists.txt 中添加以下代码来使用 /Z7

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()

默认情况下,如果 sccache 无法成功与其相关服务器通信,它将使你的构建失败。要使 sccache 而不是优雅地失败到本地编译器(而不停止),请设置环境变量 SCCACHE_IGNORE_SERVER_IO_ERROR=1

对于 CMake 3.25 及更高版本,要使用 MSVC 编译,您必须使用新的 CMAKE_MSVC_DEBUG_INFORMATION_FORMAT 选项,该选项用于配置 -Z7 标志。此外,您必须将 cmake 政策编号 0141 设置为 NEW 设置

set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded)
cmake_policy(SET CMP0141 NEW)

示例配置,我们将自动在 PATH 中查找 sccache

find_program(SCCACHE sccache REQUIRED)

set(CMAKE_C_COMPILER_LAUNCHER ${SCCACHE})
set(CMAKE_CXX_COMPILER_LAUNCHER ${SCCACHE})
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded)
cmake_policy(SET CMP0141 NEW)

或者,如果您在命令行上使用 MSVC 配置 CMake,假设 sccache 在默认搜索路径上

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

您可以在命令行中不添加任何额外标志的情况下正常构建代码,这对于 IDE 非常有用。


构建要求

sccache 是一个 Rust 程序。构建它需要 cargo(因此需要 rustc)。sccache 当前需要 Rust 1.70.0。我们建议您通过 Rustup 安装 Rust。

构建

如果您是为了非开发目的构建 sccache,请确保使用 cargo build --release 命令来获取优化后的二进制文件

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

可用功能的实际列表可以在 Cargo.toml 文件的 [features] 部分中找到。

默认情况下,sccache 会构建支持所有存储后端,但可以通过重置功能列表并启用所有其他后端来禁用个别后端。有关如何使用 Cargo 选择功能的详细信息,请参阅 Cargo 文档

特征 vendored-openssl 可用于在启用 openssl 功能的情况下将 openssl 静态链接。

构建可移植的二进制文件

当使用 dist-server 功能构建时,sccache 将依赖于 OpenSSL,如果您想要分发可移植的二进制文件,这可能是个麻烦。您可以使用 openssl/vendored 功能将 OpenSSL 静态链接。

Linux

使用 cargo 构建,并使用 ldd 检查生成的二进制文件不再依赖于 OpenSSL。

macOS

使用 cargo 构建,并使用 otool -L 检查生成的二进制文件不再依赖于 OpenSSL。

Windows

在 Windows 上,二进制文件可能还依赖于一些在较旧 Windows 版本上不可用的 MSVC CRT DLL。

您可以使用以下内容的 .cargo/config.toml 文件将 CRT 静态链接。

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

使用 cargo 构建,并使用 dumpbin /dependents 检查生成的二进制文件不再依赖于 MSVC CRT DLL。

当与 OpenSSL 静态链接时,您需要在您的 $PATH 中有 Perl。


在调用之间分离缓存

在某些情况下,如果多个不同的编译调用不应相互重用缓存的输出,可以将 SCCACHE_C_CUSTOM_CACHE_BUSTER 设置为唯一的值,该值将混合到哈希中。MACOSX_DEPLOYMENT_TARGETIPHONEOS_DEPLOYMENT_TARGET 变量已经显示出这样的重用抑制行为。目前没有为 Rust 编译设置这样的变量。


覆盖缓存

当缓存中包含损坏的构建工件时,可能需要覆盖缓存中的内容。这可以通过设置环境变量 SCCACHE_RECACHE 来实现。


调试

您可以将环境变量 SCCACHE_ERROR_LOG 设置为一个路径,并将 SCCACHE_LOG 设置为让服务器进程将日志重定向到该位置(包括未处理的恐慌输出,因为服务器内部设置了 RUST_BACKTRACE=1)。

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

您也可以为您的构建系统设置这些环境变量,例如

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

或者,如果您是在本地编译,可以通过运行 SCCACHE_START_SERVER=1 SCCACHE_NO_DAEMON=1 sccache 来手动在前台模式下运行服务器,并将日志发送到 stderr,例如通过设置环境变量 SCCACHE_LOG。这种方法不适用于 CI 服务,因为您需要同时在另一个 shell 中编译。

SCCACHE_LOG=debug SCCACHE_START_SERVER=1 SCCACHE_NO_DAEMON=1 sccache

与 GNU make jobserver 交互

sccache 提供了对 GNU make jobserver 的支持。当服务器从一个提供 jobserver 的进程启动时,sccache 将使用该 jobserver 并将其提供给它所启动的任何进程。(如果您是从 GNU make 脚本中运行 sccache,您需要在该命令前面加上 + 以获得此行为。)如果 sccache 服务器在没有 jobserver 的情况下启动,它将创建自己的 jobserver,其槽位数等于可用的 CPU 核心数。

这在使用 sccache 进行 Rust 编译时最有用,因为 rustc 支持使用 jobserver 进行并行代码生成,这样就可以确保 rustc 不会因代码生成任务而使系统过载。Cargo 实现了自己的 jobserver(请参阅 cargo 文档中的 NUM_JOBS 信息),以便 rustc 使用,因此通过 RUSTC_WRAPPER 在 cargo 中使用 sccache 进行 Rust 编译应该可以自动完成正确的事情。


已知问题

通用

  • 文件的绝对路径必须匹配才能获得缓存命中。这意味着即使您使用共享缓存,每个人也必须在相同的绝对路径(即不在 $HOME)上构建,才能相互受益。在 Rust 中,这包括存储在 $HOME/.cargo/registry/cache 中的第三方 crate 的源代码。

Rust

  • 调用系统链接器的 crate 不能被缓存。这包括 bindylibcdylibproc-macro crate。您可能可以通过将它们转换为具有薄 bin 包装器的 lib crate 来提高大型 bin crate 的编译时间。
  • 增量编译的 crate 不能被缓存。默认情况下,在调试配置文件中,Cargo 将为工作区成员和路径依赖项使用增量编译。您可以通过禁用增量编译。

Rust 的注意事项的更多细节

  • 指向 sccache 的符号链接将不会工作。请使用硬链接:ln sccache /usr/local/bin/cc

存储选项

依赖项

~0.2–9MB
~55K SLoC