Bugs item #29075, was opened at 2011-03-11 05:36 You can respond by visiting: http://rubyforge.org/tracker/?func=detail&atid=575&aid=29075&group_id=126
Category: `gem install` command (extensions) Group: next Status: Open Resolution: Rejected Priority: 3 Submitted By: Torsten Curdt (tcurdt) Assigned to: Ryan Davis (zenspider) Summary: need for a post_install hook Initial Comment: While there is Gem.post_install this cannot be used for gems that want to run some code on installation. In my particular case I need to compile some C++ code -a command line tool- that the gem depends on. It does not come with an extension though. Since there is no post_install hook exposed to the gem lifecycle people use the extconf for things like this. Since that one makes the assumption of building an extension, leaving out the create_makefile() results in Building native extensions. This could take a while... ERROR: Error installing ... ERROR: Failed to build gem native extension. No builder for extension 'path/to/extconf.rb' Which result in people doing things like this http://blog.costan.us/2008/11/post-install-post-update-scripts-for.html The best solution would certainly be to have some gem lifecyle hooks. But just making less assumption on the extension building would already be a first step. ---------------------------------------------------------------------- >Comment By: Ryan Davis (zenspider) Date: 2011-04-08 12:30 Message: Torsten, yeah. You just set your gemspec's extensions field to point to the Rakefile: s.extensions = ["notext/#{self.name}/Rakefile"] and the rakefile should work like below or however you want it to work... it's just rake so you can do anything you want. ---------------------------------------------------------------------- Comment By: Torsten Curdt (tcurdt) Date: 2011-03-15 00:02 Message: Ryan, can elaborate or point me to an example how to do a "rake-based extension"? IIUC this means providing a Rakefile (or Makefile?) instead of the generated by the extconf? Still have your test project around? ---------------------------------------------------------------------- Comment By: Ryan Davis (zenspider) Date: 2011-03-14 14:01 Message: Just to make sure I understand: you have a pure ruby gem that calls out to a binary that you want to provide (build and install) via the gem. If that is accurate, I don't think that extra post_install hooks are the right way to go here. I think you can make this work via "normal" mechanisms. I think what you want to do is design a rake-based extension but then have that rakefile build and install your binary instead of a shared library. I just simulated this with a simple hoe-based project that had 'notext/blah/Rakefile' as it's extension and that rakefile just had: task :default => :build task :build do puts "building my cmdline tool!" touch "happy" end Upon packaging and installing, 'happy' was created inside the notext dir of the install. ---------------------------------------------------------------------- Comment By: Torsten Curdt (tcurdt) Date: 2011-03-14 11:55 Message: You can turn it like you want but building binaries is what rubygems is already doing today. They just get a different linker treatment. Not sure why one make such hard distinction there. Abuse scenarios are a bogus argument as long as the extconf (or for that matter - any code from the gem) gets executed. ---------------------------------------------------------------------- Comment By: Marcus Rueckert (darix) Date: 2011-03-14 11:02 Message: and any packaging system that uses post install hooks for building files *is* broken. i didnt even refer to potential abuse scenarios yet, building native extensions for ruby is certainly in the scope of rubygems. building binaries that get installed somewhere definitely is not. ---------------------------------------------------------------------- Comment By: Torsten Curdt (tcurdt) Date: 2011-03-14 10:04 Message: If that binary was something that would make sense outside of the gem I would agree - but it doesn't. Following your arguments all native code should live somewhere else - including the normal extensions. That would add a complexity to the system I don't see worth having. A post_install hook certainly gives room for abuse but it's a common pattern found in the various packaging systems. Not sure I would call this a broken feature. In fact I think the current build in assumptions are even worse. ---------------------------------------------------------------------- Comment By: Marcus Rueckert (darix) Date: 2011-03-14 08:47 Message: imho this is just the wrong approach, intree packaging like that just sucks. for users as for packagers. maybe the user has your binary installed already just outside of $PATH? while you could walk over $PATH and check if a binary with the desired name exists, you couldnt be sure that behind the filename is really the app you are expecting and that the version is compatible. handle the absence of the binary properly in your code and document for the user that a certain binary is required for proper functioning of your gem. I would really object adding a broken feature like this. ---------------------------------------------------------------------- Comment By: Torsten Curdt (tcurdt) Date: 2011-03-14 08:07 Message: You are probably right. As long as it is tracked as feature or bug I am fine. Thanks - the short term thing works. It's just ugly :) ---------------------------------------------------------------------- Comment By: Jon Forums (jonforums) Date: 2011-03-14 08:04 Message: Fair. IMO this issue should reappear as a feature request rather than stay a bug. And that would likely lead to relooking at plugin/hook visibility. I don't know what Eric wants for next steps on this, but since he asked you to open the issue, maybe it's enough to leave it as a bug. Good luck with whatever short-term solution you choose. ---------------------------------------------------------------------- Comment By: Torsten Curdt (tcurdt) Date: 2011-03-14 07:22 Message: Sorry, but the --init is more a work around than really an option. IMO a post_install hook for a gem is quite a natural thing to expect. If that's not on the table extconf should at least not make all those assumptions people hack around today. If you just close this issue people will continue to abuse the extconf like I am doing, too now. IMO an empty extconf should just not result in an error and we would be OKish. ---------------------------------------------------------------------- Comment By: Jon Forums (jonforums) Date: 2011-03-14 06:51 Message: While you could go down the plugin/hook path and split things something like... https://github.com/jonforums/prething https://github.com/jonforums/thing I think it's a bad fit for what you're trying to do...could become a tarbaby trying to keep the `prething` plugin from affecting other gems and coordinating with your main gem. Try building/installing the `prething` and see how globally it affects RG ops. Probably faster and more robust to add an `--init` to your gem's `bin\somthing` executable and document your gem's two-step install process in a `Gem::Specification.post_install_message` and your project doc. Any reason to keep this listed as an open RG bug? ---------------------------------------------------------------------- Comment By: Jon Forums (jonforums) Date: 2011-03-12 07:18 Message: That snippet from our install script results in a rubygems/defaults/operating_system.rb file being generated similar to the following: # :DK-BEG: override 'gem install' to enable RubyInstaller DevKit usage Gem.pre_install do |gem_installer| unless gem_installer.spec.extensions.empty? unless ENV['PATH'].include?('C:\DevKit\mingw\bin') then Gem.ui.say 'Temporarily enhancing PATH to include DevKit...' if Gem.configuration.verbose ENV['PATH'] = 'C:\DevKit\bin;C:\DevKit\mingw\bin;' + ENV['PATH'] end ENV['RI_DEVKIT'] = 'C:\DevKit' ENV['CC'] = 'gcc' ENV['CPP'] = 'cpp' ENV['CXX'] = 'g++' end end # :DK-END While my usage is fairly simple and the only mildly clever parts are (a) checking whether a native extension is being installed, and (b) wrapping the code snippet in markers so I can manage non-clobbering/upgrades of existing operating_system.rb files, I'm still betting that you could use `system` to call out to your toolchain and build your C++ tool in a similar way. It's the combination of the filename/location in combination with the block to Gem.pre_install which sets the pre-install hook that RG calls at the appropriate time during an install. These two places in the source should help: https://github.com/rubygems/rubygems/blob/master/lib/rubygems.rb#L65-82 https://github.com/rubygems/rubygems/blob/master/lib/rubygems/installer.rb#L140 ---------------------------------------------------------------------- Comment By: Torsten Curdt (tcurdt) Date: 2011-03-12 02:55 Message: @Jon: Still don't quite understand when you are setting that hook. Why would that code be called on a 'gem install' ? ---------------------------------------------------------------------- Comment By: Jon Forums (jonforums) Date: 2011-03-11 08:05 Message: In the DevKit (MSYS/MinGW toolchain for Windows) subproject of the RubyInstaller we have a Ruby install script which dynamically builds a gem override script that uses the pre-install hook to setup the environment for building native gems on Windows using the DevKit: https://github.com/oneclick/rubyinstaller/blob/master/resources/devkit/dk.rb.erb#L46-65 Basically, it automagically brings the DevKit toolchain into the environment when doing something like `gem install bson_ext` Thinking out loud, but I wonder if you can do something similar but use `system` or `IO.popen` to optimistically compile your gem's C++ dependency before the install and abort if you get any errors. Might also want to check/cleanup in post-build. A wild-eyed idea, but it might work if you can split things into "pre-build dependencies" and "build extension" and abort if things go badly. ---------------------------------------------------------------------- Comment By: Torsten Curdt (tcurdt) Date: 2011-03-11 07:46 Message: Maybe I misunderstood but I think Eric said on IRC that the existing post_install is not for gems. Which is why he asked me to open this issue. Jon, can you give an example how that would work? Whether it is pre or post install is not important to me. It's just that one might want to build more than just extension on install. I got that working by abusing the extconf to execute my build and creating an empty Makefile. But that smells. ---------------------------------------------------------------------- Comment By: Jon Forums (jonforums) Date: 2011-03-11 07:13 Message: Can you split things up to use the pre-install and post-build hooks which as of 1.5.0 that can cancel gem installation...optimistically compile in the pre-install and abort if needed in either pre-install or post-build? http://blog.segment7.net/2011/01/31/rubygems-1-5 ---------------------------------------------------------------------- Comment By: Torsten Curdt (tcurdt) Date: 2011-03-11 05:54 Message: Then you also cannot allow native builds. Where is the difference? ---------------------------------------------------------------------- Comment By: Luis Lavena (luislavena) Date: 2011-03-11 05:44 Message: I would say no to this. Most of the users do not check what the gem do inside, so there is a huge potential of security risks on this. ---------------------------------------------------------------------- You can respond by visiting: http://rubyforge.org/tracker/?func=detail&atid=575&aid=29075&group_id=126 _______________________________________________ Rubygems-developers mailing list http://rubyforge.org/projects/rubygems Rubygems-developers@rubyforge.org http://rubyforge.org/mailman/listinfo/rubygems-developers