Skip to content

Commit 668da9d

Browse files
committed
refactor(rs_port): init translating search functionality
1 parent 1001fcd commit 668da9d

File tree

1 file changed

+183
-22
lines changed

1 file changed

+183
-22
lines changed

source/ports/rs_port/build.rs

Lines changed: 183 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,199 @@
1-
use std::env;
1+
use std::{
2+
env, fs,
3+
path::{Path, PathBuf},
4+
vec,
5+
};
6+
7+
// Search for MetaCall libraries in platform-specific locations
8+
// Handle custom installation paths via environment variables
9+
// Find configuration files recursively
10+
// Provide helpful error messages when things aren't found
11+
12+
/// Represents the install paths for a platform
13+
struct InstallPath {
14+
paths: Vec<PathBuf>,
15+
name: String,
16+
}
17+
18+
/// Find files recursively in a directory matching a pattern
19+
fn find_files_recursively<P: AsRef<Path>>(
20+
root_dir: P,
21+
filename: &str,
22+
max_depth: Option<usize>,
23+
) -> Result<Vec<PathBuf>, Box<dyn std::error::Error>> {
24+
let mut matches = Vec::new();
25+
let mut stack = vec![(root_dir.as_ref().to_path_buf(), 0)];
26+
27+
while let Some((current_dir, depth)) = stack.pop() {
28+
if let Some(max) = max_depth {
29+
if depth > max {
30+
continue;
31+
}
32+
}
33+
34+
if let Ok(entries) = fs::read_dir(&current_dir) {
35+
for entry in entries.flatten() {
36+
let path = entry.path();
37+
38+
if path.is_file() {
39+
// Simple filename comparison instead of regex
40+
if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) {
41+
if file_name == filename {
42+
matches.push(path);
43+
}
44+
}
45+
} else if path.is_dir() {
46+
stack.push((path, depth + 1));
47+
}
48+
}
49+
}
50+
}
51+
52+
Ok(matches)
53+
}
54+
55+
fn platform_install_paths() -> Result<InstallPath, Box<dyn std::error::Error>> {
56+
// let platform = env::var("PLATFORM");
57+
58+
if cfg!(target_os = "windows") {
59+
// defaults to path:
60+
// C:\Users\Default\AppData\Local
61+
let local_app_data = env::var("LOCALAPPDATA")
62+
.unwrap_or_else(|_| String::from("C:\\Users\\Default\\AppData\\Local"));
63+
64+
println!("windows");
65+
Ok(InstallPath {
66+
paths: vec![PathBuf::from(local_app_data)
67+
.join("Metacall")
68+
.join("metacall")],
69+
name: "metacall.dll".to_string(),
70+
})
71+
} else if cfg!(target_os = "macos") {
72+
println!("macos");
73+
Ok(InstallPath {
74+
paths: vec![
75+
PathBuf::from("/opt/homebrew/lib/"),
76+
PathBuf::from("/usr/local/lib/"),
77+
],
78+
name: "metacall.dylib".to_string(),
79+
})
80+
} else if cfg!(target_os = "linux") {
81+
println!("linux");
82+
Ok(InstallPath {
83+
paths: vec![PathBuf::from("/usr/local/lib/"), PathBuf::from("/gnu/lib/")],
84+
name: "libmetacall.so".to_string(),
85+
})
86+
} else {
87+
Err(format!("Platform {} not supported", env::consts::OS).into())
88+
}
89+
}
90+
91+
/// Get search paths, checking for custom installation path first
92+
fn get_search_config() -> Result<InstallPath, Box<dyn std::error::Error>> {
93+
// First, check if user specified a custom path
94+
if let Ok(custom_path) = env::var("METACALL_INSTALL_PATH") {
95+
// For custom paths, we need to search for any metacall library variant
96+
return Ok(InstallPath {
97+
paths: vec![PathBuf::from(custom_path)],
98+
name: r"^(lib)?metacall(d)?\.(so|dylib|dll)$".to_string(),
99+
});
100+
}
101+
102+
// Fall back to platform-specific paths
103+
platform_install_paths()
104+
}
105+
106+
/// Find the MetaCall library
107+
/// This orchestrates the search process
108+
fn find_metacall_library() -> Result<PathBuf, Box<dyn std::error::Error>> {
109+
let search_config = get_search_config()?;
110+
111+
// Search in each configured path
112+
for search_path in &search_config.paths {
113+
println!(
114+
"cargo:warning=Searching for MetaCall in: {}",
115+
search_path.display()
116+
);
117+
118+
// Only search at depth 0 (current directory)
119+
match find_files_recursively(search_path, &search_config.name, Some(0)) {
120+
Ok(files) if !files.is_empty() => {
121+
let found_lib = &files[0];
122+
println!(
123+
"cargo:warning=Found MetaCall library: {}",
124+
found_lib.display()
125+
);
126+
return Ok(found_lib.clone());
127+
}
128+
Ok(_) => {
129+
// No files found in this path, continue searching
130+
continue;
131+
}
132+
Err(e) => {
133+
println!(
134+
"cargo:warning=Error searching in {}: {}",
135+
search_path.display(),
136+
e
137+
);
138+
continue;
139+
}
140+
}
141+
}
142+
143+
// If we get here, library wasn't found
144+
let search_paths: Vec<String> = search_config
145+
.paths
146+
.iter()
147+
.map(|p| p.display().to_string())
148+
.collect();
149+
150+
Err(format!(
151+
"MetaCall library not found. Searched in: {}. \
152+
If you have it installed elsewhere, set METACALL_INSTALL_PATH environment variable.",
153+
search_paths.join(", ")
154+
)
155+
.into())
156+
}
2157

3158
fn main() {
4159
// When running tests from CMake
5160
if let Ok(val) = env::var("PROJECT_OUTPUT_DIR") {
6-
// Link search path to build folder
7161
println!("cargo:rustc-link-search=native={val}");
8162

9-
// Link against correct version of metacall
10163
match env::var("CMAKE_BUILD_TYPE") {
11-
Ok(val) => {
12-
if val == "Debug" {
13-
// Try to link the debug version when running tests
14-
println!("cargo:rustc-link-lib=dylib=metacalld");
15-
} else {
16-
println!("cargo:rustc-link-lib=dylib=metacall");
17-
}
164+
Ok(val) if val == "Debug" => {
165+
println!("cargo:rustc-link-lib=dylib=metacalld");
18166
}
19-
Err(_) => {
167+
_ => {
20168
println!("cargo:rustc-link-lib=dylib=metacall");
21169
}
22170
}
23-
} else {
24-
// When building from Cargo
25-
let profile = env::var("PROFILE").unwrap();
26-
match profile.as_str() {
27-
// "debug" => {
28-
// println!("cargo:rustc-link-lib=dylib=metacalld");
29-
// }
30-
"debug" | "release" => {
31-
println!("cargo:rustc-link-lib=dylib=metacall")
171+
return;
172+
}
173+
174+
// When building from Cargo - try to find MetaCall
175+
match find_metacall_library() {
176+
Ok(lib_path) => {
177+
// Extract the directory containing the library
178+
if let Some(lib_dir) = lib_path.parent() {
179+
println!("cargo:rustc-link-search=native={}", lib_dir.display());
32180
}
33-
_ => {
34-
println!("cargo:rustc-link-lib=dylib=metacall")
181+
182+
// Link against the library
183+
let profile = env::var("PROFILE").unwrap_or_else(|_| "release".to_string());
184+
match profile.as_str() {
185+
"debug" | "release" => {
186+
println!("cargo:rustc-link-lib=dylib=metacall");
187+
}
188+
_ => {
189+
println!("cargo:rustc-link-lib=dylib=metacall");
190+
}
35191
}
36192
}
193+
Err(e) => {
194+
println!("cargo:warning={e}");
195+
// Still try to link in case the library is in system paths
196+
println!("cargo:rustc-link-lib=dylib=metacall");
197+
}
37198
}
38199
}

0 commit comments

Comments
 (0)