Skip to content

Commit adfb68d

Browse files
committed
fix: Normalize relative paths to canonical form for CMake compatibility
CMake and some build tools prefer canonical relative paths like '../dir/file' over equivalent but non-canonical forms like 'dir/../file'. The pathdiff crate can generate non-canonical paths when calculating relative paths between directories. This commit adds lexical path normalization by processing path components: when we encounter a ParentDir (..) component, we pop the previous component instead of keeping both. Example transformation: - Before: cpp/../generated/file.cpp - After: ../cpp/generated/file.cpp This ensures better compatibility with CMake and other build tools that may not handle non-canonical paths correctly. Discovered while testing the RustBuffer 32-bit ARM fix on Android.
1 parent 2bfdedd commit adfb68d

File tree

1 file changed

+30
-1
lines changed
  • crates/ubrn_cli/src/codegen

1 file changed

+30
-1
lines changed

crates/ubrn_cli/src/codegen/mod.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,36 @@ pub(crate) trait RenderedFile: DynTemplate {
2626
let from = file
2727
.parent()
2828
.expect("Expected this file to have a directory");
29-
pathdiff::diff_utf8_paths(to, from).expect("Should be able to find a relative path")
29+
let path = pathdiff::diff_utf8_paths(to, from).expect("Should be able to find a relative path");
30+
31+
// Normalize paths for better compatibility with tools like CMake.
32+
// pathdiff can generate "dir/.." patterns which, while technically correct,
33+
// are not canonical. Normalize by resolving against a dummy base and taking the relative path.
34+
// Example: "cpp/../generated/file.cpp" becomes "../cpp/generated/file.cpp"
35+
use camino::Utf8Component;
36+
let mut normalized = Utf8PathBuf::new();
37+
38+
for component in path.components() {
39+
match component {
40+
Utf8Component::Normal(name) => {
41+
normalized.push(name);
42+
}
43+
Utf8Component::ParentDir => {
44+
if !normalized.pop() {
45+
// If we can't pop, we need to keep the ..
46+
normalized.push("..");
47+
}
48+
}
49+
comp => normalized.push(comp),
50+
}
51+
}
52+
53+
// If normalized is empty, it means we're in the same directory
54+
if normalized.as_str().is_empty() {
55+
normalized.push(".");
56+
}
57+
58+
normalized
3059
}
3160
fn filter_by(&self) -> bool {
3261
true

0 commit comments

Comments
 (0)