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.11"
version = "2.5.12"
edition = "2021"
rust-version = "1.94.1"
license = "MIT OR Apache-2.0"
Expand Down
1 change: 1 addition & 0 deletions crates/fbuild-build-esp/src/esp32/orchestrator/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ impl BuildOrchestrator for Esp32Orchestrator {
&c_flags,
&cpp_flags,
&include_dirs,
&params.project_dir,
&libs_dir,
params.verbose,
jobs,
Expand Down
2 changes: 1 addition & 1 deletion crates/fbuild-library/src/library/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Arduino library and framework dependency management: spec parsing, download, com
## Modules

- **`mod.rs`** -- Module root; re-exports framework types and `LibrarySpec`
- **`library_spec.rs`** -- Parser for `lib_deps` formats (`owner/Name@^version`, GitHub URLs, bare names)
- **`library_spec.rs`** -- Parser for `lib_deps` formats (`owner/Name@^version`, GitHub URLs, bare names, and named `symlink://`/`file://` local dependencies)
- **`library_downloader.rs`** -- Downloads libraries from GitHub URLs or the PlatformIO registry
- **`library_info.rs`** -- Scans installed libraries for include directories and source files
- **`library_compiler.rs`** -- Compiles library C/C++ sources and archives into static `.a` files
Expand Down
28 changes: 27 additions & 1 deletion crates/fbuild-library/src/library/library_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,26 @@ pub struct InstalledLibrary {
pub lib_dir: PathBuf,
/// Library name.
pub name: String,
/// Directory for generated objects and archives. Local dependencies keep
/// this separate from their source checkout.
pub build_dir: PathBuf,
}

impl InstalledLibrary {
pub fn new(lib_dir: &Path, name: &str) -> Self {
Self {
lib_dir: lib_dir.to_path_buf(),
name: name.to_string(),
build_dir: lib_dir.to_path_buf(),
}
}

/// Construct a library whose generated artifacts belong in `build_dir`.
pub fn with_build_dir(lib_dir: &Path, name: &str, build_dir: &Path) -> Self {
Self {
lib_dir: lib_dir.to_path_buf(),
name: name.to_string(),
build_dir: build_dir.to_path_buf(),
}
}

Expand Down Expand Up @@ -88,7 +101,7 @@ impl InstalledLibrary {

/// Get the archive output path for this library.
pub fn archive_path(&self) -> PathBuf {
self.lib_dir.join(format!("lib{}.a", self.name))
self.build_dir.join(format!("lib{}.a", self.name))
}
}

Expand Down Expand Up @@ -251,6 +264,19 @@ mod tests {
);
}

#[test]
fn test_archive_path_uses_external_build_dir() {
let lib = InstalledLibrary::with_build_dir(
Path::new("/source/fastled"),
"fastled",
Path::new("/build/libs/fastled"),
);
assert_eq!(
lib.archive_path(),
PathBuf::from("/build/libs/fastled/libfastled.a")
);
}

#[test]
fn test_no_src_dir() {
let tmp = tempfile::TempDir::new().unwrap();
Expand Down
48 changes: 42 additions & 6 deletions crates/fbuild-library/src/library/library_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub async fn ensure_libraries(
c_flags: &[String],
cpp_flags: &[String],
base_includes: &[PathBuf],
project_dir: &Path,
libs_dir: &Path,
verbose: bool,
jobs: usize,
Expand All @@ -83,7 +84,9 @@ pub async fn ensure_libraries(

tracing::info!("resolving {} library dependencies", specs.len());

// 2. Download all libraries in parallel
// 2. Resolve named local libraries and download remote libraries in parallel.
// Local libraries compile into `libs_dir`, never their checked-out source
// directory, so a build cannot leave generated artifacts in a dependency.
std::fs::create_dir_all(libs_dir)?;
let mut installed: Vec<InstalledLibrary> = Vec::new();
let mut downloaded_names: std::collections::HashSet<String> = std::collections::HashSet::new();
Expand All @@ -93,6 +96,28 @@ pub async fn ensure_libraries(
std::result::Result<(std::path::PathBuf, String, String), fbuild_core::FbuildError>,
> = tokio::task::JoinSet::new();
for spec in &specs {
if let Some(local_path) = &spec.local_path {
let lib_dir = if local_path.is_absolute() {
local_path.clone()
} else {
project_dir.join(local_path)
};
if !lib_dir.is_dir() {
return Err(FbuildError::PackageError(format!(
"local library '{}' does not exist or is not a directory: {}",
spec.name,
lib_dir.display()
)));
}
let sanitized = spec.sanitized_name();
installed.push(InstalledLibrary::with_build_dir(
&lib_dir,
&sanitized,
&libs_dir.join(&sanitized),
));
downloaded_names.insert(spec.name.to_lowercase());
continue;
}
let spec_clone = spec.clone();
let dir = libs_dir_owned.clone();
tasks.spawn(async move {
Expand Down Expand Up @@ -150,7 +175,7 @@ pub async fn ensure_libraries(
ar_path,
c_flags,
cpp_flags,
&lib.lib_dir,
&lib.build_dir,
verbose,
jobs,
compiler_cache,
Expand Down Expand Up @@ -311,6 +336,7 @@ pub fn ensure_libraries_sync(
c_flags: &[String],
cpp_flags: &[String],
base_includes: &[PathBuf],
project_dir: &Path,
libs_dir: &Path,
verbose: bool,
jobs: usize,
Expand All @@ -325,6 +351,7 @@ pub fn ensure_libraries_sync(
c_flags,
cpp_flags,
base_includes,
project_dir,
libs_dir,
verbose,
jobs,
Expand Down Expand Up @@ -352,6 +379,7 @@ mod tests {
&[],
&[],
&[],
Path::new("/project"),
Path::new("/libs"),
false,
1,
Expand All @@ -373,6 +401,7 @@ mod tests {
&[],
&[],
&[],
Path::new("/project"),
Path::new("/libs"),
false,
1,
Expand All @@ -384,22 +413,29 @@ mod tests {
}

#[test]
fn test_local_path_specs_skipped() {
fn test_named_local_symlink_adds_include_dir() {
let tmp = tempfile::TempDir::new().unwrap();
let local = tmp.path().join("local");
let local_src = local.join("src");
std::fs::create_dir_all(&local_src).unwrap();
std::fs::write(local_src.join("Local.h"), "").unwrap();
let libs_dir = tmp.path().join("build").join("libs");
let result = ensure_libraries_sync(
&["symlink://./local".to_string()],
&[format!("Local=symlink://{}", local.display())],
&[],
Path::new("/gcc"),
Path::new("/g++"),
Path::new("/ar"),
&[],
&[],
&[],
Path::new("/libs"),
tmp.path(),
&libs_dir,
false,
1,
None,
)
.unwrap();
assert!(result.include_dirs.is_empty());
assert_eq!(result.include_dirs, vec![local_src]);
}
}
Loading
Loading