diff --git a/build.rs b/build.rs index 824de6dc..b2042749 100644 --- a/build.rs +++ b/build.rs @@ -94,43 +94,6 @@ fn files_with_extension<'e>(dir: &Path, extension: impl AsRef + 'e) -> Re }) } -/// Returns Some(new_file_name) if some parts of the filename were removed, None otherwise -fn cleanup_lib_filename(filename: &OsStr) -> Option<&OsStr> { - let mut new_filename = filename; - // used to check for the file extension (with dots stripped) and for the part of the filename - const LIB_EXTS: [&str; 7] = [".so.", ".a.", ".dll.", ".lib.", ".dylib.", ".framework.", ".tbd."]; - let filename_path = Path::new(new_filename); - // strip lib extension from the filename - if let (Some(stem), Some(extension)) = (filename_path.file_stem(), filename_path.extension().and_then(OsStr::to_str)) { - if LIB_EXTS.iter().any(|e| e.trim_matches('.').eq_ignore_ascii_case(extension)) { - new_filename = stem; - } - } - if let Some(mut file) = new_filename.to_str() { - let orig_len = file.len(); - - // strip "lib" prefix from the filename unless targeting MSVC - if !*TARGET_ENV_MSVC { - file = file.strip_prefix("lib").unwrap_or(file); - } - - // strip lib extension + suffix (e.g. .so.4.6.0) from the filename - LIB_EXTS.iter().for_each(|&inner_ext| { - if let Some(inner_ext_idx) = file.find(inner_ext) { - file = &file[..inner_ext_idx]; - } - }); - if orig_len != file.len() { - new_filename = OsStr::new(file); - } - } - if new_filename.len() != filename.len() { - Some(new_filename) - } else { - None - } -} - fn get_module_header_dir(header_dir: &Path) -> Option { let mut out = header_dir.join("opencv2.framework/Headers"); if out.exists() { diff --git a/build/cmake_probe.rs b/build/cmake_probe.rs index 490c1c7d..6907a5d0 100644 --- a/build/cmake_probe.rs +++ b/build/cmake_probe.rs @@ -9,7 +9,7 @@ use semver::Version; use shlex::Shlex; use super::library::Linkage; -use super::Result; +use super::{Result, TARGET_ENV_MSVC}; #[derive(Debug, PartialEq, Eq)] pub struct LinkLib(pub Linkage, pub String); @@ -17,19 +17,54 @@ pub struct LinkLib(pub Linkage, pub String); impl LinkLib { #[inline] pub fn emit_cargo_rustc_link(&self) -> String { - let link_spec = self.0.as_cargo_rustc_link_spec(); - let link_spec = if self.1.starts_with(link_spec) { - "" + format!("cargo:rustc-link-lib={}{}", self.0.as_cargo_rustc_link_spec(), self.1) + } + + /// Returns Some(new_file_name) with extra parts of the filename were removed, None in case of error + pub fn with_cleaned_up_lib_filename(self) -> Option { + return Some(self); + if matches!(self.0, Linkage::Static | Linkage::Framework) { + Some(self) } else { - link_spec - }; - format!("cargo:rustc-link-lib={link_spec}{}", self.1) + let mut new_filename = Path::new(&self.1).as_os_str(); + // used to check for the file extension (with dots stripped) and for the part of the filename + const LIB_EXTS: [&str; 7] = [".so.", ".a.", ".dll.", ".lib.", ".dylib.", ".framework.", ".tbd."]; + let filename_path = Path::new(new_filename); + // strip lib extension from the filename + if let (Some(stem), Some(extension)) = (filename_path.file_stem(), filename_path.extension().and_then(OsStr::to_str)) { + if LIB_EXTS.iter().any(|e| e.trim_matches('.').eq_ignore_ascii_case(extension)) { + new_filename = stem; + } + } + if let Some(mut file) = new_filename.to_str() { + let orig_len = file.len(); + + // strip "lib" prefix from the filename unless targeting MSVC + if !*TARGET_ENV_MSVC { + file = file.strip_prefix("lib").unwrap_or(file); + } + + // strip lib extension + suffix (e.g. .so.4.6.0) from the filename + LIB_EXTS.iter().for_each(|&inner_ext| { + if let Some(inner_ext_idx) = file.find(inner_ext) { + file = &file[..inner_ext_idx]; + } + }); + if orig_len != file.len() { + new_filename = OsStr::new(file); + } + } + new_filename + .to_str() + .map(|new_filename| Self(self.0, new_filename.to_string())) + } } } impl From<&str> for LinkLib { fn from(value: &str) -> Self { - Self(Linkage::Default, value.to_string()) + let (linkage, value) = Linkage::from_prefixed_str(value); + Self(linkage, value.to_string()) } } @@ -49,7 +84,8 @@ impl LinkSearch { impl From<&str> for LinkSearch { fn from(value: &str) -> Self { - Self(Linkage::Default, value.into()) + let (linkage, value) = Linkage::from_prefixed_str(value); + Self(linkage, value.into()) } } @@ -190,43 +226,30 @@ impl<'r> CmakeProbe<'r> { } else { framework.to_string() }; - let framework_path = Path::new(&framework); - let has_extension = framework_path - .extension() - .and_then(OsStr::to_str) - .map_or(false, |ext| ext.eq_ignore_ascii_case("framework")); - let name = if has_extension { - framework - } else { - format!("{}.framework", framework) - }; - link_libs.push(LinkLib(Linkage::Framework, name)); + link_libs.push(LinkLib(Linkage::Framework, framework)); } else if !arg.starts_with('-') { let path = Path::new(arg); - let linkage = if Self::is_library_static(path) { + let linkage = if Self::is_library_static_archive(path) { Linkage::Static } else { - Linkage::Default - }; - if let Some(file) = path.file_name().and_then(super::cleanup_lib_filename) { if let Some(parent) = path.parent().map(|p| p.to_owned()) { - let search_path = LinkSearch(linkage, parent); + let search_path = LinkSearch(Linkage::Default, parent); if !link_paths.contains(&search_path) { link_paths.push(search_path); } } else { panic!("{}", arg.to_string()); } - let file = file.to_str().expect("Non-UTF8 filename"); - link_libs.push(LinkLib(linkage, file.to_string())); - } + Linkage::Default + }; + link_libs.push(LinkLib(linkage, path.to_str().expect("Non-UTF8 filename").to_string())); } else { eprintln!("=== Unexpected cmake compiler argument found: {arg}"); } } } - fn is_library_static(path: &Path) -> bool { + fn is_library_static_archive(path: &Path) -> bool { path.extension().map_or(false, |ext| ext.eq_ignore_ascii_case("a")) } diff --git a/build/library.rs b/build/library.rs index 7faecf5b..2a527baa 100644 --- a/build/library.rs +++ b/build/library.rs @@ -8,7 +8,7 @@ use dunce::canonicalize; use semver::Version; use super::cmake_probe::{CmakeProbe, LinkLib, LinkSearch}; -use super::{cleanup_lib_filename, get_version_from_headers, Result, MANIFEST_DIR, OUT_DIR, TARGET_VENDOR_APPLE}; +use super::{get_version_from_headers, Result, MANIFEST_DIR, OUT_DIR, TARGET_VENDOR_APPLE}; struct PackageName; @@ -103,6 +103,13 @@ impl Linkage { Self::Framework => "framework=", } } + + pub fn from_prefixed_str(s: &str) -> (Self, &str) { + [Self::Dynamic, Self::Static, Self::Framework] + .iter() + .find_map(|l| s.strip_prefix(l.as_cargo_rustc_link_spec()).map(|s| (*l, s))) + .unwrap_or((Self::Default, s)) + } } #[derive(Debug)] @@ -114,15 +121,9 @@ pub struct Library { impl Library { fn process_library_list(libs: impl IntoIterator) -> impl Iterator { - libs.into_iter().filter_map(|LinkLib(linkage, path)| { - let path = Path::new(&path); - if let Some(filename) = path.file_name() { - let filename = cleanup_lib_filename(filename).unwrap_or(filename); - filename.to_str().map(|f| LinkLib(linkage, f.to_owned())) - } else { - None - } - }) + libs + .into_iter() + .filter_map(|link_lib| link_lib.with_cleaned_up_lib_filename()) } fn version_from_include_paths(include_paths: impl IntoIterator>) -> Option { diff --git a/tests/mat.rs b/tests/mat.rs index 7d846225..98d37dfc 100644 --- a/tests/mat.rs +++ b/tests/mat.rs @@ -6,6 +6,7 @@ use matches::assert_matches; use opencv::core::{MatConstIterator, MatIter, Point, Point2d, Rect, Scalar, Size, Vec2b, Vec2s, Vec3d, Vec3f, Vec4w, Vector}; use opencv::prelude::*; use opencv::{core, imgproc, Error, Result}; + const PIXEL: &[u8] = include_bytes!("pixel.png"); #[test]