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
2 changes: 1 addition & 1 deletion crates/fbuild-build/src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Build orchestration for all supported embedded platforms.
- **`linker.rs`** -- `Linker` trait and `LinkerBase` shared logic (ar, objcopy, size reporting)
- **`parallel.rs`** -- Multi-threaded source compilation using `std::thread::scope` with work-stealing
- **`pipeline.rs`** -- Shared build pipeline (config parse, board load, build dir setup, compile, link)
- **`source_scanner.rs`** -- Finds .cpp/.c/.S/.ino files; preprocesses .ino into valid .cpp
- **`source_scanner.rs`** -- Finds .cpp/.cc/.cxx/.c/.S/.ino files; preprocesses .ino into valid .cpp
- **`compile_database.rs`** -- Generates `compile_commands.json` for clangd/IDE support
- **`build_output.rs`** -- Uniform build log formatting across all platforms
- **`zccache.rs`** -- Optional zccache compiler cache wrapper integration
Expand Down
39 changes: 32 additions & 7 deletions crates/fbuild-build/src/source_scanner.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Source file scanning and .ino preprocessing.
//!
//! Finds .cpp, .c, .S, .ino files in project source directories.
//! Finds .cpp, .cc, .cxx, .c, .S, .ino files in project source directories.
//! Preprocesses .ino files into valid .cpp with function prototypes and an
//! Arduino.h include when the active include roots provide that header.

Expand All @@ -16,7 +16,7 @@ use walkdir::WalkDir;
/// Collection of source files found by the scanner.
#[derive(Debug, Default)]
pub struct SourceCollection {
/// User sketch sources (.cpp, .c, .S — and preprocessed .ino)
/// User sketch sources (.cpp/.cc/.cxx, .c, .S — and preprocessed .ino)
pub sketch_sources: Vec<PathBuf>,
/// Arduino core sources
pub core_sources: Vec<PathBuf>,
Expand Down Expand Up @@ -85,7 +85,7 @@ impl SourceScanner {

/// Scan the project source directory for sketch files.
///
/// Returns preprocessed .ino files as .cpp, plus existing .cpp/.c/.S files.
/// Returns preprocessed .ino files as .cpp, plus existing .cpp/.cc/.cxx/.c/.S files.
///
/// When a `main.cpp` already `#include`s `.ino` files (PlatformIO convention),
/// the `.ino` files are NOT preprocessed separately to avoid duplicate symbols.
Expand Down Expand Up @@ -128,7 +128,7 @@ impl SourceScanner {
.to_lowercase();
match ext.as_str() {
"ino" => ino_files.push(entry),
"cpp" | "c" | "s" | "cc" => {
"cpp" | "c" | "s" | "cc" | "cxx" => {
if entry.file_name().is_some_and(|n| n == "main.cpp") {
main_cpp_path = Some(entry.clone());
}
Expand Down Expand Up @@ -167,7 +167,7 @@ impl SourceScanner {
.unwrap_or_default()
.to_string_lossy()
.to_lowercase();
matches!(ext.as_str(), "cpp" | "c" | "s" | "cc")
matches!(ext.as_str(), "cpp" | "c" | "s" | "cc" | "cxx")
})
.collect()
}
Expand All @@ -185,7 +185,7 @@ impl SourceScanner {
.unwrap_or_default()
.to_string_lossy()
.to_lowercase();
matches!(ext.as_str(), "cpp" | "c" | "s" | "cc")
matches!(ext.as_str(), "cpp" | "c" | "s" | "cc" | "cxx")
})
.collect()
}
Expand Down Expand Up @@ -961,6 +961,15 @@ mod tests {
assert!(sources[0].to_string_lossy().contains("main.cpp"));
}

#[test]
fn test_scan_cxx_files() {
let (_tmp, src_dir, build_dir) = setup_project(&[("helper.cxx", "void helper() {}")]);
let scanner = SourceScanner::new(&src_dir, &build_dir);
let sources = scanner.scan_sketch_sources().unwrap();
assert_eq!(sources.len(), 1);
assert!(sources[0].to_string_lossy().contains("helper.cxx"));
}

#[test]
fn test_scan_c_files() {
let (_tmp, src_dir, build_dir) = setup_project(&[("helper.c", "void helper() {}")]);
Expand Down Expand Up @@ -1154,11 +1163,13 @@ mod tests {
fs::create_dir_all(&core_dir).unwrap();
fs::write(core_dir.join("main.cpp"), "int main() {}").unwrap();
fs::write(core_dir.join("wiring.c"), "void init() {}").unwrap();
fs::write(core_dir.join("helper.cxx"), "void helper() {}").unwrap();
fs::write(core_dir.join("Arduino.h"), "#pragma once").unwrap();

let scanner = SourceScanner::new(&tmp.path().join("src"), &tmp.path().join("build"));
let sources = scanner.scan_core_sources(&core_dir);
assert_eq!(sources.len(), 2); // .cpp and .c, not .h
assert_eq!(sources.len(), 3); // .cpp, .c, and .cxx, not .h
assert!(sources.iter().any(|p| p.ends_with("helper.cxx")));
}

#[test]
Expand All @@ -1169,6 +1180,20 @@ mod tests {
assert!(sources.is_empty());
}

#[test]
fn test_scan_variant_cxx_sources() {
let tmp = TempDir::new().unwrap();
let variant_dir = tmp.path().join("variants/demo");
fs::create_dir_all(&variant_dir).unwrap();
fs::write(variant_dir.join("variant.cxx"), "void variant() {}").unwrap();
fs::write(variant_dir.join("variant.h"), "#pragma once").unwrap();

let scanner = SourceScanner::new(&tmp.path().join("src"), &tmp.path().join("build"));
let sources = scanner.scan_variant_sources(&variant_dir);

assert_eq!(sources, vec![variant_dir.join("variant.cxx")]);
}

#[test]
fn test_preprocess_simple_ino() {
let (_tmp, src_dir, build_dir) = setup_project(&[(
Expand Down
Loading