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 @@ -93,7 +93,7 @@ targets = [
]

[workspace.package]
version = "2.5.24"
version = "2.5.25"
edition = "2021"
rust-version = "1.95.0"
license = "AGPL-3.0-only"
Expand Down
58 changes: 55 additions & 3 deletions crates/fbuild-build-engine/src/framework_libs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,63 @@ pub fn resolve_framework_library_sources_active_declared(
defines: &HashMap<String, String>,
declared: &[String],
) -> Vec<PathBuf> {
resolve_framework_library_selection_active_declared(
libraries,
project_dir,
src_dir,
defines,
declared,
)
.source_files
}

/// Resolve the selected framework-library records using active branches and
/// explicit declarations.
///
/// Most orchestrators only need the flattened source list. ESP32 also needs
/// the selected include roots and library names so it can retain its one-archive
/// per library layout without compiling every bundled Arduino library.
pub fn resolve_framework_library_selection_active_declared(
libraries: &[FrameworkLibrary],
project_dir: &Path,
src_dir: &Path,
defines: &HashMap<String, String>,
declared: &[String],
) -> fbuild_library_select::Selection {
resolve_framework_library_selection_active_declared_with_extra(
libraries,
project_dir,
src_dir,
defines,
declared,
&[],
&[],
)
}

/// Active framework selection with additional translation-unit seeds and
/// include roots supplied by externally declared libraries.
///
/// An external library can include a framework header from one of its own
/// `.cpp` files. The compiler sees that dependency, so the LDF must see it as
/// well or the selected framework archive is omitted from the final link.
pub fn resolve_framework_library_selection_active_declared_with_extra(
libraries: &[FrameworkLibrary],
project_dir: &Path,
src_dir: &Path,
defines: &HashMap<String, String>,
declared: &[String],
extra_source_files: &[PathBuf],
extra_include_dirs: &[PathBuf],
) -> fbuild_library_select::Selection {
let roots = framework_include_scan_roots(project_dir, src_dir);
let filtered = filter_framework_libs_shadowed_by_project(libraries, &roots);
let seeds = collect_project_seeds(&roots);
let search_paths = project_search_paths(&roots);
let mut seeds = collect_project_seeds(&roots);
seeds.extend_from_slice(extra_source_files);
let mut search_paths = project_search_paths(&roots);
for include_dir in extra_include_dirs {
push_existing_unique(&mut search_paths, include_dir.clone());
}
fbuild_library_select::resolve_with_stats_active_declared(
&seeds,
&search_paths,
Expand All @@ -73,7 +126,6 @@ pub fn resolve_framework_library_sources_active_declared(
declared,
)
.0
.source_files
}

/// Warn when a project sets `lib_ldf_mode`, which fbuild does not implement.
Expand Down
91 changes: 91 additions & 0 deletions crates/fbuild-build-engine/src/framework_libs_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -686,3 +686,94 @@ fn cached_resolution_round_trips_through_file_store() {
assert!(hit_second, "second call must hit the cache");
assert_eq!(first, second, "cache hit must yield identical sources");
}

#[test]
fn active_selection_excludes_unreached_matter_library() {
// Regression guard for #1449: ESP32's framework library compiler must be
// able to receive the selected library records, not just a flattened source
// list, so it never compiles Arduino Matter for a Blink-like sketch.
let tmp = tempfile::TempDir::new().unwrap();
let project_dir = tmp.path().join("project");
let src_dir = project_dir.join("src");
std::fs::create_dir_all(&src_dir).unwrap();
std::fs::write(src_dir.join("main.cpp"), "#include <WiFi.h>\n").unwrap();

let wifi_dir = tmp.path().join("framework").join("libraries").join("WiFi");
std::fs::create_dir_all(&wifi_dir).unwrap();
std::fs::write(wifi_dir.join("WiFi.h"), "").unwrap();
std::fs::write(wifi_dir.join("WiFi.cpp"), "int wifi;\n").unwrap();

let matter_dir = tmp
.path()
.join("framework")
.join("libraries")
.join("Matter");
std::fs::create_dir_all(&matter_dir).unwrap();
std::fs::write(matter_dir.join("Matter.h"), "").unwrap();
std::fs::write(matter_dir.join("Matter.cpp"), "int matter;\n").unwrap();

let libraries = vec![
FrameworkLibrary {
name: "Matter".to_string(),
dir: matter_dir.clone(),
include_dirs: vec![matter_dir.clone()],
source_files: vec![matter_dir.join("Matter.cpp")],
},
FrameworkLibrary {
name: "WiFi".to_string(),
dir: wifi_dir.clone(),
include_dirs: vec![wifi_dir.clone()],
source_files: vec![wifi_dir.join("WiFi.cpp")],
},
];

let selection = resolve_framework_library_selection_active_declared(
&libraries,
&project_dir,
&src_dir,
&HashMap::new(),
&[],
);

assert_eq!(selection.required_libraries, vec!["WiFi"]);
assert_eq!(selection.source_files, vec![wifi_dir.join("WiFi.cpp")]);
assert_eq!(selection.include_dirs, vec![wifi_dir]);
}

#[test]
fn external_library_source_selects_framework_dependency() {
// An external lib is compiled from its own .cpp files, so those files must
// seed ESP32's LDF pass or a <WiFi.h> dependency is omitted at link time.
let tmp = tempfile::TempDir::new().unwrap();
let project_dir = tmp.path().join("project");
let src_dir = project_dir.join("src");
std::fs::create_dir_all(&src_dir).unwrap();
std::fs::write(src_dir.join("main.cpp"), "void setup() {}\n").unwrap();

let external_dir = tmp.path().join("external").join("src");
std::fs::create_dir_all(&external_dir).unwrap();
let external_source = external_dir.join("transport.cpp");
std::fs::write(&external_source, "#include <WiFi.h>\n").unwrap();

let wifi_dir = tmp.path().join("framework").join("libraries").join("WiFi");
std::fs::create_dir_all(&wifi_dir).unwrap();
std::fs::write(wifi_dir.join("WiFi.h"), "").unwrap();
std::fs::write(wifi_dir.join("WiFi.cpp"), "int wifi;\n").unwrap();

let selection = resolve_framework_library_selection_active_declared_with_extra(
&[FrameworkLibrary {
name: "WiFi".to_string(),
dir: wifi_dir.clone(),
include_dirs: vec![wifi_dir.clone()],
source_files: vec![wifi_dir.join("WiFi.cpp")],
}],
&project_dir,
&src_dir,
&HashMap::new(),
&[],
&[external_source],
&[external_dir],
);

assert_eq!(selection.required_libraries, vec!["WiFi"]);
}
Loading
Loading