Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 21 additions & 21 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ exclude = [
libraries = [{ path = "dylints/*" }]

[workspace.package]
version = "2.5.6"
version = "2.5.7"
edition = "2021"
rust-version = "1.94.1"
license = "MIT OR Apache-2.0"
Expand Down
8 changes: 3 additions & 5 deletions crates/fbuild-build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,9 @@ tree-sitter-cpp = { workspace = true }
# child processes) was deleted in the same PR; there is no
# `--no-default-features` escape hatch.
#
# Pinned at zccache 1.12.17 (`5ee292f`, upstream main). soldr's
# `_vender/zccache` submodule currently sits 3 commits behind this at
# `4180af8`; both revs speak the same shared-broker protocol, so the two
# embedded services still interoperate. Re-check that submodule when
# repinning — a protocol-affecting zccache change must land in both.
# Pinned at zccache 1.13.1 (`8cf6dd0`, release tag), which pins
# running-process 4.8.1 at `359b4e3`. Keep both revisions aligned when
# repinning so fbuild links exactly one copy of the exported broker symbols.
#
# `running-process` in the workspace root must be pinned to the SAME git rev
# zccache uses, or its unmangled `rp_*_public` C symbols get linked twice.
Expand Down
114 changes: 114 additions & 0 deletions crates/fbuild-build/tests/zccache_embedded_smoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,45 @@
//! with it).

use fbuild_build::zccache_embedded::FbuildZccacheService;
use fbuild_core::path::NormalizedPath;
use zccache::embedded::ShutdownMode;
Comment thread
coderabbitai[bot] marked this conversation as resolved.

fn find_c_compiler() -> NormalizedPath {
let path_dirs: Vec<_> =
std::env::split_paths(&std::env::var_os("PATH").expect("PATH should be set")).collect();
let on_path = |name: &str| {
path_dirs
.iter()
.map(|dir| dir.join(name))
.find(|candidate| candidate.is_file())
.map(NormalizedPath::from)
};
if cfg!(windows) {
if let Some(candidate) = on_path("clang.exe") {
return candidate;
}
if let Some(program_files) = std::env::var_os("ProgramFiles") {
let candidate = NormalizedPath::new(std::path::Path::new(&program_files))
.join("LLVM")
.join("bin")
.join("clang.exe");
if candidate.is_file() {
return candidate;
}
}
if let Some(candidate) = on_path("gcc.exe") {
return candidate;
}
panic!("clang.exe or gcc.exe must be installed for this smoke test");
}
for name in ["cc", "clang", "gcc"] {
if let Some(candidate) = on_path(name) {
return candidate;
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
panic!("cc, clang, or gcc must be installed for this smoke test");
}

/// `FbuildZccacheService::start_in` produces a working service
/// handle: the cache root exists on disk, the identity carries our
/// product tag, and a graceful shutdown returns cleanly.
Expand Down Expand Up @@ -42,3 +79,80 @@ async fn embedded_service_starts_and_shuts_down() {
.await
.expect("graceful shutdown should succeed");
}

/// A real compile traverses fbuild's embedded zccache boundary twice: the
/// first invocation populates a fresh cache and the second must materialize
/// the object from that cache. This is also a link-time guard against loading
/// two copies of running-process's unmangled `rp_*_public` exports.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn embedded_compilation_cold_miss_then_warm_hit() {
let tmp = tempfile::TempDir::new().expect("tempdir");
let cache_root = tmp.path().join("zccache");
let source = tmp.path().join("smoke.c");
let object = tmp.path().join(if cfg!(windows) {
"smoke.obj"
} else {
"smoke.o"
});
std::fs::write(&source, "int smoke(void) { return 42; }\n").expect("write source");

let svc = FbuildZccacheService::start_in(cache_root)
.await
.expect("embedded service should start");
let compiler = find_c_compiler();
let args = vec![
"-c".to_string(),
source.to_string_lossy().into_owned(),
"-o".to_string(),
object.to_string_lossy().into_owned(),
];
let mut compile_env = fbuild_core::subprocess::compile_env_for_build(tmp.path())
.expect("prepare the same hermetic compile environment used in production");
compile_env.push((
"ZCCACHE_WORKTREE_ROOT".to_string(),
tmp.path().to_string_lossy().into_owned(),
));

let cold = svc
.compile(
&compiler,
args.clone(),
tmp.path().to_path_buf(),
compile_env.clone(),
)
.await
.expect("cold embedded compile should succeed");
assert_eq!(
cold.exit_code,
0,
"cold compile stderr: {}",
String::from_utf8_lossy(&cold.stderr)
);
assert!(!cold.cached, "fresh cache unexpectedly reported a hit");
assert!(object.is_file(), "cold compile should create an object");

svc.flush()
.await
.expect("flush cold compile into the cache");
std::fs::remove_file(&object).expect("remove cold object before warm materialization");

let warm = svc
.compile(&compiler, args, tmp.path().to_path_buf(), compile_env)
.await
.expect("warm embedded compile should succeed");
assert_eq!(
warm.exit_code,
0,
"warm compile stderr: {}",
String::from_utf8_lossy(&warm.stderr)
);
assert!(
warm.cached,
"second identical compile should be a cache hit"
);
assert!(object.is_file(), "warm hit should materialize the object");

svc.shutdown(ShutdownMode::Graceful)
.await
.expect("graceful shutdown should succeed");
}
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "fbuild"
version = "2.5.6"
version = "2.5.7"
description = "PlatformIO-compatible embedded build tool (Rust implementation)"
readme = "README.md"
requires-python = ">=3.10"
Expand Down
Loading