From: "lloeki (Loic Nageleisen) via ruby-core" Date: 2024-01-10T09:22:25+00:00 Subject: [ruby-core:116137] [Ruby master Feature#20152] mkmf / extconf: Add a proper way to not compile the extension Issue #20152 has been updated by lloeki (Loic Nageleisen). > I agree that this isn't a mkmf/extconf.rb issue. This is a rubygems issue. Sounds like so to me as well. > Maybe RubyGems could recognize dummy Makefiles Not too fond of that. >> Another possibility would be if there is no Makefile created by extconf.rb, then RubyGems would not call make > I quite like that one. I too, sounds better than the one above. > Also one might need make anyway, e.g. for gems used via FFI like sassc and prism, where make is used to build the C code Not necessarily, when platform specific binary gems are available (e.g mini_racer / libv8-node). The solutions we found in our case was: - dependent gem has a hard add_runtime_dependency on the dependency. This is a prerequisite of being able to specify the dependency version requirement at gem install/bundle install time. - provide binary gems, which then inform of feature availability at runtime (something like `MyNamespace.available?` returning `true`) - the `ruby` platform gem is either one of: - a shim, and provides no implementation whatsoever, thus `MyNamespace.available?` returns `false`, which is a bit of a lie since the `ruby` platform is actually not supported - sidestep rubygems platform resolution and attempt fetching binary for that binary platform at `gem install` time. if it succeeds `MyNamespace.available?` returns `true` and succeeds `MyNamespace.available?` returns `false`, which is sad as it breaks the common "install does network but does not execute" and "build executes but does not do network" expectation. - able to compile from C/Rust source, but limit to a set list of platforms in `extconf.rb` and otherwise produce a dummy Makefile - able to compile from C/Rust source, if compilation succeeds `MyNamespace.available?` will return `true` but if compilation fails the result is swallowed, a warning is printed, and `MyNamespace.available?` will return `false` This is all mandated by ruby gems being unable to declare optional dependencies in gemspecs: ``` s.add_runtime_dependency, foo, '~> 1.1', optional: true ``` Which would mean that if `foo` is present in the bundle it must be `['>= 1.1', '< 2.0.a']` but if it's not in GEM_HOME / in Gemfile / does not resolve that's okay, for which there are two sides to the coin: dependency is not installed at all or dependency failed to install. The only way to work around that is at runtime, well after dependency resolution / gem install time: - have the hard dependency as above, ignore compilation failure / have a ruby platform shim gem, and check for availability at runtime - not have the hard dependency, and hopefully do the optional gem version check at runtime, duplicating rubygems/bundler dependency resolution (badly) Note that I'm not positing the above as a solution, merely that it seems to me that it hints at the requirement on creating dummy Makefiles that do nothing might indeed be a deeper rubygems limitation moving a dependency resolution problem to be solved by either build time or runtime hacks. ---------------------------------------- Feature #20152: mkmf / extconf: Add a proper way to not compile the extension https://bugs.ruby-lang.org/issues/20152#change-106143 * Author: byroot (Jean Boussier) * Status: Open * Priority: Normal ---------------------------------------- ### Context There are various gems that ship with a native extension as a way to speedup part of the gem, but also ship with a pure Ruby version of these methods as a fallback. So they only want to compile the extension if the platform supports it, and if not, just fallback to the slightly slower Ruby version. Right now users rely on one of two hacks to do this. Either they create an empty Makefile, but then still depend on `make` being available, or publish platform specific packages without any extension in them. Examples: - [`bootsnap` skip compilation if not on MRI or TruffleRuby](https://github.com/Shopify/bootsnap/blob/070151f1305f23102365d6b4476a91c02dead35a/ext/bootsnap/extconf.rb) - [`erb` has an extension for MRI but then need to publish a `java` version of the gem that doesn't actually contain Java code, just to skip compilation on JRuby](https://github.com/ruby/erb/issues/52) - [`hiredis-client` skips the compilation for Windows and non-MRI rubies](https://github.com/redis-rb/redis-client/blob/1ab081c1d0e47df5d55e011c9390c70b2eef6731/hiredis-client/ext/redis_client/hiredis/extconf.rb#L10-L17) ### Feature It would be very useful to have some proper first class API to skip compiling the extension. Something like: ```ruby require "mkmf" if RUBY_ENGINE != "ruby" || RUBY_PLATFORM.match?(/mswin/) skip_compilation else # ... end ``` cc @k0kubun @headius -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/