#cache #compilation #compiler #sccache #cloud-storage #build #ccache

构建 cachepot

cachepot 是一个类似 sccache 的工具。它用作编译器包装器,并在可能的情况下避免编译,使用云存储在远程存储中存储缓存。

2 个不稳定版本

0.1.0-rc.12022年3月10日
0.0.0 2020年12月10日

#85构建工具

每月 39 次下载

Apache-2.0

1MB
24K SLoC

Build Status rust 1.56.1+ badge

cachepot maskot image

cachepot - 共享编译缓存

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

它也是 sccache 的分支,具有改进的安全特性和代码库的全面改进。我们尽可能地向上游贡献,但目标可能不完全匹配。

cachepot 支持缓存 C/C++ 代码、Rust 的编译,以及使用 nvcc 的 NVIDIA CUDA。

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


目录 (ToC)


安装

Windows、Linux(针对musl编译的便携式二进制文件)和macOS的预构建x86-64二进制文件可在发布页面找到。

如果您已安装Rust工具链,则可以使用cargo安装cachepot。 请注意,这将从源代码编译cachepot,这相对资源密集。出于CI目的,您应使用预构建的二进制包。

cargo install --git https://github.com/paritytech/cachepot

使用方法

运行cachepot就像运行ccache一样:在编译命令前加上它,如下所示

cachepot gcc -o foo.o -c foo.c

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

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

请注意,您需要使用cargo 1.40或更高版本才能使此功能正常工作。

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

RUSTC_WRAPPER=/path/to/cachepot cargo build

cachepot支持gcc、clang、MSVC、rustc、NVCC和Wind River的diab编译器

如果您没有指定其他选项,cachepot将使用本地磁盘缓存。

cachepot使用客户端-服务器模型,其中服务器(我们称之为“协调器”)在客户端相同的机器上本地运行。客户端-服务器模型允许服务器/协调器通过在内存中保留一些状态来提高效率。如果尚未运行,cachepot命令将启动协调器进程,或者您可以通过运行cachepot --start-coordinator来启动后台服务器进程而不进行任何编译。

您可以通过运行cachepot --stop-coordinator来终止协调器。默认情况下,它将在10分钟的无操作后终止。

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

有关使用cachepotJenkins的说明。

要使用cmake与cachepot一起使用,请向cmake >= 3.4提供以下命令行参数

-DCMAKE_C_COMPILER_LAUNCHER=cachepot
-DCMAKE_CXX_COMPILER_LAUNCHER=cachepot

构建要求

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

构建

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

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

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

Linux

没有本地依赖项。

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

Linux和Podman

您还可以使用Parity CI Docker镜像构建存储库。

podman run --rm -it -w /shellhere/cachepot \
                    -v "$(pwd)":/shellhere/cachepot:Z \
                    -u $(id -u):$(id -g) \
                    --userns=keep-id \
                    docker.io/paritytech/cachepot-ci:staging cargo build --locked --release
#artifacts can be found in ./target/release

如果您想重新生成CI流程中的其他步骤,可以使用以下指南

macOS

没有本地依赖项。

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

Windows

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

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

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

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


存储选项

本地

cachepot默认使用本地磁盘存储。您可以通过设置环境变量CACHEPOT_DIR来更改磁盘缓存位置。默认情况下,它将在当前平台的一个合理位置使用:Linux上的~/.cache/cachepot,Windows上的%LOCALAPPDATA%\Parity\cachepot,以及macOS上的~/Library/Caches/Parity.cachepot

默认缓存大小为10GB。要更改此设置,请设置CACHEPOT_CACHE_SIZE,例如CACHEPOT_CACHE_SIZE="1G"

S3

如果您想为cachepot缓存使用S3存储,您需要将环境变量CACHEPOT_BUCKET设置为要使用的S3存储桶的名称。

您可以使用AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY来设置S3凭据。或者,您可以将AWS_IAM_CREDENTIALS_URL设置为一个返回受支持的凭据格式的URL(见EC2元数据服务),凭据将根据需要从该位置获取。如果没有这些选项之一,将直接从EC2元数据服务获取实例IAM角色的凭据。

如果您需要覆盖默认端点,可以设置CACHEPOT_ENDPOINT。例如,要连接到minio存储,可以将CACHEPOT_ENDPOINT=<ip>:<port>。如果您的端点需要TLS,请设置CACHEPOT_S3_USE_SSL=true

您还可以定义一个前缀,该前缀将添加到S3存储桶中创建和读取的所有缓存对象的键中,从而创建一个作用域。为此,请使用环境变量CACHEPOT_S3_KEY_PREFIX。当与另一个应用程序共享存储桶时,这可能非常有用。

Redis

CACHEPOT_REDIS设置为Redis的URL,格式为redis://[:<passwd>@]<hostname>[:port][/<db>]以在Redis实例中存储缓存。Redis可以配置为固定最大缓存大小的LRU(最近最少使用)缓存。根据Redis文档设置maxmemorymaxmemory-policy。适用于cachepot用例的allkeys-lru策略会丢弃最近最少访问或修改的键。

支持通过TLS的Redis。使用rediss:// URL方案(注意redissredis的区别)。将#insecure追加到URL中以禁用主机名验证并接受自签名证书(危险!)。请注意,这也会禁用SNI

Memcached

CACHEPOT_MEMCACHED设置为Memcached的URL,格式为tcp://<hostname>:<port> ...以在Memcached实例中存储缓存。

Google Cloud Storage

要使用Google Cloud Storage,您需要设置环境变量CACHEPOT_GCS_BUCKET为GCS存储桶的名称。如果您正在使用身份验证,可以将CACHEPOT_GCS_KEY_PATH设置为JSON服务账户凭证的位置,或将CACHEPOT_GCS_CREDENTIALS_URL设置为返回oauth令牌的URL。默认情况下,GCS上的CACHEPOT将是只读的。要更改此设置,请将CACHEPOT_GCS_RW_MODE设置为READ_ONLYREAD_WRITE

Azure

要使用Azure Blob Storage,您需要Azure连接字符串和一个现有Blob存储容器名称。将环境变量CACHEPOT_AZURE_CONNECTION_STRING设置为您的连接字符串,并将CACHEPOT_AZURE_BLOB_CONTAINER设置为要使用的容器名称。请注意,cachepot不会为您创建容器 - 您需要自行完成此操作。

重要:环境变量仅在服务器启动时考虑,即仅在第一次运行时。


覆盖缓存

在缓存包含损坏的构建工件的情况下,可能需要覆盖缓存中的内容。可以通过设置环境变量CACHEPOT_RECACHE来实现。


调试

可以将CACHEPOT_ERROR_LOG环境变量设置为路径,并将CACHEPOT_LOG设置为让服务器进程将其日志重定向到那里(包括未处理的panic的输出,因为服务器内部设置了RUST_BACKTRACE=1)。

CACHEPOT_ERROR_LOG=/tmp/cachepot_log.txt CACHEPOT_LOG=debug cachepot

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

CACHEPOT_ERROR_LOG=/tmp/cachepot_log.txt CACHEPOT_LOG=debug cmake --build /path/to/cmake/build/directory

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

CACHEPOT_LOG=debug CACHEPOT_START_SERVER=1 CACHEPOT_NO_DAEMON=1 cachepot

与GNU make作业服务器交互

cachePot支持GNU make jobserver。当服务器从一个提供jobserver的进程启动时,cachePot将使用该jobserver并将其提供给它所派生的任何进程。(如果您从GNU make配方中运行cachePot,您需要使用+作为命令的前缀来获得这种行为。)如果cachePot服务器在没有jobserver的情况下启动,它将创建自己的jobserver,其槽位数量等于可用的CPU核心数量。

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


已知问题

通用

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

Rust

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

Rust注意事项的更多细节

依赖关系

~26–45MB
~737K SLoC