use 5.006; use strict; use warnings; use ExtUtils::MakeMaker; use File::ShareDir::Install; use File::Spec; use File::Copy; use FindBin; use File::Temp qw/tempdir/; use Cwd qw/abs_path/; use Data::Roundtrip qw/perl2dump/; use IPC::Run; # FFI::CheckLib can check_lib with specified symbol which is handy, so use that # it does not depend on FFI! use FFI::CheckLib; # but we also need this to compile a piece of C code (not really) #use Devel::CheckLib; my $VERBOSE = exists($ENV{VERBOSE}) && defined($ENV{VERBOSE}) ? $ENV{VERBOSE} : 1; # returns an arrayref of [$cflags, $ldflags] # NOTE: 'cflags' contains the includes (as -I... -I...) # 'ldflags' contains the libs (as -L.. -L.. -l.. -l..) # returns undef on failure # when it fails, your only chance to have this run is to specify # ENV vars: OPENCV_CFLAGS and OPENCV_LDFLAGS # to contain -I and -L -l # Unix/Linux usually contains pkg-config which outputs this params # given that OpenCV was properly installed. # On M$ all goes, it's just a mess and should not be even supported. sub find_opencv_settings { my ($out, $err, $ret); # 1. check if env vars OPENCV_CFLAGS and OPENCV_LDFLAGS were specified if( $VERBOSE > 0 ){ print STDOUT "find_opencv_settings() : checking ENV for 'OPENCV_LDFLAGS' and 'OPENCV_CFLAGS' ...\n" } my $ldflags = exists($ENV{OPENCV_LDFLAGS}) && defined($ENV{OPENCV_LDFLAGS}) ? $ENV{OPENCV_LDFLAGS} : undef; my $cflags = exists($ENV{OPENCV_CFLAGS}) && defined($ENV{OPENCV_CFLAGS}) ? $ENV{OPENCV_CFLAGS} : undef; if( $ldflags and $cflags ){ if( $VERBOSE > 0 ){ print STDOUT "find_opencv_settings() : found ldflags='$ldflags', cflags='$cflags' (using supplied ENV vars).\n" } return [$cflags, $ldflags] } # 2. check if there's a pkg-config if( $VERBOSE > 0 ){ print STDOUT "find_opencv_settings() : checking with pkg-config ...\n" } for my $opv (qw/opencv4 opencv/){ my @cmd = ('pkg-config', $opv, '--libs'); eval { IPC::Run::run \@cmd, \undef, \$out, \$err, IPC::Run::timeout(30) }; if( $@ ){ if( $VERBOSE > 0 ){ print STDERR "find_opencv_settings() : failed to run command '@cmd': $@\n"; } next } chomp($out); $ldflags = $out; @cmd = ('pkg-config', $opv, '--cflags'); IPC::Run::run \@cmd, \undef, \$out, \$err, IPC::Run::timeout(30) or next; chomp($out); $cflags = $out; last; } if( $ldflags and $cflags ){ if( $VERBOSE > 0 ){ print STDOUT "find_opencv_settings() : found ldflags='$ldflags', cflags='$cflags' (using pkg-config).\n" } return [$cflags, $ldflags] } # 3. check with cmake script, provided cmake is installed if( $VERBOSE > 0 ){ print STDOUT "find_opencv_settings() : checking with cmake ...\n" } my $tmpdir = tempdir(CLEANUP => 1); my $curdir = Cwd::abs_path(Cwd::cwd); die "find_opencv_settings() : failed to chdir to tempdir '$tmpdir'." unless chdir $tmpdir; if( $VERBOSE > 0 ){ print STDOUT "find_opencv_settings() : writing CMakeLists.txt and test.cpp into tempdir '$tmpdir' ...\n"; } # write the CMakeLists.txt for cmake open my $fh, '>', 'CMakeLists.txt' or die "find_opencv_settings() : failed to open file 'CMakeLists.txt' for writing: $!"; print $fh <<'EOCM'; cmake_minimum_required(VERSION 2.9) project(RUBBISH_CMAKE_PROJECT) find_package( OpenCV REQUIRED ) include_directories( ${OpenCV_INCLUDE_DIRS} ) add_executable( _cmake_opencv_testme test.cpp ) target_link_libraries( _cmake_opencv_testme ${OpenCV_LIBS} ) message(STATUS "RUBBISH_CMAKE_PROJECT::INCLUDE_DIRS: ${OpenCV_INCLUDE_DIRS}") message(STATUS "RUBBISH_CMAKE_PROJECT::LIB_PATH: ${OpenCV_LIB_PATH}") message(STATUS "RUBBISH_CMAKE_PROJECT::INSTALL_PREFIX: ${OpenCV_INSTALL_PREFIX}") message(STATUS "RUBBISH_CMAKE_PROJECT::LIBS: ${OpenCV_LIBS}") EOCM close $fh; # now write a basic test C++ program open $fh, '>', 'test.cpp' or die "find_opencv_settings() : failed to open file 'test.cpp' for writing: $!"; print $fh <<'EOCM'; #include int main(void){ return(0); } EOCM close $fh; my @cmd = ('cmake', '.'); # does cmake even exist? if( $VERBOSE > 0 ){ print STDOUT "find_opencv_settings() : attempting to run '@cmd' into tempdir '$tmpdir' ...\n"; } eval { IPC::Run::run \@cmd, \undef, \$out, \$err }; if( $@ ){ if( $VERBOSE > 0 ){ print STDERR "find_opencv_settings() : running command has failed: '@cmd': $@\n"; } } else { my %buildparams; for my $l (split /\R/, $out){ if( $l =~ /^\-\- RUBBISH_CMAKE_PROJECT::([A-Z_]+): (.+?)$/ ){ $buildparams{$1} = $2 } } print "Build Params: \n".perl2dump(\%buildparams); if( exists($buildparams{INCLUDE_DIRS}) ){ $cflags .= ' -I'.$_ for split /\s*;\s*/, $buildparams{INCLUDE_DIRS} } if( exists($buildparams{LIB_PATH}) ){ $ldflags .= ' -L'.$_ for split /\s*;\s*/, $buildparams{LIB_PATH} } if( exists($buildparams{LIBS}) ){ $ldflags .= ' -l'.$_ for split /\s*;\s*/, $buildparams{LIBS} } } die "find_opencv_settings() : failed to chdir to previous current dir '$curdir'." unless chdir $curdir; if( $ldflags and $cflags ){ if( $VERBOSE > 0 ){ print STDOUT "find_opencv_settings() : found ldflags='$ldflags', cflags='$cflags' (using cmake).\n" } return [$cflags, $ldflags] } # 4. check with FFI::CheckLib, but this only gives us libraries! if( $VERBOSE > 0 ){ print STDOUT "find_opencv_settings() : finding ldflags (only!) with FFI::CheckLib, this is just for extra info but it is useless because it does not find the INCLUDE dir ...\n" } $cflags = ' '; # still make cflags empty and hope for the best (it must have 1 space there) $ldflags = undef; for my $wanted ('opencv_wechat_qrcode', 'opencv_world'){ # this will fail because symbol names are mangled, e.g. _ZN2cv13wechat_qrcode12WeChatQRCode15detectAndDecodeB5cxx11ERKNS_11_InputArrayERKNS_12_OutputArrayE my ($lib) = FFI::CheckLib::find_lib( lib => $wanted, symbol => 'wechat_qrcode::WeChatQRCode' ); # example output: /usr/local/lib64/libopencv_world.so.4.5.5 # this needs fine-tuning perhaps. easily done for linux but windows? ouch can't be bothered if( $lib ){ $ldflags .= ' -l'.$lib; last } } if( $ldflags and $cflags ){ if( $VERBOSE > 0 ){ print STDOUT "find_opencv_settings() : found ldflags='$ldflags', cflags='$cflags' (using ".'FFI::CheckLib::find_lib()'.").\n" } return [$cflags, $ldflags] } print STDERR "find_opencv_settings() : error, failed to find OpenCV compilation flags (library location and include-dir) using several methods." ."\nThe best way to proceed from here is to find where OpenCV library and include dir are located " ."and set ENVironment variables before re-running this script. " ."FOR EXAMPLE if library is located at '/usr/lib64/libopencv_world.so' " ."and include dir at '/usr/local/include/opencv4/include/', " ."then set these ENV vars (FOR EXAMPLE):" ."\n OPENCV_LDFLAGS='-L/usr/lib64/ -lopencv_world'" ."\n OPENCV_CFLAGS='-I/usr/local/include/opencv4/include/'" ."and re-run this script." ."The only complication then is if you don't thave the libopencv_world.so which includes all OpenCV symbols " ."but instead you have hundreds of smaller OpenCV component libraries. In which case set this:" ."\n OPENCV_LDFLAGS='-L/usr/lib64/ " # add here all libs: ."-lopencv_core " ."-lopencv_dnn " ."-lopencv_imgproc " ."-lopencv_features2d " ."-lopencv_flann " ."-lopencv_imgcodecs " ."-lopencv_wechat_qrcode " ."-lopencv_highgui " ."'" # ending the libs here ."\n\nIf running this script was successful but 'make' fails, then Perhaps you may also " ."need to add '-lpng -ltiff -ljpeg' in the same way as described above. Also -ltbb etc. In general add all libraries via ENV vars when all else fails." ."\nGood luck unless you have Unix/Linux which is a solid dev env.\n" ."\n" ; return undef # failed }