Nakilon / dhash-vips

vips-powered ruby gem to measure images similarity, implementing dHash and IDHash algorithms
MIT License
88 stars 14 forks source link

NoMethod Error During Post-Install Check #12

Open cguess opened 2 years ago

cguess commented 2 years ago

When trying to install the dhash-vips gem on MacOS 12.0.1 on Apple Silicon (ARM) using Ruby 3.0.2, I'm getting the following error:

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /Users/christopher/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/dhash-vips-0.1.1.3
/Users/christopher/.rbenv/versions/3.0.2/bin/ruby -I /Users/christopher/.rbenv/versions/3.0.2/lib/ruby/3.0.0 -r
./siteconf20211104-38007-8h8fj7.rb extconf.rb
checking for whether -I/Users/christopher/.rbenv/sources/3.0.2/ruby-3.0.2/ is accepted as CPPFLAGS... yes
checking for whether -DRUBY_EXPORT is accepted as CPPFLAGS... yes
creating Makefile

current directory: /Users/christopher/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/dhash-vips-0.1.1.3
make DESTDIR\= clean

current directory: /Users/christopher/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/dhash-vips-0.1.1.3
make DESTDIR\=
compiling idhash.c
linking shared-object idhash.bundle
/Users/christopher/.rbenv/versions/3.0.2/bin/ruby -r./lib/dhash-vips.rb ./lib/dhash-vips-post-install-test.rb
Ignoring eventmachine-1.2.7 because its extensions are not built. Try: gem pristine eventmachine --version 1.2.7
Ignoring http_parser.rb-0.6.0 because its extensions are not built. Try: gem pristine http_parser.rb --version 0.6.0
Testing native extension...
[1014914048, 1715898367, 528465920, 2122267904, 4622, 2156271871, 3229616096, 4286545664]
[2117872660, 876379772, 1216315170, 2139029504, 4325892, 1074036350, 33023, 2147483392]
./lib/dhash-vips-post-install-test.rb:10:in `<main>': undefined method `distance3_c' for DHashVips::IDHash:Module
(NoMethodError)
Did you mean?  distance3
               distance
01111110011111100111110000010100
00000000010000100001000000001010
01110110011111101111111111111111
11000000100000100110011010000001
01011111011111111111111100100010
11000000100000001000011100011111
01111111011111110011110100000000
10000000100000001000000000000000
make: *** [test] Error 1

make failed, exit code 2

Gem files will remain installed in /Users/christopher/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/dhash-vips-0.1.1.3
for inspection.
Results logged to
/Users/christopher/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/extensions/arm64-darwin-21/3.0.0/dhash-vips-0.1.1.3/gem_make.out

An error occurred while installing dhash-vips (0.1.1.3), and Bundler cannot continue.
Make sure that `gem install dhash-vips -v '0.1.1.3' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  dhash-vips

This happens when using either gem "dhash-vips" or `gem "dhash-vips", git: "https://github.com/nakilon/dhash-vips/"

Thank you for any help you can provide in figuring this out!

cguess commented 2 years ago

A quick note that I tried this on the v0.1.1.2 tag as well and it's the same error. I'm guessing it's something to do with the c extensions on x64 vs ARM?

cguess commented 2 years ago

Further: This compiles on Ubuntu ARM running in Parallels and Raspberry Pi OS on a Pi 3 without an issue, so it's something with the compiler on MacOS Monterey (maybe older versions as well).

Nakilon commented 2 years ago

Weird.

compiling idhash.c
linking shared-object idhash.bundle

This has compiled the extension that supposedly defines the method here:

rb_define_module_function(mm, "distance3_c", idhash_distance, 2);

If there was any problem during compilation it would not invoke the test.

Unfortunately I don't have neither ARM nor Monterey to dig deeper.

cguess commented 2 years ago

Thanks for getting back to me! Do you have any guidance? I'm going to attempt to dig in myself and fix this for you.

Just basic starting points would be very helpful.

Nakilon commented 2 years ago

to dig in myself and fix this

Would be cool but I wish I had any guidance for myself. The whole native extensions thing has no comprehensive manual, only a ton of mkmf methods with no explanation on how to use them properly and how the gem installation routine goes at all. And if you ask at SO they downvote, close and delete, lol. So the post-install-check thing is a pure local invention on how to check if the native extension produces correct fingerprints after installation to detect any platform issue.

The extconf.rb builds the Makefile and I've included some comments in it showing how I test it. Basically you do the ruby extconf.rb && make clean && make and it's presumably the same what the gem install is doing. The makefile creates the .bundle (for macOS) or .o (for Linux) file that is then required in Ruby code and is aliased to pure Ruby implementation as a fallback in case of exception. In your case it looks like it has created the .bundle file but without a C function for some reason.

cguess commented 2 years ago

Thanks so much for this write up! I totally get the SO frustration. I have a few ARM machines, so I may be in a good spot to work on this a bit. Let me dig in over the week and see what I can come up with.

Thank you so much for your work so far on all this, it's wildly appreciated.

Nakilon commented 1 year ago

Due to how rarely I test the compilation, yesterday I was surprised as "I don't understand how it worked at all" ..) https://github.com/Nakilon/dhash-vips/commit/2ccc42b1a3960bf1f9c34a39f7ca9a57fe146d01#diff-06bfa1add88aa00af234039a463c42fdd10e629d95926ed4d091b46d9696adaaR37 Due to the lack of class << self the alias was working in some wrong scope and you had to have the "undefined method `distance3_ruby'". Since this is the LoadError condition branch, the reason why no one reported it is probably that everyone (surprisingly) managed to have the native extension compiled.