Skip to content
Closed
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
2 changes: 2 additions & 0 deletions crates/fbuild-build-arm/src/generic_arm/arm_linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ impl Linker for ArmLinker {
&self.mcu_config.objcopy.output_format,
&self.mcu_config.objcopy.remove_sections,
"arm-none-eabi-objcopy",
// Absolute toolchain path; no caller-PATH overlay needed (#1219).
None,
)
.await
}
Expand Down
2 changes: 2 additions & 0 deletions crates/fbuild-build-arm/src/nrf52/nrf52_linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ impl Linker for Nrf52Linker {
&self.mcu_config.objcopy.output_format,
&self.mcu_config.objcopy.remove_sections,
"arm-none-eabi-objcopy",
// Absolute toolchain path; no caller-PATH overlay needed (#1219).
None,
)
.await
}
Expand Down
2 changes: 2 additions & 0 deletions crates/fbuild-build-arm/src/renesas/renesas_linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ impl Linker for RenesasLinker {
&self.mcu_config.objcopy.output_format,
&self.mcu_config.objcopy.remove_sections,
"arm-none-eabi-objcopy",
// Absolute toolchain path; no caller-PATH overlay needed (#1219).
None,
)
.await
}
Expand Down
2 changes: 2 additions & 0 deletions crates/fbuild-build-arm/src/sam/sam_linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ impl Linker for SamLinker {
&self.mcu_config.objcopy.output_format,
&self.mcu_config.objcopy.remove_sections,
"arm-none-eabi-objcopy",
// Absolute toolchain path; no caller-PATH overlay needed (#1219).
None,
)
.await
}
Expand Down
2 changes: 2 additions & 0 deletions crates/fbuild-build-arm/src/silabs/silabs_linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ impl Linker for SilabsLinker {
&self.mcu_config.objcopy.output_format,
&self.mcu_config.objcopy.remove_sections,
"arm-none-eabi-objcopy",
// Absolute toolchain path; no caller-PATH overlay needed (#1219).
None,
)
.await
}
Expand Down
2 changes: 2 additions & 0 deletions crates/fbuild-build-arm/src/teensy/teensy_linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ impl Linker for TeensyLinker {
&self.mcu_config.objcopy.output_format,
&self.mcu_config.objcopy.remove_sections,
"arm-none-eabi-objcopy",
// Absolute toolchain path; no caller-PATH overlay needed (#1219).
None,
)
.await
}
Expand Down
8 changes: 8 additions & 0 deletions crates/fbuild-build-engine/src/build_fingerprint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ pub struct BinArtifactCache {
pub flash_mode: String,
pub flash_freq: String,
pub flash_size: String,
/// Fingerprint of the esptool resolution that produced firmware.bin.
/// Empty when esptool is an absolute path (the resolution cannot
/// drift); a short hash of the caller's PATH when a bare-name spawn
/// resolves against it, so two requests with different caller PATHs
/// never share a cached bin (FastLED/fbuild#1219). `serde(default)`
/// keeps pre-existing absolute-path cache records valid.
#[serde(default)]
pub esptool_fingerprint: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down
6 changes: 6 additions & 0 deletions crates/fbuild-build-engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,12 @@ pub struct BuildParams {
/// actually emitted. This unblocks per-symbol bloat analysis on
/// over-budget builds. See FastLED/fbuild#594.
pub bloat_analysis: bool,
/// Snapshot of the calling CLI's PATH, forwarded per request so
/// bare-name tool spawns (esptool, python, objcopy) resolve against
/// the caller's PATH instead of the daemon's potentially stale one.
/// `None` when no request context exists (tests, local CLI paths).
/// See FastLED/fbuild#1219.
pub caller_path: Option<String>,
}

/// Trait for platform-specific build orchestrators.
Expand Down
6 changes: 5 additions & 1 deletion crates/fbuild-build-engine/src/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,7 @@ impl LinkerBase {
output_format: &str,
remove_sections: &[String],
tool_label: &str,
caller_path: Option<&str>,
) -> Result<PathBuf> {
use fbuild_core::subprocess::run_command;

Expand All @@ -490,11 +491,14 @@ impl LinkerBase {
args.push(hex_path.to_string_lossy().to_string());

let args_ref: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
// A bare objcopy name resolves against the caller's PATH; absolute
// toolchain paths are unaffected (FastLED/fbuild#1219).
let env = fbuild_core::subprocess::bare_name_path_overlay(args_ref[0], caller_path);
// FastLED/fbuild#809: objcopy ELF→HEX/BIN bounded at 1 min.
let result = run_command(
&args_ref,
None,
None,
env.as_ref().map(|e| &e[..]),
Some(std::time::Duration::from_secs(60)),
)
.await?;
Expand Down
10 changes: 7 additions & 3 deletions crates/fbuild-build-engine/src/pipeline/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,13 @@ impl BuildContext {
let pio_overrides = fbuild_config::PioEnvOverrides::from_map(params.pio_env.clone());
let config =
fbuild_config::PlatformIOConfig::from_path_with_overrides(&ini_path, pio_overrides)?;
let overlay =
crate::script_runtime::resolve_extra_script_overlay(project_dir, env_name, &config)
.await?;
let overlay = crate::script_runtime::resolve_extra_script_overlay(
project_dir,
env_name,
&config,
params.caller_path.as_deref(),
)
.await?;
if let Some(p) = perf.as_mut() {
p.record("config-parse", t0.elapsed());
}
Expand Down
15 changes: 11 additions & 4 deletions crates/fbuild-build-engine/src/script_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub async fn resolve_extra_script_overlay(
project_dir: &Path,
env_name: &str,
config: &fbuild_config::PlatformIOConfig,
caller_path: Option<&str>,
) -> fbuild_core::Result<BuildOverlay> {
let extra_scripts = config.get_extra_scripts(env_name)?;
if extra_scripts.is_empty() {
Expand All @@ -61,7 +62,7 @@ pub async fn resolve_extra_script_overlay(
.to_string(),
};

let python = find_python().await.ok_or_else(|| {
let python = find_python(caller_path).await.ok_or_else(|| {
fbuild_core::FbuildError::BuildFailed(
"extra_scripts detected but no Python interpreter was found; \
install Python or use --platformio"
Expand Down Expand Up @@ -116,10 +117,13 @@ pub async fn resolve_extra_script_overlay(
// — config-time evaluation, never legitimately long. Bound to 60s
// so a buggy or hostile script cannot wedge the daemon's build
// pipeline indefinitely.
// The interpreter was resolved against the caller's PATH when it is a
// bare name — spawn it against the same PATH (FastLED/fbuild#1219).
let env = fbuild_core::subprocess::bare_name_path_overlay(argv[0], caller_path);
let output = fbuild_core::subprocess::run_command(
&argv,
Some(project_dir),
None,
env.as_ref().map(|e| &e[..]),
Some(std::time::Duration::from_secs(60)),
)
.await
Expand Down Expand Up @@ -298,7 +302,7 @@ fn libs_to_flags(
Ok(flags)
}

pub async fn find_python() -> Option<Vec<String>> {
pub async fn find_python(caller_path: Option<&str>) -> Option<Vec<String>> {
let candidates: &[&[&str]] = if cfg!(windows) {
&[&["python"], &["py", "-3"]]
} else {
Expand All @@ -308,12 +312,15 @@ pub async fn find_python() -> Option<Vec<String>> {
for candidate in candidates {
let mut argv: Vec<&str> = candidate.to_vec();
argv.push("--version");
// Probe against the caller's PATH so the daemon finds the same
// interpreter the CLI's environment would (FastLED/fbuild#1219).
let env = fbuild_core::subprocess::bare_name_path_overlay(candidate[0], caller_path);
// FastLED/fbuild#809: `python --version` on the startup path —
// bound tightly so a hung interpreter cannot wedge build init.
if let Ok(output) = fbuild_core::subprocess::run_command(
&argv,
None,
None,
env.as_ref().map(|e| &e[..]),
Some(std::time::Duration::from_secs(5)),
)
.await
Expand Down
34 changes: 17 additions & 17 deletions crates/fbuild-build-engine/src/script_runtime_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ extra_scripts = {}
async fn resolve_runtime_error(project_dir: &Path) -> String {
let config =
fbuild_config::PlatformIOConfig::from_path(&project_dir.join("platformio.ini")).unwrap();
resolve_extra_script_overlay(project_dir, "demo", &config)
resolve_extra_script_overlay(project_dir, "demo", &config, None)
.await
.unwrap_err()
.to_string()
Expand Down Expand Up @@ -126,7 +126,7 @@ fn test_scope_to_link_overlay_maps_libpath_and_libs() {

#[tokio::test]
async fn test_resolve_extra_script_overlay_supports_dump_shim() {
if find_python().await.is_none() {
if find_python(None).await.is_none() {
return;
}

Expand Down Expand Up @@ -159,7 +159,7 @@ env.Append(CPPDEFINES=[\"DUMP_SHIM_OK\"])
let config =
fbuild_config::PlatformIOConfig::from_path(&project_dir.join("platformio.ini")).unwrap();
// Pinned to MockEnv (see resolve_runtime_overlay note).
let overlay = resolve_extra_script_overlay(project_dir, "demo", &config)
let overlay = resolve_extra_script_overlay(project_dir, "demo", &config, None)
.await
.unwrap();
assert!(
Expand All @@ -172,7 +172,7 @@ env.Append(CPPDEFINES=[\"DUMP_SHIM_OK\"])

#[tokio::test]
async fn test_resolve_extra_script_overlay_supports_common_noop_scons_helpers() {
if find_python().await.is_none() {
if find_python(None).await.is_none() {
return;
}

Expand Down Expand Up @@ -209,7 +209,7 @@ env.Append(CPPDEFINES=[\"HELPERS_SHIM_OK\"])
let config =
fbuild_config::PlatformIOConfig::from_path(&project_dir.join("platformio.ini")).unwrap();
// Pinned to MockEnv (see resolve_runtime_overlay note).
let overlay = resolve_extra_script_overlay(project_dir, "demo", &config)
let overlay = resolve_extra_script_overlay(project_dir, "demo", &config, None)
.await
.unwrap();
assert!(
Expand All @@ -222,7 +222,7 @@ env.Append(CPPDEFINES=[\"HELPERS_SHIM_OK\"])

#[tokio::test]
async fn test_resolve_extra_script_overlay_supports_board_config_shim() {
if find_python().await.is_none() {
if find_python(None).await.is_none() {
return;
}

Expand Down Expand Up @@ -256,7 +256,7 @@ env.Append(CPPDEFINES=[\"BOARD_CONFIG_SHIM_OK\"])
let config =
fbuild_config::PlatformIOConfig::from_path(&project_dir.join("platformio.ini")).unwrap();
// Pinned to MockEnv (see resolve_runtime_overlay note).
let overlay = resolve_extra_script_overlay(project_dir, "demo", &config)
let overlay = resolve_extra_script_overlay(project_dir, "demo", &config, None)
.await
.unwrap();
assert!(
Expand All @@ -269,7 +269,7 @@ env.Append(CPPDEFINES=[\"BOARD_CONFIG_SHIM_OK\"])

#[tokio::test]
async fn test_resolve_extra_script_overlay_supports_pio_platform_shim() {
if find_python().await.is_none() {
if find_python(None).await.is_none() {
return;
}

Expand Down Expand Up @@ -306,7 +306,7 @@ env.Append(CPPDEFINES=[\"PIO_PLATFORM_SHIM_OK\"])
let config =
fbuild_config::PlatformIOConfig::from_path(&project_dir.join("platformio.ini")).unwrap();
// Pinned to MockEnv (see resolve_runtime_overlay note).
let overlay = resolve_extra_script_overlay(project_dir, "demo", &config)
let overlay = resolve_extra_script_overlay(project_dir, "demo", &config, None)
.await
.unwrap();
assert!(
Expand All @@ -319,7 +319,7 @@ env.Append(CPPDEFINES=[\"PIO_PLATFORM_SHIM_OK\"])

#[tokio::test]
async fn test_resolve_extra_script_overlay_rejects_unsupported_script_prefix() {
if find_python().await.is_none() {
if find_python(None).await.is_none() {
return;
}

Expand All @@ -344,7 +344,7 @@ Import(\"env\")
/// corrupt the harness's JSON-on-stdout protocol.
#[tokio::test]
async fn test_resolve_extra_script_overlay_tolerates_user_stdout_noise() {
if find_python().await.is_none() {
if find_python(None).await.is_none() {
return;
}

Expand All @@ -363,7 +363,7 @@ print(\"post-append noise\")
);
let config =
fbuild_config::PlatformIOConfig::from_path(&temp.path().join("platformio.ini")).unwrap();
let overlay = resolve_extra_script_overlay(temp.path(), "demo", &config)
let overlay = resolve_extra_script_overlay(temp.path(), "demo", &config, None)
.await
.unwrap();
assert!(
Expand Down Expand Up @@ -416,7 +416,7 @@ framework = arduino
async fn resolve_runtime_overlay(project_dir: &Path) -> BuildOverlay {
let config =
fbuild_config::PlatformIOConfig::from_path(&project_dir.join("platformio.ini")).unwrap();
resolve_extra_script_overlay(project_dir, "demo", &config)
resolve_extra_script_overlay(project_dir, "demo", &config, None)
.await
.unwrap()
}
Expand All @@ -428,7 +428,7 @@ async fn resolve_runtime_overlay(project_dir: &Path) -> BuildOverlay {
/// `AddPostAction`. Source: MarlinFirmware/Marlin buildroot scripts.
#[tokio::test]
async fn test_shim_simple_marlin_cxxflags_style() {
if find_python().await.is_none() {
if find_python(None).await.is_none() {
return;
}

Expand Down Expand Up @@ -477,7 +477,7 @@ env.AddPostAction(\"$PROGPATH\", lambda *a, **k: None)
/// emit `-Dkey=value`, not a malformed array entry.
#[tokio::test]
async fn test_shim_simple_inplace_tuple_cppdefine() {
if find_python().await.is_none() {
if find_python(None).await.is_none() {
return;
}

Expand Down Expand Up @@ -516,7 +516,7 @@ env.Append(CPPDEFINES=[\"PLAIN\"])
/// `LINKFLAGS`, and registers a no-op post action.
#[tokio::test]
async fn test_shim_medium_default_environment_linkflags() {
if find_python().await.is_none() {
if find_python(None).await.is_none() {
return;
}

Expand Down Expand Up @@ -554,7 +554,7 @@ env.AddPostAction(\"$BUILD_DIR/firmware.bin\", after_build)
/// script must not hard-fail and the parallel flag mutation must land.
#[tokio::test]
async fn test_shim_medium_nonflag_scope_does_not_reject() {
if find_python().await.is_none() {
if find_python(None).await.is_none() {
return;
}

Expand Down
Loading
Loading