mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
build(ENG-21330): Replace ccache with sccache (#24200)
This commit is contained in:
@@ -120,18 +120,18 @@ function Refresh-Path {
|
||||
function Add-To-Path {
|
||||
$absolutePath = Resolve-Path $args[0]
|
||||
$currentPath = [Environment]::GetEnvironmentVariable("Path", "Machine")
|
||||
if ($currentPath -like "*$absolutePath*") {
|
||||
if ($currentPath -like "*$absolutePath*") {
|
||||
return
|
||||
}
|
||||
|
||||
$newPath = $currentPath.TrimEnd(";") + ";" + $absolutePath
|
||||
if ($newPath.Length -ge 2048) {
|
||||
Write-Warning "PATH is too long, removing duplicate and old entries..."
|
||||
|
||||
$paths = $currentPath.Split(';', [StringSplitOptions]::RemoveEmptyEntries) |
|
||||
|
||||
$paths = $currentPath.Split(';', [StringSplitOptions]::RemoveEmptyEntries) |
|
||||
Where-Object { $_ -and (Test-Path $_) } |
|
||||
Select-Object -Unique
|
||||
|
||||
|
||||
$paths += $absolutePath
|
||||
$newPath = $paths -join ';'
|
||||
while ($newPath.Length -ge 2048 -and $paths.Count -gt 1) {
|
||||
@@ -274,7 +274,6 @@ function Install-Build-Essentials {
|
||||
cmake `
|
||||
make `
|
||||
ninja `
|
||||
ccache `
|
||||
python `
|
||||
golang `
|
||||
nasm `
|
||||
@@ -282,6 +281,7 @@ function Install-Build-Essentials {
|
||||
strawberryperl `
|
||||
mingw
|
||||
Install-Rust
|
||||
Install-Sccache
|
||||
# Needed to remap stack traces
|
||||
Install-PdbAddr2line
|
||||
Install-Llvm
|
||||
@@ -344,6 +344,10 @@ function Install-Rust {
|
||||
Add-To-Path "$rustPath\cargo\bin"
|
||||
}
|
||||
|
||||
function Install-Sccache {
|
||||
Install-Package sccache -Version "0.12.0"
|
||||
}
|
||||
|
||||
function Install-PdbAddr2line {
|
||||
Execute-Command cargo install --examples "pdb-addr2line@0.11.2"
|
||||
}
|
||||
|
||||
@@ -26,8 +26,11 @@ error() {
|
||||
}
|
||||
|
||||
execute() {
|
||||
print "$ $@" >&2
|
||||
if ! "$@"; then
|
||||
local opts=$-
|
||||
set -x
|
||||
"$@"
|
||||
{ local status=$?; set +x "$opts"; } 2> /dev/null
|
||||
if [ "$status" -ne 0 ]; then
|
||||
error "Command failed: $@"
|
||||
fi
|
||||
}
|
||||
@@ -1035,7 +1038,7 @@ install_build_essentials() {
|
||||
install_llvm
|
||||
install_osxcross
|
||||
install_gcc
|
||||
install_ccache
|
||||
install_sccache
|
||||
install_rust
|
||||
install_docker
|
||||
}
|
||||
@@ -1146,12 +1149,31 @@ install_gcc() {
|
||||
execute_sudo ln -sf $(which llvm-symbolizer-$llvm_v) /usr/bin/llvm-symbolizer
|
||||
}
|
||||
|
||||
install_ccache() {
|
||||
case "$pm" in
|
||||
apt | apk | brew)
|
||||
install_packages ccache
|
||||
;;
|
||||
esac
|
||||
install_sccache() {
|
||||
# Alright, look, this function is cobbled together but it's only as cobbled
|
||||
# together as this whole script is.
|
||||
#
|
||||
# For some reason, move_to_bin doesn't work here due to permissions so I'm
|
||||
# avoiding that function. It's also wrong with permissions and so on.
|
||||
#
|
||||
# Unfortunately, we cannot use install_packages since many package managers
|
||||
# don't compile `sccache` with S3 support.
|
||||
local opts=$-
|
||||
set -ef
|
||||
|
||||
local sccache_http
|
||||
sccache_http="https://github.com/mozilla/sccache/releases/download/v0.12.0/sccache-v0.12.0-$(uname -m)-unknown-linux-musl.tar.gz"
|
||||
|
||||
local file
|
||||
file=$(download_file "$sccache_http")
|
||||
|
||||
local tmpdir
|
||||
tmpdir=$(mktemp -d)
|
||||
|
||||
execute tar -xzf "$file" -C "$tmpdir"
|
||||
execute_sudo install -m755 "$tmpdir/sccache-v0.12.0-$(uname -m)-unknown-linux-musl/sccache" "/usr/local/bin"
|
||||
|
||||
set +ef -"$opts"
|
||||
}
|
||||
|
||||
install_rust() {
|
||||
@@ -1402,10 +1424,10 @@ install_chromium() {
|
||||
apk)
|
||||
install_packages \
|
||||
chromium \
|
||||
nss \
|
||||
freetype \
|
||||
harfbuzz \
|
||||
ttf-freefont
|
||||
nss \
|
||||
freetype \
|
||||
harfbuzz \
|
||||
ttf-freefont
|
||||
;;
|
||||
apt)
|
||||
install_packages \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { spawn as nodeSpawn } from "node:child_process";
|
||||
import { chmodSync, cpSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { basename, join, relative, resolve } from "node:path";
|
||||
import {
|
||||
formatAnnotationToHtml,
|
||||
@@ -70,43 +70,8 @@ async function build(args) {
|
||||
generateOptions["-S"] = process.cwd();
|
||||
}
|
||||
|
||||
const cacheRead = isCacheReadEnabled();
|
||||
const cacheWrite = isCacheWriteEnabled();
|
||||
if (cacheRead || cacheWrite) {
|
||||
const cachePath = getCachePath();
|
||||
if (cacheRead && !existsSync(cachePath)) {
|
||||
const mainCachePath = getCachePath(getDefaultBranch());
|
||||
if (existsSync(mainCachePath)) {
|
||||
mkdirSync(cachePath, { recursive: true });
|
||||
try {
|
||||
cpSync(mainCachePath, cachePath, { recursive: true, force: true });
|
||||
} catch (error) {
|
||||
const { code } = error;
|
||||
switch (code) {
|
||||
case "EPERM":
|
||||
case "EACCES":
|
||||
try {
|
||||
chmodSync(mainCachePath, 0o777);
|
||||
cpSync(mainCachePath, cachePath, { recursive: true, force: true });
|
||||
} catch (error) {
|
||||
console.warn("Failed to copy cache with permissions fix", error);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.warn("Failed to copy cache", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
generateOptions["-DCACHE_PATH"] = cmakePath(cachePath);
|
||||
generateOptions["--fresh"] = undefined;
|
||||
if (cacheRead && cacheWrite) {
|
||||
generateOptions["-DCACHE_STRATEGY"] = "read-write";
|
||||
} else if (cacheRead) {
|
||||
generateOptions["-DCACHE_STRATEGY"] = "read-only";
|
||||
} else if (cacheWrite) {
|
||||
generateOptions["-DCACHE_STRATEGY"] = "write-only";
|
||||
}
|
||||
if (!generateOptions["-DCACHE_STRATEGY"]) {
|
||||
generateOptions["-DCACHE_STRATEGY"] = "read-write";
|
||||
}
|
||||
|
||||
const toolchain = generateOptions["--toolchain"];
|
||||
@@ -136,58 +101,17 @@ async function build(args) {
|
||||
|
||||
await startGroup("CMake Build", () => spawn("cmake", buildArgs, { env }));
|
||||
|
||||
await startGroup("sccache stats", () => {
|
||||
spawn("sccache", ["--show-stats"], { env });
|
||||
});
|
||||
|
||||
printDuration("total", Date.now() - startTime);
|
||||
}
|
||||
|
||||
function cmakePath(path) {
|
||||
return path.replace(/\\/g, "/");
|
||||
}
|
||||
|
||||
/** @param {string} str */
|
||||
const toAlphaNumeric = str => str.replace(/[^a-z0-9]/gi, "-");
|
||||
function getCachePath(branch) {
|
||||
const {
|
||||
BUILDKITE_BUILD_PATH: buildPath,
|
||||
BUILDKITE_REPO: repository,
|
||||
BUILDKITE_PULL_REQUEST_REPO: fork,
|
||||
BUILDKITE_BRANCH,
|
||||
BUILDKITE_STEP_KEY,
|
||||
} = process.env;
|
||||
|
||||
// NOTE: settings that could be long should be truncated to avoid hitting max
|
||||
// path length limit on windows (4096)
|
||||
const repositoryKey = toAlphaNumeric(
|
||||
// remove domain name, only leaving 'org/repo'
|
||||
(fork || repository).replace(/^https?:\/\/github\.com\/?/, ""),
|
||||
);
|
||||
const branchName = toAlphaNumeric(branch || BUILDKITE_BRANCH);
|
||||
const branchKey = branchName.startsWith("gh-readonly-queue-")
|
||||
? branchName.slice(18, branchName.indexOf("-pr-"))
|
||||
: branchName.slice(0, 32);
|
||||
const stepKey = toAlphaNumeric(BUILDKITE_STEP_KEY);
|
||||
return resolve(buildPath, "..", "cache", repositoryKey, branchKey, stepKey);
|
||||
}
|
||||
|
||||
function isCacheReadEnabled() {
|
||||
return (
|
||||
isBuildkite() &&
|
||||
process.env.BUILDKITE_CLEAN_CHECKOUT !== "true" &&
|
||||
process.env.BUILDKITE_BRANCH !== getDefaultBranch()
|
||||
);
|
||||
}
|
||||
|
||||
function isCacheWriteEnabled() {
|
||||
return isBuildkite();
|
||||
}
|
||||
|
||||
function isBuildkite() {
|
||||
return process.env.BUILDKITE === "true";
|
||||
}
|
||||
|
||||
function getDefaultBranch() {
|
||||
return process.env.BUILDKITE_PIPELINE_DEFAULT_BRANCH || "main";
|
||||
}
|
||||
|
||||
function parseOptions(args, flags = []) {
|
||||
const options = {};
|
||||
|
||||
|
||||
@@ -485,6 +485,12 @@ const aws = {
|
||||
});
|
||||
}
|
||||
|
||||
// Attach IAM instance profile for CI builds to enable S3 build cache access
|
||||
let iamInstanceProfile;
|
||||
if (options.ci) {
|
||||
iamInstanceProfile = JSON.stringify({ Name: "buildkite-build-agent" });
|
||||
}
|
||||
|
||||
const [instance] = await aws.runInstances({
|
||||
["image-id"]: ImageId,
|
||||
["instance-type"]: instanceType || (arch === "aarch64" ? "t4g.large" : "t3.large"),
|
||||
@@ -499,6 +505,7 @@ const aws = {
|
||||
["tag-specifications"]: JSON.stringify(tagSpecification),
|
||||
["key-name"]: keyName,
|
||||
["instance-market-options"]: marketOptions,
|
||||
["iam-instance-profile"]: iamInstanceProfile,
|
||||
});
|
||||
|
||||
const machine = aws.toMachine(instance, { ...options, username, keyPath });
|
||||
@@ -1191,6 +1198,9 @@ async function main() {
|
||||
const tags = {
|
||||
"robobun": "true",
|
||||
"robobun2": "true",
|
||||
// This tag controls the IAM role required to be able to write to the shared S3 build cache.
|
||||
// Don't want accidental polution from non-CI runs.
|
||||
"Service": args["ci"] ? "buildkite-agent" : undefined,
|
||||
"buildkite:token": args["buildkite-token"],
|
||||
"tailscale:authkey": args["tailscale-authkey"],
|
||||
...Object.fromEntries(args["tag"]?.map(tag => tag.split("=")) ?? []),
|
||||
|
||||
Reference in New Issue
Block a user