Skip to content

Commit 020dc0e

Browse files
fahdfadyviferga
andauthored
fix and refactor: rust port not finding metacall shared libraries and config files (#569)
* refactor(rs_port): init translating search functionality * stash * CI: update rust workflow for testing Signed-off-by: fahdfady <fahd.fady212@gmail.com> * CI(release-rust): update test job to use matrix strategy for OS compatibility Signed-off-by: fahdfady <fahd.fady212@gmail.com> * CI: rust release, remove windows * canonicalize * Update build.rs * Update release-rust.yml * Update release-rust.yml * Update release-rust.yml --------- Signed-off-by: fahdfady <fahd.fady212@gmail.com> Co-authored-by: Vicente Eduardo Ferrer Garcia <7854099+viferga@users.noreply.github.com>
1 parent 6b59246 commit 020dc0e

File tree

2 files changed

+191
-12
lines changed

2 files changed

+191
-12
lines changed

.github/workflows/release-rust.yml

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
name: Release Rust Crates
22

33
on:
4+
workflow_dispatch:
5+
pull_request:
46
push:
57
branches: [ master, develop ]
68
paths:
7-
- 'source/ports/rs_port/Cargo.toml'
8-
- 'source/ports/rs_port/inline/Cargo.toml'
9+
- 'source/ports/rs_port/**'
910

1011
concurrency:
1112
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@@ -15,9 +16,39 @@ env:
1516
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
1617

1718
jobs:
19+
test:
20+
name: Rust Port Tests
21+
runs-on: ${{ matrix.os }}
22+
strategy:
23+
fail-fast: false
24+
matrix:
25+
os: [ubuntu-latest, macos-latest, windows-latest]
26+
steps:
27+
- name: Check out the repo
28+
uses: actions/checkout@v4
29+
with:
30+
fetch-depth: 0
31+
- name: Install MetaCall Unix
32+
if: matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest'
33+
run: curl -sL https://raw.githubusercontent.com/metacall/install/master/install.sh | sh
34+
- name: Install MetaCall Windows
35+
if: matrix.os == 'windows-latest'
36+
run: powershell -NoProfile -ExecutionPolicy Unrestricted -Command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; &([scriptblock]::Create((Invoke-WebRequest -UseBasicParsing 'https://raw.githubusercontent.com/metacall/install/master/install.ps1')))"
37+
- name: Install Rust
38+
uses: actions-rs/toolchain@v1
39+
with:
40+
toolchain: stable
41+
override: true
42+
- name: Build and Test the Rust Port
43+
working-directory: source/ports/rs_port
44+
run: |
45+
cargo build --verbose
46+
cargo test --verbose
47+
1848
release:
1949
name: Release Rust Port
2050
runs-on: ubuntu-latest
51+
needs: test
2152
steps:
2253
- name: Check out the repo
2354
uses: actions/checkout@v4

source/ports/rs_port/build.rs

Lines changed: 158 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,147 @@
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+
names: Vec<&'static str>,
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+
if cfg!(target_os = "windows") {
57+
// Defaults to path: C:\Users\Default\AppData\Local
58+
let local_app_data = env::var("LOCALAPPDATA")
59+
.unwrap_or_else(|_| String::from("C:\\Users\\Default\\AppData\\Local"));
60+
61+
Ok(InstallPath {
62+
paths: vec![PathBuf::from(local_app_data)
63+
.join("MetaCall")
64+
.join("metacall")],
65+
names: vec!["metacall.dll"],
66+
})
67+
} else if cfg!(target_os = "macos") {
68+
Ok(InstallPath {
69+
paths: vec![
70+
PathBuf::from("/opt/homebrew/lib/"),
71+
PathBuf::from("/usr/local/lib/"),
72+
],
73+
names: vec!["metacall.dylib"],
74+
})
75+
} else if cfg!(target_os = "linux") {
76+
Ok(InstallPath {
77+
paths: vec![PathBuf::from("/usr/local/lib/"), PathBuf::from("/gnu/lib/")],
78+
names: vec!["libmetacall.so"],
79+
})
80+
} else {
81+
Err(format!("Platform {} not supported", env::consts::OS).into())
82+
}
83+
}
84+
85+
/// Get search paths, checking for custom installation path first
86+
fn get_search_config() -> Result<InstallPath, Box<dyn std::error::Error>> {
87+
// First, check if user specified a custom path
88+
if let Ok(custom_path) = env::var("METACALL_INSTALL_PATH") {
89+
// For custom paths, we need to search for any metacall library variant
90+
return Ok(InstallPath {
91+
paths: vec![PathBuf::from(custom_path)],
92+
names: vec!["libmetacall.so", "libmetacalld.so", "libmetacall.dylib", "libmetacalld.dylib", "metacall.dll", "metacalld.dll"]
93+
});
94+
}
95+
96+
// Fall back to platform-specific paths
97+
platform_install_paths()
98+
}
99+
100+
/// Find the MetaCall library
101+
/// This orchestrates the search process
102+
fn find_metacall_library() -> Result<PathBuf, Box<dyn std::error::Error>> {
103+
let search_config = get_search_config()?;
104+
105+
// Search in each configured path
106+
for search_path in &search_config.paths {
107+
for name in &search_config.names {
108+
// Search with no limit in depth
109+
match find_files_recursively(search_path, &name.to_string(), None) {
110+
Ok(files) if !files.is_empty() => {
111+
let found_lib = fs::canonicalize(&files[0])?;
112+
113+
return Ok(found_lib.clone());
114+
}
115+
Ok(_) => {
116+
// No files found in this path, continue searching
117+
continue;
118+
}
119+
Err(e) => {
120+
eprintln!(
121+
"Error searching in {}: {}",
122+
search_path.display(),
123+
e
124+
);
125+
continue;
126+
}
127+
}
128+
}
129+
}
130+
131+
// If we get here, library wasn't found
132+
let search_paths: Vec<String> = search_config
133+
.paths
134+
.iter()
135+
.map(|p| p.display().to_string())
136+
.collect();
137+
138+
Err(format!(
139+
"MetaCall library not found. Searched in: {}. \
140+
If you have it installed elsewhere, set METACALL_INSTALL_PATH environment variable.",
141+
search_paths.join(", ")
142+
)
143+
.into())
144+
}
2145

3146
fn main() {
4147
// When running tests from CMake
@@ -21,16 +164,21 @@ fn main() {
21164
}
22165
}
23166
} 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")
167+
// When building from Cargo, try to find MetaCall
168+
match find_metacall_library() {
169+
Ok(lib_path) => {
170+
// Extract the directory containing the library
171+
if let Some(lib_dir) = lib_path.parent() {
172+
println!("cargo:rustc-link-search=native={}", lib_dir.display());
173+
println!("cargo:rustc-link-lib=dylib=metacall");
174+
}
32175
}
33-
_ => {
176+
Err(e) => {
177+
// Print the error
178+
eprintln!("Failed to find MetaCall library with: {e} \
179+
Still trying to link in case the library is in system paths");
180+
181+
// Still try to link in case the library is in system paths
34182
println!("cargo:rustc-link-lib=dylib=metacall")
35183
}
36184
}

0 commit comments

Comments
 (0)