Invalid logic for symbol search
0x62ash opened this issue · 12 comments
Hello,
You delete library from search before check that it has requested symbols. So if environment has 2 or more versions of needed library it's possible that library detection fail on 1 match that does not has symbols. Right now this is why Im failing my travis builds :/
The problem come from here https://github.com/plicease/FFI-CheckLib/blob/master/lib/FFI/CheckLib.pm#L251
I think the logic is correct. Normally when searching for a library or executable in a path we stop after finding the first one. It is up to the operating system and the user to set the search paths such that the "correct" library appears first. However, I see value in the feature you are implicitly asking for. At the moment you could do this using the verify option, something like this:
check_lib(lib => 'foo', verify => sub {
my($name, $path) = @_;
# check that $path provides symbols that you require
# using either FFI::Platypus or DynaLoader
});This works because verify comes before the delete from %$lib. Which arguably violates the principal referenced above. However I think the reason that I implemented the verify subref was for this sort of situation where the first lib in the path rule might not apply.
I'd like you to be able to do this without FFI::Platypus or DynaLoader though, since you might not be using one or the other. To that end, I can think of a few things that might make this sort of thing easier:
- provide a
has_symbolsfunction that returns true if a library has all the symbols in a list
check_lib(lib => 'foo', verify => sub { has_symbols($_[1], qw( list of symbols ) });- provide a
wherefunction that returns all libraries in the search path with the given name so that you can do your own grepping or mapping:
my($lib) = grep { has_symbols($_, qw( list of symbols )) } where('foo'); It is up to the operating system and the user to set the search paths such that the "correct" library appears first
It's not possible to user set correct path for check_lib in this case:
/lib/libfoo.so.1
/lib/libfoo.so.2
has_symbols and where -- both ok for me, but these solutions looks like overcomplicated when check_lib already has symbol option
My thoughts:
check_lib_or_exit( lib => 'jpeg', symbol => 'jinit_memory_mgr' ); # <-- OK
check_lib_or_exit( lib => [ 'iconv', 'jpeg' ] ); # <-- NOK or we should ignore any further symbol option
check_lib_or_exit([ lib => 'iconv' ], [ lib => 'jpeg' ]); # <-- OK, and now we can add extra find options
check_lib_or_exit([ lib => 'iconv' ], [ lib => 'jpeg', symbol => 'jpeg_foobar_symbol' ]);
The typical way to resolve the two libfoos in your example is with a symlink. I know some platforms like OpenBSD do not seem to use this convention.
I realize this is not something FFI::CheckLib was handling correctly so I've fixed that.
I am not a fan of the arguments can be either key/value pairs or an array reference. I think the find_lib interface is already complicated enough without this sort of overloading. The symbol argument has always been intended to mean, find these symbols in any of these libraries, so it is completely acceptable to pass in both lib as list and a symbol argument.
I got this issue from Travis Ubuntu-14.04, not from OpenBSD:
$ sudo ls -al /lib/x86_64-linux-gnu/*libssl*
-rw-r--r-- 1 root root 354568 Jul 2 2014 /lib/x86_64-linux-gnu/libssl.so.0.9.8
-rw-r--r-- 1 root root 387272 Jan 30 2017 /lib/x86_64-linux-gnu/libssl.so.1.0.0
I got idea of symbol argument and its okay for me now.
If you install libssl-dev you should get libssl.so which will disambiguate this.
I can also change the algorithm to prefer the more recent .so in the absence of libssl.so symlink. Most of the time you will want the more recent version anyway.
Are *-dev packages really needed for FFI?
I feel like you shouldn't. In practice? I know at least some languages like ruby do require either the libfoo.so symlink (often part of the dev package) or the full filename of the .so file.
Okay check out 0.17_01 on its way to CPAN right now. It should work with your code as is, since it now prefers the more recent version of libcrypto. (I was able to reproduce the failure you described, and I have a travis test that makes sure that it can find libcrypto using the symbol that you are using for Crypt::OpenSSL::CMS).
I've also added the other enhancements that I mentioned. After some testing and cpantester results I intend on making a production release.
Yep, 0.17_01 works.
since it now prefers the more recent version
Does it means if I request CheckLib to find me some obsoleted (removed from newer library version) symbol it will fail if 2 versions of library exists in a system?
Yes, if you need an older version of the library then you either need a symlink to the older .so file or to use where / verify and filter appropriately. This was true before, although previously there was no preference for .so files, just the order returned from the disk.
Looks like verify is most robust solution.
Anyway thank you.