11use std:: collections:: { HashMap , HashSet } ;
22use std:: env;
33use std:: ffi:: OsStr ;
4- use std:: fs:: File ;
5- use std:: io:: { BufRead , BufReader } ;
64use std:: path:: { Path , PathBuf } ;
75use std:: time:: Instant ;
86
@@ -169,61 +167,92 @@ fn files_with_extension<'e>(dir: &Path, extension: impl AsRef<OsStr> + 'e) -> Re
169167 } )
170168}
171169
172- fn get_module_header_dir ( header_dir : & Path ) -> Option < PathBuf > {
173- let mut out = header_dir. join ( "opencv2.framework/Headers" ) ;
174- if out. exists ( ) {
175- return Some ( out) ;
170+ mod header {
171+ use std:: fs:: File ;
172+ use std:: io:: { BufRead , BufReader } ;
173+ use std:: path:: { Path , PathBuf } ;
174+
175+ use semver:: Version ;
176+
177+ pub fn get_module_header_dir ( header_dir : & Path ) -> Option < PathBuf > {
178+ let mut out = header_dir. join ( "opencv2.framework/Headers" ) ;
179+ if out. exists ( ) {
180+ return Some ( out) ;
181+ }
182+ out = header_dir. join ( "opencv2" ) ;
183+ if out. exists ( ) {
184+ return Some ( out) ;
185+ }
186+ None
176187 }
177- out = header_dir. join ( "opencv2" ) ;
178- if out. exists ( ) {
179- return Some ( out) ;
188+
189+ pub fn get_version_header ( header_dir : & Path ) -> Option < PathBuf > {
190+ get_module_header_dir ( header_dir)
191+ . map ( |dir| dir. join ( "core/version.hpp" ) )
192+ . filter ( |hdr| hdr. is_file ( ) )
180193 }
181- None
182- }
183194
184- fn get_version_header ( header_dir : & Path ) -> Option < PathBuf > {
185- get_module_header_dir ( header_dir)
186- . map ( |dir| dir. join ( "core/version.hpp " ) )
187- . filter ( |hdr| hdr. is_file ( ) )
188- }
195+ pub fn get_config_header ( header_dir : & Path ) -> Option < PathBuf > {
196+ get_module_header_dir ( header_dir)
197+ . map ( |dir| dir. join ( "cvconfig.h " ) )
198+ . filter ( |hdr| hdr. is_file ( ) )
199+ }
189200
190- fn get_version_from_headers ( header_dir : & Path ) -> Option < Version > {
191- let version_hpp = get_version_header ( header_dir) ?;
192- let mut major = None ;
193- let mut minor = None ;
194- let mut revision = None ;
195- let mut line = String :: with_capacity ( 256 ) ;
196- let mut reader = BufReader :: new ( File :: open ( version_hpp) . ok ( ) ?) ;
197- while let Ok ( bytes_read) = reader. read_line ( & mut line) {
198- if bytes_read == 0 {
199- break ;
200- }
201- if let Some ( line) = line. strip_prefix ( "#define CV_VERSION_" ) {
202- let mut parts = line. split_whitespace ( ) ;
203- if let ( Some ( ver_spec) , Some ( version) ) = ( parts. next ( ) , parts. next ( ) ) {
204- match ver_spec {
205- "MAJOR" => {
206- major = Some ( version. parse ( ) . ok ( ) ?) ;
207- }
208- "MINOR" => {
209- minor = Some ( version. parse ( ) . ok ( ) ?) ;
210- }
211- "REVISION" => {
212- revision = Some ( version. parse ( ) . ok ( ) ?) ;
201+ pub fn find_version ( header_dir : & Path ) -> Option < Version > {
202+ let version_hpp = get_version_header ( header_dir) ?;
203+ let mut major = None ;
204+ let mut minor = None ;
205+ let mut revision = None ;
206+ let mut line = String :: with_capacity ( 256 ) ;
207+ let mut reader = BufReader :: new ( File :: open ( version_hpp) . ok ( ) ?) ;
208+ while let Ok ( bytes_read) = reader. read_line ( & mut line) {
209+ if bytes_read == 0 {
210+ break ;
211+ }
212+ if let Some ( line) = line. strip_prefix ( "#define CV_VERSION_" ) {
213+ let mut parts = line. split_whitespace ( ) ;
214+ if let ( Some ( ver_spec) , Some ( version) ) = ( parts. next ( ) , parts. next ( ) ) {
215+ match ver_spec {
216+ "MAJOR" => {
217+ major = Some ( version. parse ( ) . ok ( ) ?) ;
218+ }
219+ "MINOR" => {
220+ minor = Some ( version. parse ( ) . ok ( ) ?) ;
221+ }
222+ "REVISION" => {
223+ revision = Some ( version. parse ( ) . ok ( ) ?) ;
224+ }
225+ _ => { }
213226 }
214- _ => { }
227+ }
228+ if major. is_some ( ) && minor. is_some ( ) && revision. is_some ( ) {
229+ break ;
215230 }
216231 }
217- if major. is_some ( ) && minor. is_some ( ) && revision. is_some ( ) {
232+ line. clear ( ) ;
233+ }
234+ if let ( Some ( major) , Some ( minor) , Some ( revision) ) = ( major, minor, revision) {
235+ Some ( Version :: new ( major, minor, revision) )
236+ } else {
237+ None
238+ }
239+ }
240+
241+ pub fn find_enabled_features ( header_dir : & Path ) -> Option < Vec < String > > {
242+ let config_h = get_config_header ( header_dir) ?;
243+ let mut out = Vec :: with_capacity ( 64 ) ;
244+ let mut line = String :: with_capacity ( 256 ) ;
245+ let mut reader = BufReader :: new ( File :: open ( config_h) . ok ( ) ?) ;
246+ while let Ok ( bytes_read) = reader. read_line ( & mut line) {
247+ if bytes_read == 0 {
218248 break ;
219249 }
250+ if let Some ( feature) = line. strip_prefix ( "#define HAVE_" ) {
251+ out. push ( feature. trim ( ) . to_lowercase ( ) ) ;
252+ }
253+ line. clear ( ) ;
220254 }
221- line. clear ( ) ;
222- }
223- if let ( Some ( major) , Some ( minor) , Some ( revision) ) = ( major, minor, revision) {
224- Some ( Version :: new ( major, minor, revision) )
225- } else {
226- None
255+ Some ( out)
227256 }
228257}
229258
@@ -264,13 +293,18 @@ fn make_modules_and_alises(
264293 Ok ( ( modules, aliases) )
265294}
266295
267- fn emit_inherent_features ( opencv_version : & Version ) {
296+ fn emit_inherent_features ( opencv : & Library ) {
268297 if VersionReq :: parse ( ">=4.10" )
269298 . expect ( "Static version requirement" )
270- . matches ( opencv_version )
299+ . matches ( & opencv . version )
271300 {
272301 println ! ( "cargo::rustc-cfg=ocvrs_has_inherent_feature_hfloat" ) ;
273302 }
303+ for feature in & opencv. enabled_features {
304+ if feature == "opencl" {
305+ println ! ( "cargo::rustc-cfg=ocvrs_has_inherent_feature_opencl" ) ;
306+ }
307+ }
274308}
275309
276310fn make_compiler ( opencv : & Library , ffi_export_suffix : & str ) -> cc:: Build {
@@ -374,9 +408,7 @@ fn main() -> Result<()> {
374408 for module in SUPPORTED_MODULES {
375409 println ! ( "cargo::rustc-check-cfg=cfg(ocvrs_has_module_{module})" ) ;
376410 }
377- // MSRV: switch to #[expect] when MSRV is 1.81
378- #[ allow( clippy:: single_element_loop) ]
379- for inherent_feature in [ "hfloat" ] {
411+ for inherent_feature in [ "hfloat" , "opencl" ] {
380412 println ! ( "cargo::rustc-check-cfg=cfg(ocvrs_has_inherent_feature_{inherent_feature})" ) ;
381413 }
382414
@@ -419,10 +451,10 @@ fn main() -> Result<()> {
419451 let opencv_header_dir = opencv
420452 . include_paths
421453 . iter ( )
422- . find ( |p| get_version_header ( p) . is_some ( ) )
423- . expect ( "Discovered OpenCV include paths is empty or contains non-existent paths " ) ;
454+ . find ( |p| header :: get_version_header ( p ) . is_some ( ) && header :: get_config_header ( p) . is_some ( ) )
455+ . expect ( "Discovered OpenCV include paths do not contain valid OpenCV headers " ) ;
424456
425- if let Some ( header_version) = get_version_from_headers ( opencv_header_dir) {
457+ if let Some ( header_version) = header :: find_version ( opencv_header_dir) {
426458 if header_version != opencv. version {
427459 panic ! (
428460 "OpenCV version from the headers: {header_version} (at {}) must match version of the OpenCV library: {} (include paths: {:?})" ,
@@ -442,7 +474,7 @@ fn main() -> Result<()> {
442474 )
443475 }
444476
445- let opencv_module_header_dir = get_module_header_dir ( opencv_header_dir) . expect ( "Can't find OpenCV module header dir" ) ;
477+ let opencv_module_header_dir = header :: get_module_header_dir ( opencv_header_dir) . expect ( "Can't find OpenCV module header dir" ) ;
446478 eprintln ! (
447479 "=== Detected OpenCV module header dir at: {}" ,
448480 opencv_module_header_dir. display( )
@@ -452,7 +484,7 @@ fn main() -> Result<()> {
452484 println ! ( "cargo::rustc-cfg=ocvrs_has_module_{module}" ) ;
453485 }
454486
455- emit_inherent_features ( & opencv. version ) ;
487+ emit_inherent_features ( & opencv) ;
456488
457489 setup_rerun ( ) ?;
458490
0 commit comments